eslint 8.57.0 → 9.2.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 (156) hide show
  1. package/README.md +31 -28
  2. package/bin/eslint.js +4 -3
  3. package/conf/ecma-version.js +16 -0
  4. package/conf/globals.js +1 -0
  5. package/conf/rule-type-list.json +3 -1
  6. package/lib/api.js +7 -11
  7. package/lib/cli-engine/cli-engine.js +14 -3
  8. package/lib/cli-engine/formatters/formatters-meta.json +1 -29
  9. package/lib/cli-engine/lint-result-cache.js +2 -2
  10. package/lib/cli.js +115 -36
  11. package/lib/config/default-config.js +3 -0
  12. package/lib/config/flat-config-array.js +110 -24
  13. package/lib/config/flat-config-helpers.js +41 -20
  14. package/lib/config/flat-config-schema.js +1 -7
  15. package/lib/config/rule-validator.js +42 -6
  16. package/lib/eslint/eslint-helpers.js +116 -58
  17. package/lib/eslint/eslint.js +892 -377
  18. package/lib/eslint/index.js +2 -2
  19. package/lib/eslint/legacy-eslint.js +728 -0
  20. package/lib/linter/apply-disable-directives.js +59 -31
  21. package/lib/linter/code-path-analysis/code-path-analyzer.js +0 -1
  22. package/lib/linter/code-path-analysis/code-path.js +32 -30
  23. package/lib/linter/code-path-analysis/fork-context.js +1 -1
  24. package/lib/linter/config-comment-parser.js +8 -11
  25. package/lib/linter/index.js +1 -3
  26. package/lib/linter/interpolate.js +24 -2
  27. package/lib/linter/linter.js +428 -207
  28. package/lib/linter/report-translator.js +3 -3
  29. package/lib/linter/rules.js +6 -15
  30. package/lib/linter/source-code-fixer.js +1 -1
  31. package/lib/linter/timing.js +16 -8
  32. package/lib/options.js +35 -3
  33. package/lib/rule-tester/index.js +3 -1
  34. package/lib/rule-tester/rule-tester.js +424 -347
  35. package/lib/rules/array-bracket-newline.js +1 -1
  36. package/lib/rules/array-bracket-spacing.js +1 -1
  37. package/lib/rules/block-scoped-var.js +1 -1
  38. package/lib/rules/callback-return.js +2 -2
  39. package/lib/rules/camelcase.js +3 -5
  40. package/lib/rules/capitalized-comments.js +10 -7
  41. package/lib/rules/comma-dangle.js +1 -1
  42. package/lib/rules/comma-style.js +2 -2
  43. package/lib/rules/complexity.js +14 -1
  44. package/lib/rules/constructor-super.js +99 -100
  45. package/lib/rules/default-case.js +1 -1
  46. package/lib/rules/eol-last.js +2 -2
  47. package/lib/rules/function-paren-newline.js +2 -2
  48. package/lib/rules/indent-legacy.js +5 -5
  49. package/lib/rules/indent.js +5 -5
  50. package/lib/rules/index.js +1 -2
  51. package/lib/rules/key-spacing.js +2 -2
  52. package/lib/rules/line-comment-position.js +1 -1
  53. package/lib/rules/lines-around-directive.js +2 -2
  54. package/lib/rules/max-depth.js +1 -1
  55. package/lib/rules/max-len.js +3 -3
  56. package/lib/rules/max-lines.js +3 -3
  57. package/lib/rules/max-nested-callbacks.js +1 -1
  58. package/lib/rules/max-params.js +1 -1
  59. package/lib/rules/max-statements.js +1 -1
  60. package/lib/rules/multiline-comment-style.js +7 -7
  61. package/lib/rules/new-cap.js +1 -1
  62. package/lib/rules/newline-after-var.js +1 -1
  63. package/lib/rules/newline-before-return.js +1 -1
  64. package/lib/rules/no-case-declarations.js +13 -1
  65. package/lib/rules/no-constant-binary-expression.js +7 -8
  66. package/lib/rules/no-constant-condition.js +18 -7
  67. package/lib/rules/no-constructor-return.js +2 -2
  68. package/lib/rules/no-dupe-class-members.js +2 -2
  69. package/lib/rules/no-else-return.js +1 -1
  70. package/lib/rules/no-empty-function.js +2 -2
  71. package/lib/rules/no-empty-static-block.js +1 -1
  72. package/lib/rules/no-extend-native.js +1 -2
  73. package/lib/rules/no-extra-semi.js +1 -1
  74. package/lib/rules/no-fallthrough.js +41 -16
  75. package/lib/rules/no-implicit-coercion.js +66 -24
  76. package/lib/rules/no-inner-declarations.js +23 -2
  77. package/lib/rules/no-invalid-regexp.js +1 -1
  78. package/lib/rules/no-invalid-this.js +1 -1
  79. package/lib/rules/no-lone-blocks.js +3 -3
  80. package/lib/rules/no-loss-of-precision.js +1 -1
  81. package/lib/rules/no-misleading-character-class.js +225 -69
  82. package/lib/rules/no-mixed-spaces-and-tabs.js +1 -1
  83. package/lib/rules/no-multiple-empty-lines.js +1 -1
  84. package/lib/rules/no-new-native-nonconstructor.js +1 -1
  85. package/lib/rules/no-new-symbol.js +8 -1
  86. package/lib/rules/no-restricted-globals.js +1 -1
  87. package/lib/rules/no-restricted-imports.js +186 -40
  88. package/lib/rules/no-restricted-modules.js +2 -2
  89. package/lib/rules/no-return-await.js +1 -1
  90. package/lib/rules/no-sequences.js +1 -0
  91. package/lib/rules/no-this-before-super.js +45 -13
  92. package/lib/rules/no-trailing-spaces.js +2 -3
  93. package/lib/rules/no-unneeded-ternary.js +1 -1
  94. package/lib/rules/no-unsafe-optional-chaining.js +1 -1
  95. package/lib/rules/no-unused-private-class-members.js +1 -1
  96. package/lib/rules/no-unused-vars.js +197 -36
  97. package/lib/rules/no-useless-assignment.js +566 -0
  98. package/lib/rules/no-useless-backreference.js +1 -1
  99. package/lib/rules/no-useless-computed-key.js +2 -2
  100. package/lib/rules/no-useless-return.js +7 -2
  101. package/lib/rules/object-curly-spacing.js +3 -3
  102. package/lib/rules/object-property-newline.js +1 -1
  103. package/lib/rules/one-var.js +5 -5
  104. package/lib/rules/padded-blocks.js +7 -7
  105. package/lib/rules/prefer-arrow-callback.js +3 -3
  106. package/lib/rules/prefer-reflect.js +1 -1
  107. package/lib/rules/prefer-regex-literals.js +1 -1
  108. package/lib/rules/prefer-template.js +1 -1
  109. package/lib/rules/radix.js +2 -2
  110. package/lib/rules/semi-style.js +1 -1
  111. package/lib/rules/sort-imports.js +1 -1
  112. package/lib/rules/sort-keys.js +1 -1
  113. package/lib/rules/sort-vars.js +1 -1
  114. package/lib/rules/space-unary-ops.js +1 -1
  115. package/lib/rules/strict.js +1 -1
  116. package/lib/rules/use-isnan.js +101 -7
  117. package/lib/rules/utils/ast-utils.js +16 -7
  118. package/lib/rules/utils/char-source.js +240 -0
  119. package/lib/rules/utils/lazy-loading-rule-map.js +1 -1
  120. package/lib/rules/utils/unicode/index.js +9 -4
  121. package/lib/rules/yield-star-spacing.js +1 -1
  122. package/lib/shared/runtime-info.js +1 -0
  123. package/lib/shared/serialization.js +55 -0
  124. package/lib/shared/stats.js +30 -0
  125. package/lib/shared/string-utils.js +9 -11
  126. package/lib/shared/types.js +35 -1
  127. package/lib/source-code/index.js +3 -1
  128. package/lib/source-code/source-code.js +299 -85
  129. package/lib/source-code/token-store/backward-token-cursor.js +3 -3
  130. package/lib/source-code/token-store/cursors.js +4 -2
  131. package/lib/source-code/token-store/forward-token-comment-cursor.js +3 -3
  132. package/lib/source-code/token-store/forward-token-cursor.js +3 -3
  133. package/lib/source-code/token-store/index.js +2 -2
  134. package/lib/unsupported-api.js +3 -5
  135. package/messages/no-config-found.js +1 -1
  136. package/messages/plugin-conflict.js +1 -1
  137. package/messages/plugin-invalid.js +1 -1
  138. package/messages/plugin-missing.js +1 -1
  139. package/package.json +32 -29
  140. package/conf/config-schema.js +0 -93
  141. package/lib/cli-engine/formatters/checkstyle.js +0 -60
  142. package/lib/cli-engine/formatters/compact.js +0 -60
  143. package/lib/cli-engine/formatters/jslint-xml.js +0 -41
  144. package/lib/cli-engine/formatters/junit.js +0 -82
  145. package/lib/cli-engine/formatters/tap.js +0 -95
  146. package/lib/cli-engine/formatters/unix.js +0 -58
  147. package/lib/cli-engine/formatters/visualstudio.js +0 -63
  148. package/lib/cli-engine/xml-escape.js +0 -34
  149. package/lib/eslint/flat-eslint.js +0 -1155
  150. package/lib/rule-tester/flat-rule-tester.js +0 -1131
  151. package/lib/rules/require-jsdoc.js +0 -122
  152. package/lib/rules/utils/patterns/letters.js +0 -36
  153. package/lib/rules/valid-jsdoc.js +0 -516
  154. package/lib/shared/config-validator.js +0 -347
  155. package/lib/shared/deprecation-warnings.js +0 -58
  156. package/lib/shared/relative-module-resolver.js +0 -50
