eslint 9.0.0 → 9.1.1
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 +3 -3
- package/bin/eslint.js +2 -14
- package/conf/globals.js +1 -0
- package/lib/cli.js +40 -1
- package/lib/config/flat-config-array.js +110 -4
- package/lib/eslint/eslint-helpers.js +79 -45
- package/lib/eslint/eslint.js +8 -4
- package/lib/linter/apply-disable-directives.js +24 -24
- package/lib/linter/linter.js +27 -57
- package/lib/options.js +2 -2
- package/lib/rules/no-constant-condition.js +18 -7
- package/lib/shared/string-utils.js +9 -11
- package/lib/source-code/source-code.js +128 -0
- package/messages/no-config-found.js +1 -1
- package/package.json +8 -7
package/README.md
CHANGED
@@ -48,7 +48,7 @@ Prerequisites: [Node.js](https://nodejs.org/) (`^18.18.0`, `^20.9.0`, or `>=21.1
|
|
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,7 +59,7 @@ 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 `eslint.config.js` or `eslint.config.mjs` 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
64
|
```js
|
65
65
|
import pluginJs from "@eslint/js";
|
@@ -300,7 +300,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
|
|
300
300
|
<!--sponsorsstart-->
|
301
301
|
<h3>Platinum Sponsors</h3>
|
302
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>
|
303
|
-
<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>
|
304
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>
|
305
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>
|
306
306
|
<!--sponsorsend-->
|
package/bin/eslint.js
CHANGED
@@ -140,23 +140,11 @@ ${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" });
|
148
|
-
return;
|
149
|
-
}
|
150
|
-
|
151
|
-
// Call the config inspector if `--inspect-config` is present.
|
152
|
-
if (process.argv.includes("--inspect-config")) {
|
153
|
-
|
154
|
-
console.warn("You can also run this command directly using 'npx @eslint/config-inspector' in the same directory as your configuration file.");
|
155
|
-
|
156
|
-
const spawn = require("cross-spawn");
|
157
|
-
|
158
|
-
spawn.sync("npx", ["@eslint/config-inspector"], { encoding: "utf8", stdio: "inherit" });
|
159
|
-
|
147
|
+
spawn.sync("npm", ["init", "@eslint/config@latest"], { encoding: "utf8", stdio: "inherit" });
|
160
148
|
return;
|
161
149
|
}
|
162
150
|
|
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"),
|
@@ -336,6 +336,27 @@ async function printResults(engine, results, format, outputFile, resultsMeta) {
|
|
336
336
|
*/
|
337
337
|
const cli = {
|
338
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
|
+
|
339
360
|
/**
|
340
361
|
* Executes the CLI based on an array of arguments that is passed in.
|
341
362
|
* @param {string|Array|Object} args The arguments to process.
|
@@ -425,6 +446,24 @@ const cli = {
|
|
425
446
|
return 0;
|
426
447
|
}
|
427
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
|
+
|
428
467
|
debug(`Running on ${useStdin ? "text" : "files"}`);
|
429
468
|
|
430
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
|
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.
|
@@ -851,6 +852,8 @@ class ESLint {
|
|
851
852
|
errorOnUnmatchedPattern
|
852
853
|
});
|
853
854
|
const controller = new AbortController();
|
855
|
+
const retryCodes = new Set(["ENFILE", "EMFILE"]);
|
856
|
+
const retrier = new Retrier(error => retryCodes.has(error.code));
|
854
857
|
|
855
858
|
debug(`${filePaths.length} files found in: ${Date.now() - startTime}ms`);
|
856
859
|
|
@@ -919,7 +922,7 @@ class ESLint {
|
|
919
922
|
fixer = message => shouldMessageBeFixed(message, config, fixTypesSet) && originalFix(message);
|
920
923
|
}
|
921
924
|
|
922
|
-
return fs.readFile(filePath, { encoding: "utf8", signal: controller.signal })
|
925
|
+
return retrier.retry(() => fs.readFile(filePath, { encoding: "utf8", signal: controller.signal })
|
923
926
|
.then(text => {
|
924
927
|
|
925
928
|
// fail immediately if an error occurred in another file
|
@@ -949,11 +952,11 @@ class ESLint {
|
|
949
952
|
}
|
950
953
|
|
951
954
|
return result;
|
952
|
-
})
|
955
|
+
}))
|
956
|
+
.catch(error => {
|
953
957
|
controller.abort(error);
|
954
958
|
throw error;
|
955
959
|
});
|
956
|
-
|
957
960
|
})
|
958
961
|
);
|
959
962
|
|
@@ -1214,5 +1217,6 @@ async function shouldUseFlatConfig() {
|
|
1214
1217
|
|
1215
1218
|
module.exports = {
|
1216
1219
|
ESLint,
|
1217
|
-
shouldUseFlatConfig
|
1220
|
+
shouldUseFlatConfig,
|
1221
|
+
locateConfigFileToUse
|
1218
1222
|
};
|
@@ -38,16 +38,16 @@ function compareLocations(itemA, itemB) {
|
|
38
38
|
* @param {Iterable<Directive>} directives Unused directives to be removed.
|
39
39
|
* @returns {Directive[][]} Directives grouped by their parent comment.
|
40
40
|
*/
|
41
|
-
function
|
41
|
+
function groupByParentDirective(directives) {
|
42
42
|
const groups = new Map();
|
43
43
|
|
44
44
|
for (const directive of directives) {
|
45
|
-
const { unprocessedDirective: {
|
45
|
+
const { unprocessedDirective: { parentDirective } } = directive;
|
46
46
|
|
47
|
-
if (groups.has(
|
48
|
-
groups.get(
|
47
|
+
if (groups.has(parentDirective)) {
|
48
|
+
groups.get(parentDirective).push(directive);
|
49
49
|
} else {
|
50
|
-
groups.set(
|
50
|
+
groups.set(parentDirective, [directive]);
|
51
51
|
}
|
52
52
|
}
|
53
53
|
|
@@ -57,19 +57,19 @@ function groupByParentComment(directives) {
|
|
57
57
|
/**
|
58
58
|
* Creates removal details for a set of directives within the same comment.
|
59
59
|
* @param {Directive[]} directives Unused directives to be removed.
|
60
|
-
* @param {Token}
|
60
|
+
* @param {Token} node The backing Comment token.
|
61
61
|
* @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
|
62
62
|
*/
|
63
|
-
function createIndividualDirectivesRemoval(directives,
|
63
|
+
function createIndividualDirectivesRemoval(directives, node) {
|
64
64
|
|
65
65
|
/*
|
66
|
-
* `
|
66
|
+
* `node.value` starts right after `//` or `/*`.
|
67
67
|
* All calculated offsets will be relative to this index.
|
68
68
|
*/
|
69
|
-
const commentValueStart =
|
69
|
+
const commentValueStart = node.range[0] + "//".length;
|
70
70
|
|
71
71
|
// Find where the list of rules starts. `\S+` matches with the directive name (e.g. `eslint-disable-line`)
|
72
|
-
const listStartOffset = /^\s*\S+\s+/u.exec(
|
72
|
+
const listStartOffset = /^\s*\S+\s+/u.exec(node.value)[0].length;
|
73
73
|
|
74
74
|
/*
|
75
75
|
* Get the list text without any surrounding whitespace. In order to preserve the original
|
@@ -78,7 +78,7 @@ function createIndividualDirectivesRemoval(directives, commentToken) {
|
|
78
78
|
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
79
79
|
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
80
80
|
*/
|
81
|
-
const listText =
|
81
|
+
const listText = node.value
|
82
82
|
.slice(listStartOffset) // remove directive name and all whitespace before the list
|
83
83
|
.split(/\s-{2,}\s/u)[0] // remove `-- comment`, if it exists
|
84
84
|
.trimEnd(); // remove all whitespace after the list
|
@@ -159,13 +159,13 @@ function createIndividualDirectivesRemoval(directives, commentToken) {
|
|
159
159
|
}
|
160
160
|
|
161
161
|
/**
|
162
|
-
* Creates a description of deleting an entire unused disable
|
162
|
+
* Creates a description of deleting an entire unused disable directive.
|
163
163
|
* @param {Directive[]} directives Unused directives to be removed.
|
164
|
-
* @param {Token}
|
165
|
-
* @returns {{ description, fix, unprocessedDirective }} Details for later creation of an output
|
164
|
+
* @param {Token} node The backing Comment token.
|
165
|
+
* @returns {{ description, fix, unprocessedDirective }} Details for later creation of an output problem.
|
166
166
|
*/
|
167
|
-
function
|
168
|
-
const { range } =
|
167
|
+
function createDirectiveRemoval(directives, node) {
|
168
|
+
const { range } = node;
|
169
169
|
const ruleIds = directives.filter(directive => directive.ruleId).map(directive => `'${directive.ruleId}'`);
|
170
170
|
|
171
171
|
return {
|
@@ -186,20 +186,20 @@ function createCommentRemoval(directives, commentToken) {
|
|
186
186
|
* @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
|
187
187
|
*/
|
188
188
|
function processUnusedDirectives(allDirectives) {
|
189
|
-
const directiveGroups =
|
189
|
+
const directiveGroups = groupByParentDirective(allDirectives);
|
190
190
|
|
191
191
|
return directiveGroups.flatMap(
|
192
192
|
directives => {
|
193
|
-
const {
|
194
|
-
const remainingRuleIds = new Set(
|
193
|
+
const { parentDirective } = directives[0].unprocessedDirective;
|
194
|
+
const remainingRuleIds = new Set(parentDirective.ruleIds);
|
195
195
|
|
196
196
|
for (const directive of directives) {
|
197
197
|
remainingRuleIds.delete(directive.ruleId);
|
198
198
|
}
|
199
199
|
|
200
200
|
return remainingRuleIds.size
|
201
|
-
? createIndividualDirectivesRemoval(directives,
|
202
|
-
: [
|
201
|
+
? createIndividualDirectivesRemoval(directives, parentDirective.node)
|
202
|
+
: [createDirectiveRemoval(directives, parentDirective.node)];
|
203
203
|
}
|
204
204
|
);
|
205
205
|
}
|
@@ -372,7 +372,7 @@ function applyDirectives(options) {
|
|
372
372
|
|
373
373
|
const unusedDirectives = processed
|
374
374
|
.map(({ description, fix, unprocessedDirective }) => {
|
375
|
-
const {
|
375
|
+
const { parentDirective, type, line, column } = unprocessedDirective;
|
376
376
|
|
377
377
|
let message;
|
378
378
|
|
@@ -388,8 +388,8 @@ function applyDirectives(options) {
|
|
388
388
|
return {
|
389
389
|
ruleId: null,
|
390
390
|
message,
|
391
|
-
line: type === "disable-next-line" ?
|
392
|
-
column: type === "disable-next-line" ?
|
391
|
+
line: type === "disable-next-line" ? parentDirective.node.loc.start.line : line,
|
392
|
+
column: type === "disable-next-line" ? parentDirective.node.loc.start.column + 1 : column,
|
393
393
|
severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2,
|
394
394
|
nodeType: null,
|
395
395
|
...options.disableFixes ? {} : { fix }
|
package/lib/linter/linter.js
CHANGED
@@ -273,23 +273,21 @@ function createLintingProblem(options) {
|
|
273
273
|
* Creates a collection of disable directives from a comment
|
274
274
|
* @param {Object} options to create disable directives
|
275
275
|
* @param {("disable"|"enable"|"disable-line"|"disable-next-line")} options.type The type of directive comment
|
276
|
-
* @param {token} options.commentToken The Comment token
|
277
276
|
* @param {string} options.value The value after the directive in the comment
|
278
277
|
* comment specified no specific rules, so it applies to all rules (e.g. `eslint-disable`)
|
279
278
|
* @param {string} options.justification The justification of the directive
|
280
|
-
* @param {
|
279
|
+
* @param {ASTNode|token} options.node The Comment node/token.
|
280
|
+
* @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
|
281
281
|
* @returns {Object} Directives and problems from the comment
|
282
282
|
*/
|
283
|
-
function createDisableDirectives(
|
284
|
-
const { commentToken, type, value, justification, ruleMapper } = options;
|
283
|
+
function createDisableDirectives({ type, value, justification, node }, ruleMapper) {
|
285
284
|
const ruleIds = Object.keys(commentParser.parseListConfig(value));
|
286
285
|
const directiveRules = ruleIds.length ? ruleIds : [null];
|
287
286
|
const result = {
|
288
287
|
directives: [], // valid disable directives
|
289
288
|
directiveProblems: [] // problems in directives
|
290
289
|
};
|
291
|
-
|
292
|
-
const parentComment = { commentToken, ruleIds };
|
290
|
+
const parentDirective = { node, ruleIds };
|
293
291
|
|
294
292
|
for (const ruleId of directiveRules) {
|
295
293
|
|
@@ -297,25 +295,25 @@ function createDisableDirectives(options) {
|
|
297
295
|
if (ruleId === null || !!ruleMapper(ruleId)) {
|
298
296
|
if (type === "disable-next-line") {
|
299
297
|
result.directives.push({
|
300
|
-
|
298
|
+
parentDirective,
|
301
299
|
type,
|
302
|
-
line:
|
303
|
-
column:
|
300
|
+
line: node.loc.end.line,
|
301
|
+
column: node.loc.end.column + 1,
|
304
302
|
ruleId,
|
305
303
|
justification
|
306
304
|
});
|
307
305
|
} else {
|
308
306
|
result.directives.push({
|
309
|
-
|
307
|
+
parentDirective,
|
310
308
|
type,
|
311
|
-
line:
|
312
|
-
column:
|
309
|
+
line: node.loc.start.line,
|
310
|
+
column: node.loc.start.column + 1,
|
313
311
|
ruleId,
|
314
312
|
justification
|
315
313
|
});
|
316
314
|
}
|
317
315
|
} else {
|
318
|
-
result.directiveProblems.push(createLintingProblem({ ruleId, loc:
|
316
|
+
result.directiveProblems.push(createLintingProblem({ ruleId, loc: node.loc }));
|
319
317
|
}
|
320
318
|
}
|
321
319
|
return result;
|
@@ -388,8 +386,12 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig, config)
|
|
388
386
|
case "eslint-disable-next-line":
|
389
387
|
case "eslint-disable-line": {
|
390
388
|
const directiveType = directiveText.slice("eslint-".length);
|
391
|
-
const
|
392
|
-
|
389
|
+
const { directives, directiveProblems } = createDisableDirectives({
|
390
|
+
type: directiveType,
|
391
|
+
value: directiveValue,
|
392
|
+
justification: justificationPart,
|
393
|
+
node: comment
|
394
|
+
}, ruleMapper);
|
393
395
|
|
394
396
|
disableDirectives.push(...directives);
|
395
397
|
problems.push(...directiveProblems);
|
@@ -543,53 +545,21 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig, config)
|
|
543
545
|
* A collection of the directive comments that were found, along with any problems that occurred when parsing
|
544
546
|
*/
|
545
547
|
function getDirectiveCommentsForFlatConfig(sourceCode, ruleMapper) {
|
546
|
-
const problems = [];
|
547
548
|
const disableDirectives = [];
|
549
|
+
const problems = [];
|
548
550
|
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
if (!match) {
|
555
|
-
return;
|
556
|
-
}
|
557
|
-
const directiveText = match[1];
|
558
|
-
const lineCommentSupported = /^eslint-disable-(next-)?line$/u.test(directiveText);
|
559
|
-
|
560
|
-
if (comment.type === "Line" && !lineCommentSupported) {
|
561
|
-
return;
|
562
|
-
}
|
563
|
-
|
564
|
-
if (directiveText === "eslint-disable-line" && comment.loc.start.line !== comment.loc.end.line) {
|
565
|
-
const message = `${directiveText} comment should not span multiple lines.`;
|
566
|
-
|
567
|
-
problems.push(createLintingProblem({
|
568
|
-
ruleId: null,
|
569
|
-
message,
|
570
|
-
loc: comment.loc
|
571
|
-
}));
|
572
|
-
return;
|
573
|
-
}
|
574
|
-
|
575
|
-
const directiveValue = directivePart.slice(match.index + directiveText.length);
|
551
|
+
const {
|
552
|
+
directives: directivesSources,
|
553
|
+
problems: directivesProblems
|
554
|
+
} = sourceCode.getDisableDirectives();
|
576
555
|
|
577
|
-
|
578
|
-
case "eslint-disable":
|
579
|
-
case "eslint-enable":
|
580
|
-
case "eslint-disable-next-line":
|
581
|
-
case "eslint-disable-line": {
|
582
|
-
const directiveType = directiveText.slice("eslint-".length);
|
583
|
-
const options = { commentToken: comment, type: directiveType, value: directiveValue, justification: justificationPart, ruleMapper };
|
584
|
-
const { directives, directiveProblems } = createDisableDirectives(options);
|
556
|
+
problems.push(...directivesProblems.map(createLintingProblem));
|
585
557
|
|
586
|
-
|
587
|
-
|
588
|
-
break;
|
589
|
-
}
|
558
|
+
directivesSources.forEach(directive => {
|
559
|
+
const { directives, directiveProblems } = createDisableDirectives(directive, ruleMapper);
|
590
560
|
|
591
|
-
|
592
|
-
|
561
|
+
disableDirectives.push(...directives);
|
562
|
+
problems.push(...directiveProblems);
|
593
563
|
});
|
594
564
|
|
595
565
|
return {
|
package/lib/options.js
CHANGED
@@ -38,7 +38,7 @@ const optionator = require("optionator");
|
|
38
38
|
* @property {boolean} [help] Show help
|
39
39
|
* @property {boolean} ignore Disable use of ignore files and patterns
|
40
40
|
* @property {string} [ignorePath] Specify path of ignore file
|
41
|
-
* @property {string[]} [ignorePattern]
|
41
|
+
* @property {string[]} [ignorePattern] Patterns of files to ignore. In eslintrc mode, these are in addition to `.eslintignore`
|
42
42
|
* @property {boolean} init Run config initialization wizard
|
43
43
|
* @property {boolean} inlineConfig Prevent comments from changing config or rules
|
44
44
|
* @property {number} maxWarnings Number of warnings to trigger nonzero exit code
|
@@ -261,7 +261,7 @@ module.exports = function(usingFlatConfig) {
|
|
261
261
|
{
|
262
262
|
option: "ignore-pattern",
|
263
263
|
type: "[String]",
|
264
|
-
description:
|
264
|
+
description: `Patterns of files to ignore${usingFlatConfig ? "" : " (in addition to those in .eslintignore)"}`,
|
265
265
|
concatRepeatedArrays: [true, {
|
266
266
|
oneValuePerFlag: true
|
267
267
|
}]
|
@@ -31,8 +31,7 @@ module.exports = {
|
|
31
31
|
type: "object",
|
32
32
|
properties: {
|
33
33
|
checkLoops: {
|
34
|
-
|
35
|
-
default: true
|
34
|
+
enum: ["all", "allExceptWhileTrue", "none", true, false]
|
36
35
|
}
|
37
36
|
},
|
38
37
|
additionalProperties: false
|
@@ -45,11 +44,17 @@ module.exports = {
|
|
45
44
|
},
|
46
45
|
|
47
46
|
create(context) {
|
48
|
-
const options = context.options[0] || {}
|
49
|
-
|
50
|
-
|
47
|
+
const options = context.options[0] || {};
|
48
|
+
let checkLoops = options.checkLoops ?? "allExceptWhileTrue";
|
49
|
+
const loopSetStack = [];
|
51
50
|
const sourceCode = context.sourceCode;
|
52
51
|
|
52
|
+
if (options.checkLoops === true) {
|
53
|
+
checkLoops = "all";
|
54
|
+
} else if (options.checkLoops === false) {
|
55
|
+
checkLoops = "none";
|
56
|
+
}
|
57
|
+
|
53
58
|
let loopsInCurrentScope = new Set();
|
54
59
|
|
55
60
|
//--------------------------------------------------------------------------
|
@@ -120,7 +125,7 @@ module.exports = {
|
|
120
125
|
* @private
|
121
126
|
*/
|
122
127
|
function checkLoop(node) {
|
123
|
-
if (checkLoops) {
|
128
|
+
if (checkLoops === "all" || checkLoops === "allExceptWhileTrue") {
|
124
129
|
trackConstantConditionLoop(node);
|
125
130
|
}
|
126
131
|
}
|
@@ -132,7 +137,13 @@ module.exports = {
|
|
132
137
|
return {
|
133
138
|
ConditionalExpression: reportIfConstant,
|
134
139
|
IfStatement: reportIfConstant,
|
135
|
-
WhileStatement
|
140
|
+
WhileStatement(node) {
|
141
|
+
if (node.test.type === "Literal" && node.test.value === true && checkLoops === "allExceptWhileTrue") {
|
142
|
+
return;
|
143
|
+
}
|
144
|
+
|
145
|
+
checkLoop(node);
|
146
|
+
},
|
136
147
|
"WhileStatement:exit": checkConstantConditionLoopInSet,
|
137
148
|
DoWhileStatement: checkLoop,
|
138
149
|
"DoWhileStatement:exit": checkConstantConditionLoopInSet,
|
@@ -5,12 +5,6 @@
|
|
5
5
|
|
6
6
|
"use strict";
|
7
7
|
|
8
|
-
//------------------------------------------------------------------------------
|
9
|
-
// Requirements
|
10
|
-
//------------------------------------------------------------------------------
|
11
|
-
|
12
|
-
const Graphemer = require("graphemer").default;
|
13
|
-
|
14
8
|
//------------------------------------------------------------------------------
|
15
9
|
// Helpers
|
16
10
|
//------------------------------------------------------------------------------
|
@@ -18,8 +12,8 @@ const Graphemer = require("graphemer").default;
|
|
18
12
|
// eslint-disable-next-line no-control-regex -- intentionally including control characters
|
19
13
|
const ASCII_REGEX = /^[\u0000-\u007f]*$/u;
|
20
14
|
|
21
|
-
/** @type {
|
22
|
-
let
|
15
|
+
/** @type {Intl.Segmenter | undefined} */
|
16
|
+
let segmenter;
|
23
17
|
|
24
18
|
//------------------------------------------------------------------------------
|
25
19
|
// Public Interface
|
@@ -47,11 +41,15 @@ function getGraphemeCount(value) {
|
|
47
41
|
return value.length;
|
48
42
|
}
|
49
43
|
|
50
|
-
|
51
|
-
|
44
|
+
segmenter ??= new Intl.Segmenter("en-US"); // en-US locale should be supported everywhere
|
45
|
+
let graphemeCount = 0;
|
46
|
+
|
47
|
+
// eslint-disable-next-line no-unused-vars -- for-of needs a variable
|
48
|
+
for (const unused of segmenter.segment(value)) {
|
49
|
+
graphemeCount++;
|
52
50
|
}
|
53
51
|
|
54
|
-
return
|
52
|
+
return graphemeCount;
|
55
53
|
}
|
56
54
|
|
57
55
|
module.exports = {
|
@@ -373,6 +373,56 @@ class TraversalStep {
|
|
373
373
|
}
|
374
374
|
}
|
375
375
|
|
376
|
+
/**
|
377
|
+
* A class to represent a directive comment.
|
378
|
+
*/
|
379
|
+
class Directive {
|
380
|
+
|
381
|
+
/**
|
382
|
+
* The type of directive.
|
383
|
+
* @type {"disable"|"enable"|"disable-next-line"|"disable-line"}
|
384
|
+
* @readonly
|
385
|
+
*/
|
386
|
+
type;
|
387
|
+
|
388
|
+
/**
|
389
|
+
* The node representing the directive.
|
390
|
+
* @type {ASTNode|Comment}
|
391
|
+
* @readonly
|
392
|
+
*/
|
393
|
+
node;
|
394
|
+
|
395
|
+
/**
|
396
|
+
* Everything after the "eslint-disable" portion of the directive,
|
397
|
+
* but before the "--" that indicates the justification.
|
398
|
+
* @type {string}
|
399
|
+
* @readonly
|
400
|
+
*/
|
401
|
+
value;
|
402
|
+
|
403
|
+
/**
|
404
|
+
* The justification for the directive.
|
405
|
+
* @type {string}
|
406
|
+
* @readonly
|
407
|
+
*/
|
408
|
+
justification;
|
409
|
+
|
410
|
+
/**
|
411
|
+
* Creates a new instance.
|
412
|
+
* @param {Object} options The options for the directive.
|
413
|
+
* @param {"disable"|"enable"|"disable-next-line"|"disable-line"} options.type The type of directive.
|
414
|
+
* @param {ASTNode|Comment} options.node The node representing the directive.
|
415
|
+
* @param {string} options.value The value of the directive.
|
416
|
+
* @param {string} options.justification The justification for the directive.
|
417
|
+
*/
|
418
|
+
constructor({ type, node, value, justification }) {
|
419
|
+
this.type = type;
|
420
|
+
this.node = node;
|
421
|
+
this.value = value;
|
422
|
+
this.justification = justification;
|
423
|
+
}
|
424
|
+
}
|
425
|
+
|
376
426
|
//------------------------------------------------------------------------------
|
377
427
|
// Public Interface
|
378
428
|
//------------------------------------------------------------------------------
|
@@ -921,6 +971,84 @@ class SourceCode extends TokenStore {
|
|
921
971
|
return configNodes;
|
922
972
|
}
|
923
973
|
|
974
|
+
/**
|
975
|
+
* Returns an all directive nodes that enable or disable rules along with any problems
|
976
|
+
* encountered while parsing the directives.
|
977
|
+
* @returns {{problems:Array<Problem>,directives:Array<Directive>}} Information
|
978
|
+
* that ESLint needs to further process the directives.
|
979
|
+
*/
|
980
|
+
getDisableDirectives() {
|
981
|
+
|
982
|
+
// check the cache first
|
983
|
+
const cachedDirectives = this[caches].get("disableDirectives");
|
984
|
+
|
985
|
+
if (cachedDirectives) {
|
986
|
+
return cachedDirectives;
|
987
|
+
}
|
988
|
+
|
989
|
+
const problems = [];
|
990
|
+
const directives = [];
|
991
|
+
|
992
|
+
this.getInlineConfigNodes().forEach(comment => {
|
993
|
+
const { directivePart, justificationPart } = commentParser.extractDirectiveComment(comment.value);
|
994
|
+
|
995
|
+
// Step 1: Extract the directive text
|
996
|
+
const match = directivesPattern.exec(directivePart);
|
997
|
+
|
998
|
+
if (!match) {
|
999
|
+
return;
|
1000
|
+
}
|
1001
|
+
|
1002
|
+
const directiveText = match[1];
|
1003
|
+
|
1004
|
+
// Step 2: Extract the directive value
|
1005
|
+
const lineCommentSupported = /^eslint-disable-(next-)?line$/u.test(directiveText);
|
1006
|
+
|
1007
|
+
if (comment.type === "Line" && !lineCommentSupported) {
|
1008
|
+
return;
|
1009
|
+
}
|
1010
|
+
|
1011
|
+
// Step 3: Validate the directive does not span multiple lines
|
1012
|
+
if (directiveText === "eslint-disable-line" && comment.loc.start.line !== comment.loc.end.line) {
|
1013
|
+
const message = `${directiveText} comment should not span multiple lines.`;
|
1014
|
+
|
1015
|
+
problems.push({
|
1016
|
+
ruleId: null,
|
1017
|
+
message,
|
1018
|
+
loc: comment.loc
|
1019
|
+
});
|
1020
|
+
return;
|
1021
|
+
}
|
1022
|
+
|
1023
|
+
// Step 4: Extract the directive value and create the Directive object
|
1024
|
+
const directiveValue = directivePart.slice(match.index + directiveText.length);
|
1025
|
+
|
1026
|
+
switch (directiveText) {
|
1027
|
+
case "eslint-disable":
|
1028
|
+
case "eslint-enable":
|
1029
|
+
case "eslint-disable-next-line":
|
1030
|
+
case "eslint-disable-line": {
|
1031
|
+
const directiveType = directiveText.slice("eslint-".length);
|
1032
|
+
|
1033
|
+
directives.push(new Directive({
|
1034
|
+
type: directiveType,
|
1035
|
+
node: comment,
|
1036
|
+
value: directiveValue,
|
1037
|
+
justification: justificationPart
|
1038
|
+
}));
|
1039
|
+
}
|
1040
|
+
|
1041
|
+
// no default
|
1042
|
+
}
|
1043
|
+
});
|
1044
|
+
|
1045
|
+
const result = { problems, directives };
|
1046
|
+
|
1047
|
+
this[caches].set("disableDirectives", result);
|
1048
|
+
|
1049
|
+
return result;
|
1050
|
+
}
|
1051
|
+
|
924
1052
|
/**
|
925
1053
|
* Applies language options sent in from the core.
|
926
1054
|
* @param {Object} languageOptions The language options for this run.
|
@@ -6,7 +6,7 @@ module.exports = function(it) {
|
|
6
6
|
return `
|
7
7
|
ESLint couldn't find a configuration file. To set up a configuration file for this project, please run:
|
8
8
|
|
9
|
-
npm init @eslint/config
|
9
|
+
npm init @eslint/config@latest
|
10
10
|
|
11
11
|
ESLint looked for configuration files in ${directoryPath} and its ancestors. If it found none, it then looked in your home directory.
|
12
12
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "9.
|
3
|
+
"version": "9.1.1",
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
6
6
|
"bin": {
|
@@ -33,7 +33,8 @@
|
|
33
33
|
"test:browser": "node Makefile.js wdio",
|
34
34
|
"test:cli": "mocha",
|
35
35
|
"test:fuzz": "node Makefile.js fuzz",
|
36
|
-
"test:performance": "node Makefile.js perf"
|
36
|
+
"test:performance": "node Makefile.js perf",
|
37
|
+
"test:emfile": "node tools/check-emfile-handling.js"
|
37
38
|
},
|
38
39
|
"gitHooks": {
|
39
40
|
"pre-commit": "lint-staged"
|
@@ -68,9 +69,10 @@
|
|
68
69
|
"@eslint-community/eslint-utils": "^4.2.0",
|
69
70
|
"@eslint-community/regexpp": "^4.6.1",
|
70
71
|
"@eslint/eslintrc": "^3.0.2",
|
71
|
-
"@eslint/js": "9.
|
72
|
-
"@humanwhocodes/config-array": "^0.
|
72
|
+
"@eslint/js": "9.1.1",
|
73
|
+
"@humanwhocodes/config-array": "^0.13.0",
|
73
74
|
"@humanwhocodes/module-importer": "^1.0.1",
|
75
|
+
"@humanwhocodes/retry": "^0.2.3",
|
74
76
|
"@nodelib/fs.walk": "^1.2.8",
|
75
77
|
"ajv": "^6.12.4",
|
76
78
|
"chalk": "^4.0.0",
|
@@ -86,7 +88,6 @@
|
|
86
88
|
"file-entry-cache": "^8.0.0",
|
87
89
|
"find-up": "^5.0.0",
|
88
90
|
"glob-parent": "^6.0.2",
|
89
|
-
"graphemer": "^1.4.0",
|
90
91
|
"ignore": "^5.2.0",
|
91
92
|
"imurmurhash": "^0.1.4",
|
92
93
|
"is-glob": "^4.0.0",
|
@@ -120,7 +121,7 @@
|
|
120
121
|
"eslint": "file:.",
|
121
122
|
"eslint-config-eslint": "file:packages/eslint-config-eslint",
|
122
123
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
123
|
-
"eslint-plugin-eslint-plugin": "^
|
124
|
+
"eslint-plugin-eslint-plugin": "^6.0.0",
|
124
125
|
"eslint-plugin-internal-rules": "file:tools/internal-rules",
|
125
126
|
"eslint-plugin-jsdoc": "^46.9.0",
|
126
127
|
"eslint-plugin-n": "^16.6.0",
|
@@ -131,7 +132,7 @@
|
|
131
132
|
"fast-glob": "^3.2.11",
|
132
133
|
"fs-teardown": "^0.1.3",
|
133
134
|
"glob": "^10.0.0",
|
134
|
-
"globals": "^
|
135
|
+
"globals": "^15.0.0",
|
135
136
|
"got": "^11.8.3",
|
136
137
|
"gray-matter": "^4.0.3",
|
137
138
|
"js-yaml": "^4.1.0",
|