coffeelint 1.11.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 = [];