coffeelint 1.11.0 → 1.14.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Coffeelint [![Build Status](https://travis-ci.org/zmbush/coffeelint-ruby.svg?branch=master)](https://travis-ci.org/zmbush/coffeelint-ruby) [![Gem Version](https://badge.fury.io/rb/coffeelint.png)](http://badge.fury.io/rb/coffeelint)
2
2
 
3
- Using coffeelint version: v1.11.0
3
+ Using coffeelint version: v1.14.0
4
4
 
5
5
  Coffeelint is a set of simple ruby bindings for [coffeelint](https://github.com/clutchski/coffeelint).
6
6
 
@@ -82,7 +82,7 @@ mergeDefaultConfig = function(userConfig) {
82
82
  try {
83
83
  ruleLoader = nodeRequire('./ruleLoader');
84
84
  ruleLoader.loadFromConfig(coffeelint, userConfig);
85
- } catch (_error) {}
85
+ } catch (undefined) {}
86
86
  config = {};
87
87
  if (userConfig.coffeelint) {
88
88
  config.coffeelint = userConfig.coffeelint;
@@ -141,8 +141,8 @@ coffeelint.trimConfig = function(userConfig) {
141
141
  coffeelint.invertLiterate = function(source) {
142
142
  var len, line, n, newSource, ref;
143
143
  source = CoffeeScript.helpers.invertLiterate(source);
144
- newSource = "";
145
- ref = source.split("\n");
144
+ newSource = '';
145
+ ref = source.split('\n');
146
146
  for (n = 0, len = ref.length; n < len; n++) {
147
147
  line = ref[n];
148
148
  if (line.match(/^#/)) {
@@ -162,24 +162,24 @@ coffeelint.registerRule = function(RuleConstructor, ruleName) {
162
162
  ruleName = void 0;
163
163
  }
164
164
  p = new RuleConstructor;
165
- name = (p != null ? (ref = p.rule) != null ? ref.name : void 0 : void 0) || "(unknown)";
165
+ name = (p != null ? (ref = p.rule) != null ? ref.name : void 0 : void 0) || '(unknown)';
166
166
  e = function(msg) {
167
167
  throw new Error("Invalid rule: " + name + " " + msg);
168
168
  };
169
169
  if (p.rule == null) {
170
- e("Rules must provide rule attribute with a default configuration.");
170
+ e('Rules must provide rule attribute with a default configuration.');
171
171
  }
172
172
  if (p.rule.name == null) {
173
- e("Rule defaults require a name");
173
+ e('Rule defaults require a name');
174
174
  }
175
175
  if ((ruleName != null) && ruleName !== p.rule.name) {
176
176
  e("Mismatched rule name: " + ruleName);
177
177
  }
178
178
  if (p.rule.message == null) {
179
- e("Rule defaults require a message");
179
+ e('Rule defaults require a message');
180
180
  }
181
181
  if (p.rule.description == null) {
182
- e("Rule defaults require a description");
182
+ e('Rule defaults require a description');
183
183
  }
184
184
  if ((ref1 = p.rule.level) !== 'ignore' && ref1 !== 'warn' && ref1 !== 'error') {
185
185
  e("Default level must be 'ignore', 'warn', or 'error'");
@@ -189,7 +189,7 @@ coffeelint.registerRule = function(RuleConstructor, ruleName) {
189
189
  e("'tokens' is required for 'lintToken'");
190
190
  }
191
191
  } else if (typeof p.lintLine !== 'function' && typeof p.lintAST !== 'function') {
192
- e("Rules must implement lintToken, lintLine, or lintAST");
192
+ e('Rules must implement lintToken, lintLine, or lintAST');
193
193
  }
194
194
  RULES[p.rule.name] = p.rule;
195
195
  return _rules[p.rule.name] = RuleConstructor;
@@ -284,7 +284,7 @@ hasSyntaxError = function(source) {
284
284
  try {
285
285
  CoffeeScript.tokens(source);
286
286
  return false;
287
- } catch (_error) {}
287
+ } catch (undefined) {}
288
288
  return true;
289
289
  };
290
290
 
@@ -314,7 +314,7 @@ coffeelint.lint = function(source, userConfig, literate) {
314
314
  source = this.invertLiterate(source);
315
315
  }
316
316
  if ((userConfig != null ? (ref = userConfig.coffeelint) != null ? ref.transforms : void 0 : void 0) != null) {
317
- sourceLength = source.split("\n").length;
317
+ sourceLength = source.split('\n').length;
318
318
  ref2 = userConfig != null ? (ref1 = userConfig.coffeelint) != null ? ref1.transforms : void 0 : void 0;
319
319
  for (n = 0, len = ref2.length; n < len; n++) {
320
320
  m = ref2[n];
@@ -322,9 +322,9 @@ coffeelint.lint = function(source, userConfig, literate) {
322
322
  ruleLoader = nodeRequire('./ruleLoader');
323
323
  transform = ruleLoader.require(m);
324
324
  source = transform(source);
325
- } catch (_error) {}
325
+ } catch (undefined) {}
326
326
  }
327
- if (sourceLength !== source.split("\n").length && config.transform_messes_up_line_numbers.level !== 'ignore') {
327
+ if (sourceLength !== source.split('\n').length && config.transform_messes_up_line_numbers.level !== 'ignore') {
328
328
  errors.push(extend({
329
329
  lineNumber: 1,
330
330
  context: "File was transformed from " + sourceLength + " lines to " + (source.split("\n").length) + " lines"
@@ -429,7 +429,7 @@ coffeelint.setCache = function(obj) {
429
429
  module.exports={
430
430
  "name": "coffeelint",
431
431
  "description": "Lint your CoffeeScript",
432
- "version": "1.11.0",
432
+ "version": "1.14.0",
433
433
  "homepage": "http://www.coffeelint.org",
434
434
  "keywords": [
435
435
  "lint",
@@ -470,6 +470,7 @@ module.exports={
470
470
  "testrule": "npm run compile && ./vowsrunner.js --spec",
471
471
  "posttest": "npm run lint",
472
472
  "prepublish": "cake prepublish",
473
+ "postpublish": "cake postpublish",
473
474
  "publish": "cake publish",
474
475
  "install": "cake install",
475
476
  "lint": "cake compile && ./bin/coffeelint .",
@@ -545,12 +546,12 @@ module.exports = ASTLinter = (function(superClass) {
545
546
  };
546
547
 
547
548
  ASTLinter.prototype.lint = function() {
548
- var coffeeError, err, errors, j, len, ref, rule, v;
549
+ var coffeeError, err, error, errors, j, len, ref, rule, v;
549
550
  errors = [];
550
551
  try {
551
552
  this.node = this.CoffeeScript.nodes(this.source);
552
- } catch (_error) {
553
- coffeeError = _error;
553
+ } catch (error) {
554
+ coffeeError = error;
554
555
  err = this._parseCoffeeScriptError(coffeeError);
555
556
  if (err != null) {
556
557
  errors.push(err);
@@ -646,7 +647,7 @@ module.exports = BaseLinter = (function() {
646
647
  }
647
648
  level = attrs.level;
648
649
  if (level !== 'ignore' && level !== 'warn' && level !== 'error') {
649
- throw new Error("unknown level " + level);
650
+ throw new Error("unknown level " + level + " for rule: " + ruleName);
650
651
  }
651
652
  if (level === 'error' || level === 'warn') {
652
653
  attrs.rule = ruleName;
@@ -657,7 +658,7 @@ module.exports = BaseLinter = (function() {
657
658
  };
658
659
 
659
660
  BaseLinter.prototype.acceptRule = function(rule) {
660
- throw new Error("acceptRule needs to be overridden in the subclass");
661
+ throw new Error('acceptRule needs to be overridden in the subclass');
661
662
  };
662
663
 
663
664
  BaseLinter.prototype.setupRules = function(rules) {
@@ -675,7 +676,7 @@ module.exports = BaseLinter = (function() {
675
676
  results.push(void 0);
676
677
  }
677
678
  } else if (level !== 'ignore') {
678
- throw new Error("unknown level " + level);
679
+ throw new Error("unknown level " + level + " for rule: " + rule);
679
680
  } else {
680
681
  results.push(void 0);
681
682
  }
@@ -851,15 +852,8 @@ module.exports = LexicalLinter = (function(superClass) {
851
852
  };
852
853
 
853
854
  LexicalLinter.prototype.lintToken = function(token) {
854
- var base, errors, j, len, lineNumber, ref, ref1, rule, type, v, value;
855
- type = token[0], value = token[1], lineNumber = token[2];
856
- if (typeof lineNumber === "object") {
857
- if (type === 'OUTDENT' || type === 'INDENT') {
858
- lineNumber = lineNumber.last_line;
859
- } else {
860
- lineNumber = lineNumber.first_line;
861
- }
862
- }
855
+ var base, errors, j, len, lineNumber, ref, ref1, ref2, rule, type, v, value;
856
+ type = token[0], value = token[1], (ref = token[2], lineNumber = ref.first_line);
863
857
  if ((base = this.tokensByLine)[lineNumber] == null) {
864
858
  base[lineNumber] = [];
865
859
  }
@@ -867,10 +861,10 @@ module.exports = LexicalLinter = (function(superClass) {
867
861
  this.lineNumber = lineNumber || this.lineNumber || 0;
868
862
  this.tokenApi.lineNumber = this.lineNumber;
869
863
  errors = [];
870
- ref = this.rules;
871
- for (j = 0, len = ref.length; j < len; j++) {
872
- rule = ref[j];
873
- if (!(ref1 = token[0], indexOf.call(rule.tokens, ref1) >= 0)) {
864
+ ref1 = this.rules;
865
+ for (j = 0, len = ref1.length; j < len; j++) {
866
+ rule = ref1[j];
867
+ if (!(ref2 = token[0], indexOf.call(rule.tokens, ref2) >= 0)) {
874
868
  continue;
875
869
  }
876
870
  v = this.normalizeResult(rule, rule.lintToken(token, this.tokenApi));
@@ -885,8 +879,11 @@ module.exports = LexicalLinter = (function(superClass) {
885
879
  if (attrs == null) {
886
880
  attrs = {};
887
881
  }
888
- attrs.lineNumber = this.lineNumber + 1;
889
- attrs.line = this.tokenApi.lines[this.lineNumber];
882
+ if (attrs.lineNumber == null) {
883
+ attrs.lineNumber = this.lineNumber;
884
+ }
885
+ attrs.lineNumber += 1;
886
+ attrs.line = this.tokenApi.lines[attrs.lineNumber - 1];
890
887
  return LexicalLinter.__super__.createError.call(this, ruleName, attrs);
891
888
  };
892
889
 
@@ -935,7 +932,7 @@ LineApi = (function() {
935
932
  this.context["class"].classIndents = null;
936
933
  }
937
934
  }
938
- if (this.context["class"].inClass && !line.match(/^\s*$/)) {
935
+ if (!line.match(/^\s*$/)) {
939
936
  this.context["class"].lastUnemptyLineInClass = this.lineNumber;
940
937
  }
941
938
  } else {
@@ -1021,6 +1018,7 @@ module.exports = LineLinter = (function(superClass) {
1021
1018
  for (lineNumber = i = 0, len = ref.length; i < len; lineNumber = ++i) {
1022
1019
  line = ref[lineNumber];
1023
1020
  this.lineApi.lineNumber = this.lineNumber = lineNumber;
1021
+ this.lineApi.line = this.lineApi.lines[lineNumber];
1024
1022
  this.lineApi.maintainClassContext(line);
1025
1023
  this.collectInlineConfig(line);
1026
1024
  ref1 = this.lintLine(line);
@@ -1056,7 +1054,7 @@ module.exports = LineLinter = (function(superClass) {
1056
1054
  ref = result[2].split(',');
1057
1055
  for (i = 0, len = ref.length; i < len; i++) {
1058
1056
  r = ref[i];
1059
- rules.push(r.replace(/^\s+|\s+$/g, ""));
1057
+ rules.push(r.replace(/^\s+|\s+$/g, ''));
1060
1058
  }
1061
1059
  }
1062
1060
  this.block_config[cmd][this.lineNumber] = rules;
@@ -1108,7 +1106,7 @@ module.exports = ArrowSpacing = (function() {
1108
1106
  name: 'arrow_spacing',
1109
1107
  level: 'ignore',
1110
1108
  message: 'Function arrows (-> and =>) must be spaced properly',
1111
- 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>"
1109
+ 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>'
1112
1110
  };
1113
1111
 
1114
1112
  ArrowSpacing.prototype.tokens = ['->', '=>'];
@@ -1119,28 +1117,15 @@ module.exports = ArrowSpacing = (function() {
1119
1117
  if (!pp) {
1120
1118
  return;
1121
1119
  }
1122
- if (!token.spaced && (pp[1] === "(" && (pp.generated == null)) && tokenApi.peek(1)[0] === 'INDENT' && tokenApi.peek(2)[0] === 'OUTDENT') {
1120
+ if (!token.spaced && tokenApi.peek(1)[0] === 'INDENT' && tokenApi.peek(2)[0] === 'OUTDENT') {
1123
1121
  return null;
1124
- } else if (!(((token.spaced != null) || (token.newLine != null) || this.atEof(tokenApi)) && (((pp.spaced != null) || pp[0] === 'TERMINATOR') || (pp.generated != null) || pp[0] === "INDENT" || (pp[1] === "(" && (pp.generated == null))))) {
1122
+ } 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))))) {
1125
1123
  return true;
1126
1124
  } else {
1127
1125
  return null;
1128
1126
  }
1129
1127
  };
1130
1128
 
1131
- ArrowSpacing.prototype.atEof = function(tokenApi) {
1132
- var i, j, len, ref, ref1, token, tokens;
1133
- tokens = tokenApi.tokens, i = tokenApi.i;
1134
- ref = tokens.slice(i + 1);
1135
- for (j = 0, len = ref.length; j < len; j++) {
1136
- token = ref[j];
1137
- if (!(token.generated || ((ref1 = token[0]) === 'OUTDENT' || ref1 === 'TERMINATOR'))) {
1138
- return false;
1139
- }
1140
- }
1141
- return true;
1142
- };
1143
-
1144
1129
  return ArrowSpacing;
1145
1130
 
1146
1131
  })();
@@ -1174,7 +1159,7 @@ module.exports = BracesSpacing = (function() {
1174
1159
  while (true) {
1175
1160
  totalDifference += difference;
1176
1161
  nearestToken = tokenApi.peek(totalDifference);
1177
- if (nearestToken[0] === 'OUTDENT') {
1162
+ if (nearestToken[0] === 'OUTDENT' || (nearestToken.generated != null)) {
1178
1163
  continue;
1179
1164
  }
1180
1165
  return nearestToken;
@@ -1240,7 +1225,7 @@ module.exports = CamelCaseClasses = (function() {
1240
1225
  name: 'camel_case_classes',
1241
1226
  level: 'error',
1242
1227
  message: 'Class name should be UpperCamelCased',
1243
- 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."
1228
+ 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.'
1244
1229
  };
1245
1230
 
1246
1231
  CamelCaseClasses.prototype.tokens = ['CLASS'];
@@ -1288,7 +1273,7 @@ module.exports = ColonAssignmentSpacing = (function() {
1288
1273
  left: 0,
1289
1274
  right: 0
1290
1275
  },
1291
- 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# Good\nobject = {spacing : true}\nclass Dog\n canBark : true\n\n# Bad\nobject = {spacing: true}\nclass Cat\n canBark: false\n</code></pre>"
1276
+ 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>'
1292
1277
  };
1293
1278
 
1294
1279
  ColonAssignmentSpacing.prototype.tokens = [':'];
@@ -1318,7 +1303,7 @@ module.exports = ColonAssignmentSpacing = (function() {
1318
1303
  return null;
1319
1304
  } else {
1320
1305
  return {
1321
- context: "Incorrect spacing around column " + token[2].first_column + ".\nExpected left: " + spaceRules.left + ", right: " + spaceRules.right + ".\nGot left: " + leftSpacing + ", right: " + rightSpacing + "."
1306
+ context: "Incorrect spacing around column " + token[2].first_column
1322
1307
  };
1323
1308
  }
1324
1309
  };
@@ -1337,10 +1322,10 @@ module.exports = CyclomaticComplexity = (function() {
1337
1322
 
1338
1323
  CyclomaticComplexity.prototype.rule = {
1339
1324
  name: 'cyclomatic_complexity',
1340
- value: 10,
1341
1325
  level: 'ignore',
1342
1326
  message: 'The cyclomatic complexity is too damn high',
1343
- description: 'Examine the complexity of your application.'
1327
+ value: 10,
1328
+ description: 'Examine the complexity of your function.'
1344
1329
  };
1345
1330
 
1346
1331
  CyclomaticComplexity.prototype.getComplexity = function(node) {
@@ -1356,16 +1341,16 @@ module.exports = CyclomaticComplexity = (function() {
1356
1341
  return void 0;
1357
1342
  };
1358
1343
 
1359
- CyclomaticComplexity.prototype.lintNode = function(node, line) {
1344
+ CyclomaticComplexity.prototype.lintNode = function(node) {
1360
1345
  var complexity, error, name, ref, rule;
1361
1346
  name = (ref = this.astApi) != null ? ref.getNodeName(node) : void 0;
1362
1347
  complexity = this.getComplexity(node);
1363
1348
  node.eachChild((function(_this) {
1364
1349
  return function(childNode) {
1365
- var nodeLine;
1366
- nodeLine = childNode.locationData.first_line;
1367
- if (childNode) {
1368
- return complexity += _this.lintNode(childNode, nodeLine);
1350
+ var childComplexity, ref1;
1351
+ childComplexity = _this.lintNode(childNode);
1352
+ if (((ref1 = _this.astApi) != null ? ref1.getNodeName(childNode) : void 0) !== 'Code') {
1353
+ return complexity += childComplexity;
1369
1354
  }
1370
1355
  };
1371
1356
  })(this));
@@ -1373,7 +1358,7 @@ module.exports = CyclomaticComplexity = (function() {
1373
1358
  if (name === 'Code' && complexity >= rule.value) {
1374
1359
  error = this.astApi.createError({
1375
1360
  context: complexity + 1,
1376
- lineNumber: line + 1,
1361
+ lineNumber: node.locationData.first_line + 1,
1377
1362
  lineNumberEnd: node.locationData.last_line + 1
1378
1363
  });
1379
1364
  if (error) {
@@ -1397,7 +1382,7 @@ module.exports = DuplicateKey = (function() {
1397
1382
  name: 'duplicate_key',
1398
1383
  level: 'error',
1399
1384
  message: 'Duplicate key defined in object or class',
1400
- description: "Prevents defining duplicate keys in object literals and classes"
1385
+ description: 'Prevents defining duplicate keys in object literals and classes'
1401
1386
  };
1402
1387
 
1403
1388
  DuplicateKey.prototype.tokens = ['IDENTIFIER', '{', '}'];
@@ -1469,7 +1454,7 @@ module.exports = EmptyConstructorNeedsParens = (function() {
1469
1454
  name: 'empty_constructor_needs_parens',
1470
1455
  level: 'ignore',
1471
1456
  message: 'Invoking a constructor without parens and without arguments',
1472
- description: "Requires constructors with no parameters to include the parens"
1457
+ description: 'Requires constructors with no parameters to include the parens'
1473
1458
  };
1474
1459
 
1475
1460
  EmptyConstructorNeedsParens.prototype.tokens = ['UNARY'];
@@ -1533,7 +1518,7 @@ module.exports = EnsureComprehensions = (function() {
1533
1518
  EnsureComprehensions.prototype.forBlock = false;
1534
1519
 
1535
1520
  EnsureComprehensions.prototype.lintToken = function(token, tokenApi) {
1536
- var atEqual, idents, numCallEnds, numCallStarts, peeker, prevIdents, prevToken, ref, ref1;
1521
+ var atEqual, idents, numCallEnds, numCallStarts, numParenEnds, numParenStarts, peeker, prevIdents, prevToken, ref, ref1;
1537
1522
  idents = this.findIdents(tokenApi);
1538
1523
  if (this.forBlock) {
1539
1524
  this.forBlock = false;
@@ -1543,6 +1528,8 @@ module.exports = EnsureComprehensions = (function() {
1543
1528
  atEqual = false;
1544
1529
  numCallEnds = 0;
1545
1530
  numCallStarts = 0;
1531
+ numParenStarts = 0;
1532
+ numParenEnds = 0;
1546
1533
  prevIdents = [];
1547
1534
  while ((prevToken = tokenApi.peek(peeker))) {
1548
1535
  if (prevToken[0] === 'CALL_END') {
@@ -1551,6 +1538,12 @@ module.exports = EnsureComprehensions = (function() {
1551
1538
  if (prevToken[0] === 'CALL_START') {
1552
1539
  numCallStarts++;
1553
1540
  }
1541
+ if (prevToken[0] === '(') {
1542
+ numParenStarts++;
1543
+ }
1544
+ if (prevToken[0] === ')') {
1545
+ numParenEnds++;
1546
+ }
1554
1547
  if (prevToken[0] === 'IDENTIFIER') {
1555
1548
  if (!atEqual) {
1556
1549
  prevIdents.push(prevToken[1]);
@@ -1561,12 +1554,12 @@ module.exports = EnsureComprehensions = (function() {
1561
1554
  if (((ref1 = prevToken[0]) === '(' || ref1 === '->' || ref1 === 'TERMINATOR') || (prevToken.newLine != null)) {
1562
1555
  break;
1563
1556
  }
1564
- if (prevToken[0] === '=') {
1557
+ if (prevToken[0] === '=' && numParenEnds === numParenStarts) {
1565
1558
  atEqual = true;
1566
1559
  }
1567
1560
  peeker--;
1568
1561
  }
1569
- if (atEqual && prevIdents.length > 0 && numCallStarts === numCallEnds) {
1562
+ if (atEqual && numCallStarts === numCallEnds) {
1570
1563
  return {
1571
1564
  context: ''
1572
1565
  };
@@ -1615,14 +1608,17 @@ module.exports = EOLLast = (function() {
1615
1608
  name: 'eol_last',
1616
1609
  level: 'ignore',
1617
1610
  message: 'File does not end with a single newline',
1618
- description: "Checks that the file ends with a single newline"
1611
+ description: 'Checks that the file ends with a single newline'
1619
1612
  };
1620
1613
 
1621
1614
  EOLLast.prototype.lintLine = function(line, lineApi) {
1615
+ var isNewline, previousIsNewline;
1622
1616
  if (!lineApi.isLastLine()) {
1623
1617
  return null;
1624
1618
  }
1625
- if (line.length) {
1619
+ isNewline = line.length === 0;
1620
+ previousIsNewline = lineApi.lineCount > 1 ? lineApi.lines[lineApi.lineNumber - 1].length === 0 : false;
1621
+ if (!(isNewline && !previousIsNewline)) {
1626
1622
  return true;
1627
1623
  }
1628
1624
  };
@@ -1634,7 +1630,8 @@ module.exports = EOLLast = (function() {
1634
1630
 
1635
1631
 
1636
1632
  },{}],18:[function(require,module,exports){
1637
- var Indentation;
1633
+ var Indentation,
1634
+ 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; };
1638
1635
 
1639
1636
  module.exports = Indentation = (function() {
1640
1637
  Indentation.prototype.rule = {
@@ -1642,23 +1639,25 @@ module.exports = Indentation = (function() {
1642
1639
  value: 2,
1643
1640
  level: 'error',
1644
1641
  message: 'Line contains inconsistent indentation',
1645
- 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."
1642
+ 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.'
1646
1643
  };
1647
1644
 
1648
1645
  Indentation.prototype.tokens = ['INDENT', '[', ']', '.'];
1649
1646
 
1647
+ Indentation.prototype.keywords = ['->', '=>', '@', 'CATCH', 'CLASS', 'ELSE', 'FINALLY', 'FOR', 'FORIN', 'FOROF', 'IDENTIFIER', 'IF', 'LEADING_WHEN', 'LOOP', 'RETURN', 'SWITCH', 'THROW', 'TRY', 'UNTIL', 'WHEN', 'WHILE', 'YIELD'];
1648
+
1650
1649
  function Indentation() {
1651
1650
  this.arrayTokens = [];
1652
1651
  }
1653
1652
 
1654
1653
  Indentation.prototype.lintToken = function(token, tokenApi) {
1655
- var currentLine, expected, ignoreIndent, isArrayIndent, isInterpIndent, isMultiline, lineNumber, lines, numIndents, previous, previousSymbol, ref, ref1, ref2, type;
1654
+ var currentLine, expected, ignoreIndent, isArrayIndent, isMultiline, lineNumber, lines, numIndents, previous, previousSymbol, ref, ref1, ref2, type;
1656
1655
  type = token[0], numIndents = token[1], (ref = token[2], lineNumber = ref.first_line);
1657
1656
  lines = tokenApi.lines, lineNumber = tokenApi.lineNumber;
1658
1657
  expected = tokenApi.config[this.rule.name].value;
1659
1658
  if (type === '.') {
1660
1659
  currentLine = lines[lineNumber];
1661
- if (((ref1 = currentLine.match(/\S/i)) != null ? ref1[0] : void 0) === '.') {
1660
+ if (((ref1 = currentLine.match(/\S/)) != null ? ref1[0] : void 0) === '.') {
1662
1661
  return this.handleChain(tokenApi, expected);
1663
1662
  }
1664
1663
  return void 0;
@@ -1667,20 +1666,18 @@ module.exports = Indentation = (function() {
1667
1666
  this.lintArray(token);
1668
1667
  return void 0;
1669
1668
  }
1670
- if (token.generated != null) {
1669
+ if ((token.generated != null) || (token.explicit != null)) {
1671
1670
  return null;
1672
1671
  }
1673
- previous = tokenApi.peek(-2);
1674
- isInterpIndent = previous && previous[0] === '+';
1675
1672
  previous = tokenApi.peek(-1);
1676
1673
  isArrayIndent = this.inArray() && (previous != null ? previous.newLine : void 0);
1677
1674
  previousSymbol = (ref2 = tokenApi.peek(-1)) != null ? ref2[0] : void 0;
1678
1675
  isMultiline = previousSymbol === '=' || previousSymbol === ',';
1679
- ignoreIndent = isInterpIndent || isArrayIndent || isMultiline;
1676
+ ignoreIndent = isArrayIndent || isMultiline;
1680
1677
  numIndents = this.getCorrectIndent(tokenApi);
1681
- if (!ignoreIndent && numIndents !== expected) {
1678
+ if (!ignoreIndent && !(indexOf.call(numIndents, expected) >= 0)) {
1682
1679
  return {
1683
- context: "Expected " + expected + " got " + numIndents
1680
+ context: "Expected " + expected + " got " + numIndents[0]
1684
1681
  };
1685
1682
  }
1686
1683
  };
@@ -1717,9 +1714,9 @@ module.exports = Indentation = (function() {
1717
1714
  checkNum = lineNumber - prevNum;
1718
1715
  if (checkNum >= 0) {
1719
1716
  prevLine = lines[checkNum];
1720
- if (prevLine.match(/\S/i)[0] === '.' || checkNum === lastCheck) {
1721
- currentSpaces = (ref = currentLine.match(/\S/i)) != null ? ref.index : void 0;
1722
- prevSpaces = (ref1 = prevLine.match(/\S/i)) != null ? ref1.index : void 0;
1717
+ if (prevLine.match(/\S/)[0] === '.' || checkNum === lastCheck) {
1718
+ currentSpaces = (ref = currentLine.match(/\S/)) != null ? ref.index : void 0;
1719
+ prevSpaces = (ref1 = prevLine.match(/\S/)) != null ? ref1.index : void 0;
1723
1720
  numIndents = currentSpaces - prevSpaces;
1724
1721
  prevIsIndent = prevSpaces % expected !== 0;
1725
1722
  currIsIndent = currentSpaces % expected !== 0;
@@ -1735,21 +1732,81 @@ module.exports = Indentation = (function() {
1735
1732
  }
1736
1733
  };
1737
1734
 
1735
+ Indentation.prototype.grabLineTokens = function(tokenApi, lineNumber, all) {
1736
+ var i, k, len, len1, ref, ref1, results, results1, tok, tokensByLine;
1737
+ if (all == null) {
1738
+ all = false;
1739
+ }
1740
+ tokensByLine = tokenApi.tokensByLine;
1741
+ while (!((tokensByLine[lineNumber] != null) || lineNumber === 0)) {
1742
+ lineNumber--;
1743
+ }
1744
+ if (all) {
1745
+ ref = tokensByLine[lineNumber];
1746
+ results = [];
1747
+ for (i = 0, len = ref.length; i < len; i++) {
1748
+ tok = ref[i];
1749
+ results.push(tok);
1750
+ }
1751
+ return results;
1752
+ } else {
1753
+ ref1 = tokensByLine[lineNumber];
1754
+ results1 = [];
1755
+ for (k = 0, len1 = ref1.length; k < len1; k++) {
1756
+ tok = ref1[k];
1757
+ if ((tok.generated == null) && tok[0] !== 'OUTDENT') {
1758
+ results1.push(tok);
1759
+ }
1760
+ }
1761
+ return results1;
1762
+ }
1763
+ };
1764
+
1738
1765
  Indentation.prototype.getCorrectIndent = function(tokenApi) {
1739
- var curIndent, i, lineNumber, lines, prevIndent, prevLine, prevNum, ref, ref1, ref2, tokens;
1740
- lineNumber = tokenApi.lineNumber, lines = tokenApi.lines, tokens = tokenApi.tokens, i = tokenApi.i;
1766
+ var _, curIndent, i, j, len, lineNumber, lines, prevIndent, prevNum, prevTokens, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ret, skipAssign, t, tokens, tryLine;
1767
+ lineNumber = tokenApi.lineNumber, lines = tokenApi.lines, tokens = tokenApi.tokens;
1741
1768
  curIndent = (ref = lines[lineNumber].match(/\S/)) != null ? ref.index : void 0;
1742
1769
  prevNum = 1;
1743
1770
  while (/^\s*(#|$)/.test(lines[lineNumber - prevNum])) {
1744
1771
  prevNum += 1;
1745
1772
  }
1746
- prevLine = lines[lineNumber - prevNum];
1747
- prevIndent = (ref1 = prevLine.match(/^(\s*)\./)) != null ? ref1[1].length : void 0;
1748
- if (prevIndent > 0) {
1749
- return curIndent - ((ref2 = prevLine.match(/\S/)) != null ? ref2.index : void 0);
1773
+ prevTokens = this.grabLineTokens(tokenApi, lineNumber - prevNum);
1774
+ if (((ref1 = prevTokens[0]) != null ? ref1[0] : void 0) === 'INDENT') {
1775
+ return [curIndent - ((ref2 = prevTokens[1]) != null ? ref2[2].first_column : void 0), curIndent - prevTokens[0][1]];
1750
1776
  } else {
1751
- return tokens[i][1];
1777
+ prevIndent = (ref3 = prevTokens[0]) != null ? ref3[2].first_column : void 0;
1778
+ for (j = i = 0, len = prevTokens.length; i < len; j = ++i) {
1779
+ _ = prevTokens[j];
1780
+ if (!(prevTokens[j][0] === '=' && ((ref4 = prevTokens[j + 1]) != null ? ref4[0] : void 0) === 'IF')) {
1781
+ continue;
1782
+ }
1783
+ skipAssign = curIndent - prevTokens[j + 1][2].first_column;
1784
+ ret = curIndent - prevIndent;
1785
+ if (skipAssign < 0) {
1786
+ return [ret];
1787
+ }
1788
+ return [skipAssign, ret];
1789
+ }
1790
+ while (prevIndent > curIndent) {
1791
+ tryLine = lineNumber - prevNum;
1792
+ prevTokens = this.grabLineTokens(tokenApi, tryLine, true);
1793
+ if (((ref5 = prevTokens[0]) != null ? ref5[0] : void 0) === 'INDENT') {
1794
+ prevIndent = prevTokens[0][1];
1795
+ prevTokens = prevTokens.slice(1);
1796
+ }
1797
+ t = 0;
1798
+ while (!((prevTokens[t] == null) || (ref6 = prevTokens[t][0], indexOf.call(this.keywords, ref6) >= 0))) {
1799
+ t++;
1800
+ }
1801
+ prevTokens = prevTokens.slice(t);
1802
+ prevNum++;
1803
+ if (prevTokens[0] == null) {
1804
+ continue;
1805
+ }
1806
+ prevIndent = (ref7 = prevTokens[0]) != null ? ref7[2].first_column : void 0;
1807
+ }
1752
1808
  }
1809
+ return [curIndent - prevIndent];
1753
1810
  };
1754
1811
 
1755
1812
  return Indentation;
@@ -1769,7 +1826,7 @@ module.exports = LineEndings = (function() {
1769
1826
  level: 'ignore',
1770
1827
  value: 'unix',
1771
1828
  message: 'Line contains incorrect line endings',
1772
- description: "This rule ensures your project uses only <tt>windows</tt> or\n<tt>unix</tt> line endings. This rule is disabled by default."
1829
+ description: 'This rule ensures your project uses only <tt>windows</tt> or\n<tt>unix</tt> line endings. This rule is disabled by default.'
1773
1830
  };
1774
1831
 
1775
1832
  LineEndings.prototype.lintLine = function(line, lineApi) {
@@ -1820,7 +1877,7 @@ module.exports = MaxLineLength = (function() {
1820
1877
  level: 'error',
1821
1878
  limitComments: true,
1822
1879
  message: 'Line exceeds maximum allowed length',
1823
- description: "This rule imposes a maximum line length on your code. <a\nhref=\"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."
1880
+ description: 'This rule imposes a maximum line length on your code. <a\nhref="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.'
1824
1881
  };
1825
1882
 
1826
1883
  MaxLineLength.prototype.lintLine = function(line, lineApi) {
@@ -1890,7 +1947,7 @@ module.exports = MissingFatArrows = (function() {
1890
1947
  level: 'ignore',
1891
1948
  is_strict: false,
1892
1949
  message: 'Used `this` in a function without a fat arrow',
1893
- 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."
1950
+ 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.'
1894
1951
  };
1895
1952
 
1896
1953
  MissingFatArrows.prototype.lintAST = function(node, astApi) {
@@ -1900,15 +1957,18 @@ module.exports = MissingFatArrows = (function() {
1900
1957
  };
1901
1958
 
1902
1959
  MissingFatArrows.prototype.lintNode = function(node, methods) {
1903
- var error, is_strict, ref;
1960
+ var error, isStrict, ref;
1904
1961
  if (methods == null) {
1905
1962
  methods = [];
1906
1963
  }
1907
- is_strict = (ref = this.astApi.config[this.rule.name]) != null ? ref.is_strict : void 0;
1964
+ isStrict = (ref = this.astApi.config[this.rule.name]) != null ? ref.is_strict : void 0;
1965
+ if (this.isPrototype(node)) {
1966
+ return;
1967
+ }
1908
1968
  if (this.isConstructor(node)) {
1909
1969
  return;
1910
1970
  }
1911
- if ((!this.isFatArrowCode(node)) && (is_strict ? true : indexOf.call(methods, node) < 0) && (this.needsFatArrow(node))) {
1971
+ if ((!this.isFatArrowCode(node)) && (isStrict ? true : indexOf.call(methods, node) < 0) && (this.needsFatArrow(node))) {
1912
1972
  error = this.astApi.createError({
1913
1973
  lineNumber: node.locationData.first_line + 1
1914
1974
  });
@@ -1946,6 +2006,18 @@ module.exports = MissingFatArrows = (function() {
1946
2006
  return this.astApi.getNodeName(node) === 'Obj';
1947
2007
  };
1948
2008
 
2009
+ MissingFatArrows.prototype.isPrototype = function(node) {
2010
+ var i, ident, len, props, ref, ref1;
2011
+ props = (node != null ? (ref = node.variable) != null ? ref.properties : void 0 : void 0) || [];
2012
+ for (i = 0, len = props.length; i < len; i++) {
2013
+ ident = props[i];
2014
+ if (((ref1 = ident.name) != null ? ref1.value : void 0) === 'prototype') {
2015
+ return true;
2016
+ }
2017
+ }
2018
+ return false;
2019
+ };
2020
+
1949
2021
  MissingFatArrows.prototype.isThis = function(node) {
1950
2022
  return this.isValue(node) && node.base.value === 'this';
1951
2023
  };
@@ -1997,23 +2069,63 @@ module.exports = NewlinesAfterClasses = (function() {
1997
2069
  value: 3,
1998
2070
  level: 'ignore',
1999
2071
  message: 'Wrong count of newlines between a class and other code',
2000
- 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."
2072
+ 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.'
2001
2073
  };
2002
2074
 
2003
- NewlinesAfterClasses.prototype.lintLine = function(line, lineApi) {
2004
- var context, ending, got, lineNumber;
2005
- ending = lineApi.config[this.rule.name].value;
2006
- if (!ending || lineApi.isLastLine()) {
2007
- return null;
2008
- }
2009
- lineNumber = lineApi.lineNumber, context = lineApi.context;
2010
- if (!context["class"].inClass && (context["class"].lastUnemptyLineInClass != null) && (lineNumber - context["class"].lastUnemptyLineInClass) !== ending) {
2011
- got = lineNumber - context["class"].lastUnemptyLineInClass;
2012
- return {
2013
- context: "Expected " + ending + " got " + got
2014
- };
2075
+ NewlinesAfterClasses.prototype.tokens = ['CLASS', '}', '{'];
2076
+
2077
+ NewlinesAfterClasses.prototype.classBracesCount = 0;
2078
+
2079
+ NewlinesAfterClasses.prototype.classCount = 0;
2080
+
2081
+ NewlinesAfterClasses.prototype.lintToken = function(token, tokenApi) {
2082
+ var afters, befores, comment, ending, got, lineNumber, lines, numIndents, outdent, ref, ref1, ref2, start, trueLine, type;
2083
+ type = token[0], numIndents = token[1], (ref = token[2], lineNumber = ref.first_line);
2084
+ lines = tokenApi.lines;
2085
+ ending = tokenApi.config[this.rule.name].value;
2086
+ if (type === 'CLASS') {
2087
+ this.classCount++;
2088
+ }
2089
+ if (this.classCount > 0 && (token.generated != null)) {
2090
+ if (type === '{' && ((ref1 = token.origin) != null ? ref1[0] : void 0) === ':') {
2091
+ this.classBracesCount++;
2092
+ }
2093
+ if (type === '}' && ((ref2 = token.origin) != null ? ref2[0] : void 0) === 'OUTDENT') {
2094
+ this.classBracesCount--;
2095
+ this.classCount--;
2096
+ if (this.classCount === 0 && this.classBracesCount === 0) {
2097
+ befores = 1;
2098
+ afters = 1;
2099
+ comment = 0;
2100
+ outdent = token.origin[2].first_line;
2101
+ start = Math.min(lineNumber, outdent);
2102
+ trueLine = Infinity;
2103
+ while (/^\s*(#|$)/.test(lines[start + afters])) {
2104
+ if (/^\s*#/.test(lines[start + afters])) {
2105
+ comment += 1;
2106
+ } else {
2107
+ trueLine = Math.min(trueLine, start + afters);
2108
+ }
2109
+ afters += 1;
2110
+ }
2111
+ while (/^\s*(#|$)/.test(lines[start - befores])) {
2112
+ if (/^\s*#/.test(lines[start - befores])) {
2113
+ comment += 1;
2114
+ } else {
2115
+ trueLine = Math.min(trueLine, start - befores);
2116
+ }
2117
+ befores += 1;
2118
+ }
2119
+ got = afters + befores - comment - 2;
2120
+ if (got !== ending && trueLine + ending <= lines.length) {
2121
+ return {
2122
+ context: "Expected " + ending + " got " + got,
2123
+ lineNumber: trueLine
2124
+ };
2125
+ }
2126
+ }
2127
+ }
2015
2128
  }
2016
- return null;
2017
2129
  };
2018
2130
 
2019
2131
  return NewlinesAfterClasses;
@@ -2032,10 +2144,10 @@ module.exports = NoBackticks = (function() {
2032
2144
  name: 'no_backticks',
2033
2145
  level: 'error',
2034
2146
  message: 'Backticks are forbidden',
2035
- 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."
2147
+ 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.'
2036
2148
  };
2037
2149
 
2038
- NoBackticks.prototype.tokens = ["JS"];
2150
+ NoBackticks.prototype.tokens = ['JS'];
2039
2151
 
2040
2152
  NoBackticks.prototype.lintToken = function(token, tokenApi) {
2041
2153
  return true;
@@ -2058,10 +2170,10 @@ module.exports = NoDebugger = (function() {
2058
2170
  level: 'warn',
2059
2171
  message: 'Found debugging code',
2060
2172
  console: false,
2061
- description: "This rule detects `debugger` and optionally `console` calls\nThis rule is `warn` by default."
2173
+ description: 'This rule detects `debugger` and optionally `console` calls\nThis rule is `warn` by default.'
2062
2174
  };
2063
2175
 
2064
- NoDebugger.prototype.tokens = ["DEBUGGER", "IDENTIFIER"];
2176
+ NoDebugger.prototype.tokens = ['DEBUGGER', 'IDENTIFIER'];
2065
2177
 
2066
2178
  NoDebugger.prototype.lintToken = function(token, tokenApi) {
2067
2179
  var method, ref, ref1;
@@ -2102,7 +2214,7 @@ module.exports = NoEmptyFunctions = (function() {
2102
2214
  name: 'no_empty_functions',
2103
2215
  level: 'ignore',
2104
2216
  message: 'Empty function',
2105
- 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>"
2217
+ 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>'
2106
2218
  };
2107
2219
 
2108
2220
  NoEmptyFunctions.prototype.lintAST = function(node, astApi) {
@@ -2141,10 +2253,10 @@ module.exports = NoEmptyParamList = (function() {
2141
2253
  name: 'no_empty_param_list',
2142
2254
  level: 'ignore',
2143
2255
  message: 'Empty parameter list is forbidden',
2144
- 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."
2256
+ 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.'
2145
2257
  };
2146
2258
 
2147
- NoEmptyParamList.prototype.tokens = ["PARAM_START"];
2259
+ NoEmptyParamList.prototype.tokens = ['PARAM_START'];
2148
2260
 
2149
2261
  NoEmptyParamList.prototype.lintToken = function(token, tokenApi) {
2150
2262
  var nextType;
@@ -2170,27 +2282,36 @@ module.exports = NoImplicitBraces = (function() {
2170
2282
  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.'
2171
2283
  };
2172
2284
 
2173
- NoImplicitBraces.prototype.tokens = ['{', 'OUTDENT', 'CLASS'];
2285
+ NoImplicitBraces.prototype.tokens = ['{', 'OUTDENT', 'CLASS', 'IDENTIFIER'];
2174
2286
 
2175
2287
  function NoImplicitBraces() {
2176
2288
  this.isClass = false;
2177
- this.classBrace = false;
2289
+ this.className = void 0;
2178
2290
  }
2179
2291
 
2180
2292
  NoImplicitBraces.prototype.lintToken = function(token, tokenApi) {
2181
- var lineNum, previousToken, type, val;
2293
+ var lineNum, peekTwo, prevToken, type, val;
2182
2294
  type = token[0], val = token[1], lineNum = token[2];
2183
2295
  if (type === 'OUTDENT' || type === 'CLASS') {
2184
2296
  return this.trackClass.apply(this, arguments);
2185
2297
  }
2186
- if (token.generated) {
2187
- if (this.classBrace) {
2188
- this.classBrace = false;
2189
- return;
2190
- }
2298
+ if (type === 'IDENTIFIER' && this.isClass && ((this.className == null) || tokenApi.peek(-1)[0] === 'EXTENDS')) {
2299
+ this.className = val;
2300
+ }
2301
+ if (token.generated && type === '{') {
2191
2302
  if (!tokenApi.config[this.rule.name].strict) {
2192
- previousToken = tokenApi.peek(-1)[0];
2193
- if (previousToken === 'INDENT') {
2303
+ prevToken = tokenApi.peek(-1)[0];
2304
+ if (prevToken === 'INDENT' || prevToken === 'TERMINATOR') {
2305
+ return;
2306
+ }
2307
+ }
2308
+ if (this.isClass) {
2309
+ prevToken = tokenApi.peek(-1)[0];
2310
+ if (prevToken === 'TERMINATOR') {
2311
+ return;
2312
+ }
2313
+ peekTwo = tokenApi.peek(-2);
2314
+ if (peekTwo[0] === 'IDENTIFIER' && peekTwo[1] === this.className) {
2194
2315
  return;
2195
2316
  }
2196
2317
  }
@@ -2203,11 +2324,10 @@ module.exports = NoImplicitBraces = (function() {
2203
2324
  ref = [token, tokenApi.peek()], (ref1 = ref[0], n0 = ref1[0], ln = ref1[ref1.length - 1]), (ref2 = ref[1], n1 = ref2[0]);
2204
2325
  if (n0 === 'OUTDENT' && n1 === 'TERMINATOR') {
2205
2326
  this.isClass = false;
2206
- this.classBrace = false;
2207
2327
  }
2208
2328
  if (n0 === 'CLASS') {
2209
2329
  this.isClass = true;
2210
- this.classBrace = true;
2330
+ this.className = void 0;
2211
2331
  }
2212
2332
  return null;
2213
2333
  };
@@ -2226,10 +2346,10 @@ module.exports = NoImplicitParens = (function() {
2226
2346
 
2227
2347
  NoImplicitParens.prototype.rule = {
2228
2348
  name: 'no_implicit_parens',
2229
- strict: true,
2230
2349
  level: 'ignore',
2231
2350
  message: 'Implicit parens are forbidden',
2232
- 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."
2351
+ strict: true,
2352
+ 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.'
2233
2353
  };
2234
2354
 
2235
2355
  NoImplicitParens.prototype.tokens = ['CALL_END'];
@@ -2349,10 +2469,10 @@ module.exports = NoPlusPlus = (function() {
2349
2469
  name: 'no_plusplus',
2350
2470
  level: 'ignore',
2351
2471
  message: 'The increment and decrement operators are forbidden',
2352
- 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."
2472
+ 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.'
2353
2473
  };
2354
2474
 
2355
- NoPlusPlus.prototype.tokens = ["++", "--"];
2475
+ NoPlusPlus.prototype.tokens = ['++', '--'];
2356
2476
 
2357
2477
  NoPlusPlus.prototype.lintToken = function(token, tokenApi) {
2358
2478
  return {
@@ -2384,7 +2504,7 @@ module.exports = NoPrivateFunctionFatArrows = (function() {
2384
2504
  name: 'no_private_function_fat_arrows',
2385
2505
  level: 'warn',
2386
2506
  message: 'Used the fat arrow for a private function',
2387
- description: "Warns when you use the fat arrow for a private function\ninside a class defintion scope. It is not necessary and\nit does not do anything."
2507
+ 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.'
2388
2508
  };
2389
2509
 
2390
2510
  NoPrivateFunctionFatArrows.prototype.lintAST = function(node, astApi) {
@@ -2474,7 +2594,7 @@ module.exports = NoStandAloneAt = (function() {
2474
2594
  name: 'no_stand_alone_at',
2475
2595
  level: 'ignore',
2476
2596
  message: '@ must not be used stand alone',
2477
- description: "This rule checks that no stand alone @ are in use, they are\ndiscouraged. Further information in CoffeScript issue <a\nhref=\"https://github.com/jashkenas/coffee-script/issues/1601\">\n#1601</a>"
2597
+ description: 'This rule checks that no stand alone @ are in use, they are\ndiscouraged. Further information in CoffeeScript issue <a\nhref="https://github.com/jashkenas/coffee-script/issues/1601">\n#1601</a>'
2478
2598
  };
2479
2599
 
2480
2600
  NoStandAloneAt.prototype.tokens = ['@'];
@@ -2514,7 +2634,7 @@ module.exports = NoTabs = (function() {
2514
2634
  name: 'no_tabs',
2515
2635
  level: 'error',
2516
2636
  message: 'Line contains tab indentation',
2517
- description: "This rule forbids tabs in indentation. Enough said. It is enabled by\ndefault."
2637
+ description: 'This rule forbids tabs in indentation. Enough said. It is enabled by\ndefault.'
2518
2638
  };
2519
2639
 
2520
2640
  NoTabs.prototype.lintLine = function(line, lineApi) {
@@ -2541,15 +2661,20 @@ module.exports = NoThis = (function() {
2541
2661
 
2542
2662
  NoThis.prototype.rule = {
2543
2663
  name: 'no_this',
2544
- description: 'This rule prohibits \'this\'.\nUse \'@\' instead.',
2545
2664
  level: 'ignore',
2546
- message: "Don't use 'this', use '@' instead"
2665
+ message: "Don't use 'this', use '@' instead",
2666
+ description: 'This rule prohibits \'this\'.\nUse \'@\' instead.'
2547
2667
  };
2548
2668
 
2549
2669
  NoThis.prototype.tokens = ['THIS'];
2550
2670
 
2551
2671
  NoThis.prototype.lintToken = function(token, tokenApi) {
2552
- return true;
2672
+ var level, nextToken, ref;
2673
+ level = tokenApi.config.no_stand_alone_at.level;
2674
+ nextToken = (ref = tokenApi.peek(1)) != null ? ref[0] : void 0;
2675
+ if (!(level !== 'ignore' && nextToken !== '.')) {
2676
+ return true;
2677
+ }
2553
2678
  };
2554
2679
 
2555
2680
  return NoThis;
@@ -2568,7 +2693,7 @@ module.exports = NoThrowingStrings = (function() {
2568
2693
  name: 'no_throwing_strings',
2569
2694
  level: 'error',
2570
2695
  message: 'Throwing strings is forbidden',
2571
- 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://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."
2696
+ 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://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.'
2572
2697
  };
2573
2698
 
2574
2699
  NoThrowingStrings.prototype.tokens = ['THROW'];
@@ -2602,7 +2727,7 @@ module.exports = NoTrailingSemicolons = (function() {
2602
2727
  name: 'no_trailing_semicolons',
2603
2728
  level: 'error',
2604
2729
  message: 'Line contains a trailing semicolon',
2605
- 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."
2730
+ 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.'
2606
2731
  };
2607
2732
 
2608
2733
  NoTrailingSemicolons.prototype.lintLine = function(line, lineApi) {
@@ -2657,7 +2782,7 @@ module.exports = NoTrailingWhitespace = (function() {
2657
2782
  message: 'Line ends with trailing whitespace',
2658
2783
  allowed_in_comments: false,
2659
2784
  allowed_in_empty_lines: true,
2660
- description: "This rule forbids trailing whitespace in your code, since it is\nneedless cruft. It is enabled by default."
2785
+ description: 'This rule forbids trailing whitespace in your code, since it is\nneedless cruft. It is enabled by default.'
2661
2786
  };
2662
2787
 
2663
2788
  NoTrailingWhitespace.prototype.lintLine = function(line, lineApi) {
@@ -2781,7 +2906,7 @@ module.exports = NoUnnecessaryFatArrows = (function() {
2781
2906
  name: 'no_unnecessary_fat_arrows',
2782
2907
  level: 'warn',
2783
2908
  message: 'Unnecessary fat arrow',
2784
- description: "Disallows defining functions with fat arrows when `this`\nis not used within the function."
2909
+ description: 'Disallows defining functions with fat arrows when `this`\nis not used within the function.'
2785
2910
  };
2786
2911
 
2787
2912
  NoUnnecessaryFatArrows.prototype.lintAST = function(node, astApi) {
@@ -2861,7 +2986,7 @@ module.exports = NonEmptyConstructorNeedsParens = (function(superClass) {
2861
2986
  name: 'non_empty_constructor_needs_parens',
2862
2987
  level: 'ignore',
2863
2988
  message: 'Invoking a constructor without parens and with arguments',
2864
- description: "Requires constructors with parameters to include the parens"
2989
+ description: 'Requires constructors with parameters to include the parens'
2865
2990
  };
2866
2991
 
2867
2992
  NonEmptyConstructorNeedsParens.prototype.handleExpectedCallStart = function(expectedCallStart) {
@@ -2884,10 +3009,10 @@ module.exports = PreferEnglishOperator = (function() {
2884
3009
 
2885
3010
  PreferEnglishOperator.prototype.rule = {
2886
3011
  name: 'prefer_english_operator',
2887
- description: 'This rule prohibits &&, ||, ==, != and !.\nUse and, or, is, isnt, and not instead.\n!! for converting to a boolean is ignored.',
2888
3012
  level: 'ignore',
3013
+ message: 'Don\'t use &&, ||, ==, !=, or !',
2889
3014
  doubleNotLevel: 'ignore',
2890
- message: 'Don\'t use &&, ||, ==, !=, or !'
3015
+ description: 'This rule prohibits &&, ||, ==, != and !.\nUse and, or, is, isnt, and not instead.\n!! for converting to a boolean is ignored.'
2891
3016
  };
2892
3017
 
2893
3018
  PreferEnglishOperator.prototype.tokens = ['COMPARE', 'UNARY_MATH', 'LOGIC'];
@@ -2947,7 +3072,7 @@ module.exports = SpaceOperators = (function() {
2947
3072
  name: 'space_operators',
2948
3073
  level: 'ignore',
2949
3074
  message: 'Operators must be spaced properly',
2950
- description: "This rule enforces that operators have space around them."
3075
+ description: 'This rule enforces that operators have spaces around them.'
2951
3076
  };
2952
3077
 
2953
3078
  SpaceOperators.prototype.tokens = ['+', '-', '=', '**', 'MATH', 'COMPARE', 'LOGIC', 'COMPOUND_ASSIGN', 'STRING_START', 'STRING_END', 'CALL_START', 'CALL_END'];
@@ -3053,9 +3178,9 @@ var SpacingAfterComma;
3053
3178
  module.exports = SpacingAfterComma = (function() {
3054
3179
  SpacingAfterComma.prototype.rule = {
3055
3180
  name: 'spacing_after_comma',
3056
- description: 'This rule requires a space after commas.',
3057
3181
  level: 'ignore',
3058
- message: 'Spaces are required after commas'
3182
+ message: 'a space is required after commas',
3183
+ description: 'This rule checks to make sure you have a space after commas.'
3059
3184
  };
3060
3185
 
3061
3186
  SpacingAfterComma.prototype.tokens = [',', 'REGEX_START', 'REGEX_END'];
@@ -3076,9 +3201,7 @@ module.exports = SpacingAfterComma = (function() {
3076
3201
  return;
3077
3202
  }
3078
3203
  if (!(token.spaced || token.newLine || token.generated || this.isRegexFlag(token, tokenApi))) {
3079
- return {
3080
- context: token[1]
3081
- };
3204
+ return true;
3082
3205
  }
3083
3206
  };
3084
3207
 
@@ -3107,7 +3230,7 @@ module.exports = TransformMessesUpLineNumbers = (function() {
3107
3230
  name: 'transform_messes_up_line_numbers',
3108
3231
  level: 'warn',
3109
3232
  message: 'Transforming source messes up line numbers',
3110
- description: "This rule detects when changes are made by transform function,\nand warns that line numbers are probably incorrect."
3233
+ description: 'This rule detects when changes are made by transform function,\nand warns that line numbers are probably incorrect.'
3111
3234
  };
3112
3235
 
3113
3236
  TransformMessesUpLineNumbers.prototype.tokens = [];