eslint 3.16.1 → 3.19.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.
Files changed (86) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/README.md +1 -0
  3. package/conf/eslint-recommended.js +2 -0
  4. package/lib/ast-utils.js +3 -67
  5. package/lib/code-path-analysis/code-path-analyzer.js +2 -7
  6. package/lib/code-path-analysis/debug-helpers.js +17 -16
  7. package/lib/config/config-file.js +68 -38
  8. package/lib/config/config-rule.js +14 -10
  9. package/lib/config/plugins.js +19 -8
  10. package/lib/eslint.js +11 -10
  11. package/lib/formatters/codeframe.js +4 -9
  12. package/lib/formatters/stylish.js +5 -4
  13. package/lib/ignored-paths.js +6 -0
  14. package/lib/internal-rules/internal-no-invalid-meta.js +2 -40
  15. package/lib/rules/array-callback-return.js +15 -5
  16. package/lib/rules/arrow-body-style.js +2 -2
  17. package/lib/rules/arrow-parens.js +9 -3
  18. package/lib/rules/capitalized-comments.js +2 -1
  19. package/lib/rules/comma-dangle.js +3 -2
  20. package/lib/rules/comma-spacing.js +4 -14
  21. package/lib/rules/comma-style.js +8 -14
  22. package/lib/rules/complexity.js +14 -8
  23. package/lib/rules/consistent-return.js +17 -10
  24. package/lib/rules/curly.js +2 -2
  25. package/lib/rules/dot-notation.js +12 -6
  26. package/lib/rules/func-name-matching.js +18 -7
  27. package/lib/rules/func-names.js +20 -5
  28. package/lib/rules/keyword-spacing.js +19 -4
  29. package/lib/rules/line-comment-position.js +15 -5
  30. package/lib/rules/lines-around-comment.js +19 -0
  31. package/lib/rules/lines-around-directive.js +1 -1
  32. package/lib/rules/max-params.js +17 -4
  33. package/lib/rules/max-statements.js +11 -10
  34. package/lib/rules/new-parens.js +7 -21
  35. package/lib/rules/no-compare-neg-zero.js +53 -0
  36. package/lib/rules/no-cond-assign.js +4 -17
  37. package/lib/rules/no-else-return.js +19 -4
  38. package/lib/rules/no-empty-function.js +9 -16
  39. package/lib/rules/no-extra-parens.js +110 -121
  40. package/lib/rules/no-extra-semi.js +16 -3
  41. package/lib/rules/no-global-assign.js +1 -1
  42. package/lib/rules/no-implicit-coercion.js +21 -8
  43. package/lib/rules/no-invalid-regexp.js +2 -1
  44. package/lib/rules/no-multiple-empty-lines.js +2 -4
  45. package/lib/rules/no-native-reassign.js +1 -1
  46. package/lib/rules/no-negated-in-lhs.js +1 -1
  47. package/lib/rules/no-new-func.js +6 -8
  48. package/lib/rules/no-new.js +2 -6
  49. package/lib/rules/no-param-reassign.js +37 -7
  50. package/lib/rules/no-process-exit.js +2 -10
  51. package/lib/rules/no-restricted-properties.js +2 -0
  52. package/lib/rules/no-restricted-syntax.js +32 -21
  53. package/lib/rules/no-return-await.js +1 -1
  54. package/lib/rules/no-sequences.js +2 -2
  55. package/lib/rules/no-sync.js +8 -13
  56. package/lib/rules/no-unsafe-negation.js +1 -1
  57. package/lib/rules/no-unused-expressions.js +10 -1
  58. package/lib/rules/no-unused-vars.js +12 -12
  59. package/lib/rules/no-use-before-define.js +1 -1
  60. package/lib/rules/no-useless-computed-key.js +12 -1
  61. package/lib/rules/no-useless-escape.js +8 -2
  62. package/lib/rules/no-useless-return.js +13 -2
  63. package/lib/rules/nonblock-statement-body-position.js +114 -0
  64. package/lib/rules/object-curly-spacing.js +2 -2
  65. package/lib/rules/object-shorthand.js +10 -3
  66. package/lib/rules/operator-assignment.js +20 -3
  67. package/lib/rules/padded-blocks.js +37 -31
  68. package/lib/rules/prefer-const.js +1 -1
  69. package/lib/rules/prefer-destructuring.js +1 -1
  70. package/lib/rules/quotes.js +1 -0
  71. package/lib/rules/semi-spacing.js +2 -15
  72. package/lib/rules/semi.js +17 -13
  73. package/lib/rules/sort-vars.js +3 -5
  74. package/lib/rules/space-before-function-paren.js +53 -77
  75. package/lib/rules/space-in-parens.js +4 -8
  76. package/lib/rules/space-unary-ops.js +19 -1
  77. package/lib/rules/strict.js +8 -2
  78. package/lib/rules/yoda.js +2 -2
  79. package/lib/testers/rule-tester.js +44 -13
  80. package/lib/util/fix-tracker.js +121 -0
  81. package/lib/util/glob-util.js +1 -1
  82. package/lib/util/node-event-generator.js +274 -4
  83. package/lib/util/source-code-fixer.js +3 -9
  84. package/lib/util/source-code.js +99 -2
  85. package/lib/util/traverser.js +16 -25
  86. package/package.json +34 -34
