eslint 8.13.0 → 8.17.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 (63) hide show
  1. package/README.md +17 -12
  2. package/bin/eslint.js +1 -1
  3. package/lib/cli-engine/cli-engine.js +2 -4
  4. package/lib/cli-engine/lint-result-cache.js +1 -1
  5. package/lib/eslint/eslint.js +3 -3
  6. package/lib/linter/code-path-analysis/code-path-segment.js +1 -1
  7. package/lib/linter/code-path-analysis/code-path-state.js +1 -1
  8. package/lib/linter/code-path-analysis/code-path.js +1 -1
  9. package/lib/rules/accessor-pairs.js +4 -4
  10. package/lib/rules/callback-return.js +2 -2
  11. package/lib/rules/capitalized-comments.js +1 -1
  12. package/lib/rules/consistent-this.js +1 -1
  13. package/lib/rules/dot-notation.js +2 -2
  14. package/lib/rules/function-paren-newline.js +8 -5
  15. package/lib/rules/global-require.js +3 -3
  16. package/lib/rules/indent-legacy.js +2 -2
  17. package/lib/rules/indent.js +45 -13
  18. package/lib/rules/index.js +1 -0
  19. package/lib/rules/jsx-quotes.js +1 -1
  20. package/lib/rules/lines-around-comment.js +3 -3
  21. package/lib/rules/max-lines.js +2 -2
  22. package/lib/rules/max-statements.js +1 -1
  23. package/lib/rules/newline-before-return.js +1 -1
  24. package/lib/rules/no-bitwise.js +2 -2
  25. package/lib/rules/no-console.js +1 -1
  26. package/lib/rules/no-constant-binary-expression.js +500 -0
  27. package/lib/rules/no-constant-condition.js +4 -197
  28. package/lib/rules/no-control-regex.js +23 -10
  29. package/lib/rules/no-empty-function.js +1 -1
  30. package/lib/rules/no-extra-boolean-cast.js +3 -3
  31. package/lib/rules/no-extra-semi.js +1 -1
  32. package/lib/rules/no-global-assign.js +1 -1
  33. package/lib/rules/no-implicit-coercion.js +8 -8
  34. package/lib/rules/no-loop-func.js +1 -1
  35. package/lib/rules/no-magic-numbers.js +3 -3
  36. package/lib/rules/no-misleading-character-class.js +90 -17
  37. package/lib/rules/no-mixed-operators.js +1 -1
  38. package/lib/rules/no-mixed-requires.js +1 -1
  39. package/lib/rules/no-multi-spaces.js +1 -1
  40. package/lib/rules/no-native-reassign.js +1 -1
  41. package/lib/rules/no-new-object.js +1 -1
  42. package/lib/rules/no-new-wrappers.js +1 -1
  43. package/lib/rules/no-octal.js +2 -2
  44. package/lib/rules/no-prototype-builtins.js +3 -3
  45. package/lib/rules/no-shadow.js +5 -5
  46. package/lib/rules/no-sparse-arrays.js +1 -1
  47. package/lib/rules/no-underscore-dangle.js +31 -2
  48. package/lib/rules/no-unused-expressions.js +1 -1
  49. package/lib/rules/no-unused-vars.js +1 -1
  50. package/lib/rules/no-use-before-define.js +15 -2
  51. package/lib/rules/operator-assignment.js +2 -2
  52. package/lib/rules/prefer-const.js +1 -1
  53. package/lib/rules/prefer-reflect.js +2 -2
  54. package/lib/rules/prefer-regex-literals.js +3 -3
  55. package/lib/rules/quote-props.js +2 -2
  56. package/lib/rules/quotes.js +1 -1
  57. package/lib/rules/spaced-comment.js +1 -1
  58. package/lib/rules/utils/ast-utils.js +203 -7
  59. package/lib/rules/valid-jsdoc.js +1 -1
  60. package/lib/rules/valid-typeof.js +4 -4
  61. package/lib/rules/yoda.js +1 -1
  62. package/lib/shared/types.js +1 -1
  63. package/package.json +25 -8
