eslint 7.0.0-alpha.1 → 7.0.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 (84) hide show
  1. package/CHANGELOG.md +329 -0
  2. package/README.md +7 -7
  3. package/bin/eslint.js +115 -77
  4. package/conf/category-list.json +2 -3
  5. package/conf/environments.js +2 -1
  6. package/conf/eslint-recommended.js +3 -0
  7. package/lib/api.js +2 -0
  8. package/lib/cli-engine/cascading-config-array-factory.js +16 -2
  9. package/lib/cli-engine/cli-engine.js +53 -47
  10. package/lib/cli-engine/config-array/config-array.js +30 -1
  11. package/lib/cli-engine/config-array/ignore-pattern.js +7 -1
  12. package/lib/cli-engine/config-array-factory.js +244 -235
  13. package/lib/cli.js +181 -95
  14. package/lib/eslint/eslint.js +656 -0
  15. package/lib/eslint/index.js +7 -0
  16. package/lib/init/autoconfig.js +4 -4
  17. package/lib/init/config-file.js +2 -2
  18. package/lib/init/config-initializer.js +2 -4
  19. package/lib/init/source-code-utils.js +2 -2
  20. package/lib/linter/node-event-generator.js +2 -2
  21. package/lib/options.js +0 -1
  22. package/lib/rule-tester/rule-tester.js +178 -23
  23. package/lib/rules/accessor-pairs.js +2 -2
  24. package/lib/rules/array-callback-return.js +3 -18
  25. package/lib/rules/arrow-body-style.js +26 -15
  26. package/lib/rules/callback-return.js +4 -0
  27. package/lib/rules/camelcase.js +38 -1
  28. package/lib/rules/comma-style.js +3 -8
  29. package/lib/rules/computed-property-spacing.js +2 -2
  30. package/lib/rules/curly.js +124 -40
  31. package/lib/rules/func-call-spacing.js +4 -3
  32. package/lib/rules/func-names.js +31 -24
  33. package/lib/rules/getter-return.js +2 -12
  34. package/lib/rules/global-require.js +4 -0
  35. package/lib/rules/handle-callback-err.js +4 -0
  36. package/lib/rules/id-blacklist.js +140 -64
  37. package/lib/rules/id-length.js +14 -4
  38. package/lib/rules/indent-legacy.js +0 -16
  39. package/lib/rules/key-spacing.js +1 -1
  40. package/lib/rules/new-cap.js +1 -1
  41. package/lib/rules/newline-per-chained-call.js +6 -3
  42. package/lib/rules/no-alert.js +5 -3
  43. package/lib/rules/no-buffer-constructor.js +4 -0
  44. package/lib/rules/no-dupe-else-if.js +1 -1
  45. package/lib/rules/no-empty-function.js +4 -2
  46. package/lib/rules/no-eval.js +3 -2
  47. package/lib/rules/no-extra-bind.js +1 -1
  48. package/lib/rules/no-extra-boolean-cast.js +168 -38
  49. package/lib/rules/no-extra-parens.js +9 -5
  50. package/lib/rules/no-implied-eval.js +83 -101
  51. package/lib/rules/no-import-assign.js +1 -1
  52. package/lib/rules/no-inner-declarations.js +31 -39
  53. package/lib/rules/no-lone-blocks.js +1 -1
  54. package/lib/rules/no-magic-numbers.js +72 -37
  55. package/lib/rules/no-mixed-requires.js +4 -0
  56. package/lib/rules/no-new-object.js +15 -3
  57. package/lib/rules/no-new-require.js +4 -0
  58. package/lib/rules/no-new-wrappers.js +1 -1
  59. package/lib/rules/no-obj-calls.js +24 -5
  60. package/lib/rules/no-path-concat.js +4 -0
  61. package/lib/rules/no-plusplus.js +39 -3
  62. package/lib/rules/no-process-env.js +4 -0
  63. package/lib/rules/no-process-exit.js +4 -0
  64. package/lib/rules/no-prototype-builtins.js +1 -1
  65. package/lib/rules/no-restricted-modules.js +52 -18
  66. package/lib/rules/no-setter-return.js +1 -1
  67. package/lib/rules/no-sync.js +4 -0
  68. package/lib/rules/no-underscore-dangle.js +1 -1
  69. package/lib/rules/no-unexpected-multiline.js +22 -12
  70. package/lib/rules/no-useless-concat.js +1 -1
  71. package/lib/rules/operator-assignment.js +3 -3
  72. package/lib/rules/operator-linebreak.js +4 -16
  73. package/lib/rules/prefer-numeric-literals.js +3 -3
  74. package/lib/rules/prefer-object-spread.js +2 -2
  75. package/lib/rules/require-await.js +1 -1
  76. package/lib/rules/space-before-function-paren.js +5 -2
  77. package/lib/rules/template-curly-spacing.js +59 -42
  78. package/lib/rules/utils/ast-utils.js +65 -4
  79. package/lib/rules/wrap-iife.js +54 -17
  80. package/lib/rules/yoda.js +101 -51
  81. package/lib/shared/relative-module-resolver.js +1 -0
  82. package/lib/shared/types.js +9 -2
  83. package/messages/plugin-conflict.txt +7 -0
  84. package/package.json +27 -26
