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
@@ -70,7 +70,7 @@ module.exports = {
70
70
  const sourceCode = context.sourceCode;
71
71
 
72
72
  // Swallow the final newline, as some editors add it automatically and we don't want it to cause an issue
73
- const allLines = sourceCode.lines[sourceCode.lines.length - 1] === "" ? sourceCode.lines.slice(0, -1) : sourceCode.lines;
73
+ const allLines = sourceCode.lines.at(-1) === "" ? sourceCode.lines.slice(0, -1) : sourceCode.lines;
74
74
  const templateLiteralLines = new Set();
75
75
 
76
76
  //--------------------------------------------------------------------------
@@ -22,7 +22,7 @@ module.exports = {
22
22
 
23
23
  docs: {
24
24
  description: "Disallow `new` operators with global non-constructor functions",
25
- recommended: false,
25
+ recommended: true,
26
26
  url: "https://eslint.org/docs/latest/rules/no-new-native-nonconstructor"
27
27
  },
28
28
 
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @fileoverview Rule to disallow use of the new operator with the `Symbol` object
3
3
  * @author Alberto Rodríguez
4
+ * @deprecated in ESLint v9.0.0
4
5
  */
5
6
 
6
7
  "use strict";
@@ -16,10 +17,16 @@ module.exports = {
16
17
 
17
18
  docs: {
18
19
  description: "Disallow `new` operators with the `Symbol` object",
19
- recommended: true,
20
+ recommended: false,
20
21
  url: "https://eslint.org/docs/latest/rules/no-new-symbol"
21
22
  },
22
23
 
24
+ deprecated: true,
25
+
26
+ replacedBy: [
27
+ "no-new-native-nonconstructor"
28
+ ],
29
+
23
30
  schema: [],
24
31
 
25
32
  messages: {
@@ -97,7 +97,7 @@ module.exports = {
97
97
  * @private
98
98
  */
99
99
  function isRestricted(name) {
100
- return Object.prototype.hasOwnProperty.call(restrictedGlobalMessages, name);
100
+ return Object.hasOwn(restrictedGlobalMessages, name);
101
101
  }
102
102
 
103
103
  return {
@@ -34,10 +34,17 @@ const arrayOfStringsOrObjects = {
34
34
  items: {
35
35
  type: "string"
36
36
  }
37
+ },
38
+ allowImportNames: {
39
+ type: "array",
40
+ items: {
41
+ type: "string"
42
+ }
37
43
  }
38
44
  },
39
45
  additionalProperties: false,
40
- required: ["name"]
46
+ required: ["name"],
47
+ not: { required: ["importNames", "allowImportNames"] }
41
48
  }
42
49
  ]
43
50
  },
@@ -66,6 +73,14 @@ const arrayOfStringsOrObjectPatterns = {
66
73
  minItems: 1,
67
74
  uniqueItems: true
68
75
  },
76
+ allowImportNames: {
77
+ type: "array",
78
+ items: {
79
+ type: "string"
80
+ },
81
+ minItems: 1,
82
+ uniqueItems: true
83
+ },
69
84
  group: {
70
85
  type: "array",
71
86
  items: {
@@ -77,6 +92,9 @@ const arrayOfStringsOrObjectPatterns = {
77
92
  importNamePattern: {
78
93
  type: "string"
79
94
  },
95
+ allowImportNamePattern: {
96
+ type: "string"
97
+ },
80
98
  message: {
81
99
  type: "string",
82
100
  minLength: 1
@@ -86,7 +104,16 @@ const arrayOfStringsOrObjectPatterns = {
86
104
  }
87
105
  },
88
106
  additionalProperties: false,
89
- required: ["group"]
107
+ required: ["group"],
108
+ not: {
109
+ anyOf: [
110
+ { required: ["importNames", "allowImportNames"] },
111
+ { required: ["importNamePattern", "allowImportNamePattern"] },
112
+ { required: ["importNames", "allowImportNamePattern"] },
113
+ { required: ["importNamePattern", "allowImportNames"] },
114
+ { required: ["allowImportNames", "allowImportNamePattern"] }
115
+ ]
116
+ }
90
117
  },
91
118
  uniqueItems: true
92
119
  }
@@ -131,7 +158,23 @@ module.exports = {
131
158
 
132
159
  importName: "'{{importName}}' import from '{{importSource}}' is restricted.",
133
160
  // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
134
- importNameWithCustomMessage: "'{{importName}}' import from '{{importSource}}' is restricted. {{customMessage}}"
161
+ importNameWithCustomMessage: "'{{importName}}' import from '{{importSource}}' is restricted. {{customMessage}}",
162
+
163
+ allowedImportName: "'{{importName}}' import from '{{importSource}}' is restricted because only '{{allowedImportNames}}' import(s) is/are allowed.",
164
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
165
+ allowedImportNameWithCustomMessage: "'{{importName}}' import from '{{importSource}}' is restricted because only '{{allowedImportNames}}' import(s) is/are allowed. {{customMessage}}",
166
+
167
+ everythingWithAllowImportNames: "* import is invalid because only '{{allowedImportNames}}' from '{{importSource}}' is/are allowed.",
168
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
169
+ everythingWithAllowImportNamesAndCustomMessage: "* import is invalid because only '{{allowedImportNames}}' from '{{importSource}}' is/are allowed. {{customMessage}}",
170
+
171
+ allowedImportNamePattern: "'{{importName}}' import from '{{importSource}}' is restricted because only imports that match the pattern '{{allowedImportNamePattern}}' are allowed from '{{importSource}}'.",
172
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
173
+ allowedImportNamePatternWithCustomMessage: "'{{importName}}' import from '{{importSource}}' is restricted because only imports that match the pattern '{{allowedImportNamePattern}}' are allowed from '{{importSource}}'. {{customMessage}}",
174
+
175
+ everythingWithAllowedImportNamePattern: "* import is invalid because only imports that match the pattern '{{allowedImportNamePattern}}' from '{{importSource}}' are allowed.",
176
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
177
+ everythingWithAllowedImportNamePatternWithCustomMessage: "* import is invalid because only imports that match the pattern '{{allowedImportNamePattern}}' from '{{importSource}}' are allowed. {{customMessage}}"
135
178
  },
136
179
 
137
180
  schema: {
@@ -158,20 +201,29 @@ module.exports = {
158
201
  const options = Array.isArray(context.options) ? context.options : [];
159
202
  const isPathAndPatternsObject =
160
203
  typeof options[0] === "object" &&
161
- (Object.prototype.hasOwnProperty.call(options[0], "paths") || Object.prototype.hasOwnProperty.call(options[0], "patterns"));
204
+ (Object.hasOwn(options[0], "paths") || Object.hasOwn(options[0], "patterns"));
162
205
 
163
206
  const restrictedPaths = (isPathAndPatternsObject ? options[0].paths : context.options) || [];
164
- const restrictedPathMessages = restrictedPaths.reduce((memo, importSource) => {
207
+ const groupedRestrictedPaths = restrictedPaths.reduce((memo, importSource) => {
208
+ const path = typeof importSource === "string"
209
+ ? importSource
210
+ : importSource.name;
211
+
212
+ if (!memo[path]) {
213
+ memo[path] = [];
214
+ }
215
+
165
216
  if (typeof importSource === "string") {
166
- memo[importSource] = { message: null };
217
+ memo[path].push({});
167
218
  } else {
168
- memo[importSource.name] = {
219
+ memo[path].push({
169
220
  message: importSource.message,
170
- importNames: importSource.importNames
171
- };
221
+ importNames: importSource.importNames,
222
+ allowImportNames: importSource.allowImportNames
223
+ });
172
224
  }
173
225
  return memo;
174
- }, {});
226
+ }, Object.create(null));
175
227
 
176
228
  // Handle patterns too, either as strings or groups
177
229
  let restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || [];
@@ -182,12 +234,18 @@ module.exports = {
182
234
  }
183
235
 
184
236
  // relative paths are supported for this rule
185
- const restrictedPatternGroups = restrictedPatterns.map(({ group, message, caseSensitive, importNames, importNamePattern }) => ({
186
- matcher: ignore({ allowRelativePaths: true, ignorecase: !caseSensitive }).add(group),
187
- customMessage: message,
188
- importNames,
189
- importNamePattern
190
- }));
237
+ const restrictedPatternGroups = restrictedPatterns.map(
238
+ ({ group, message, caseSensitive, importNames, importNamePattern, allowImportNames, allowImportNamePattern }) => (
239
+ {
240
+ matcher: ignore({ allowRelativePaths: true, ignorecase: !caseSensitive }).add(group),
241
+ customMessage: message,
242
+ importNames,
243
+ importNamePattern,
244
+ allowImportNames,
245
+ allowImportNamePattern
246
+ }
247
+ )
248
+ );
191
249
 
192
250
  // if no imports are restricted we don't need to check
193
251
  if (Object.keys(restrictedPaths).length === 0 && restrictedPatternGroups.length === 0) {
@@ -203,33 +261,60 @@ module.exports = {
203
261
  * @private
204
262
  */
205
263
  function checkRestrictedPathAndReport(importSource, importNames, node) {
206
- if (!Object.prototype.hasOwnProperty.call(restrictedPathMessages, importSource)) {
264
+ if (!Object.hasOwn(groupedRestrictedPaths, importSource)) {
207
265
  return;
208
266
  }
209
267
 
210
- const customMessage = restrictedPathMessages[importSource].message;
211
- const restrictedImportNames = restrictedPathMessages[importSource].importNames;
212
-
213
- if (restrictedImportNames) {
214
- if (importNames.has("*")) {
215
- const specifierData = importNames.get("*")[0];
268
+ groupedRestrictedPaths[importSource].forEach(restrictedPathEntry => {
269
+ const customMessage = restrictedPathEntry.message;
270
+ const restrictedImportNames = restrictedPathEntry.importNames;
271
+ const allowedImportNames = restrictedPathEntry.allowImportNames;
216
272
 
273
+ if (!restrictedImportNames && !allowedImportNames) {
217
274
  context.report({
218
275
  node,
219
- messageId: customMessage ? "everythingWithCustomMessage" : "everything",
220
- loc: specifierData.loc,
276
+ messageId: customMessage ? "pathWithCustomMessage" : "path",
221
277
  data: {
222
278
  importSource,
223
- importNames: restrictedImportNames,
224
279
  customMessage
225
280
  }
226
281
  });
282
+
283
+ return;
227
284
  }
228
285
 
229
- restrictedImportNames.forEach(importName => {
230
- if (importNames.has(importName)) {
231
- const specifiers = importNames.get(importName);
286
+ importNames.forEach((specifiers, importName) => {
287
+ if (importName === "*") {
288
+ const [specifier] = specifiers;
232
289
 
290
+ if (restrictedImportNames) {
291
+ context.report({
292
+ node,
293
+ messageId: customMessage ? "everythingWithCustomMessage" : "everything",
294
+ loc: specifier.loc,
295
+ data: {
296
+ importSource,
297
+ importNames: restrictedImportNames,
298
+ customMessage
299
+ }
300
+ });
301
+ } else if (allowedImportNames) {
302
+ context.report({
303
+ node,
304
+ messageId: customMessage ? "everythingWithAllowImportNamesAndCustomMessage" : "everythingWithAllowImportNames",
305
+ loc: specifier.loc,
306
+ data: {
307
+ importSource,
308
+ allowedImportNames,
309
+ customMessage
310
+ }
311
+ });
312
+ }
313
+
314
+ return;
315
+ }
316
+
317
+ if (restrictedImportNames && restrictedImportNames.includes(importName)) {
233
318
  specifiers.forEach(specifier => {
234
319
  context.report({
235
320
  node,
@@ -243,17 +328,24 @@ module.exports = {
243
328
  });
244
329
  });
245
330
  }
246
- });
247
- } else {
248
- context.report({
249
- node,
250
- messageId: customMessage ? "pathWithCustomMessage" : "path",
251
- data: {
252
- importSource,
253
- customMessage
331
+
332
+ if (allowedImportNames && !allowedImportNames.includes(importName)) {
333
+ specifiers.forEach(specifier => {
334
+ context.report({
335
+ node,
336
+ loc: specifier.loc,
337
+ messageId: customMessage ? "allowedImportNameWithCustomMessage" : "allowedImportName",
338
+ data: {
339
+ importSource,
340
+ customMessage,
341
+ importName,
342
+ allowedImportNames
343
+ }
344
+ });
345
+ });
254
346
  }
255
347
  });
256
- }
348
+ });
257
349
  }
258
350
 
259
351
  /**
@@ -271,12 +363,14 @@ module.exports = {
271
363
  const customMessage = group.customMessage;
272
364
  const restrictedImportNames = group.importNames;
273
365
  const restrictedImportNamePattern = group.importNamePattern ? new RegExp(group.importNamePattern, "u") : null;
366
+ const allowedImportNames = group.allowImportNames;
367
+ const allowedImportNamePattern = group.allowImportNamePattern ? new RegExp(group.allowImportNamePattern, "u") : null;
274
368
 
275
- /*
369
+ /**
276
370
  * If we are not restricting to any specific import names and just the pattern itself,
277
371
  * report the error and move on
278
372
  */
279
- if (!restrictedImportNames && !restrictedImportNamePattern) {
373
+ if (!restrictedImportNames && !allowedImportNames && !restrictedImportNamePattern && !allowedImportNamePattern) {
280
374
  context.report({
281
375
  node,
282
376
  messageId: customMessage ? "patternWithCustomMessage" : "patterns",
@@ -303,6 +397,28 @@ module.exports = {
303
397
  customMessage
304
398
  }
305
399
  });
400
+ } else if (allowedImportNames) {
401
+ context.report({
402
+ node,
403
+ messageId: customMessage ? "everythingWithAllowImportNamesAndCustomMessage" : "everythingWithAllowImportNames",
404
+ loc: specifier.loc,
405
+ data: {
406
+ importSource,
407
+ allowedImportNames,
408
+ customMessage
409
+ }
410
+ });
411
+ } else if (allowedImportNamePattern) {
412
+ context.report({
413
+ node,
414
+ messageId: customMessage ? "everythingWithAllowedImportNamePatternWithCustomMessage" : "everythingWithAllowedImportNamePattern",
415
+ loc: specifier.loc,
416
+ data: {
417
+ importSource,
418
+ allowedImportNamePattern,
419
+ customMessage
420
+ }
421
+ });
306
422
  } else {
307
423
  context.report({
308
424
  node,
@@ -336,6 +452,36 @@ module.exports = {
336
452
  });
337
453
  });
338
454
  }
455
+
456
+ if (allowedImportNames && !allowedImportNames.includes(importName)) {
457
+ specifiers.forEach(specifier => {
458
+ context.report({
459
+ node,
460
+ messageId: customMessage ? "allowedImportNameWithCustomMessage" : "allowedImportName",
461
+ loc: specifier.loc,
462
+ data: {
463
+ importSource,
464
+ customMessage,
465
+ importName,
466
+ allowedImportNames
467
+ }
468
+ });
469
+ });
470
+ } else if (allowedImportNamePattern && !allowedImportNamePattern.test(importName)) {
471
+ specifiers.forEach(specifier => {
472
+ context.report({
473
+ node,
474
+ messageId: customMessage ? "allowedImportNamePatternWithCustomMessage" : "allowedImportNamePattern",
475
+ loc: specifier.loc,
476
+ data: {
477
+ importSource,
478
+ customMessage,
479
+ importName,
480
+ allowedImportNamePattern
481
+ }
482
+ });
483
+ });
484
+ }
339
485
  });
340
486
  }
341
487
 
@@ -90,7 +90,7 @@ module.exports = {
90
90
  const options = Array.isArray(context.options) ? context.options : [];
91
91
  const isPathAndPatternsObject =
92
92
  typeof options[0] === "object" &&
93
- (Object.prototype.hasOwnProperty.call(options[0], "paths") || Object.prototype.hasOwnProperty.call(options[0], "patterns"));
93
+ (Object.hasOwn(options[0], "paths") || Object.hasOwn(options[0], "patterns"));
94
94
 
95
95
  const restrictedPaths = (isPathAndPatternsObject ? options[0].paths : context.options) || [];
96
96
  const restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || [];
@@ -178,7 +178,7 @@ module.exports = {
178
178
  * @private
179
179
  */
180
180
  function isRestrictedPath(name) {
181
- return Object.prototype.hasOwnProperty.call(restrictedPathMessages, name);
181
+ return Object.hasOwn(restrictedPathMessages, name);
182
182
  }
183
183
 
184
184
  return {
@@ -118,7 +118,7 @@ module.exports = {
118
118
  if (node.parent.type === "LogicalExpression" && node === node.parent.right) {
119
119
  return isInTailCallPosition(node.parent);
120
120
  }
121
- if (node.parent.type === "SequenceExpression" && node === node.parent.expressions[node.parent.expressions.length - 1]) {
121
+ if (node.parent.type === "SequenceExpression" && node === node.parent.expressions.at(-1)) {
122
122
  return isInTailCallPosition(node.parent);
123
123
  }
124
124
  return false;
@@ -35,6 +35,7 @@ module.exports = {
35
35
  },
36
36
 
37
37
  schema: [{
38
+ type: "object",
38
39
  properties: {
39
40
  allowInParentheses: {
40
41
  type: "boolean",
@@ -30,6 +30,29 @@ function isConstructorFunction(node) {
30
30
  );
31
31
  }
32
32
 
33
+ /*
34
+ * Information for each code path segment.
35
+ * - superCalled: The flag which shows `super()` called in all code paths.
36
+ * - invalidNodes: The array of invalid ThisExpression and Super nodes.
37
+ */
38
+ /**
39
+ *
40
+ */
41
+ class SegmentInfo {
42
+
43
+ /**
44
+ * Indicates whether `super()` is called in all code paths.
45
+ * @type {boolean}
46
+ */
47
+ superCalled = false;
48
+
49
+ /**
50
+ * The array of invalid ThisExpression and Super nodes.
51
+ * @type {ASTNode[]}
52
+ */
53
+ invalidNodes = [];
54
+ }
55
+
33
56
  //------------------------------------------------------------------------------
34
57
  // Rule Definition
35
58
  //------------------------------------------------------------------------------
@@ -64,13 +87,7 @@ module.exports = {
64
87
  */
65
88
  let funcInfo = null;
66
89
 
67
- /*
68
- * Information for each code path segment.
69
- * Each key is the id of a code path segment.
70
- * Each value is an object:
71
- * - superCalled: The flag which shows `super()` called in all code paths.
72
- * - invalidNodes: The array of invalid ThisExpression and Super nodes.
73
- */
90
+ /** @type {Record<string, SegmentInfo>} */
74
91
  let segInfoMap = Object.create(null);
75
92
 
76
93
  /**
@@ -79,7 +96,7 @@ module.exports = {
79
96
  * @returns {boolean} `true` if `super()` is called.
80
97
  */
81
98
  function isCalled(segment) {
82
- return !segment.reachable || segInfoMap[segment.id].superCalled;
99
+ return !segment.reachable || segInfoMap[segment.id]?.superCalled;
83
100
  }
84
101
 
85
102
  /**
@@ -197,11 +214,26 @@ module.exports = {
197
214
  return;
198
215
  }
199
216
 
217
+ /**
218
+ * A collection of nodes to avoid duplicate reports.
219
+ * @type {Set<ASTNode>}
220
+ */
221
+ const reported = new Set();
222
+
200
223
  codePath.traverseSegments((segment, controller) => {
201
224
  const info = segInfoMap[segment.id];
225
+ const invalidNodes = info.invalidNodes
226
+ .filter(
202
227
 
203
- for (let i = 0; i < info.invalidNodes.length; ++i) {
204
- const invalidNode = info.invalidNodes[i];
228
+ /*
229
+ * Avoid duplicate reports.
230
+ * When there is a `finally`, invalidNodes may contain already reported node.
231
+ */
232
+ node => !reported.has(node)
233
+ );
234
+
235
+ for (const invalidNode of invalidNodes) {
236
+ reported.add(invalidNode);
205
237
 
206
238
  context.report({
207
239
  messageId: "noBeforeSuper",
@@ -270,18 +302,18 @@ module.exports = {
270
302
  funcInfo.codePath.traverseSegments(
271
303
  { first: toSegment, last: fromSegment },
272
304
  (segment, controller) => {
273
- const info = segInfoMap[segment.id];
305
+ const info = segInfoMap[segment.id] ?? new SegmentInfo();
274
306
 
275
307
  if (info.superCalled) {
276
- info.invalidNodes = [];
277
308
  controller.skip();
278
309
  } else if (
279
310
  segment.prevSegments.length > 0 &&
280
311
  segment.prevSegments.every(isCalled)
281
312
  ) {
282
313
  info.superCalled = true;
283
- info.invalidNodes = [];
284
314
  }
315
+
316
+ segInfoMap[segment.id] = info;
285
317
  }
286
318
  );
287
319
  },
@@ -129,8 +129,7 @@ module.exports = {
129
129
  comments = sourceCode.getAllComments(),
130
130
  commentLineNumbers = getCommentLineNumbers(comments);
131
131
 
132
- let totalLength = 0,
133
- fixRange = [];
132
+ let totalLength = 0;
134
133
 
135
134
  for (let i = 0, ii = lines.length; i < ii; i++) {
136
135
  const lineNumber = i + 1;
@@ -177,7 +176,7 @@ module.exports = {
177
176
  continue;
178
177
  }
179
178
 
180
- fixRange = [rangeStart, rangeEnd];
179
+ const fixRange = [rangeStart, rangeEnd];
181
180
 
182
181
  if (!ignoreComments || !commentLineNumbers.has(lineNumber)) {
183
182
  report(node, location, fixRange);
@@ -76,7 +76,7 @@ module.exports = {
76
76
  * @returns {string} A string representing an inverted expression
77
77
  */
78
78
  function invertExpression(node) {
79
- if (node.type === "BinaryExpression" && Object.prototype.hasOwnProperty.call(OPERATOR_INVERSES, node.operator)) {
79
+ if (node.type === "BinaryExpression" && Object.hasOwn(OPERATOR_INVERSES, node.operator)) {
80
80
  const operatorToken = sourceCode.getFirstTokenBetween(
81
81
  node.left,
82
82
  node.right,
@@ -94,7 +94,7 @@ module.exports = {
94
94
  break;
95
95
  case "SequenceExpression":
96
96
  checkUndefinedShortCircuit(
97
- node.expressions[node.expressions.length - 1],
97
+ node.expressions.at(-1),
98
98
  reportFunc
99
99
  );
100
100
  break;
@@ -16,7 +16,7 @@ module.exports = {
16
16
 
17
17
  docs: {
18
18
  description: "Disallow unused private class members",
19
- recommended: false,
19
+ recommended: true,
20
20
  url: "https://eslint.org/docs/latest/rules/no-unused-private-class-members"
21
21
  },
22
22