eslint 8.22.0 → 8.33.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 +51 -45
- package/bin/eslint.js +2 -4
- package/conf/globals.js +6 -1
- package/conf/rule-type-list.json +2 -2
- package/lib/cli-engine/file-enumerator.js +4 -2
- package/lib/cli-engine/formatters/formatters-meta.json +46 -0
- package/lib/cli-engine/formatters/html.js +76 -51
- package/lib/cli.js +163 -40
- package/lib/config/default-config.js +2 -2
- package/lib/config/flat-config-array.js +1 -1
- package/lib/eslint/eslint-helpers.js +409 -87
- package/lib/eslint/eslint.js +5 -2
- package/lib/eslint/flat-eslint.js +113 -110
- package/lib/linter/code-path-analysis/code-path-segment.js +2 -2
- package/lib/linter/code-path-analysis/code-path-state.js +7 -7
- package/lib/linter/code-path-analysis/debug-helpers.js +3 -3
- package/lib/linter/code-path-analysis/id-generator.js +2 -2
- package/lib/linter/config-comment-parser.js +1 -2
- package/lib/linter/linter.js +17 -7
- package/lib/linter/timing.js +4 -4
- package/lib/options.js +293 -239
- package/lib/rule-tester/flat-rule-tester.js +13 -11
- package/lib/rule-tester/rule-tester.js +15 -11
- package/lib/rules/array-callback-return.js +2 -2
- package/lib/rules/comma-dangle.js +3 -3
- package/lib/rules/for-direction.js +1 -1
- package/lib/rules/func-name-matching.js +2 -2
- package/lib/rules/getter-return.js +14 -8
- package/lib/rules/global-require.js +2 -1
- package/lib/rules/id-length.js +43 -2
- package/lib/rules/indent-legacy.js +4 -4
- package/lib/rules/indent.js +23 -15
- package/lib/rules/index.js +3 -0
- package/lib/rules/key-spacing.js +50 -38
- package/lib/rules/lines-around-comment.js +2 -2
- package/lib/rules/logical-assignment-operators.js +474 -0
- package/lib/rules/multiline-ternary.js +2 -2
- package/lib/rules/new-cap.js +2 -2
- package/lib/rules/no-else-return.js +1 -1
- package/lib/rules/no-empty-static-block.js +47 -0
- package/lib/rules/no-empty.js +19 -2
- package/lib/rules/no-extra-boolean-cast.js +1 -1
- package/lib/rules/no-extra-parens.js +18 -3
- package/lib/rules/no-fallthrough.js +26 -5
- package/lib/rules/no-implicit-coercion.js +20 -1
- package/lib/rules/no-implicit-globals.js +5 -0
- package/lib/rules/no-invalid-regexp.js +40 -18
- package/lib/rules/no-labels.js +1 -1
- package/lib/rules/no-lone-blocks.js +1 -1
- package/lib/rules/no-loss-of-precision.js +2 -2
- package/lib/rules/no-magic-numbers.js +18 -1
- package/lib/rules/no-misleading-character-class.js +4 -4
- package/lib/rules/no-new-native-nonconstructor.js +64 -0
- package/lib/rules/no-obj-calls.js +1 -1
- package/lib/rules/no-restricted-exports.js +106 -10
- package/lib/rules/no-return-await.js +28 -1
- package/lib/rules/no-underscore-dangle.js +36 -11
- package/lib/rules/no-unneeded-ternary.js +1 -1
- package/lib/rules/no-use-before-define.js +1 -1
- package/lib/rules/no-useless-computed-key.js +1 -1
- package/lib/rules/no-var.js +2 -2
- package/lib/rules/no-warning-comments.js +24 -5
- package/lib/rules/padded-blocks.js +1 -1
- package/lib/rules/prefer-arrow-callback.js +4 -3
- package/lib/rules/prefer-const.js +13 -1
- package/lib/rules/prefer-named-capture-group.js +71 -6
- package/lib/rules/prefer-object-spread.js +1 -1
- package/lib/rules/prefer-regex-literals.js +147 -32
- package/lib/rules/prefer-rest-params.js +1 -1
- package/lib/rules/require-yield.js +0 -1
- package/lib/rules/strict.js +1 -1
- package/lib/rules/utils/ast-utils.js +10 -4
- package/lib/shared/directives.js +15 -0
- package/lib/shared/logging.js +1 -1
- package/lib/shared/runtime-info.js +1 -1
- package/lib/shared/traverser.js +1 -1
- package/lib/shared/types.js +15 -2
- package/lib/source-code/token-store/cursor.js +1 -1
- package/messages/print-config-with-directory-path.js +1 -1
- package/package.json +27 -27
@@ -13,8 +13,31 @@ const path = require("path");
|
|
13
13
|
const fs = require("fs");
|
14
14
|
const fsp = fs.promises;
|
15
15
|
const isGlob = require("is-glob");
|
16
|
-
const globby = require("globby");
|
17
16
|
const hash = require("../cli-engine/hash");
|
17
|
+
const minimatch = require("minimatch");
|
18
|
+
const util = require("util");
|
19
|
+
const fswalk = require("@nodelib/fs.walk");
|
20
|
+
const globParent = require("glob-parent");
|
21
|
+
const isPathInside = require("is-path-inside");
|
22
|
+
|
23
|
+
//-----------------------------------------------------------------------------
|
24
|
+
// Fixup references
|
25
|
+
//-----------------------------------------------------------------------------
|
26
|
+
|
27
|
+
const doFsWalk = util.promisify(fswalk.walk);
|
28
|
+
const Minimatch = minimatch.Minimatch;
|
29
|
+
const MINIMATCH_OPTIONS = { dot: true };
|
30
|
+
|
31
|
+
//-----------------------------------------------------------------------------
|
32
|
+
// Types
|
33
|
+
//-----------------------------------------------------------------------------
|
34
|
+
|
35
|
+
/**
|
36
|
+
* @typedef {Object} GlobSearch
|
37
|
+
* @property {Array<string>} patterns The normalized patterns to use for a search.
|
38
|
+
* @property {Array<string>} rawPatterns The patterns as entered by the user
|
39
|
+
* before doing any normalization.
|
40
|
+
*/
|
18
41
|
|
19
42
|
//-----------------------------------------------------------------------------
|
20
43
|
// Errors
|
@@ -36,6 +59,30 @@ class NoFilesFoundError extends Error {
|
|
36
59
|
}
|
37
60
|
}
|
38
61
|
|
62
|
+
/**
|
63
|
+
* The error type when a search fails to match multiple patterns.
|
64
|
+
*/
|
65
|
+
class UnmatchedSearchPatternsError extends Error {
|
66
|
+
|
67
|
+
/**
|
68
|
+
* @param {Object} options The options for the error.
|
69
|
+
* @param {string} options.basePath The directory that was searched.
|
70
|
+
* @param {Array<string>} options.unmatchedPatterns The glob patterns
|
71
|
+
* which were not found.
|
72
|
+
* @param {Array<string>} options.patterns The glob patterns that were
|
73
|
+
* searched.
|
74
|
+
* @param {Array<string>} options.rawPatterns The raw glob patterns that
|
75
|
+
* were searched.
|
76
|
+
*/
|
77
|
+
constructor({ basePath, unmatchedPatterns, patterns, rawPatterns }) {
|
78
|
+
super(`No files matching '${rawPatterns}' in '${basePath}' were found.`);
|
79
|
+
this.basePath = basePath;
|
80
|
+
this.unmatchedPatterns = unmatchedPatterns;
|
81
|
+
this.patterns = patterns;
|
82
|
+
this.rawPatterns = rawPatterns;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
39
86
|
/**
|
40
87
|
* The error type when there are files matched by a glob, but all of them have been ignored.
|
41
88
|
*/
|
@@ -66,9 +113,9 @@ function isNonEmptyString(x) {
|
|
66
113
|
}
|
67
114
|
|
68
115
|
/**
|
69
|
-
* Check if a given value is an array of non-empty
|
116
|
+
* Check if a given value is an array of non-empty strings or not.
|
70
117
|
* @param {any} x The value to check.
|
71
|
-
* @returns {boolean} `true` if `x` is an array of non-empty
|
118
|
+
* @returns {boolean} `true` if `x` is an array of non-empty strings.
|
72
119
|
*/
|
73
120
|
function isArrayOfNonEmptyString(x) {
|
74
121
|
return Array.isArray(x) && x.every(isNonEmptyString);
|
@@ -96,6 +143,317 @@ function isGlobPattern(pattern) {
|
|
96
143
|
return isGlob(path.sep === "\\" ? normalizeToPosix(pattern) : pattern);
|
97
144
|
}
|
98
145
|
|
146
|
+
|
147
|
+
/**
|
148
|
+
* Determines if a given glob pattern will return any results.
|
149
|
+
* Used primarily to help with useful error messages.
|
150
|
+
* @param {Object} options The options for the function.
|
151
|
+
* @param {string} options.basePath The directory to search.
|
152
|
+
* @param {string} options.pattern A glob pattern to match.
|
153
|
+
* @returns {Promise<boolean>} True if there is a glob match, false if not.
|
154
|
+
*/
|
155
|
+
function globMatch({ basePath, pattern }) {
|
156
|
+
|
157
|
+
let found = false;
|
158
|
+
const patternToUse = path.isAbsolute(pattern)
|
159
|
+
? normalizeToPosix(path.relative(basePath, pattern))
|
160
|
+
: pattern;
|
161
|
+
|
162
|
+
const matcher = new Minimatch(patternToUse, MINIMATCH_OPTIONS);
|
163
|
+
|
164
|
+
const fsWalkSettings = {
|
165
|
+
|
166
|
+
deepFilter(entry) {
|
167
|
+
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
168
|
+
|
169
|
+
return !found && matcher.match(relativePath, true);
|
170
|
+
},
|
171
|
+
|
172
|
+
entryFilter(entry) {
|
173
|
+
if (found || entry.dirent.isDirectory()) {
|
174
|
+
return false;
|
175
|
+
}
|
176
|
+
|
177
|
+
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
178
|
+
|
179
|
+
if (matcher.match(relativePath)) {
|
180
|
+
found = true;
|
181
|
+
return true;
|
182
|
+
}
|
183
|
+
|
184
|
+
return false;
|
185
|
+
}
|
186
|
+
};
|
187
|
+
|
188
|
+
return new Promise(resolve => {
|
189
|
+
|
190
|
+
// using a stream so we can exit early because we just need one match
|
191
|
+
const globStream = fswalk.walkStream(basePath, fsWalkSettings);
|
192
|
+
|
193
|
+
globStream.on("data", () => {
|
194
|
+
globStream.destroy();
|
195
|
+
resolve(true);
|
196
|
+
});
|
197
|
+
|
198
|
+
// swallow errors as they're not important here
|
199
|
+
globStream.on("error", () => { });
|
200
|
+
|
201
|
+
globStream.on("end", () => {
|
202
|
+
resolve(false);
|
203
|
+
});
|
204
|
+
globStream.read();
|
205
|
+
});
|
206
|
+
|
207
|
+
}
|
208
|
+
|
209
|
+
/**
|
210
|
+
* Searches a directory looking for matching glob patterns. This uses
|
211
|
+
* the config array's logic to determine if a directory or file should
|
212
|
+
* be ignored, so it is consistent with how ignoring works throughout
|
213
|
+
* ESLint.
|
214
|
+
* @param {Object} options The options for this function.
|
215
|
+
* @param {string} options.basePath The directory to search.
|
216
|
+
* @param {Array<string>} options.patterns An array of glob patterns
|
217
|
+
* to match.
|
218
|
+
* @param {Array<string>} options.rawPatterns An array of glob patterns
|
219
|
+
* as the user inputted them. Used for errors.
|
220
|
+
* @param {FlatConfigArray} options.configs The config array to use for
|
221
|
+
* determining what to ignore.
|
222
|
+
* @param {boolean} options.errorOnUnmatchedPattern Determines if an error
|
223
|
+
* should be thrown when a pattern is unmatched.
|
224
|
+
* @returns {Promise<Array<string>>} An array of matching file paths
|
225
|
+
* or an empty array if there are no matches.
|
226
|
+
* @throws {UnmatchedSearchPatternsErrror} If there is a pattern that doesn't
|
227
|
+
* match any files.
|
228
|
+
*/
|
229
|
+
async function globSearch({
|
230
|
+
basePath,
|
231
|
+
patterns,
|
232
|
+
rawPatterns,
|
233
|
+
configs,
|
234
|
+
errorOnUnmatchedPattern
|
235
|
+
}) {
|
236
|
+
|
237
|
+
if (patterns.length === 0) {
|
238
|
+
return [];
|
239
|
+
}
|
240
|
+
|
241
|
+
/*
|
242
|
+
* In this section we are converting the patterns into Minimatch
|
243
|
+
* instances for performance reasons. Because we are doing the same
|
244
|
+
* matches repeatedly, it's best to compile those patterns once and
|
245
|
+
* reuse them multiple times.
|
246
|
+
*
|
247
|
+
* To do that, we convert any patterns with an absolute path into a
|
248
|
+
* relative path and normalize it to Posix-style slashes. We also keep
|
249
|
+
* track of the relative patterns to map them back to the original
|
250
|
+
* patterns, which we need in order to throw an error if there are any
|
251
|
+
* unmatched patterns.
|
252
|
+
*/
|
253
|
+
const relativeToPatterns = new Map();
|
254
|
+
const matchers = patterns.map((pattern, i) => {
|
255
|
+
const patternToUse = path.isAbsolute(pattern)
|
256
|
+
? normalizeToPosix(path.relative(basePath, pattern))
|
257
|
+
: pattern;
|
258
|
+
|
259
|
+
relativeToPatterns.set(patternToUse, patterns[i]);
|
260
|
+
|
261
|
+
return new Minimatch(patternToUse, MINIMATCH_OPTIONS);
|
262
|
+
});
|
263
|
+
|
264
|
+
/*
|
265
|
+
* We track unmatched patterns because we may want to throw an error when
|
266
|
+
* they occur. To start, this set is initialized with all of the patterns.
|
267
|
+
* Every time a match occurs, the pattern is removed from the set, making
|
268
|
+
* it easy to tell if we have any unmatched patterns left at the end of
|
269
|
+
* search.
|
270
|
+
*/
|
271
|
+
const unmatchedPatterns = new Set([...relativeToPatterns.keys()]);
|
272
|
+
|
273
|
+
const filePaths = (await doFsWalk(basePath, {
|
274
|
+
|
275
|
+
deepFilter(entry) {
|
276
|
+
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
277
|
+
const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true));
|
278
|
+
|
279
|
+
return matchesPattern && !configs.isDirectoryIgnored(entry.path);
|
280
|
+
},
|
281
|
+
entryFilter(entry) {
|
282
|
+
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
283
|
+
|
284
|
+
// entries may be directories or files so filter out directories
|
285
|
+
if (entry.dirent.isDirectory()) {
|
286
|
+
return false;
|
287
|
+
}
|
288
|
+
|
289
|
+
/*
|
290
|
+
* Optimization: We need to track when patterns are left unmatched
|
291
|
+
* and so we use `unmatchedPatterns` to do that. There is a bit of
|
292
|
+
* complexity here because the same file can be matched by more than
|
293
|
+
* one pattern. So, when we start, we actually need to test every
|
294
|
+
* pattern against every file. Once we know there are no remaining
|
295
|
+
* unmatched patterns, then we can switch to just looking for the
|
296
|
+
* first matching pattern for improved speed.
|
297
|
+
*/
|
298
|
+
const matchesPattern = unmatchedPatterns.size > 0
|
299
|
+
? matchers.reduce((previousValue, matcher) => {
|
300
|
+
const pathMatches = matcher.match(relativePath);
|
301
|
+
|
302
|
+
/*
|
303
|
+
* We updated the unmatched patterns set only if the path
|
304
|
+
* matches and the file isn't ignored. If the file is
|
305
|
+
* ignored, that means there wasn't a match for the
|
306
|
+
* pattern so it should not be removed.
|
307
|
+
*
|
308
|
+
* Performance note: isFileIgnored() aggressively caches
|
309
|
+
* results so there is no performance penalty for calling
|
310
|
+
* it twice with the same argument.
|
311
|
+
*/
|
312
|
+
if (pathMatches && !configs.isFileIgnored(entry.path)) {
|
313
|
+
unmatchedPatterns.delete(matcher.pattern);
|
314
|
+
}
|
315
|
+
|
316
|
+
return pathMatches || previousValue;
|
317
|
+
}, false)
|
318
|
+
: matchers.some(matcher => matcher.match(relativePath));
|
319
|
+
|
320
|
+
return matchesPattern && !configs.isFileIgnored(entry.path);
|
321
|
+
}
|
322
|
+
|
323
|
+
})).map(entry => entry.path);
|
324
|
+
|
325
|
+
// now check to see if we have any unmatched patterns
|
326
|
+
if (errorOnUnmatchedPattern && unmatchedPatterns.size > 0) {
|
327
|
+
throw new UnmatchedSearchPatternsError({
|
328
|
+
basePath,
|
329
|
+
unmatchedPatterns: [...unmatchedPatterns].map(
|
330
|
+
pattern => relativeToPatterns.get(pattern)
|
331
|
+
),
|
332
|
+
patterns,
|
333
|
+
rawPatterns
|
334
|
+
});
|
335
|
+
}
|
336
|
+
|
337
|
+
return filePaths;
|
338
|
+
}
|
339
|
+
|
340
|
+
/**
|
341
|
+
* Throws an error for unmatched patterns. The error will only contain information about the first one.
|
342
|
+
* Checks to see if there are any ignored results for a given search.
|
343
|
+
* @param {Object} options The options for this function.
|
344
|
+
* @param {string} options.basePath The directory to search.
|
345
|
+
* @param {Array<string>} options.patterns An array of glob patterns
|
346
|
+
* that were used in the original search.
|
347
|
+
* @param {Array<string>} options.rawPatterns An array of glob patterns
|
348
|
+
* as the user inputted them. Used for errors.
|
349
|
+
* @param {Array<string>} options.unmatchedPatterns A non-empty array of glob patterns
|
350
|
+
* that were unmatched in the original search.
|
351
|
+
* @returns {void} Always throws an error.
|
352
|
+
* @throws {NoFilesFoundError} If the first unmatched pattern
|
353
|
+
* doesn't match any files even when there are no ignores.
|
354
|
+
* @throws {AllFilesIgnoredError} If the first unmatched pattern
|
355
|
+
* matches some files when there are no ignores.
|
356
|
+
*/
|
357
|
+
async function throwErrorForUnmatchedPatterns({
|
358
|
+
basePath,
|
359
|
+
patterns,
|
360
|
+
rawPatterns,
|
361
|
+
unmatchedPatterns
|
362
|
+
}) {
|
363
|
+
|
364
|
+
const pattern = unmatchedPatterns[0];
|
365
|
+
const rawPattern = rawPatterns[patterns.indexOf(pattern)];
|
366
|
+
|
367
|
+
const patternHasMatch = await globMatch({
|
368
|
+
basePath,
|
369
|
+
pattern
|
370
|
+
});
|
371
|
+
|
372
|
+
if (patternHasMatch) {
|
373
|
+
throw new AllFilesIgnoredError(rawPattern);
|
374
|
+
}
|
375
|
+
|
376
|
+
// if we get here there are truly no matches
|
377
|
+
throw new NoFilesFoundError(rawPattern, true);
|
378
|
+
}
|
379
|
+
|
380
|
+
/**
|
381
|
+
* Performs multiple glob searches in parallel.
|
382
|
+
* @param {Object} options The options for this function.
|
383
|
+
* @param {Map<string,GlobSearch>} options.searches
|
384
|
+
* An array of glob patterns to match.
|
385
|
+
* @param {FlatConfigArray} options.configs The config array to use for
|
386
|
+
* determining what to ignore.
|
387
|
+
* @param {boolean} options.errorOnUnmatchedPattern Determines if an
|
388
|
+
* unmatched glob pattern should throw an error.
|
389
|
+
* @returns {Promise<Array<string>>} An array of matching file paths
|
390
|
+
* or an empty array if there are no matches.
|
391
|
+
*/
|
392
|
+
async function globMultiSearch({ searches, configs, errorOnUnmatchedPattern }) {
|
393
|
+
|
394
|
+
/*
|
395
|
+
* For convenience, we normalized the search map into an array of objects.
|
396
|
+
* Next, we filter out all searches that have no patterns. This happens
|
397
|
+
* primarily for the cwd, which is prepopulated in the searches map as an
|
398
|
+
* optimization. However, if it has no patterns, it means all patterns
|
399
|
+
* occur outside of the cwd and we can safely filter out that search.
|
400
|
+
*/
|
401
|
+
const normalizedSearches = [...searches].map(
|
402
|
+
([basePath, { patterns, rawPatterns }]) => ({ basePath, patterns, rawPatterns })
|
403
|
+
).filter(({ patterns }) => patterns.length > 0);
|
404
|
+
|
405
|
+
const results = await Promise.allSettled(
|
406
|
+
normalizedSearches.map(
|
407
|
+
({ basePath, patterns, rawPatterns }) => globSearch({
|
408
|
+
basePath,
|
409
|
+
patterns,
|
410
|
+
rawPatterns,
|
411
|
+
configs,
|
412
|
+
errorOnUnmatchedPattern
|
413
|
+
})
|
414
|
+
)
|
415
|
+
);
|
416
|
+
|
417
|
+
const filePaths = [];
|
418
|
+
|
419
|
+
for (let i = 0; i < results.length; i++) {
|
420
|
+
|
421
|
+
const result = results[i];
|
422
|
+
const currentSearch = normalizedSearches[i];
|
423
|
+
|
424
|
+
if (result.status === "fulfilled") {
|
425
|
+
|
426
|
+
// if the search was successful just add the results
|
427
|
+
if (result.value.length > 0) {
|
428
|
+
filePaths.push(...result.value);
|
429
|
+
}
|
430
|
+
|
431
|
+
continue;
|
432
|
+
}
|
433
|
+
|
434
|
+
// if we make it here then there was an error
|
435
|
+
const error = result.reason;
|
436
|
+
|
437
|
+
// unexpected errors should be re-thrown
|
438
|
+
if (!error.basePath) {
|
439
|
+
throw error;
|
440
|
+
}
|
441
|
+
|
442
|
+
if (errorOnUnmatchedPattern) {
|
443
|
+
|
444
|
+
await throwErrorForUnmatchedPatterns({
|
445
|
+
...currentSearch,
|
446
|
+
unmatchedPatterns: error.unmatchedPatterns
|
447
|
+
});
|
448
|
+
|
449
|
+
}
|
450
|
+
|
451
|
+
}
|
452
|
+
|
453
|
+
return [...new Set(filePaths)];
|
454
|
+
|
455
|
+
}
|
456
|
+
|
99
457
|
/**
|
100
458
|
* Finds all files matching the options specified.
|
101
459
|
* @param {Object} args The arguments objects.
|
@@ -104,6 +462,8 @@ function isGlobPattern(pattern) {
|
|
104
462
|
* false to not interpret glob patterns.
|
105
463
|
* @param {string} args.cwd The current working directory to find from.
|
106
464
|
* @param {FlatConfigArray} args.configs The configs for the current run.
|
465
|
+
* @param {boolean} args.errorOnUnmatchedPattern Determines if an unmatched pattern
|
466
|
+
* should throw an error.
|
107
467
|
* @returns {Promise<Array<string>>} The fully resolved file paths.
|
108
468
|
* @throws {AllFilesIgnoredError} If there are no results due to an ignore pattern.
|
109
469
|
* @throws {NoFilesFoundError} If no files matched the given patterns.
|
@@ -112,25 +472,28 @@ async function findFiles({
|
|
112
472
|
patterns,
|
113
473
|
globInputPaths,
|
114
474
|
cwd,
|
115
|
-
configs
|
475
|
+
configs,
|
476
|
+
errorOnUnmatchedPattern
|
116
477
|
}) {
|
117
478
|
|
118
479
|
const results = [];
|
119
|
-
const globbyPatterns = [];
|
120
480
|
const missingPatterns = [];
|
481
|
+
let globbyPatterns = [];
|
482
|
+
let rawPatterns = [];
|
483
|
+
const searches = new Map([[cwd, { patterns: globbyPatterns, rawPatterns: [] }]]);
|
121
484
|
|
122
485
|
// check to see if we have explicit files and directories
|
123
486
|
const filePaths = patterns.map(filePath => path.resolve(cwd, filePath));
|
124
487
|
const stats = await Promise.all(
|
125
488
|
filePaths.map(
|
126
|
-
filePath => fsp.stat(filePath).catch(() => {})
|
489
|
+
filePath => fsp.stat(filePath).catch(() => { })
|
127
490
|
)
|
128
491
|
);
|
129
492
|
|
130
493
|
stats.forEach((stat, index) => {
|
131
494
|
|
132
495
|
const filePath = filePaths[index];
|
133
|
-
const pattern = patterns[index];
|
496
|
+
const pattern = normalizeToPosix(patterns[index]);
|
134
497
|
|
135
498
|
if (stat) {
|
136
499
|
|
@@ -138,55 +501,25 @@ async function findFiles({
|
|
138
501
|
if (stat.isFile()) {
|
139
502
|
results.push({
|
140
503
|
filePath,
|
141
|
-
ignored: configs.
|
504
|
+
ignored: configs.isFileIgnored(filePath)
|
142
505
|
});
|
143
506
|
}
|
144
507
|
|
145
508
|
// directories need extensions attached
|
146
509
|
if (stat.isDirectory()) {
|
147
510
|
|
148
|
-
//
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
// patterns ending with * are not used for file search
|
158
|
-
if (filePattern.endsWith("*")) {
|
159
|
-
return false;
|
160
|
-
}
|
161
|
-
|
162
|
-
// not sure how to handle negated patterns yet
|
163
|
-
if (filePattern.startsWith("!")) {
|
164
|
-
return false;
|
165
|
-
}
|
166
|
-
|
167
|
-
// check if the pattern would be inside the cwd or not
|
168
|
-
const fullFilePattern = path.join(cwd, filePattern);
|
169
|
-
const relativeFilePattern = path.relative(configs.basePath, fullFilePattern);
|
170
|
-
|
171
|
-
return !relativeFilePattern.startsWith("..");
|
172
|
-
})
|
173
|
-
.map(filePattern => {
|
174
|
-
if (filePattern.startsWith("**")) {
|
175
|
-
return path.join(pattern, filePattern);
|
176
|
-
}
|
177
|
-
|
178
|
-
// adjust the path to be relative to the cwd
|
179
|
-
return path.relative(
|
180
|
-
cwd,
|
181
|
-
path.join(configs.basePath, filePattern)
|
182
|
-
);
|
183
|
-
})
|
184
|
-
.map(normalizeToPosix);
|
185
|
-
|
186
|
-
if (filePatterns.length) {
|
187
|
-
globbyPatterns.push(...filePatterns);
|
511
|
+
// group everything in cwd together and split out others
|
512
|
+
if (isPathInside(filePath, cwd)) {
|
513
|
+
({ patterns: globbyPatterns, rawPatterns } = searches.get(cwd));
|
514
|
+
} else {
|
515
|
+
if (!searches.has(filePath)) {
|
516
|
+
searches.set(filePath, { patterns: [], rawPatterns: [] });
|
517
|
+
}
|
518
|
+
({ patterns: globbyPatterns, rawPatterns } = searches.get(filePath));
|
188
519
|
}
|
189
520
|
|
521
|
+
globbyPatterns.push(`${normalizeToPosix(filePath)}/**`);
|
522
|
+
rawPatterns.push(pattern);
|
190
523
|
}
|
191
524
|
|
192
525
|
return;
|
@@ -194,45 +527,37 @@ async function findFiles({
|
|
194
527
|
|
195
528
|
// save patterns for later use based on whether globs are enabled
|
196
529
|
if (globInputPaths && isGlobPattern(filePath)) {
|
197
|
-
globbyPatterns.push(pattern);
|
198
|
-
} else {
|
199
|
-
missingPatterns.push(pattern);
|
200
|
-
}
|
201
|
-
});
|
202
|
-
|
203
|
-
// note: globbyPatterns can be an empty array
|
204
|
-
const globbyResults = (await globby(globbyPatterns, {
|
205
|
-
cwd,
|
206
|
-
absolute: true,
|
207
|
-
ignore: configs.ignores.filter(matcher => typeof matcher === "string")
|
208
|
-
}));
|
209
|
-
|
210
|
-
// if there are no results, tell the user why
|
211
|
-
if (!results.length && !globbyResults.length) {
|
212
530
|
|
213
|
-
|
214
|
-
/* eslint-disable no-unreachable-loop -- We want to exit early. */
|
215
|
-
for (const globbyPattern of globbyPatterns) {
|
531
|
+
const basePath = globParent(filePath);
|
216
532
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
533
|
+
// group in cwd if possible and split out others
|
534
|
+
if (isPathInside(basePath, cwd)) {
|
535
|
+
({ patterns: globbyPatterns, rawPatterns } = searches.get(cwd));
|
536
|
+
} else {
|
537
|
+
if (!searches.has(basePath)) {
|
538
|
+
searches.set(basePath, { patterns: [], rawPatterns: [] });
|
539
|
+
}
|
540
|
+
({ patterns: globbyPatterns, rawPatterns } = searches.get(basePath));
|
222
541
|
}
|
223
542
|
|
224
|
-
|
225
|
-
|
543
|
+
globbyPatterns.push(filePath);
|
544
|
+
rawPatterns.push(pattern);
|
545
|
+
} else {
|
546
|
+
missingPatterns.push(pattern);
|
226
547
|
}
|
227
|
-
|
228
|
-
|
229
|
-
}
|
548
|
+
});
|
230
549
|
|
231
550
|
// there were patterns that didn't match anything, tell the user
|
232
|
-
if (missingPatterns.length) {
|
551
|
+
if (errorOnUnmatchedPattern && missingPatterns.length) {
|
233
552
|
throw new NoFilesFoundError(missingPatterns[0], globInputPaths);
|
234
553
|
}
|
235
554
|
|
555
|
+
// now we are safe to do the search
|
556
|
+
const globbyResults = await globMultiSearch({
|
557
|
+
searches,
|
558
|
+
configs,
|
559
|
+
errorOnUnmatchedPattern
|
560
|
+
});
|
236
561
|
|
237
562
|
return [
|
238
563
|
...results,
|
@@ -322,6 +647,7 @@ function createIgnoreResult(filePath, baseDir) {
|
|
322
647
|
message
|
323
648
|
}
|
324
649
|
],
|
650
|
+
suppressedMessages: [],
|
325
651
|
errorCount: 0,
|
326
652
|
warningCount: 1,
|
327
653
|
fatalErrorCount: 0,
|
@@ -378,12 +704,10 @@ function processOptions({
|
|
378
704
|
cacheStrategy = "metadata",
|
379
705
|
cwd = process.cwd(),
|
380
706
|
errorOnUnmatchedPattern = true,
|
381
|
-
extensions = null, // ← should be null by default because if it's an array then it suppresses RFC20 feature.
|
382
707
|
fix = false,
|
383
708
|
fixTypes = null, // ← should be null by default because if it's an array then it suppresses rules that don't have the `meta.type` property.
|
384
709
|
globInputPaths = true,
|
385
710
|
ignore = true,
|
386
|
-
ignorePath = null, // ← should be null by default because if it's a string then it may throw ENOENT.
|
387
711
|
ignorePatterns = null,
|
388
712
|
overrideConfig = null,
|
389
713
|
overrideConfigFile = null,
|
@@ -405,12 +729,18 @@ function processOptions({
|
|
405
729
|
if (unknownOptionKeys.includes("envs")) {
|
406
730
|
errors.push("'envs' has been removed.");
|
407
731
|
}
|
732
|
+
if (unknownOptionKeys.includes("extensions")) {
|
733
|
+
errors.push("'extensions' has been removed.");
|
734
|
+
}
|
408
735
|
if (unknownOptionKeys.includes("resolvePluginsRelativeTo")) {
|
409
736
|
errors.push("'resolvePluginsRelativeTo' has been removed.");
|
410
737
|
}
|
411
738
|
if (unknownOptionKeys.includes("globals")) {
|
412
739
|
errors.push("'globals' has been removed. Please use the 'overrideConfig.languageOptions.globals' option instead.");
|
413
740
|
}
|
741
|
+
if (unknownOptionKeys.includes("ignorePath")) {
|
742
|
+
errors.push("'ignorePath' has been removed.");
|
743
|
+
}
|
414
744
|
if (unknownOptionKeys.includes("ignorePattern")) {
|
415
745
|
errors.push("'ignorePattern' has been removed. Please use the 'overrideConfig.ignorePatterns' option instead.");
|
416
746
|
}
|
@@ -451,9 +781,6 @@ function processOptions({
|
|
451
781
|
if (typeof errorOnUnmatchedPattern !== "boolean") {
|
452
782
|
errors.push("'errorOnUnmatchedPattern' must be a boolean.");
|
453
783
|
}
|
454
|
-
if (!isArrayOfNonEmptyString(extensions) && extensions !== null) {
|
455
|
-
errors.push("'extensions' must be an array of non-empty strings or null.");
|
456
|
-
}
|
457
784
|
if (typeof fix !== "boolean" && typeof fix !== "function") {
|
458
785
|
errors.push("'fix' must be a boolean or a function.");
|
459
786
|
}
|
@@ -466,9 +793,6 @@ function processOptions({
|
|
466
793
|
if (typeof ignore !== "boolean") {
|
467
794
|
errors.push("'ignore' must be a boolean.");
|
468
795
|
}
|
469
|
-
if (!isNonEmptyString(ignorePath) && ignorePath !== null) {
|
470
|
-
errors.push("'ignorePath' must be a non-empty string or null.");
|
471
|
-
}
|
472
796
|
if (typeof overrideConfig !== "object") {
|
473
797
|
errors.push("'overrideConfig' must be an object or null.");
|
474
798
|
}
|
@@ -507,12 +831,10 @@ function processOptions({
|
|
507
831
|
overrideConfig,
|
508
832
|
cwd,
|
509
833
|
errorOnUnmatchedPattern,
|
510
|
-
extensions,
|
511
834
|
fix,
|
512
835
|
fixTypes,
|
513
836
|
globInputPaths,
|
514
837
|
ignore,
|
515
|
-
ignorePath,
|
516
838
|
ignorePatterns,
|
517
839
|
reportUnusedDisableDirectives
|
518
840
|
};
|
package/lib/eslint/eslint.js
CHANGED
@@ -36,11 +36,12 @@ const { version } = require("../../package.json");
|
|
36
36
|
/** @typedef {import("../shared/types").Plugin} Plugin */
|
37
37
|
/** @typedef {import("../shared/types").Rule} Rule */
|
38
38
|
/** @typedef {import("../shared/types").LintResult} LintResult */
|
39
|
+
/** @typedef {import("../shared/types").ResultsMeta} ResultsMeta */
|
39
40
|
|
40
41
|
/**
|
41
42
|
* The main formatter object.
|
42
43
|
* @typedef LoadedFormatter
|
43
|
-
* @property {
|
44
|
+
* @property {(results: LintResult[], resultsMeta: ResultsMeta) => string | Promise<string>} format format function.
|
44
45
|
*/
|
45
46
|
|
46
47
|
/**
|
@@ -625,14 +626,16 @@ class ESLint {
|
|
625
626
|
/**
|
626
627
|
* The main formatter method.
|
627
628
|
* @param {LintResult[]} results The lint results to format.
|
629
|
+
* @param {ResultsMeta} resultsMeta Warning count and max threshold.
|
628
630
|
* @returns {string | Promise<string>} The formatted lint results.
|
629
631
|
*/
|
630
|
-
format(results) {
|
632
|
+
format(results, resultsMeta) {
|
631
633
|
let rulesMeta = null;
|
632
634
|
|
633
635
|
results.sort(compareResultsByFilePath);
|
634
636
|
|
635
637
|
return formatter(results, {
|
638
|
+
...resultsMeta,
|
636
639
|
get cwd() {
|
637
640
|
return options.cwd;
|
638
641
|
},
|