@@ -696,20 +696,6 @@ module.exports = {
696
696
  return startLine === endLine;
697
697
  }
698
698
 
699
- /**
700
- * Check to see if the first element inside an array is an object and on the same line as the node
701
- * If the node is not an array then it will return false.
702
- * @param {ASTNode} node node to check
703
- * @returns {boolean} success/failure
704
- */
705
- function isFirstArrayElementOnSameLine(node) {
706
- if (node.type === "ArrayExpression" && node.elements[0]) {
707
- return node.elements[0].loc.start.line === node.loc.start.line && node.elements[0].type === "ObjectExpression";
708
- }
709
- return false;
710
-
711
- }
712
-
713
699
  /**
714
700
  * Check indent for array block content or object block content
715
701
  * @param {ASTNode} node node to examine
@@ -776,8 +762,6 @@ module.exports = {
776
762
  nodeIndent += indentSize;
777
763
  }
778
764
  }
779
- } else if (!parentVarNode && !isFirstArrayElementOnSameLine(parent) && parent.type !== "MemberExpression" && parent.type !== "ExpressionStatement" && parent.type !== "AssignmentExpression" && parent.type !== "Property") {
780
- nodeIndent += indentSize;
781
765
  }
782
766
 
783
767
  checkFirstNodeLineIndent(node, nodeIndent);
@@ -45,7 +45,7 @@ function isSingleLine(node) {
45
45
  /**
46
46
  * Checks whether the properties on a single line.
47
47
  * @param {ASTNode[]} properties List of Property AST nodes.
48
- * @returns {boolean} True if all properies is on a single line.
48
+ * @returns {boolean} True if all properties is on a single line.
49
49
  */
50
50
  function isSingleLineProperties(properties) {
51
51
  const [firstProp] = properties,
@@ -235,7 +235,7 @@ module.exports = {
235
235
  callee = callee.property;
236
236
  }
237
237
 
238
- context.report({ node, loc: callee.loc.start, messageId });
238
+ context.report({ node, loc: callee.loc, messageId });
239
239
  }
240
240
 
241
241
  //--------------------------------------------------------------------------
@@ -90,16 +90,19 @@ module.exports = {
90
90
  }
91
91
 
