eslint 6.5.1 → 6.7.2

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 (197) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/README.md +10 -9
  3. package/conf/config-schema.js +1 -0
  4. package/conf/default-cli-options.js +1 -1
  5. package/lib/cli-engine/cascading-config-array-factory.js +40 -14
  6. package/lib/cli-engine/cli-engine.js +49 -21
  7. package/lib/cli-engine/config-array/config-array.js +13 -4
  8. package/lib/cli-engine/config-array/config-dependency.js +2 -0
  9. package/lib/cli-engine/config-array/extracted-config.js +27 -0
  10. package/lib/cli-engine/config-array/ignore-pattern.js +231 -0
  11. package/lib/cli-engine/config-array/index.js +2 -0
  12. package/lib/cli-engine/config-array/override-tester.js +2 -0
  13. package/lib/cli-engine/config-array-factory.js +120 -2
  14. package/lib/cli-engine/file-enumerator.js +65 -34
  15. package/lib/cli-engine/formatters/html.js +1 -0
  16. package/lib/init/autoconfig.js +1 -11
  17. package/lib/init/config-file.js +0 -1
  18. package/lib/init/config-initializer.js +4 -4
  19. package/lib/init/config-rule.js +1 -5
  20. package/lib/init/npm-utils.js +0 -5
  21. package/lib/linter/code-path-analysis/code-path-analyzer.js +24 -38
  22. package/lib/linter/code-path-analysis/code-path-segment.js +17 -25
  23. package/lib/linter/code-path-analysis/code-path-state.js +40 -81
  24. package/lib/linter/code-path-analysis/code-path.js +10 -11
  25. package/lib/linter/code-path-analysis/debug-helpers.js +8 -12
  26. package/lib/linter/code-path-analysis/fork-context.js +23 -34
  27. package/lib/linter/code-path-analysis/id-generator.js +2 -2
  28. package/lib/linter/linter.js +121 -95
  29. package/lib/linter/node-event-generator.js +3 -2
  30. package/lib/linter/report-translator.js +73 -7
  31. package/lib/rule-tester/rule-tester.js +46 -14
  32. package/lib/rules/accessor-pairs.js +8 -8
  33. package/lib/rules/array-bracket-newline.js +12 -15
  34. package/lib/rules/array-bracket-spacing.js +12 -12
  35. package/lib/rules/array-callback-return.js +6 -11
  36. package/lib/rules/array-element-newline.js +5 -8
  37. package/lib/rules/arrow-parens.js +0 -1
  38. package/lib/rules/block-scoped-var.js +3 -3
  39. package/lib/rules/block-spacing.js +4 -4
  40. package/lib/rules/camelcase.js +19 -6
  41. package/lib/rules/capitalized-comments.js +0 -7
  42. package/lib/rules/class-methods-use-this.js +3 -3
  43. package/lib/rules/comma-dangle.js +20 -25
  44. package/lib/rules/comma-spacing.js +1 -1
  45. package/lib/rules/computed-property-spacing.js +14 -14
  46. package/lib/rules/consistent-return.js +4 -5
  47. package/lib/rules/consistent-this.js +5 -5
  48. package/lib/rules/constructor-super.js +14 -16
  49. package/lib/rules/curly.js +12 -9
  50. package/lib/rules/default-param-last.js +1 -0
  51. package/lib/rules/dot-location.js +11 -12
  52. package/lib/rules/func-names.js +6 -6
  53. package/lib/rules/function-call-argument-newline.js +8 -6
  54. package/lib/rules/generator-star-spacing.js +4 -9
  55. package/lib/rules/getter-return.js +4 -7
  56. package/lib/rules/grouped-accessor-pairs.js +224 -0
  57. package/lib/rules/indent.js +13 -2
  58. package/lib/rules/index.js +5 -0
  59. package/lib/rules/init-declarations.js +2 -2
  60. package/lib/rules/jsx-quotes.js +1 -1
  61. package/lib/rules/keyword-spacing.js +32 -56
  62. package/lib/rules/lines-around-directive.js +1 -1
  63. package/lib/rules/max-len.js +0 -5
  64. package/lib/rules/max-statements-per-line.js +3 -7
  65. package/lib/rules/multiline-comment-style.js +237 -106
  66. package/lib/rules/multiline-ternary.js +3 -3
  67. package/lib/rules/newline-after-var.js +6 -7
  68. package/lib/rules/newline-before-return.js +8 -9
  69. package/lib/rules/newline-per-chained-call.js +2 -4
  70. package/lib/rules/no-class-assign.js +2 -2
  71. package/lib/rules/no-compare-neg-zero.js +1 -2
  72. package/lib/rules/no-cond-assign.js +14 -4
  73. package/lib/rules/no-confusing-arrow.js +2 -2
  74. package/lib/rules/no-console.js +4 -8
  75. package/lib/rules/no-const-assign.js +1 -1
  76. package/lib/rules/no-constructor-return.js +62 -0
  77. package/lib/rules/no-dupe-args.js +1 -1
  78. package/lib/rules/no-dupe-class-members.js +3 -4
  79. package/lib/rules/no-dupe-else-if.js +122 -0
  80. package/lib/rules/no-dupe-keys.js +6 -5
  81. package/lib/rules/no-duplicate-imports.js +14 -18
  82. package/lib/rules/no-else-return.js +0 -8
  83. package/lib/rules/no-empty-function.js +2 -4
  84. package/lib/rules/no-eval.js +10 -18
  85. package/lib/rules/no-ex-assign.js +1 -1
  86. package/lib/rules/no-extra-bind.js +5 -12
  87. package/lib/rules/no-extra-boolean-cast.js +0 -2
  88. package/lib/rules/no-extra-label.js +4 -9
  89. package/lib/rules/no-extra-parens.js +17 -15
  90. package/lib/rules/no-extra-semi.js +5 -6
  91. package/lib/rules/no-fallthrough.js +6 -6
  92. package/lib/rules/no-func-assign.js +3 -3
  93. package/lib/rules/no-global-assign.js +4 -4
  94. package/lib/rules/no-implicit-coercion.js +10 -10
  95. package/lib/rules/no-implicit-globals.js +90 -8
  96. package/lib/rules/no-implied-eval.js +0 -1
  97. package/lib/rules/no-inline-comments.js +25 -11
  98. package/lib/rules/no-invalid-this.js +17 -5
  99. package/lib/rules/no-labels.js +3 -6
  100. package/lib/rules/no-lone-blocks.js +1 -1
  101. package/lib/rules/no-loop-func.js +6 -11
  102. package/lib/rules/no-magic-numbers.js +6 -6
  103. package/lib/rules/no-misleading-character-class.js +14 -7
  104. package/lib/rules/no-mixed-operators.js +13 -22
  105. package/lib/rules/no-mixed-requires.js +0 -1
  106. package/lib/rules/no-multi-spaces.js +1 -1
  107. package/lib/rules/no-native-reassign.js +4 -4
  108. package/lib/rules/no-octal-escape.js +1 -1
  109. package/lib/rules/no-param-reassign.js +28 -7
  110. package/lib/rules/no-redeclare.js +1 -1
  111. package/lib/rules/no-regex-spaces.js +0 -1
  112. package/lib/rules/no-restricted-imports.js +11 -11
  113. package/lib/rules/no-self-assign.js +12 -13
  114. package/lib/rules/no-sequences.js +3 -3
  115. package/lib/rules/no-setter-return.js +227 -0
  116. package/lib/rules/no-shadow.js +1 -4
  117. package/lib/rules/no-tabs.js +8 -2
  118. package/lib/rules/no-this-before-super.js +12 -13
  119. package/lib/rules/no-trailing-spaces.js +19 -7
  120. package/lib/rules/no-underscore-dangle.js +23 -4
  121. package/lib/rules/no-unexpected-multiline.js +8 -0
  122. package/lib/rules/no-unmodified-loop-condition.js +16 -29
  123. package/lib/rules/no-unneeded-ternary.js +3 -3
  124. package/lib/rules/no-unreachable.js +7 -7
  125. package/lib/rules/no-unsafe-finally.js +4 -7
  126. package/lib/rules/no-unsafe-negation.js +32 -9
  127. package/lib/rules/no-unused-expressions.js +11 -7
  128. package/lib/rules/no-unused-labels.js +3 -6
  129. package/lib/rules/no-unused-vars.js +22 -29
  130. package/lib/rules/no-use-before-define.js +10 -15
  131. package/lib/rules/no-useless-call.js +4 -4
  132. package/lib/rules/no-useless-computed-key.js +60 -33
  133. package/lib/rules/no-useless-concat.js +4 -4
  134. package/lib/rules/no-useless-constructor.js +14 -22
  135. package/lib/rules/no-useless-escape.js +29 -8
  136. package/lib/rules/no-useless-rename.js +7 -7
  137. package/lib/rules/no-useless-return.js +8 -15
  138. package/lib/rules/no-var.js +12 -25
  139. package/lib/rules/no-warning-comments.js +0 -1
  140. package/lib/rules/no-whitespace-before-property.js +3 -3
  141. package/lib/rules/object-curly-newline.js +7 -10
  142. package/lib/rules/object-curly-spacing.js +21 -22
  143. package/lib/rules/object-shorthand.js +1 -1
  144. package/lib/rules/one-var-declaration-per-line.js +2 -2
  145. package/lib/rules/operator-assignment.js +33 -3
  146. package/lib/rules/padded-blocks.js +1 -1
  147. package/lib/rules/padding-line-between-statements.js +0 -16
  148. package/lib/rules/prefer-arrow-callback.js +6 -6
  149. package/lib/rules/prefer-const.js +27 -28
  150. package/lib/rules/prefer-destructuring.js +1 -7
  151. package/lib/rules/prefer-exponentiation-operator.js +189 -0
  152. package/lib/rules/prefer-named-capture-group.js +0 -1
  153. package/lib/rules/prefer-numeric-literals.js +32 -4
  154. package/lib/rules/prefer-object-spread.js +7 -7
  155. package/lib/rules/prefer-rest-params.js +3 -6
  156. package/lib/rules/prefer-spread.js +4 -4
  157. package/lib/rules/prefer-template.js +5 -6
  158. package/lib/rules/quote-props.js +1 -1
  159. package/lib/rules/quotes.js +5 -6
  160. package/lib/rules/radix.js +5 -10
  161. package/lib/rules/require-await.js +10 -5
  162. package/lib/rules/require-yield.js +2 -2
  163. package/lib/rules/rest-spread-spacing.js +1 -1
  164. package/lib/rules/semi.js +6 -3
  165. package/lib/rules/sort-imports.js +3 -4
  166. package/lib/rules/sort-keys.js +1 -3
  167. package/lib/rules/space-before-blocks.js +1 -2
  168. package/lib/rules/space-in-parens.js +4 -4
  169. package/lib/rules/space-infix-ops.js +6 -6
  170. package/lib/rules/spaced-comment.js +20 -22
  171. package/lib/rules/strict.js +2 -4
  172. package/lib/rules/symbol-description.js +1 -2
  173. package/lib/rules/template-curly-spacing.js +2 -2
  174. package/lib/rules/use-isnan.js +40 -3
  175. package/lib/rules/utils/ast-utils.js +84 -85
  176. package/lib/rules/utils/fix-tracker.js +0 -6
  177. package/lib/rules/utils/lazy-loading-rule-map.js +0 -1
  178. package/lib/rules/vars-on-top.js +11 -11
  179. package/lib/shared/config-ops.js +2 -2
  180. package/lib/shared/runtime-info.js +8 -8
  181. package/lib/shared/traverser.js +2 -0
  182. package/lib/shared/types.js +9 -0
  183. package/lib/source-code/source-code.js +94 -17
  184. package/lib/source-code/token-store/backward-token-comment-cursor.js +5 -5
  185. package/lib/source-code/token-store/backward-token-cursor.js +5 -5
  186. package/lib/source-code/token-store/cursors.js +17 -19
  187. package/lib/source-code/token-store/decorative-cursor.js +1 -1
  188. package/lib/source-code/token-store/filter-cursor.js +2 -2
  189. package/lib/source-code/token-store/forward-token-comment-cursor.js +5 -5
  190. package/lib/source-code/token-store/forward-token-cursor.js +5 -5
  191. package/lib/source-code/token-store/index.js +86 -92
  192. package/lib/source-code/token-store/limit-cursor.js +2 -2
  193. package/lib/source-code/token-store/padded-token-cursor.js +7 -7
  194. package/lib/source-code/token-store/skip-cursor.js +2 -2
  195. package/lib/source-code/token-store/utils.js +9 -13
  196. package/package.json +9 -7
  197. package/lib/cli-engine/ignored-paths.js +0 -362