@@ -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
 
@@ -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;
@@ -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
 
@@ -74,7 +74,7 @@ module.exports = {
74
74
  const lastToken = sourceCode.getLastToken(node);
75
75
  const secondToLastToken = sourceCode.getTokenBefore(lastToken);
76
76
 
77
- return lastToken.type === "Punctuator" && lastToken.value === ";" && lastToken.loc.start.line > secondToLastToken.loc.end.line
77
+ return astUtils.isSemicolonToken(lastToken) && lastToken.loc.start.line > secondToLastToken.loc.end.line
78
78
  ? secondToLastToken
79
79
  : lastToken;
80
80
  }
@@ -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
 
@@ -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
  }
@@ -6,28 +6,14 @@
6
6
  "use strict";
7
7
 
8
8
  //------------------------------------------------------------------------------
9
- // Helpers
9
+ // Requirements
10
10
  //------------------------------------------------------------------------------
11
11
 
12
- /**
13
- * Checks whether the given token is an opening parenthesis or not.
14
- *
15
- * @param {Token} token - The token to check.
16
- * @returns {boolean} `true` if the token is an opening parenthesis.
17
- */
18
- function isOpeningParen(token) {
19
- return token.type === "Punctuator" && token.value === "(";
20
- }
12
+ const astUtils = require("../ast-utils");
21
13
 
22
- /**
23
- * Checks whether the given token is an closing parenthesis or not.
24
- *
25
- * @param {Token} token - The token to check.
26
- * @returns {boolean} `true` if the token is an closing parenthesis.
27
- */
28
- function isClosingParen(token) {
29
- return token.type === "Punctuator" && token.value === ")";
30
- }
14
+ //------------------------------------------------------------------------------
15
+ // Helpers
16
+ //------------------------------------------------------------------------------
31
17
 
32
18
  //------------------------------------------------------------------------------
33
19
  // Rule Definition
@@ -56,8 +42,8 @@ module.exports = {
56
42
  }
57
43
 
58
44
  const lastToken = sourceCode.getLastToken(node);
59
- const hasLastParen = lastToken && isClosingParen(lastToken);
60
- const hasParens = hasLastParen && isOpeningParen(sourceCode.getTokenBefore(lastToken));
45
+ const hasLastParen = lastToken && astUtils.isClosingParenToken(lastToken);
46
+ const hasParens = hasLastParen && astUtils.isOpeningParenToken(sourceCode.getTokenBefore(lastToken));
61
47
 
