eslint 9.0.0-rc.0 → 9.1.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 +7 -11
- package/conf/globals.js +1 -0
- package/lib/cli.js +42 -1
- package/lib/config/flat-config-array.js +110 -4
- package/lib/eslint/eslint-helpers.js +84 -45
- package/lib/eslint/eslint.js +24 -5
- package/lib/linter/apply-disable-directives.js +24 -24
- package/lib/linter/linter.js +181 -66
- package/lib/linter/timing.js +16 -8
- package/lib/options.js +27 -3
- package/lib/rule-tester/rule-tester.js +18 -2
- package/lib/rules/camelcase.js +3 -5
- package/lib/rules/constructor-super.js +62 -93
- package/lib/rules/no-constant-condition.js +18 -7
- package/lib/rules/no-lone-blocks.js +1 -1
- package/lib/rules/no-unused-vars.js +179 -29
- package/lib/rules/use-isnan.js +2 -2
- package/lib/shared/stats.js +30 -0
- package/lib/shared/string-utils.js +9 -11
- package/lib/shared/types.js +34 -0
- package/lib/source-code/source-code.js +128 -0
- 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/messages/plugin-conflict.js +1 -1
- package/messages/plugin-invalid.js +1 -1
- package/messages/plugin-missing.js +1 -1
- package/package.json +11 -9
package/README.md
CHANGED
@@ -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
|
63
|
-
|
64
|
-
```
|
65
|
-
|
66
|
-
|
67
|
-
"semi": ["error", "always"],
|
68
|
-
"quotes": ["error", "double"]
|
69
|
-
}
|
70
|
-
}
|
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
|
+
|
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:
|
@@ -304,9 +300,9 @@ The following companies, organizations, and individuals support ESLint's ongoing
|
|
304
300
|
<!--sponsorsstart-->
|
305
301
|
<h3>Platinum Sponsors</h3>
|
306
302
|
<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>
|
307
|
-
<p><a href="https://
|
303
|
+
<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>
|
308
304
|
<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>
|
309
|
-
<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://
|
305
|
+
<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>
|
310
306
|
<!--sponsorsend-->
|
311
307
|
|
312
308
|
## Technology Sponsors
|
package/conf/globals.js
CHANGED
package/lib/cli.js
CHANGED
@@ -19,7 +19,7 @@ const fs = require("fs"),
|
|
19
19
|
path = require("path"),
|
20
20
|
{ promisify } = require("util"),
|
21
21
|
{ LegacyESLint } = require("./eslint"),
|
22
|
-
{ ESLint, shouldUseFlatConfig } = require("./eslint/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"),
|
@@ -131,6 +131,7 @@ async function translateOptions({
|
|
131
131
|
resolvePluginsRelativeTo,
|
132
132
|
rule,
|
133
133
|
rulesdir,
|
134
|
+
stats,
|
134
135
|
warnIgnored,
|
135
136
|
passOnNoPatterns,
|
136
137
|
maxWarnings
|
@@ -222,6 +223,7 @@ async function translateOptions({
|
|
222
223
|
|
223
224
|
if (configType === "flat") {
|
224
225
|
options.ignorePatterns = ignorePattern;
|
226
|
+
options.stats = stats;
|
225
227
|
options.warnIgnored = warnIgnored;
|
226
228
|
|
227
229
|
/*
|
@@ -334,6 +336,27 @@ async function printResults(engine, results, format, outputFile, resultsMeta) {
|
|
334
336
|
*/
|
335
337
|
const cli = {
|
336
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
|
+
|
337
360
|
/**
|
338
361
|
* Executes the CLI based on an array of arguments that is passed in.
|
339
362
|
* @param {string|Array|Object} args The arguments to process.
|
@@ -423,6 +446,24 @@ const cli = {
|
|
423
446
|
return 0;
|
424
447
|
}
|
425
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
|
+
|
426
467
|
debug(`Running on ${useStdin ? "text" : "files"}`);
|
427
468
|
|
428
469
|
if (options.fix && options.fixDryRun) {
|
@@ -18,6 +18,11 @@ const { defaultConfig } = require("./default-config");
|
|
18
18
|
// Helpers
|
19
19
|
//-----------------------------------------------------------------------------
|
20
20
|
|
21
|
+
/**
|
22
|
+
* Fields that are considered metadata and not part of the config object.
|
23
|
+
*/
|
24
|
+
const META_FIELDS = new Set(["name"]);
|
25
|
+
|
21
26
|
const ruleValidator = new RuleValidator();
|
22
27
|
|
23
28
|
/**
|
@@ -74,7 +79,53 @@ function getObjectId(object) {
|
|
74
79
|
return name;
|
75
80
|
}
|
76
81
|
|
82
|
+
/**
|
83
|
+
* Wraps a config error with details about where the error occurred.
|
84
|
+
* @param {Error} error The original error.
|
85
|
+
* @param {number} originalLength The original length of the config array.
|
86
|
+
* @param {number} baseLength The length of the base config.
|
87
|
+
* @returns {TypeError} The new error with details.
|
88
|
+
*/
|
89
|
+
function wrapConfigErrorWithDetails(error, originalLength, baseLength) {
|
90
|
+
|
91
|
+
let location = "user-defined";
|
92
|
+
let configIndex = error.index;
|
93
|
+
|
94
|
+
/*
|
95
|
+
* A config array is set up in this order:
|
96
|
+
* 1. Base config
|
97
|
+
* 2. Original configs
|
98
|
+
* 3. User-defined configs
|
99
|
+
* 4. CLI-defined configs
|
100
|
+
*
|
101
|
+
* So we need to adjust the index to account for the base config.
|
102
|
+
*
|
103
|
+
* - If the index is less than the base length, it's in the base config
|
104
|
+
* (as specified by `baseConfig` argument to `FlatConfigArray` constructor).
|
105
|
+
* - If the index is greater than the base length but less than the original
|
106
|
+
* length + base length, it's in the original config. The original config
|
107
|
+
* is passed to the `FlatConfigArray` constructor as the first argument.
|
108
|
+
* - Otherwise, it's in the user-defined config, which is loaded from the
|
109
|
+
* config file and merged with any command-line options.
|
110
|
+
*/
|
111
|
+
if (error.index < baseLength) {
|
112
|
+
location = "base";
|
113
|
+
} else if (error.index < originalLength + baseLength) {
|
114
|
+
location = "original";
|
115
|
+
configIndex = error.index - baseLength;
|
116
|
+
} else {
|
117
|
+
configIndex = error.index - originalLength - baseLength;
|
118
|
+
}
|
119
|
+
|
120
|
+
return new TypeError(
|
121
|
+
`${error.message.slice(0, -1)} at ${location} index ${configIndex}.`,
|
122
|
+
{ cause: error }
|
123
|
+
);
|
124
|
+
}
|
125
|
+
|
77
126
|
const originalBaseConfig = Symbol("originalBaseConfig");
|
127
|
+
const originalLength = Symbol("originalLength");
|
128
|
+
const baseLength = Symbol("baseLength");
|
78
129
|
|
79
130
|
//-----------------------------------------------------------------------------
|
80
131
|
// Exports
|
@@ -101,12 +152,24 @@ class FlatConfigArray extends ConfigArray {
|
|
101
152
|
schema: flatConfigSchema
|
102
153
|
});
|
103
154
|
|
155
|
+
/**
|
156
|
+
* The original length of the array before any modifications.
|
157
|
+
* @type {number}
|
158
|
+
*/
|
159
|
+
this[originalLength] = this.length;
|
160
|
+
|
104
161
|
if (baseConfig[Symbol.iterator]) {
|
105
162
|
this.unshift(...baseConfig);
|
106
163
|
} else {
|
107
164
|
this.unshift(baseConfig);
|
108
165
|
}
|
109
166
|
|
167
|
+
/**
|
168
|
+
* The length of the array after applying the base config.
|
169
|
+
* @type {number}
|
170
|
+
*/
|
171
|
+
this[baseLength] = this.length - this[originalLength];
|
172
|
+
|
110
173
|
/**
|
111
174
|
* The base config used to build the config array.
|
112
175
|
* @type {Array<FlatConfig>}
|
@@ -124,6 +187,49 @@ class FlatConfigArray extends ConfigArray {
|
|
124
187
|
Object.defineProperty(this, "shouldIgnore", { writable: false });
|
125
188
|
}
|
126
189
|
|
190
|
+
/**
|
191
|
+
* Normalizes the array by calling the superclass method and catching/rethrowing
|
192
|
+
* any ConfigError exceptions with additional details.
|
193
|
+
* @param {any} [context] The context to use to normalize the array.
|
194
|
+
* @returns {Promise<FlatConfigArray>} A promise that resolves when the array is normalized.
|
195
|
+
*/
|
196
|
+
normalize(context) {
|
197
|
+
return super.normalize(context)
|
198
|
+
.catch(error => {
|
199
|
+
if (error.name === "ConfigError") {
|
200
|
+
throw wrapConfigErrorWithDetails(error, this[originalLength], this[baseLength]);
|
201
|
+
}
|
202
|
+
|
203
|
+
throw error;
|
204
|
+
|
205
|
+
});
|
206
|
+
}
|
207
|
+
|
208
|
+
/**
|
209
|
+
* Normalizes the array by calling the superclass method and catching/rethrowing
|
210
|
+
* any ConfigError exceptions with additional details.
|
211
|
+
* @param {any} [context] The context to use to normalize the array.
|
212
|
+
* @returns {FlatConfigArray} The current instance.
|
213
|
+
* @throws {TypeError} If the config is invalid.
|
214
|
+
*/
|
215
|
+
normalizeSync(context) {
|
216
|
+
|
217
|
+
try {
|
218
|
+
|
219
|
+
return super.normalizeSync(context);
|
220
|
+
|
221
|
+
} catch (error) {
|
222
|
+
|
223
|
+
if (error.name === "ConfigError") {
|
224
|
+
throw wrapConfigErrorWithDetails(error, this[originalLength], this[baseLength]);
|
225
|
+
}
|
226
|
+
|
227
|
+
throw error;
|
228
|
+
|
229
|
+
}
|
230
|
+
|
231
|
+
}
|
232
|
+
|
127
233
|
/* eslint-disable class-methods-use-this -- Desired as instance method */
|
128
234
|
/**
|
129
235
|
* Replaces a config with another config to allow us to put strings
|
@@ -135,15 +241,15 @@ class FlatConfigArray extends ConfigArray {
|
|
135
241
|
[ConfigArraySymbol.preprocessConfig](config) {
|
136
242
|
|
137
243
|
/*
|
138
|
-
* If `
|
139
|
-
*
|
140
|
-
*
|
244
|
+
* If a config object has `ignores` and no other non-meta fields, then it's an object
|
245
|
+
* for global ignores. If `shouldIgnore` is false, that object shouldn't apply,
|
246
|
+
* so we'll remove its `ignores`.
|
141
247
|
*/
|
142
248
|
if (
|
143
249
|
!this.shouldIgnore &&
|
144
250
|
!this[originalBaseConfig].includes(config) &&
|
145
251
|
config.ignores &&
|
146
|
-
|
252
|
+
Object.keys(config).filter(key => !META_FIELDS.has(key)).length === 1
|
147
253
|
) {
|
148
254
|
/* eslint-disable-next-line no-unused-vars -- need to strip off other keys */
|
149
255
|
const { ignores, ...otherKeys } = config;
|
@@ -15,7 +15,6 @@ const fsp = fs.promises;
|
|
15
15
|
const isGlob = require("is-glob");
|
16
16
|
const hash = require("../cli-engine/hash");
|
17
17
|
const minimatch = require("minimatch");
|
18
|
-
const util = require("util");
|
19
18
|
const fswalk = require("@nodelib/fs.walk");
|
20
19
|
const globParent = require("glob-parent");
|
21
20
|
const isPathInside = require("is-path-inside");
|
@@ -24,7 +23,6 @@ const isPathInside = require("is-path-inside");
|
|
24
23
|
// Fixup references
|
25
24
|
//-----------------------------------------------------------------------------
|
26
25
|
|
27
|
-
const doFsWalk = util.promisify(fswalk.walk);
|
28
26
|
const Minimatch = minimatch.Minimatch;
|
29
27
|
const MINIMATCH_OPTIONS = { dot: true };
|
30
28
|
|
@@ -280,56 +278,92 @@ async function globSearch({
|
|
280
278
|
*/
|
281
279
|
const unmatchedPatterns = new Set([...relativeToPatterns.keys()]);
|
282
280
|
|
283
|
-
const filePaths = (await
|
281
|
+
const filePaths = (await new Promise((resolve, reject) => {
|
284
282
|
|
285
|
-
|
286
|
-
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
287
|
-
const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true));
|
288
|
-
|
289
|
-
return matchesPattern && !configs.isDirectoryIgnored(entry.path);
|
290
|
-
},
|
291
|
-
entryFilter(entry) {
|
292
|
-
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
283
|
+
let promiseRejected = false;
|
293
284
|
|
294
|
-
|
295
|
-
|
285
|
+
/**
|
286
|
+
* Wraps a boolean-returning filter function. The wrapped function will reject the promise if an error occurs.
|
287
|
+
* @param {Function} filter A filter function to wrap.
|
288
|
+
* @returns {Function} A function similar to the wrapped filter that rejects the promise if an error occurs.
|
289
|
+
*/
|
290
|
+
function wrapFilter(filter) {
|
291
|
+
return (...args) => {
|
292
|
+
|
293
|
+
// No need to run the filter if an error has been thrown.
|
294
|
+
if (!promiseRejected) {
|
295
|
+
try {
|
296
|
+
return filter(...args);
|
297
|
+
} catch (error) {
|
298
|
+
promiseRejected = true;
|
299
|
+
reject(error);
|
300
|
+
}
|
301
|
+
}
|
296
302
|
return false;
|
297
|
-
}
|
303
|
+
};
|
304
|
+
}
|
298
305
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
306
|
+
fswalk.walk(
|
307
|
+
basePath,
|
308
|
+
{
|
309
|
+
deepFilter: wrapFilter(entry => {
|
310
|
+
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
311
|
+
const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true));
|
312
|
+
|
313
|
+
return matchesPattern && !configs.isDirectoryIgnored(entry.path);
|
314
|
+
}),
|
315
|
+
entryFilter: wrapFilter(entry => {
|
316
|
+
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
317
|
+
|
318
|
+
// entries may be directories or files so filter out directories
|
319
|
+
if (entry.dirent.isDirectory()) {
|
320
|
+
return false;
|
321
|
+
}
|
311
322
|
|
312
323
|
/*
|
313
|
-
* We
|
314
|
-
*
|
315
|
-
*
|
316
|
-
* pattern
|
317
|
-
*
|
318
|
-
*
|
319
|
-
*
|
320
|
-
* it twice with the same argument.
|
324
|
+
* Optimization: We need to track when patterns are left unmatched
|
325
|
+
* and so we use `unmatchedPatterns` to do that. There is a bit of
|
326
|
+
* complexity here because the same file can be matched by more than
|
327
|
+
* one pattern. So, when we start, we actually need to test every
|
328
|
+
* pattern against every file. Once we know there are no remaining
|
329
|
+
* unmatched patterns, then we can switch to just looking for the
|
330
|
+
* first matching pattern for improved speed.
|
321
331
|
*/
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
332
|
+
const matchesPattern = unmatchedPatterns.size > 0
|
333
|
+
? matchers.reduce((previousValue, matcher) => {
|
334
|
+
const pathMatches = matcher.match(relativePath);
|
335
|
+
|
336
|
+
/*
|
337
|
+
* We updated the unmatched patterns set only if the path
|
338
|
+
* matches and the file isn't ignored. If the file is
|
339
|
+
* ignored, that means there wasn't a match for the
|
340
|
+
* pattern so it should not be removed.
|
341
|
+
*
|
342
|
+
* Performance note: isFileIgnored() aggressively caches
|
343
|
+
* results so there is no performance penalty for calling
|
344
|
+
* it twice with the same argument.
|
345
|
+
*/
|
346
|
+
if (pathMatches && !configs.isFileIgnored(entry.path)) {
|
347
|
+
unmatchedPatterns.delete(matcher.pattern);
|
348
|
+
}
|
349
|
+
|
350
|
+
return pathMatches || previousValue;
|
351
|
+
}, false)
|
352
|
+
: matchers.some(matcher => matcher.match(relativePath));
|
353
|
+
|
354
|
+
return matchesPattern && !configs.isFileIgnored(entry.path);
|
355
|
+
})
|
356
|
+
},
|
357
|
+
(error, entries) => {
|
358
|
+
|
359
|
+
// If the promise is already rejected, calling `resolve` or `reject` will do nothing.
|
360
|
+
if (error) {
|
361
|
+
reject(error);
|
362
|
+
} else {
|
363
|
+
resolve(entries);
|
364
|
+
}
|
365
|
+
}
|
366
|
+
);
|
333
367
|
})).map(entry => entry.path);
|
334
368
|
|
335
369
|
// now check to see if we have any unmatched patterns
|
@@ -685,6 +719,7 @@ function processOptions({
|
|
685
719
|
overrideConfig = null,
|
686
720
|
overrideConfigFile = null,
|
687
721
|
plugins = {},
|
722
|
+
stats = false,
|
688
723
|
warnIgnored = true,
|
689
724
|
passOnNoPatterns = false,
|
690
725
|
ruleFilter = () => true,
|
@@ -791,6 +826,9 @@ function processOptions({
|
|
791
826
|
if (Array.isArray(plugins)) {
|
792
827
|
errors.push("'plugins' doesn't add plugins to configuration to load. Please use the 'overrideConfig.plugins' option instead.");
|
793
828
|
}
|
829
|
+
if (typeof stats !== "boolean") {
|
830
|
+
errors.push("'stats' must be a boolean.");
|
831
|
+
}
|
794
832
|
if (typeof warnIgnored !== "boolean") {
|
795
833
|
errors.push("'warnIgnored' must be a boolean.");
|
796
834
|
}
|
@@ -818,6 +856,7 @@ function processOptions({
|
|
818
856
|
globInputPaths,
|
819
857
|
ignore,
|
820
858
|
ignorePatterns,
|
859
|
+
stats,
|
821
860
|
passOnNoPatterns,
|
822
861
|
warnIgnored,
|
823
862
|
ruleFilter
|
package/lib/eslint/eslint.js
CHANGED
@@ -42,6 +42,7 @@ const {
|
|
42
42
|
const { pathToFileURL } = require("url");
|
43
43
|
const { FlatConfigArray } = require("../config/flat-config-array");
|
44
44
|
const LintResultCache = require("../cli-engine/lint-result-cache");
|
45
|
+
const { Retrier } = require("@humanwhocodes/retry");
|
45
46
|
|
46
47
|
/*
|
47
48
|
* This is necessary to allow overwriting writeFile for testing purposes.
|
@@ -84,6 +85,7 @@ const LintResultCache = require("../cli-engine/lint-result-cache");
|
|
84
85
|
* doesn't do any config file lookup when `true`; considered to be a config filename
|
85
86
|
* when a string.
|
86
87
|
* @property {Record<string,Plugin>} [plugins] An array of plugin implementations.
|
88
|
+
* @property {boolean} [stats] True enables added statistics on lint results.
|
87
89
|
* @property {boolean} warnIgnored Show warnings when the file list includes ignored files
|
88
90
|
* @property {boolean} [passOnNoPatterns=false] When set to true, missing patterns cause
|
89
91
|
* the linting operation to short circuit and not report any failures.
|
@@ -465,6 +467,7 @@ async function calculateConfigArray(eslint, {
|
|
465
467
|
* @param {boolean} config.fix If `true` then it does fix.
|
466
468
|
* @param {boolean} config.allowInlineConfig If `true` then it uses directive comments.
|
467
469
|
* @param {Function} config.ruleFilter A predicate function to filter which rules should be run.
|
470
|
+
* @param {boolean} config.stats If `true`, then if reports extra statistics with the lint results.
|
468
471
|
* @param {Linter} config.linter The linter instance to verify.
|
469
472
|
* @returns {LintResult} The result of linting.
|
470
473
|
* @private
|
@@ -477,6 +480,7 @@ function verifyText({
|
|
477
480
|
fix,
|
478
481
|
allowInlineConfig,
|
479
482
|
ruleFilter,
|
483
|
+
stats,
|
480
484
|
linter
|
481
485
|
}) {
|
482
486
|
const filePath = providedFilePath || "<text>";
|
@@ -497,6 +501,7 @@ function verifyText({
|
|
497
501
|
filename: filePathToVerify,
|
498
502
|
fix,
|
499
503
|
ruleFilter,
|
504
|
+
stats,
|
500
505
|
|
501
506
|
/**
|
502
507
|
* Check if the linter should adopt a given code block or not.
|
@@ -528,6 +533,13 @@ function verifyText({
|
|
528
533
|
result.source = text;
|
529
534
|
}
|
530
535
|
|
536
|
+
if (stats) {
|
537
|
+
result.stats = {
|
538
|
+
times: linter.getTimes(),
|
539
|
+
fixPasses: linter.getFixPassCount()
|
540
|
+
};
|
541
|
+
}
|
542
|
+
|
531
543
|
return result;
|
532
544
|
}
|
533
545
|
|
@@ -808,6 +820,7 @@ class ESLint {
|
|
808
820
|
fix,
|
809
821
|
fixTypes,
|
810
822
|
ruleFilter,
|
823
|
+
stats,
|
811
824
|
globInputPaths,
|
812
825
|
errorOnUnmatchedPattern,
|
813
826
|
warnIgnored
|
@@ -839,6 +852,8 @@ class ESLint {
|
|
839
852
|
errorOnUnmatchedPattern
|
840
853
|
});
|
841
854
|
const controller = new AbortController();
|
855
|
+
const retryCodes = new Set(["ENFILE", "EMFILE"]);
|
856
|
+
const retrier = new Retrier(error => retryCodes.has(error.code));
|
842
857
|
|
843
858
|
debug(`${filePaths.length} files found in: ${Date.now() - startTime}ms`);
|
844
859
|
|
@@ -907,7 +922,7 @@ class ESLint {
|
|
907
922
|
fixer = message => shouldMessageBeFixed(message, config, fixTypesSet) && originalFix(message);
|
908
923
|
}
|
909
924
|
|
910
|
-
return fs.readFile(filePath, { encoding: "utf8", signal: controller.signal })
|
925
|
+
return retrier.retry(() => fs.readFile(filePath, { encoding: "utf8", signal: controller.signal })
|
911
926
|
.then(text => {
|
912
927
|
|
913
928
|
// fail immediately if an error occurred in another file
|
@@ -922,6 +937,7 @@ class ESLint {
|
|
922
937
|
fix: fixer,
|
923
938
|
allowInlineConfig,
|
924
939
|
ruleFilter,
|
940
|
+
stats,
|
925
941
|
linter
|
926
942
|
});
|
927
943
|
|
@@ -936,11 +952,11 @@ class ESLint {
|
|
936
952
|
}
|
937
953
|
|
938
954
|
return result;
|
939
|
-
})
|
955
|
+
}))
|
956
|
+
.catch(error => {
|
940
957
|
controller.abort(error);
|
941
958
|
throw error;
|
942
959
|
});
|
943
|
-
|
944
960
|
})
|
945
961
|
);
|
946
962
|
|
@@ -1010,7 +1026,8 @@ class ESLint {
|
|
1010
1026
|
cwd,
|
1011
1027
|
fix,
|
1012
1028
|
warnIgnored: constructorWarnIgnored,
|
1013
|
-
ruleFilter
|
1029
|
+
ruleFilter,
|
1030
|
+
stats
|
1014
1031
|
} = eslintOptions;
|
1015
1032
|
const results = [];
|
1016
1033
|
const startTime = Date.now();
|
@@ -1034,6 +1051,7 @@ class ESLint {
|
|
1034
1051
|
fix,
|
1035
1052
|
allowInlineConfig,
|
1036
1053
|
ruleFilter,
|
1054
|
+
stats,
|
1037
1055
|
linter
|
1038
1056
|
}));
|
1039
1057
|
}
|
@@ -1199,5 +1217,6 @@ async function shouldUseFlatConfig() {
|
|
1199
1217
|
|
1200
1218
|
module.exports = {
|
1201
1219
|
ESLint,
|
1202
|
-
shouldUseFlatConfig
|
1220
|
+
shouldUseFlatConfig,
|
1221
|
+
locateConfigFileToUse
|
1203
1222
|
};
|