Skip to content

Instantly share code, notes, and snippets.

@jspiro
Created March 5, 2019 23:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jspiro/8ee89f7d654afa58115cf26af0e4779b to your computer and use it in GitHub Desktop.
Save jspiro/8ee89f7d654afa58115cf26af0e4779b to your computer and use it in GitHub Desktop.
coffeelint.org snapshot 9/19
* {
padding:0;
margin:0;
}
html {
width:100%;
}
body {
background: -webkit-radial-gradient(circle, #eee, #555);
background: -moz-radial-gradient(circle, #eee, #555);
font-family:monospace;
width:100%;
margin-bottom:40px;
font-size:14px;
line-height:1.5em;
}
/**
* Header styles.
*/
.header {
background-color: #111;
border-bottom: 1px solid black;
width:100%;
vertical-align:bottom;
position:relative;
height:40px;
}
.title {
font-weight:normal;
display:inline-block;
float:left;
font-size:30px;
margin-right: 40px;
color: #fff;
position:relative;
top:8px;
}
.header_links {
font-size:13px;
position:relative;
top:10px;
}
.header_links li {
display:inline;
float:left;
}
.header_links a {
color: #eee;
text-decoration:none;
margin-right:10px;
padding:5px;
}
.header_links a:hover {
color: #fff;
background-color:#2b2b2b;
border-radius:5px;
}
/**
* Body styles.
*/
.container {
width: 900px;
margin-left:auto;
margin-right:auto;
}
.row {
margin-top:20px;
box-shadow: 2px -2px 6px rgba(0, 0, 0, 0.5);
border: 2px solid #555;
background: white;
border-radius:5px;
}
.report_row, .doc_row {
padding-left:75px;
padding-right:75px;
}
.row.doc_row .options pre {
overflow-x: scroll;
max-width: 400px;
}
.doc_row {
font-family: "Helvetica Neue", "Lucida Grande", "Lucida Sans Unicode",
Helvetica, Arial, sans-serif !important;
padding-bottom:20px;
}
p {
margin-bottom:10px;
}
.section_title {
margin-top:35px;
margin-bottom:15px;
font-size:25px;
font-family:monospace;
}
a {
color:#C00000;
}
.forkme {
position: absolute;
z-index: 5;
top: 0;
right: 0;
border: 0;
}
.clear {
clear:both;
}
code, .error_report {
font-family:monospace;
border: 1px dotted black;
display:block;
padding:10px;
margin-top:10px;
margin-bottom:10px;
background-color:#eee;
}
/* Editor styling */
.row.editor_row {
padding-left:20px;
background-color:#111;
border: 0;
}
.editor {
background-color:#111;
min-height:250px;
color:#339933;
font-family:monospace;
font-size:16px;
font-weight:normal;
resize:none;
outline:none;
width:100%;
border:none;
}
tt {
padding:3px;
background-color:#eee;
font-family:monospace;
border:1px dotted #aaa;
}
.run {
font-size:20px;
float:right;
text-transform:uppercase;
display:inline;
position:relative;
top:20px;
right:20px;
background-color: #eee;
padding:4px;
border:1px solid #2b2b2b;
border-radius:5px;
cursor:pointer;
background: -webkit-radial-gradient(circle, #fff, #bbb);
background: -moz-radial-gradient(circle, #fff, #bbb);
width:3em;
text-align:center;
position:relative;
z-index:10;
}
/** Report style **/
.report_row {
display:none;
padding-bottom:10px;
}
.report_row.success {
background: #b2e0c2;
background: -webkit-radial-gradient(circle, #B2e0c2, #99D6AD);
}
.report_row.failure {
background-color:#ffe6e6;
background: -webkit-radial-gradient(circle, #ffe6e6, #ffcccc);
}
.error_report {
width:100%;
border: 1px dotted black;
}
.error_report .lineNumber {
min-width:100px;
text-align:right;
padding-right:10px;
}
/* Options table */
.options {
margin-top:20px;
border-width: 1px 1px 1px 1px;
border-spacing: 0;
border-collapse: collapse;
border-color: #2b2b2b;
border-style: solid;
}
.options thead tr {
color:black;
font-weight:bold;
}
.options tbody tr:nth-child(odd) {
background-color: #efefef;
}
.options td, th {
margin: 0;
padding: 15px;
border-width: 1px 1px 1px 1px;
border-color: #2b2b2b;
border-style: solid;
}
.options .rule {
text-align:center;
vertical-align:middle;
font-family:monospace;
font-weight:bold;
}
.options code {
background-color:#ffffdd;
margin-bottom:0;
font-size:13px;
}
.changelog_header {
margin-bottom:0.8em;
display:inline;
}
.changelog_date {
display:inline;
color:#444;
font-size:80%;
}
.changelog_history {
margin-left:2em;
margin-bottom:1em;
}
.api_call {
margin-top:15px;
font-family:monospace;
margin-bottom:8px;
font-weight:bold;
}
/*
FILE ARCHIVED ON 20:46:35 Jun 12, 2018 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 22:53:29 Mar 05, 2019.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
*/
/*
playback timings (ms):
LoadShardBlock: 103.805 (3)
esindex: 0.006
captures_list: 117.517
CDXLines.iter: 9.588 (3)
PetaboxLoader3.datanode: 158.331 (5)
exclusion.robots: 0.186
exclusion.robots.policy: 0.174
RedisCDXSource: 1.842
PetaboxLoader3.resolve: 58.037 (2)
load_resource: 220.31
*/
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.coffeelint=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/*
CoffeeLint
Copyright (c) 2011 Matthew Perpick.
CoffeeLint is freely distributable under the MIT license.
*/
var ASTLinter, CoffeeScript, ERROR, ErrorReport, IGNORE, LexicalLinter, LineLinter, RULES, WARN, _rules, cache, coffeelint, defaults, difference, extend, hasSyntaxError, mergeDefaultConfig, nodeRequire, packageJSON, sameJSON, union,
slice = [].slice,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
coffeelint = exports;
nodeRequire = require;
if (typeof window !== "undefined" && window !== null) {
CoffeeScript = window.CoffeeScript;
}
if (CoffeeScript == null) {
CoffeeScript = nodeRequire('coffee-script');
}
if (CoffeeScript == null) {
throw new Error('Unable to find CoffeeScript');
}
packageJSON = require('./../package.json');
coffeelint.VERSION = packageJSON.version;
ERROR = 'error';
WARN = 'warn';
IGNORE = 'ignore';
coffeelint.RULES = RULES = require('./rules.coffee');
extend = function() {
var destination, j, k, len, source, sources, v;
destination = arguments[0], sources = 2 <= arguments.length ? slice.call(arguments, 1) : [];
for (j = 0, len = sources.length; j < len; j++) {
source = sources[j];
for (k in source) {
v = source[k];
destination[k] = v;
}
}
return destination;
};
defaults = function(source, defaults) {
return extend({}, defaults, source);
};
union = function(a, b) {
var c, j, len, len1, n, results, x;
c = {};
for (j = 0, len = a.length; j < len; j++) {
x = a[j];
c[x] = true;
}
for (n = 0, len1 = b.length; n < len1; n++) {
x = b[n];
c[x] = true;
}
results = [];
for (x in c) {
results.push(x);
}
return results;
};
difference = function(a, b) {
var j, len, results, x;
results = [];
for (j = 0, len = a.length; j < len; j++) {
x = a[j];
if (indexOf.call(b, x) < 0) {
results.push(x);
}
}
return results;
};
LineLinter = require('./line_linter.coffee');
LexicalLinter = require('./lexical_linter.coffee');
ASTLinter = require('./ast_linter.coffee');
cache = null;
mergeDefaultConfig = function(userConfig) {
var config, rule, ruleConfig, ruleLoader;
try {
ruleLoader = nodeRequire('./ruleLoader');
ruleLoader.loadFromConfig(coffeelint, userConfig);
} catch (_error) {}
config = {};
if (userConfig.coffeelint) {
config.coffeelint = userConfig.coffeelint;
}
for (rule in RULES) {
ruleConfig = RULES[rule];
config[rule] = defaults(userConfig[rule], ruleConfig);
}
return config;
};
sameJSON = function(a, b) {
return JSON.stringify(a) === JSON.stringify(b);
};
coffeelint.trimConfig = function(userConfig) {
var config, dConfig, dValue, key, newConfig, ref, rule, value;
newConfig = {};
userConfig = mergeDefaultConfig(userConfig);
for (rule in userConfig) {
config = userConfig[rule];
dConfig = RULES[rule];
if (rule === 'coffeelint') {
config.transforms = config._transforms;
delete config._transforms;
config.coffeescript = config._coffeescript;
delete config._coffeescript;
newConfig[rule] = config;
} else if ((config.level === (ref = dConfig.level) && ref === 'ignore')) {
void 0;
} else if (config.level === 'ignore') {
newConfig[rule] = {
level: 'ignore'
};
} else {
config.module = config._module;
delete config._module;
for (key in config) {
value = config[key];
if (key === 'message' || key === 'description' || key === 'name') {
continue;
}
dValue = dConfig[key];
if (value !== dValue && !sameJSON(value, dValue)) {
if (newConfig[rule] == null) {
newConfig[rule] = {};
}
newConfig[rule][key] = value;
}
}
}
}
return newConfig;
};
coffeelint.invertLiterate = function(source) {
var j, len, line, newSource, ref;
source = CoffeeScript.helpers.invertLiterate(source);
newSource = '';
ref = source.split('\n');
for (j = 0, len = ref.length; j < len; j++) {
line = ref[j];
if (line.match(/^#/)) {
line = line.replace(/\s*$/, '');
}
line = line.replace(/^\s{4}/g, '');
newSource += line + "\n";
}
return newSource;
};
_rules = {};
coffeelint.registerRule = function(RuleConstructor, ruleName) {
var e, name, p, ref, ref1;
if (ruleName == null) {
ruleName = void 0;
}
p = new RuleConstructor;
name = (p != null ? (ref = p.rule) != null ? ref.name : void 0 : void 0) || '(unknown)';
e = function(msg) {
throw new Error("Invalid rule: " + name + " " + msg);
};
if (p.rule == null) {
e('Rules must provide rule attribute with a default configuration.');
}
if (p.rule.name == null) {
e('Rule defaults require a name');
}
if ((ruleName != null) && ruleName !== p.rule.name) {
e("Mismatched rule name: " + ruleName);
}
if (p.rule.message == null) {
e('Rule defaults require a message');
}
if (p.rule.description == null) {
e('Rule defaults require a description');
}
if ((ref1 = p.rule.level) !== 'ignore' && ref1 !== 'warn' && ref1 !== 'error') {
e("Default level must be 'ignore', 'warn', or 'error'");
}
if (typeof p.lintToken === 'function') {
if (!p.tokens) {
e("'tokens' is required for 'lintToken'");
}
} else if (typeof p.lintLine !== 'function' && typeof p.lintAST !== 'function') {
e('Rules must implement lintToken, lintLine, or lintAST');
}
RULES[p.rule.name] = p.rule;
return _rules[p.rule.name] = RuleConstructor;
};
coffeelint.getRules = function() {
var j, key, len, output, ref;
output = {};
ref = Object.keys(RULES).sort();
for (j = 0, len = ref.length; j < len; j++) {
key = ref[j];
output[key] = RULES[key];
}
return output;
};
coffeelint.registerRule(require('./rules/arrow_spacing.coffee'));
coffeelint.registerRule(require('./rules/braces_spacing.coffee'));
coffeelint.registerRule(require('./rules/no_tabs.coffee'));
coffeelint.registerRule(require('./rules/no_trailing_whitespace.coffee'));
coffeelint.registerRule(require('./rules/max_line_length.coffee'));
coffeelint.registerRule(require('./rules/line_endings.coffee'));
coffeelint.registerRule(require('./rules/no_trailing_semicolons.coffee'));
coffeelint.registerRule(require('./rules/indentation.coffee'));
coffeelint.registerRule(require('./rules/camel_case_classes.coffee'));
coffeelint.registerRule(require('./rules/colon_assignment_spacing.coffee'));
coffeelint.registerRule(require('./rules/no_implicit_braces.coffee'));
coffeelint.registerRule(require('./rules/no_nested_string_interpolation.coffee'));
coffeelint.registerRule(require('./rules/no_plusplus.coffee'));
coffeelint.registerRule(require('./rules/no_throwing_strings.coffee'));
coffeelint.registerRule(require('./rules/no_backticks.coffee'));
coffeelint.registerRule(require('./rules/no_implicit_parens.coffee'));
coffeelint.registerRule(require('./rules/no_empty_param_list.coffee'));
coffeelint.registerRule(require('./rules/no_stand_alone_at.coffee'));
coffeelint.registerRule(require('./rules/space_operators.coffee'));
coffeelint.registerRule(require('./rules/duplicate_key.coffee'));
coffeelint.registerRule(require('./rules/empty_constructor_needs_parens.coffee'));
coffeelint.registerRule(require('./rules/cyclomatic_complexity.coffee'));
coffeelint.registerRule(require('./rules/newlines_after_classes.coffee'));
coffeelint.registerRule(require('./rules/no_unnecessary_fat_arrows.coffee'));
coffeelint.registerRule(require('./rules/missing_fat_arrows.coffee'));
coffeelint.registerRule(require('./rules/non_empty_constructor_needs_parens.coffee'));
coffeelint.registerRule(require('./rules/no_unnecessary_double_quotes.coffee'));
coffeelint.registerRule(require('./rules/no_debugger.coffee'));
coffeelint.registerRule(require('./rules/no_interpolation_in_single_quotes.coffee'));
coffeelint.registerRule(require('./rules/no_empty_functions.coffee'));
coffeelint.registerRule(require('./rules/prefer_english_operator.coffee'));
coffeelint.registerRule(require('./rules/spacing_after_comma.coffee'));
coffeelint.registerRule(require('./rules/transform_messes_up_line_numbers.coffee'));
coffeelint.registerRule(require('./rules/ensure_comprehensions.coffee'));
coffeelint.registerRule(require('./rules/no_this.coffee'));
coffeelint.registerRule(require('./rules/eol_last.coffee'));
coffeelint.registerRule(require('./rules/no_private_function_fat_arrows.coffee'));
hasSyntaxError = function(source) {
try {
CoffeeScript.tokens(source);
return false;
} catch (_error) {}
return true;
};
ErrorReport = require('./error_report.coffee');
coffeelint.getErrorReport = function() {
return new ErrorReport(coffeelint);
};
coffeelint.lint = function(source, userConfig, literate) {
var allErrors, astErrors, cmd, config, disabled, disabledEntirely, disabledInitially, disabledLine, e, errors, i, inlineConfig, j, l, len, len1, lexErrors, lexicalLinter, lineErrors, lineLinter, m, n, name, nextLine, o, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, regex, rule, ruleLoader, rules, set, sourceLength, tokensByLine, transform;
if (userConfig == null) {
userConfig = {};
}
if (literate == null) {
literate = false;
}
errors = [];
if (cache != null) {
cache.setConfig(userConfig);
}
if (cache != null ? cache.has(source) : void 0) {
return cache != null ? cache.get(source) : void 0;
}
config = mergeDefaultConfig(userConfig);
if (literate) {
source = this.invertLiterate(source);
}
if ((userConfig != null ? (ref = userConfig.coffeelint) != null ? ref.transforms : void 0 : void 0) != null) {
sourceLength = source.split('\n').length;
ref2 = userConfig != null ? (ref1 = userConfig.coffeelint) != null ? ref1.transforms : void 0 : void 0;
for (j = 0, len = ref2.length; j < len; j++) {
m = ref2[j];
try {
ruleLoader = nodeRequire('./ruleLoader');
transform = ruleLoader.require(m);
source = transform(source);
} catch (_error) {}
}
if (sourceLength !== source.split('\n').length && config.transform_messes_up_line_numbers.level !== 'ignore') {
errors.push(extend({
lineNumber: 1,
context: "File was transformed from " + sourceLength + " lines to " + (source.split("\n").length) + " lines"
}, config.transform_messes_up_line_numbers));
}
}
if ((userConfig != null ? (ref3 = userConfig.coffeelint) != null ? ref3.coffeescript : void 0 : void 0) != null) {
CoffeeScript = ruleLoader.require(userConfig.coffeelint.coffeescript);
}
for (name in userConfig) {
if (name !== 'coffeescript_error' && name !== '_comment') {
if (_rules[name] == null) {
void 0;
}
}
}
disabledInitially = [];
ref4 = source.split('\n');
for (n = 0, len1 = ref4.length; n < len1; n++) {
l = ref4[n];
ref5 = LineLinter.getDirective(l) || [], regex = ref5[0], set = ref5[1], rule = ref5[ref5.length - 1];
if ((set === 'enable' || set === 'enable-line') && ((ref6 = config[rule]) != null ? ref6.level : void 0) === 'ignore') {
disabledInitially.push(rule);
config[rule].level = 'error';
}
}
astErrors = new ASTLinter(source, config, _rules, CoffeeScript).lint();
errors = errors.concat(astErrors);
if (!hasSyntaxError(source)) {
lexicalLinter = new LexicalLinter(source, config, _rules, CoffeeScript);
lexErrors = lexicalLinter.lint();
errors = errors.concat(lexErrors);
tokensByLine = lexicalLinter.tokensByLine;
lineLinter = new LineLinter(source, config, _rules, tokensByLine, literate);
lineErrors = lineLinter.lint();
errors = errors.concat(lineErrors);
inlineConfig = lineLinter.inlineConfig;
} else {
inlineConfig = {
enable: {},
disable: {},
'enable-line': {},
'disable-line': {}
};
}
errors.sort(function(a, b) {
return a.lineNumber - b.lineNumber;
});
disabledEntirely = (function() {
var len2, map, o, ref7, result;
result = [];
map = {};
ref7 = errors || [];
for (o = 0, len2 = ref7.length; o < len2; o++) {
name = ref7[o].name;
if (!map[name]) {
result.push(name);
map[name] = true;
}
}
return result;
})();
allErrors = errors;
errors = [];
disabled = disabledInitially;
nextLine = 0;
for (i = o = 0, ref7 = source.split('\n').length; 0 <= ref7 ? o < ref7 : o > ref7; i = 0 <= ref7 ? ++o : --o) {
disabledLine = disabled;
for (cmd in inlineConfig) {
rules = inlineConfig[cmd][i];
if (rules != null) {
({
'disable': function() {
if (rules.length) {
disabled = union(disabled, rules);
return disabledLine = union(disabledLine, rules);
} else {
return disabled = disabledLine = disabledEntirely;
}
},
'disable-line': function() {
if (rules.length) {
return disabledLine = union(disabledLine, rules);
} else {
return disabledLine = disabledEntirely;
}
},
'enable': function() {
if (rules.length) {
disabled = difference(disabled, rules);
return disabledLine = difference(disabledLine, rules);
} else {
return disabled = disabledLine = disabledInitially;
}
},
'enable-line': function() {
if (rules.length) {
return disabledLine = difference(disabledLine, rules);
} else {
return disabledLine = disabledInitially;
}
}
})[cmd]();
}
}
while (nextLine === i && allErrors.length > 0) {
nextLine = allErrors[0].lineNumber - 1;
e = allErrors[0];
if (e.lineNumber === i + 1 || (e.lineNumber == null)) {
e = allErrors.shift();
if (ref8 = e.rule, indexOf.call(disabledLine, ref8) < 0) {
errors.push(e);
}
}
}
}
if (cache != null) {
cache.set(source, errors);
}
return errors;
};
coffeelint.setCache = function(obj) {
return cache = obj;
};
},{"./../package.json":2,"./ast_linter.coffee":3,"./error_report.coffee":5,"./lexical_linter.coffee":6,"./line_linter.coffee":7,"./rules.coffee":8,"./rules/arrow_spacing.coffee":9,"./rules/braces_spacing.coffee":10,"./rules/camel_case_classes.coffee":11,"./rules/colon_assignment_spacing.coffee":12,"./rules/cyclomatic_complexity.coffee":13,"./rules/duplicate_key.coffee":14,"./rules/empty_constructor_needs_parens.coffee":15,"./rules/ensure_comprehensions.coffee":16,"./rules/eol_last.coffee":17,"./rules/indentation.coffee":18,"./rules/line_endings.coffee":19,"./rules/max_line_length.coffee":20,"./rules/missing_fat_arrows.coffee":21,"./rules/newlines_after_classes.coffee":22,"./rules/no_backticks.coffee":23,"./rules/no_debugger.coffee":24,"./rules/no_empty_functions.coffee":25,"./rules/no_empty_param_list.coffee":26,"./rules/no_implicit_braces.coffee":27,"./rules/no_implicit_parens.coffee":28,"./rules/no_interpolation_in_single_quotes.coffee":29,"./rules/no_nested_string_interpolation.coffee":30,"./rules/no_plusplus.coffee":31,"./rules/no_private_function_fat_arrows.coffee":32,"./rules/no_stand_alone_at.coffee":33,"./rules/no_tabs.coffee":34,"./rules/no_this.coffee":35,"./rules/no_throwing_strings.coffee":36,"./rules/no_trailing_semicolons.coffee":37,"./rules/no_trailing_whitespace.coffee":38,"./rules/no_unnecessary_double_quotes.coffee":39,"./rules/no_unnecessary_fat_arrows.coffee":40,"./rules/non_empty_constructor_needs_parens.coffee":41,"./rules/prefer_english_operator.coffee":42,"./rules/space_operators.coffee":43,"./rules/spacing_after_comma.coffee":44,"./rules/transform_messes_up_line_numbers.coffee":45}],2:[function(require,module,exports){
module.exports={
"name": "coffeelint",
"description": "Lint your CoffeeScript",
"version": "1.15.0",
"homepage": "https://web.archive.org/web/20180612201411/http://www.coffeelint.org/",
"keywords": [
"lint",
"coffeescript",
"coffee-script"
],
"author": "Matthew Perpick <clutchski@gmail.com>",
"main": "./lib/coffeelint.js",
"engines": {
"npm": ">=1.3.7",
"node": ">=0.8.0"
},
"repository": {
"type": "git",
"url": "git://github.com/clutchski/coffeelint.git"
},
"bin": {
"coffeelint": "./bin/coffeelint"
},
"dependencies": {
"browserify": "~8.1.0",
"coffee-script": "^1.9.1",
"coffeeify": "~1.0.0",
"glob": "^4.0.0",
"ignore": "^2.2.15",
"optimist": "^0.6.1",
"resolve": "^0.6.3",
"strip-json-comments": "^1.0.2"
},
"devDependencies": {
"vows": ">=0.6.0",
"underscore": ">=1.4.4"
},
"license": "MIT",
"scripts": {
"pretest": "cake compile",
"test": "./vowsrunner.js --spec test/*.coffee test/*.litcoffee",
"testrule": "npm run compile && ./vowsrunner.js --spec",
"posttest": "npm run lint",
"prepublish": "cake prepublish",
"postpublish": "cake postpublish",
"publish": "cake publish",
"install": "cake install",
"lint": "cake compile && ./bin/coffeelint .",
"lint-csv": "cake compile && ./bin/coffeelint --csv .",
"lint-jslint": "cake compile && ./bin/coffeelint --jslint .",
"compile": "cake compile"
}
}
},{}],3:[function(require,module,exports){
var ASTApi, ASTLinter, BaseLinter, hasChildren, node_children,
hasProp = {}.hasOwnProperty,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
BaseLinter = require('./base_linter.coffee');
node_children = {
Class: ['variable', 'parent', 'body'],
Code: ['params', 'body'],
For: ['body', 'source', 'guard', 'step'],
If: ['condition', 'body', 'elseBody'],
Obj: ['properties'],
Op: ['first', 'second'],
Switch: ['subject', 'cases', 'otherwise'],
Try: ['attempt', 'recovery', 'ensure'],
Value: ['base', 'properties'],
While: ['condition', 'guard', 'body']
};
hasChildren = function(node, children) {
var ref;
return (node != null ? (ref = node.children) != null ? ref.length : void 0 : void 0) === children.length && (node != null ? node.children.every(function(elem, i) {
return elem === children[i];
}) : void 0);
};
ASTApi = (function() {
function ASTApi(config1) {
this.config = config1;
}
ASTApi.prototype.getNodeName = function(node) {
var children, name, ref;
name = node != null ? (ref = node.constructor) != null ? ref.name : void 0 : void 0;
if (node_children[name]) {
return name;
} else {
for (name in node_children) {
if (!hasProp.call(node_children, name)) continue;
children = node_children[name];
if (hasChildren(node, children)) {
return name;
}
}
}
};
return ASTApi;
})();
module.exports = ASTLinter = (function(superClass) {
extend(ASTLinter, superClass);
function ASTLinter(source, config, rules, CoffeeScript) {
this.CoffeeScript = CoffeeScript;
ASTLinter.__super__.constructor.call(this, source, config, rules);
this.astApi = new ASTApi(this.config);
}
ASTLinter.prototype.acceptRule = function(rule) {
return typeof rule.lintAST === 'function';
};
ASTLinter.prototype.lint = function() {
var coffeeError, err, errors, j, len, ref, rule, v;
errors = [];
try {
this.node = this.CoffeeScript.nodes(this.source);
} catch (_error) {
coffeeError = _error;
err = this._parseCoffeeScriptError(coffeeError);
if (err != null) {
errors.push(err);
}
return errors;
}
ref = this.rules;
for (j = 0, len = ref.length; j < len; j++) {
rule = ref[j];
this.astApi.createError = (function(_this) {
return function(attrs) {
if (attrs == null) {
attrs = {};
}
return _this.createError(rule.rule.name, attrs);
};
})(this);
rule.errors = errors;
v = this.normalizeResult(rule, rule.lintAST(this.node, this.astApi));
if (v != null) {
return v;
}
}
return errors;
};
ASTLinter.prototype._parseCoffeeScriptError = function(coffeeError) {
var attrs, lineNumber, match, message, rule;
rule = this.config['coffeescript_error'];
message = coffeeError.toString();
lineNumber = -1;
if (coffeeError.location != null) {
lineNumber = coffeeError.location.first_line + 1;
} else {
match = /line (\d+)/.exec(message);
if ((match != null ? match.length : void 0) > 1) {
lineNumber = parseInt(match[1], 10);
}
}
attrs = {
message: message,
level: rule.level,
lineNumber: lineNumber
};
return this.createError('coffeescript_error', attrs);
};
return ASTLinter;
})(BaseLinter);
},{"./base_linter.coffee":4}],4:[function(require,module,exports){
var BaseLinter, defaults, extend,
slice = [].slice;
extend = function() {
var destination, i, k, len, source, sources, v;
destination = arguments[0], sources = 2 <= arguments.length ? slice.call(arguments, 1) : [];
for (i = 0, len = sources.length; i < len; i++) {
source = sources[i];
for (k in source) {
v = source[k];
destination[k] = v;
}
}
return destination;
};
defaults = function(source, defaults) {
return extend({}, defaults, source);
};
module.exports = BaseLinter = (function() {
function BaseLinter(source1, config, rules) {
this.source = source1;
this.config = config;
this.setupRules(rules);
}
BaseLinter.prototype.isObject = function(obj) {
return obj === Object(obj);
};
BaseLinter.prototype.createError = function(ruleName, attrs) {
var level;
if (attrs == null) {
attrs = {};
}
if (attrs.level == null) {
attrs.level = this.config[ruleName].level;
}
level = attrs.level;
if (level !== 'ignore' && level !== 'warn' && level !== 'error') {
throw new Error("unknown level " + level + " for rule: " + ruleName);
}
if (level === 'error' || level === 'warn') {
attrs.rule = ruleName;
return defaults(attrs, this.config[ruleName]);
} else {
return null;
}
};
BaseLinter.prototype.acceptRule = function(rule) {
throw new Error('acceptRule needs to be overridden in the subclass');
};
BaseLinter.prototype.setupRules = function(rules) {
var RuleConstructor, level, name, results, rule;
this.rules = [];
results = [];
for (name in rules) {
RuleConstructor = rules[name];
level = this.config[name].level;
if (level === 'error' || level === 'warn') {
rule = new RuleConstructor(this, this.config);
if (this.acceptRule(rule)) {
results.push(this.rules.push(rule));
} else {
results.push(void 0);
}
} else if (level !== 'ignore') {
throw new Error("unknown level " + level + " for rule: " + rule);
} else {
results.push(void 0);
}
}
return results;
};
BaseLinter.prototype.normalizeResult = function(p, result) {
if (result === true) {
return this.createError(p.rule.name);
}
if (this.isObject(result)) {
return this.createError(p.rule.name, result);
}
};
return BaseLinter;
})();
},{}],5:[function(require,module,exports){
var ErrorReport;
module.exports = ErrorReport = (function() {
function ErrorReport(coffeelint) {
this.coffeelint = coffeelint;
this.paths = {};
}
ErrorReport.prototype.lint = function(filename, source, config, literate) {
if (config == null) {
config = {};
}
if (literate == null) {
literate = false;
}
return this.paths[filename] = this.coffeelint.lint(source, config, literate);
};
ErrorReport.prototype.getExitCode = function() {
var path;
for (path in this.paths) {
if (this.pathHasError(path)) {
return 1;
}
}
return 0;
};
ErrorReport.prototype.getSummary = function() {
var error, errorCount, errors, i, len, path, pathCount, ref, warningCount;
pathCount = errorCount = warningCount = 0;
ref = this.paths;
for (path in ref) {
errors = ref[path];
pathCount++;
for (i = 0, len = errors.length; i < len; i++) {
error = errors[i];
if (error.level === 'error') {
errorCount++;
}
if (error.level === 'warn') {
warningCount++;
}
}
}
return {
errorCount: errorCount,
warningCount: warningCount,
pathCount: pathCount
};
};
ErrorReport.prototype.getErrors = function(path) {
return this.paths[path];
};
ErrorReport.prototype.pathHasWarning = function(path) {
return this._hasLevel(path, 'warn');
};
ErrorReport.prototype.pathHasError = function(path) {
return this._hasLevel(path, 'error');
};
ErrorReport.prototype.hasError = function() {
var path;
for (path in this.paths) {
if (this.pathHasError(path)) {
return true;
}
}
return false;
};
ErrorReport.prototype._hasLevel = function(path, level) {
var error, i, len, ref;
ref = this.paths[path];
for (i = 0, len = ref.length; i < len; i++) {
error = ref[i];
if (error.level === level) {
return true;
}
}
return false;
};
return ErrorReport;
})();
},{}],6:[function(require,module,exports){
var BaseLinter, LexicalLinter, TokenApi,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
TokenApi = (function() {
function TokenApi(CoffeeScript, source, config1, tokensByLine) {
this.config = config1;
this.tokensByLine = tokensByLine;
this.tokens = CoffeeScript.tokens(source);
this.lines = source.split('\n');
this.tokensByLine = {};
}
TokenApi.prototype.i = 0;
TokenApi.prototype.peek = function(n) {
if (n == null) {
n = 1;
}
return this.tokens[this.i + n] || null;
};
return TokenApi;
})();
BaseLinter = require('./base_linter.coffee');
module.exports = LexicalLinter = (function(superClass) {
extend(LexicalLinter, superClass);
function LexicalLinter(source, config, rules, CoffeeScript) {
LexicalLinter.__super__.constructor.call(this, source, config, rules);
this.tokenApi = new TokenApi(CoffeeScript, source, this.config, this.tokensByLine);
this.tokensByLine = this.tokenApi.tokensByLine;
}
LexicalLinter.prototype.acceptRule = function(rule) {
return typeof rule.lintToken === 'function';
};
LexicalLinter.prototype.lint = function() {
var error, errors, i, j, k, len, len1, ref, ref1, token;
errors = [];
ref = this.tokenApi.tokens;
for (i = j = 0, len = ref.length; j < len; i = ++j) {
token = ref[i];
this.tokenApi.i = i;
ref1 = this.lintToken(token);
for (k = 0, len1 = ref1.length; k < len1; k++) {
error = ref1[k];
errors.push(error);
}
}
return errors;
};
LexicalLinter.prototype.lintToken = function(token) {
var base, errors, j, len, lineNumber, ref, ref1, ref2, rule, type, v, value;
type = token[0], value = token[1], (ref = token[2], lineNumber = ref.first_line);
if ((base = this.tokensByLine)[lineNumber] == null) {
base[lineNumber] = [];
}
this.tokensByLine[lineNumber].push(token);
this.lineNumber = lineNumber || this.lineNumber || 0;
this.tokenApi.lineNumber = this.lineNumber;
errors = [];
ref1 = this.rules;
for (j = 0, len = ref1.length; j < len; j++) {
rule = ref1[j];
if (!(ref2 = token[0], indexOf.call(rule.tokens, ref2) >= 0)) {
continue;
}
v = this.normalizeResult(rule, rule.lintToken(token, this.tokenApi));
if (v != null) {
errors.push(v);
}
}
return errors;
};
LexicalLinter.prototype.createError = function(ruleName, attrs) {
if (attrs == null) {
attrs = {};
}
if (attrs.lineNumber == null) {
attrs.lineNumber = this.lineNumber;
}
attrs.lineNumber += 1;
attrs.line = this.tokenApi.lines[attrs.lineNumber - 1];
return LexicalLinter.__super__.createError.call(this, ruleName, attrs);
};
return LexicalLinter;
})(BaseLinter);
},{"./base_linter.coffee":4}],7:[function(require,module,exports){
var BaseLinter, LineApi, LineLinter, configShortcuts, configStatement,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
LineApi = (function() {
function LineApi(source, config1, tokensByLine1, literate1) {
this.config = config1;
this.tokensByLine = tokensByLine1;
this.literate = literate1;
this.line = null;
this.lines = source.split('\n');
this.lineCount = this.lines.length;
this.context = {
"class": {
inClass: false,
lastUnemptyLineInClass: null,
classIndents: null
}
};
}
LineApi.prototype.lineNumber = 0;
LineApi.prototype.isLiterate = function() {
return this.literate;
};
LineApi.prototype.maintainClassContext = function(line) {
if (this.context["class"].inClass) {
if (this.lineHasToken('INDENT')) {
this.context["class"].classIndents++;
} else if (this.lineHasToken('OUTDENT')) {
this.context["class"].classIndents--;
if (this.context["class"].classIndents === 0) {
this.context["class"].inClass = false;
this.context["class"].classIndents = null;
}
}
if (!line.match(/^\s*$/)) {
this.context["class"].lastUnemptyLineInClass = this.lineNumber;
}
} else {
if (!line.match(/\\s*/)) {
this.context["class"].lastUnemptyLineInClass = null;
}
if (this.lineHasToken('CLASS')) {
this.context["class"].inClass = true;
this.context["class"].lastUnemptyLineInClass = this.lineNumber;
this.context["class"].classIndents = 0;
}
}
return null;
};
LineApi.prototype.isLastLine = function() {
return this.lineNumber === this.lineCount - 1;
};
LineApi.prototype.lineHasToken = function(tokenType, lineNumber) {
var i, len, token, tokens;
if (tokenType == null) {
tokenType = null;
}
if (lineNumber == null) {
lineNumber = null;
}
lineNumber = lineNumber != null ? lineNumber : this.lineNumber;
if (tokenType == null) {
return this.tokensByLine[lineNumber] != null;
} else {
tokens = this.tokensByLine[lineNumber];
if (tokens == null) {
return null;
}
for (i = 0, len = tokens.length; i < len; i++) {
token = tokens[i];
if (token[0] === tokenType) {
return true;
}
}
return false;
}
};
LineApi.prototype.getLineTokens = function() {
return this.tokensByLine[this.lineNumber] || [];
};
return LineApi;
})();
BaseLinter = require('./base_linter.coffee');
configStatement = /coffeelint:\s*((disable|enable)(-line)?)(?:=([\w\s,]*))?/;
configShortcuts = [[/\#.*noqa/, 'coffeelint: disable-line']];
module.exports = LineLinter = (function(superClass) {
extend(LineLinter, superClass);
LineLinter.getDirective = function(line) {
var i, len, ref, replacement, shortcut;
for (i = 0, len = configShortcuts.length; i < len; i++) {
ref = configShortcuts[i], shortcut = ref[0], replacement = ref[1];
if (line.match(shortcut)) {
return configStatement.exec(replacement);
}
}
return configStatement.exec(line);
};
function LineLinter(source, config, rules, tokensByLine, literate) {
if (literate == null) {
literate = false;
}
LineLinter.__super__.constructor.call(this, source, config, rules);
this.lineApi = new LineApi(source, config, tokensByLine, literate);
this.inlineConfig = {
enable: {},
disable: {},
'enable-line': {},
'disable-line': {}
};
}
LineLinter.prototype.acceptRule = function(rule) {
return typeof rule.lintLine === 'function';
};
LineLinter.prototype.lint = function() {
var error, errors, i, j, len, len1, line, lineNumber, ref, ref1;
errors = [];
ref = this.lineApi.lines;
for (lineNumber = i = 0, len = ref.length; i < len; lineNumber = ++i) {
line = ref[lineNumber];
this.lineApi.lineNumber = this.lineNumber = lineNumber;
this.lineApi.line = this.lineApi.lines[lineNumber];
this.lineApi.maintainClassContext(line);
this.collectInlineConfig(line);
ref1 = this.lintLine(line);
for (j = 0, len1 = ref1.length; j < len1; j++) {
error = ref1[j];
errors.push(error);
}
}
return errors;
};
LineLinter.prototype.lintLine = function(line) {
var errors, i, len, ref, rule, v;
errors = [];
ref = this.rules;
for (i = 0, len = ref.length; i < len; i++) {
rule = ref[i];
v = this.normalizeResult(rule, rule.lintLine(line, this.lineApi));
if (v != null) {
errors.push(v);
}
}
return errors;
};
LineLinter.prototype.collectInlineConfig = function(line) {
var cmd, i, len, r, ref, result, rules;
result = this.constructor.getDirective(line);
if (result != null) {
cmd = result[1];
rules = [];
if (result[4] != null) {
ref = result[4].split(',');
for (i = 0, len = ref.length; i < len; i++) {
r = ref[i];
rules.push(r.replace(/^\s+|\s+$/g, ''));
}
}
this.inlineConfig[cmd][this.lineNumber] = rules;
}
return null;
};
LineLinter.prototype.createError = function(rule, attrs) {
var ref;
if (attrs == null) {
attrs = {};
}
attrs.lineNumber = this.lineNumber + 1;
attrs.level = (ref = this.config[rule]) != null ? ref.level : void 0;
return LineLinter.__super__.createError.call(this, rule, attrs);
};
return LineLinter;
})(BaseLinter);
},{"./base_linter.coffee":4}],8:[function(require,module,exports){
var ERROR, IGNORE, WARN;
ERROR = 'error';
WARN = 'warn';
IGNORE = 'ignore';
module.exports = {
coffeescript_error: {
level: ERROR,
message: ''
}
};
},{}],9:[function(require,module,exports){
var ArrowSpacing;
module.exports = ArrowSpacing = (function() {
function ArrowSpacing() {}
ArrowSpacing.prototype.rule = {
name: 'arrow_spacing',
level: 'ignore',
message: 'Function arrows (-> and =>) must be spaced properly',
description: '<p>This rule checks to see that there is spacing before and after\nthe arrow operator that declares a function. This rule is disabled\nby default.</p> <p>Note that if arrow_spacing is enabled, and you\npass an empty function as a parameter, arrow_spacing will accept\neither a space or no space in-between the arrow operator and the\nparenthesis</p>\n<pre><code># Both of this will not trigger an error,\n# even with arrow_spacing enabled.\nx(-> 3)\nx( -> 3)\n\n# However, this will trigger an error\nx((a,b)-> 3)\n</code>\n</pre>'
};
ArrowSpacing.prototype.tokens = ['->', '=>'];
ArrowSpacing.prototype.lintToken = function(token, tokenApi) {
var pp;
pp = tokenApi.peek(-1);
if (!pp) {
return;
}
if (!token.spaced && tokenApi.peek(1)[0] === 'INDENT' && tokenApi.peek(2)[0] === 'OUTDENT') {
return null;
} else if (!(((token.spaced != null) || (token.newLine != null)) && (((pp.spaced != null) || pp[0] === 'TERMINATOR') || (pp.generated != null) || pp[0] === 'INDENT' || (pp[1] === '(' && (pp.generated == null))))) {
return true;
} else {
return null;
}
};
return ArrowSpacing;
})();
},{}],10:[function(require,module,exports){
var BracesSpacing;
module.exports = BracesSpacing = (function() {
function BracesSpacing() {}
BracesSpacing.prototype.rule = {
name: 'braces_spacing',
level: 'ignore',
spaces: 0,
empty_object_spaces: 0,
message: 'Curly braces must have the proper spacing',
description: 'This rule checks to see that there is the proper spacing inside\ncurly braces. The spacing amount is specified by "spaces".\nThe spacing amount for empty objects is specified by\n"empty_object_spaces".\n\n<pre><code>\n# Spaces is 0\n{a: b} # Good\n{a: b } # Bad\n{ a: b} # Bad\n{ a: b } # Bad\n\n# Spaces is 1\n{a: b} # Bad\n{a: b } # Bad\n{ a: b} # Bad\n{ a: b } # Good\n{ a: b } # Bad\n{ a: b } # Bad\n{ a: b } # Bad\n\n# Empty Object Spaces is 0\n{} # Good\n{ } # Bad\n\n# Empty Object Spaces is 1\n{} # Bad\n{ } # Good\n</code></pre>\n\nThis rule is disabled by default.'
};
BracesSpacing.prototype.tokens = ['{', '}'];
BracesSpacing.prototype.distanceBetweenTokens = function(firstToken, secondToken) {
return secondToken[2].first_column - firstToken[2].last_column - 1;
};
BracesSpacing.prototype.findNearestToken = function(token, tokenApi, difference) {
var nearestToken, totalDifference;
totalDifference = 0;
while (true) {
totalDifference += difference;
nearestToken = tokenApi.peek(totalDifference);
if (nearestToken[0] === 'OUTDENT' || (nearestToken.generated != null)) {
continue;
}
return nearestToken;
}
};
BracesSpacing.prototype.tokensOnSameLine = function(firstToken, secondToken) {
return firstToken[2].first_line === secondToken[2].first_line;
};
BracesSpacing.prototype.getExpectedSpaces = function(tokenApi, firstToken, secondToken) {
var config, ref;
config = tokenApi.config[this.rule.name];
if (firstToken[0] === '{' && secondToken[0] === '}') {
return (ref = config.empty_object_spaces) != null ? ref : config.spaces;
} else {
return config.spaces;
}
};
BracesSpacing.prototype.lintToken = function(token, tokenApi) {
var actual, expected, firstToken, msg, ref, secondToken;
if (token.generated) {
return null;
}
ref = token[0] === '{' ? [token, this.findNearestToken(token, tokenApi, 1)] : [this.findNearestToken(token, tokenApi, -1), token], firstToken = ref[0], secondToken = ref[1];
if (!this.tokensOnSameLine(firstToken, secondToken)) {
return null;
}
expected = this.getExpectedSpaces(tokenApi, firstToken, secondToken);
actual = this.distanceBetweenTokens(firstToken, secondToken);
if (actual === expected) {
return null;
} else {
msg = "There should be " + expected + " space";
if (expected !== 1) {
msg += 's';
}
msg += " inside \"" + token[0] + "\"";
return {
context: msg
};
}
};
return BracesSpacing;
})();
},{}],11:[function(require,module,exports){
var CamelCaseClasses, regexes;
regexes = {
camelCase: /^[A-Z_][a-zA-Z\d]*$/
};
module.exports = CamelCaseClasses = (function() {
function CamelCaseClasses() {}
CamelCaseClasses.prototype.rule = {
name: 'camel_case_classes',
level: 'error',
message: 'Class name should be UpperCamelCased',
description: 'This rule mandates that all class names are UpperCamelCased.\nCamel casing class names is a generally accepted way of\ndistinguishing constructor functions - which require the \'new\'\nprefix to behave properly - from plain old functions.\n<pre>\n<code># Good!\nclass BoaConstrictor\n\n# Bad!\nclass boaConstrictor\n</code>\n</pre>\nThis rule is enabled by default.'
};
CamelCaseClasses.prototype.tokens = ['CLASS'];
CamelCaseClasses.prototype.lintToken = function(token, tokenApi) {
var className, offset, ref, ref1, ref2;
if ((token.newLine != null) || ((ref = tokenApi.peek()[0]) === 'INDENT' || ref === 'EXTENDS')) {
return null;
}
className = null;
offset = 1;
while (!className) {
if (((ref1 = tokenApi.peek(offset + 1)) != null ? ref1[0] : void 0) === '.') {
offset += 2;
} else if (((ref2 = tokenApi.peek(offset)) != null ? ref2[0] : void 0) === '@') {
offset += 1;
} else {
className = tokenApi.peek(offset)[1];
}
}
if (!regexes.camelCase.test(className)) {
return {
context: "class name: " + className
};
}
};
return CamelCaseClasses;
})();
},{}],12:[function(require,module,exports){
var ColonAssignmentSpacing;
module.exports = ColonAssignmentSpacing = (function() {
function ColonAssignmentSpacing() {}
ColonAssignmentSpacing.prototype.rule = {
name: 'colon_assignment_spacing',
level: 'ignore',
message: 'Colon assignment without proper spacing',
spacing: {
left: 0,
right: 0
},
description: '<p>This rule checks to see that there is spacing before and\nafter the colon in a colon assignment (i.e., classes, objects).\nThe spacing amount is specified by\nspacing.left and spacing.right, respectively.\nA zero value means no spacing required.\n</p>\n<pre><code>\n#\n# If spacing.left and spacing.right is 1\n#\n\n# Doesn\'t throw an error\nobject = {spacing : true}\nclass Dog\n canBark : true\n\n# Throws an error\nobject = {spacing: true}\nclass Cat\n canBark: false\n</code></pre>'
};
ColonAssignmentSpacing.prototype.tokens = [':'];
ColonAssignmentSpacing.prototype.lintToken = function(token, tokenApi) {
var checkSpacing, getSpaceFromToken, isLeftSpaced, isRightSpaced, leftSpacing, nextToken, previousToken, ref, ref1, rightSpacing, spaceRules;
spaceRules = tokenApi.config[this.rule.name].spacing;
previousToken = tokenApi.peek(-1);
nextToken = tokenApi.peek(1);
getSpaceFromToken = function(direction) {
switch (direction) {
case 'left':
return token[2].first_column - previousToken[2].last_column - 1;
case 'right':
return nextToken[2].first_column - token[2].first_column - 1;
}
};
checkSpacing = function(direction) {
var isSpaced, spacing;
spacing = getSpaceFromToken(direction);
isSpaced = spacing < 0 ? true : spacing === parseInt(spaceRules[direction]);
return [isSpaced, spacing];
};
ref = checkSpacing('left'), isLeftSpaced = ref[0], leftSpacing = ref[1];
ref1 = checkSpacing('right'), isRightSpaced = ref1[0], rightSpacing = ref1[1];
if (isLeftSpaced && isRightSpaced) {
return null;
} else {
return {
context: "Incorrect spacing around column " + token[2].first_column
};
}
};
return ColonAssignmentSpacing;
})();
},{}],13:[function(require,module,exports){
var CyclomaticComplexity;
module.exports = CyclomaticComplexity = (function() {
function CyclomaticComplexity() {}
CyclomaticComplexity.prototype.rule = {
name: 'cyclomatic_complexity',
level: 'ignore',
message: 'The cyclomatic complexity is too damn high',
value: 10,
description: 'Examine the complexity of your function.'
};
CyclomaticComplexity.prototype.getComplexity = function(node) {
var complexity, name, ref;
name = this.astApi.getNodeName(node);
complexity = name === 'If' || name === 'While' || name === 'For' || name === 'Try' ? 1 : name === 'Op' && ((ref = node.operator) === '&&' || ref === '||') ? 1 : name === 'Switch' ? node.cases.length : 0;
return complexity;
};
CyclomaticComplexity.prototype.lintAST = function(node, astApi) {
this.astApi = astApi;
this.lintNode(node);
return void 0;
};
CyclomaticComplexity.prototype.lintNode = function(node) {
var complexity, error, name, ref, rule;
name = (ref = this.astApi) != null ? ref.getNodeName(node) : void 0;
complexity = this.getComplexity(node);
node.eachChild((function(_this) {
return function(childNode) {
var childComplexity, ref1;
childComplexity = _this.lintNode(childNode);
if (((ref1 = _this.astApi) != null ? ref1.getNodeName(childNode) : void 0) !== 'Code') {
return complexity += childComplexity;
}
};
})(this));
rule = this.astApi.config[this.rule.name];
if (name === 'Code' && complexity >= rule.value) {
error = this.astApi.createError({
context: complexity + 1,
lineNumber: node.locationData.first_line + 1,
lineNumberEnd: node.locationData.last_line + 1
});
if (error) {
this.errors.push(error);
}
}
return complexity;
};
return CyclomaticComplexity;
})();
},{}],14:[function(require,module,exports){
var DuplicateKey;
module.exports = DuplicateKey = (function() {
DuplicateKey.prototype.rule = {
name: 'duplicate_key',
level: 'error',
message: 'Duplicate key defined in object or class',
description: 'Prevents defining duplicate keys in object literals and classes'
};
DuplicateKey.prototype.tokens = ['IDENTIFIER', '{', '}'];
function DuplicateKey() {
this.braceScopes = [];
}
DuplicateKey.prototype.lintToken = function(arg, tokenApi) {
var type;
type = arg[0];
if (type === '{' || type === '}') {
this.lintBrace.apply(this, arguments);
return void 0;
}
if (type === 'IDENTIFIER') {
return this.lintIdentifier.apply(this, arguments);
}
};
DuplicateKey.prototype.lintIdentifier = function(token, tokenApi) {
var key, nextToken, previousToken;
key = token[1];
if (this.currentScope == null) {
return null;
}
nextToken = tokenApi.peek(1);
if (nextToken[1] !== ':') {
return null;
}
previousToken = tokenApi.peek(-1);
if (previousToken[0] === '@') {
key = "@" + key;
}
key = "identifier-" + key;
if (this.currentScope[key]) {
return true;
} else {
this.currentScope[key] = token;
return null;
}
};
DuplicateKey.prototype.lintBrace = function(token) {
if (token[0] === '{') {
if (this.currentScope != null) {
this.braceScopes.push(this.currentScope);
}
this.currentScope = {};
} else {
this.currentScope = this.braceScopes.pop();
}
return null;
};
return DuplicateKey;
})();
},{}],15:[function(require,module,exports){
var EmptyConstructorNeedsParens;
module.exports = EmptyConstructorNeedsParens = (function() {
function EmptyConstructorNeedsParens() {}
EmptyConstructorNeedsParens.prototype.rule = {
name: 'empty_constructor_needs_parens',
level: 'ignore',
message: 'Invoking a constructor without parens and without arguments',
description: 'Requires constructors with no parameters to include the parens'
};
EmptyConstructorNeedsParens.prototype.tokens = ['UNARY'];
EmptyConstructorNeedsParens.prototype.lintToken = function(token, tokenApi) {
var expectedCallStart, expectedIdentifier, identifierIndex, peek, ref;
if (token[1] === 'new') {
peek = tokenApi.peek.bind(tokenApi);
identifierIndex = 1;
while (true) {
expectedIdentifier = peek(identifierIndex);
expectedCallStart = peek(identifierIndex + 1);
if ((expectedIdentifier != null ? expectedIdentifier[0] : void 0) === 'IDENTIFIER') {
if ((expectedCallStart != null ? expectedCallStart[0] : void 0) === '.') {
identifierIndex += 2;
continue;
}
if ((expectedCallStart != null ? expectedCallStart[0] : void 0) === 'INDEX_START') {
while (((ref = peek(identifierIndex)) != null ? ref[0] : void 0) !== 'INDEX_END') {
identifierIndex++;
}
continue;
}
}
break;
}
if ((expectedIdentifier != null ? expectedIdentifier[0] : void 0) === 'IDENTIFIER' && (expectedCallStart != null)) {
return this.handleExpectedCallStart(expectedCallStart);
}
}
};
EmptyConstructorNeedsParens.prototype.handleExpectedCallStart = function(expectedCallStart) {
if (expectedCallStart[0] !== 'CALL_START') {
return true;
}
};
return EmptyConstructorNeedsParens;
})();
},{}],16:[function(require,module,exports){
var EnsureComprehensions,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
module.exports = EnsureComprehensions = (function() {
function EnsureComprehensions() {}
EnsureComprehensions.prototype.rule = {
name: 'ensure_comprehensions',
level: 'warn',
message: 'Comprehensions must have parentheses around them',
description: 'This rule makes sure that parentheses are around comprehensions.'
};
EnsureComprehensions.prototype.tokens = ['FOR'];
EnsureComprehensions.prototype.forBlock = false;
EnsureComprehensions.prototype.lintToken = function(token, tokenApi) {
var atEqual, idents, numCallEnds, numCallStarts, numParenEnds, numParenStarts, peeker, prevIdents, prevToken, ref, ref1;
idents = this.findIdents(tokenApi);
if (this.forBlock) {
this.forBlock = false;
return;
}
peeker = -1;
atEqual = false;
numCallEnds = 0;
numCallStarts = 0;
numParenStarts = 0;
numParenEnds = 0;
prevIdents = [];
while ((prevToken = tokenApi.peek(peeker))) {
if (prevToken[0] === 'CALL_END') {
numCallEnds++;
}
if (prevToken[0] === 'CALL_START') {
numCallStarts++;
}
if (prevToken[0] === '(') {
numParenStarts++;
}
if (prevToken[0] === ')') {
numParenEnds++;
}
if (prevToken[0] === 'IDENTIFIER') {
if (!atEqual) {
prevIdents.push(prevToken[1]);
} else if (ref = prevToken[1], indexOf.call(idents, ref) >= 0) {
return;
}
}
if (((ref1 = prevToken[0]) === '(' || ref1 === '->' || ref1 === 'TERMINATOR') || (prevToken.newLine != null)) {
break;
}
if (prevToken[0] === '=' && numParenEnds === numParenStarts) {
atEqual = true;
}
peeker--;
}
if (atEqual && numCallStarts === numCallEnds) {
return {
context: ''
};
}
};
EnsureComprehensions.prototype.findIdents = function(tokenApi) {
var idents, nextToken, peeker, ref;
peeker = 1;
idents = [];
while ((nextToken = tokenApi.peek(peeker))) {
if (nextToken[0] === 'IDENTIFIER') {
idents.push(nextToken[1]);
}
if ((ref = nextToken[0]) === 'FORIN' || ref === 'FOROF') {
break;
}
peeker++;
}
while ((nextToken = tokenApi.peek(peeker))) {
if (nextToken[0] === 'TERMINATOR') {
break;
}
if (nextToken[0] === 'INDENT') {
this.forBlock = true;
break;
}
peeker++;
}
return idents;
};
return EnsureComprehensions;
})();
},{}],17:[function(require,module,exports){
var EOLLast;
module.exports = EOLLast = (function() {
function EOLLast() {}
EOLLast.prototype.rule = {
name: 'eol_last',
level: 'ignore',
message: 'File does not end with a single newline',
description: 'Checks that the file ends with a single newline'
};
EOLLast.prototype.lintLine = function(line, lineApi) {
var isNewline, previousIsNewline;
if (!lineApi.isLastLine()) {
return null;
}
isNewline = line.length === 0;
previousIsNewline = lineApi.lineCount > 1 ? lineApi.lines[lineApi.lineNumber - 1].length === 0 : false;
if (!(isNewline && !previousIsNewline)) {
return true;
}
};
return EOLLast;
})();
},{}],18:[function(require,module,exports){
var Indentation,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
module.exports = Indentation = (function() {
Indentation.prototype.rule = {
name: 'indentation',
value: 2,
level: 'error',
message: 'Line contains inconsistent indentation',
description: 'This rule imposes a standard number of spaces to be used for\nindentation. Since whitespace is significant in CoffeeScript, it\'s\ncritical that a project chooses a standard indentation format and\nstays consistent. Other roads lead to darkness. <pre> <code>#\nEnabling this option will prevent this ugly\n# but otherwise valid CoffeeScript.\ntwoSpaces = () ->\n fourSpaces = () ->\n eightSpaces = () ->\n \'this is valid CoffeeScript\'\n\n</code>\n</pre>\nTwo space indentation is enabled by default.'
};
Indentation.prototype.tokens = ['INDENT', '[', ']', '.'];
Indentation.prototype.keywords = ['->', '=>', '@', 'CATCH', 'CLASS', 'ELSE', 'FINALLY', 'FOR', 'FORIN', 'FOROF', 'IDENTIFIER', 'IF', 'LEADING_WHEN', 'LOOP', 'RETURN', 'SWITCH', 'THROW', 'TRY', 'UNTIL', 'WHEN', 'WHILE', 'YIELD'];
function Indentation() {
this.arrayTokens = [];
}
Indentation.prototype.lintToken = function(token, tokenApi) {
var currentLine, expected, ignoreIndent, isArrayIndent, isMultiline, lineNumber, lines, numIndents, previous, previousSymbol, ref, ref1, ref2, type;
type = token[0], numIndents = token[1], (ref = token[2], lineNumber = ref.first_line);
lines = tokenApi.lines, lineNumber = tokenApi.lineNumber;
expected = tokenApi.config[this.rule.name].value;
if (type === '.') {
currentLine = lines[lineNumber];
if (((ref1 = currentLine.match(/\S/)) != null ? ref1[0] : void 0) === '.') {
return this.handleChain(tokenApi, expected);
}
return void 0;
}
if (type === '[' || type === ']') {
this.lintArray(token);
return void 0;
}
if ((token.generated != null) || (token.explicit != null)) {
return null;
}
previous = tokenApi.peek(-1);
isArrayIndent = this.inArray() && (previous != null ? previous.newLine : void 0);
previousSymbol = (ref2 = tokenApi.peek(-1)) != null ? ref2[0] : void 0;
isMultiline = previousSymbol === '=' || previousSymbol === ',';
ignoreIndent = isArrayIndent || isMultiline;
numIndents = this.getCorrectIndent(tokenApi);
if (!ignoreIndent && !(indexOf.call(numIndents, expected) >= 0)) {
return {
context: "Expected " + expected + " got " + numIndents[0]
};
}
};
Indentation.prototype.inArray = function() {
return this.arrayTokens.length > 0;
};
Indentation.prototype.lintArray = function(token) {
if (token[0] === '[') {
this.arrayTokens.push(token);
} else if (token[0] === ']') {
this.arrayTokens.pop();
}
return null;
};
Indentation.prototype.handleChain = function(tokenApi, expected) {
var callStart, checkNum, currIsIndent, currentLine, currentSpaces, findCallStart, lastCheck, lineNumber, lines, numIndents, prevIsIndent, prevLine, prevNum, prevSpaces, ref, ref1;
lastCheck = 1;
callStart = 1;
prevNum = 1;
lineNumber = tokenApi.lineNumber, lines = tokenApi.lines;
currentLine = lines[lineNumber];
findCallStart = tokenApi.peek(-callStart);
while (findCallStart && findCallStart[0] !== 'TERMINATOR') {
lastCheck = findCallStart[2].first_line;
callStart += 1;
findCallStart = tokenApi.peek(-callStart);
}
while ((lineNumber - prevNum > lastCheck) && !/^\s*\./.test(lines[lineNumber - prevNum])) {
prevNum += 1;
}
checkNum = lineNumber - prevNum;
if (checkNum >= 0) {
prevLine = lines[checkNum];
if (prevLine.match(/\S/)[0] === '.' || checkNum === lastCheck) {
currentSpaces = (ref = currentLine.match(/\S/)) != null ? ref.index : void 0;
prevSpaces = (ref1 = prevLine.match(/\S/)) != null ? ref1.index : void 0;
numIndents = currentSpaces - prevSpaces;
prevIsIndent = prevSpaces % expected !== 0;
currIsIndent = currentSpaces % expected !== 0;
if (prevIsIndent && currIsIndent) {
numIndents = currentSpaces;
}
if (numIndents % expected !== 0) {
return {
context: "Expected " + expected + " got " + numIndents
};
}
}
}
};
Indentation.prototype.grabLineTokens = function(tokenApi, lineNumber, all) {
var i, k, len, len1, ref, ref1, results, results1, tok, tokensByLine;
if (all == null) {
all = false;
}
tokensByLine = tokenApi.tokensByLine;
while (!((tokensByLine[lineNumber] != null) || lineNumber === 0)) {
lineNumber--;
}
if (all) {
ref = tokensByLine[lineNumber];
results = [];
for (i = 0, len = ref.length; i < len; i++) {
tok = ref[i];
results.push(tok);
}
return results;
} else {
ref1 = tokensByLine[lineNumber];
results1 = [];
for (k = 0, len1 = ref1.length; k < len1; k++) {
tok = ref1[k];
if ((tok.generated == null) && tok[0] !== 'OUTDENT') {
results1.push(tok);
}
}
return results1;
}
};
Indentation.prototype.getCorrectIndent = function(tokenApi) {
var _, curIndent, i, j, len, lineNumber, lines, prevIndent, prevNum, prevTokens, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ret, skipAssign, t, tokens, tryLine;
lineNumber = tokenApi.lineNumber, lines = tokenApi.lines, tokens = tokenApi.tokens;
curIndent = (ref = lines[lineNumber].match(/\S/)) != null ? ref.index : void 0;
prevNum = 1;
while (/^\s*(#|$)/.test(lines[lineNumber - prevNum])) {
prevNum += 1;
}
prevTokens = this.grabLineTokens(tokenApi, lineNumber - prevNum);
if (((ref1 = prevTokens[0]) != null ? ref1[0] : void 0) === 'INDENT') {
return [curIndent - ((ref2 = prevTokens[1]) != null ? ref2[2].first_column : void 0), curIndent - prevTokens[0][1]];
} else {
prevIndent = (ref3 = prevTokens[0]) != null ? ref3[2].first_column : void 0;
for (j = i = 0, len = prevTokens.length; i < len; j = ++i) {
_ = prevTokens[j];
if (!(prevTokens[j][0] === '=' && ((ref4 = prevTokens[j + 1]) != null ? ref4[0] : void 0) === 'IF')) {
continue;
}
skipAssign = curIndent - prevTokens[j + 1][2].first_column;
ret = curIndent - prevIndent;
if (skipAssign < 0) {
return [ret];
}
return [skipAssign, ret];
}
while (prevIndent > curIndent) {
tryLine = lineNumber - prevNum;
prevTokens = this.grabLineTokens(tokenApi, tryLine, true);
if (((ref5 = prevTokens[0]) != null ? ref5[0] : void 0) === 'INDENT') {
prevIndent = prevTokens[0][1];
prevTokens = prevTokens.slice(1);
}
t = 0;
while (!((prevTokens[t] == null) || (ref6 = prevTokens[t][0], indexOf.call(this.keywords, ref6) >= 0))) {
t++;
}
prevTokens = prevTokens.slice(t);
prevNum++;
if (prevTokens[0] == null) {
continue;
}
prevIndent = (ref7 = prevTokens[0]) != null ? ref7[2].first_column : void 0;
}
}
return [curIndent - prevIndent];
};
return Indentation;
})();
},{}],19:[function(require,module,exports){
var LineEndings;
module.exports = LineEndings = (function() {
function LineEndings() {}
LineEndings.prototype.rule = {
name: 'line_endings',
level: 'ignore',
value: 'unix',
message: 'Line contains incorrect line endings',
description: 'This rule ensures your project uses only <tt>windows</tt> or\n<tt>unix</tt> line endings. This rule is disabled by default.'
};
LineEndings.prototype.lintLine = function(line, lineApi) {
var ending, lastChar, ref, valid;
ending = (ref = lineApi.config[this.rule.name]) != null ? ref.value : void 0;
if (!ending || lineApi.isLastLine() || !line) {
return null;
}
lastChar = line[line.length - 1];
valid = (function() {
if (ending === 'windows') {
return lastChar === '\r';
} else if (ending === 'unix') {
return lastChar !== '\r';
} else {
throw new Error("unknown line ending type: " + ending);
}
})();
if (!valid) {
return {
context: "Expected " + ending
};
} else {
return null;
}
};
return LineEndings;
})();
},{}],20:[function(require,module,exports){
var MaxLineLength, regexes;
regexes = {
literateComment: /^\#\s/,
longUrlComment: /^\s*\#\s*http[^\s]+$/
};
module.exports = MaxLineLength = (function() {
function MaxLineLength() {}
MaxLineLength.prototype.rule = {
name: 'max_line_length',
value: 80,
level: 'error',
limitComments: true,
message: 'Line exceeds maximum allowed length',
description: 'This rule imposes a maximum line length on your code. <a\nhref="https://web.archive.org/web/20180612201411/http://www.python.org/dev/peps/pep-0008/">Python\'s style\nguide</a> does a good job explaining why you might want to limit the\nlength of your lines, though this is a matter of taste.\n\nLines can be no longer than eighty characters by default.'
};
MaxLineLength.prototype.lintLine = function(line, lineApi) {
var limitComments, lineLength, max, ref, ref1;
max = (ref = lineApi.config[this.rule.name]) != null ? ref.value : void 0;
limitComments = (ref1 = lineApi.config[this.rule.name]) != null ? ref1.limitComments : void 0;
lineLength = line.replace(/\s+$/, '').length;
if (lineApi.isLiterate() && regexes.literateComment.test(line)) {
lineLength -= 2;
}
if (max && max < lineLength && !regexes.longUrlComment.test(line)) {
if (!limitComments) {
if (lineApi.getLineTokens().length === 0) {
return;
}
}
return {
context: "Length is " + lineLength + ", max is " + max
};
}
};
return MaxLineLength;
})();
},{}],21:[function(require,module,exports){
var MissingFatArrows, any, containsButIsnt,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
any = function(arr, test) {
return arr.reduce((function(res, elt) {
return res || test(elt);
}), false);
};
containsButIsnt = function(node, nIsThis, nIsClass) {
var target;
target = void 0;
node.traverseChildren(false, function(n) {
if (nIsClass(n)) {
return false;
}
if (nIsThis(n)) {
target = n;
return false;
}
});
return target;
};
module.exports = MissingFatArrows = (function() {
function MissingFatArrows() {
this.isFatArrowCode = bind(this.isFatArrowCode, this);
this.isThis = bind(this.isThis, this);
this.isObject = bind(this.isObject, this);
this.isValue = bind(this.isValue, this);
this.isClass = bind(this.isClass, this);
this.isCode = bind(this.isCode, this);
}
MissingFatArrows.prototype.rule = {
name: 'missing_fat_arrows',
level: 'ignore',
is_strict: false,
message: 'Used `this` in a function without a fat arrow',
description: 'Warns when you use `this` inside a function that wasn\'t defined\nwith a fat arrow. This rule does not apply to methods defined in a\nclass, since they have `this` bound to the class instance (or the\nclass itself, for class methods). The option `is_strict` is\navailable for checking bindings of class methods.\n\nIt is impossible to statically determine whether a function using\n`this` will be bound with the correct `this` value due to language\nfeatures like `Function.prototype.call` and\n`Function.prototype.bind`, so this rule may produce false positives.'
};
MissingFatArrows.prototype.lintAST = function(node, astApi) {
this.astApi = astApi;
this.lintNode(node);
return void 0;
};
MissingFatArrows.prototype.lintNode = function(node, methods) {
var error, isStrict, ref;
if (methods == null) {
methods = [];
}
isStrict = (ref = this.astApi.config[this.rule.name]) != null ? ref.is_strict : void 0;
if (this.isPrototype(node)) {
return;
}
if (this.isConstructor(node)) {
return;
}
if ((!this.isFatArrowCode(node)) && (isStrict ? true : indexOf.call(methods, node) < 0) && (this.needsFatArrow(node))) {
error = this.astApi.createError({
lineNumber: node.locationData.first_line + 1
});
this.errors.push(error);
}
return node.eachChild((function(_this) {
return function(child) {
return _this.lintNode(child, (function() {
switch (false) {
case !this.isClass(node):
return this.methodsOfClass(node);
case !this.isCode(node):
return [];
default:
return methods;
}
}).call(_this));
};
})(this));
};
MissingFatArrows.prototype.isCode = function(node) {
return this.astApi.getNodeName(node) === 'Code';
};
MissingFatArrows.prototype.isClass = function(node) {
return this.astApi.getNodeName(node) === 'Class';
};
MissingFatArrows.prototype.isValue = function(node) {
return this.astApi.getNodeName(node) === 'Value';
};
MissingFatArrows.prototype.isObject = function(node) {
return this.astApi.getNodeName(node) === 'Obj';
};
MissingFatArrows.prototype.isPrototype = function(node) {
var i, ident, len, props, ref, ref1;
props = (node != null ? (ref = node.variable) != null ? ref.properties : void 0 : void 0) || [];
for (i = 0, len = props.length; i < len; i++) {
ident = props[i];
if (((ref1 = ident.name) != null ? ref1.value : void 0) === 'prototype') {
return true;
}
}
return false;
};
MissingFatArrows.prototype.isThis = function(node) {
return this.isValue(node) && node.base.value === 'this';
};
MissingFatArrows.prototype.isFatArrowCode = function(node) {
return this.isCode(node) && node.bound;
};
MissingFatArrows.prototype.isConstructor = function(node) {
var ref, ref1;
return ((ref = node.variable) != null ? (ref1 = ref.base) != null ? ref1.value : void 0 : void 0) === 'constructor';
};
MissingFatArrows.prototype.needsFatArrow = function(node) {
return this.isCode(node) && (any(node.params, (function(_this) {
return function(param) {
return param.contains(_this.isThis) != null;
};
})(this)) || containsButIsnt(node.body, this.isThis, this.isClass));
};
MissingFatArrows.prototype.methodsOfClass = function(classNode) {
var bodyNodes, returnNode;
bodyNodes = classNode.body.expressions;
returnNode = bodyNodes[bodyNodes.length - 1];
if ((returnNode != null) && this.isValue(returnNode) && this.isObject(returnNode.base)) {
return returnNode.base.properties.map(function(assignNode) {
return assignNode.value;
}).filter(this.isCode);
} else {
return [];
}
};
return MissingFatArrows;
})();
},{}],22:[function(require,module,exports){
var NewlinesAfterClasses;
module.exports = NewlinesAfterClasses = (function() {
function NewlinesAfterClasses() {}
NewlinesAfterClasses.prototype.rule = {
name: 'newlines_after_classes',
value: 3,
level: 'ignore',
message: 'Wrong count of newlines between a class and other code',
description: '<p>Checks the number of newlines between classes and other code.</p>\n\nOptions:\n- <pre><code>value</code></pre> - The number of required newlines\nafter class definitions. Defaults to 3.'
};
NewlinesAfterClasses.prototype.tokens = ['CLASS', '}', '{'];
NewlinesAfterClasses.prototype.classBracesCount = 0;
NewlinesAfterClasses.prototype.classCount = 0;
NewlinesAfterClasses.prototype.lintToken = function(token, tokenApi) {
var afters, befores, comment, ending, got, lineNumber, lines, numIndents, outdent, ref, ref1, ref2, start, trueLine, type;
type = token[0], numIndents = token[1], (ref = token[2], lineNumber = ref.first_line);
lines = tokenApi.lines;
ending = tokenApi.config[this.rule.name].value;
if (type === 'CLASS') {
this.classCount++;
}
if (this.classCount > 0 && (token.generated != null)) {
if (type === '{' && ((ref1 = token.origin) != null ? ref1[0] : void 0) === ':') {
this.classBracesCount++;
}
if (type === '}' && ((ref2 = token.origin) != null ? ref2[0] : void 0) === 'OUTDENT') {
this.classBracesCount--;
this.classCount--;
if (this.classCount === 0 && this.classBracesCount === 0) {
befores = 1;
afters = 1;
comment = 0;
outdent = token.origin[2].first_line;
start = Math.min(lineNumber, outdent);
trueLine = Infinity;
while (/^\s*(#|$)/.test(lines[start + afters])) {
if (/^\s*#/.test(lines[start + afters])) {
comment += 1;
} else {
trueLine = Math.min(trueLine, start + afters);
}
afters += 1;
}
while (/^\s*(#|$)/.test(lines[start - befores])) {
if (/^\s*#/.test(lines[start - befores])) {
comment += 1;
} else {
trueLine = Math.min(trueLine, start - befores);
}
befores += 1;
}
got = afters + befores - comment - 2;
if (got !== ending && trueLine + ending <= lines.length) {
return {
context: "Expected " + ending + " got " + got,
lineNumber: trueLine
};
}
}
}
}
};
return NewlinesAfterClasses;
})();
},{}],23:[function(require,module,exports){
var NoBackticks;
module.exports = NoBackticks = (function() {
function NoBackticks() {}
NoBackticks.prototype.rule = {
name: 'no_backticks',
level: 'error',
message: 'Backticks are forbidden',
description: 'Backticks allow snippets of JavaScript to be embedded in\nCoffeeScript. While some folks consider backticks useful in a few\nniche circumstances, they should be avoided because so none of\nJavaScript\'s "bad parts", like <tt>with</tt> and <tt>eval</tt>,\nsneak into CoffeeScript.\nThis rule is enabled by default.'
};
NoBackticks.prototype.tokens = ['JS'];
NoBackticks.prototype.lintToken = function(token, tokenApi) {
return true;
};
return NoBackticks;
})();
},{}],24:[function(require,module,exports){
var NoDebugger;
module.exports = NoDebugger = (function() {
function NoDebugger() {}
NoDebugger.prototype.rule = {
name: 'no_debugger',
level: 'warn',
message: 'Found debugging code',
console: false,
description: 'This rule detects `debugger` and optionally `console` calls\nThis rule is `warn` by default.'
};
NoDebugger.prototype.tokens = ['DEBUGGER', 'IDENTIFIER'];
NoDebugger.prototype.lintToken = function(token, tokenApi) {
var method, ref, ref1;
if (token[0] === 'DEBUGGER') {
return {
context: "found '" + token[0] + "'"
};
}
if ((ref = tokenApi.config[this.rule.name]) != null ? ref.console : void 0) {
if (token[1] === 'console' && ((ref1 = tokenApi.peek(1)) != null ? ref1[0] : void 0) === '.') {
method = tokenApi.peek(2);
return {
context: "found 'console." + method[1] + "'"
};
}
}
};
return NoDebugger;
})();
},{}],25:[function(require,module,exports){
var NoEmptyFunctions, isEmptyCode;
isEmptyCode = function(node, astApi) {
var nodeName;
nodeName = astApi.getNodeName(node);
return nodeName === 'Code' && node.body.isEmpty();
};
module.exports = NoEmptyFunctions = (function() {
function NoEmptyFunctions() {}
NoEmptyFunctions.prototype.rule = {
name: 'no_empty_functions',
level: 'ignore',
message: 'Empty function',
description: 'Disallows declaring empty functions. The goal of this rule is that\nunintentional empty callbacks can be detected:\n<pre>\n<code>someFunctionWithCallback ->\ndoSomethingSignificant()\n</code>\n</pre>\nThe problem is that the call to\n<tt>doSomethingSignificant</tt> will be made regardless\nof <tt>someFunctionWithCallback</tt>\'s execution. It can\nbe because you did not indent the call to\n<tt>doSomethingSignificant</tt> properly.\n\nIf you really meant that <tt>someFunctionWithCallback</tt>\nshould call a callback that does nothing, you can write your code\nthis way:\n<pre>\n<code>someFunctionWithCallback ->\n undefined\ndoSomethingSignificant()\n</code>\n</pre>'
};
NoEmptyFunctions.prototype.lintAST = function(node, astApi) {
this.lintNode(node, astApi);
return void 0;
};
NoEmptyFunctions.prototype.lintNode = function(node, astApi) {
var error;
if (isEmptyCode(node, astApi)) {
error = astApi.createError({
lineNumber: node.locationData.first_line + 1
});
this.errors.push(error);
}
return node.eachChild((function(_this) {
return function(child) {
return _this.lintNode(child, astApi);
};
})(this));
};
return NoEmptyFunctions;
})();
},{}],26:[function(require,module,exports){
var NoEmptyParamList;
module.exports = NoEmptyParamList = (function() {
function NoEmptyParamList() {}
NoEmptyParamList.prototype.rule = {
name: 'no_empty_param_list',
level: 'ignore',
message: 'Empty parameter list is forbidden',
description: 'This rule prohibits empty parameter lists in function definitions.\n<pre>\n<code># The empty parameter list in here is unnecessary:\nmyFunction = () -&gt;\n\n# We might favor this instead:\nmyFunction = -&gt;\n</code>\n</pre>\nEmpty parameter lists are permitted by default.'
};
NoEmptyParamList.prototype.tokens = ['PARAM_START'];
NoEmptyParamList.prototype.lintToken = function(token, tokenApi) {
var nextType;
nextType = tokenApi.peek()[0];
return nextType === 'PARAM_END';
};
return NoEmptyParamList;
})();
},{}],27:[function(require,module,exports){
var NoImplicitBraces;
module.exports = NoImplicitBraces = (function() {
NoImplicitBraces.prototype.rule = {
name: 'no_implicit_braces',
level: 'ignore',
message: 'Implicit braces are forbidden',
strict: true,
description: 'This rule prohibits implicit braces when declaring object literals.\nImplicit braces can make code more difficult to understand,\nespecially when used in combination with optional parenthesis.\n<pre>\n<code># Do you find this code ambiguous? Is it a\n# function call with three arguments or four?\nmyFunction a, b, 1:2, 3:4\n\n# While the same code written in a more\n# explicit manner has no ambiguity.\nmyFunction(a, b, {1:2, 3:4})\n</code>\n</pre>\nImplicit braces are permitted by default, since their use is\nidiomatic CoffeeScript.'
};
NoImplicitBraces.prototype.tokens = ['{', 'OUTDENT', 'CLASS', 'IDENTIFIER', 'EXTENDS'];
function NoImplicitBraces() {
this.isClass = false;
this.className = '';
}
NoImplicitBraces.prototype.lintToken = function(token, tokenApi) {
var _type, _val, c, lineNum, peekIdent, prevToken, ref, ref1, type, val;
type = token[0], val = token[1], lineNum = token[2];
if (type === 'OUTDENT' || type === 'CLASS') {
return this.trackClass.apply(this, arguments);
}
if (type === 'EXTENDS') {
this.className = '';
return;
}
if (type === 'IDENTIFIER' && this.isClass && this.className === '') {
c = 0;
while ((ref = tokenApi.peek(c)[0]) === 'IDENTIFIER' || ref === '.') {
this.className += tokenApi.peek(c)[1];
c++;
}
}
if (token.generated && type === '{') {
if (!tokenApi.config[this.rule.name].strict) {
prevToken = tokenApi.peek(-1)[0];
if (prevToken === 'INDENT' || prevToken === 'TERMINATOR') {
return;
}
}
if (this.isClass) {
prevToken = tokenApi.peek(-1)[0];
if (prevToken === 'TERMINATOR') {
return;
}
peekIdent = '';
c = -2;
while ((ref1 = tokenApi.peek(c), _type = ref1[0], _val = ref1[1], ref1)) {
if (_type !== 'IDENTIFIER' && _type !== '.') {
break;
}
peekIdent = _val + peekIdent;
c--;
}
if (peekIdent === this.className) {
return;
}
}
return true;
}
};
NoImplicitBraces.prototype.trackClass = function(token, tokenApi) {
var ln, n0, n1, ref, ref1, ref2;
ref = [token, tokenApi.peek()], (ref1 = ref[0], n0 = ref1[0], ln = ref1[ref1.length - 1]), (ref2 = ref[1], n1 = ref2[0]);
if (n0 === 'OUTDENT' && n1 === 'TERMINATOR') {
this.isClass = false;
}
if (n0 === 'CLASS') {
this.isClass = true;
this.className = '';
}
return null;
};
return NoImplicitBraces;
})();
},{}],28:[function(require,module,exports){
var NoImplicitParens;
module.exports = NoImplicitParens = (function() {
function NoImplicitParens() {}
NoImplicitParens.prototype.rule = {
name: 'no_implicit_parens',
level: 'ignore',
message: 'Implicit parens are forbidden',
strict: true,
description: 'This rule prohibits implicit parens on function calls.\n<pre>\n<code># Some folks don\'t like this style of coding.\nmyFunction a, b, c\n\n# And would rather it always be written like this:\nmyFunction(a, b, c)\n</code>\n</pre>\nImplicit parens are permitted by default, since their use is\nidiomatic CoffeeScript.'
};
NoImplicitParens.prototype.tokens = ['CALL_END'];
NoImplicitParens.prototype.lintToken = function(token, tokenApi) {
var i, t;
if (token.generated) {
if (tokenApi.config[this.rule.name].strict !== false) {
return true;
} else {
i = -1;
while (true) {
t = tokenApi.peek(i);
if ((t == null) || (t[0] === 'CALL_START' && t.generated)) {
return true;
}
if (t[2].first_line !== token[2].first_line) {
return null;
}
i -= 1;
}
}
}
};
return NoImplicitParens;
})();
},{}],29:[function(require,module,exports){
var NoInterpolationInSingleQuotes;
module.exports = NoInterpolationInSingleQuotes = (function() {
function NoInterpolationInSingleQuotes() {}
NoInterpolationInSingleQuotes.prototype.rule = {
name: 'no_interpolation_in_single_quotes',
level: 'ignore',
message: 'Interpolation in single quoted strings is forbidden',
description: 'This rule prohibits string interpolation in a single quoted string.\n<pre>\n<code># String interpolation in single quotes is not allowed:\nfoo = \'#{bar}\'\n\n# Double quotes is OK of course\nfoo = "#{bar}"\n</code>\n</pre>\nString interpolation in single quoted strings is permitted by\ndefault.'
};
NoInterpolationInSingleQuotes.prototype.tokens = ['STRING'];
NoInterpolationInSingleQuotes.prototype.lintToken = function(token, tokenApi) {
var hasInterpolation, tokenValue;
tokenValue = token[1];
hasInterpolation = tokenValue.match(/^\'.*#\{[^}]+\}.*\'$/);
return hasInterpolation;
};
return NoInterpolationInSingleQuotes;
})();
},{}],30:[function(require,module,exports){
var NoNestedStringInterpolation;
module.exports = NoNestedStringInterpolation = (function() {
NoNestedStringInterpolation.prototype.rule = {
name: 'no_nested_string_interpolation',
level: 'warn',
message: 'Nested string interpolation is forbidden',
description: 'This rule warns about nested string interpolation,\nas it tends to make code harder to read and understand.\n<pre>\n<code># Good!\nstr = "Book by #{firstName.toUpperCase()} #{lastName.toUpperCase()}"\n\n# Bad!\nstr = "Book by #{"#{firstName} #{lastName}".toUpperCase()}"\n</code>\n</pre>'
};
NoNestedStringInterpolation.prototype.tokens = ['STRING_START', 'STRING_END'];
function NoNestedStringInterpolation() {
this.startedStrings = 0;
this.generatedError = false;
}
NoNestedStringInterpolation.prototype.lintToken = function(arg, tokenApi) {
var type;
type = arg[0];
if (type === 'STRING_START') {
return this.trackStringStart();
} else {
return this.trackStringEnd();
}
};
NoNestedStringInterpolation.prototype.trackStringStart = function() {
this.startedStrings += 1;
if (this.startedStrings <= 1 || this.generatedError) {
return;
}
this.generatedError = true;
return true;
};
NoNestedStringInterpolation.prototype.trackStringEnd = function() {
this.startedStrings -= 1;
if (this.startedStrings === 1) {
return this.generatedError = false;
}
};
return NoNestedStringInterpolation;
})();
},{}],31:[function(require,module,exports){
var NoPlusPlus;
module.exports = NoPlusPlus = (function() {
function NoPlusPlus() {}
NoPlusPlus.prototype.rule = {
name: 'no_plusplus',
level: 'ignore',
message: 'The increment and decrement operators are forbidden',
description: 'This rule forbids the increment and decrement arithmetic operators.\nSome people believe the <tt>++</tt> and <tt>--</tt> to be cryptic\nand the cause of bugs due to misunderstandings of their precedence\nrules.\nThis rule is disabled by default.'
};
NoPlusPlus.prototype.tokens = ['++', '--'];
NoPlusPlus.prototype.lintToken = function(token, tokenApi) {
return {
context: "found '" + token[0] + "'"
};
};
return NoPlusPlus;
})();
},{}],32:[function(require,module,exports){
var NoPrivateFunctionFatArrows,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
module.exports = NoPrivateFunctionFatArrows = (function() {
function NoPrivateFunctionFatArrows() {
this.isFatArrowCode = bind(this.isFatArrowCode, this);
this.isObject = bind(this.isObject, this);
this.isValue = bind(this.isValue, this);
this.isClass = bind(this.isClass, this);
this.isCode = bind(this.isCode, this);
}
NoPrivateFunctionFatArrows.prototype.rule = {
name: 'no_private_function_fat_arrows',
level: 'warn',
message: 'Used the fat arrow for a private function',
description: 'Warns when you use the fat arrow for a private function\ninside a class definition scope. It is not necessary and\nit does not do anything.'
};
NoPrivateFunctionFatArrows.prototype.lintAST = function(node, astApi) {
this.astApi = astApi;
this.lintNode(node);
return void 0;
};
NoPrivateFunctionFatArrows.prototype.lintNode = function(node, functions) {
var error;
if (functions == null) {
functions = [];
}
if (this.isFatArrowCode(node) && indexOf.call(functions, node) >= 0) {
error = this.astApi.createError({
lineNumber: node.locationData.first_line + 1
});
this.errors.push(error);
}
return node.eachChild((function(_this) {
return function(child) {
return _this.lintNode(child, (function() {
switch (false) {
case !this.isClass(node):
return this.functionsOfClass(node);
case !this.isCode(node):
return [];
default:
return functions;
}
}).call(_this));
};
})(this));
};
NoPrivateFunctionFatArrows.prototype.isCode = function(node) {
return this.astApi.getNodeName(node) === 'Code';
};
NoPrivateFunctionFatArrows.prototype.isClass = function(node) {
return this.astApi.getNodeName(node) === 'Class';
};
NoPrivateFunctionFatArrows.prototype.isValue = function(node) {
return this.astApi.getNodeName(node) === 'Value';
};
NoPrivateFunctionFatArrows.prototype.isObject = function(node) {
return this.astApi.getNodeName(node) === 'Obj';
};
NoPrivateFunctionFatArrows.prototype.isFatArrowCode = function(node) {
return this.isCode(node) && node.bound;
};
NoPrivateFunctionFatArrows.prototype.functionsOfClass = function(classNode) {
var bodyNode, bodyValues;
bodyValues = (function() {
var i, len, ref, results;
ref = classNode.body.expressions;
results = [];
for (i = 0, len = ref.length; i < len; i++) {
bodyNode = ref[i];
if (this.isValue(bodyNode) && this.isObject(bodyNode.base)) {
continue;
}
results.push(bodyNode.value);
}
return results;
}).call(this);
return bodyValues.filter(this.isCode);
};
return NoPrivateFunctionFatArrows;
})();
},{}],33:[function(require,module,exports){
var NoStandAloneAt;
module.exports = NoStandAloneAt = (function() {
function NoStandAloneAt() {}
NoStandAloneAt.prototype.rule = {
name: 'no_stand_alone_at',
level: 'ignore',
message: '@ must not be used stand alone',
description: 'This rule checks that no stand alone @ are in use, they are\ndiscouraged. Further information in CoffeeScript issue <a\nhref="https://web.archive.org/web/20180612201411/https://github.com/jashkenas/coffee-script/issues/1601">\n#1601</a>'
};
NoStandAloneAt.prototype.tokens = ['@'];
NoStandAloneAt.prototype.lintToken = function(token, tokenApi) {
var isDot, isIdentifier, isIndexStart, isValidProtoProperty, nextToken, protoProperty, spaced;
nextToken = tokenApi.peek();
spaced = token.spaced;
isIdentifier = nextToken[0] === 'IDENTIFIER';
isIndexStart = nextToken[0] === 'INDEX_START';
isDot = nextToken[0] === '.';
if (nextToken[0] === '::') {
protoProperty = tokenApi.peek(2);
isValidProtoProperty = protoProperty[0] === 'IDENTIFIER';
}
if (spaced || (!isIdentifier && !isIndexStart && !isDot && !isValidProtoProperty)) {
return true;
}
};
return NoStandAloneAt;
})();
},{}],34:[function(require,module,exports){
var NoTabs, indentationRegex,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
indentationRegex = /\S/;
module.exports = NoTabs = (function() {
function NoTabs() {}
NoTabs.prototype.rule = {
name: 'no_tabs',
level: 'error',
message: 'Line contains tab indentation',
description: 'This rule forbids tabs in indentation. Enough said. It is enabled by\ndefault.'
};
NoTabs.prototype.lintLine = function(line, lineApi) {
var indentation;
indentation = line.split(indentationRegex)[0];
if (lineApi.lineHasToken() && indexOf.call(indentation, '\t') >= 0) {
return true;
} else {
return null;
}
};
return NoTabs;
})();
},{}],35:[function(require,module,exports){
var NoThis;
module.exports = NoThis = (function() {
function NoThis() {}
NoThis.prototype.rule = {
name: 'no_this',
level: 'ignore',
message: "Don't use 'this', use '@' instead",
description: 'This rule prohibits \'this\'.\nUse \'@\' instead.'
};
NoThis.prototype.tokens = ['THIS'];
NoThis.prototype.lintToken = function(token, tokenApi) {
var level, nextToken, ref;
level = tokenApi.config.no_stand_alone_at.level;
nextToken = (ref = tokenApi.peek(1)) != null ? ref[0] : void 0;
if (!(level !== 'ignore' && nextToken !== '.')) {
return true;
}
};
return NoThis;
})();
},{}],36:[function(require,module,exports){
var NoThrowingStrings;
module.exports = NoThrowingStrings = (function() {
function NoThrowingStrings() {}
NoThrowingStrings.prototype.rule = {
name: 'no_throwing_strings',
level: 'error',
message: 'Throwing strings is forbidden',
description: 'This rule forbids throwing string literals or interpolations. While\nJavaScript (and CoffeeScript by extension) allow any expression to\nbe thrown, it is best to only throw <a\nhref="https://web.archive.org/web/20180612201411/https://developer.mozilla.org\n/en/JavaScript/Reference/Global_Objects/Error"> Error</a> objects,\nbecause they contain valuable debugging information like the stack\ntrace. Because of JavaScript\'s dynamic nature, CoffeeLint cannot\nensure you are always throwing instances of <tt>Error</tt>. It will\nonly catch the simple but real case of throwing literal strings.\n<pre>\n<code># CoffeeLint will catch this:\nthrow "i made a boo boo"\n\n# ... but not this:\nthrow getSomeString()\n</code>\n</pre>\nThis rule is enabled by default.'
};
NoThrowingStrings.prototype.tokens = ['THROW'];
NoThrowingStrings.prototype.lintToken = function(token, tokenApi) {
var n1, nextIsString, ref;
ref = tokenApi.peek(), n1 = ref[0];
nextIsString = n1 === 'STRING' || n1 === 'STRING_START';
return nextIsString;
};
return NoThrowingStrings;
})();
},{}],37:[function(require,module,exports){
var NoTrailingSemicolons, regexes,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
slice = [].slice;
regexes = {
trailingSemicolon: /;\r?$/
};
module.exports = NoTrailingSemicolons = (function() {
function NoTrailingSemicolons() {}
NoTrailingSemicolons.prototype.rule = {
name: 'no_trailing_semicolons',
level: 'error',
message: 'Line contains a trailing semicolon',
description: 'This rule prohibits trailing semicolons, since they are needless\ncruft in CoffeeScript.\n<pre>\n<code># This semicolon is meaningful.\nx = \'1234\'; console.log(x)\n\n# This semicolon is redundant.\nalert(\'end of line\');\n</code>\n</pre>\nTrailing semicolons are forbidden by default.'
};
NoTrailingSemicolons.prototype.lintLine = function(line, lineApi) {
var endPos, first, hasNewLine, hasSemicolon, i, last, lineTokens, newLine, ref, ref1, startCounter, startPos, stopTokens, tokenLen;
lineTokens = lineApi.getLineTokens();
tokenLen = lineTokens.length;
stopTokens = ['TERMINATOR', 'HERECOMMENT'];
if (tokenLen === 1 && (ref = lineTokens[0][0], indexOf.call(stopTokens, ref) >= 0)) {
return;
}
newLine = line;
if (tokenLen > 1 && lineTokens[tokenLen - 1][0] === 'TERMINATOR') {
startPos = lineTokens[tokenLen - 2][2].last_column + 1;
endPos = lineTokens[tokenLen - 1][2].first_column;
if (startPos !== endPos) {
startCounter = startPos;
while (line[startCounter] !== '#' && startCounter < line.length) {
startCounter++;
}
newLine = line.substring(0, startCounter).replace(/\s*$/, '');
}
}
hasSemicolon = regexes.trailingSemicolon.test(newLine);
first = 2 <= lineTokens.length ? slice.call(lineTokens, 0, i = lineTokens.length - 1) : (i = 0, []), last = lineTokens[i++];
hasNewLine = last && (last.newLine != null);
if (hasSemicolon && !hasNewLine && lineApi.lineHasToken() && !((ref1 = last[0]) === 'STRING' || ref1 === 'IDENTIFIER' || ref1 === 'STRING_END')) {
return true;
}
};
return NoTrailingSemicolons;
})();
},{}],38:[function(require,module,exports){
var NoTrailingWhitespace, regexes;
regexes = {
trailingWhitespace: /[^\s]+[\t ]+\r?$/,
onlySpaces: /^[\t ]+\r?$/,
lineHasComment: /^\s*[^\#]*\#/
};
module.exports = NoTrailingWhitespace = (function() {
function NoTrailingWhitespace() {}
NoTrailingWhitespace.prototype.rule = {
name: 'no_trailing_whitespace',
level: 'error',
message: 'Line ends with trailing whitespace',
allowed_in_comments: false,
allowed_in_empty_lines: true,
description: 'This rule forbids trailing whitespace in your code, since it is\nneedless cruft. It is enabled by default.'
};
NoTrailingWhitespace.prototype.lintLine = function(line, lineApi) {
var i, len, ref, ref1, ref2, str, token, tokens;
if (!((ref = lineApi.config['no_trailing_whitespace']) != null ? ref.allowed_in_empty_lines : void 0)) {
if (regexes.onlySpaces.test(line)) {
return true;
}
}
if (regexes.trailingWhitespace.test(line)) {
if (!((ref1 = lineApi.config['no_trailing_whitespace']) != null ? ref1.allowed_in_comments : void 0)) {
return true;
}
line = line;
tokens = lineApi.tokensByLine[lineApi.lineNumber];
if (!tokens) {
return null;
}
ref2 = (function() {
var j, len, results;
results = [];
for (j = 0, len = tokens.length; j < len; j++) {
token = tokens[j];
if (token[0] === 'STRING') {
results.push(token[1]);
}
}
return results;
})();
for (i = 0, len = ref2.length; i < len; i++) {
str = ref2[i];
line = line.replace(str, 'STRING');
}
if (!regexes.lineHasComment.test(line)) {
return true;
}
}
};
return NoTrailingWhitespace;
})();
},{}],39:[function(require,module,exports){
var NoUnnecessaryDoubleQuotes;
module.exports = NoUnnecessaryDoubleQuotes = (function() {
NoUnnecessaryDoubleQuotes.prototype.rule = {
name: 'no_unnecessary_double_quotes',
level: 'ignore',
message: 'Unnecessary double quotes are forbidden',
description: 'This rule prohibits double quotes unless string interpolation is\nused or the string contains single quotes.\n<pre>\n<code># Double quotes are discouraged:\nfoo = "bar"\n\n# Unless string interpolation is used:\nfoo = "#{bar}baz"\n\n# Or they prevent cumbersome escaping:\nfoo = "I\'m just following the \'rules\'"\n</code>\n</pre>\nDouble quotes are permitted by default.'
};
function NoUnnecessaryDoubleQuotes() {
this.regexps = [];
this.interpolationLevel = 0;
}
NoUnnecessaryDoubleQuotes.prototype.tokens = ['STRING', 'STRING_START', 'STRING_END'];
NoUnnecessaryDoubleQuotes.prototype.lintToken = function(token, tokenApi) {
var hasLegalConstructs, ref, stringValue, tokenValue, type;
type = token[0], tokenValue = token[1];
if (type === 'STRING_START' || type === 'STRING_END') {
return this.trackParens.apply(this, arguments);
}
stringValue = tokenValue.match(/^\"(.*)\"$/);
if (!stringValue) {
return false;
}
if (((ref = tokenApi.peek(2)) != null ? ref[0] : void 0) === 'REGEX_END') {
return false;
}
hasLegalConstructs = this.isInInterpolation() || this.hasSingleQuote(tokenValue);
return !hasLegalConstructs;
};
NoUnnecessaryDoubleQuotes.prototype.isInInterpolation = function() {
return this.interpolationLevel > 0;
};
NoUnnecessaryDoubleQuotes.prototype.trackParens = function(token, tokenApi) {
if (token[0] === 'STRING_START') {
this.interpolationLevel += 1;
} else if (token[0] === 'STRING_END') {
this.interpolationLevel -= 1;
}
return null;
};
NoUnnecessaryDoubleQuotes.prototype.hasSingleQuote = function(tokenValue) {
return tokenValue.indexOf("'") !== -1;
};
return NoUnnecessaryDoubleQuotes;
})();
},{}],40:[function(require,module,exports){
var NoUnnecessaryFatArrows, any,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
any = function(arr, test) {
return arr.reduce((function(res, elt) {
return res || test(elt);
}), false);
};
module.exports = NoUnnecessaryFatArrows = (function() {
function NoUnnecessaryFatArrows() {
this.needsFatArrow = bind(this.needsFatArrow, this);
this.isThis = bind(this.isThis, this);
}
NoUnnecessaryFatArrows.prototype.rule = {
name: 'no_unnecessary_fat_arrows',
level: 'warn',
message: 'Unnecessary fat arrow',
description: 'Disallows defining functions with fat arrows when `this`\nis not used within the function.'
};
NoUnnecessaryFatArrows.prototype.lintAST = function(node, astApi) {
this.astApi = astApi;
this.lintNode(node);
return void 0;
};
NoUnnecessaryFatArrows.prototype.lintNode = function(node) {
var error;
if ((this.isFatArrowCode(node)) && (!this.needsFatArrow(node))) {
error = this.astApi.createError({
lineNumber: node.locationData.first_line + 1
});
this.errors.push(error);
}
return node.eachChild((function(_this) {
return function(child) {
return _this.lintNode(child);
};
})(this));
};
NoUnnecessaryFatArrows.prototype.isCode = function(node) {
return this.astApi.getNodeName(node) === 'Code';
};
NoUnnecessaryFatArrows.prototype.isFatArrowCode = function(node) {
return this.isCode(node) && node.bound;
};
NoUnnecessaryFatArrows.prototype.isValue = function(node) {
return this.astApi.getNodeName(node) === 'Value';
};
NoUnnecessaryFatArrows.prototype.isThis = function(node) {
return this.isValue(node) && node.base.value === 'this';
};
NoUnnecessaryFatArrows.prototype.needsFatArrow = function(node) {
return this.isCode(node) && (any(node.params, (function(_this) {
return function(param) {
return param.contains(_this.isThis) != null;
};
})(this)) || (node.body.contains(this.isThis) != null) || (node.body.contains((function(_this) {
return function(child) {
if (!_this.astApi.getNodeName(child)) {
return (child.isSuper != null) && child.isSuper;
} else {
return _this.isFatArrowCode(child) && _this.needsFatArrow(child);
}
};
})(this)) != null));
};
return NoUnnecessaryFatArrows;
})();
},{}],41:[function(require,module,exports){
var NonEmptyConstructorNeedsParens, ParentClass,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
ParentClass = require('./empty_constructor_needs_parens.coffee');
module.exports = NonEmptyConstructorNeedsParens = (function(superClass) {
extend(NonEmptyConstructorNeedsParens, superClass);
function NonEmptyConstructorNeedsParens() {
return NonEmptyConstructorNeedsParens.__super__.constructor.apply(this, arguments);
}
NonEmptyConstructorNeedsParens.prototype.rule = {
name: 'non_empty_constructor_needs_parens',
level: 'ignore',
message: 'Invoking a constructor without parens and with arguments',
description: 'Requires constructors with parameters to include the parens'
};
NonEmptyConstructorNeedsParens.prototype.handleExpectedCallStart = function(expectedCallStart) {
if (expectedCallStart[0] === 'CALL_START' && expectedCallStart.generated) {
return true;
}
};
return NonEmptyConstructorNeedsParens;
})(ParentClass);
},{"./empty_constructor_needs_parens.coffee":15}],42:[function(require,module,exports){
var PreferEnglishOperator;
module.exports = PreferEnglishOperator = (function() {
function PreferEnglishOperator() {}
PreferEnglishOperator.prototype.rule = {
name: 'prefer_english_operator',
level: 'ignore',
message: 'Don\'t use &&, ||, ==, !=, or !',
doubleNotLevel: 'ignore',
description: 'This rule prohibits &&, ||, ==, != and !.\nUse and, or, is, isnt, and not instead.\n!! for converting to a boolean is ignored.'
};
PreferEnglishOperator.prototype.tokens = ['COMPARE', 'UNARY_MATH', 'LOGIC'];
PreferEnglishOperator.prototype.lintToken = function(token, tokenApi) {
var actual_token, config, context, first_column, last_column, level, line, ref;
config = tokenApi.config[this.rule.name];
level = config.level;
ref = token[2], first_column = ref.first_column, last_column = ref.last_column;
line = tokenApi.lines[tokenApi.lineNumber];
actual_token = line.slice(first_column, +last_column + 1 || 9e9);
context = (function() {
var ref1, ref2;
switch (actual_token) {
case '==':
return 'Replace "==" with "is"';
case '!=':
return 'Replace "!=" with "isnt"';
case '||':
return 'Replace "||" with "or"';
case '&&':
return 'Replace "&&" with "and"';
case '!':
if (((ref1 = tokenApi.peek(1)) != null ? ref1[0] : void 0) === 'UNARY_MATH') {
level = config.doubleNotLevel;
return '"?" is usually better than "!!"';
} else if (((ref2 = tokenApi.peek(-1)) != null ? ref2[0] : void 0) === 'UNARY_MATH') {
return void 0;
} else {
return 'Replace "!" with "not"';
}
break;
default:
return void 0;
}
})();
if (context != null) {
return {
level: level,
context: context
};
}
};
return PreferEnglishOperator;
})();
},{}],43:[function(require,module,exports){
var SpaceOperators,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
module.exports = SpaceOperators = (function() {
SpaceOperators.prototype.rule = {
name: 'space_operators',
level: 'ignore',
message: 'Operators must be spaced properly',
description: 'This rule enforces that operators have spaces around them.'
};
SpaceOperators.prototype.tokens = ['+', '-', '=', '**', 'MATH', 'COMPARE', 'LOGIC', 'COMPOUND_ASSIGN', 'STRING_START', 'STRING_END', 'CALL_START', 'CALL_END'];
function SpaceOperators() {
this.callTokens = [];
this.parenTokens = [];
this.interpolationLevel = 0;
}
SpaceOperators.prototype.lintToken = function(arg, tokenApi) {
var type;
type = arg[0];
if (type === 'CALL_START' || type === 'CALL_END') {
this.trackCall.apply(this, arguments);
return;
}
if (type === 'STRING_START' || type === 'STRING_END') {
return this.trackParens.apply(this, arguments);
}
if (type === '+' || type === '-') {
return this.lintPlus.apply(this, arguments);
} else {
return this.lintMath.apply(this, arguments);
}
};
SpaceOperators.prototype.lintPlus = function(token, tokenApi) {
var isUnary, p, ref, unaries;
if (this.isInInterpolation() || this.isInExtendedRegex()) {
return null;
}
p = tokenApi.peek(-1);
unaries = ['TERMINATOR', '(', '=', '-', '+', ',', 'CALL_START', 'INDEX_START', '..', '...', 'COMPARE', 'IF', 'THROW', 'LOGIC', 'POST_IF', ':', '[', 'INDENT', 'COMPOUND_ASSIGN', 'RETURN', 'MATH', 'BY', 'LEADING_WHEN'];
isUnary = !p ? false : (ref = p[0], indexOf.call(unaries, ref) >= 0);
if ((isUnary && (token.spaced != null)) || (!isUnary && !token.newLine && (!token.spaced || (p && !p.spaced)))) {
return {
context: token[1]
};
} else {
return null;
}
};
SpaceOperators.prototype.lintMath = function(token, tokenApi) {
var p;
p = tokenApi.peek(-1);
if (!token.newLine && (!token.spaced || (p && !p.spaced))) {
return {
context: token[1]
};
} else {
return null;
}
};
SpaceOperators.prototype.isInExtendedRegex = function() {
var i, len, ref, t;
ref = this.callTokens;
for (i = 0, len = ref.length; i < len; i++) {
t = ref[i];
if (t.isRegex) {
return true;
}
}
return false;
};
SpaceOperators.prototype.isInInterpolation = function() {
return this.interpolationLevel > 0;
};
SpaceOperators.prototype.trackCall = function(token, tokenApi) {
var p;
if (token[0] === 'CALL_START') {
p = tokenApi.peek(-1);
token.isRegex = p && p[0] === 'IDENTIFIER' && p[1] === 'RegExp';
this.callTokens.push(token);
} else {
this.callTokens.pop();
}
return null;
};
SpaceOperators.prototype.trackParens = function(token, tokenApi) {
if (token[0] === 'STRING_START') {
this.interpolationLevel += 1;
} else if (token[0] === 'STRING_END') {
this.interpolationLevel -= 1;
}
return null;
};
return SpaceOperators;
})();
},{}],44:[function(require,module,exports){
var SpacingAfterComma;
module.exports = SpacingAfterComma = (function() {
SpacingAfterComma.prototype.rule = {
name: 'spacing_after_comma',
level: 'ignore',
message: 'a space is required after commas',
description: 'This rule checks to make sure you have a space after commas.'
};
SpacingAfterComma.prototype.tokens = [',', 'REGEX_START', 'REGEX_END'];
function SpacingAfterComma() {
this.inRegex = false;
}
SpacingAfterComma.prototype.lintToken = function(token, tokenApi) {
var type;
type = token[0];
if (type === 'REGEX_START') {
this.inRegex = true;
return;
}
if (type === 'REGEX_END') {
this.inRegex = false;
return;
}
if (!(token.spaced || token.newLine || token.generated || this.isRegexFlag(token, tokenApi))) {
return true;
}
};
SpacingAfterComma.prototype.isRegexFlag = function(token, tokenApi) {
var maybeEnd;
if (!this.inRegex) {
return false;
}
maybeEnd = tokenApi.peek(3);
return (maybeEnd != null ? maybeEnd[0] : void 0) === 'REGEX_END';
};
return SpacingAfterComma;
})();
},{}],45:[function(require,module,exports){
var TransformMessesUpLineNumbers;
module.exports = TransformMessesUpLineNumbers = (function() {
function TransformMessesUpLineNumbers() {}
TransformMessesUpLineNumbers.prototype.rule = {
name: 'transform_messes_up_line_numbers',
level: 'warn',
message: 'Transforming source messes up line numbers',
description: 'This rule detects when changes are made by transform function,\nand warns that line numbers are probably incorrect.'
};
TransformMessesUpLineNumbers.prototype.tokens = [];
TransformMessesUpLineNumbers.prototype.lintToken = function(token, tokenApi) {};
return TransformMessesUpLineNumbers;
})();
},{}]},{},[1])(1)
});
/*
FILE ARCHIVED ON 20:14:11 Jun 12, 2018 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 23:01:57 Mar 05, 2019.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
*/
/*
playback timings (ms):
LoadShardBlock: 63.826 (3)
esindex: 0.009
captures_list: 82.547
CDXLines.iter: 13.634 (3)
PetaboxLoader3.datanode: 75.315 (5)
exclusion.robots: 0.181
exclusion.robots.policy: 0.169
RedisCDXSource: 1.906
PetaboxLoader3.resolve: 82.34 (2)
load_resource: 99.647
*/
<!DOCTYPE html>
<html>
<head><script src="https://archive.org/includes/analytics.js?v=cf34f82" type="text/javascript"></script>
<script type="text/javascript">window.addEventListener('DOMContentLoaded',function(){var v=archive_analytics.values;v.service='wb';v.server_name='wwwb-app104.us.archive.org';v.server_ms=366;archive_analytics.send_pageview({});});</script>
<script type="text/javascript" src="https://web.archive.org/static/js/ait-client-rewrite.js?v=1549496156" charset="utf-8"></script>
<script type="text/javascript">
WB_wombat_Init('https://web.archive.org/web', '20180929154522', 'www.coffeelint.org');
</script>
<script type="text/javascript" src="https://web.archive.org/static/js/wbhack.js?v=1549496156" charset="utf-8"></script>
<script type="text/javascript">
__wbhack.init('https://web.archive.org/web');
</script>
<link rel="stylesheet" type="text/css" href="https://web.archive.org/static/css/banner-styles.css?v=1549496156" />
<link rel="stylesheet" type="text/css" href="https://web.archive.org/static/css/iconochive.css?v=1549496156" />
<!-- End Wayback Rewrite JS Include -->
<meta http-equiv="content-type" content="text/html;charset=UTF-8"/>
<title>CoffeeLint - Lint your CoffeeScript</title>
<link rel="stylesheet" type="text/css" href="coffeelint.css"/>
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon"/>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-27677530-2']);
_gaq.push(['_setDomainName', 'coffeelint.org']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl/' : 'http://www/') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<!-- HEADER -->
<div class="header">
<div class="container">
<h1 class="title">
CoffeeLint
</h1>
<ul class="header_links">
<li><a href="index.html#overview">Overview</a></li>
<li><a href="index.html#install">Install</a></li>
<li><a href="index.html#usage">Usage</a></li>
<li><a href="index.html#options">Options</a></li>
<li><a href="index.html#api">API</a></li>
<li><a href="index.html#plugins">Plugins</a></li>
<li><a href="index.html#about">About</a></li>
<li><a href="index.html#changelog">Change Log</a></li>
<li><a href="https://github.com/clutchski/coffeelint">Source</a></li>
</ul>
</div>
</div>
<div class="container">
<!-- EDITOR -->
<div class="row editor_row">
<div class="run">Run</div>
<textarea class="editor" spellcheck="false"># Lint your CoffeeScript!
class Gangster
wasItAGoodDay : () -&gt;
yes
</textarea>
</div>
<!-- LINT REPORT -->
<div class="row report_row">
<div class="report_container section_container">
<div class="report">
<h1 class="section_title"></h1>
<div class="section_body"></div>
</div>
</div>
</div>
<!-- DOCUMENTATION -->
<div class="row doc_row">
<h2 class="section_title" id="overview">Overview</h2>
<p>
CoffeeLint is a style checker that helps keep
<a href="http://coffeescript.org/">CoffeeScript</a>
code clean and consistent. CoffeeScript does a great job at
insulating programmers from many of
JavaScript's bad parts, but it won't help enforce a consistent style
across a code base. CoffeeLint can help with that.
</p>
<p>
If you have an idea, a bug report or anything else to say, reach out
on the
<a href="http://github.com/clutchski/coffeelint/issues">issues page</a>.
</p>
<h2 class="section_title" id="install">Installation</h2>
<p>
To install, make sure you have a working version of the latest
stable version of <a href="http://nodejs.org/">Node</a> and
<a href="http://npmjs.org/">NPM</a> (the Node Package Manager) and then
run:
</p>
<code>
npm install -g coffeelint
</code>
<p>Leave off the <tt>g</tt> if you do not want to install globally.</p>
<h2 class="section_title">Getting Started</h2>
<ul>
<li>
<a href="https://github.com/clutchski/coffeelint/blob/master/doc/user.md">Users</a>
</li>
<li>
<a href="https://github.com/clutchski/coffeelint/blob/master/doc/integration.md">Plugin Developers</a>
</li>
</ul>
<h2 class="section_title" id="usage">Usage</h2>
<p>
Once you have Coffeelint installed, to lint your scripts, run:
</p>
<code>coffeelint application.coffee</code>
<p>
To specify your own configuration file, do the following:
</p>
<code>coffeelint -f coffeelint.json application.coffee</code>
<p>
If any errors were found, a non-zero code will be returned.
</p>
<p>
To generate a configuration file, do
</p>
<code>coffeelint --makeconfig &gt; coffeelint.json</code>
<p>
You can then configure the rules to your liking.
</p>
<p>
New in 1.0: CoffeeLint will automatically pick up config files. When
linting a file (as opposed to stdin) it will walk up the directory
tree looking for a coffeelint.json or a package.json that has a
"coffeelintConfig" object. If neither of those are found or you're
linting from stdin it will check your home for a coffeelint.json
file.
</p>
<h2 class="section_title" id="options">Options</h2>
</p>
<p>
By default, CoffeeLint will help ensure you are writing idiomatic
CoffeeScript, but every rule is optional and configurable so it can
be tuned to fit your preferred coding style. To override any of
CoffeeLint's default options, <a href="index.html#usage">generate a
configuration file</a> and tweak it as needed. To enable an option,
set its level to <tt>error</tt>, and to disable an option, set its
level to <tt>ignore</tt>. If you set the level to <tt>warn</tt>,
violations will be reported, but won't cause a non-zero exit code.
</p>
<p>
To disable a rule inline use the following:
</p>
<pre><code>
# coffeelint: disable=max_line_length
foo = "some/huge/line/string/with/embed/#{values}.that/surpasses/the/max/column/width"
# coffeelint: enable=max_line_length
</code></pre>
<p>Here's a rundown of CoffeeLint's rules:</p>
<table class="options">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="rule">arrow_spacing</td>
<td class="description">
<p>This rule checks to see that there is spacing before and after
the arrow operator that declares a function. This rule is disabled
by default.</p> <p>Note that if arrow_spacing is enabled, and you
pass an empty function as a parameter, arrow_spacing will accept
either a space or no space in-between the arrow operator and the
parenthesis</p>
<pre><code># Both of this will not trigger an error,
# even with arrow_spacing enabled.
x(-&gt; 3)
x( -&gt; 3)
# However, this will trigger an error
x((a,b)-&gt; 3)
</code>
</pre>
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">braces_spacing</td>
<td class="description">
This rule checks to see that there is the proper spacing inside
curly braces. The spacing amount is specified by "spaces".
The spacing amount for empty objects is specified by
"empty_object_spaces".
<pre><code>
# Spaces is 0
{a: b} # Good
{a: b } # Bad
{ a: b} # Bad
{ a: b } # Bad
# Spaces is 1
{a: b} # Bad
{a: b } # Bad
{ a: b} # Bad
{ a: b } # Good
{ a: b } # Bad
{ a: b } # Bad
{ a: b } # Bad
# Empty Object Spaces is 0
{} # Good
{ } # Bad
# Empty Object Spaces is 1
{} # Bad
{ } # Good
</code></pre>
This rule is disabled by default.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">camel_case_classes</td>
<td class="description">
This rule mandates that all class names are UpperCamelCased.
Camel casing class names is a generally accepted way of
distinguishing constructor functions - which require the 'new'
prefix to behave properly - from plain old functions.
<pre>
<code># Good!
class BoaConstrictor
# Bad!
class boaConstrictor
</code>
</pre>
This rule is enabled by default.
<p><em>default level: error</em></p>
</td>
</tr>
<tr>
<td class="rule">coffeescript_error</td>
<td class="description">
[no description provided]
<p><em>default level: error</em></p>
</td>
</tr>
<tr>
<td class="rule">colon_assignment_spacing</td>
<td class="description">
<p>This rule checks to see that there is spacing before and
after the colon in a colon assignment (i.e., classes, objects).
The spacing amount is specified by
spacing.left and spacing.right, respectively.
A zero value means no spacing required.
</p>
<pre><code>
#
# If spacing.left and spacing.right is 1
#
# Doesn't throw an error
object = {spacing : true}
class Dog
canBark : true
# Throws an error
object = {spacing: true}
class Cat
canBark: false
</code></pre>
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">cyclomatic_complexity</td>
<td class="description">
Examine the complexity of your function.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">duplicate_key</td>
<td class="description">
Prevents defining duplicate keys in object literals and classes
<p><em>default level: error</em></p>
</td>
</tr>
<tr>
<td class="rule">empty_constructor_needs_parens</td>
<td class="description">
Requires constructors with no parameters to include the parens
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">ensure_comprehensions</td>
<td class="description">
This rule makes sure that parentheses are around comprehensions.
<p><em>default level: warn</em></p>
</td>
</tr>
<tr>
<td class="rule">eol_last</td>
<td class="description">
Checks that the file ends with a single newline
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">indentation</td>
<td class="description">
This rule imposes a standard number of spaces to be used for
indentation. Since whitespace is significant in CoffeeScript, it's
critical that a project chooses a standard indentation format and
stays consistent. Other roads lead to darkness. <pre> <code>#
Enabling this option will prevent this ugly
# but otherwise valid CoffeeScript.
twoSpaces = () -&gt;
fourSpaces = () -&gt;
eightSpaces = () -&gt;
'this is valid CoffeeScript'
</code>
</pre>
Two space indentation is enabled by default.
<p><em>default level: error</em></p>
</td>
</tr>
<tr>
<td class="rule">line_endings</td>
<td class="description">
This rule ensures your project uses only <tt>windows</tt> or
<tt>unix</tt> line endings. This rule is disabled by default.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">max_line_length</td>
<td class="description">
This rule imposes a maximum line length on your code. <a href="http://www.python.org/dev/peps/pep-0008/">Python's style
guide</a> does a good job explaining why you might want to limit the
length of your lines, though this is a matter of taste.
Lines can be no longer than eighty characters by default.
<p><em>default level: error</em></p>
</td>
</tr>
<tr>
<td class="rule">missing_fat_arrows</td>
<td class="description">
Warns when you use `this` inside a function that wasn't defined
with a fat arrow. This rule does not apply to methods defined in a
class, since they have `this` bound to the class instance (or the
class itself, for class methods). The option `is_strict` is
available for checking bindings of class methods.
It is impossible to statically determine whether a function using
`this` will be bound with the correct `this` value due to language
features like `Function.prototype.call` and
`Function.prototype.bind`, so this rule may produce false positives.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">newlines_after_classes</td>
<td class="description">
<p>Checks the number of newlines between classes and other code.</p>
Options:
- <pre><code>value</code></pre> - The number of required newlines
after class definitions. Defaults to 3.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">no_backticks</td>
<td class="description">
Backticks allow snippets of JavaScript to be embedded in
CoffeeScript. While some folks consider backticks useful in a few
niche circumstances, they should be avoided because so none of
JavaScript's "bad parts", like <tt>with</tt> and <tt>eval</tt>,
sneak into CoffeeScript.
This rule is enabled by default.
<p><em>default level: error</em></p>
</td>
</tr>
<tr>
<td class="rule">no_debugger</td>
<td class="description">
This rule detects `debugger` and optionally `console` calls
This rule is `warn` by default.
<p><em>default level: warn</em></p>
</td>
</tr>
<tr>
<td class="rule">no_empty_functions</td>
<td class="description">
Disallows declaring empty functions. The goal of this rule is that
unintentional empty callbacks can be detected:
<pre>
<code>someFunctionWithCallback -&gt;
doSomethingSignificant()
</code>
</pre>
The problem is that the call to
<tt>doSomethingSignificant</tt> will be made regardless
of <tt>someFunctionWithCallback</tt>'s execution. It can
be because you did not indent the call to
<tt>doSomethingSignificant</tt> properly.
If you really meant that <tt>someFunctionWithCallback</tt>
should call a callback that does nothing, you can write your code
this way:
<pre>
<code>someFunctionWithCallback -&gt;
undefined
doSomethingSignificant()
</code>
</pre>
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">no_empty_param_list</td>
<td class="description">
This rule prohibits empty parameter lists in function definitions.
<pre>
<code># The empty parameter list in here is unnecessary:
myFunction = () -&gt;
# We might favor this instead:
myFunction = -&gt;
</code>
</pre>
Empty parameter lists are permitted by default.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">no_implicit_braces</td>
<td class="description">
This rule prohibits implicit braces when declaring object literals.
Implicit braces can make code more difficult to understand,
especially when used in combination with optional parenthesis.
<pre>
<code># Do you find this code ambiguous? Is it a
# function call with three arguments or four?
myFunction a, b, 1:2, 3:4
# While the same code written in a more
# explicit manner has no ambiguity.
myFunction(a, b, {1:2, 3:4})
</code>
</pre>
Implicit braces are permitted by default, since their use is
idiomatic CoffeeScript.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">no_implicit_parens</td>
<td class="description">
This rule prohibits implicit parens on function calls.
<pre>
<code># Some folks don't like this style of coding.
myFunction a, b, c
# And would rather it always be written like this:
myFunction(a, b, c)
</code>
</pre>
Implicit parens are permitted by default, since their use is
idiomatic CoffeeScript.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">no_interpolation_in_single_quotes</td>
<td class="description">
This rule prohibits string interpolation in a single quoted string.
<pre>
<code># String interpolation in single quotes is not allowed:
foo = '#{bar}'
# Double quotes is OK of course
foo = "#{bar}"
</code>
</pre>
String interpolation in single quoted strings is permitted by
default.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">no_nested_string_interpolation</td>
<td class="description">
This rule warns about nested string interpolation,
as it tends to make code harder to read and understand.
<pre>
<code># Good!
str = "Book by #{firstName.toUpperCase()} #{lastName.toUpperCase()}"
# Bad!
str = "Book by #{"#{firstName} #{lastName}".toUpperCase()}"
</code>
</pre>
<p><em>default level: warn</em></p>
</td>
</tr>
<tr>
<td class="rule">no_plusplus</td>
<td class="description">
This rule forbids the increment and decrement arithmetic operators.
Some people believe the <tt>++</tt> and <tt>--</tt> to be cryptic
and the cause of bugs due to misunderstandings of their precedence
rules.
This rule is disabled by default.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">no_private_function_fat_arrows</td>
<td class="description">
Warns when you use the fat arrow for a private function
inside a class definition scope. It is not necessary and
it does not do anything.
<p><em>default level: warn</em></p>
</td>
</tr>
<tr>
<td class="rule">no_stand_alone_at</td>
<td class="description">
This rule checks that no stand alone @ are in use, they are
discouraged. Further information in CoffeeScript issue <a href="https://github.com/jashkenas/coffee-script/issues/1601">
#1601</a>
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">no_tabs</td>
<td class="description">
This rule forbids tabs in indentation. Enough said. It is enabled by
default.
<p><em>default level: error</em></p>
</td>
</tr>
<tr>
<td class="rule">no_this</td>
<td class="description">
This rule prohibits 'this'.
Use '@' instead.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">no_throwing_strings</td>
<td class="description">
This rule forbids throwing string literals or interpolations. While
JavaScript (and CoffeeScript by extension) allow any expression to
be thrown, it is best to only throw <a href="https://developer.mozilla.org
/en/JavaScript/Reference/Global_Objects/Error"> Error</a> objects,
because they contain valuable debugging information like the stack
trace. Because of JavaScript's dynamic nature, CoffeeLint cannot
ensure you are always throwing instances of <tt>Error</tt>. It will
only catch the simple but real case of throwing literal strings.
<pre>
<code># CoffeeLint will catch this:
throw "i made a boo boo"
# ... but not this:
throw getSomeString()
</code>
</pre>
This rule is enabled by default.
<p><em>default level: error</em></p>
</td>
</tr>
<tr>
<td class="rule">no_trailing_semicolons</td>
<td class="description">
This rule prohibits trailing semicolons, since they are needless
cruft in CoffeeScript.
<pre>
<code># This semicolon is meaningful.
x = '1234'; console.log(x)
# This semicolon is redundant.
alert('end of line');
</code>
</pre>
Trailing semicolons are forbidden by default.
<p><em>default level: error</em></p>
</td>
</tr>
<tr>
<td class="rule">no_trailing_whitespace</td>
<td class="description">
This rule forbids trailing whitespace in your code, since it is
needless cruft. It is enabled by default.
<p><em>default level: error</em></p>
</td>
</tr>
<tr>
<td class="rule">no_unnecessary_double_quotes</td>
<td class="description">
This rule prohibits double quotes unless string interpolation is
used or the string contains single quotes.
<pre>
<code># Double quotes are discouraged:
foo = "bar"
# Unless string interpolation is used:
foo = "#{bar}baz"
# Or they prevent cumbersome escaping:
foo = "I'm just following the 'rules'"
</code>
</pre>
Double quotes are permitted by default.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">no_unnecessary_fat_arrows</td>
<td class="description">
Disallows defining functions with fat arrows when `this`
is not used within the function.
<p><em>default level: warn</em></p>
</td>
</tr>
<tr>
<td class="rule">non_empty_constructor_needs_parens</td>
<td class="description">
Requires constructors with parameters to include the parens
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">prefer_english_operator</td>
<td class="description">
This rule prohibits &amp;&amp;, ||, ==, != and !.
Use and, or, is, isnt, and not instead.
!! for converting to a boolean is ignored.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">space_operators</td>
<td class="description">
This rule enforces that operators have spaces around them.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">spacing_after_comma</td>
<td class="description">
This rule checks to make sure you have a space after commas.
<p><em>default level: ignore</em></p>
</td>
</tr>
<tr>
<td class="rule">transform_messes_up_line_numbers</td>
<td class="description">
This rule detects when changes are made by transform function,
and warns that line numbers are probably incorrect.
<p><em>default level: warn</em></p>
</td>
</tr>
</tbody>
</table>
</p>
<h2 class="section_title" id="api">API</h2>
<p>
If you'd like to run CoffeeScript in the browser or any other
Javascript runtime, include
<a href="http://coffeescript.org/extras/coffee-script.js">coffee-script.js</a>
and
<a href="http://www.coffeelint.org/js/coffeelint.js">
coffeelint.js
</a>
and you're off to the races. Then you can call CoffeeLint directly
with the following API:
</p>
<h3 class="api_call">coffeelint.lint(source, configuration)</h3>
<p>
Lints the CoffeeScript source with the given configuration
and returns an array of lint errors and warnings. If the array is
empty, all is well. Compile time errors will be thrown.
An error is a Javascript object with the following properties:
</p>
<pre><code>{
rule : 'Name of the violated rule',
lineNumber: 'Number of the line that caused the violation',
level: 'The severity level of the violated rule',
message: 'Information about the violated rule',
context: 'Optional details about why the rule was violated'
}</code></pre>
<h3 class="api_call">coffeelint.registerRule(RuleConstructor)</h3>
<p>
Registers a custom rule that may be run by CoffeeLint. If the rule
is ignored by default it will still require overriding it's level
just like the default rules. They have actually all be
re-implemented as pluggable rules that come bundled in CoffeeLint.
</p>
<h2 class="section_title" id="loading-custom-rules">Loading Custom Rules</h2>
<p>
Not every possible rule will be included in the CoffeeLint project.
Maybe it's very specific to your project, or it's not specific to
CoffeeScript.
</p>
<p>
By convention rule authors add the keyword <tt>coffeelintrule</tt> to their npm package.json so custom rules can be found easily. Click <a href="https://npmjs.org/search?q=coffeelintrule">here</a> to list all currently available custom rules on npm.
</p>
<p>
For example, maybe you want to get a warning if you don't have a
newline at the end of your files. We'll imagine you globally
installed the package <a href="https://github.com/Dreamscapes/coffeelint-newline-at-eof">"coffeelint-newline-eof"</a>.
</p>
<!-- Found this example at https://github.com/clutchski/coffeelint/pull/79 -->
<pre><code>{
// This name MUST match the default configuration of the rule being loaded.
"newline_at_eof": {
// NodeJS module to load. It can also be a path to the rule (useful for devleopment)
"module": "coffeelint-newline-at-eof",
// Maybe the rule author set it to error by default and you only want a warning.
"level": "warn"
}
}</code></pre>
<p>
Now every time you run CoffeeLint it will load that rule and
override it's default level to "warn".
</p>
<h2 class="section_title" id="building-custom-rules">Building Custom Rules</h2>
<p>
CoffeeLint has three types of linters that run. In no particular order they are.
<ul>
<li>LineLinter: processes one line at a time, usually with regular expressions</li>
<li>TokenLinter: processes the token stream generated by CoffeeScript.</li>
<li>ASTLinter: Processes the Abstract Syntax Tree. AST rules are
only called with the root node and it is up to the rule to
recurse the tree.</li>
</ul>
</p>
<p>
Rules may be loaded using <pre><code>--rules /path/to/rules/</code></pre> or
<pre><code>coffeelint.registerRule(RuleConstructor)</code></pre> when
outside of the CLI.
</p>
<p>
Rules do not have to be written in CoffeeScript. A new instance of
each rule is constructed for each file, so the RuleConstructor must
be a constructor function that generates a new clean instance of
your rule when the new operator is used.
</p>
<p>
Your rule instance must have a .rule attribute with it's default
configuration. "name", "level" "message", and "description" are
all required. "level" must be one of 'ignore', 'warn', or
'error'. Once you have a valid rule configuration CoffeeLint
requires you to implement one function depending on which type of
linter your rule needs.
<code>
lintLine(line, lineApi)<br/>
lintToken(token, tokenApi)<br>
lintAST(ast, astApi)
</code>
The second parameter of each is an object with helper functions.
It's best to just check the source or look at how other plugins
are using those.
</p>
<p>
If your function returns true it will generate an error. If you
need override how the error is generated, maybe providing a
context attribute, you can return an object that will get mixed
into the generated error. The NoPlusPlus is a simple example of
this.
</p>
<p>
The core rules have been rewritten as stand alone rules both to
prove the system and provide examples of how to write rules.
To get started no_plus_plus is a Token rule, no_tabs is a Line rule,
and cyclomatic_complexity is an AST rule.
</p>
<p>
The <pre>--rules</pre> option will load every .js or .coffee file
it finds and assume they export the RuleConstructor. Since the
browser doesn't have a standard export system it's up to you to
determine how you'll load your plugin and register it with
<pre>coffeelint.registerRule</pre>
</p>
<h2 class="section_title" id="plugins">Plugins</h2>
<p>
Some nice folks have coded up some cool CoffeeLint plugins for editors and
build systems. Check them out:
<ul class="changelog_history">
<li>The aptly named
<a href="https://github.com/kchmck/vim-coffee-script">vim-coffee-script</a>
by Mick Koch. </li>
<li>
<a href="https://github.com/purcell/flymake-coffee">flymake-coffee</a>, en emacs flymake plugin by Steve Purcell.
<li>
<a href="https://github.com/ajkavanagh/coffeelintnode">CoffeeLintNode</a>,
an emacs plugin, by Alex Kavanagh.</li>
<li><a href="https://github.com/ilkosta/coffeelint-brunch">CoffeeLint-brunch</a>
is a plugin for <a href="http://brunch.io/">Brunch.io</a>, by Costantino Giuliodori.
</li>
<li><a href="https://github.com/vojtajina/grunt-coffeelint">Grunt-CoffeeLint</a>
is a plugin for <a href="http://gruntjs.com/">Grunt.js</a>, by Vojta Jina.
</li>
<li><a href="https://github.com/scrooloose/syntastic">Syntastic</a>
a Vim syntax checker, now support CoffeeLint.
</li>
<li><a href="https://github.com/dbashford/mimosa-coffeelint">mimosa-coffeelint</a>
is a plugin for <a href="http://mimosa.io/">Mimosa</a>, by David Bashford.
</li>
<li><a href="https://github.com/synaway/arcanist-coffee-lib">arcanist-coffee-lib</a>
is a set of <a href="https://github.com/facebook/arcanist">Arcanist</a> extensions,
including a wrapper for CoffeeLint.
</li>
<li>
<a href="https://github.com/janraasch/gulp-coffeelint">gulp-coffeelint</a>
is a plugin for
<a href="https://github.com/wearefractal/gulp">gulp</a>, by Jan Raasch.
</li>
<li>
<a href="https://github.com/zipcodeman/coffeelint-ruby">coffeelint-ruby</a>
is a set of bindings for ruby, by Zachary Bush
</li>
<li>
<a href="https://github.com/brigade/overcommit">overcommit</a>
is a fully configurable and extendable Git hook manager
including support for CoffeeLint.
</li>
</ul>
</p>
<h2 class="section_title" id="about">About</h2>
<p>
CoffeeLint is open sourced under the MIT License. If you want to
hack on the code, report a bug or suggest a new feature, head on
over <a href="http://github.com/clutchski/coffeelint">here</a>.
</p>
<p>
Thanks to CoffeeScript's
<a href="https://github.com/jashkenas/coffee-script/contributors">developers</a>
for a great language (and a re-usable Lexer). Thanks to the creators of
<a href="http://www.jslint.com/">JSLint</a>,
<a href="http://www.jshint.com/">JSHint</a>,
<a href="http://www.logilab.org/857">Pylint</a>,
<a href="http://en.wikipedia.org/wiki/Lint_(software)">lint</a>
and my mother for inspiration.
</p>
<h2 class="section_title" id="changelog">Change Log</h2>
<div> <h3 class="changelog_header">1.14.1-1.15.0</h3> <small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.14.1...v1.15.0">2015.11.18<a></a></small>
<p>
This version updates the enable/disable directives. In addition to
the existing <tt># coffeelint: disable=rule_name</tt> you can also
use <tt># coffeelint disable-line=rule_name</tt>. The rule name is
still optional in both cases, and you can enable the rules using
the same syntax.
</p>
<p>
You can also use <tt># noqa</tt> as a shortcut for <tt># coffeelint: disable-line</tt>
</p>
<ul class="changelog_history">
<li>See <a href="https://github.com/clutchski/coffeelint/pull/552">#552</a> for more details.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.14.0-1.14.1</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.14.0...v1.14.1">2015.11.18<a></a></small>
<p>Most of the changes are more for linting the development files of
coffeelint. The minor version increase is due to the change in
cyclomatic_complexity, which now ignores nested functions. I foresee
this change affecting very few people but probably still needs a minor
version increase.
</p>
<ul class="changelog_history">
<li><tt>cyclomatic_complexity</tt> rule has been changed to ignore nested functions</li>
<li>1.4.1: inlined rules not previously specified in JSON config now properly return a message</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.11.0-1.13.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.11.0...v1.13.0">2015.10.7<a></a></small>
<p>The v1.12.x versions are considered buggy and you should upgrade to v1.13.x if you experience problems</p>
<strong>These releases were largely for bugfixes!</strong>
<ul class="changelog_history">
<li>Bugfix for <tt>no_implicit_braces</tt> causing errors in classes and other edge cases</li>
<li>Bugfix for <tt>ensure_comprehensions</tt> where it failed if a nested loop had an equal sign</li>
<li>Bugfix for <tt>braces_spacing</tt> failing over generated curly braces</li>
<li>Several changes to <tt>indentation</tt> See <a href="https://github.com/clutchski/coffeelint/commit/bffa2532efd8bcca5d9c1b3a9d3b5914e882dd5f">bffa25</a>
for the full list of changes. However between the release of v1.12.0 and v1.13.0, a regression was caused by fixing one of the indentation requests and
as a result the change was reverted. The revert will most likely not affect too many users
<li>Bugfix for <tt>newlines_after_classes</tt>, also fixed regressions caused between v1.12.0 and v1.13.0. If you have v1.12.x and are experiencing problems, please upgrade.
Also note nested classes are now ignored completely
</li>
<li><tt>no_this</tt> is now compatible with <tt>no_stand_alone_at</tt> and will make checks against singular `this`</li>
<li>Bugfix for <tt>missing_fat_arrows</tt>, declaring a class prototype (via '::' operator) no longer fail if they don't use a fat arrow</li>
<li>Bugfix for <tt>eol_last</tt>, it now fails if there are multiple newlines at the end of a file (thanks <a href="https://github.com/charlierudolph">charlierudolph</a>)<li>
<li>Bugfix for <tt>arrow_spacing</tt>, now ignores arrow spacing in empty functions (thanks <a href="https://github.com/sgentle">sgentle</a>)</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.10.0-1.11.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.10.0...v1.11.0">2015.8.19<a></a></small>
<ul class="changelog_history">
<li>New config option <tt>{ "extends": "coffeelint-config-myconfig" } based on <a href="http://eslint.org/docs/developer-guide/shareable-configs">eslint's shareable configs</a></tt></li>
<li>New rule <tt>no_nested_string_interpolation</tt></li>
<li>New rule <tt>no_private_function_fat_arrows</tt></li>
<li>New CLI option <tt>--ext</tt> to specify alternate file extensions to check</li>
<li>Bugfixes including tracking nested string interpolation which eleminates some misleading warnings</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.9.7-1.10.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.9.7...v1.10.0">2015.5.31<a></a></small>
<ul class="changelog_history">
<li>New option <tt>--trimconfig</tt>. shows the minimal config to implement your customizations.</li>
<li>New rule <tt>eol_last</tt></li>
<li>New rule <tt>no_this</tt> (prefer @ instead)</li>
<li>New option in <tt>no_debugger</tt> to flag console calls</li>
<li>Many small bug fixes</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.9.4-1.9.6</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.9.4...v1.9.6">2015.5.5<a></a></small>
<ul class="changelog_history">
<li>Fix no_interpolation_in_single_quotes to only handle single quotes #400</li>
<li>Avoid non-standard String.prototype.trimRight #401</li>
<li>Strip comments from config file before parsing #407</li>
<li>missing_fat_arrows: fix constructor checking in strict mode #409</li>
<li>Use configfilter to expand module names</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.9.3-1.9.4</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.9.3...v1.9.4">2015.4.6<a></a></small>
<ul class="changelog_history">
<li>missing_fat_arrows: added strict-mode option, defaults to false</li>
<li>Add "empty_object_spaces" to braces_spacing</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.9.1-1.9.3</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.9.1...v1.9.3">2015.3.29<a></a></small>
<ul class="changelog_history">
<li>Add fat arrow to `arrow_spacing`</li>
<li>Fix an exception when package.json can't be parsed.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.9.0-1.9.1</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.9.0...v1.9.1">2015.2.22<a></a></small>
<ul class="changelog_history">
<li>Small change to make CoffeeLint compatible with atom.io</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.8.1-1.9.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.8.1...v1.9.0">2015.2.20<a></a></small>
<ul class="changelog_history">
<li>Updated to CoffeeScript 1.9.1 thanks to swang</li>
<li>Fix <tt>no_implicit_braces error</tt> in class declarations</li>
<li>New rule <tt>braces_padding</tt></li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.7.1-1.8.1</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.7.1...v1.8.1">2014.12.20<a></a></small>
<ul class="changelog_history">
<li>New rule <tt>ensure_comprehensions</tt> (warn by default)</li>
<li>Added options to
<a href="https://github.com/clutchski/coffeelint/blob/master/doc/user.md#how-do-i-use-jsx-reactjs">
transform
</a>
code before processing it. (JSX support) or to use a different
<a href="https://github.com/clutchski/coffeelint/blob/master/doc/user.md#what-about-different-flavors-of-coffeescript-like-icedcoffeescript">
flavor of CoffeeScript
</a>
.
</li>
<li>New rule <tt>transform_messes_up_line_numbers</tt>. This simply tells you if a transform you're using changes the total number of lines in the file.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.7.0-1.7.1</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.7.0...v1.7.1">2014.12.15<a></a></small>
<ul class="changelog_history">
<li>Fix for <tt>spacing_after_comma</tt> so that newlines count as space after commas</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.6.0-1.7.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.6.0...v1.7.0">2014.12.12<a></a></small>
<ul class="changelog_history">
<li>New rule <tt>spacing_after_comma</tt></li>
<li>Indentation improvements</li>
<li>Fix Block RegExp triggering in <tt>no_unnecessary_double_quotes</tt></li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.5.7-1.6.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.5.7...v1.6.0">2014.08.30<a></a></small>
<ul class="changelog_history">
<li>New rule <tt>prefer_english_operator</tt></li>
<li>New behavior <tt>.coffeelintignore</tt> works just like a .gitignore</li>
<li>Exposed <tt>ErrorReporter</tt> to 3rd parties so reporters can be used outside our CLI implementation. See <a href="https://github.com/clutchski/coffeelint/pull/330">#330</a> for details</li>
<li>Linting from STDIN will look for config files.</li>
<li><tt>-f</tt> option can specify a package.json that contains <tt>coffeelintConfig</tt></li>
<li>Depricated <tt>--no-color</tt> in favor of new <tt>--color=<always never auto></tt> option</li>
<li>Fixed an indentation bug when you have a blank line in the middle of a chained call.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.5.3-1.5.5</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.5.3...v1.5.5">2014.08.12<a></a></small>
<ul class="changelog_history">
<li>#317 Change $HOME search priority to account for non-default windows users.</li>
<li>#320 Remove support for chaining calls using a dot at the end of a line.</li>
<li>Removed extra messages that broke XML output.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.5.2-1.5.3</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.5.2...v1.5.3">2014.08.08<a></a></small>
<ul class="changelog_history">
<li>Indentation improvements for chained calls. See #285</li>
<li>Fixed some missing cases for <tt>space_operators</tt></li>
<li>Fix for a last-line edge case in <tt>no_implicit_parens</tt></li>
<li>Fixed trailing semicolons in multi-line strings with multiple embedded tokens</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.5.0-1.5.2</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.5.0...master">2014.06.07<a></a></small>
<ul class="changelog_history">
<li>#280 Fix for fat-arrow false positives. It was producing errors when the class is defined inside a function (AMD style)</li>
<li>MANY indentation fixes. See #282.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.4.1-1.5.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.4.1...v1.5.0">2014.05.28<a></a></small>
<ul class="changelog_history">
<li>New: --cache and coffeelint.setCache(obj)</li>
<li>Rule module loading is not limited to running from the commandline. See #279</li>
<li>Fix for #173: Empty functions surrounded by parens don't require
spacing.</li>
<li>Fix for #271: trailing semicolons multiline strings are ignored</li>
<li>Fix for #214: <tt>no_unnecessary_fat_arrows</tt> doesn't trigger if the function contains super.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.3.0-1.4.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.3.0...v1.4.0">2014.05.16<a></a></small>
<ul class="changelog_history">
<li>Similar to grunt-cli, the coffeelint command will now load the project-specific version of coffeelint if there is one there.</li>
<li>3rd party rules don't have to be globally installed any more.</li>
<li>Added --reporter option that also supports 3rd party reporters. <a href="https://github.com/janraasch/coffeelint-stylish">coffeelint-stylish</a> is the first one available.</li>
<li>Documentation for <a href="https://github.com/clutchski/coffeelint/blob/master/doc/user.md">new users</a> and <a href="https://github.com/clutchski/coffeelint/blob/master/doc/integration.md">3rd party developers</a>.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.2.0-1.3.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.2.0...v1.3.0">2014.04.17<a></a></small>
<ul class="changelog_history">
<li>New rule <tt>no_empty_functions</tt></li>
<li>Improved documentation on how to contribute in README.md</li>
<li>Rules using the AST work with a minified version of CoffeeScript</li>
<li>Fixed line length check to account for windows line endings</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.1.0-1.2.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.1.0...v1.2.0">2014.03.07<a></a></small>
<ul class="changelog_history">
<li>New rule <tt>no_debugger</tt></li>
<li>New rule <tt>no_interpolation_in_single_quotes</tt></li>
<li>New rule <tt>no_unnecessary_double_quotes</tt></li>
<li>Strict mode for <tt>no_implicit_parens</tt>. Turning it off allows implicit parens when they span multiple lines.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">1.0.8-1.1.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v1.0.8...v1.1.0">2014.02.22<a></a></small>
<ul class="changelog_history">
<li>CoffeeScript 1.7 support</li>
<li>Dropped support for CoffeeScript 1.6. (Use ~1.0.0 if you still need it)</li>
</ul>
</div>
<div>
<h3 class="changelog_header">0.6.0-1.0.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v0.6.0...v1.0.0">2013.11.21<a></a></small>
<ul class="changelog_history">
<li>CoffeeLint will detect config files by default.</li>
<li>New rule <tt>colon_assignment_spacing</tt></li>
<li>New rule <tt>no_unnecessary_fat_arrows</tt></li>
<li>New rule <tt>missing_fat_arrows</tt></li>
<li>Added an option to <tt>no_trailing_whitespace</tt> to forbid trailing space on empty lines</li>
<li>Added an option to <tt>no_implicit_braces</tt> to allow unambiguous implicit braces</li>
<li>Fixed --makeconfig</li>
<li>New option: --checkstyle</li>
<li>Fixed invalid XML produced by --jslint</li>
<li>Removed the need for the -r flag. It remains for backward compatibility but doesn't do anything now</li>
</ul>
</div>
<div>
<h3 class="changelog_header">0.5.7-0.6.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v0.5.7...v0.6.0">2013.10.10<a></a></small>
<ul class="changelog_history">
<li>New internal structure to support custom rules.</li>
<li>Dropped support for NodeJS 0.6.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">0.5.6-0.5.7</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v0.5.6...v0.5.7">2013.08.10<a></a></small>
<ul class="changelog_history">
<li>CSVReporter now has a column for last line to account for cyclomatic complexity spanning the length of the function</li>
<li>Added support for literate CoffeeScript</li>
<li>Dropped support for CoffeeScript 1.4 and 1.5</li>
<li>Fixed <tt>non_empty_constructor_needs_parens</tt> for namespaced constructors</li>
<li>Simplified the build process to allow installing direct from the git repo</li>
<li>More fixes to indentation checking (continued https://github.com/clutchski/coffeelint/issues/107)</li>
<li>Fixed spacing error when returning negative numbers (https://github.com/clutchski/coffeelint/issues/129)</li>
<li>Fixed arrow spacing in callback parameters (https://github.com/clutchski/coffeelint/issues/131)</li>
<li>Added beginning and end line numbers for cyclomatic complexity (https://github.com/clutchski/coffeelint/pull/134)</li>
<li>Added header to CSVReporter</li>
<li>Fixes for <tt>space_operators</tt>(https://github.com/clutchski/coffeelint/issues/137)</li>
</ul>
</div>
<div>
<h3 class="changelog_header">0.5.5-0.5.6</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v0.5.4...v0.5.6">2013.06.07<a></a></small>
<ul class="changelog_history">
<li>Added <tt>no_empty_param_list</tt> rule.</li>
<li>Added the <tt>--makeconfig</tt> option.</li>
<li>CoffeeScript 1.5 and 1.6 compatibility</li>
<li>Fixed indentation of chained functions. (https://github.com/clutchski/coffeelint/issues/107, fixed 1/2 of #4)</li>
<li>Fixed bug in <tt>no_stand_alone_at</tt> (https://github.com/jashkenas/coffee-script/issues/1601)</li>
<li>Added <tt>arrow_spacing</tt> rule (require spaces around arrows)</li>
<li>Added <tt>empty_constructor_needs_parens</tt></li>
<li>Added <tt>non_empty_constructor_needs_parens</tt></li>
<li>Added <tt>duplicate_key</tt> (http://jslinterrors.com/duplicate-key-a/)</li>
<li>Added <tt>no_trailing_whitespace.allowed_in_comments</tt> rule option (Allow trailing space in comments. Created to allow markdown)</li>
<li>Added <tt>newlines_after_classes</tt> rule</li>
<li>Line length exception. Lines containing only a link are ignored.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">0.5.4</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v0.5.3...v0.5.4">2012.11.06<a></a></small>
<ul class="changelog_history">
<li>Support for default configuration file using environment variable <tt>COFFEELINT_CONFIG</tt>.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">0.5.3</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v0.5.2...v0.5.3">2012.11.06<a></a></small>
<ul class="changelog_history">
<li>Added <tt>no_stand_alone_at</tt> rule.</li>
<li>Fixed correctly reporting line numbers of compilation errors after line 10.</li>
<li>Fixed incomplete results output.</li>
</ul>
</div>
<div>
<h3 class="changelog_header">0.5.2</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v0.5.1...v0.5.2">2012.09.18</a></small>
</div>
<ul class="changelog_history">
<li>Added <tt>--nocolor</tt> option.</li>
<li>My main man ruddzw fixed issue #58, in which the <tt>-q</tt> option was
suppressing information even when it was off.</li>
<li>Fixed broken <tt>jslint</tt> option.</li>
<li>The <tt>no_trailing_semicolons</tt> rule now works on Windows
files.</li>
</ul>
<div>
<h3 class="changelog_header">0.5.1</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v0.5.0...v0.5.1">2012.09.15</a></small>
</div>
<ul class="changelog_history">
<li>Show CoffeeScript syntax errors in the same manner as lint
errors.</li>
<li>Brad Dunbar added the <tt>-q</tt> command line option, which
only prints errors.</li>
</ul>
<div>
<h3 class="changelog_header">0.5.0</h3>
<small class="changelog_date">- <a href="https://github.com/clutchski/coffeelint/compare/v0.4.0...v0.5.0">2012.09.08</a></small>
</div>
<ul class="changelog_history">
<li>Lint code from stdin with the <tt>--stdin</tt> option, thanks
to sjz.</li>
<li>Added the <tt>no_implicit_parens</tt> rule.</li>
<li>Leandro Ostera added the <tt>--jslint</tt> reporter, to allow
CoffeeLint to integrate with the Jenkin's violations plugin.</li>
<li>Implicit braces are always allowed in in class
defiinitions, thanks to Omar Khan.</li>
<li>CoffeeLint now requires CoffeeScript 1.3.3</li>
</ul>
<div>
<h3 class="changelog_header">0.4.0</h3>
<small class="changelog_date">- 2012.04.06</small>
</div>
<ul class="changelog_history">
<li>Added fancy coloured output and proper CSV output.</li>
<li>Directories can be recursively linted.</li>
<li>Added the <tt>line endings</tt> rule.</li>
<li>Rewrote the command line tool in CoffeeScript.</li>
</ul>
<div>
<h3 class="changelog_header">0.3.0</h3>
<small class="changelog_date">- 2012.03.13</small>
</div>
<ul class="changelog_history">
<li>Added the <tt>no_backticks</tt> rule.</li>
<li>Colorized the command line output.</li>
<li>Added validation for the rule names.</li>
<li>Allowed windows line endings, thanks to <a href="https://github.com/szinsli">szinsli</a>.</li>
</ul>
<div>
<h3 class="changelog_header">0.2.0</h3>
<small class="changelog_date">- 2012.01.26</small>
</div>
<ul class="changelog_history">
<li>Added warnings, which will be reported, but won't fail
the command line tool.
</li>
</ul>
<div>
<h3 class="changelog_header">0.1.0</h3>
<small class="changelog_date">- 2012.01.22</small>
</div>
<ul class="changelog_history">
<li>Initial CoffeeLint release.</li>
</ul>
</div>
</div>
<a href="http://github.com/clutchski/coffeelint">
<img class="forkme" src="https://web.archive.org/web/20180929154522im_/http://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub"/>
</a>
<script type="text/javascript" src="https://web.archive.org/web/20180929154522js_/http://www.coffeelint.org/js/vendor/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="https://web.archive.org/web/20180929154522js_/http://www.coffeelint.org/js/vendor/coffee-script.js"></script>
<script type="text/javascript" src="https://web.archive.org/web/20180929154522js_/http://www.coffeelint.org/js/coffeelint.js"></script>
<script type="text/javascript" src="https://web.archive.org/web/20180929154522js_/http://www.coffeelint.org/js/trycoffeelint.js"></script>
</body>
</html>
<!--
FILE ARCHIVED ON 15:45:22 Sep 29, 2018 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 22:55:35 Mar 05, 2019.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
-->
<!--
playback timings (ms):
LoadShardBlock: 99.504 (3)
esindex: 0.005
captures_list: 119.445
CDXLines.iter: 8.545 (3)
PetaboxLoader3.datanode: 131.406 (5)
exclusion.robots: 0.12
exclusion.robots.policy: 0.113
RedisCDXSource: 8.46
PetaboxLoader3.resolve: 191.448 (3)
load_resource: 237.101
-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment