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.
- package/README.md +31 -28
- package/bin/eslint.js +4 -3
- package/conf/ecma-version.js +16 -0
- package/conf/globals.js +1 -0
- package/conf/rule-type-list.json +3 -1
- package/lib/api.js +7 -11
- package/lib/cli-engine/cli-engine.js +14 -3
- package/lib/cli-engine/formatters/formatters-meta.json +1 -29
- package/lib/cli-engine/lint-result-cache.js +2 -2
- package/lib/cli.js +115 -36
- package/lib/config/default-config.js +3 -0
- package/lib/config/flat-config-array.js +110 -24
- package/lib/config/flat-config-helpers.js +41 -20
- package/lib/config/flat-config-schema.js +1 -7
- package/lib/config/rule-validator.js +42 -6
- package/lib/eslint/eslint-helpers.js +116 -58
- package/lib/eslint/eslint.js +892 -377
- package/lib/eslint/index.js +2 -2
- package/lib/eslint/legacy-eslint.js +728 -0
- package/lib/linter/apply-disable-directives.js +59 -31
- package/lib/linter/code-path-analysis/code-path-analyzer.js +0 -1
- package/lib/linter/code-path-analysis/code-path.js +32 -30
- package/lib/linter/code-path-analysis/fork-context.js +1 -1
- package/lib/linter/config-comment-parser.js +8 -11
- package/lib/linter/index.js +1 -3
- package/lib/linter/interpolate.js +24 -2
- package/lib/linter/linter.js +428 -207
- package/lib/linter/report-translator.js +3 -3
- package/lib/linter/rules.js +6 -15
- package/lib/linter/source-code-fixer.js +1 -1
- package/lib/linter/timing.js +16 -8
- package/lib/options.js +35 -3
- package/lib/rule-tester/index.js +3 -1
- package/lib/rule-tester/rule-tester.js +424 -347
- package/lib/rules/array-bracket-newline.js +1 -1
- package/lib/rules/array-bracket-spacing.js +1 -1
- package/lib/rules/block-scoped-var.js +1 -1
- package/lib/rules/callback-return.js +2 -2
- package/lib/rules/camelcase.js +3 -5
- package/lib/rules/capitalized-comments.js +10 -7
- package/lib/rules/comma-dangle.js +1 -1
- package/lib/rules/comma-style.js +2 -2
- package/lib/rules/complexity.js +14 -1
- package/lib/rules/constructor-super.js +99 -100
- package/lib/rules/default-case.js +1 -1
- package/lib/rules/eol-last.js +2 -2
- package/lib/rules/function-paren-newline.js +2 -2
- package/lib/rules/indent-legacy.js +5 -5
- package/lib/rules/indent.js +5 -5
- package/lib/rules/index.js +1 -2
- package/lib/rules/key-spacing.js +2 -2
- package/lib/rules/line-comment-position.js +1 -1
- package/lib/rules/lines-around-directive.js +2 -2
- package/lib/rules/max-depth.js +1 -1
- package/lib/rules/max-len.js +3 -3
- package/lib/rules/max-lines.js +3 -3
- package/lib/rules/max-nested-callbacks.js +1 -1
- package/lib/rules/max-params.js +1 -1
- package/lib/rules/max-statements.js +1 -1
- package/lib/rules/multiline-comment-style.js +7 -7
- package/lib/rules/new-cap.js +1 -1
- package/lib/rules/newline-after-var.js +1 -1
- package/lib/rules/newline-before-return.js +1 -1
- package/lib/rules/no-case-declarations.js +13 -1
- package/lib/rules/no-constant-binary-expression.js +7 -8
- package/lib/rules/no-constant-condition.js +18 -7
- package/lib/rules/no-constructor-return.js +2 -2
- package/lib/rules/no-dupe-class-members.js +2 -2
- package/lib/rules/no-else-return.js +1 -1
- package/lib/rules/no-empty-function.js +2 -2
- package/lib/rules/no-empty-static-block.js +1 -1
- package/lib/rules/no-extend-native.js +1 -2
- package/lib/rules/no-extra-semi.js +1 -1
- package/lib/rules/no-fallthrough.js +41 -16
- package/lib/rules/no-implicit-coercion.js +66 -24
- package/lib/rules/no-inner-declarations.js +23 -2
- package/lib/rules/no-invalid-regexp.js +1 -1
- package/lib/rules/no-invalid-this.js +1 -1
- package/lib/rules/no-lone-blocks.js +3 -3
- package/lib/rules/no-loss-of-precision.js +1 -1
- package/lib/rules/no-misleading-character-class.js +225 -69
- package/lib/rules/no-mixed-spaces-and-tabs.js +1 -1
- package/lib/rules/no-multiple-empty-lines.js +1 -1
- package/lib/rules/no-new-native-nonconstructor.js +1 -1
- package/lib/rules/no-new-symbol.js +8 -1
- package/lib/rules/no-restricted-globals.js +1 -1
- package/lib/rules/no-restricted-imports.js +186 -40
- package/lib/rules/no-restricted-modules.js +2 -2
- package/lib/rules/no-return-await.js +1 -1
- package/lib/rules/no-sequences.js +1 -0
- package/lib/rules/no-this-before-super.js +45 -13
- package/lib/rules/no-trailing-spaces.js +2 -3
- package/lib/rules/no-unneeded-ternary.js +1 -1
- package/lib/rules/no-unsafe-optional-chaining.js +1 -1
- package/lib/rules/no-unused-private-class-members.js +1 -1
- package/lib/rules/no-unused-vars.js +197 -36
- package/lib/rules/no-useless-assignment.js +566 -0
- package/lib/rules/no-useless-backreference.js +1 -1
- package/lib/rules/no-useless-computed-key.js +2 -2
- package/lib/rules/no-useless-return.js +7 -2
- package/lib/rules/object-curly-spacing.js +3 -3
- package/lib/rules/object-property-newline.js +1 -1
- package/lib/rules/one-var.js +5 -5
- package/lib/rules/padded-blocks.js +7 -7
- package/lib/rules/prefer-arrow-callback.js +3 -3
- package/lib/rules/prefer-reflect.js +1 -1
- package/lib/rules/prefer-regex-literals.js +1 -1
- package/lib/rules/prefer-template.js +1 -1
- package/lib/rules/radix.js +2 -2
- package/lib/rules/semi-style.js +1 -1
- package/lib/rules/sort-imports.js +1 -1
- package/lib/rules/sort-keys.js +1 -1
- package/lib/rules/sort-vars.js +1 -1
- package/lib/rules/space-unary-ops.js +1 -1
- package/lib/rules/strict.js +1 -1
- package/lib/rules/use-isnan.js +101 -7
- package/lib/rules/utils/ast-utils.js +16 -7
- package/lib/rules/utils/char-source.js +240 -0
- package/lib/rules/utils/lazy-loading-rule-map.js +1 -1
- package/lib/rules/utils/unicode/index.js +9 -4
- package/lib/rules/yield-star-spacing.js +1 -1
- package/lib/shared/runtime-info.js +1 -0
- package/lib/shared/serialization.js +55 -0
- package/lib/shared/stats.js +30 -0
- package/lib/shared/string-utils.js +9 -11
- package/lib/shared/types.js +35 -1
- package/lib/source-code/index.js +3 -1
- package/lib/source-code/source-code.js +299 -85
- package/lib/source-code/token-store/backward-token-cursor.js +3 -3
- package/lib/source-code/token-store/cursors.js +4 -2
- package/lib/source-code/token-store/forward-token-comment-cursor.js +3 -3
- package/lib/source-code/token-store/forward-token-cursor.js +3 -3
- package/lib/source-code/token-store/index.js +2 -2
- package/lib/unsupported-api.js +3 -5
- package/messages/no-config-found.js +1 -1
- package/messages/plugin-conflict.js +1 -1
- package/messages/plugin-invalid.js +1 -1
- package/messages/plugin-missing.js +1 -1
- package/package.json +32 -29
- package/conf/config-schema.js +0 -93
- package/lib/cli-engine/formatters/checkstyle.js +0 -60
- package/lib/cli-engine/formatters/compact.js +0 -60
- package/lib/cli-engine/formatters/jslint-xml.js +0 -41
- package/lib/cli-engine/formatters/junit.js +0 -82
- package/lib/cli-engine/formatters/tap.js +0 -95
- package/lib/cli-engine/formatters/unix.js +0 -58
- package/lib/cli-engine/formatters/visualstudio.js +0 -63
- package/lib/cli-engine/xml-escape.js +0 -34
- package/lib/eslint/flat-eslint.js +0 -1155
- package/lib/rule-tester/flat-rule-tester.js +0 -1131
- package/lib/rules/require-jsdoc.js +0 -122
- package/lib/rules/utils/patterns/letters.js +0 -36
- package/lib/rules/valid-jsdoc.js +0 -516
- package/lib/shared/config-validator.js +0 -347
- package/lib/shared/deprecation-warnings.js +0 -58
- 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/) (`^
|
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
|
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
|
-
```
|
65
|
-
|
66
|
-
|
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
|
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
|
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/
|
244
|
-
<img src="https://github.com/
|
245
|
-
|
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="
|
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://
|
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
|
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
package/conf/rule-type-list.json
CHANGED
@@ -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,
|
13
|
-
const {
|
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
|
28
|
+
async function loadESLint({ useFlatConfig } = {}) {
|
30
29
|
|
31
30
|
/*
|
32
|
-
* Note: The
|
33
|
-
*
|
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 =
|
38
|
-
? useFlatConfig
|
39
|
-
: await shouldUseFlatConfig({ cwd });
|
35
|
+
const shouldESLintUseFlatConfig = useFlatConfig ?? (await shouldUseFlatConfig());
|
40
36
|
|
41
|
-
return shouldESLintUseFlatConfig ?
|
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.
|
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
|
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.
|
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.
|
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
|
-
{
|
22
|
-
{
|
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
|
-
|
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
|
-
|
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 (
|
270
|
-
|
271
|
-
const filePath = path.resolve(process.cwd(), outputFile);
|
307
|
+
if (outputFile) {
|
308
|
+
const filePath = path.resolve(process.cwd(), outputFile);
|
272
309
|
|
273
|
-
|
274
|
-
|
275
|
-
|
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
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
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
|
380
|
-
: new
|
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 ?
|
487
|
+
const ActiveESLint = usingFlatConfig ? ESLint : LegacyESLint;
|
409
488
|
|
410
489
|
const engine = new ActiveESLint(await translateOptions(options, usingFlatConfig ? "flat" : "eslintrc"));
|
411
490
|
let results;
|