@@ -71,6 +71,9 @@ function same(a, b) {
71
71
  */
72
72
  return same(a.object, b.object) && same(a.property, b.property);
73
73
 
74
+ case "ThisExpression":
75
+ return true;
76
+
74
77
  default:
75
78
  return false;
76
79
  }
@@ -83,8 +86,14 @@ function same(a, b) {
83
86
  * @returns {boolean} `true` if the node can be fixed
84
87
  */
85
88
  function canBeFixed(node) {
86
- return node.type === "Identifier" ||
87
- node.type === "MemberExpression" && node.object.type === "Identifier" && (!node.computed || node.property.type === "Literal");
89
+ return (
90
+ node.type === "Identifier" ||
91
+ (
92
+ node.type === "MemberExpression" &&
93
+ (node.object.type === "Identifier" || node.object.type === "ThisExpression") &&
94
+ (!node.computed || node.property.type === "Literal")
95
+ )
96
+ );
88
97
  }
89
98
 
90
99
  module.exports = {
@@ -150,6 +159,11 @@ module.exports = {
150
159
  const leftText = sourceCode.getText().slice(node.range[0], equalsToken.range[0]);
151
160
  const rightText = sourceCode.getText().slice(operatorToken.range[1], node.right.range[1]);
152
161
 
162
+ // Check for comments that would be removed.
163
+ if (sourceCode.commentsExistBetween(equalsToken, operatorToken)) {
164
+ return null;
165
+ }
166
+
153
167
  return fixer.replaceText(node, `${leftText}${expr.operator}=${rightText}`);
154
168
  }
155
169
  return null;
@@ -182,11 +196,17 @@ module.exports = {
182
196
  messageId: "unexpected",
183
197
  fix(fixer) {
184
198
  if (canBeFixed(node.left)) {
199
+ const firstToken = sourceCode.getFirstToken(node);
185
200
  const operatorToken = getOperatorToken(node);
186
201
  const leftText = sourceCode.getText().slice(node.range[0], operatorToken.range[0]);
187
202
  const newOperator = node.operator.slice(0, -1);
188
203
  let rightText;
189
204
 
205
+ // Check for comments that would be duplicated.
206
+ if (sourceCode.commentsExistBetween(firstToken, operatorToken)) {
207
+ return null;
208
+ }
209
+
190
210
  // If this change would modify precedence (e.g. `foo *= bar + 1` => `foo = foo * (bar + 1)`), parenthesize the right side.
191
211
  if (
192
212
  astUtils.getPrecedence(node.right) <= astUtils.getPrecedence({ type: "BinaryExpression", operator: newOperator }) &&
@@ -194,7 +214,17 @@ module.exports = {
194
214
  ) {
195
215
  rightText = `${sourceCode.text.slice(operatorToken.range[1], node.right.range[0])}(${sourceCode.getText(node.right)})`;
196
216
  } else {
197
- rightText = sourceCode.text.slice(operatorToken.range[1], node.range[1]);
217
+ const firstRightToken = sourceCode.getFirstToken(node.right);
218
+ let rightTextPrefix = "";
219
+
220
+ if (
221
+ operatorToken.range[1] === firstRightToken.range[0] &&
222
+ !astUtils.canTokensBeAdjacent(newOperator, firstRightToken)
223
+ ) {
224
+ rightTextPrefix = " "; // foo+=+bar -> foo= foo+ +bar
225
+ }
226
+
227
+ rightText = `${rightTextPrefix}${sourceCode.text.slice(operatorToken.range[1], node.range[1])}`;
198
228
  }
199
229
 
200
230
  return fixer.replaceText(node, `${leftText}= ${leftText}${newOperator}${rightText}`);
@@ -97,7 +97,7 @@ module.exports = {
97
97
 
98
98
  /**
99
99
  * Gets the open brace token from a given node.
100
- * @param {ASTNode} node - A BlockStatement or SwitchStatement node from which to get the open brace.
100
+ * @param {ASTNode} node A BlockStatement or SwitchStatement node from which to get the open brace.
101
101
  * @returns {Token} The token of the open brace.
102
102
  */
103
103
  function getOpenBrace(node) {
@@ -25,7 +25,6 @@ const CJS_IMPORT = /^require\(/u;
25
25
 
26
26
  /**
27
27
  * Creates tester which check if a node starts with specific keyword.
28
- *
29
28
  * @param {string} keyword The keyword to test.
30
29
  * @returns {Object} the created tester.
31
30
  * @private
@@ -39,7 +38,6 @@ function newKeywordTester(keyword) {
39
38
 
40
39
  /**
41
40
  * Creates tester which check if a node starts with specific keyword and spans a single line.
42
- *
43
41
  * @param {string} keyword The keyword to test.
44
42
  * @returns {Object} the created tester.
45
43
  * @private
@@ -54,7 +52,6 @@ function newSinglelineKeywordTester(keyword) {
54
52
 
55
53
  /**
56
54
  * Creates tester which check if a node starts with specific keyword and spans multiple lines.
57
- *
58
55
  * @param {string} keyword The keyword to test.
59
56
  * @returns {Object} the created tester.
60
57
  * @private
@@ -69,7 +66,6 @@ function newMultilineKeywordTester(keyword) {
69
66
 
70
67
  /**
71
68
  * Creates tester which check if a node is specific type.
72
- *
73
69
  * @param {string} type The node type to test.
74
70
  * @returns {Object} the created tester.
75
71
  * @private
@@ -83,7 +79,6 @@ function newNodeTypeTester(type) {
83
79
 
84
80
  /**
85
81
  * Checks the given node is an expression statement of IIFE.
86
- *
87
82
  * @param {ASTNode} node The node to check.
88
83
  * @returns {boolean} `true` if the node is an expression statement of IIFE.
89
84
  * @private
@@ -103,7 +98,6 @@ function isIIFEStatement(node) {
103
98
  /**
104
99
  * Checks whether the given node is a block-like statement.
105
100
  * This checks the last token of the node is the closing brace of a block.
106
- *
107
101
  * @param {SourceCode} sourceCode The source code to get tokens.
108
102
  * @param {ASTNode} node The node to check.
109
103
  * @returns {boolean} `true` if the node is a block-like statement.
@@ -187,7 +181,6 @@ function isDirectivePrologue(node, sourceCode) {
187
181
  *
188
182
  * foo()
189
183
  * ;[1, 2, 3].forEach(bar)
190
- *
191
184
  * @param {SourceCode} sourceCode The source code to get tokens.
192
185
  * @param {ASTNode} node The node to get.
193
186
  * @returns {Token} The actual last token.
@@ -224,7 +217,6 @@ function replacerToRemovePaddingLines(_, trailingSpaces, indentSpaces) {
224
217
  /**
225
218
  * Check and report statements for `any` configuration.
226
219
  * It does nothing.
227
- *
228
220
  * @returns {void}
229
221
  * @private
230
222
  */
@@ -236,7 +228,6 @@ function verifyForAny() {
236
228
  * This autofix removes blank lines between the given 2 statements.
237
229
  * However, if comments exist between 2 blank lines, it does not remove those
238
230
  * blank lines automatically.
239
- *
240
231
  * @param {RuleContext} context The rule context to report.
241
232
  * @param {ASTNode} _ Unused. The previous node to check.
242
233
  * @param {ASTNode} nextNode The next node to check.
@@ -276,7 +267,6 @@ function verifyForNever(context, _, nextNode, paddingLines) {
276
267
  * This autofix inserts a blank line between the given 2 statements.
277
268
  * If the `prevNode` has trailing comments, it inserts a blank line after the
278
269
  * trailing comments.
279
- *
280
270
  * @param {RuleContext} context The rule context to report.
281
271
  * @param {ASTNode} prevNode The previous node to check.
282
272
  * @param {ASTNode} nextNode The next node to check.
@@ -318,7 +308,6 @@ function verifyForAlways(context, prevNode, nextNode, paddingLines) {
318
308
  *
319
309
  * // comment.
320
310
  * bar();
321
- *
322
311
  * @param {Token} token The token to check.
323
312
  * @returns {boolean} `true` if the token is not a trailing comment.
324
313
  * @private
@@ -511,7 +500,6 @@ module.exports = {
511
500
 
512
501
  /**
513
502
  * Checks whether the given node matches the given type.
514
- *
515
503
  * @param {ASTNode} node The statement node to check.
516
504
  * @param {string|string[]} type The statement type to check.
517
505
  * @returns {boolean} `true` if the statement node matched the type.
@@ -531,7 +519,6 @@ module.exports = {
531
519
 
532
520
  /**
533
521
  * Finds the last matched configure from configureList.
534
- *
535
522
  * @param {ASTNode} prevNode The previous statement to match.
536
523
  * @param {ASTNode} nextNode The current statement to match.
537
524
  * @returns {Object} The tester of the last matched configure.
@@ -554,7 +541,6 @@ module.exports = {
554
541
  /**
555
542
  * Gets padding line sequences between the given 2 statements.
556
543
  * Comments are separators of the padding line sequences.
557
- *
558
544
  * @param {ASTNode} prevNode The previous statement to count.
559
545
  * @param {ASTNode} nextNode The current statement to count.
560
546
  * @returns {Array<Token[]>} The array of token pairs.
@@ -584,7 +570,6 @@ module.exports = {
584
570
 
585
571
  /**
586
572
  * Verify padding lines between the given node and the previous node.
587
- *
588
573
  * @param {ASTNode} node The node to verify.
589
574
  * @returns {void}
590
575
  * @private
@@ -616,7 +601,6 @@ module.exports = {
616
601
  /**
617
602
  * Verify padding lines between the given node and the previous node.
618
603
  * Then process to enter to new scope.
619
- *
620
604
  * @param {ASTNode} node The node to verify.
621
605
  * @returns {void}
622
606
  * @private
@@ -11,7 +11,7 @@
11
11
 
12
12
  /**
13
13
  * Checks whether or not a given variable is a function name.
14
- * @param {eslint-scope.Variable} variable - A variable to check.
14
+ * @param {eslint-scope.Variable} variable A variable to check.
15
15
  * @returns {boolean} `true` if the variable is a function name.
16
16
  */
17
17
  function isFunctionName(variable) {
@@ -20,9 +20,9 @@ function isFunctionName(variable) {
20
20
 
21
21
  /**
22
22
  * Checks whether or not a given MetaProperty node equals to a given value.
23
- * @param {ASTNode} node - A MetaProperty node to check.
24
- * @param {string} metaName - The name of `MetaProperty.meta`.
25
- * @param {string} propertyName - The name of `MetaProperty.property`.
23
+ * @param {ASTNode} node A MetaProperty node to check.
24
+ * @param {string} metaName The name of `MetaProperty.meta`.
25
+ * @param {string} propertyName The name of `MetaProperty.property`.
26
26
  * @returns {boolean} `true` if the node is the specific value.
27
27
  */
28
28
  function checkMetaProperty(node, metaName, propertyName) {
@@ -31,7 +31,7 @@ function checkMetaProperty(node, metaName, propertyName) {
31
31
 
32
32
  /**
33
33
  * Gets the variable object of `arguments` which is defined implicitly.
34
- * @param {eslint-scope.Scope} scope - A scope to get.
34
+ * @param {eslint-scope.Scope} scope A scope to get.
35
35
  * @returns {eslint-scope.Variable} The found variable object.
36
36
  */
37
37
  function getVariableOfArguments(scope) {
@@ -57,7 +57,7 @@ function getVariableOfArguments(scope) {
57
57
 
58
58
  /**
59
59
  * Checkes whether or not a given node is a callback.
60
- * @param {ASTNode} node - A node to check.
60
+ * @param {ASTNode} node A node to check.
61
61
  * @returns {Object}
62
62
  * {boolean} retv.isCallback - `true` if the node is a callback.
63
63
  * {boolean} retv.isLexicalThis - `true` if the node is with `.bind(this)`.
@@ -17,8 +17,7 @@ const DESTRUCTURING_HOST_TYPE = /^(?:VariableDeclarator|AssignmentExpression)$/u
17
17
 
18
18
  /**
19
19
  * Checks whether a given node is located at `ForStatement.init` or not.
20
- *
21
- * @param {ASTNode} node - A node to check.
20
+ * @param {ASTNode} node A node to check.
22
21
  * @returns {boolean} `true` if the node is located at `ForStatement.init`.
23
22
  */
24
23
  function isInitOfForStatement(node) {
@@ -27,8 +26,7 @@ function isInitOfForStatement(node) {
27
26
 
28
27
  /**
29
28
  * Checks whether a given Identifier node becomes a VariableDeclaration or not.
30
- *
31
- * @param {ASTNode} identifier - An Identifier node to check.
29
+ * @param {ASTNode} identifier An Identifier node to check.
32
30
  * @returns {boolean} `true` if the node can become a VariableDeclaration.
33
31
  */
34
32
  function canBecomeVariableDeclaration(identifier) {
@@ -51,9 +49,8 @@ function canBecomeVariableDeclaration(identifier) {
51
49
  /**
52
50
  * Checks if an property or element is from outer scope or function parameters
53
51
  * in destructing pattern.
54
- *
55
- * @param {string} name - A variable name to be checked.
56
- * @param {eslint-scope.Scope} initScope - A scope to start find.
52
+ * @param {string} name A variable name to be checked.
53
+ * @param {eslint-scope.Scope} initScope A scope to start find.
57
54
  * @returns {boolean} Indicates if the variable is from outer scope or function parameters.
58
55
  */
59
56
  function isOuterVariableInDestructing(name, initScope) {
@@ -76,8 +73,7 @@ function isOuterVariableInDestructing(name, initScope) {
76
73
  * belongs to.
77
74
  * This is used to detect a mix of reassigned and never reassigned in a
78
75
  * destructuring.
79
- *
80
- * @param {eslint-scope.Reference} reference - A reference to get.
76
+ * @param {eslint-scope.Reference} reference A reference to get.
81
77
  * @returns {ASTNode|null} A VariableDeclarator/AssignmentExpression node or
82
78
  * null.
83
79
  */
@@ -162,9 +158,8 @@ function hasMemberExpressionAssignment(node) {
162
158
  * `/*exported foo` directive comment makes such variables. This rule does not
163
159
  * warn such variables because this rule cannot distinguish whether the
164
160
  * exported variables are reassigned or not.
165
- *
166
- * @param {eslint-scope.Variable} variable - A variable to get.
167
- * @param {boolean} ignoreReadBeforeAssign -
161
+ * @param {eslint-scope.Variable} variable A variable to get.
162
+ * @param {boolean} ignoreReadBeforeAssign
168
163
  * The value of `ignoreReadBeforeAssign` option.
169
164
  * @returns {ASTNode|null}
170
165
  * An Identifier node if the variable should change to const.
@@ -262,9 +257,8 @@ function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) {
262
257
  * reference of given variables belongs to.
263
258
  * This is used to detect a mix of reassigned and never reassigned in a
264
259
  * destructuring.
265
- *
266
- * @param {eslint-scope.Variable[]} variables - Variables to group by destructuring.
267
- * @param {boolean} ignoreReadBeforeAssign -
260
+ * @param {eslint-scope.Variable[]} variables Variables to group by destructuring.
261
+ * @param {boolean} ignoreReadBeforeAssign
268
262
  * The value of `ignoreReadBeforeAssign` option.
269
263
  * @returns {Map<ASTNode, ASTNode[]>} Grouped identifier nodes.
270
264
  */
@@ -308,10 +302,9 @@ function groupByDestructuring(variables, ignoreReadBeforeAssign) {
308
302
 
309
303
  /**
310
304
  * Finds the nearest parent of node with a given type.
311
- *
312
- * @param {ASTNode} node The node to search from.
313
- * @param {string} type The type field of the parent node.
314
- * @param {Function} shouldStop – a predicate that returns true if the traversal should stop, and false otherwise.
305
+ * @param {ASTNode} node The node to search from.
306
+ * @param {string} type The type field of the parent node.
307
+ * @param {Function} shouldStop A predicate that returns true if the traversal should stop, and false otherwise.
315
308
  * @returns {ASTNode} The closest ancestor with the specified type; null if no such ancestor exists.
316
309
  */
317
310
  function findUp(node, type, shouldStop) {
@@ -363,7 +356,9 @@ module.exports = {
363
356
  const ignoreReadBeforeAssign = options.ignoreReadBeforeAssign === true;
364
357
  const variables = [];
365
358
  let reportCount = 0;
366
- let name = "";
359
+ let checkedId = null;
360
+ let checkedName = "";
361
+
367
362
 
368
363
  /**
369
364
  * Reports given identifier nodes if all of the nodes should be declared
@@ -374,8 +369,7 @@ module.exports = {
374
369
  * nullable. In simple declaration or assignment cases, the length of
375
370
  * the array is 1. In destructuring cases, the length of the array can
376
371
  * be 2 or more.
377
- *
378
- * @param {(eslint-scope.Reference|null)[]} nodes -
372
+ * @param {(eslint-scope.Reference|null)[]} nodes
379
373
  * References which are grouped by destructuring to report.
380
374
  * @returns {void}
381
375
  */
@@ -395,25 +389,30 @@ module.exports = {
395
389
  /*
396
390
  * First we check the declaration type and then depending on
397
391
  * if the type is a "VariableDeclarator" or its an "ObjectPattern"
398
- * we compare the name from the first identifier, if the names are different
399
- * we assign the new name and reset the count of reportCount and nodeCount in
392
+ * we compare the name and id from the first identifier, if the names are different
393
+ * we assign the new name, id and reset the count of reportCount and nodeCount in
400
394
  * order to check each block for the number of reported errors and base our fix
401
395
  * based on comparing nodes.length and nodesToReport.length.
402
396
  */
403
397
 
404
398
  if (firstDecParent.type === "VariableDeclarator") {
405
399
 
406
- if (firstDecParent.id.name !== name) {
407
- name = firstDecParent.id.name;
400
+ if (firstDecParent.id.name !== checkedName) {
401
+ checkedName = firstDecParent.id.name;
408
402
  reportCount = 0;
409
403
  }
410
404
 
411
405
  if (firstDecParent.id.type === "ObjectPattern") {
412
- if (firstDecParent.init.name !== name) {
413
- name = firstDecParent.init.name;
406
+ if (firstDecParent.init.name !== checkedName) {
407
+ checkedName = firstDecParent.init.name;
414
408
  reportCount = 0;
415
409
  }
416
410
  }
411
+
412
+ if (firstDecParent.id !== checkedId) {
413
+ checkedId = firstDecParent.id;
414
+ reportCount = 0;
415
+ }
417
416
  }
418
417
  }
419
418
  }
@@ -103,6 +103,7 @@ module.exports = {
103
103
  // Helpers
104
104
  //--------------------------------------------------------------------------
105
105
 
106
+ // eslint-disable-next-line jsdoc/require-description
106
107
  /**
107
108
  * @param {string} nodeType "AssignmentExpression" or "VariableDeclarator"
108
109
  * @param {string} destructuringType "array" or "object"
@@ -119,7 +120,6 @@ module.exports = {
119
120
  *
120
121
  * This is used to differentiate array index access from object property
121
122
  * access.
122
- *
123
123
  * @param {ASTNode} node the node to evaluate
124
124
  * @returns {boolean} whether or not the node is an integer
125
125
  */
@@ -129,7 +129,6 @@ module.exports = {
129
129
 
130
130
  /**
131
131
  * Report that the given node should use destructuring
132
- *
133
132
  * @param {ASTNode} reportNode the node to report
134
133
  * @param {string} type the type of destructuring that should have been done
135
134
  * @param {Function|null} fix the fix function or null to pass to context.report
@@ -153,7 +152,6 @@ module.exports = {
153
152
  * Assignment expression is not fixed.
154
153
  * Array destructuring is not fixed.
155
154
  * Renamed property is not fixed.
156
- *
157
155
  * @param {ASTNode} node the the node to evaluate
158
156
  * @returns {boolean} whether or not the node should be fixed
159
157
  */
@@ -168,7 +166,6 @@ module.exports = {
168
166
  * Fix a node into object destructuring.
169
167
  * This function only handles the simplest case of object destructuring,
170
168
  * see {@link shouldFix}.
171
- *
172
169
  * @param {SourceCodeFixer} fixer the fixer object
173
170
  * @param {ASTNode} node the node to be fixed.
174
171
  * @returns {Object} a fix for the node
@@ -189,7 +186,6 @@ module.exports = {
189
186
  *
190
187
  * Pulled out into a separate method so that VariableDeclarators and
191
188
  * AssignmentExpressions can share the same verification logic.
192
- *
193
189
  * @param {ASTNode} leftNode the left-hand side of the assignment
194
190
  * @param {ASTNode} rightNode the right-hand side of the assignment
195
191
  * @param {ASTNode} reportNode the node to report the error on
@@ -231,7 +227,6 @@ module.exports = {
231
227
  /**
232
228
  * Check if a given variable declarator is coming from an property access
233
229
  * that should be using destructuring instead
234
- *
235
230
  * @param {ASTNode} node the variable declarator to check
236
231
  * @returns {void}
237
232
  */
@@ -252,7 +247,6 @@ module.exports = {
252
247
 
253
248
  /**
254
249
  * Run the `prefer-destructuring` check on an AssignmentExpression
255
- *
256
250
  * @param {ASTNode} node the AssignmentExpression node
257
251
  * @returns {void}
258
252
  */
@@ -0,0 +1,189 @@
1
+ /**
2
+ * @fileoverview Rule to disallow Math.pow in favor of the ** operator
3
+ * @author Milos Djermanovic
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("./utils/ast-utils");
13
+ const { CALL, ReferenceTracker } = require("eslint-utils");
14
+
15
+ //------------------------------------------------------------------------------
16
+ // Helpers
17
+ //------------------------------------------------------------------------------
18
+
19
+ const PRECEDENCE_OF_EXPONENTIATION_EXPR = astUtils.getPrecedence({ type: "BinaryExpression", operator: "**" });
20
+
21
+ /**
22
+ * Determines whether the given node needs parens if used as the base in an exponentiation binary expression.
23
+ * @param {ASTNode} base The node to check.
24
+ * @returns {boolean} `true` if the node needs to be parenthesised.
25
+ */
26
+ function doesBaseNeedParens(base) {
27
+ return (
28
+
29
+ // '**' is right-associative, parens are needed when Math.pow(a ** b, c) is converted to (a ** b) ** c
30
+ astUtils.getPrecedence(base) <= PRECEDENCE_OF_EXPONENTIATION_EXPR ||
31
+
32
+ // An unary operator cannot be used immediately before an exponentiation expression
33
+ base.type === "UnaryExpression"
34
+ );
35
+ }
36
+
37
+ /**
38
+ * Determines whether the given node needs parens if used as the exponent in an exponentiation binary expression.
39
+ * @param {ASTNode} exponent The node to check.
40
+ * @returns {boolean} `true` if the node needs to be parenthesised.
41
+ */
42
+ function doesExponentNeedParens(exponent) {
43
+
44
+ // '**' is right-associative, there is no need for parens when Math.pow(a, b ** c) is converted to a ** b ** c
45
+ return astUtils.getPrecedence(exponent) < PRECEDENCE_OF_EXPONENTIATION_EXPR;
46
+ }
47
+
48
+ /**
49
+ * Determines whether an exponentiation binary expression at the place of the given node would need parens.
50
+ * @param {ASTNode} node A node that would be replaced by an exponentiation binary expression.
51
+ * @param {SourceCode} sourceCode A SourceCode object.
52
+ * @returns {boolean} `true` if the expression needs to be parenthesised.
53
+ */
54
+ function doesExponentiationExpressionNeedParens(node, sourceCode) {
55
+ const parent = node.parent;
56
+
57
+ const needsParens = (
58
+ parent.type === "ClassDeclaration" ||
59
+ (
60
+ parent.type.endsWith("Expression") &&
61
+ astUtils.getPrecedence(parent) >= PRECEDENCE_OF_EXPONENTIATION_EXPR &&
62
+ !(parent.type === "BinaryExpression" && parent.operator === "**" && parent.right === node) &&
63
+ !((parent.type === "CallExpression" || parent.type === "NewExpression") && parent.arguments.includes(node)) &&
64
+ !(parent.type === "MemberExpression" && parent.computed && parent.property === node) &&
65
+ !(parent.type === "ArrayExpression")
66
+ )
67
+ );
68
+
69
+ return needsParens && !astUtils.isParenthesised(sourceCode, node);
70
+ }
71
+
72
+ /**
73
+ * Optionally parenthesizes given text.
74
+ * @param {string} text The text to parenthesize.
75
+ * @param {boolean} shouldParenthesize If `true`, the text will be parenthesised.
76
+ * @returns {string} parenthesised or unchanged text.
77
+ */
78
+ function parenthesizeIfShould(text, shouldParenthesize) {
79
+ return shouldParenthesize ? `(${text})` : text;
80
+ }
81
+
82
+ //------------------------------------------------------------------------------
83
+ // Rule Definition
84
+ //------------------------------------------------------------------------------
85
+
86
+ module.exports = {
87
+ meta: {
88
+ type: "suggestion",
89
+
90
+ docs: {
91
+ description: "disallow the use of `Math.pow` in favor of the `**` operator",
92
+ category: "Stylistic Issues",
93
+ recommended: false,
94
+ url: "https://eslint.org/docs/rules/prefer-exponentiation-operator"
95
+ },
96
+
97
+ schema: [],
98
+ fixable: "code",
99
+
100
+ messages: {
101
+ useExponentiation: "Use the '**' operator instead of 'Math.pow'."
102
+ }
103
+ },
104
+
105
+ create(context) {
106
+ const sourceCode = context.getSourceCode();
107
+
108
+ /**
109
+ * Reports the given node.
110
+ * @param {ASTNode} node 'Math.pow()' node to report.
111
+ * @returns {void}
112
+ */
113
+ function report(node) {
114
+ context.report({
115
+ node,
116
+ messageId: "useExponentiation",
117
+ fix(fixer) {
118
+ if (
119
+ node.arguments.length !== 2 ||
120
+ node.arguments.some(arg => arg.type === "SpreadElement") ||
121
+ sourceCode.getCommentsInside(node).length > 0
122
+ ) {
123
+ return null;
124
+ }
125
+
126
+ const base = node.arguments[0],
127
+ exponent = node.arguments[1],
128
+ baseText = sourceCode.getText(base),
129
+ exponentText = sourceCode.getText(exponent),
130
+ shouldParenthesizeBase = doesBaseNeedParens(base),
131
+ shouldParenthesizeExponent = doesExponentNeedParens(exponent),
132
+ shouldParenthesizeAll = doesExponentiationExpressionNeedParens(node, sourceCode);
133
+
134
+ let prefix = "",
135
+ suffix = "";
136
+
137
+ if (!shouldParenthesizeAll) {
138
+ if (!shouldParenthesizeBase) {
139
+ const firstReplacementToken = sourceCode.getFirstToken(base),
140
+ tokenBefore = sourceCode.getTokenBefore(node);
141
+
142
+ if (
143
+ tokenBefore &&
144
+ tokenBefore.range[1] === node.range[0] &&
145
+ !astUtils.canTokensBeAdjacent(tokenBefore, firstReplacementToken)
146
+ ) {
147
+ prefix = " "; // a+Math.pow(++b, c) -> a+ ++b**c
148
+ }
149
+ }
150
+ if (!shouldParenthesizeExponent) {
151
+ const lastReplacementToken = sourceCode.getLastToken(exponent),
152
+ tokenAfter = sourceCode.getTokenAfter(node);
153
+
154
+ if (
155
+ tokenAfter &&
156
+ node.range[1] === tokenAfter.range[0] &&
157
+ !astUtils.canTokensBeAdjacent(lastReplacementToken, tokenAfter)
158
+ ) {
159
+ suffix = " "; // Math.pow(a, b)in c -> a**b in c
160
+ }
161
+ }
162
+ }
163
+
164
+ const baseReplacement = parenthesizeIfShould(baseText, shouldParenthesizeBase),
165
+ exponentReplacement = parenthesizeIfShould(exponentText, shouldParenthesizeExponent),
166
+ replacement = parenthesizeIfShould(`${baseReplacement}**${exponentReplacement}`, shouldParenthesizeAll);
167
+
168
+ return fixer.replaceText(node, `${prefix}${replacement}${suffix}`);
169
+ }
170
+ });
171
+ }
172
+
173
+ return {
174
+ Program() {
175
+ const scope = context.getScope();
176
+ const tracker = new ReferenceTracker(scope);
177
+ const trackMap = {
178
+ Math: {
179
+ pow: { [CALL]: true }
180
+ }
181
+ };
182
+
183
+ for (const { node } of tracker.iterateGlobalReferences(trackMap)) {
184
+ report(node);
185
+ }
186
+ }
187
+ };
188
+ }
189
+ };
@@ -49,7 +49,6 @@ module.exports = {
49
49
 
50
50
  /**
51
51
  * Function to check regular expression.
52
- *
53
52
  * @param {string} pattern The regular expression pattern to be check.
54
53
  * @param {ASTNode} node AST node which contains regular expression.
55
54
  * @param {boolean} uFlag Flag indicates whether unicode mode is enabled or not.