92
92
  if (depth > ignoreChainWithDepth && astUtils.isTokenOnSameLine(callee.object, callee.property)) {
93
+ const firstTokenAfterObject = sourceCode.getTokenAfter(callee.object, astUtils.isNotClosingParenToken);
94
+
93
95
  context.report({
94
96
  node: callee.property,
95
- loc: callee.property.loc.start,
97
+ loc: {
98
+ start: firstTokenAfterObject.loc.start,
99
+ end: callee.loc.end
100
+ },
96
101
  messageId: "expected",
97
102
  data: {
98
103
  callee: getPropertyText(callee)
99
104
  },
100
105
  fix(fixer) {
101
- const firstTokenAfterObject = sourceCode.getTokenAfter(callee.object, astUtils.isNotClosingParenToken);
102
-
103
106
  return fixer.insertTextBefore(firstTokenAfterObject, "\n");
104
107
  }
105
108
  });
@@ -8,7 +8,10 @@
8
8
  // Requirements
9
9
  //------------------------------------------------------------------------------
10
10
 
11
- const getPropertyName = require("./utils/ast-utils").getStaticPropertyName;
11
+ const {
12
+ getStaticPropertyName: getPropertyName,
13
+ getVariableByName
14
+ } = require("./utils/ast-utils");
12
15
 
13
16
  //------------------------------------------------------------------------------
14
17
  // Helpers
@@ -61,7 +64,7 @@ function isGlobalThisReferenceOrGlobalWindow(scope, node) {
61
64
  if (scope.type === "global" && node.type === "ThisExpression") {
62
65
  return true;
63
66
  }
64
- if (node.name === "window") {
67
+ if (node.name === "window" || (node.name === "globalThis" && getVariableByName(scope, "globalThis"))) {
65
68
  return !isShadowed(scope, node);
66
69
  }
67
70
 
@@ -119,7 +122,6 @@ module.exports = {
119
122
  });
120
123
  }
121
124
  }
122
-
123
125
  }
124
126
  };
125
127
 
@@ -10,6 +10,10 @@
10
10
 
