coffeelint 0.3.0 → 0.4.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/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=doc
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.4.1
3
+ Using coffeelint version: v1.6.1
4
4
 
5
5
  Coffeelint is a set of simple ruby bindings for [coffeelint](https://github.com/clutchski/coffeelint).
6
6
 
@@ -50,6 +50,8 @@ Coffeelint.run_test_suite(directory, :config_file => 'coffeelint_config.json')
50
50
 
51
51
  Then it will load the config options from that file.
52
52
 
53
+ To use a local version of coffeelint instead of the one bundled with the gem, You can set the path with `Coffeelint.set_path(/path/to/coffeelint.js)`
54
+
53
55
  Additionally, if you are using rails you also get the rake task:
54
56
 
55
57
  rake coffeelint
@@ -2,7 +2,7 @@
2
2
  module.exports={
3
3
  "name": "coffeelint",
4
4
  "description": "Lint your CoffeeScript",
5
- "version": "1.4.1",
5
+ "version": "1.6.1",
6
6
  "homepage": "http://www.coffeelint.org",
7
7
  "keywords": [
8
8
  "lint",
@@ -12,6 +12,7 @@ module.exports={
12
12
  "author": "Matthew Perpick <clutchski@gmail.com>",
13
13
  "main": "./lib/coffeelint.js",
14
14
  "engines": {
15
+ "npm": ">=1.3.7",
15
16
  "node": ">=0.8.0"
16
17
  },
17
18
  "repository": {
@@ -25,8 +26,9 @@ module.exports={
25
26
  "browserify": "~3.37",
26
27
  "coffee-script": "~1.7",
27
28
  "coffeeify": "~0.6.0",
28
- "glob": ">=3.1.9",
29
- "optimist": ">=0.2.8",
29
+ "glob": "^4.0.0",
30
+ "ignore": "^2.2.15",
31
+ "optimist": "^0.6.1",
30
32
  "resolve": "^0.6.3"
31
33
  },
32
34
  "devDependencies": {
@@ -41,14 +43,14 @@ module.exports={
41
43
  ],
42
44
  "scripts": {
43
45
  "pretest": "cake compile",
44
- "test": "coffee vowsrunner.coffee --spec test/*.coffee test/*.litcoffee",
46
+ "test": "./vowsrunner.js --spec test/*.coffee test/*.litcoffee",
45
47
  "posttest": "npm run lint",
46
48
  "prepublish": "cake prepublish",
47
49
  "publish": "cake publish",
48
50
  "install": "cake install",
49
- "lint": "cake compile && ./bin/coffeelint -f coffeelint.json src/*.coffee test/*.coffee test/*.litcoffee",
50
- "lint-csv": "cake compile && ./bin/coffeelint --csv -f coffeelint.json src/*.coffee test/*.coffee",
51
- "lint-jslint": "cake compile && ./bin/coffeelint --jslint -f coffeelint.json src/*.coffee test/*.coffee",
51
+ "lint": "cake compile && ./bin/coffeelint .",
52
+ "lint-csv": "cake compile && ./bin/coffeelint --csv .",
53
+ "lint-jslint": "cake compile && ./bin/coffeelint --jslint .",
52
54
  "compile": "cake compile"
53
55
  }
54
56
  }
@@ -278,17 +280,18 @@ CoffeeLint
278
280
  Copyright (c) 2011 Matthew Perpick.
279
281
  CoffeeLint is freely distributable under the MIT license.
280
282
  */
281
- var ASTLinter, CoffeeScript, ERROR, IGNORE, LexicalLinter, LineLinter, RULES, WARN, coffeelint, cs, defaults, difference, extend, hasSyntaxError, mergeDefaultConfig, packageJSON, _rules,
283
+ var ASTLinter, CoffeeScript, ERROR, ErrorReport, IGNORE, LexicalLinter, LineLinter, RULES, WARN, cache, coffeelint, defaults, difference, extend, hasSyntaxError, mergeDefaultConfig, nodeRequire, packageJSON, _rules,
282
284
  __slice = [].slice,
283
285
  __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; };
284
286
 
285
287
  coffeelint = exports;
286
288
 
289
+ nodeRequire = _dereq_;
290
+
287
291
  if (typeof window !== "undefined" && window !== null) {
288
292
  CoffeeScript = window.CoffeeScript;
289
293
  } else {
290
- cs = 'coffee-script';
291
- CoffeeScript = _dereq_(cs);
294
+ CoffeeScript = nodeRequire('coffee-script');
292
295
  }
293
296
 
294
297
  packageJSON = _dereq_('./../package.json');
@@ -340,6 +343,8 @@ LexicalLinter = _dereq_('./lexical_linter.coffee');
340
343
 
341
344
  ASTLinter = _dereq_('./ast_linter.coffee');
342
345
 
346
+ cache = null;
347
+
343
348
  mergeDefaultConfig = function(userConfig) {
344
349
  var config, rule, ruleConfig;
345
350
  config = {};
@@ -407,6 +412,17 @@ coffeelint.registerRule = function(RuleConstructor, ruleName) {
407
412
  return _rules[p.rule.name] = RuleConstructor;
408
413
  };
409
414
 
415
+ coffeelint.getRules = function() {
416
+ var key, output, _i, _len, _ref;
417
+ output = {};
418
+ _ref = Object.keys(RULES).sort();
419
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
420
+ key = _ref[_i];
421
+ output[key] = RULES[key];
422
+ }
423
+ return output;
424
+ };
425
+
410
426
  coffeelint.registerRule(_dereq_('./rules/arrow_spacing.coffee'));
411
427
 
412
428
  coffeelint.registerRule(_dereq_('./rules/no_tabs.coffee'));
@@ -463,6 +479,8 @@ coffeelint.registerRule(_dereq_('./rules/no_interpolation_in_single_quotes.coffe
463
479
 
464
480
  coffeelint.registerRule(_dereq_('./rules/no_empty_functions.coffee'));
465
481
 
482
+ coffeelint.registerRule(_dereq_('./rules/prefer_english_operator.coffee'));
483
+
466
484
  hasSyntaxError = function(source) {
467
485
  try {
468
486
  CoffeeScript.tokens(source);
@@ -471,14 +489,30 @@ hasSyntaxError = function(source) {
471
489
  return true;
472
490
  };
473
491
 
492
+ ErrorReport = _dereq_('./error_report.coffee');
493
+
494
+ coffeelint.getErrorReport = function() {
495
+ return new ErrorReport(coffeelint);
496
+ };
497
+
474
498
  coffeelint.lint = function(source, userConfig, literate) {
475
- var all_errors, astErrors, block_config, cmd, config, disabled, disabled_initially, e, errors, i, l, lexErrors, lexicalLinter, lineErrors, lineLinter, name, next_line, r, rules, s, tokensByLine, _i, _j, _k, _len, _len1, _ref, _ref1, _ref2, _ref3, _ref4;
499
+ var all_errors, astErrors, block_config, cmd, config, disabled, disabled_initially, e, errors, i, l, lexErrors, lexicalLinter, lineErrors, lineLinter, name, next_line, r, ruleLoader, rules, s, tokensByLine, _i, _j, _k, _len, _len1, _ref, _ref1, _ref2, _ref3, _ref4;
476
500
  if (userConfig == null) {
477
501
  userConfig = {};
478
502
  }
479
503
  if (literate == null) {
480
504
  literate = false;
481
505
  }
506
+ try {
507
+ ruleLoader = nodeRequire('./ruleLoader');
508
+ ruleLoader.loadFromConfig(this, userConfig);
509
+ } catch (_error) {}
510
+ if (cache != null) {
511
+ cache.setConfig(userConfig);
512
+ }
513
+ if (cache != null ? cache.has(source) : void 0) {
514
+ return cache != null ? cache.get(source) : void 0;
515
+ }
482
516
  if (literate) {
483
517
  source = this.invertLiterate(source);
484
518
  }
@@ -562,11 +596,110 @@ coffeelint.lint = function(source, userConfig, literate) {
562
596
  }
563
597
  }
564
598
  }
599
+ if (cache != null) {
600
+ cache.set(source, errors);
601
+ }
565
602
  return errors;
566
603
  };
567
604
 
605
+ coffeelint.setCache = function(obj) {
606
+ return cache = obj;
607
+ };
608
+
609
+
610
+ },{"./../package.json":1,"./ast_linter.coffee":2,"./error_report.coffee":5,"./lexical_linter.coffee":6,"./line_linter.coffee":7,"./rules.coffee":8,"./rules/arrow_spacing.coffee":9,"./rules/camel_case_classes.coffee":10,"./rules/colon_assignment_spacing.coffee":11,"./rules/cyclomatic_complexity.coffee":12,"./rules/duplicate_key.coffee":13,"./rules/empty_constructor_needs_parens.coffee":14,"./rules/indentation.coffee":15,"./rules/line_endings.coffee":16,"./rules/max_line_length.coffee":17,"./rules/missing_fat_arrows.coffee":18,"./rules/newlines_after_classes.coffee":19,"./rules/no_backticks.coffee":20,"./rules/no_debugger.coffee":21,"./rules/no_empty_functions.coffee":22,"./rules/no_empty_param_list.coffee":23,"./rules/no_implicit_braces.coffee":24,"./rules/no_implicit_parens.coffee":25,"./rules/no_interpolation_in_single_quotes.coffee":26,"./rules/no_plusplus.coffee":27,"./rules/no_stand_alone_at.coffee":28,"./rules/no_tabs.coffee":29,"./rules/no_throwing_strings.coffee":30,"./rules/no_trailing_semicolons.coffee":31,"./rules/no_trailing_whitespace.coffee":32,"./rules/no_unnecessary_double_quotes.coffee":33,"./rules/no_unnecessary_fat_arrows.coffee":34,"./rules/non_empty_constructor_needs_parens.coffee":35,"./rules/prefer_english_operator.coffee":36,"./rules/space_operators.coffee":37}],5:[function(_dereq_,module,exports){
611
+ var ErrorReport;
612
+
613
+ module.exports = ErrorReport = (function() {
614
+ function ErrorReport(coffeelint) {
615
+ this.coffeelint = coffeelint;
616
+ this.paths = {};
617
+ }
618
+
619
+ ErrorReport.prototype.lint = function(filename, source, config, literate) {
620
+ if (config == null) {
621
+ config = {};
622
+ }
623
+ if (literate == null) {
624
+ literate = false;
625
+ }
626
+ return this.paths[filename] = this.coffeelint.lint(source, config, literate);
627
+ };
628
+
629
+ ErrorReport.prototype.getExitCode = function() {
630
+ var path;
631
+ for (path in this.paths) {
632
+ if (this.pathHasError(path)) {
633
+ return 1;
634
+ }
635
+ }
636
+ return 0;
637
+ };
638
+
639
+ ErrorReport.prototype.getSummary = function() {
640
+ var error, errorCount, errors, path, pathCount, warningCount, _i, _len, _ref;
641
+ pathCount = errorCount = warningCount = 0;
642
+ _ref = this.paths;
643
+ for (path in _ref) {
644
+ errors = _ref[path];
645
+ pathCount++;
646
+ for (_i = 0, _len = errors.length; _i < _len; _i++) {
647
+ error = errors[_i];
648
+ if (error.level === 'error') {
649
+ errorCount++;
650
+ }
651
+ if (error.level === 'warn') {
652
+ warningCount++;
653
+ }
654
+ }
655
+ }
656
+ return {
657
+ errorCount: errorCount,
658
+ warningCount: warningCount,
659
+ pathCount: pathCount
660
+ };
661
+ };
662
+
663
+ ErrorReport.prototype.getErrors = function(path) {
664
+ return this.paths[path];
665
+ };
666
+
667
+ ErrorReport.prototype.pathHasWarning = function(path) {
668
+ return this._hasLevel(path, 'warn');
669
+ };
670
+
671
+ ErrorReport.prototype.pathHasError = function(path) {
672
+ return this._hasLevel(path, 'error');
673
+ };
674
+
675
+ ErrorReport.prototype.hasError = function() {
676
+ var path;
677
+ for (path in this.paths) {
678
+ if (this.pathHasError(path)) {
679
+ return true;
680
+ }
681
+ }
682
+ return false;
683
+ };
684
+
685
+ ErrorReport.prototype._hasLevel = function(path, level) {
686
+ var error, _i, _len, _ref;
687
+ _ref = this.paths[path];
688
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
689
+ error = _ref[_i];
690
+ if (error.level === level) {
691
+ return true;
692
+ }
693
+ }
694
+ return false;
695
+ };
696
+
697
+ return ErrorReport;
698
+
699
+ })();
700
+
568
701
 
569
- },{"./../package.json":1,"./ast_linter.coffee":2,"./lexical_linter.coffee":5,"./line_linter.coffee":6,"./rules.coffee":7,"./rules/arrow_spacing.coffee":8,"./rules/camel_case_classes.coffee":9,"./rules/colon_assignment_spacing.coffee":10,"./rules/cyclomatic_complexity.coffee":11,"./rules/duplicate_key.coffee":12,"./rules/empty_constructor_needs_parens.coffee":13,"./rules/indentation.coffee":14,"./rules/line_endings.coffee":15,"./rules/max_line_length.coffee":16,"./rules/missing_fat_arrows.coffee":17,"./rules/newlines_after_classes.coffee":18,"./rules/no_backticks.coffee":19,"./rules/no_debugger.coffee":20,"./rules/no_empty_functions.coffee":21,"./rules/no_empty_param_list.coffee":22,"./rules/no_implicit_braces.coffee":23,"./rules/no_implicit_parens.coffee":24,"./rules/no_interpolation_in_single_quotes.coffee":25,"./rules/no_plusplus.coffee":26,"./rules/no_stand_alone_at.coffee":27,"./rules/no_tabs.coffee":28,"./rules/no_throwing_strings.coffee":29,"./rules/no_trailing_semicolons.coffee":30,"./rules/no_trailing_whitespace.coffee":31,"./rules/no_unnecessary_double_quotes.coffee":32,"./rules/no_unnecessary_fat_arrows.coffee":33,"./rules/non_empty_constructor_needs_parens.coffee":34,"./rules/space_operators.coffee":35}],5:[function(_dereq_,module,exports){
702
+ },{}],6:[function(_dereq_,module,exports){
570
703
  var BaseLinter, LexicalLinter, TokenApi,
571
704
  __hasProp = {}.hasOwnProperty,
572
705
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
@@ -670,7 +803,7 @@ module.exports = LexicalLinter = (function(_super) {
670
803
  })(BaseLinter);
671
804
 
672
805
 
673
- },{"./base_linter.coffee":3}],6:[function(_dereq_,module,exports){
806
+ },{"./base_linter.coffee":3}],7:[function(_dereq_,module,exports){
674
807
  var BaseLinter, LineApi, LineLinter, configStatement,
675
808
  __hasProp = {}.hasOwnProperty,
676
809
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
@@ -853,7 +986,7 @@ module.exports = LineLinter = (function(_super) {
853
986
  })(BaseLinter);
854
987
 
855
988
 
856
- },{"./base_linter.coffee":3}],7:[function(_dereq_,module,exports){
989
+ },{"./base_linter.coffee":3}],8:[function(_dereq_,module,exports){
857
990
  var ERROR, IGNORE, WARN;
858
991
 
859
992
  ERROR = 'error';
@@ -870,7 +1003,7 @@ module.exports = {
870
1003
  };
871
1004
 
872
1005
 
873
- },{}],8:[function(_dereq_,module,exports){
1006
+ },{}],9:[function(_dereq_,module,exports){
874
1007
  var ArrowSpacing;
875
1008
 
876
1009
  module.exports = ArrowSpacing = (function() {
@@ -888,7 +1021,9 @@ module.exports = ArrowSpacing = (function() {
888
1021
  ArrowSpacing.prototype.lintToken = function(token, tokenApi) {
889
1022
  var pp;
890
1023
  pp = tokenApi.peek(-1);
891
- 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))))) {
1024
+ if (!token.spaced && (pp[1] === "(" && (pp.generated == null)) && tokenApi.peek(1)[0] === 'INDENT' && tokenApi.peek(2)[0] === 'OUTDENT') {
1025
+ return null;
1026
+ } 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))))) {
892
1027
  return true;
893
1028
  } else {
894
1029
  return null;
@@ -913,7 +1048,7 @@ module.exports = ArrowSpacing = (function() {
913
1048
  })();
914
1049
 
915
1050
 
916
- },{}],9:[function(_dereq_,module,exports){
1051
+ },{}],10:[function(_dereq_,module,exports){
917
1052
  var CamelCaseClasses, regexes;
918
1053
 
919
1054
  regexes = {
@@ -960,7 +1095,7 @@ module.exports = CamelCaseClasses = (function() {
960
1095
  })();
961
1096
 
962
1097
 
963
- },{}],10:[function(_dereq_,module,exports){
1098
+ },{}],11:[function(_dereq_,module,exports){
964
1099
  var ColonAssignmentSpacing;
965
1100
 
966
1101
  module.exports = ColonAssignmentSpacing = (function() {
@@ -980,8 +1115,8 @@ module.exports = ColonAssignmentSpacing = (function() {
980
1115
  ColonAssignmentSpacing.prototype.tokens = [':'];
981
1116
 
982
1117
  ColonAssignmentSpacing.prototype.lintToken = function(token, tokenApi) {
983
- var checkSpacing, getSpaceFromToken, isLeftSpaced, isRightSpaced, leftSpacing, nextToken, previousToken, rightSpacing, spacingAllowances, _ref, _ref1;
984
- spacingAllowances = tokenApi.config[this.rule.name].spacing;
1118
+ var checkSpacing, getSpaceFromToken, isLeftSpaced, isRightSpaced, leftSpacing, nextToken, previousToken, rightSpacing, spaceRules, _ref, _ref1;
1119
+ spaceRules = tokenApi.config[this.rule.name].spacing;
985
1120
  previousToken = tokenApi.peek(-1);
986
1121
  nextToken = tokenApi.peek(1);
987
1122
  getSpaceFromToken = function(direction) {
@@ -995,7 +1130,7 @@ module.exports = ColonAssignmentSpacing = (function() {
995
1130
  checkSpacing = function(direction) {
996
1131
  var isSpaced, spacing;
997
1132
  spacing = getSpaceFromToken(direction);
998
- isSpaced = spacing < 0 ? true : spacing === parseInt(spacingAllowances[direction]);
1133
+ isSpaced = spacing < 0 ? true : spacing === parseInt(spaceRules[direction]);
999
1134
  return [isSpaced, spacing];
1000
1135
  };
1001
1136
  _ref = checkSpacing('left'), isLeftSpaced = _ref[0], leftSpacing = _ref[1];
@@ -1004,7 +1139,7 @@ module.exports = ColonAssignmentSpacing = (function() {
1004
1139
  return null;
1005
1140
  } else {
1006
1141
  return {
1007
- context: "Incorrect spacing around column " + token[2].first_column + ".\nExpected left: " + spacingAllowances.left + ", right: " + spacingAllowances.right + ".\nGot left: " + leftSpacing + ", right: " + rightSpacing + "."
1142
+ context: "Incorrect spacing around column " + token[2].first_column + ".\nExpected left: " + spaceRules.left + ", right: " + spaceRules.right + ".\nGot left: " + leftSpacing + ", right: " + rightSpacing + "."
1008
1143
  };
1009
1144
  }
1010
1145
  };
@@ -1014,7 +1149,7 @@ module.exports = ColonAssignmentSpacing = (function() {
1014
1149
  })();
1015
1150
 
1016
1151
 
1017
- },{}],11:[function(_dereq_,module,exports){
1152
+ },{}],12:[function(_dereq_,module,exports){
1018
1153
  var NoTabs;
1019
1154
 
1020
1155
  module.exports = NoTabs = (function() {
@@ -1073,7 +1208,7 @@ module.exports = NoTabs = (function() {
1073
1208
  })();
1074
1209
 
1075
1210
 
1076
- },{}],12:[function(_dereq_,module,exports){
1211
+ },{}],13:[function(_dereq_,module,exports){
1077
1212
  var DuplicateKey;
1078
1213
 
1079
1214
  module.exports = DuplicateKey = (function() {
@@ -1084,7 +1219,7 @@ module.exports = DuplicateKey = (function() {
1084
1219
  description: "Prevents defining duplicate keys in object literals and classes"
1085
1220
  };
1086
1221
 
1087
- DuplicateKey.prototype.tokens = ['IDENTIFIER', "{", "}"];
1222
+ DuplicateKey.prototype.tokens = ['IDENTIFIER', '{', '}'];
1088
1223
 
1089
1224
  function DuplicateKey() {
1090
1225
  this.braceScopes = [];
@@ -1093,11 +1228,11 @@ module.exports = DuplicateKey = (function() {
1093
1228
  DuplicateKey.prototype.lintToken = function(_arg, tokenApi) {
1094
1229
  var type;
1095
1230
  type = _arg[0];
1096
- if (type === "{" || type === "}") {
1231
+ if (type === '{' || type === '}') {
1097
1232
  this.lintBrace.apply(this, arguments);
1098
1233
  return void 0;
1099
1234
  }
1100
- if (type === "IDENTIFIER") {
1235
+ if (type === 'IDENTIFIER') {
1101
1236
  return this.lintIdentifier.apply(this, arguments);
1102
1237
  }
1103
1238
  };
@@ -1142,7 +1277,7 @@ module.exports = DuplicateKey = (function() {
1142
1277
  })();
1143
1278
 
1144
1279
 
1145
- },{}],13:[function(_dereq_,module,exports){
1280
+ },{}],14:[function(_dereq_,module,exports){
1146
1281
  var EmptyConstructorNeedsParens;
1147
1282
 
1148
1283
  module.exports = EmptyConstructorNeedsParens = (function() {
@@ -1189,7 +1324,7 @@ module.exports = EmptyConstructorNeedsParens = (function() {
1189
1324
  })();
1190
1325
 
1191
1326
 
1192
- },{}],14:[function(_dereq_,module,exports){
1327
+ },{}],15:[function(_dereq_,module,exports){
1193
1328
  var Indentation;
1194
1329
 
1195
1330
  module.exports = Indentation = (function() {
@@ -1201,16 +1336,25 @@ module.exports = Indentation = (function() {
1201
1336
  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."
1202
1337
  };
1203
1338
 
1204
- Indentation.prototype.tokens = ['INDENT', "[", "]"];
1339
+ Indentation.prototype.tokens = ['INDENT', '[', ']', '.'];
1205
1340
 
1206
1341
  function Indentation() {
1207
1342
  this.arrayTokens = [];
1208
1343
  }
1209
1344
 
1210
1345
  Indentation.prototype.lintToken = function(token, tokenApi) {
1211
- var currentLine, expected, ignoreIndent, isArrayIndent, isInterpIndent, isMultiline, lineNumber, lines, numIndents, prevNum, previous, previousIndentation, previousLine, previousSymbol, type, _ref;
1212
- type = token[0], numIndents = token[1], lineNumber = token[2];
1213
- if (type === "[" || type === "]") {
1346
+ var currentLine, expected, ignoreIndent, isArrayIndent, isInterpIndent, isMultiline, lineNumber, lines, numIndents, previous, previousSymbol, type, _ref, _ref1, _ref2;
1347
+ type = token[0], numIndents = token[1], (_ref = token[2], lineNumber = _ref.first_line);
1348
+ lines = tokenApi.lines, lineNumber = tokenApi.lineNumber;
1349
+ expected = tokenApi.config[this.rule.name].value;
1350
+ if (type === '.') {
1351
+ currentLine = lines[lineNumber];
1352
+ if (((_ref1 = currentLine.match(/\S/i)) != null ? _ref1[0] : void 0) === '.') {
1353
+ return this.handleChain(tokenApi, expected);
1354
+ }
1355
+ return void 0;
1356
+ }
1357
+ if (type === '[' || type === ']') {
1214
1358
  this.lintArray(token);
1215
1359
  return void 0;
1216
1360
  }
@@ -1221,22 +1365,10 @@ module.exports = Indentation = (function() {
1221
1365
  isInterpIndent = previous && previous[0] === '+';
1222
1366
  previous = tokenApi.peek(-1);
1223
1367
  isArrayIndent = this.inArray() && (previous != null ? previous.newLine : void 0);
1224
- previousSymbol = (_ref = tokenApi.peek(-1)) != null ? _ref[0] : void 0;
1368
+ previousSymbol = (_ref2 = tokenApi.peek(-1)) != null ? _ref2[0] : void 0;
1225
1369
  isMultiline = previousSymbol === '=' || previousSymbol === ',';
1226
1370
  ignoreIndent = isInterpIndent || isArrayIndent || isMultiline;
1227
- if (this.isChainedCall(tokenApi)) {
1228
- lines = tokenApi.lines, lineNumber = tokenApi.lineNumber;
1229
- currentLine = lines[lineNumber];
1230
- prevNum = 1;
1231
- while (/^\s*(#|$)/.test(lines[lineNumber - prevNum])) {
1232
- prevNum += 1;
1233
- }
1234
- previousLine = lines[lineNumber - prevNum];
1235
- previousIndentation = previousLine.match(/^(\s*)/)[1].length;
1236
- numIndents = currentLine.match(/^(\s*)/)[1].length;
1237
- numIndents -= previousIndentation;
1238
- }
1239
- expected = tokenApi.config[this.rule.name].value;
1371
+ numIndents = this.getCorrectIndent(tokenApi);
1240
1372
  if (!ignoreIndent && numIndents !== expected) {
1241
1373
  return {
1242
1374
  context: "Expected " + expected + " got " + numIndents
@@ -1257,37 +1389,58 @@ module.exports = Indentation = (function() {
1257
1389
  return null;
1258
1390
  };
1259
1391
 
1260
- Indentation.prototype.isChainedCall = function(tokenApi) {
1261
- var i, lastNewLineIndex, lines, t, token, tokens;
1262
- tokens = tokenApi.tokens, i = tokenApi.i;
1263
- lines = (function() {
1264
- var _i, _len, _ref, _results;
1265
- _ref = tokens.slice(0, +i + 1 || 9e9);
1266
- _results = [];
1267
- for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
1268
- token = _ref[i];
1269
- if (token.newLine != null) {
1270
- _results.push(i);
1392
+ Indentation.prototype.handleChain = function(tokenApi, expected) {
1393
+ var callStart, checkNum, currIsIndent, currentLine, currentSpaces, findCallStart, lastCheck, lineNumber, lines, numIndents, prevIsIndent, prevLine, prevNum, prevSpaces, _ref, _ref1;
1394
+ lastCheck = 1;
1395
+ callStart = 1;
1396
+ prevNum = 1;
1397
+ lineNumber = tokenApi.lineNumber, lines = tokenApi.lines;
1398
+ currentLine = lines[lineNumber];
1399
+ findCallStart = tokenApi.peek(-callStart);
1400
+ while (findCallStart && findCallStart[0] !== 'TERMINATOR') {
1401
+ lastCheck = findCallStart[2].first_line;
1402
+ callStart += 1;
1403
+ findCallStart = tokenApi.peek(-callStart);
1404
+ }
1405
+ while ((lineNumber - prevNum > lastCheck) && !/^\s*\./.test(lines[lineNumber - prevNum])) {
1406
+ prevNum += 1;
1407
+ }
1408
+ checkNum = lineNumber - prevNum;
1409
+ if (checkNum >= 0) {
1410
+ prevLine = lines[checkNum];
1411
+ if (prevLine.match(/\S/i)[0] === '.' || checkNum === lastCheck) {
1412
+ currentSpaces = (_ref = currentLine.match(/\S/i)) != null ? _ref.index : void 0;
1413
+ prevSpaces = (_ref1 = prevLine.match(/\S/i)) != null ? _ref1.index : void 0;
1414
+ numIndents = currentSpaces - prevSpaces;
1415
+ prevIsIndent = prevSpaces % expected !== 0;
1416
+ currIsIndent = currentSpaces % expected !== 0;
1417
+ if (prevIsIndent && currIsIndent) {
1418
+ numIndents = currentSpaces;
1271
1419
  }
1272
- }
1273
- return _results;
1274
- })();
1275
- lastNewLineIndex = lines ? lines[lines.length - 2] : null;
1276
- if (lastNewLineIndex == null) {
1277
- return false;
1278
- }
1279
- tokens = [tokens[lastNewLineIndex], tokens[lastNewLineIndex + 1]];
1280
- return !!((function() {
1281
- var _i, _len, _results;
1282
- _results = [];
1283
- for (_i = 0, _len = tokens.length; _i < _len; _i++) {
1284
- t = tokens[_i];
1285
- if (t && t[0] === '.') {
1286
- _results.push(t);
1420
+ if (numIndents % expected !== 0) {
1421
+ return {
1422
+ context: "Expected " + expected + " got " + numIndents
1423
+ };
1287
1424
  }
1288
1425
  }
1289
- return _results;
1290
- })()).length;
1426
+ }
1427
+ };
1428
+
1429
+ Indentation.prototype.getCorrectIndent = function(tokenApi) {
1430
+ var curIndent, i, lineNumber, lines, prevIndent, prevLine, prevNum, tokens, _ref, _ref1, _ref2;
1431
+ lineNumber = tokenApi.lineNumber, lines = tokenApi.lines, tokens = tokenApi.tokens, i = tokenApi.i;
1432
+ curIndent = (_ref = lines[lineNumber].match(/\S/)) != null ? _ref.index : void 0;
1433
+ prevNum = 1;
1434
+ while (/^\s*(#|$)/.test(lines[lineNumber - prevNum])) {
1435
+ prevNum += 1;
1436
+ }
1437
+ prevLine = lines[lineNumber - prevNum];
1438
+ prevIndent = (_ref1 = prevLine.match(/^(\s*)\./)) != null ? _ref1[1].length : void 0;
1439
+ if (prevIndent > 0) {
1440
+ return curIndent - ((_ref2 = prevLine.match(/\S/)) != null ? _ref2.index : void 0);
1441
+ } else {
1442
+ return tokens[i][1];
1443
+ }
1291
1444
  };
1292
1445
 
1293
1446
  return Indentation;
@@ -1295,7 +1448,7 @@ module.exports = Indentation = (function() {
1295
1448
  })();
1296
1449
 
1297
1450
 
1298
- },{}],15:[function(_dereq_,module,exports){
1451
+ },{}],16:[function(_dereq_,module,exports){
1299
1452
  var LineEndings;
1300
1453
 
1301
1454
  module.exports = LineEndings = (function() {
@@ -1339,7 +1492,7 @@ module.exports = LineEndings = (function() {
1339
1492
  })();
1340
1493
 
1341
1494
 
1342
- },{}],16:[function(_dereq_,module,exports){
1495
+ },{}],17:[function(_dereq_,module,exports){
1343
1496
  var MaxLineLength, regexes;
1344
1497
 
1345
1498
  regexes = {
@@ -1384,8 +1537,8 @@ module.exports = MaxLineLength = (function() {
1384
1537
  })();
1385
1538
 
1386
1539
 
1387
- },{}],17:[function(_dereq_,module,exports){
1388
- var MissingFatArrows, any,
1540
+ },{}],18:[function(_dereq_,module,exports){
1541
+ var MissingFatArrows, any, containsButIsnt,
1389
1542
  __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
1390
1543
  __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; };
1391
1544
 
@@ -1395,6 +1548,21 @@ any = function(arr, test) {
1395
1548
  }), false);
1396
1549
  };
1397
1550
 
1551
+ containsButIsnt = function(node, nIsThis, nIsClass) {
1552
+ var target;
1553
+ target = void 0;
1554
+ node.traverseChildren(false, function(n) {
1555
+ if (nIsClass(n)) {
1556
+ return false;
1557
+ }
1558
+ if (nIsThis(n)) {
1559
+ target = n;
1560
+ return false;
1561
+ }
1562
+ });
1563
+ return target;
1564
+ };
1565
+
1398
1566
  module.exports = MissingFatArrows = (function() {
1399
1567
  function MissingFatArrows() {
1400
1568
  this.isFatArrowCode = __bind(this.isFatArrowCode, this);
@@ -1474,7 +1642,7 @@ module.exports = MissingFatArrows = (function() {
1474
1642
  return function(param) {
1475
1643
  return param.contains(_this.isThis) != null;
1476
1644
  };
1477
- })(this)) || (node.body.contains(this.isThis) != null));
1645
+ })(this)) || containsButIsnt(node.body, this.isThis, this.isClass));
1478
1646
  };
1479
1647
 
1480
1648
  MissingFatArrows.prototype.methodsOfClass = function(classNode) {
@@ -1495,7 +1663,7 @@ module.exports = MissingFatArrows = (function() {
1495
1663
  })();
1496
1664
 
1497
1665
 
1498
- },{}],18:[function(_dereq_,module,exports){
1666
+ },{}],19:[function(_dereq_,module,exports){
1499
1667
  var NewlinesAfterClasses;
1500
1668
 
1501
1669
  module.exports = NewlinesAfterClasses = (function() {
@@ -1530,7 +1698,7 @@ module.exports = NewlinesAfterClasses = (function() {
1530
1698
  })();
1531
1699
 
1532
1700
 
1533
- },{}],19:[function(_dereq_,module,exports){
1701
+ },{}],20:[function(_dereq_,module,exports){
1534
1702
  var NoBackticks;
1535
1703
 
1536
1704
  module.exports = NoBackticks = (function() {
@@ -1554,7 +1722,7 @@ module.exports = NoBackticks = (function() {
1554
1722
  })();
1555
1723
 
1556
1724
 
1557
- },{}],20:[function(_dereq_,module,exports){
1725
+ },{}],21:[function(_dereq_,module,exports){
1558
1726
  var NoDebugger;
1559
1727
 
1560
1728
  module.exports = NoDebugger = (function() {
@@ -1580,7 +1748,7 @@ module.exports = NoDebugger = (function() {
1580
1748
  })();
1581
1749
 
1582
1750
 
1583
- },{}],21:[function(_dereq_,module,exports){
1751
+ },{}],22:[function(_dereq_,module,exports){
1584
1752
  var NoEmptyFunctions, isEmptyCode;
1585
1753
 
1586
1754
  isEmptyCode = function(node, astApi) {
@@ -1624,7 +1792,7 @@ module.exports = NoEmptyFunctions = (function() {
1624
1792
  })();
1625
1793
 
1626
1794
 
1627
- },{}],22:[function(_dereq_,module,exports){
1795
+ },{}],23:[function(_dereq_,module,exports){
1628
1796
  var NoEmptyParamList;
1629
1797
 
1630
1798
  module.exports = NoEmptyParamList = (function() {
@@ -1650,7 +1818,7 @@ module.exports = NoEmptyParamList = (function() {
1650
1818
  })();
1651
1819
 
1652
1820
 
1653
- },{}],23:[function(_dereq_,module,exports){
1821
+ },{}],24:[function(_dereq_,module,exports){
1654
1822
  var NoImplicitBraces;
1655
1823
 
1656
1824
  module.exports = NoImplicitBraces = (function() {
@@ -1699,7 +1867,7 @@ module.exports = NoImplicitBraces = (function() {
1699
1867
  })();
1700
1868
 
1701
1869
 
1702
- },{}],24:[function(_dereq_,module,exports){
1870
+ },{}],25:[function(_dereq_,module,exports){
1703
1871
  var NoImplicitParens;
1704
1872
 
1705
1873
  module.exports = NoImplicitParens = (function() {
@@ -1713,7 +1881,7 @@ module.exports = NoImplicitParens = (function() {
1713
1881
  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."
1714
1882
  };
1715
1883
 
1716
- NoImplicitParens.prototype.tokens = ["CALL_END"];
1884
+ NoImplicitParens.prototype.tokens = ['CALL_END'];
1717
1885
 
1718
1886
  NoImplicitParens.prototype.lintToken = function(token, tokenApi) {
1719
1887
  var i, t;
@@ -1724,10 +1892,10 @@ module.exports = NoImplicitParens = (function() {
1724
1892
  i = -1;
1725
1893
  while (true) {
1726
1894
  t = tokenApi.peek(i);
1727
- if ((t == null) || t[0] === 'CALL_START') {
1895
+ if ((t == null) || (t[0] === 'CALL_START' && t.generated)) {
1728
1896
  return true;
1729
1897
  }
1730
- if (t.newLine) {
1898
+ if (t[2].first_line !== token[2].first_line) {
1731
1899
  return null;
1732
1900
  }
1733
1901
  i -= 1;
@@ -1741,7 +1909,7 @@ module.exports = NoImplicitParens = (function() {
1741
1909
  })();
1742
1910
 
1743
1911
 
1744
- },{}],25:[function(_dereq_,module,exports){
1912
+ },{}],26:[function(_dereq_,module,exports){
1745
1913
  var NoInterpolationInSingleQuotes;
1746
1914
 
1747
1915
  module.exports = NoInterpolationInSingleQuotes = (function() {
@@ -1751,7 +1919,7 @@ module.exports = NoInterpolationInSingleQuotes = (function() {
1751
1919
  name: 'no_interpolation_in_single_quotes',
1752
1920
  level: 'ignore',
1753
1921
  message: 'Interpolation in single quoted strings is forbidden',
1754
- description: 'This rule prohibits string interpolation in a single quoted string.\n<pre>\n<code># String interpolation in single quotes is not allowed:\nfoo = \'#{bar}\'\n\n# Double quotes is OK of course\nfoo = "#{bar}"\n</code>\n</pre>\nString interpolation in single quoted strings is permitted by \ndefault.'
1922
+ description: 'This rule prohibits string interpolation in a single quoted string.\n<pre>\n<code># String interpolation in single quotes is not allowed:\nfoo = \'#{bar}\'\n\n# Double quotes is OK of course\nfoo = "#{bar}"\n</code>\n</pre>\nString interpolation in single quoted strings is permitted by\ndefault.'
1755
1923
  };
1756
1924
 
1757
1925
  NoInterpolationInSingleQuotes.prototype.tokens = ['STRING'];
@@ -1768,7 +1936,7 @@ module.exports = NoInterpolationInSingleQuotes = (function() {
1768
1936
  })();
1769
1937
 
1770
1938
 
1771
- },{}],26:[function(_dereq_,module,exports){
1939
+ },{}],27:[function(_dereq_,module,exports){
1772
1940
  var NoPlusPlus;
1773
1941
 
1774
1942
  module.exports = NoPlusPlus = (function() {
@@ -1794,7 +1962,7 @@ module.exports = NoPlusPlus = (function() {
1794
1962
  })();
1795
1963
 
1796
1964
 
1797
- },{}],27:[function(_dereq_,module,exports){
1965
+ },{}],28:[function(_dereq_,module,exports){
1798
1966
  var NoStandAloneAt;
1799
1967
 
1800
1968
  module.exports = NoStandAloneAt = (function() {
@@ -1807,7 +1975,7 @@ module.exports = NoStandAloneAt = (function() {
1807
1975
  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>"
1808
1976
  };
1809
1977
 
1810
- NoStandAloneAt.prototype.tokens = ["@"];
1978
+ NoStandAloneAt.prototype.tokens = ['@'];
1811
1979
 
1812
1980
  NoStandAloneAt.prototype.lintToken = function(token, tokenApi) {
1813
1981
  var isDot, isIdentifier, isIndexStart, isValidProtoProperty, nextToken, protoProperty, spaced;
@@ -1830,7 +1998,7 @@ module.exports = NoStandAloneAt = (function() {
1830
1998
  })();
1831
1999
 
1832
2000
 
1833
- },{}],28:[function(_dereq_,module,exports){
2001
+ },{}],29:[function(_dereq_,module,exports){
1834
2002
  var NoTabs, indentationRegex,
1835
2003
  __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; };
1836
2004
 
@@ -1861,7 +2029,7 @@ module.exports = NoTabs = (function() {
1861
2029
  })();
1862
2030
 
1863
2031
 
1864
- },{}],29:[function(_dereq_,module,exports){
2032
+ },{}],30:[function(_dereq_,module,exports){
1865
2033
  var NoThrowingStrings;
1866
2034
 
1867
2035
  module.exports = NoThrowingStrings = (function() {
@@ -1874,7 +2042,7 @@ module.exports = NoThrowingStrings = (function() {
1874
2042
  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."
1875
2043
  };
1876
2044
 
1877
- NoThrowingStrings.prototype.tokens = ["THROW"];
2045
+ NoThrowingStrings.prototype.tokens = ['THROW'];
1878
2046
 
1879
2047
  NoThrowingStrings.prototype.lintToken = function(token, tokenApi) {
1880
2048
  var n1, n2, nextIsString, _ref;
@@ -1888,8 +2056,9 @@ module.exports = NoThrowingStrings = (function() {
1888
2056
  })();
1889
2057
 
1890
2058
 
1891
- },{}],30:[function(_dereq_,module,exports){
2059
+ },{}],31:[function(_dereq_,module,exports){
1892
2060
  var NoTrailingSemicolons, regexes,
2061
+ __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; },
1893
2062
  __slice = [].slice;
1894
2063
 
1895
2064
  regexes = {
@@ -1907,18 +2076,20 @@ module.exports = NoTrailingSemicolons = (function() {
1907
2076
  };
1908
2077
 
1909
2078
  NoTrailingSemicolons.prototype.lintLine = function(line, lineApi) {
1910
- var endPos, first, hasNewLine, hasSemicolon, last, lineTokens, newLine, startCounter, startPos, _i, _ref;
2079
+ var endPos, first, hasNewLine, hasSemicolon, last, lineTokens, newLine, startCounter, startPos, stopTokens, tokenLen, _i, _ref, _ref1;
1911
2080
  lineTokens = lineApi.getLineTokens();
1912
- if (lineTokens.length === 1 && ((_ref = lineTokens[0][0]) === 'TERMINATOR' || _ref === 'HERECOMMENT')) {
2081
+ tokenLen = lineTokens.length;
2082
+ stopTokens = ['TERMINATOR', 'HERECOMMENT'];
2083
+ if (tokenLen === 1 && (_ref = lineTokens[0][0], __indexOf.call(stopTokens, _ref) >= 0)) {
1913
2084
  return;
1914
2085
  }
1915
2086
  newLine = line;
1916
- if (lineTokens.length > 1 && lineTokens[lineTokens.length - 1][0] === 'TERMINATOR') {
1917
- startPos = lineTokens[lineTokens.length - 2][2].last_column + 1;
1918
- endPos = lineTokens[lineTokens.length - 1][2].first_column;
2087
+ if (tokenLen > 1 && lineTokens[tokenLen - 1][0] === 'TERMINATOR') {
2088
+ startPos = lineTokens[tokenLen - 2][2].last_column + 1;
2089
+ endPos = lineTokens[tokenLen - 1][2].first_column;
1919
2090
  if (startPos !== endPos) {
1920
2091
  startCounter = startPos;
1921
- while (line[startCounter] !== "#" && startCounter < line.length) {
2092
+ while (line[startCounter] !== '#' && startCounter < line.length) {
1922
2093
  startCounter++;
1923
2094
  }
1924
2095
  newLine = line.substring(0, startCounter).replace(/\s*$/, '');
@@ -1927,7 +2098,7 @@ module.exports = NoTrailingSemicolons = (function() {
1927
2098
  hasSemicolon = regexes.trailingSemicolon.test(newLine);
1928
2099
  first = 2 <= lineTokens.length ? __slice.call(lineTokens, 0, _i = lineTokens.length - 1) : (_i = 0, []), last = lineTokens[_i++];
1929
2100
  hasNewLine = last && (last.newLine != null);
1930
- if (hasSemicolon && !hasNewLine && lineApi.lineHasToken() && last[0] !== 'STRING') {
2101
+ if (hasSemicolon && !hasNewLine && lineApi.lineHasToken() && !((_ref1 = last[0]) === 'STRING' || _ref1 === 'IDENTIFIER' || _ref1 === 'CALL_END')) {
1931
2102
  return true;
1932
2103
  }
1933
2104
  };
@@ -1937,7 +2108,7 @@ module.exports = NoTrailingSemicolons = (function() {
1937
2108
  })();
1938
2109
 
1939
2110
 
1940
- },{}],31:[function(_dereq_,module,exports){
2111
+ },{}],32:[function(_dereq_,module,exports){
1941
2112
  var NoTrailingWhitespace, regexes;
1942
2113
 
1943
2114
  regexes = {
@@ -2000,43 +2171,95 @@ module.exports = NoTrailingWhitespace = (function() {
2000
2171
  })();
2001
2172
 
2002
2173
 
2003
- },{}],32:[function(_dereq_,module,exports){
2174
+ },{}],33:[function(_dereq_,module,exports){
2004
2175
  var NoUnnecessaryDoubleQuotes;
2005
2176
 
2006
2177
  module.exports = NoUnnecessaryDoubleQuotes = (function() {
2007
- function NoUnnecessaryDoubleQuotes() {}
2008
-
2009
2178
  NoUnnecessaryDoubleQuotes.prototype.rule = {
2010
2179
  name: 'no_unnecessary_double_quotes',
2011
2180
  level: 'ignore',
2012
2181
  message: 'Unnecessary double quotes are forbidden',
2013
- description: 'This rule prohibits double quotes unless string interpolation is \nused or the string contains single quotes.\n<pre>\n<code># Double quotes are discouraged:\nfoo = "bar"\n\n# Unless string interpolation is used:\nfoo = "#{bar}baz"\n\n# Or they prevent cumbersome escaping:\nfoo = "I\'m just following the \'rules\'"\n</code>\n</pre>\nDouble quotes are permitted by default.'
2182
+ description: 'This rule prohibits double quotes unless string interpolation is\nused or the string contains single quotes.\n<pre>\n<code># Double quotes are discouraged:\nfoo = "bar"\n\n# Unless string interpolation is used:\nfoo = "#{bar}baz"\n\n# Or they prevent cumbersome escaping:\nfoo = "I\'m just following the \'rules\'"\n</code>\n</pre>\nDouble quotes are permitted by default.'
2014
2183
  };
2015
2184
 
2185
+ function NoUnnecessaryDoubleQuotes() {
2186
+ this.regexps = [];
2187
+ }
2188
+
2016
2189
  NoUnnecessaryDoubleQuotes.prototype.tokens = ['STRING'];
2017
2190
 
2018
2191
  NoUnnecessaryDoubleQuotes.prototype.lintToken = function(token, tokenApi) {
2019
- var hasLegalConstructs, stringValue, tokenValue;
2192
+ var e, hasLegalConstructs, i, notInBlock, s, stringValue, tokenValue;
2020
2193
  tokenValue = token[1];
2194
+ i = tokenApi.i;
2021
2195
  stringValue = tokenValue.match(/^\"(.*)\"$/);
2022
- if (!stringValue) {
2196
+ if (this.regexps.length === 0) {
2197
+ this.regexps = this.getBlockRegExps(tokenApi);
2198
+ }
2199
+ notInBlock = ((function() {
2200
+ var _i, _len, _ref, _ref1, _results;
2201
+ _ref = this.regexps;
2202
+ _results = [];
2203
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
2204
+ _ref1 = _ref[_i], s = _ref1[0], e = _ref1[1];
2205
+ if ((s < i && i < e)) {
2206
+ _results.push(1);
2207
+ }
2208
+ }
2209
+ return _results;
2210
+ }).call(this)).length === 0;
2211
+ if (!(stringValue && notInBlock)) {
2023
2212
  return false;
2024
2213
  }
2025
2214
  hasLegalConstructs = this.isInterpolated(tokenApi) || this.containsSingleQuote(tokenValue);
2026
2215
  return !hasLegalConstructs;
2027
2216
  };
2028
2217
 
2218
+ NoUnnecessaryDoubleQuotes.prototype.getBlockRegExps = function(tokenApi) {
2219
+ var callEnds, col, curTok, i, idx, ii, lin, lines, regexps, t, tokens, _i, _j, _len, _len1, _ref;
2220
+ lines = tokenApi.lines, tokens = tokenApi.tokens;
2221
+ regexps = [];
2222
+ for (i = _i = 0, _len = tokens.length; _i < _len; i = ++_i) {
2223
+ t = tokens[i];
2224
+ if (!(t[0] === 'IDENTIFIER' && t[1] === 'RegExp')) {
2225
+ continue;
2226
+ }
2227
+ _ref = t[2], lin = _ref.first_line, col = _ref.first_column;
2228
+ if (lines[lin].slice(col, +(col + 2) + 1 || 9e9) === "///") {
2229
+ regexps.push([i, 0]);
2230
+ }
2231
+ }
2232
+ for (idx = _j = 0, _len1 = regexps.length; _j < _len1; idx = ++_j) {
2233
+ i = regexps[idx][0];
2234
+ ii = 2;
2235
+ callEnds = 1;
2236
+ while (callEnds > 0 && (curTok = tokens[i + ii][0])) {
2237
+ if (curTok === 'CALL_END') {
2238
+ callEnds--;
2239
+ }
2240
+ if (curTok === 'CALL_START') {
2241
+ callEnds++;
2242
+ }
2243
+ ii++;
2244
+ }
2245
+ regexps[idx][1] = i + ii - 1;
2246
+ }
2247
+ return regexps;
2248
+ };
2249
+
2029
2250
  NoUnnecessaryDoubleQuotes.prototype.isInterpolated = function(tokenApi) {
2030
- var currentIndex, i, isInterpolated, lineTokens, token, tokenName, _i, _ref;
2031
- currentIndex = tokenApi.i;
2251
+ var i, idx, isInterpolated, token, tokenName, _i, _ref;
2252
+ idx = tokenApi.i;
2032
2253
  isInterpolated = false;
2033
- lineTokens = tokenApi.tokensByLine[tokenApi.lineNumber];
2034
- for (i = _i = 1; 1 <= currentIndex ? _i <= currentIndex : _i >= currentIndex; i = 1 <= currentIndex ? ++_i : --_i) {
2254
+ for (i = _i = 1; 1 <= idx ? _i <= idx : _i >= idx; i = 1 <= idx ? ++_i : --_i) {
2035
2255
  token = tokenApi.peek(-i);
2256
+ if (token == null) {
2257
+ break;
2258
+ }
2036
2259
  tokenName = token[0];
2037
2260
  if (tokenName === ')' && token.stringEnd) {
2038
2261
  break;
2039
- } else if (tokenName === '(' && ((_ref = token.origin) != null ? _ref[1] : void 0) === "string interpolation") {
2262
+ } else if (tokenName === '(' && ((_ref = token.origin) != null ? _ref[1] : void 0) === 'string interpolation') {
2040
2263
  isInterpolated = true;
2041
2264
  break;
2042
2265
  }
@@ -2053,7 +2276,7 @@ module.exports = NoUnnecessaryDoubleQuotes = (function() {
2053
2276
  })();
2054
2277
 
2055
2278
 
2056
- },{}],33:[function(_dereq_,module,exports){
2279
+ },{}],34:[function(_dereq_,module,exports){
2057
2280
  var NoUnnecessaryFatArrows, any,
2058
2281
  __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
2059
2282
 
@@ -2120,7 +2343,11 @@ module.exports = NoUnnecessaryFatArrows = (function() {
2120
2343
  };
2121
2344
  })(this)) || (node.body.contains(this.isThis) != null) || (node.body.contains((function(_this) {
2122
2345
  return function(child) {
2123
- return _this.isFatArrowCode(child) && _this.needsFatArrow(child);
2346
+ if (!_this.astApi.getNodeName(child)) {
2347
+ return (child.isSuper != null) && child.isSuper;
2348
+ } else {
2349
+ return _this.isFatArrowCode(child) && _this.needsFatArrow(child);
2350
+ }
2124
2351
  };
2125
2352
  })(this)) != null));
2126
2353
  };
@@ -2130,7 +2357,7 @@ module.exports = NoUnnecessaryFatArrows = (function() {
2130
2357
  })();
2131
2358
 
2132
2359
 
2133
- },{}],34:[function(_dereq_,module,exports){
2360
+ },{}],35:[function(_dereq_,module,exports){
2134
2361
  var NonEmptyConstructorNeedsParens, ParentClass,
2135
2362
  __hasProp = {}.hasOwnProperty,
2136
2363
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
@@ -2162,7 +2389,68 @@ module.exports = NonEmptyConstructorNeedsParens = (function(_super) {
2162
2389
  })(ParentClass);
2163
2390
 
2164
2391
 
2165
- },{"./empty_constructor_needs_parens.coffee":13}],35:[function(_dereq_,module,exports){
2392
+ },{"./empty_constructor_needs_parens.coffee":14}],36:[function(_dereq_,module,exports){
2393
+ var RuleProcessor;
2394
+
2395
+ module.exports = RuleProcessor = (function() {
2396
+ function RuleProcessor() {}
2397
+
2398
+ RuleProcessor.prototype.rule = {
2399
+ name: 'prefer_english_operator',
2400
+ description: 'This rule prohibits &&, ||, ==, != and !.\nUse and, or, is, isnt, and not instead.\n!! for converting to a boolean is ignored.',
2401
+ level: 'ignore',
2402
+ doubleNotLevel: 'ignore',
2403
+ message: 'Don\'t use &&, ||, ==, !=, or !'
2404
+ };
2405
+
2406
+ RuleProcessor.prototype.tokens = ['COMPARE', 'UNARY_MATH', 'LOGIC'];
2407
+
2408
+ RuleProcessor.prototype.lintToken = function(token, tokenApi) {
2409
+ var actual_token, config, context, first_column, last_column, level, line, _ref;
2410
+ config = tokenApi.config[this.rule.name];
2411
+ level = config.level;
2412
+ _ref = token[2], first_column = _ref.first_column, last_column = _ref.last_column;
2413
+ line = tokenApi.lines[tokenApi.lineNumber];
2414
+ actual_token = line.slice(first_column, +last_column + 1 || 9e9);
2415
+ context = (function() {
2416
+ var _ref1, _ref2;
2417
+ switch (actual_token) {
2418
+ case '==':
2419
+ return 'Replace "==" with "is"';
2420
+ case '!=':
2421
+ return 'Replace "!=" with "isnt"';
2422
+ case '||':
2423
+ return 'Replace "||" with "or"';
2424
+ case '&&':
2425
+ return 'Replace "&&" with "and"';
2426
+ case '!':
2427
+ if (((_ref1 = tokenApi.peek(1)) != null ? _ref1[0] : void 0) === 'UNARY_MATH') {
2428
+ level = config.doubleNotLevel;
2429
+ return '"?" is usually better than "!!"';
2430
+ } else if (((_ref2 = tokenApi.peek(-1)) != null ? _ref2[0] : void 0) === 'UNARY_MATH') {
2431
+ return void 0;
2432
+ } else {
2433
+ return 'Replace "!" with "not"';
2434
+ }
2435
+ break;
2436
+ default:
2437
+ return void 0;
2438
+ }
2439
+ })();
2440
+ if (context != null) {
2441
+ return {
2442
+ level: level,
2443
+ context: context
2444
+ };
2445
+ }
2446
+ };
2447
+
2448
+ return RuleProcessor;
2449
+
2450
+ })();
2451
+
2452
+
2453
+ },{}],37:[function(_dereq_,module,exports){
2166
2454
  var SpaceOperators,
2167
2455
  __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; };
2168
2456
 
@@ -2174,7 +2462,7 @@ module.exports = SpaceOperators = (function() {
2174
2462
  description: "This rule enforces that operators have space around them."
2175
2463
  };
2176
2464
 
2177
- SpaceOperators.prototype.tokens = ["+", "-", "=", "**", "MATH", "COMPARE", "LOGIC", "COMPOUND_ASSIGN", "(", ")", "CALL_START", "CALL_END"];
2465
+ SpaceOperators.prototype.tokens = ['+', '-', '=', '**', 'MATH', 'COMPARE', 'LOGIC', 'COMPOUND_ASSIGN', '(', ')', 'CALL_START', 'CALL_END'];
2178
2466
 
2179
2467
  function SpaceOperators() {
2180
2468
  this.callTokens = [];
@@ -2184,15 +2472,15 @@ module.exports = SpaceOperators = (function() {
2184
2472
  SpaceOperators.prototype.lintToken = function(_arg, tokenApi) {
2185
2473
  var type;
2186
2474
  type = _arg[0];
2187
- if (type === "CALL_START" || type === "CALL_END") {
2475
+ if (type === 'CALL_START' || type === 'CALL_END') {
2188
2476
  this.lintCall.apply(this, arguments);
2189
2477
  return void 0;
2190
2478
  }
2191
- if (type === "(" || type === ")") {
2479
+ if (type === '(' || type === ')') {
2192
2480
  this.lintParens.apply(this, arguments);
2193
2481
  return void 0;
2194
2482
  }
2195
- if (type === "+" || type === "-") {
2483
+ if (type === '+' || type === '-') {
2196
2484
  return this.lintPlus.apply(this, arguments);
2197
2485
  } else {
2198
2486
  return this.lintMath.apply(this, arguments);
@@ -2207,7 +2495,7 @@ module.exports = SpaceOperators = (function() {
2207
2495
  p = tokenApi.peek(-1);
2208
2496
  unaries = ['TERMINATOR', '(', '=', '-', '+', ',', 'CALL_START', 'INDEX_START', '..', '...', 'COMPARE', 'IF', 'THROW', 'LOGIC', 'POST_IF', ':', '[', 'INDENT', 'COMPOUND_ASSIGN', 'RETURN', 'MATH', 'BY', 'LEADING_WHEN'];
2209
2497
  isUnary = !p ? false : (_ref = p[0], __indexOf.call(unaries, _ref) >= 0);
2210
- if ((isUnary && token.spaced) || (!isUnary && !token.spaced && !token.newLine)) {
2498
+ if ((isUnary && token.spaced) || (!isUnary && !token.newLine && (!token.spaced || (p && !p.spaced)))) {
2211
2499
  return {
2212
2500
  context: token[1]
2213
2501
  };
@@ -2217,7 +2505,9 @@ module.exports = SpaceOperators = (function() {
2217
2505
  };
2218
2506
 
2219
2507
  SpaceOperators.prototype.lintMath = function(token, tokenApi) {
2220
- if (!token.spaced && !token.newLine) {
2508
+ var p;
2509
+ p = tokenApi.peek(-1);
2510
+ if (!token.newLine && (!token.spaced || (p && !p.spaced))) {
2221
2511
  return {
2222
2512
  context: token[1]
2223
2513
  };