package/README.md CHANGED
@@ -235,15 +235,15 @@ Milos Djermanovic
235
235
  The people who review and implement new features.
236
236
 
237
237
  <table><tbody><tr><td align="center" valign="top" width="11%">
238
- <a href="https://github.com/mysticatea">
239
- <img src="https://github.com/mysticatea.png?s=75" width="75" height="75"><br />
240
- Toru Nagashima
241
- </a>
242
- </td><td align="center" valign="top" width="11%">
243
238
  <a href="https://github.com/aladdin-add">
244
239
  <img src="https://github.com/aladdin-add.png?s=75" width="75" height="75"><br />
245
240
  唯然
246
241
  </a>
242
+ </td><td align="center" valign="top" width="11%">
243
+ <a href="https://github.com/snitin315">
244
+ <img src="https://github.com/snitin315.png?s=75" width="75" height="75"><br />
245
+ Nitin Kumar
246
+ </a>
247
247
  </td></tr></tbody></table>
248
248
 
249
249
  ### Committers
@@ -261,6 +261,16 @@ Brett Zamir
261
261
  Bryan Mishkin
262
262
  </a>
263
263
  </td><td align="center" valign="top" width="11%">
264
+ <a href="https://github.com/mysticatea">
265
+ <img src="https://github.com/mysticatea.png?s=75" width="75" height="75"><br />
266
+ Toru Nagashima
267
+ </a>
268
+ </td><td align="center" valign="top" width="11%">
269
+ <a href="https://github.com/SaraSoueidan">
270
+ <img src="https://github.com/SaraSoueidan.png?s=75" width="75" height="75"><br />
271
+ Sara Soueidan
272
+ </a>
273
+ </td><td align="center" valign="top" width="11%">
264
274
  <a href="https://github.com/g-plane">
265
275
  <img src="https://github.com/g-plane.png?s=75" width="75" height="75"><br />
266
276
  Pig Fang
@@ -275,11 +285,6 @@ Anix
275
285
  <img src="https://github.com/yeonjuan.png?s=75" width="75" height="75"><br />
276
286
  YeonJuan
277
287
  </a>
278
- </td><td align="center" valign="top" width="11%">
279
- <a href="https://github.com/snitin315">
280
- <img src="https://github.com/snitin315.png?s=75" width="75" height="75"><br />
281
- Nitin Kumar
282
- </a>
283
288
  </td></tr></tbody></table>
284
289
 
285
290
  <!--teamend-->
@@ -292,9 +297,9 @@ The following companies, organizations, and individuals support ESLint's ongoing
292
297
  <!--sponsorsstart-->
293
298
  <h3>Platinum Sponsors</h3>
294
299
  <p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
295
- <p><a href="https://contra.com"><img src="https://images.opencollective.com/contra1/c70f93f/logo.png" alt="Contra" height="96"></a> <a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
300
+ <p><a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
296
301
  <p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
297
- <p><a href="https://launchdarkly.com"><img src="https://images.opencollective.com/launchdarkly/574bb9e/logo.png" alt="launchdarkly" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a></p>
302
+ <p><a href="https://launchdarkly.com"><img src="https://images.opencollective.com/launchdarkly/574bb9e/logo.png" alt="launchdarkly" height="32"></a> <a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a></p>
298
303
  <!--sponsorsend-->
299
304
 
300
305
  ## <a name="technology-sponsors"></a>Technology Sponsors