62
48
  if (!hasParens) {
63
49
  context.report({
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @fileoverview The rule should warn against code that tries to compare against -0.
3
+ * @author Aladdin-ADD <hh_2013@foxmail.com>
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Rule Definition
9
+ //------------------------------------------------------------------------------
10
+
11
+ module.exports = {
12
+ meta: {
13
+ docs: {
14
+ description: "disallow comparing against -0",
15
+ category: "Possible Errors",
16
+ recommended: false
17
+ },
18
+ fixable: null,
19
+ schema: []
20
+ },
21
+
22
+ create(context) {
23
+
24
+ //--------------------------------------------------------------------------
25
+ // Helpers
26
+ //--------------------------------------------------------------------------
27
+
28
+ /**
29
+ * Checks a given node is -0
30
+ *
31
+ * @param {ASTNode} node - A node to check.
32
+ * @returns {boolean} `true` if the node is -0.
33
+ */
34
+ function isNegZero(node) {
35
+ return node.type === "UnaryExpression" && node.operator === "-" && node.argument.type === "Literal" && node.argument.value === 0;
36
+ }
37
+ const OPERATORS_TO_CHECK = new Set([">", ">=", "<", "<=", "==", "===", "!=", "!=="]);
38
+
39
+ return {
40
+ BinaryExpression(node) {
41
+ if (OPERATORS_TO_CHECK.has(node.operator)) {
42
+ if (isNegZero(node.left) || isNegZero(node.right)) {
43
+ context.report({
44
+ node,
45
+ message: "Do not use the '{{operator}}' operator to compare against -0.",
46
+ data: { operator: node.operator }
47
+ });
48
+ }
49
+ }
50
+ }
51
+ };
52
+ }
53
+ };
@@ -66,19 +66,6 @@ module.exports = {
66
66
  return null;
67
67
  }
68
68
 
69
- /**
70
- * Check whether the code represented by an AST node is enclosed in parentheses.
71
- * @param {!Object} node The node to test.
72
- * @returns {boolean} `true` if the code is enclosed in parentheses; otherwise, `false`.
73
- */
74
- function isParenthesised(node) {
75
- const previousToken = sourceCode.getTokenBefore(node),
76
- nextToken = sourceCode.getTokenAfter(node);
77
-
78
- return previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
79
- nextToken.value === ")" && nextToken.range[0] >= node.range[1];
80
- }
81
-
82
69
  /**
83
70
  * Check whether the code represented by an AST node is enclosed in two sets of parentheses.
84
71
  * @param {!Object} node The node to test.
@@ -88,9 +75,9 @@ module.exports = {
88
75
  const previousToken = sourceCode.getTokenBefore(node, 1),
89
76
  nextToken = sourceCode.getTokenAfter(node, 1);
90
77
 
91
- return isParenthesised(node) &&
92
- previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
93
- nextToken.value === ")" && nextToken.range[0] >= node.range[1];
78
+ return astUtils.isParenthesised(sourceCode, node) &&
79
+ astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] &&
80
+ astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1];
94
81
  }
95
82
 
96
83
  /**
@@ -102,7 +89,7 @@ module.exports = {
102
89
  if (node.test &&
103
90
  (node.test.type === "AssignmentExpression") &&
104
91
  (node.type === "ForStatement"
105
- ? !isParenthesised(node.test)
92
+ ? !astUtils.isParenthesised(sourceCode, node.test)
106
93
  : !isParenthesisedTwice(node.test)
107
94
  )
108
95
  ) {
@@ -5,6 +5,13 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("../ast-utils");
13
+ const FixTracker = require("../util/fix-tracker");
14
+
8
15
  //------------------------------------------------------------------------------
9
16
  // Rule Definition
10
17
  //------------------------------------------------------------------------------
@@ -86,7 +93,13 @@ module.exports = {
86
93
  } else {
87
94
  fixedSource = source;
88
95
  }
89
- return fixer.replaceTextRange([elseToken.start, node.end], fixedSource);
96
+
97
+ // Extend the replacement range to include the entire
98
+ // function to avoid conflicting with no-useless-return.
99
+ // https://github.com/eslint/eslint/issues/8026
100
+ return new FixTracker(fixer, sourceCode)
101
+ .retainEnclosingFunction(node)
102
+ .replaceTextRange([elseToken.start, node.end], fixedSource);
90
103
  }
91
104
  });
92
105
  }
@@ -187,9 +200,11 @@ module.exports = {
187
200
  let consequents,
188
201
  alternate;
189
202
 
190
- // Only "top-level" if statements are checked, meaning the first `if`
191
- // in a `if-else-if-...` chain.
192
- if (parent.type === "IfStatement" && parent.alternate === node) {
203
+ /*
204
+ * Fixing this would require splitting one statement into two, so no error should
205
+ * be reported if this node is in a position where only one statement is allowed.
206
+ */
207
+ if (!astUtils.STATEMENT_LIST_PARENTS.has(parent.type)) {
193
208
  return;
194
209
  }
195
210
 
@@ -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
  // Helpers
10
16
  //------------------------------------------------------------------------------
@@ -19,18 +25,6 @@ const ALLOW_OPTIONS = Object.freeze([
19
25
  "setters",
20
26
  "constructors"
21
27
  ]);
22
- const SHOW_KIND = Object.freeze({
23
- functions: "function",
24
- arrowFunctions: "arrow function",
25
- generatorFunctions: "generator function",
26
- asyncFunctions: "async function",
27
- methods: "method",
28
- generatorMethods: "generator method",
29
- asyncMethods: "async method",
30
- getters: "getter",
31
- setters: "setter",
32
- constructors: "constructor"
33
- });
34
28
 
35
29
  /**
36
30
  * Gets the kind of a given function node.
@@ -137,6 +131,7 @@ module.exports = {
137
131
  */
138
132
  function reportIfEmpty(node) {
139
133
  const kind = getKind(node);
134
+ const name = astUtils.getFunctionNameWithKind(node);
140
135
 
141
136
  if (allowed.indexOf(kind) === -1 &&
142
137
  node.body.type === "BlockStatement" &&
@@ -146,10 +141,8 @@ module.exports = {
146
141
  context.report({
147
142
  node,
148
143
  loc: node.body.loc.start,
149
- message: "Unexpected empty {{kind}}.",
150
- data: {
151
- kind: SHOW_KIND[kind]
152
- }
144
+ message: "Unexpected empty {{name}}.",
145
+ data: { name }
153
146
  });
154
147
  }
155
148
  }