coffeelint 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
  };