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
package/README.md CHANGED
@@ -43,12 +43,12 @@ ESLint is a tool for identifying and reporting on patterns found in ECMAScript/J
43
43
 
44
44
  ## Installation and Usage
45
45
 
46
- Prerequisites: [Node.js](https://nodejs.org/) (`^12.22.0`, `^14.17.0`, or `>=16.0.0`) built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
46
+ Prerequisites: [Node.js](https://nodejs.org/) (`^18.18.0`, `^20.9.0`, or `>=21.1.0`) built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
47
47
 
48
48
  You can install and configure ESLint using this command:
49
49
 
50
50
  ```shell
51
- npm init @eslint/config
51
+ npm init @eslint/config@latest
52
52
  ```
53
53
 
54
54
  After that, you can run ESLint on any file or directory like this:
@@ -59,15 +59,11 @@ After that, you can run ESLint on any file or directory like this:
59
59
 
60
60
  ## Configuration
61
61
 
62
- After running `npm init @eslint/config`, you'll have an `.eslintrc` file in your directory. In it, you'll see some rules configured like this:
62
+ After running `npm init @eslint/config`, you'll have an `eslint.config.js` (or `eslint.config.mjs`) file in your directory. In it, you'll see some rules configured like this:
63
63
 
64
- ```json
65
- {
66
- "rules": {
67
- "semi": ["error", "always"],
68
- "quotes": ["error", "double"]
69
- }
70
- }
64
+ ```js
65
+ import pluginJs from "@eslint/js";
66
+ export default [ pluginJs.configs.recommended, ];
71
67
  ```
72
68
 
73
69
  The names `"semi"` and `"quotes"` are the names of [rules](https://eslint.org/docs/rules) in ESLint. The first value is the error level of the rule and can be one of these values:
@@ -103,7 +99,7 @@ We are now at or near 100% compatibility with JSCS. If you try ESLint and believ
103
99
 
104
100
  ### Does Prettier replace ESLint?
105
101
 
106
- No, ESLint and Prettier have diffent jobs: ESLint is a linter (looking for problematic patterns) and Prettier is a code formatter. Using both tools is common, refer to [Prettier's documentation](https://prettier.io/docs/en/install#eslint-and-other-linters) to learn how to configure them to work well with each other.
102
+ No, ESLint and Prettier have different jobs: ESLint is a linter (looking for problematic patterns) and Prettier is a code formatter. Using both tools is common, refer to [Prettier's documentation](https://prettier.io/docs/en/install#eslint-and-other-linters) to learn how to configure them to work well with each other.
107
103
 
108
104
  ### Why can't ESLint find my plugins?
109
105
 
@@ -117,7 +113,7 @@ Yes, ESLint natively supports parsing JSX syntax (this must be enabled in [confi
117
113
 
118
114
  ### What ECMAScript versions does ESLint support?
119
115
 
120
- ESLint has full support for ECMAScript 3, 5 (default), 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, and 2023. You can set your desired ECMAScript syntax (and other settings, like global variables or your target environments) through [configuration](https://eslint.org/docs/latest/use/configure).
116
+ ESLint has full support for ECMAScript 3, 5, and every year from 2015 up until the most recent stage 4 specification (the default). You can set your desired ECMAScript syntax and other settings (like global variables) through [configuration](https://eslint.org/docs/latest/use/configure).
121
117
 
122
118
  ### What about experimental features?
123
119
 
@@ -127,6 +123,18 @@ In other cases (including if rules need to warn on more or fewer cases due to ne
127
123
 
128
124
  Once a language feature has been adopted into the ECMAScript standard (stage 4 according to the [TC39 process](https://tc39.github.io/process-document/)), we will accept issues and pull requests related to the new feature, subject to our [contributing guidelines](https://eslint.org/docs/latest/contribute). Until then, please use the appropriate parser and plugin(s) for your experimental feature.
129
125
 
126
+ ### Which Node.js versions does ESLint support?
127
+
128
+ ESLint updates the supported Node.js versions with each major release of ESLint. At that time, ESLint's supported Node.js versions are updated to be:
129
+
130
+ 1. The most recent maintenance release of Node.js
131
+ 1. The lowest minor version of the Node.js LTS release that includes the features the ESLint team wants to use.
132
+ 1. The Node.js Current release
133
+
134
+ ESLint is also expected to work with Node.js versions released after the Node.js Current release.
135
+
136
+ Refer to the [Quick Start Guide](https://eslint.org/docs/latest/use/getting-started#prerequisites) for the officially supported Node.js versions for a given ESLint release.
137
+
130
138
  ### Where to ask for help?
131
139
 
132
140
  Open a [discussion](https://github.com/eslint/eslint/discussions) or stop by our [Discord server](https://eslint.org/chat).
@@ -213,6 +221,11 @@ The people who manage releases, review feature requests, and meet regularly to e
213
221
  Nicholas C. Zakas
214
222
  </a>
215
223
  </td><td align="center" valign="top" width="11%">
224
+ <a href="https://github.com/fasttime">
225
+ <img src="https://github.com/fasttime.png?s=75" width="75" height="75" alt="Francesco Trotta's Avatar"><br />
226
+ Francesco Trotta
227
+ </a>
228
+ </td><td align="center" valign="top" width="11%">
216
229
  <a href="https://github.com/mdjermanovic">
217
230
  <img src="https://github.com/mdjermanovic.png?s=75" width="75" height="75" alt="Milos Djermanovic's Avatar"><br />
218
231
  Milos Djermanovic
@@ -240,19 +253,9 @@ Nitin Kumar
240
253
  The people who review and fix bugs and help triage issues.
241
254
 
242
255
  <table><tbody><tr><td align="center" valign="top" width="11%">
243
- <a href="https://github.com/bmish">
244
- <img src="https://github.com/bmish.png?s=75" width="75" height="75" alt="Bryan Mishkin's Avatar"><br />
245
- Bryan Mishkin
246
- </a>
247
- </td><td align="center" valign="top" width="11%">
248
- <a href="https://github.com/fasttime">
249
- <img src="https://github.com/fasttime.png?s=75" width="75" height="75" alt="Francesco Trotta's Avatar"><br />
250
- Francesco Trotta
251
- </a>
252
- </td><td align="center" valign="top" width="11%">
253
- <a href="https://github.com/ota-meshi">
254
- <img src="https://github.com/ota-meshi.png?s=75" width="75" height="75" alt="Yosuke Ota's Avatar"><br />
255
- Yosuke Ota
256
+ <a href="https://github.com/JoshuaKGoldberg">
257
+ <img src="https://github.com/JoshuaKGoldberg.png?s=75" width="75" height="75" alt="Josh Goldberg ✨'s Avatar"><br />
258
+ Josh Goldberg ✨
256
259
  </a>
257
260
  </td><td align="center" valign="top" width="11%">
258
261
  <a href="https://github.com/Tanujkanti4441">
@@ -291,10 +294,10 @@ The following companies, organizations, and individuals support ESLint's ongoing
291
294
  <!-- NOTE: This section is autogenerated. Do not manually edit.-->
292
295
  <!--sponsorsstart-->
293
296
  <h3>Platinum Sponsors</h3>
294
- <p><a href="#"><img src="https://images.opencollective.com/2021-frameworks-fund/logo.png" alt="Chrome Frameworks Fund" height="undefined"></a> <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>
297
+ <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
298
  <p><a href="https://engineering.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></p><h3>Silver Sponsors</h3>
296
- <p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="64"></a> <a href="https://www.workleap.com"><img src="https://avatars.githubusercontent.com/u/53535748?u=d1e55d7661d724bf2281c1bfd33cb8f99fe2465f&v=4" alt="Workleap" height="64"></a></p><h3>Bronze Sponsors</h3>
297
- <p><a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" 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://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" 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://transloadit.com/"><img src="https://avatars.githubusercontent.com/u/125754?v=4" alt="Transloadit" 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://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104?v=4" alt="Nx" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a></p>
299
+ <p><a href="https://www.jetbrains.com/"><img src="https://images.opencollective.com/jetbrains/eb04ddc/logo.png" alt="JetBrains" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="64"></a> <a href="https://www.workleap.com"><img src="https://avatars.githubusercontent.com/u/53535748?u=d1e55d7661d724bf2281c1bfd33cb8f99fe2465f&v=4" alt="Workleap" height="64"></a></p><h3>Bronze Sponsors</h3>
300
+ <p><a href="https://www.notion.so"><img src="https://images.opencollective.com/notion/bf3b117/logo.png" alt="notion" 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://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" 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://transloadit.com/"><img src="https://avatars.githubusercontent.com/u/125754?v=4" alt="Transloadit" 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://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104?v=4" alt="Nx" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://usenextbase.com"><img src="https://avatars.githubusercontent.com/u/145838380?v=4" alt="Nextbase Starter Kit" height="32"></a></p>
298
301
  <!--sponsorsend-->
299
302
 
300
303
  ## Technology Sponsors
package/bin/eslint.js CHANGED
@@ -140,16 +140,17 @@ ${getErrorMessage(error)}`;
140
140
  if (process.argv.includes("--init")) {
141
141
 
142
142
  // `eslint --init` has been moved to `@eslint/create-config`
143
- console.warn("You can also run this command directly using 'npm init @eslint/config'.");
143
+ console.warn("You can also run this command directly using 'npm init @eslint/config@latest'.");
144
144
 
145
145
  const spawn = require("cross-spawn");
146
146
 
147
- spawn.sync("npm", ["init", "@eslint/config"], { encoding: "utf8", stdio: "inherit" });
147
+ spawn.sync("npm", ["init", "@eslint/config@latest"], { encoding: "utf8", stdio: "inherit" });
148
148
  return;
149
149
  }
150
150
 
151
151
  // Otherwise, call the CLI.
152
- const exitCode = await require("../lib/cli").execute(
152
+ const cli = require("../lib/cli");
153
+ const exitCode = await cli.execute(
153
154
  process.argv,
154
155
  process.argv.includes("--stdin") ? await readStdin() : null,
155
156
  true
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @fileoverview Configuration related to ECMAScript versions
3
+ * @author Milos Djermanovic
4
+ */
5
+
6
+ "use strict";
7
+
8
+ /**
9
+ * The latest ECMAScript version supported by ESLint.
10
+ * @type {number} year-based ECMAScript version
11
+ */
12
+ const LATEST_ECMA_VERSION = 2024;
13
+
14
+ module.exports = {
15
+ LATEST_ECMA_VERSION
16
+ };
package/conf/globals.js CHANGED
@@ -70,6 +70,7 @@ const es2015 = {
70
70
  Int16Array: false,
71
71
  Int32Array: false,
72
72
  Int8Array: false,
73
+ Intl: false,
73
74
  Map: false,
74
75
  Promise: false,
75
76
  Proxy: false,
@@ -23,6 +23,8 @@
23
23
  { "removed": "space-in-brackets", "replacedBy": ["object-curly-spacing", "array-bracket-spacing"] },
24
24
  { "removed": "space-return-throw-case", "replacedBy": ["keyword-spacing"] },
25
25
  { "removed": "space-unary-word-ops", "replacedBy": ["space-unary-ops"] },
26
- { "removed": "spaced-line-comment", "replacedBy": ["spaced-comment"] }
26
+ { "removed": "spaced-line-comment", "replacedBy": ["spaced-comment"] },
27
+ { "removed": "valid-jsdoc", "replacedBy": [] },
28
+ { "removed": "require-jsdoc", "replacedBy": [] }
27
29
  ]
28
30
  }
package/lib/api.js CHANGED
@@ -9,8 +9,8 @@
9
9
  // Requirements
10
10
  //-----------------------------------------------------------------------------
11
11
 
12
- const { ESLint, FlatESLint } = require("./eslint");
13
- const { shouldUseFlatConfig } = require("./eslint/flat-eslint");
12
+ const { ESLint, shouldUseFlatConfig } = require("./eslint/eslint");
13
+ const { LegacyESLint } = require("./eslint/legacy-eslint");
14
14
  const { Linter } = require("./linter");
15
15
  const { RuleTester } = require("./rule-tester");
16
16
  const { SourceCode } = require("./source-code");
@@ -23,22 +23,18 @@ const { SourceCode } = require("./source-code");
23
23
  * Loads the correct ESLint constructor given the options.
24
24
  * @param {Object} [options] The options object
25
25
  * @param {boolean} [options.useFlatConfig] Whether or not to use a flat config
26
- * @param {string} [options.cwd] The current working directory
27
26
  * @returns {Promise<ESLint|LegacyESLint>} The ESLint constructor
28
27
  */
29
- async function loadESLint({ useFlatConfig, cwd = process.cwd() } = {}) {
28
+ async function loadESLint({ useFlatConfig } = {}) {
30
29
 
31
30
  /*
32
- * Note: The v9.x version of this function doesn't have a cwd option
33
- * because it's not used. It's only used in the v8.x version of this
34
- * function.
31
+ * Note: The v8.x version of this function also accepted a `cwd` option, but
32
+ * it is not used in this implementation so we silently ignore it.
35
33
  */
36
34
 
37
- const shouldESLintUseFlatConfig = typeof useFlatConfig === "boolean"
38
- ? useFlatConfig
39
- : await shouldUseFlatConfig({ cwd });
35
+ const shouldESLintUseFlatConfig = useFlatConfig ?? (await shouldUseFlatConfig());
40
36
 
41
- return shouldESLintUseFlatConfig ? FlatESLint : ESLint;
37
+ return shouldESLintUseFlatConfig ? ESLint : LegacyESLint;
42
38
  }
43
39
 
44
40
  //-----------------------------------------------------------------------------
@@ -41,6 +41,17 @@ const hash = require("./hash");
41
41
  const LintResultCache = require("./lint-result-cache");
42
42
 
43
43
  const debug = require("debug")("eslint:cli-engine");
44
+ const removedFormatters = new Set([
45
+ "checkstyle",
46
+ "codeframe",
47
+ "compact",
48
+ "jslint-xml",
49
+ "junit",
50
+ "table",
51
+ "tap",
52
+ "unix",
53
+ "visualstudio"
54
+ ]);
44
55
  const validFixTypes = new Set(["directive", "problem", "suggestion", "layout"]);
45
56
 
46
57
  //------------------------------------------------------------------------------
@@ -639,7 +650,7 @@ class CLIEngine {
639
650
  });
640
651
  const lintResultCache =
641
652
  options.cache ? new LintResultCache(cacheFilePath, options.cacheStrategy) : null;
642
- const linter = new Linter({ cwd: options.cwd });
653
+ const linter = new Linter({ cwd: options.cwd, configType: "eslintrc" });
643
654
 
644
655
  /** @type {ConfigArray[]} */
645
656
  const lastConfigArrays = [configArrayFactory.getConfigArrayForFile()];
@@ -721,7 +732,7 @@ class CLIEngine {
721
732
  * @returns {void}
722
733
  */
723
734
  static outputFixes(report) {
724
- report.results.filter(result => Object.prototype.hasOwnProperty.call(result, "output")).forEach(result => {
735
+ report.results.filter(result => Object.hasOwn(result, "output")).forEach(result => {
725
736
  fs.writeFileSync(result.filePath, result.output);
726
737
  });
727
738
  }
@@ -1047,7 +1058,7 @@ class CLIEngine {
1047
1058
  try {
1048
1059
  return require(formatterPath);
1049
1060
  } catch (ex) {
1050
- if (format === "table" || format === "codeframe") {
1061
+ if (removedFormatters.has(format)) {
1051
1062
  ex.message = `The ${format} formatter is no longer part of core ESLint. Install it manually with \`npm install -D eslint-formatter-${format}\``;
1052
1063
  } else {
1053
1064
  ex.message = `There was a problem loading formatter: ${formatterPath}\nError: ${ex.message}`;
@@ -1,20 +1,8 @@
1
1
  [
2
- {
3
- "name": "checkstyle",
4
- "description": "Outputs results to the [Checkstyle](https://checkstyle.sourceforge.io/) format."
5
- },
6
- {
7
- "name": "compact",
8
- "description": "Human-readable output format. Mimics the default output of JSHint."
9
- },
10
2
  {
11
3
  "name": "html",
12
4
  "description": "Outputs results to HTML. The `html` formatter is useful for visual presentation in the browser."
13
5
  },
14
- {
15
- "name": "jslint-xml",
16
- "description": "Outputs results to format compatible with the [JSLint Jenkins plugin](https://plugins.jenkins.io/jslint/)."
17
- },
18
6
  {
19
7
  "name": "json-with-metadata",
20
8
  "description": "Outputs JSON-serialized results. The `json-with-metadata` provides the same linting results as the [`json`](#json) formatter with additional metadata about the rules applied. The linting results are included in the `results` property and the rules metadata is included in the `metadata` property.\n\nAlternatively, you can use the [ESLint Node.js API](../../integrate/nodejs-api) to programmatically use ESLint."
@@ -23,24 +11,8 @@
23
11
  "name": "json",
24
12
  "description": "Outputs JSON-serialized results. The `json` formatter is useful when you want to programmatically work with the CLI's linting results.\n\nAlternatively, you can use the [ESLint Node.js API](../../integrate/nodejs-api) to programmatically use ESLint."
25
13
  },
26
- {
27
- "name": "junit",
28
- "description": "Outputs results to format compatible with the [JUnit Jenkins plugin](https://plugins.jenkins.io/junit/)."
29
- },
30
14
  {
31
15
  "name": "stylish",
32
16
  "description": "Human-readable output format. This is the default formatter."
33
- },
34
- {
35
- "name": "tap",
36
- "description": "Outputs results to the [Test Anything Protocol (TAP)](https://testanything.org/) specification format."
37
- },
38
- {
39
- "name": "unix",
40
- "description": "Outputs results to a format similar to many commands in UNIX-like systems. Parsable with tools such as [grep](https://www.gnu.org/software/grep/manual/grep.html), [sed](https://www.gnu.org/software/sed/manual/sed.html), and [awk](https://www.gnu.org/software/gawk/manual/gawk.html)."
41
- },
42
- {
43
- "name": "visualstudio",
44
- "description": "Outputs results to format compatible with the integrated terminal of the [Visual Studio](https://visualstudio.microsoft.com/) IDE. When using Visual Studio, you can click on the linting results in the integrated terminal to go to the issue in the source code."
45
17
  }
46
- ]
18
+ ]
@@ -164,7 +164,7 @@ class LintResultCache {
164
164
  * @returns {void}
165
165
  */
166
166
  setCachedLintResults(filePath, config, result) {
167
- if (result && Object.prototype.hasOwnProperty.call(result, "output")) {
167
+ if (result && Object.hasOwn(result, "output")) {
168
168
  return;
169
169
  }
170
170
 
@@ -181,7 +181,7 @@ class LintResultCache {
181
181
  * In `getCachedLintResults`, if source is explicitly null, we will
182
182
  * read the file from the filesystem to set the value again.
183
183
  */
184
- if (Object.prototype.hasOwnProperty.call(resultToSerialize, "source")) {
184
+ if (Object.hasOwn(resultToSerialize, "source")) {
185
185
  resultToSerialize.source = null;
186
186
  }
187
187
 
package/lib/cli.js CHANGED
@@ -18,8 +18,8 @@
18
18
  const fs = require("fs"),
19
19
  path = require("path"),
20
20
  { promisify } = require("util"),
21
- { ESLint } = require("./eslint"),
22
- { FlatESLint, shouldUseFlatConfig } = require("./eslint/flat-eslint"),
21
+ { LegacyESLint } = require("./eslint"),
22
+ { ESLint, shouldUseFlatConfig, locateConfigFileToUse } = require("./eslint/eslint"),
23
23
  createCLIOptions = require("./options"),
24
24
  log = require("./shared/logging"),
25
25
  RuntimeInfo = require("./shared/runtime-info"),
@@ -37,6 +37,7 @@ const debug = require("debug")("eslint:cli");
37
37
  /** @typedef {import("./eslint/eslint").LintMessage} LintMessage */
38
38
  /** @typedef {import("./eslint/eslint").LintResult} LintResult */
39
39
  /** @typedef {import("./options").ParsedCLIOptions} ParsedCLIOptions */
40
+ /** @typedef {import("./shared/types").Plugin} Plugin */
40
41
  /** @typedef {import("./shared/types").ResultsMeta} ResultsMeta */
41
42
 
42
43
  //------------------------------------------------------------------------------
@@ -47,6 +48,32 @@ const mkdir = promisify(fs.mkdir);
47
48
  const stat = promisify(fs.stat);
48
49
  const writeFile = promisify(fs.writeFile);
49
50
 
51
+ /**
52
+ * Loads plugins with the specified names.
53
+ * @param {{ "import": (name: string) => Promise<any> }} importer An object with an `import` method called once for each plugin.
54
+ * @param {string[]} pluginNames The names of the plugins to be loaded, with or without the "eslint-plugin-" prefix.
55
+ * @returns {Promise<Record<string, Plugin>>} A mapping of plugin short names to implementations.
56
+ */
57
+ async function loadPlugins(importer, pluginNames) {
58
+ const plugins = {};
59
+
60
+ await Promise.all(pluginNames.map(async pluginName => {
61
+
62
+ const longName = naming.normalizePackageName(pluginName, "eslint-plugin");
63
+ const module = await importer.import(longName);
64
+
65
+ if (!("default" in module)) {
66
+ throw new Error(`"${longName}" cannot be used with the \`--plugin\` option because its default module does not provide a \`default\` export`);
67
+ }
68
+
69
+ const shortName = naming.getShorthandName(pluginName, "eslint-plugin");
70
+
71
+ plugins[shortName] = module.default;
72
+ }));
73
+
74
+ return plugins;
75
+ }
76
+
50
77
  /**
51
78
  * Predicate function for whether or not to apply fixes in quiet mode.
52
79
  * If a message is a warning, do not apply a fix.
@@ -58,6 +85,16 @@ function quietFixPredicate(message) {
58
85
  return message.severity === 2;
59
86
  }
60
87
 
88
+ /**
89
+ * Predicate function for whether or not to run a rule in quiet mode.
90
+ * If a rule is set to warning, do not run it.
91
+ * @param {{ ruleId: string; severity: number; }} rule The rule id and severity.
92
+ * @returns {boolean} True if the lint rule should run, false otherwise.
93
+ */
94
+ function quietRuleFilter(rule) {
95
+ return rule.severity === 2;
96
+ }
97
+
61
98
  /**
62
99
  * Translates the CLI options into the options expected by the ESLint constructor.
63
100
  * @param {ParsedCLIOptions} cliOptions The CLI options to translate.
@@ -94,7 +131,10 @@ async function translateOptions({
94
131
  resolvePluginsRelativeTo,
95
132
  rule,
96
133
  rulesdir,
97
- warnIgnored
134
+ stats,
135
+ warnIgnored,
136
+ passOnNoPatterns,
137
+ maxWarnings
98
138
  }, configType) {
99
139
 
100
140
  let overrideConfig, overrideConfigFile;
@@ -140,17 +180,7 @@ async function translateOptions({
140
180
  }
141
181
 
142
182
  if (plugin) {
143
- const plugins = {};
144
-
145
- for (const pluginName of plugin) {
146
-
147
- const shortName = naming.getShorthandName(pluginName, "eslint-plugin");
148
- const longName = naming.normalizePackageName(pluginName, "eslint-plugin");
149
-
150
- plugins[shortName] = await importer.import(longName);
151
- }
152
-
153
- overrideConfig[0].plugins = plugins;
183
+ overrideConfig[0].plugins = await loadPlugins(importer, plugin);
154
184
  }
155
185
 
156
186
  } else {
@@ -187,12 +217,20 @@ async function translateOptions({
187
217
  fixTypes: fixType,
188
218
  ignore,
189
219
  overrideConfig,
190
- overrideConfigFile
220
+ overrideConfigFile,
221
+ passOnNoPatterns
191
222
  };
192
223
 
193
224
  if (configType === "flat") {
194
225
  options.ignorePatterns = ignorePattern;
226
+ options.stats = stats;
195
227
  options.warnIgnored = warnIgnored;
228
+
229
+ /*
230
+ * For performance reasons rules not marked as 'error' are filtered out in quiet mode. As maxWarnings
231
+ * requires rules set to 'warn' to be run, we only filter out 'warn' rules if maxWarnings is not specified.
232
+ */
233
+ options.ruleFilter = quiet && maxWarnings === -1 ? quietRuleFilter : () => true;
196
234
  } else {
197
235
  options.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
198
236
  options.rulePaths = rulesdir;
@@ -266,25 +304,23 @@ async function printResults(engine, results, format, outputFile, resultsMeta) {
266
304
 
267
305
  const output = await formatter.format(results, resultsMeta);
268
306
 
269
- if (output) {
270
- if (outputFile) {
271
- const filePath = path.resolve(process.cwd(), outputFile);
307
+ if (outputFile) {
308
+ const filePath = path.resolve(process.cwd(), outputFile);
272
309
 
273
- if (await isDirectory(filePath)) {
274
- log.error("Cannot write to output file path, it is a directory: %s", outputFile);
275
- return false;
276
- }
310
+ if (await isDirectory(filePath)) {
311
+ log.error("Cannot write to output file path, it is a directory: %s", outputFile);
312
+ return false;
313
+ }
277
314
 
278
- try {
279
- await mkdir(path.dirname(filePath), { recursive: true });
280
- await writeFile(filePath, output);
281
- } catch (ex) {
282
- log.error("There was a problem writing the output file:\n%s", ex);
283
- return false;
284
- }
285
- } else {
286
- log.info(output);
315
+ try {
316
+ await mkdir(path.dirname(filePath), { recursive: true });
317
+ await writeFile(filePath, output);
318
+ } catch (ex) {
319
+ log.error("There was a problem writing the output file:\n%s", ex);
320
+ return false;
287
321
  }
322
+ } else if (output) {
323
+ log.info(output);
288
324
  }
289
325
 
290
326
  return true;
@@ -300,14 +336,35 @@ async function printResults(engine, results, format, outputFile, resultsMeta) {
300
336
  */
301
337
  const cli = {
302
338
 
339
+ /**
340
+ * Calculates the command string for the --inspect-config operation.
341
+ * @param {string} configFile The path to the config file to inspect.
342
+ * @returns {Promise<string>} The command string to execute.
343
+ */
344
+ async calculateInspectConfigFlags(configFile) {
345
+
346
+ // find the config file
347
+ const {
348
+ configFilePath,
349
+ basePath,
350
+ error
351
+ } = await locateConfigFileToUse({ cwd: process.cwd(), configFile });
352
+
353
+ if (error) {
354
+ throw error;
355
+ }
356
+
357
+ return ["--config", configFilePath, "--basePath", basePath];
358
+ },
359
+
303
360
  /**
304
361
  * Executes the CLI based on an array of arguments that is passed in.
305
362
  * @param {string|Array|Object} args The arguments to process.
306
363
  * @param {string} [text] The text to lint (used for TTY).
307
- * @param {boolean} [allowFlatConfig] Whether or not to allow flat config.
364
+ * @param {boolean} [allowFlatConfig=true] Whether or not to allow flat config.
308
365
  * @returns {Promise<number>} The exit code for the operation.
309
366
  */
310
- async execute(args, text, allowFlatConfig) {
367
+ async execute(args, text, allowFlatConfig = true) {
311
368
  if (Array.isArray(args)) {
312
369
  debug("CLI args: %o", args.slice(2));
313
370
  }
@@ -323,6 +380,10 @@ const cli = {
323
380
 
324
381
  debug("Using flat config?", usingFlatConfig);
325
382
 
383
+ if (allowFlatConfig && !usingFlatConfig) {
384
+ process.emitWarning("You are using an eslintrc configuration file, which is deprecated and support will be removed in v10.0.0. Please migrate to an eslint.config.js file. See https://eslint.org/docs/latest/use/configure/migration-guide for details.", "ESLintRCWarning");
385
+ }
386
+
326
387
  const CLIOptions = createCLIOptions(usingFlatConfig);
327
388
 
328
389
  /** @type {ParsedCLIOptions} */
@@ -376,8 +437,8 @@ const cli = {
376
437
  }
377
438
 
378
439
  const engine = usingFlatConfig
379
- ? new FlatESLint(await translateOptions(options, "flat"))
380
- : new ESLint(await translateOptions(options));
440
+ ? new ESLint(await translateOptions(options, "flat"))
441
+ : new LegacyESLint(await translateOptions(options));
381
442
  const fileConfig =
382
443
  await engine.calculateConfigForFile(options.printConfig);
383
444
 
@@ -385,6 +446,24 @@ const cli = {
385
446
  return 0;
386
447
  }
387
448
 
449
+ if (options.inspectConfig) {
450
+
451
+ log.info("You can also run this command directly using 'npx @eslint/config-inspector' in the same directory as your configuration file.");
452
+
453
+ try {
454
+ const flatOptions = await translateOptions(options, "flat");
455
+ const spawn = require("cross-spawn");
456
+ const flags = await cli.calculateInspectConfigFlags(flatOptions.overrideConfigFile);
457
+
458
+ spawn.sync("npx", ["@eslint/config-inspector", ...flags], { encoding: "utf8", stdio: "inherit" });
459
+ } catch (error) {
460
+ log.error(error);
461
+ return 2;
462
+ }
463
+
464
+ return 0;
465
+ }
466
+
388
467
  debug(`Running on ${useStdin ? "text" : "files"}`);
389
468
 
390
469
  if (options.fix && options.fixDryRun) {
@@ -405,7 +484,7 @@ const cli = {
405
484
  return 2;
406
485
  }
407
486
 
408
- const ActiveESLint = usingFlatConfig ? FlatESLint : ESLint;
487
+ const ActiveESLint = usingFlatConfig ? ESLint : LegacyESLint;
409
488
 
410
489
  const engine = new ActiveESLint(await translateOptions(options, usingFlatConfig ? "flat" : "eslintrc"));
411
490
  let results;
@@ -42,6 +42,9 @@ exports.defaultConfig = [
42
42
  ecmaVersion: "latest",
43
43
  parser: require("espree"),
44
44
  parserOptions: {}
45
+ },
46
+ linterOptions: {
47
+ reportUnusedDisableDirectives: 1
45
48
  }
46
49
  },
47
50