eslint 3.15.0 → 3.17.1

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.
Files changed (118) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/conf/{eslint.json → eslint-recommended.js} +87 -71
  3. package/lib/ast-utils.js +182 -80
  4. package/lib/code-path-analysis/code-path-state.js +2 -2
  5. package/lib/config/autoconfig.js +3 -3
  6. package/lib/config/config-file.js +14 -7
  7. package/lib/config/config-initializer.js +1 -1
  8. package/lib/config.js +3 -2
  9. package/lib/eslint.js +4 -4
  10. package/lib/internal-rules/internal-no-invalid-meta.js +2 -40
  11. package/lib/rules/array-callback-return.js +15 -5
  12. package/lib/rules/arrow-body-style.js +7 -4
  13. package/lib/rules/arrow-spacing.js +7 -6
  14. package/lib/rules/block-spacing.js +2 -2
  15. package/lib/rules/brace-style.js +2 -6
  16. package/lib/rules/capitalized-comments.js +8 -7
  17. package/lib/rules/comma-spacing.js +3 -3
  18. package/lib/rules/complexity.js +14 -8
  19. package/lib/rules/consistent-return.js +18 -11
  20. package/lib/rules/constructor-super.js +3 -3
  21. package/lib/rules/curly.js +11 -7
  22. package/lib/rules/default-case.js +3 -3
  23. package/lib/rules/eqeqeq.js +15 -6
  24. package/lib/rules/func-call-spacing.js +10 -13
  25. package/lib/rules/func-names.js +20 -5
  26. package/lib/rules/generator-star-spacing.js +18 -19
  27. package/lib/rules/id-blacklist.js +2 -2
  28. package/lib/rules/id-length.js +3 -3
  29. package/lib/rules/id-match.js +2 -2
  30. package/lib/rules/indent.js +7 -6
  31. package/lib/rules/key-spacing.js +12 -16
  32. package/lib/rules/keyword-spacing.js +21 -17
  33. package/lib/rules/line-comment-position.js +16 -6
  34. package/lib/rules/linebreak-style.js +7 -1
  35. package/lib/rules/lines-around-comment.js +23 -4
  36. package/lib/rules/lines-around-directive.js +3 -3
  37. package/lib/rules/max-lines.js +2 -2
  38. package/lib/rules/max-params.js +17 -4
  39. package/lib/rules/max-statements-per-line.js +7 -6
  40. package/lib/rules/max-statements.js +11 -10
  41. package/lib/rules/newline-after-var.js +7 -2
  42. package/lib/rules/newline-per-chained-call.js +3 -1
  43. package/lib/rules/no-compare-neg-zero.js +53 -0
  44. package/lib/rules/no-cond-assign.js +3 -3
  45. package/lib/rules/no-else-return.js +13 -1
  46. package/lib/rules/no-empty-function.js +9 -16
  47. package/lib/rules/no-extend-native.js +3 -3
  48. package/lib/rules/no-extra-bind.js +3 -4
  49. package/lib/rules/no-extra-boolean-cast.js +8 -0
  50. package/lib/rules/no-extra-parens.js +1 -2
  51. package/lib/rules/no-extra-semi.js +13 -1
  52. package/lib/rules/no-inner-declarations.js +4 -4
  53. package/lib/rules/no-invalid-regexp.js +2 -1
  54. package/lib/rules/no-irregular-whitespace.js +7 -1
  55. package/lib/rules/no-lone-blocks.js +10 -10
  56. package/lib/rules/no-mixed-operators.js +1 -7
  57. package/lib/rules/no-multi-spaces.js +4 -1
  58. package/lib/rules/no-multi-str.js +7 -3
  59. package/lib/rules/no-multiple-empty-lines.js +2 -4
  60. package/lib/rules/no-param-reassign.js +29 -6
  61. package/lib/rules/no-restricted-properties.js +2 -0
  62. package/lib/rules/no-return-assign.js +7 -14
  63. package/lib/rules/no-return-await.js +1 -1
  64. package/lib/rules/no-sequences.js +7 -6
  65. package/lib/rules/no-trailing-spaces.js +8 -2
  66. package/lib/rules/no-undefined.js +45 -6
  67. package/lib/rules/no-unexpected-multiline.js +9 -8
  68. package/lib/rules/no-unneeded-ternary.js +5 -1
  69. package/lib/rules/no-unused-labels.js +17 -2
  70. package/lib/rules/no-unused-vars.js +13 -27
  71. package/lib/rules/no-use-before-define.js +1 -1
  72. package/lib/rules/no-useless-computed-key.js +8 -3
  73. package/lib/rules/no-useless-concat.js +10 -7
  74. package/lib/rules/no-useless-escape.js +2 -2
  75. package/lib/rules/no-useless-return.js +14 -9
  76. package/lib/rules/no-var.js +1 -3
  77. package/lib/rules/no-whitespace-before-property.js +5 -16
  78. package/lib/rules/nonblock-statement-body-position.js +114 -0
  79. package/lib/rules/object-curly-newline.js +2 -2
  80. package/lib/rules/object-curly-spacing.js +7 -25
  81. package/lib/rules/object-property-newline.js +3 -3
  82. package/lib/rules/object-shorthand.js +4 -3
  83. package/lib/rules/operator-assignment.js +2 -2
  84. package/lib/rules/operator-linebreak.js +8 -10
  85. package/lib/rules/padded-blocks.js +39 -30
  86. package/lib/rules/prefer-destructuring.js +1 -1
  87. package/lib/rules/prefer-spread.js +1 -1
  88. package/lib/rules/prefer-template.js +1 -1
  89. package/lib/rules/quotes.js +10 -6
  90. package/lib/rules/semi-spacing.js +4 -0
  91. package/lib/rules/semi.js +13 -1
  92. package/lib/rules/space-before-function-paren.js +8 -5
  93. package/lib/rules/space-unary-ops.js +19 -1
  94. package/lib/rules/spaced-comment.js +2 -2
  95. package/lib/rules/strict.js +10 -4
  96. package/lib/rules/unicode-bom.js +1 -1
  97. package/lib/rules/wrap-iife.js +5 -5
  98. package/lib/rules/yoda.js +4 -9
  99. package/lib/testers/rule-tester.js +46 -9
  100. package/lib/token-store/backward-token-comment-cursor.js +57 -0
  101. package/lib/token-store/backward-token-cursor.js +56 -0
  102. package/lib/token-store/cursor.js +76 -0
  103. package/lib/token-store/cursors.js +92 -0
  104. package/lib/token-store/decorative-cursor.js +39 -0
  105. package/lib/token-store/filter-cursor.js +43 -0
  106. package/lib/token-store/forward-token-comment-cursor.js +57 -0
  107. package/lib/token-store/forward-token-cursor.js +61 -0
  108. package/lib/token-store/index.js +604 -0
  109. package/lib/token-store/limit-cursor.js +40 -0
  110. package/lib/token-store/padded-token-cursor.js +38 -0
  111. package/lib/token-store/skip-cursor.js +42 -0
  112. package/lib/token-store/utils.js +100 -0
  113. package/lib/util/fix-tracker.js +121 -0
  114. package/lib/util/source-code-fixer.js +35 -39
  115. package/lib/util/source-code.js +129 -16
  116. package/messages/extend-config-missing.txt +3 -0
  117. package/package.json +5 -6
  118. package/lib/token-store.js +0 -203
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("../ast-utils");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -67,19 +73,10 @@ module.exports = {
67
73
  * @private
68
74
  */
69
75
  function checkSpacing(node) {
76
+ const lastToken = sourceCode.getLastToken(node);
70
77
  const lastCalleeToken = sourceCode.getLastToken(node.callee);
71
- let prevToken = lastCalleeToken;
72
- let parenToken = sourceCode.getTokenAfter(lastCalleeToken);
73
-
74
- // advances to an open parenthesis.
75
- while (
76
- parenToken &&
77
- parenToken.range[1] < node.range[1] &&
78
- parenToken.value !== "("
79
- ) {
80
- prevToken = parenToken;
81
- parenToken = sourceCode.getTokenAfter(parenToken);
82
- }
78
+ const parenToken = sourceCode.getFirstTokenBetween(lastCalleeToken, lastToken, astUtils.isOpeningParenToken);
79
+ const prevToken = parenToken && sourceCode.getTokenBefore(parenToken);
83
80
 
84
81
  // Parens in NewExpression are optional
85
82
  if (!(parenToken && parenToken.range[1] < node.range[1])) {
@@ -88,7 +85,7 @@ module.exports = {
88
85
 
89
86
  const textBetweenTokens = text.slice(prevToken.range[1], parenToken.range[0]).replace(/\/\*.*?\*\//g, "");
90
87
  const hasWhitespace = /\s/.test(textBetweenTokens);
91
- const hasNewline = hasWhitespace && /[\n\r\u2028\u2029]/.test(textBetweenTokens);
88
+ const hasNewline = hasWhitespace && astUtils.LINEBREAK_MATCHER.test(textBetweenTokens);
92
89
 
93
90
  /*
94
91
  * never allowNewlines hasWhitespace hasNewline message
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("../ast-utils");
13
+
8
14
  /**
9
15
  * Checks whether or not a given variable is a function name.
10
16
  * @param {escope.Variable} variable - A variable to check.
@@ -82,15 +88,24 @@ module.exports = {
82
88
  return;
83
89
  }
84
90
 
85
- const name = node.id && node.id.name;
91
+ const hasName = Boolean(node.id && node.id.name);
92
+ const name = astUtils.getFunctionNameWithKind(node);
86
93
 
87
94
  if (never) {
88
- if (name) {
89
- context.report({ node, message: "Unexpected function expression name." });
95
+ if (hasName) {
96
+ context.report({
97
+ node,
98
+ message: "Unexpected named {{name}}.",
99
+ data: { name }
100
+ });
90
101
  }
91
102
  } else {
92
- if (!name && (asNeeded ? !hasInferredName(node) : !isObjectOrClassMethod(node))) {
93
- context.report({ node, message: "Missing function expression name." });
103
+ if (!hasName && (asNeeded ? !hasInferredName(node) : !isObjectOrClassMethod(node))) {
104
+ context.report({
105
+ node,
106
+ message: "Unexpected unnamed {{name}}.",
107
+ data: { name }
108
+ });
94
109
  }
95
110
  }
96
111
  }
@@ -55,21 +55,26 @@ module.exports = {
55
55
  const sourceCode = context.getSourceCode();
56
56
 
57
57
  /**
58
- * Gets `*` token from a given node.
58
+ * Checks if the given token is a star token or not.
59
59
  *
60
- * @param {ASTNode} node - A node to get `*` token. This is one of
61
- * FunctionDeclaration, FunctionExpression, Property, and
62
- * MethodDefinition.
63
- * @returns {Token} `*` token.
60
+ * @param {Token} token - The token to check.
61
+ * @returns {boolean} `true` if the token is a star token.
64
62
  */
65
- function getStarToken(node) {
66
- let token = sourceCode.getFirstToken(node);
67
-
68
- while (token.value !== "*") {
69
- token = sourceCode.getTokenAfter(token);
70
- }
63
+ function isStarToken(token) {
64
+ return token.value === "*" && token.type === "Punctuator";
65
+ }
71
66
 
72
- return token;
67
+ /**
68
+ * Gets the generator star token of the given function node.
69
+ *
70
+ * @param {ASTNode} node - The function node to get.
71
+ * @returns {Token} Found star token.
72
+ */
73
+ function getStarToken(node) {
74
+ return sourceCode.getFirstToken(
75
+ (node.parent.method || node.parent.type === "MethodDefinition") ? node.parent : node,
76
+ isStarToken
77
+ );
73
78
  }
74
79
 
75
80
  /**
@@ -116,17 +121,11 @@ module.exports = {
116
121
  * @returns {void}
117
122
  */
118
123
  function checkFunction(node) {
119
- let starToken;
120
-
121
124
  if (!node.generator) {
122
125
  return;
123
126
  }
124
127
 
125
- if (node.parent.method || node.parent.type === "MethodDefinition") {
126
- starToken = getStarToken(node.parent);
127
- } else {
128
- starToken = getStarToken(node);
129
- }
128
+ const starToken = getStarToken(node);
130
129
 
131
130
  // Only check before when preceded by `function`|`static` keyword
132
131
  const prevToken = sourceCode.getTokenBefore(starToken);
@@ -55,8 +55,8 @@ module.exports = {
55
55
  * @returns {boolean} whether an error should be reported or not
56
56
  */
57
57
  function shouldReport(effectiveParent, name) {
58
- return effectiveParent.type !== "CallExpression"
59
- && effectiveParent.type !== "NewExpression" &&
58
+ return effectiveParent.type !== "CallExpression" &&
59
+ effectiveParent.type !== "NewExpression" &&
60
60
  isInvalid(name);
61
61
  }
62
62
 
@@ -104,9 +104,9 @@ module.exports = {
104
104
  if (isValidExpression && (isValidExpression === true || isValidExpression(parent, node))) {
105
105
  context.report({
106
106
  node,
107
- message: isShort ?
108
- "Identifier name '{{name}}' is too short (< {{min}})." :
109
- "Identifier name '{{name}}' is too long (> {{max}}).",
107
+ message: isShort
108
+ ? "Identifier name '{{name}}' is too short (< {{min}})."
109
+ : "Identifier name '{{name}}' is too long (> {{max}}).",
110
110
  data: { name, min: minLength, max: maxLength }
111
111
  });
112
112
  }
@@ -63,8 +63,8 @@ module.exports = {
63
63
  * @returns {boolean} whether an error should be reported or not
64
64
  */
65
65
  function shouldReport(effectiveParent, name) {
66
- return effectiveParent.type !== "CallExpression"
67
- && effectiveParent.type !== "NewExpression" &&
66
+ return effectiveParent.type !== "CallExpression" &&
67
+ effectiveParent.type !== "NewExpression" &&
68
68
  isInvalid(name);
69
69
  }
70
70
 
@@ -8,6 +8,12 @@
8
8
 
9
9
  "use strict";
10
10
 
11
+ //------------------------------------------------------------------------------
12
+ // Requirements
13
+ //------------------------------------------------------------------------------
14
+
15
+ const astUtils = require("../ast-utils");
16
+
11
17
  //------------------------------------------------------------------------------
12
18
  // Rule Definition
13
19
  //------------------------------------------------------------------------------
@@ -435,15 +441,10 @@ module.exports = {
435
441
  * @returns {void}
436
442
  */
437
443
  function checkLastReturnStatementLineIndent(node, firstLineIndent) {
438
- const nodeLastToken = sourceCode.getLastToken(node);
439
- let lastToken = nodeLastToken;
440
444
 
441
445
  // in case if return statement ends with ');' we have traverse back to ')'
442
446
  // otherwise we'll measure indent for ';' and replace ')'
443
- while (lastToken.value !== ")") {
444
- lastToken = sourceCode.getTokenBefore(lastToken);
445
- }
446
-
447
+ const lastToken = sourceCode.getLastToken(node, astUtils.isClosingParenToken);
447
448
  const textBeforeClosingParenthesis = sourceCode.getText(lastToken, lastToken.loc.start.column).slice(0, -1);
448
449
 
449
450
  if (textBeforeClosingParenthesis.trim()) {
@@ -4,6 +4,12 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const astUtils = require("../ast-utils");
12
+
7
13
  //------------------------------------------------------------------------------
8
14
  // Helpers
9
15
  //------------------------------------------------------------------------------
@@ -15,7 +21,7 @@
15
21
  * @returns {boolean} True if str contains a line terminator.
16
22
  */
17
23
  function containsLineTerminator(str) {
18
- return /[\n\r\u2028\u2029]/.test(str);
24
+ return astUtils.LINEBREAK_MATCHER.test(str);
19
25
  }
20
26
 
21
27
  /**
@@ -364,14 +370,9 @@ module.exports = {
364
370
  * @returns {ASTNode} The last token before a colon punctuator.
365
371
  */
366
372
  function getLastTokenBeforeColon(node) {
367
- let prevNode;
373
+ const colonToken = sourceCode.getTokenAfter(node, astUtils.isColonToken);
368
374
 
369
- while (node && (node.type !== "Punctuator" || node.value !== ":")) {
370
- prevNode = node;
371
- node = sourceCode.getTokenAfter(node);
372
- }
373
-
374
- return prevNode;
375
+ return sourceCode.getTokenBefore(colonToken);
375
376
  }
376
377
 
377
378
  /**
@@ -381,12 +382,7 @@ module.exports = {
381
382
  * @returns {ASTNode} The colon punctuator.
382
383
  */
383
384
  function getNextColon(node) {
384
-
385
- while (node && (node.type !== "Punctuator" || node.value !== ":")) {
386
- node = sourceCode.getTokenAfter(node);
387
- }
388
-
389
- return node;
385
+ return sourceCode.getTokenAfter(node, astUtils.isColonToken);
390
386
  }
391
387
 
392
388
  /**
@@ -417,8 +413,8 @@ module.exports = {
417
413
  function report(property, side, whitespace, expected, mode) {
418
414
  const diff = whitespace.length - expected,
419
415
  nextColon = getNextColon(property.key),
420
- tokenBeforeColon = sourceCode.getTokenOrCommentBefore(nextColon),
421
- tokenAfterColon = sourceCode.getTokenOrCommentAfter(nextColon),
416
+ tokenBeforeColon = sourceCode.getTokenBefore(nextColon, { includeComments: true }),
417
+ tokenAfterColon = sourceCode.getTokenAfter(nextColon, { includeComments: true }),
422
418
  isKeySide = side === "key",
423
419
  locStart = isKeySide ? tokenBeforeColon.loc.start : tokenAfterColon.loc.start,
424
420
  isExtra = diff > 0,
@@ -342,11 +342,7 @@ module.exports = {
342
342
  */
343
343
  function checkSpacingAroundTokenBefore(node) {
344
344
  if (node) {
345
- let token = sourceCode.getTokenBefore(node);
346
-
347
- while (token.type !== "Keyword") {
348
- token = sourceCode.getTokenBefore(token);
349
- }
345
+ const token = sourceCode.getTokenBefore(node, astUtils.isKeywordToken);
350
346
 
351
347
  checkSpacingAround(token);
352
348
  }
@@ -363,7 +359,8 @@ module.exports = {
363
359
  const firstToken = node && sourceCode.getFirstToken(node);
364
360
 
365
361
  if (firstToken &&
366
- (firstToken.type === "Keyword" || firstToken.value === "async")
362
+ ((firstToken.type === "Keyword" && firstToken.value === "function") ||
363
+ firstToken.value === "async")
367
364
  ) {
368
365
  checkSpacingBefore(firstToken);
369
366
  }
@@ -439,14 +436,7 @@ module.exports = {
439
436
  */
440
437
  function checkSpacingForForOfStatement(node) {
441
438
  checkSpacingAroundFirstToken(node);
442
-
443
- // `of` is not a keyword token.
444
- let token = sourceCode.getTokenBefore(node.right);
445
-
446
- while (token.value !== "of") {
447
- token = sourceCode.getTokenBefore(token);
448
- }
449
- checkSpacingAround(token);
439
+ checkSpacingAround(sourceCode.getTokenBefore(node.right, astUtils.isNotOpeningParenToken));
450
440
  }
451
441
 
452
442
  /**
@@ -506,11 +496,25 @@ module.exports = {
506
496
  node.value.async
507
497
  )
508
498
  ) {
509
- const token = sourceCode.getFirstToken(
510
- node,
511
- node.static ? 1 : 0
499
+ const token = sourceCode.getTokenBefore(
500
+ node.key,
501
+ tok => {
502
+ switch (tok.value) {
503
+ case "get":
504
+ case "set":
505
+ case "async":
506
+ return true;
507
+ default:
508
+ return false;
509
+ }
510
+ }
512
511
  );
513
512
 
513
+ if (!token) {
514
+ throw new Error("Failed to find token get, set, or async beside method name");
515
+ }
516
+
517
+
514
518
  checkSpacingAround(token);
515
519
  }
516
520
  }
@@ -4,6 +4,8 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ const astUtils = require("../ast-utils");
8
+
7
9
  //------------------------------------------------------------------------------
8
10
  // Rule Definition
9
11
  //------------------------------------------------------------------------------
@@ -33,6 +35,9 @@ module.exports = {
33
35
  },
34
36
  applyDefaultPatterns: {
35
37
  type: "boolean"
38
+ },
39
+ applyDefaultIgnorePatterns: {
40
+ type: "boolean"
36
41
  }
37
42
  },
38
43
  additionalProperties: false
@@ -43,12 +48,11 @@ module.exports = {
43
48
  },
44
49
 
45
50
  create(context) {
46
- const DEFAULT_IGNORE_PATTERN = "^\\s*(?:eslint|jshint\\s+|jslint\\s+|istanbul\\s+|globals?\\s+|exported\\s+|jscs|falls?\\s?through)";
47
51
  const options = context.options[0];
48
52
 
49
53
  let above,
50
54
  ignorePattern,
51
- applyDefaultPatterns = true;
55
+ applyDefaultIgnorePatterns = true;
52
56
 
53
57
  if (!options || typeof options === "string") {
54
58
  above = !options || options === "above";
@@ -56,10 +60,16 @@ module.exports = {
56
60
  } else {
57
61
  above = options.position === "above";
58
62
  ignorePattern = options.ignorePattern;
59
- applyDefaultPatterns = options.applyDefaultPatterns !== false;
63
+
64
+ if (options.hasOwnProperty("applyDefaultIgnorePatterns")) {
65
+ applyDefaultIgnorePatterns = options.applyDefaultIgnorePatterns !== false;
66
+ } else {
67
+ applyDefaultIgnorePatterns = options.applyDefaultPatterns !== false;
68
+ }
60
69
  }
61
70
 
62
- const defaultIgnoreRegExp = new RegExp(DEFAULT_IGNORE_PATTERN);
71
+ const defaultIgnoreRegExp = astUtils.COMMENTS_IGNORE_PATTERN;
72
+ const fallThroughRegExp = /^\s*falls?\s?through/;
63
73
  const customIgnoreRegExp = new RegExp(ignorePattern);
64
74
  const sourceCode = context.getSourceCode();
65
75
 
@@ -69,7 +79,7 @@ module.exports = {
69
79
 
70
80
  return {
71
81
  LineComment(node) {
72
- if (applyDefaultPatterns && defaultIgnoreRegExp.test(node.value)) {
82
+ if (applyDefaultIgnorePatterns && (defaultIgnoreRegExp.test(node.value) || fallThroughRegExp.test(node.value))) {
73
83
  return;
74
84
  }
75
85
 
@@ -77,7 +87,7 @@ module.exports = {
77
87
  return;
78
88
  }
79
89
 
80
- const previous = sourceCode.getTokenOrCommentBefore(node);
90
+ const previous = sourceCode.getTokenBefore(node, { includeComments: true });
81
91
  const isOnSameLine = previous && previous.loc.end.line === node.loc.start.line;
82
92
 
83
93
  if (above) {
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("../ast-utils");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -60,7 +66,7 @@ module.exports = {
60
66
  expectedLF = linebreakStyle === "unix",
61
67
  expectedLFChars = expectedLF ? "\n" : "\r\n",
62
68
  source = sourceCode.getText(),
63
- pattern = /\r\n|\r|\n|\u2028|\u2029/g;
69
+ pattern = astUtils.createGlobalLinebreakMatcher();
64
70
  let match;
65
71
 
66
72
  let i = 0;
@@ -93,6 +93,12 @@ module.exports = {
93
93
  },
94
94
  allowArrayEnd: {
95
95
  type: "boolean"
96
+ },
97
+ ignorePattern: {
98
+ type: "string"
99
+ },
100
+ applyDefaultIgnorePatterns: {
101
+ type: "boolean"
96
102
  }
97
103
  },
98
104
  additionalProperties: false
@@ -103,6 +109,11 @@ module.exports = {
103
109
  create(context) {
104
110
 
105
111
  const options = context.options[0] ? Object.assign({}, context.options[0]) : {};
112
+ const ignorePattern = options.ignorePattern;
113
+ const defaultIgnoreRegExp = astUtils.COMMENTS_IGNORE_PATTERN;
114
+ const customIgnoreRegExp = new RegExp(ignorePattern);
115
+ const applyDefaultIgnorePatterns = options.applyDefaultIgnorePatterns !== false;
116
+
106
117
 
107
118
  options.beforeLineComment = options.beforeLineComment || false;
108
119
  options.afterLineComment = options.afterLineComment || false;
@@ -139,7 +150,7 @@ module.exports = {
139
150
 
140
151
  token = node;
141
152
  do {
142
- token = sourceCode.getTokenOrCommentBefore(token);
153
+ token = sourceCode.getTokenBefore(token, { includeComments: true });
143
154
  } while (isCommentNodeType(token));
144
155
 
145
156
  if (token && astUtils.isTokenOnSameLine(token, node)) {
@@ -148,7 +159,7 @@ module.exports = {
148
159
 
149
160
  token = node;
150
161
  do {
151
- token = sourceCode.getTokenOrCommentAfter(token);
162
+ token = sourceCode.getTokenAfter(token, { includeComments: true });
152
163
  } while (isCommentNodeType(token));
153
164
 
154
165
  if (token && astUtils.isTokenOnSameLine(node, token)) {
@@ -270,6 +281,14 @@ module.exports = {
270
281
  * @returns {void}
271
282
  */
272
283
  function checkForEmptyLine(node, opts) {
284
+ if (applyDefaultIgnorePatterns && defaultIgnoreRegExp.test(node.value)) {
285
+ return;
286
+ }
287
+
288
+ if (ignorePattern && customIgnoreRegExp.test(node.value)) {
289
+ return;
290
+ }
291
+
273
292
  let after = opts.after,
274
293
  before = opts.before;
275
294
 
@@ -300,8 +319,8 @@ module.exports = {
300
319
  return;
301
320
  }
302
321
 
303
- const previousTokenOrComment = sourceCode.getTokenOrCommentBefore(node);
304
- const nextTokenOrComment = sourceCode.getTokenOrCommentAfter(node);
322
+ const previousTokenOrComment = sourceCode.getTokenBefore(node, { includeComments: true });
323
+ const nextTokenOrComment = sourceCode.getTokenAfter(node, { includeComments: true });
305
324
 
306
325
  // check for newline before
307
326
  if (!exceptionStartAllowed && before && !lodash.includes(commentAndEmptyLines, prevLineNum) &&
@@ -57,7 +57,7 @@ module.exports = {
57
57
  * @returns {boolean} Whether or not the passed in node is preceded by a blank newline.
58
58
  */
59
59
  function hasNewlineBefore(node) {
60
- const tokenBefore = sourceCode.getTokenOrCommentBefore(node);
60
+ const tokenBefore = sourceCode.getTokenBefore(node, { includeComments: true });
61
61
  const tokenLineBefore = tokenBefore ? tokenBefore.loc.end.line : 0;
62
62
 
63
63
  return node.loc.start.line - tokenLineBefore >= 2;
@@ -86,7 +86,7 @@ module.exports = {
86
86
  */
87
87
  function hasNewlineAfter(node) {
88
88
  const lastToken = getLastTokenOnLine(node);
89
- const tokenAfter = sourceCode.getTokenOrCommentAfter(lastToken);
89
+ const tokenAfter = sourceCode.getTokenAfter(lastToken, { includeComments: true });
90
90
 
91
91
  return tokenAfter.loc.start.line - lastToken.loc.end.line >= 2;
92
92
  }
@@ -131,7 +131,7 @@ module.exports = {
131
131
  }
132
132
 
133
133
  const firstDirective = directives[0];
134
- const hasTokenOrCommentBefore = !!sourceCode.getTokenOrCommentBefore(firstDirective);
134
+ const hasTokenOrCommentBefore = !!sourceCode.getTokenBefore(firstDirective, { includeComments: true });
135
135
 
136
136
  // Only check before the first directive if it is preceded by a comment or if it is at the top of
137
137
  // the file and expectLineBefore is set to "never". This is to not force a newline at the top of
@@ -90,7 +90,7 @@ module.exports = {
90
90
 
91
91
  token = comment;
92
92
  do {
93
- token = sourceCode.getTokenOrCommentBefore(token);
93
+ token = sourceCode.getTokenBefore(token, { includeComments: true });
94
94
  } while (isCommentNodeType(token));
95
95
 
96
96
  if (token && astUtils.isTokenOnSameLine(token, comment)) {
@@ -99,7 +99,7 @@ module.exports = {
99
99
 
100
100
  token = comment;
101
101
  do {
102
- token = sourceCode.getTokenOrCommentAfter(token);
102
+ token = sourceCode.getTokenAfter(token, { includeComments: true });
103
103
  } while (isCommentNodeType(token));
104
104
 
105
105
  if (token && astUtils.isTokenOnSameLine(comment, token)) {
@@ -5,6 +5,14 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const lodash = require("lodash");
13
+
14
+ const astUtils = require("../ast-utils");
15
+
8
16
  //------------------------------------------------------------------------------
9
17
  // Rule Definition
10
18
  //------------------------------------------------------------------------------
@@ -66,10 +74,15 @@ module.exports = {
66
74
  */
67
75
  function checkFunction(node) {
68
76
  if (node.params.length > numParams) {
69
- context.report({ node, message: "This function has too many parameters ({{count}}). Maximum allowed is {{max}}.", data: {
70
- count: node.params.length,
71
- max: numParams
72
- } });
77
+ context.report({
78
+ node,
79
+ message: "{{name}} has too many parameters ({{count}}). Maximum allowed is {{max}}.",
80
+ data: {
81
+ name: lodash.upperFirst(astUtils.getFunctionNameWithKind(node)),
82
+ count: node.params.length,
83
+ max: numParams
84
+ }
85
+ });
73
86
  }
74
87
  }
75
88
 
@@ -4,6 +4,12 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const astUtils = require("../ast-utils");
12
+
7
13
  //------------------------------------------------------------------------------
8
14
  // Rule Definition
9
15
  //------------------------------------------------------------------------------
@@ -74,12 +80,7 @@ module.exports = {
74
80
  * @returns {Token} The actual last token.
75
81
  */
76
82
  function getActualLastToken(node) {
77
- let lastToken = sourceCode.getLastToken(node);
78
-
79
- if (lastToken.value === ";") {
80
- lastToken = sourceCode.getTokenBefore(lastToken);
81
- }
82
- return lastToken;
83
+ return sourceCode.getLastToken(node, astUtils.isNotSemicolonToken);
83
84
  }
84
85
 
85
86
  /**
@@ -5,6 +5,14 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const lodash = require("lodash");
13
+
14
+ const astUtils = require("../ast-utils");
15
+
8
16
  //------------------------------------------------------------------------------
9
17
  // Rule Definition
10
18
  //------------------------------------------------------------------------------
@@ -84,19 +92,12 @@ module.exports = {
84
92
  */
85
93
  function reportIfTooManyStatements(node, count, max) {
86
94
  if (count > max) {
87
- const messageEnd = " has too many statements ({{count}}). Maximum allowed is {{max}}.";
88
- let name = "This function";
89
-
90
- if (node.id) {
91
- name = `Function '${node.id.name}'`;
92
- } else if (node.parent.type === "MethodDefinition" || node.parent.type === "Property") {
93
- name = `Function '${context.getSource(node.parent.key)}'`;
94
- }
95
+ const name = lodash.upperFirst(astUtils.getFunctionNameWithKind(node));
95
96
 
96
97
  context.report({
97
98
  node,
98
- message: name + messageEnd,
99
- data: { count, max }
99
+ message: "{{name}} has too many statements ({{count}}). Maximum allowed is {{max}}.",
100
+ data: { name, count, max }
100
101
  });
101
102
  }
102
103
  }