@@ -74,7 +74,7 @@ module.exports = {
74
74
  function normalizeOptionValue(option) {
75
75
  let consistent = false;
76
76
  let multiline = false;
77
- let minItems = 0;
77
+ let minItems;
78
78
 
79
79
  if (option) {
80
80
  if (option === "consistent") {
@@ -199,7 +199,7 @@ module.exports = {
199
199
  : sourceCode.getLastToken(node),
200
200
  penultimate = sourceCode.getTokenBefore(last),
201
201
  firstElement = node.elements[0],
202
- lastElement = node.elements[node.elements.length - 1];
202
+ lastElement = node.elements.at(-1);
203
203
 
204
204
  const openingBracketMustBeSpaced =
205
205
  options.objectsInArraysException && isObjectType(firstElement) ||
@@ -79,7 +79,7 @@ module.exports = {
79
79
  }
80
80
 
81
81
  // Defines a predicate to check whether or not a given reference is outside of valid scope.
82
- const scopeRange = stack[stack.length - 1];
82
+ const scopeRange = stack.at(-1);
83
83
 
84
84
  /**
85
85
  * Check if a reference is out of scope
@@ -147,7 +147,7 @@ module.exports = {
147
147
  if (closestBlock.type === "BlockStatement") {
148
148
 
149
149
  // find the last item in the block
150
- const lastItem = closestBlock.body[closestBlock.body.length - 1];
150
+ const lastItem = closestBlock.body.at(-1);
151
151
 
152
152
  // if the callback is the last thing in a block that might be ok
153
153
  if (isCallbackExpression(node, lastItem)) {
@@ -168,7 +168,7 @@ module.exports = {
168
168
  if (lastItem.type === "ReturnStatement") {
169
169
 
170
170
  // but only if the callback is immediately before
171
- if (isCallbackExpression(node, closestBlock.body[closestBlock.body.length - 2])) {
171
+ if (isCallbackExpression(node, closestBlock.body.at(-2))) {
172
172
  return;
173
173
  }
174
174
  }
@@ -47,11 +47,9 @@ module.exports = {
47
47
  },
48
48
  allow: {
49
49
  type: "array",
50
- items: [
51
- {
52
- type: "string"
53
- }
54
- ],
50
+ items: {
51
+ type: "string"
52
+ },
55
53
  minItems: 0,
56
54
  uniqueItems: true
57
55
  }
@@ -8,7 +8,6 @@
8
8
  // Requirements
9
9
  //------------------------------------------------------------------------------
10
10
 
11
- const LETTER_PATTERN = require("./utils/patterns/letters");
12
11
  const astUtils = require("./utils/ast-utils");
13
12
 
14
13
  //------------------------------------------------------------------------------
@@ -17,7 +16,8 @@ const astUtils = require("./utils/ast-utils");
17
16
 
18
17
  const DEFAULT_IGNORE_PATTERN = astUtils.COMMENTS_IGNORE_PATTERN,
19
18
  WHITESPACE = /\s/gu,
20
- MAYBE_URL = /^\s*[^:/?#\s]+:\/\/[^?#]/u; // TODO: Combine w/ max-len pattern?
19
+ MAYBE_URL = /^\s*[^:/?#\s]+:\/\/[^?#]/u, // TODO: Combine w/ max-len pattern?
20
+ LETTER_PATTERN = /\p{L}/u;
21
21
 
22
22
  /*
23
23
  * Base schema body for defining the basic capitalization rule, ignorePattern,
@@ -233,7 +233,8 @@ module.exports = {
233
233
  return true;
234
234
  }
235
235
 
236
- const firstWordChar = commentWordCharsOnly[0];
236
+ // Get the first Unicode character (1 or 2 code units).
237
+ const [firstWordChar] = commentWordCharsOnly;
237
238
 
238
239
  if (!LETTER_PATTERN.test(firstWordChar)) {
239
240
  return true;
@@ -273,12 +274,14 @@ module.exports = {
273
274
  messageId,
274
275
  fix(fixer) {
275
276
  const match = comment.value.match(LETTER_PATTERN);
277
+ const char = match[0];
276
278
 
277
- return fixer.replaceTextRange(
279
+ // Offset match.index by 2 to account for the first 2 characters that start the comment (// or /*)
280
+ const charIndex = comment.range[0] + match.index + 2;
278
281
 
279
- // Offset match.index by 2 to account for the first 2 characters that start the comment (// or /*)
280
- [comment.range[0] + match.index + 2, comment.range[0] + match.index + 3],
281
- capitalize === "always" ? match[0].toLocaleUpperCase() : match[0].toLocaleLowerCase()
282
+ return fixer.replaceTextRange(
283
+ [charIndex, charIndex + char.length],
284
+ capitalize === "always" ? char.toLocaleUpperCase() : char.toLocaleLowerCase()
282
285
  );
283
286
  }
284
287
  });
@@ -154,7 +154,7 @@ module.exports = {
154
154
  * @returns {any} The last element
155
155
  */
156
156
  function last(array) {
157
- return array[array.length - 1];
157
+ return array.at(-1);
158
158
  }
159
159
 
160
160
  switch (node.type) {
@@ -66,7 +66,7 @@ module.exports = {
66
66
  NewExpression: true
67
67
  };
68
68
 
69
- if (context.options.length === 2 && Object.prototype.hasOwnProperty.call(context.options[1], "exceptions")) {
69
+ if (context.options.length === 2 && Object.hasOwn(context.options[1], "exceptions")) {
70
70
  const keys = Object.keys(context.options[1].exceptions);
71
71
 
72
72
  for (let i = 0; i < keys.length; i++) {
@@ -218,7 +218,7 @@ module.exports = {
218
218
 
219
219
  previousItemToken = tokenAfterItem
220
220
  ? sourceCode.getTokenBefore(tokenAfterItem)
221
- : sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1];
221
+ : sourceCode.ast.tokens.at(-1);
222
222
  } else {
223
223
  previousItemToken = currentItemToken;
224
224
  }
@@ -64,7 +64,7 @@ module.exports = {
64
64
 
65
65
  if (
66
66
  typeof option === "object" &&
67
- (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
67
+ (Object.hasOwn(option, "maximum") || Object.hasOwn(option, "max"))
68
68
  ) {
69
69
  THRESHOLD = option.maximum || option.max;
70
70
  } else if (typeof option === "number") {
@@ -109,6 +109,7 @@ module.exports = {
109
109
  IfStatement: increaseComplexity,
110
110
  WhileStatement: increaseComplexity,
111
111
  DoWhileStatement: increaseComplexity,
112
+ AssignmentPattern: increaseComplexity,
112
113
 
113
114
  // Avoid `default`
114
115
  "SwitchCase[test]": increaseComplexity,
@@ -120,6 +121,18 @@ module.exports = {
120
121
  }
121
122
  },
122
123
 
124
+ MemberExpression(node) {
125
+ if (node.optional === true) {
126
+ increaseComplexity();
127
+ }
128
+ },
129
+
130
+ CallExpression(node) {
131
+ if (node.optional === true) {
132
+ increaseComplexity();
133
+ }
134
+ },
135
+
123
136
  onCodePathEnd(codePath, node) {
124
137
  const complexity = complexities.pop();
125
138
 
@@ -9,22 +9,6 @@
9
9
  // Helpers
10
10
  //------------------------------------------------------------------------------
11
11
 
12
- /**
13
- * Checks all segments in a set and returns true if any are reachable.
14
- * @param {Set<CodePathSegment>} segments The segments to check.
15
- * @returns {boolean} True if any segment is reachable; false otherwise.
16
- */
17
- function isAnySegmentReachable(segments) {
18
-
19
- for (const segment of segments) {
20
- if (segment.reachable) {
21
- return true;
22
- }
23
- }
24
-
25
- return false;
26
- }
27
-
28
12
  /**
29
13
  * Checks whether or not a given node is a constructor.
30
14
  * @param {ASTNode} node A node to check. This node type is one of
@@ -109,7 +93,7 @@ function isPossibleConstructor(node) {
109
93
  );
110
94
 
111
95
  case "SequenceExpression": {
112
- const lastExpression = node.expressions[node.expressions.length - 1];
96
+ const lastExpression = node.expressions.at(-1);
113
97
 
114
98
  return isPossibleConstructor(lastExpression);
115
99
  }
@@ -119,6 +103,30 @@ function isPossibleConstructor(node) {
119
103
  }
120
104
  }
121
105
 
106
+ /**
107
+ * A class to store information about a code path segment.
108
+ */
109
+ class SegmentInfo {
110
+
111
+ /**
112
+ * Indicates if super() is called in all code paths.
113
+ * @type {boolean}
114
+ */
115
+ calledInEveryPaths = false;
116
+
117
+ /**
118
+ * Indicates if super() is called in any code paths.
119
+ * @type {boolean}
120
+ */
121
+ calledInSomePaths = false;
122
+
123
+ /**
124
+ * The nodes which have been validated and don't need to be reconsidered.
125
+ * @type {ASTNode[]}
126
+ */
127
+ validNodes = [];
128
+ }
129
+
122
130
  //------------------------------------------------------------------------------
123
131
  // Rule Definition
124
132
  //------------------------------------------------------------------------------
@@ -141,8 +149,7 @@ module.exports = {
141
149
  missingAll: "Expected to call 'super()'.",
142
150
 
143
151
  duplicate: "Unexpected duplicate 'super()'.",
144
- badSuper: "Unexpected 'super()' because 'super' is not a constructor.",
145
- unexpected: "Unexpected 'super()'."
152
+ badSuper: "Unexpected 'super()' because 'super' is not a constructor."
146
153
  }
147
154
  },
148
155
 
@@ -159,14 +166,10 @@ module.exports = {
159
166
  */
160
167
  let funcInfo = null;
161
168
 
162
- /*
163
- * {Map<string, {calledInSomePaths: boolean, calledInEveryPaths: boolean}>}
164
- * Information for each code path segment.
165
- * - calledInSomePaths: A flag of be called `super()` in some code paths.
166
- * - calledInEveryPaths: A flag of be called `super()` in all code paths.
167
- * - validNodes:
169
+ /**
170
+ * @type {Record<string, SegmentInfo>}
168
171
  */
169
- let segInfoMap = Object.create(null);
172
+ const segInfoMap = Object.create(null);
170
173
 
171
174
  /**
172
175
  * Gets the flag which shows `super()` is called in some paths.
@@ -177,23 +180,21 @@ module.exports = {
177
180
  return segment.reachable && segInfoMap[segment.id].calledInSomePaths;
178
181
  }
179
182
 
183
+ /**
184
+ * Determines if a segment has been seen in the traversal.
185
+ * @param {CodePathSegment} segment A code path segment to check.
186
+ * @returns {boolean} `true` if the segment has been seen.
187
+ */
188
+ function hasSegmentBeenSeen(segment) {
189
+ return !!segInfoMap[segment.id];
190
+ }
191
+
180
192
  /**
181
193
  * Gets the flag which shows `super()` is called in all paths.
182
194
  * @param {CodePathSegment} segment A code path segment to get.
183
195
  * @returns {boolean} The flag which shows `super()` is called in all paths.
184
196
  */
185
197
  function isCalledInEveryPath(segment) {
186
-
187
- /*
188
- * If specific segment is the looped segment of the current segment,
189
- * skip the segment.
190
- * If not skipped, this never becomes true after a loop.
191
- */
192
- if (segment.nextSegments.length === 1 &&
193
- segment.nextSegments[0].isLoopedPrevSegment(segment)
194
- ) {
195
- return true;
196
- }
197
198
  return segment.reachable && segInfoMap[segment.id].calledInEveryPaths;
198
199
  }
199
200
 
@@ -250,9 +251,9 @@ module.exports = {
250
251
  }
251
252
 
252
253
  // Reports if `super()` lacked.
253
- const segments = codePath.returnedSegments;
254
- const calledInEveryPaths = segments.every(isCalledInEveryPath);
255
- const calledInSomePaths = segments.some(isCalledInSomePath);
254
+ const returnedSegments = codePath.returnedSegments;
255
+ const calledInEveryPaths = returnedSegments.every(isCalledInEveryPath);
256
+ const calledInSomePaths = returnedSegments.some(isCalledInSomePath);
256
257
 
257
258
  if (!calledInEveryPaths) {
258
259
  context.report({
@@ -267,29 +268,37 @@ module.exports = {
267
268
  /**
268
269
  * Initialize information of a given code path segment.
269
270
  * @param {CodePathSegment} segment A code path segment to initialize.
271
+ * @param {CodePathSegment} node Node that starts the segment.
270
272
  * @returns {void}
271
273
  */
272
- onCodePathSegmentStart(segment) {
274
+ onCodePathSegmentStart(segment, node) {
273
275
 
274
276
  funcInfo.currentSegments.add(segment);
275
277
 
276
- if (!(funcInfo && funcInfo.isConstructor && funcInfo.hasExtends)) {
278
+ if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
277
279
  return;
278
280
  }
279
281
 
280
282
  // Initialize info.
281
- const info = segInfoMap[segment.id] = {
282
- calledInSomePaths: false,
283
- calledInEveryPaths: false,
284
- validNodes: []
285
- };
283
+ const info = segInfoMap[segment.id] = new SegmentInfo();
284
+
285
+ const seenPrevSegments = segment.prevSegments.filter(hasSegmentBeenSeen);
286
286
 
287
287
  // When there are previous segments, aggregates these.
288
- const prevSegments = segment.prevSegments;
288
+ if (seenPrevSegments.length > 0) {
289
+ info.calledInSomePaths = seenPrevSegments.some(isCalledInSomePath);
290
+ info.calledInEveryPaths = seenPrevSegments.every(isCalledInEveryPath);
291
+ }
289
292
 
290
- if (prevSegments.length > 0) {
291
- info.calledInSomePaths = prevSegments.some(isCalledInSomePath);
292
- info.calledInEveryPaths = prevSegments.every(isCalledInEveryPath);
293
+ /*
294
+ * ForStatement > *.update segments are a special case as they are created in advance,
295
+ * without seen previous segments. Since they logically don't affect `calledInEveryPaths`
296
+ * calculations, and they can never be a lone previous segment of another one, we'll set
297
+ * their `calledInEveryPaths` to `true` to effectively ignore them in those calculations.
298
+ * .
299
+ */
300
+ if (node.parent && node.parent.type === "ForStatement" && node.parent.update === node) {
301
+ info.calledInEveryPaths = true;
293
302
  }
294
303
  },
295
304
 
@@ -316,25 +325,30 @@ module.exports = {
316
325
  * @returns {void}
317
326
  */
318
327
  onCodePathSegmentLoop(fromSegment, toSegment) {
319
- if (!(funcInfo && funcInfo.isConstructor && funcInfo.hasExtends)) {
328
+ if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
320
329
  return;
321
330
  }
322
331
 
323
- // Update information inside of the loop.
324
- const isRealLoop = toSegment.prevSegments.length >= 2;
325
-
326
332
  funcInfo.codePath.traverseSegments(
327
333
  { first: toSegment, last: fromSegment },
328
- segment => {
334
+ (segment, controller) => {
329
335
  const info = segInfoMap[segment.id];
330
- const prevSegments = segment.prevSegments;
331
336
 
332
- // Updates flags.
333
- info.calledInSomePaths = prevSegments.some(isCalledInSomePath);
334
- info.calledInEveryPaths = prevSegments.every(isCalledInEveryPath);
337
+ // skip segments after the loop
338
+ if (!info) {
339
+ controller.skip();
340
+ return;
341
+ }
342
+
343
+ const seenPrevSegments = segment.prevSegments.filter(hasSegmentBeenSeen);
344
+ const calledInSomePreviousPaths = seenPrevSegments.some(isCalledInSomePath);
345
+ const calledInEveryPreviousPaths = seenPrevSegments.every(isCalledInEveryPath);
346
+
347
+ info.calledInSomePaths ||= calledInSomePreviousPaths;
348
+ info.calledInEveryPaths ||= calledInEveryPreviousPaths;
335
349
 
336
350
  // If flags become true anew, reports the valid nodes.
337
- if (info.calledInSomePaths || isRealLoop) {
351
+ if (calledInSomePreviousPaths) {
338
352
  const nodes = info.validNodes;
339
353
 
340
354
  info.validNodes = [];
@@ -358,7 +372,7 @@ module.exports = {
358
372
  * @returns {void}
359
373
  */
360
374
  "CallExpression:exit"(node) {
361
- if (!(funcInfo && funcInfo.isConstructor)) {
375
+ if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
362
376
  return;
363
377
  }
364
378
 
@@ -368,41 +382,34 @@ module.exports = {
368
382
  }
369
383
 
370
384
  // Reports if needed.
371
- if (funcInfo.hasExtends) {
372
- const segments = funcInfo.currentSegments;
373
- let duplicate = false;
374
- let info = null;
385
+ const segments = funcInfo.currentSegments;
386
+ let duplicate = false;
387
+ let info = null;
375
388
 
376
- for (const segment of segments) {
389
+ for (const segment of segments) {
377
390
 
378
- if (segment.reachable) {
379
- info = segInfoMap[segment.id];
391
+ if (segment.reachable) {
392
+ info = segInfoMap[segment.id];
380
393
 
381
- duplicate = duplicate || info.calledInSomePaths;
382
- info.calledInSomePaths = info.calledInEveryPaths = true;
383
- }
394
+ duplicate = duplicate || info.calledInSomePaths;
395
+ info.calledInSomePaths = info.calledInEveryPaths = true;
384
396
  }
397
+ }
385
398
 
386
- if (info) {
387
- if (duplicate) {
388
- context.report({
389
- messageId: "duplicate",
390
- node
391
- });
392
- } else if (!funcInfo.superIsConstructor) {
393
- context.report({
394
- messageId: "badSuper",
395
- node
396
- });
397
- } else {
398
- info.validNodes.push(node);
399
- }
399
+ if (info) {
400
+ if (duplicate) {
401
+ context.report({
402
+ messageId: "duplicate",
403
+ node
404
+ });
405
+ } else if (!funcInfo.superIsConstructor) {
406
+ context.report({
407
+ messageId: "badSuper",
408
+ node
409
+ });
410
+ } else {
411
+ info.validNodes.push(node);
400
412
  }
401
- } else if (isAnySegmentReachable(funcInfo.currentSegments)) {
402
- context.report({
403
- messageId: "unexpected",
404
- node
405
- });
406
413
  }
407
414
  },
408
415
 
@@ -412,7 +419,7 @@ module.exports = {
412
419
  * @returns {void}
413
420
  */
414
421
  ReturnStatement(node) {
415
- if (!(funcInfo && funcInfo.isConstructor && funcInfo.hasExtends)) {
422
+ if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
416
423
  return;
417
424
  }
418
425
 
@@ -432,14 +439,6 @@ module.exports = {
432
439
  info.calledInSomePaths = info.calledInEveryPaths = true;
433
440
  }
434
441
  }
435
- },
436
-
437
- /**
438
- * Resets state.
439
- * @returns {void}
440
- */
441
- "Program:exit"() {
442
- segInfoMap = Object.create(null);
443
442
  }
444
443
  };
445
444
  }
@@ -54,7 +54,7 @@ module.exports = {
54
54
  * @returns {any} Last element
55
55
  */
56
56
  function last(collection) {
57
- return collection[collection.length - 1];
57
+ return collection.at(-1);
58
58
  }
59
59
 
60
60
  //--------------------------------------------------------------------------
@@ -45,7 +45,7 @@ module.exports = {
45
45
  Program: function checkBadEOF(node) {
46
46
  const sourceCode = context.sourceCode,
47
47
  src = sourceCode.getText(),
48
- lastLine = sourceCode.lines[sourceCode.lines.length - 1],
48
+ lastLine = sourceCode.lines.at(-1),
49
49
  location = {
50
50
  column: lastLine.length,
51
51
  line: sourceCode.lines.length
@@ -89,7 +89,7 @@ module.exports = {
89
89
  });
90
90
  } else if (mode === "never" && endsWithNewline) {
91
91
 
92
- const secondLastLine = sourceCode.lines[sourceCode.lines.length - 2];
92
+ const secondLastLine = sourceCode.lines.at(-2);
93
93
 
94
94
  // File is newline-terminated, but shouldn't be
95
95
  context.report({
@@ -218,7 +218,7 @@ module.exports = {
218
218
  case "FunctionExpression": {
219
219
  const leftParen = sourceCode.getFirstToken(node, astUtils.isOpeningParenToken);
220
220
  const rightParen = node.params.length
221
- ? sourceCode.getTokenAfter(node.params[node.params.length - 1], astUtils.isClosingParenToken)
221
+ ? sourceCode.getTokenAfter(node.params.at(-1), astUtils.isClosingParenToken)
222
222
  : sourceCode.getTokenAfter(leftParen);
223
223
 
224
224
  return { leftParen, rightParen };
@@ -234,7 +234,7 @@ module.exports = {
234
234
  }
235
235
 
236
236
  const rightParen = node.params.length
237
- ? sourceCode.getTokenAfter(node.params[node.params.length - 1], astUtils.isClosingParenToken)
237
+ ? sourceCode.getTokenAfter(node.params.at(-1), astUtils.isClosingParenToken)
238
238
  : sourceCode.getTokenAfter(firstToken);
239
239
 
240
240
  return {
@@ -789,7 +789,7 @@ module.exports = {
789
789
  if (elements.length > 0) {
790
790
 
791
791
  // Skip last block line check if last item in same line
792
- if (elements[elements.length - 1].loc.end.line === node.loc.end.line) {
792
+ if (elements.at(-1).loc.end.line === node.loc.end.line) {
793
793
  return;
794
794
  }
795
795
  }
@@ -830,7 +830,7 @@ module.exports = {
830
830
  }
831
831
 
832
832
  let indent;
833
- let nodesToCheck = [];
833
+ let nodesToCheck;
834
834
 
835
835
  /*
836
836
  * For this statements we should check indent from statement beginning,
@@ -873,7 +873,7 @@ module.exports = {
873
873
  */
874
874
  function filterOutSameLineVars(node) {
875
875
  return node.declarations.reduce((finalCollection, elem) => {
876
- const lastElem = finalCollection[finalCollection.length - 1];
876
+ const lastElem = finalCollection.at(-1);
877
877
 
878
878
  if ((elem.loc.start.line !== node.loc.start.line && !lastElem) ||
879
879
  (lastElem && lastElem.loc.start.line !== elem.loc.start.line)) {
@@ -892,7 +892,7 @@ module.exports = {
892
892
  function checkIndentInVariableDeclarations(node) {
893
893
  const elements = filterOutSameLineVars(node);
894
894
  const nodeIndent = getNodeIndent(node).goodChar;
895
- const lastElement = elements[elements.length - 1];
895
+ const lastElement = elements.at(-1);
896
896
 
897
897
  const elementsIndent = nodeIndent + indentSize * options.VariableDeclarator[node.kind];
898
898
 
@@ -999,7 +999,7 @@ module.exports = {
999
999
  },
1000
1000
 
1001
1001
  VariableDeclaration(node) {
1002
- if (node.declarations[node.declarations.length - 1].loc.start.line > node.declarations[0].loc.start.line) {
1002
+ if (node.declarations.at(-1).loc.start.line > node.declarations[0].loc.start.line) {
1003
1003
  checkIndentInVariableDeclarations(node);
1004
1004
  }
1005
1005
  },
@@ -1077,7 +1077,7 @@ module.exports = {
1077
1077
  "ObjectExpression, ObjectPattern"(node) {
1078
1078
  const openingCurly = sourceCode.getFirstToken(node);
1079
1079
  const closingCurly = sourceCode.getTokenAfter(
1080
- node.properties.length ? node.properties[node.properties.length - 1] : openingCurly,
1080
+ node.properties.length ? node.properties.at(-1) : openingCurly,
1081
1081
  astUtils.isClosingBraceToken
1082
1082
  );
1083
1083
 
@@ -1407,7 +1407,7 @@ module.exports = {
1407
1407
  PropertyDefinition(node) {
1408
1408
  const firstToken = sourceCode.getFirstToken(node);
1409
1409
  const maybeSemicolonToken = sourceCode.getLastToken(node);
1410
- let keyLastToken = null;
1410
+ let keyLastToken;
1411
1411
 
1412
1412
  // Indent key.
1413
1413
  if (node.computed) {
@@ -1458,7 +1458,7 @@ module.exports = {
1458
1458
 
1459
1459
  if (node.cases.length) {
1460
1460
  sourceCode.getTokensBetween(
1461
- node.cases[node.cases.length - 1],
1461
+ node.cases.at(-1),
1462
1462
  closingCurly,
1463
1463
  { includeComments: true, filter: astUtils.isCommentToken }
1464
1464
  ).forEach(token => offsets.ignoreToken(token));
@@ -1488,7 +1488,7 @@ module.exports = {
1488
1488
  },
1489
1489
 
1490
1490
  VariableDeclaration(node) {
1491
- let variableIndent = Object.prototype.hasOwnProperty.call(options.VariableDeclarator, node.kind)
1491
+ let variableIndent = Object.hasOwn(options.VariableDeclarator, node.kind)
1492
1492
  ? options.VariableDeclarator[node.kind]
1493
1493
  : DEFAULT_VARIABLE_INDENT;
1494
1494
 
@@ -1509,7 +1509,7 @@ module.exports = {
1509
1509
  variableIndent = DEFAULT_VARIABLE_INDENT;
1510
1510
  }
1511
1511
 
1512
- if (node.declarations[node.declarations.length - 1].loc.start.line > node.loc.start.line) {
1512
+ if (node.declarations.at(-1).loc.start.line > node.loc.start.line) {
1513
1513
 
1514
1514
  /*
1515
1515
  * VariableDeclarator indentation is a bit different from other forms of indentation, in that the
@@ -229,6 +229,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
229
229
  "no-unused-private-class-members": () => require("./no-unused-private-class-members"),
230
230
  "no-unused-vars": () => require("./no-unused-vars"),
231
231
  "no-use-before-define": () => require("./no-use-before-define"),
232
+ "no-useless-assignment": () => require("./no-useless-assignment"),
232
233
  "no-useless-backreference": () => require("./no-useless-backreference"),
233
234
  "no-useless-call": () => require("./no-useless-call"),
234
235
  "no-useless-catch": () => require("./no-useless-catch"),
@@ -273,7 +274,6 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
273
274
  radix: () => require("./radix"),
274
275
  "require-atomic-updates": () => require("./require-atomic-updates"),
275
276
  "require-await": () => require("./require-await"),
276
- "require-jsdoc": () => require("./require-jsdoc"),
277
277
  "require-unicode-regexp": () => require("./require-unicode-regexp"),
278
278
  "require-yield": () => require("./require-yield"),
279
279
  "rest-spread-spacing": () => require("./rest-spread-spacing"),
@@ -296,7 +296,6 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
296
296
  "template-tag-spacing": () => require("./template-tag-spacing"),
297
297
  "unicode-bom": () => require("./unicode-bom"),
298
298
  "use-isnan": () => require("./use-isnan"),
299
- "valid-jsdoc": () => require("./valid-jsdoc"),
300
299
  "valid-typeof": () => require("./valid-typeof"),
301
300
  "vars-on-top": () => require("./vars-on-top"),
302
301
  "wrap-iife": () => require("./wrap-iife"),