package/bin/eslint.js CHANGED
@@ -69,7 +69,7 @@ function getErrorMessage(error) {
69
69
  // Lazy loading because this is used only if an error happened.
70
70
  const util = require("util");
71
71
 
72
- // Foolproof -- thirdparty module might throw non-object.
72
+ // Foolproof -- third-party module might throw non-object.
73
73
  if (typeof error !== "object" || error === null) {
74
74
  return String(error);
75
75
  }
@@ -366,9 +366,7 @@ function *iterateRuleDeprecationWarnings(usedConfigArrays) {
366
366
 
367
367
  // Flatten used configs.
368
368
  /** @type {ExtractedConfig[]} */
369
- const configs = [].concat(
370
- ...usedConfigArrays.map(getUsedExtractedConfigs)
371
- );
369
+ const configs = usedConfigArrays.flatMap(getUsedExtractedConfigs);
372
370
 
373
371
  // Traverse rule configs.
374
372
  for (const config of configs) {
@@ -1023,7 +1021,7 @@ class CLIEngine {
1023
1021
  let formatterPath;
1024
1022
 
1025
1023
  // if there's a slash, then it's a file (TODO: this check seems dubious for scoped npm packages)
1026
- if (!namespace && normalizedFormatName.indexOf("/") > -1) {
1024
+ if (!namespace && normalizedFormatName.includes("/")) {
1027
1025
  formatterPath = path.resolve(cwd, normalizedFormatName);
1028
1026
  } else {
1029
1027
  try {
@@ -36,7 +36,7 @@ const invalidCacheStrategyErrorMessage = `Cache strategy must be one of: ${valid
36
36
  */
37
37
  function isValidCacheStrategy(cacheStrategy) {
38
38
  return (
39
- validCacheStrategies.indexOf(cacheStrategy) !== -1
39
+ validCacheStrategies.includes(cacheStrategy)
40
40
  );
41
41
  }
42
42
 
@@ -104,9 +104,9 @@ function isNonEmptyString(x) {
104
104
  }
105
105
 
106
106
  /**
107
- * Check if a given value is an array of non-empty stringss or not.
107
+ * Check if a given value is an array of non-empty strings or not.
108
108
  * @param {any} x The value to check.
109
- * @returns {boolean} `true` if `x` is an array of non-empty stringss.
109
+ * @returns {boolean} `true` if `x` is an array of non-empty strings.
110
110
  */
111
111
  function isArrayOfNonEmptyString(x) {
112
112
  return Array.isArray(x) && x.every(isNonEmptyString);
@@ -599,7 +599,7 @@ class ESLint {
599
599
  * The following values are allowed:
600
600
  * - `undefined` ... Load `stylish` builtin formatter.
601
601
  * - A builtin formatter name ... Load the builtin formatter.
602
- * - A thirdparty formatter name:
602
+ * - A third-party formatter name:
603
603
  * - `foo` → `eslint-formatter-foo`
604
604
  * - `@foo` → `@foo/eslint-formatter`
605
605
  * - `@foo/bar` → `@foo/eslint-formatter-bar`
@@ -100,7 +100,7 @@ class CodePathSegment {
100
100
  * @returns {boolean} `true` if the segment is coming from the end of a loop.
101
101
  */
102
102
  isLoopedPrevSegment(segment) {
103
- return this.internal.loopedPrevSegments.indexOf(segment) !== -1;
103
+ return this.internal.loopedPrevSegments.includes(segment);
104
104
  }
105
105
 
106
106
  /**
@@ -33,7 +33,7 @@ function addToReturnedOrThrown(dest, others, all, segments) {
33
33
  const segment = segments[i];
34
34
 
35
35
  dest.push(segment);
36
- if (others.indexOf(segment) === -1) {
36
+ if (!others.includes(segment)) {
37
37
  all.push(segment);
38
38
  }
39
39
  }
@@ -212,7 +212,7 @@ class CodePath {
212
212
  }
213
213
 
214
214
  // Reset the flag of skipping if all branches have been skipped.
215
- if (skippedSegment && segment.prevSegments.indexOf(skippedSegment) !== -1) {
215
+ if (skippedSegment && segment.prevSegments.includes(skippedSegment)) {
216
216
  skippedSegment = null;
217
217
  }
218
218
  visited[segment.id] = true;
@@ -299,12 +299,12 @@ module.exports = {
299
299
  * @private
300
300
  */
301
301
  function checkPropertyDescriptor(node) {
302
- const namesToCheck = node.properties
302
+ const namesToCheck = new Set(node.properties
303
303
  .filter(p => p.type === "Property" && p.kind === "init" && !p.computed)
304
- .map(({ key }) => key.name);
304
+ .map(({ key }) => key.name));
305
305
 
306
- const hasGetter = namesToCheck.includes("get");
307
- const hasSetter = namesToCheck.includes("set");
306
+ const hasGetter = namesToCheck.has("get");
307
+ const hasSetter = namesToCheck.has("set");
308
308
 
309
309
  if (checkSetWithoutGet && hasSetter && !hasGetter) {
310
310
  report(node, "missingGetter");
@@ -53,7 +53,7 @@ module.exports = {
53
53
  if (!node.parent) {
54
54
  return null;
55
55
  }
56
- if (types.indexOf(node.parent.type) === -1) {
56
+ if (!types.includes(node.parent.type)) {
57
57
  return findClosestParentOfType(node.parent, types);
58
58
  }
59
59
  return node.parent;
@@ -87,7 +87,7 @@ module.exports = {
87
87
  * @returns {boolean} Whether or not this function matches our callback name.
88
88
  */
89
89
  function isCallback(node) {
90
- return containsOnlyIdentifiers(node.callee) && callbacks.indexOf(sourceCode.getText(node.callee)) > -1;
90
+ return containsOnlyIdentifiers(node.callee) && callbacks.includes(sourceCode.getText(node.callee));
91
91
  }
92
92
 
93
93
  /**
@@ -185,7 +185,7 @@ module.exports = {
185
185
 
186
186
  return Boolean(
187
187
  previousTokenOrComment &&
188
- ["Block", "Line"].indexOf(previousTokenOrComment.type) !== -1
188
+ ["Block", "Line"].includes(previousTokenOrComment.type)
189
189
  );
190
190
  }
191
191
 
@@ -65,7 +65,7 @@ module.exports = {
65
65
  function checkAssignment(node, name, value) {
66
66
  const isThis = value.type === "ThisExpression";
67
67
 
68
- if (aliases.indexOf(name) !== -1) {
68
+ if (aliases.includes(name)) {
69
69
  if (!isThis || node.operator && node.operator !== "=") {
70
70
  reportBadAssignment(node, name);
71
71
  }
@@ -76,7 +76,7 @@ module.exports = {
76
76
  function checkComputedProperty(node, value) {
77
77
  if (
78
78
  validIdentifier.test(value) &&
79
- (allowKeywords || keywords.indexOf(String(value)) === -1) &&
79
+ (allowKeywords || !keywords.includes(String(value))) &&
80
80
  !(allowPattern && allowPattern.test(value))
81
81
  ) {
82
82
  const formattedValue = node.property.type === "Literal" ? JSON.stringify(value) : `\`${value}\``;
@@ -142,7 +142,7 @@ module.exports = {
142
142
  !allowKeywords &&
143
143
  !node.computed &&
144
144
  node.property.type === "Identifier" &&
145
- keywords.indexOf(String(node.property.name)) !== -1
145
+ keywords.includes(String(node.property.name))
146
146
  ) {
147
147
  context.report({
148
148
  node: node.property,
@@ -183,7 +183,7 @@ module.exports = {
183
183
  /**
184
184
  * Gets the left paren and right paren tokens of a node.
185
185
  * @param {ASTNode} node The node with parens
186
- * @throws {TypeError} Unexecpted node type.
186
+ * @throws {TypeError} Unexpected node type.
187
187
  * @returns {Object} An object with keys `leftParen` for the left paren token, and `rightParen` for the right paren token.
188
188
  * Can also return `null` if an expression has no parens (e.g. a NewExpression with no arguments, or an ArrowFunctionExpression
189
189
  * with a single parameter)
@@ -191,10 +191,13 @@ module.exports = {
191
191
  function getParenTokens(node) {
192
192
  switch (node.type) {
193
193
  case "NewExpression":
194
- if (!node.arguments.length && !(
195
- astUtils.isOpeningParenToken(sourceCode.getLastToken(node, { skip: 1 })) &&
196
- astUtils.isClosingParenToken(sourceCode.getLastToken(node))
197
- )) {
194
+ if (!node.arguments.length &&
195
+ !(
196
+ astUtils.isOpeningParenToken(sourceCode.getLastToken(node, { skip: 1 })) &&
197
+ astUtils.isClosingParenToken(sourceCode.getLastToken(node)) &&
198
+ node.callee.range[1] < node.range[1]
199
+ )
200
+ ) {
198
201
 
199
202
  // If the NewExpression does not have parens (e.g. `new Foo`), return null.
200
203
  return null;
@@ -6,7 +6,7 @@
6
6
 
7
7
  "use strict";
8
8
 
9
- const ACCEPTABLE_PARENTS = [
9
+ const ACCEPTABLE_PARENTS = new Set([
10
10
  "AssignmentExpression",
11
11
  "VariableDeclarator",
12
12
  "MemberExpression",
@@ -16,7 +16,7 @@ const ACCEPTABLE_PARENTS = [
16
16
  "Program",
17
17
  "VariableDeclaration",
18
18
  "ChainExpression"
19
- ];
19
+ ]);
20
20
 
21
21
  /**
22
22
  * Finds the eslint-scope reference in the given scope.
@@ -75,7 +75,7 @@ module.exports = {
75
75
  const currentScope = context.getScope();
76
76
 
77
77
  if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) {
78
- const isGoodRequire = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.indexOf(parent.type) > -1);
78
+ const isGoodRequire = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.has(parent.type));
79
79
 
80
80
  if (!isGoodRequire) {
81
81
  context.report({ node, messageId: "unexpected" });
@@ -753,7 +753,7 @@ module.exports = {
753
753
  if (typeof options.CallExpression.arguments === "number") {
754
754
  nodeIndent += options.CallExpression.arguments * indentSize;
755
755
  } else if (options.CallExpression.arguments === "first") {
756
- if (parent.arguments.indexOf(node) !== -1) {
756
+ if (parent.arguments.includes(node)) {
757
757
  nodeIndent = parent.arguments[0].loc.start.column;
758
758
  }
759
759
  } else {
@@ -840,7 +840,7 @@ module.exports = {
840
840
  "IfStatement", "WhileStatement", "ForStatement", "ForInStatement", "ForOfStatement", "DoWhileStatement", "ClassDeclaration", "TryStatement"
841
841
  ];
842
842
 
843
- if (node.parent && statementsWithProperties.indexOf(node.parent.type) !== -1 && isNodeBodyBlock(node)) {
843
+ if (node.parent && statementsWithProperties.includes(node.parent.type) && isNodeBodyBlock(node)) {
844
844
  indent = getNodeIndent(node.parent).goodChar;
845
845
  } else if (node.parent && node.parent.type === "CatchClause") {
846
846
  indent = getNodeIndent(node.parent.parent).goodChar;
@@ -796,7 +796,7 @@ module.exports = {
796
796
  let statement = node.parent && node.parent.parent;
797
797
 
798
798
  while (
799
- statement.type === "UnaryExpression" && ["!", "~", "+", "-"].indexOf(statement.operator) > -1 ||
799
+ statement.type === "UnaryExpression" && ["!", "~", "+", "-"].includes(statement.operator) ||
800
800
  statement.type === "AssignmentExpression" ||
801
801
  statement.type === "LogicalExpression" ||
802
802
  statement.type === "SequenceExpression" ||
@@ -916,18 +916,6 @@ module.exports = {
916
916
  }
917
917
 
918
918
  offsets.setDesiredOffsets([firstBodyToken.range[0], lastBodyToken.range[1]], lastParentToken, 1);
919
-
920
- /*
921
- * For blockless nodes with semicolon-first style, don't indent the semicolon.
922
- * e.g.
923
- * if (foo) bar()
924
- * ; [1, 2, 3].map(foo)
925
- */
926
- const lastToken = sourceCode.getLastToken(node);
927
-
928
- if (node.type !== "EmptyStatement" && astUtils.isSemicolonToken(lastToken)) {
929
- offsets.setDesiredOffset(lastToken, lastParentToken, 0);
930
- }
931
919
  }
932
920
  }
933
921
 
@@ -1271,6 +1259,50 @@ module.exports = {
1271
1259
  }
1272
1260
  },
1273
1261
 
1262
+ /*
1263
+ * For blockless nodes with semicolon-first style, don't indent the semicolon.
1264
+ * e.g.
1265
+ * if (foo)
1266
+ * bar()
1267
+ * ; [1, 2, 3].map(foo)
1268
+ *
1269
+ * Traversal into the node sets indentation of the semicolon, so we need to override it on exit.
1270
+ */
1271
+ ":matches(DoWhileStatement, ForStatement, ForInStatement, ForOfStatement, IfStatement, WhileStatement):exit"(node) {
1272
+ let nodesToCheck;
1273
+
1274
+ if (node.type === "IfStatement") {
1275
+ nodesToCheck = [node.consequent];
1276
+ if (node.alternate) {
1277
+ nodesToCheck.push(node.alternate);
1278
+ }
1279
+ } else {
1280
+ nodesToCheck = [node.body];
1281
+ }
1282
+
1283
+ for (const nodeToCheck of nodesToCheck) {
1284
+ const lastToken = sourceCode.getLastToken(nodeToCheck);
1285
+
1286
+ if (astUtils.isSemicolonToken(lastToken)) {
1287
+ const tokenBeforeLast = sourceCode.getTokenBefore(lastToken);
1288
+ const tokenAfterLast = sourceCode.getTokenAfter(lastToken);
1289
+
1290
+ // override indentation of `;` only if its line looks like a semicolon-first style line
1291
+ if (
1292
+ !astUtils.isTokenOnSameLine(tokenBeforeLast, lastToken) &&
1293
+ tokenAfterLast &&
1294
+ astUtils.isTokenOnSameLine(lastToken, tokenAfterLast)
1295
+ ) {
1296
+ offsets.setDesiredOffset(
1297
+ lastToken,
1298
+ sourceCode.getFirstToken(node),
1299
+ 0
1300
+ );
1301
+ }
1302
+ }
1303
+ }
1304
+ },
1305
+
1274
1306
  ImportDeclaration(node) {
1275
1307
  if (node.specifiers.some(specifier => specifier.type === "ImportSpecifier")) {
1276
1308
  const openingCurly = sourceCode.getFirstToken(node, astUtils.isOpeningBraceToken);
@@ -103,6 +103,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
103
103
  "no-confusing-arrow": () => require("./no-confusing-arrow"),
104
104
  "no-console": () => require("./no-console"),
105
105
  "no-const-assign": () => require("./no-const-assign"),
106
+ "no-constant-binary-expression": () => require("./no-constant-binary-expression"),
106
107
  "no-constant-condition": () => require("./no-constant-condition"),
107
108
  "no-constructor-return": () => require("./no-constructor-return"),
108
109
  "no-continue": () => require("./no-continue"),
@@ -70,7 +70,7 @@ module.exports = {
70
70
  * @public
71
71
  */
72
72
  function usesExpectedQuotes(node) {
73
- return node.value.indexOf(setting.quote) !== -1 || astUtils.isSurroundedBy(node.raw, setting.quote);
73
+ return node.value.includes(setting.quote) || astUtils.isSurroundedBy(node.raw, setting.quote);
74
74
  }
75
75
 
76
76
  return {
@@ -141,7 +141,7 @@ module.exports = {
141
141
  comments = sourceCode.getAllComments(),
142
142
  commentLines = getCommentLineNums(comments),
143
143
  emptyLines = getEmptyLineNums(lines),
144
- commentAndEmptyLines = commentLines.concat(emptyLines);
144
+ commentAndEmptyLines = new Set(commentLines.concat(emptyLines));
145
145
 
146
146
  /**
147
147
  * Returns whether or not comments are on lines starting with or ending with code
@@ -393,7 +393,7 @@ module.exports = {
393
393
  const nextTokenOrComment = sourceCode.getTokenAfter(token, { includeComments: true });
394
394
 
395
395
  // check for newline before
396
- if (!exceptionStartAllowed && before && !commentAndEmptyLines.includes(prevLineNum) &&
396
+ if (!exceptionStartAllowed && before && !commentAndEmptyLines.has(prevLineNum) &&
397
397
  !(astUtils.isCommentToken(previousTokenOrComment) && astUtils.isTokenOnSameLine(previousTokenOrComment, token))) {
398
398
  const lineStart = token.range[0] - token.loc.start.column;
399
399
  const range = [lineStart, lineStart];
@@ -408,7 +408,7 @@ module.exports = {
408
408
  }
409
409
 
410
410
  // check for newline after
411
- if (!exceptionEndAllowed && after && !commentAndEmptyLines.includes(nextLineNum) &&
411
+ if (!exceptionEndAllowed && after && !commentAndEmptyLines.has(nextLineNum) &&
412
412
  !(astUtils.isCommentToken(nextTokenOrComment) && astUtils.isTokenOnSameLine(token, nextTokenOrComment))) {
413
413
  context.report({
414
414
  node: token,
@@ -159,10 +159,10 @@ module.exports = {
159
159
  if (skipComments) {
160
160
  const comments = sourceCode.getAllComments();
161
161
 
162
- const commentLines = comments.flatMap(getLinesWithoutCode);
162
+ const commentLines = new Set(comments.flatMap(getLinesWithoutCode));
163
163
 
164
164
  lines = lines.filter(
165
- l => !commentLines.includes(l.lineNumber)
165
+ l => !commentLines.has(l.lineNumber)
166
166
  );
167
167
  }
168
168
 
@@ -126,7 +126,7 @@ module.exports = {
126
126
 
127
127
  /*
128
128
  * This rule does not apply to class static blocks, but we have to track them so
129
- * that stataments in them do not count as statements in the enclosing function.
129
+ * that statements in them do not count as statements in the enclosing function.
130
130
  */
131
131
  if (node.type === "StaticBlock") {
132
132
  return;
@@ -47,7 +47,7 @@ module.exports = {
47
47
  function isPrecededByTokens(node, testTokens) {
48
48
  const tokenBefore = sourceCode.getTokenBefore(node);
49
49
 
50
- return testTokens.some(token => tokenBefore.value === token);
50
+ return testTokens.includes(tokenBefore.value);
51
51
  }
52
52
 
53
53
  /**
@@ -76,7 +76,7 @@ module.exports = {
76
76
  * @returns {boolean} Whether or not the node has a bitwise operator.
77
77
  */
78
78
  function hasBitwiseOperator(node) {
79
- return BITWISE_OPERATORS.indexOf(node.operator) !== -1;
79
+ return BITWISE_OPERATORS.includes(node.operator);
80
80
  }
81
81
 
82
82
  /**
@@ -85,7 +85,7 @@ module.exports = {
85
85
  * @returns {boolean} Whether or not the node has a bitwise operator.
86
86
  */
87
87
  function allowedOperator(node) {
88
- return allowed.indexOf(node.operator) !== -1;
88
+ return allowed.includes(node.operator);
89
89
  }
90
90
 
91
91
  /**
@@ -72,7 +72,7 @@ module.exports = {
72
72
  function isAllowed(node) {
73
73
  const propertyName = astUtils.getStaticPropertyName(node);
74
74
 
75
- return propertyName && allowed.indexOf(propertyName) !== -1;
75
+ return propertyName && allowed.includes(propertyName);
76
76
  }
77
77
 
78
78
  /**