11
11
  module.exports = {
12
12
  meta: {
13
+ deprecated: true,
14
+
15
+ replacedBy: ["node/no-deprecated-api"],
16
+
13
17
  type: "problem",
14
18
 
15
19
  docs: {
@@ -53,7 +53,7 @@ module.exports = {
53
53
  docs: {
54
54
  description: "disallow duplicate conditions in if-else-if chains",
55
55
  category: "Possible Errors",
56
- recommended: false,
56
+ recommended: true,
57
57
  url: "https://eslint.org/docs/rules/no-dupe-else-if"
58
58
  },
59
59
 
@@ -23,7 +23,9 @@ const ALLOW_OPTIONS = Object.freeze([
23
23
  "generatorMethods",
24
24
  "getters",
25
25
  "setters",
26
- "constructors"
26
+ "constructors",
27
+ "asyncFunctions",
28
+ "asyncMethods"
27
29
  ]);
28
30
 
29
31
  /**
@@ -149,7 +151,7 @@ module.exports = {
149
151
  ) {
150
152
  context.report({
151
153
  node,
152
- loc: node.body.loc.start,
154
+ loc: node.body.loc,
153
155
  messageId: "unexpected",
154
156
  data: { name }
155
157
  });
@@ -17,7 +17,8 @@ const astUtils = require("./utils/ast-utils");
17
17
 
18
18
  const candidatesOfGlobalObject = Object.freeze([
19
19
  "global",
20
- "window"
20
+ "window",
21
+ "globalThis"
21
22
  ]);
22
23
 
23
24
  /**
@@ -158,7 +159,7 @@ module.exports = {
158
159
 
159
160
  context.report({
160
161
  node: reportNode,
161
- loc: locationNode.loc.start,
162
+ loc: locationNode.loc,
162
163
  messageId: "unexpected"
163
164
  });
164
165
  }
@@ -64,7 +64,7 @@ module.exports = {
64
64
  context.report({
65
65
  node: node.parent.parent,
66
66
  messageId: "unexpected",
67
- loc: node.parent.property.loc.start,
67
+ loc: node.parent.property.loc,
68
68
  fix(fixer) {
69
69
  if (node.parent.parent.arguments.length && !isSideEffectFree(node.parent.parent.arguments[0])) {
70
70
  return null;
@@ -10,6 +10,9 @@
10
10
  //------------------------------------------------------------------------------
11
11
 
12
12
  const astUtils = require("./utils/ast-utils");
13
+ const eslintUtils = require("eslint-utils");
14
+
15
+ const precedence = astUtils.getPrecedence;
13
16
 
14
17
  //------------------------------------------------------------------------------
15
18
  // Rule Definition
@@ -26,7 +29,16 @@ module.exports = {
26
29
  url: "https://eslint.org/docs/rules/no-extra-boolean-cast"
27
30
  },
28
31
 
29
- schema: [],
32
+ schema: [{
33
+ type: "object",
34
+ properties: {
35
+ enforceForLogicalOperands: {
36
+ type: "boolean",
37
+ default: false
38
+ }
39
+ },
40
+ additionalProperties: false
41
+ }],
30
42
  fixable: "code",
31
43
 
32
44
  messages: {
@@ -47,23 +59,67 @@ module.exports = {
47
59
  "ForStatement"
48
60
  ];
49
61
 
62
+ /**
63
+ * Check if a node is a Boolean function or constructor.
64
+ * @param {ASTNode} node the node
65
+ * @returns {boolean} If the node is Boolean function or constructor
66
+ */
67
+ function isBooleanFunctionOrConstructorCall(node) {
68
+
69
+ // Boolean(<bool>) and new Boolean(<bool>)
70
+ return (node.type === "CallExpression" || node.type === "NewExpression") &&
71
+ node.callee.type === "Identifier" &&
72
+ node.callee.name === "Boolean";
73
+ }
74
+
75
+ /**
76
+ * Checks whether the node is a logical expression and that the option is enabled
77
+ * @param {ASTNode} node the node
78
+ * @returns {boolean} if the node is a logical expression and option is enabled
79
+ */
80
+ function isLogicalContext(node) {
81
+ return node.type === "LogicalExpression" &&
82
+ (node.operator === "||" || node.operator === "&&") &&
83
+ (context.options.length && context.options[0].enforceForLogicalOperands === true);
84
+
85
+ }
86
+
87
+
50
88
  /**
51
89
  * Check if a node is in a context where its value would be coerced to a boolean at runtime.
52
90
  * @param {ASTNode} node The node
53
- * @param {ASTNode} parent Its parent
54
91
  * @returns {boolean} If it is in a boolean context
55
92
  */
56
- function isInBooleanContext(node, parent) {
93
+ function isInBooleanContext(node) {
57
94
  return (
58
- (BOOLEAN_NODE_TYPES.indexOf(parent.type) !== -1 &&
59
- node === parent.test) ||
95
+ (isBooleanFunctionOrConstructorCall(node.parent) &&
96
+ node === node.parent.arguments[0]) ||
97
+
98
+ (BOOLEAN_NODE_TYPES.indexOf(node.parent.type) !== -1 &&
99
+ node === node.parent.test) ||
60
100
 
61
101
  // !<bool>
62
- (parent.type === "UnaryExpression" &&
63
- parent.operator === "!")
102
+ (node.parent.type === "UnaryExpression" &&
103
+ node.parent.operator === "!")
64
104
  );
65
105
  }
66
106
 
107
+ /**
108
+ * Checks whether the node is a context that should report an error
109
+ * Acts recursively if it is in a logical context
110
+ * @param {ASTNode} node the node
111
+ * @returns {boolean} If the node is in one of the flagged contexts
112
+ */
113
+ function isInFlaggedContext(node) {
114
+ return isInBooleanContext(node) ||
115
+ (isLogicalContext(node.parent) &&
116
+
117
+ // For nested logical statements
118
+ isInFlaggedContext(node.parent)
119
+ );
120
+ }
121
+
122
+
67
123
  /**
68
124
  * Check if a node has comments inside.
69
125
  * @param {ASTNode} node The node to check.
@@ -73,40 +129,95 @@ module.exports = {
73
129
  return Boolean(sourceCode.getCommentsInside(node).length);
74
130
  }
75
131
 
132
+ /**
133
+ * Checks if the given node is wrapped in grouping parentheses. Parentheses for constructs such as if() don't count.
134
+ * @param {ASTNode} node The node to check.
135
+ * @returns {boolean} `true` if the node is parenthesized.
136
+ * @private
137
+ */
138
+ function isParenthesized(node) {
139
+ return eslintUtils.isParenthesized(1, node, sourceCode);
140
+ }
141
+
142
+ /**
143
+ * Determines whether the given node needs to be parenthesized when replacing the previous node.
144
+ * It assumes that `previousNode` is the node to be reported by this rule, so it has a limited list
145
+ * of possible parent node types. By the same assumption, the node's role in a particular parent is already known.
146
+ * For example, if the parent is `ConditionalExpression`, `previousNode` must be its `test` child.
147
+ * @param {ASTNode} previousNode Previous node.
148
+ * @param {ASTNode} node The node to check.
149
+ * @returns {boolean} `true` if the node needs to be parenthesized.
150
+ */
151
+ function needsParens(previousNode, node) {
152
+ if (isParenthesized(previousNode)) {
153
+
154
+ // parentheses around the previous node will stay, so there is no need for an additional pair
155
+ return false;
156
+ }
157
+
158
+ // parent of the previous node will become parent of the replacement node
159
+ const parent = previousNode.parent;
160
+
161
+ switch (parent.type) {
162
+ case "CallExpression":
163
+ case "NewExpression":
164
+ return node.type === "SequenceExpression";
165
+ case "IfStatement":
166
+ case "DoWhileStatement":
167
+ case "WhileStatement":
168
+ case "ForStatement":
169
+ return false;
170
+ case "ConditionalExpression":
171
+ return precedence(node) <= precedence(parent);
172
+ case "UnaryExpression":
173
+ return precedence(node) < precedence(parent);
174
+ case "LogicalExpression":
175
+ if (previousNode === parent.left) {
176
+ return precedence(node) < precedence(parent);
177
+ }
178
+ return precedence(node) <= precedence(parent);
179
+
180
+ /* istanbul ignore next */
181
+ default:
182
+ throw new Error(`Unexpected parent type: ${parent.type}`);
183
+ }
184
+ }
185
+
76
186
  return {
77
187
  UnaryExpression(node) {
78
- const ancestors = context.getAncestors(),
79
- parent = ancestors.pop(),
80
- grandparent = ancestors.pop();
188
+ const parent = node.parent;
189
+
81
190
 
82
191
  // Exit early if it's guaranteed not to match
83
192
  if (node.operator !== "!" ||
84
- parent.type !== "UnaryExpression" ||
85
- parent.operator !== "!") {
193
+ parent.type !== "UnaryExpression" ||
194
+ parent.operator !== "!") {
86
195
  return;
87
196
  }
88
197
 
89
- if (isInBooleanContext(parent, grandparent) ||
90
198
 
91
- // Boolean(<bool>) and new Boolean(<bool>)
92
- ((grandparent.type === "CallExpression" || grandparent.type === "NewExpression") &&
93
- grandparent.callee.type === "Identifier" &&
94
- grandparent.callee.name === "Boolean")
95
- ) {
199
+ if (isInFlaggedContext(parent)) {
96
200
  context.report({
97
201
  node: parent,
98
202
  messageId: "unexpectedNegation",
99
- fix: fixer => {
203
+ fix(fixer) {
100
204
  if (hasCommentsInside(parent)) {
101
205
  return null;
102
206
  }
103
207
 
208
+ if (needsParens(parent, node.argument)) {
209
+ return fixer.replaceText(parent, `(${sourceCode.getText(node.argument)})`);
210
+ }
211
+
104
212
  let prefix = "";
105
213
  const tokenBefore = sourceCode.getTokenBefore(parent);
106
214
  const firstReplacementToken = sourceCode.getFirstToken(node.argument);
107
215
 
108
- if (tokenBefore && tokenBefore.range[1] === parent.range[0] &&
109
- !astUtils.canTokensBeAdjacent(tokenBefore, firstReplacementToken)) {
216
+ if (
217
+ tokenBefore &&
218
+ tokenBefore.range[1] === parent.range[0] &&
219
+ !astUtils.canTokensBeAdjacent(tokenBefore, firstReplacementToken)
220
+ ) {
110
221
  prefix = " ";
111
222
  }
112
223
 
@@ -115,22 +226,25 @@ module.exports = {
115
226
  });
116
227
  }
117
228
  },
118
- CallExpression(node) {
119
- const parent = node.parent;
120
229
 
230
+ CallExpression(node) {
121
231
  if (node.callee.type !== "Identifier" || node.callee.name !== "Boolean") {
122
232
  return;
123
233
  }
124
234
 
125
- if (isInBooleanContext(node, parent)) {
235
+ if (isInFlaggedContext(node)) {
126
236
  context.report({
127
237
  node,
128
238
  messageId: "unexpectedCall",
129
- fix: fixer => {
130
- if (!node.arguments.length) {
239
+ fix(fixer) {
240
+ const parent = node.parent;
241
+
242
+ if (node.arguments.length === 0) {
131
243
  if (parent.type === "UnaryExpression" && parent.operator === "!") {
132
244
 
133
- // !Boolean() -> true
245
+ /*
246
+ * !Boolean() -> true
247
+ */
134
248
 
135
249
  if (hasCommentsInside(parent)) {
136
250
  return null;
@@ -140,32 +254,48 @@ module.exports = {
140
254
  let prefix = "";
141
255
  const tokenBefore = sourceCode.getTokenBefore(parent);
142
256
 
143
- if (tokenBefore && tokenBefore.range[1] === parent.range[0] &&
144
- !astUtils.canTokensBeAdjacent(tokenBefore, replacement)) {
257
+ if (
258
+ tokenBefore &&
259
+ tokenBefore.range[1] === parent.range[0] &&
260
+ !astUtils.canTokensBeAdjacent(tokenBefore, replacement)
261
+ ) {
145
262
  prefix = " ";
146
263
  }
147
264
 
148
265
  return fixer.replaceText(parent, prefix + replacement);
149
266
  }
150
267
 
151
- // Boolean() -> false
268
+ /*
269
+ * Boolean() -> false
270
+ */
271
+
152
272
  if (hasCommentsInside(node)) {
153
273
  return null;
154
274
  }
275
+
155
276
  return fixer.replaceText(node, "false");
156
277
  }
157
278
 
158
- if (node.arguments.length > 1 || node.arguments[0].type === "SpreadElement" ||
159
- hasCommentsInside(node)) {
160
- return null;
161
- }
279
+ if (node.arguments.length === 1) {
280
+ const argument = node.arguments[0];
162
281
 
163
- const argument = node.arguments[0];
282
+ if (argument.type === "SpreadElement" || hasCommentsInside(node)) {
283
+ return null;
284
+ }
285
+
286
+ /*
287
+ * Boolean(expression) -> expression
288
+ */
164
289
 
165
- if (astUtils.getPrecedence(argument) < astUtils.getPrecedence(node.parent)) {
166
- return fixer.replaceText(node, `(${sourceCode.getText(argument)})`);
290
+ if (needsParens(node, argument)) {
291
+ return fixer.replaceText(node, `(${sourceCode.getText(argument)})`);
292
+ }
293
+
294
+ return fixer.replaceText(node, sourceCode.getText(argument));
167
295
  }
168
- return fixer.replaceText(node, sourceCode.getText(argument));
296
+
297
+ // two or more arguments
298
+ return null;
169
299
  }
170
300
  });
171
301
  }
@@ -307,13 +307,13 @@ module.exports = {
307
307
  */
308
308
  function requiresLeadingSpace(node) {
309
309
  const leftParenToken = sourceCode.getTokenBefore(node);
310
- const tokenBeforeLeftParen = sourceCode.getTokenBefore(node, 1);
311
- const firstToken = sourceCode.getFirstToken(node);
310
+ const tokenBeforeLeftParen = sourceCode.getTokenBefore(leftParenToken, { includeComments: true });
311
+ const tokenAfterLeftParen = sourceCode.getTokenAfter(leftParenToken, { includeComments: true });
312
312
 
313
313
  return tokenBeforeLeftParen &&
314
314
  tokenBeforeLeftParen.range[1] === leftParenToken.range[0] &&
315
- leftParenToken.range[1] === firstToken.range[0] &&
316
- !astUtils.canTokensBeAdjacent(tokenBeforeLeftParen, firstToken);
315
+ leftParenToken.range[1] === tokenAfterLeftParen.range[0] &&
316
+ !astUtils.canTokensBeAdjacent(tokenBeforeLeftParen, tokenAfterLeftParen);
317
317
  }
318
318
 
319
319
  /**
@@ -560,7 +560,11 @@ module.exports = {
560
560
  tokensToIgnore.add(secondToken);
561
561
  }
562
562
 
563
- if (hasExcessParens(node)) {
563
+ const hasExtraParens = node.parent.type === "ExportDefaultDeclaration"
564
+ ? hasExcessParensWithPrecedence(node, PRECEDENCE_OF_ASSIGNMENT_EXPR)
565
+ : hasExcessParens(node);
566
+
567
+ if (hasExtraParens) {
564
568
  report(node);
565
569
  }
566
570
  }