eslint 9.11.1 → 9.13.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 +8 -9
- package/bin/eslint.js +5 -0
- package/lib/cli-engine/formatters/stylish.js +2 -2
- package/lib/cli.js +14 -18
- package/lib/config/config-loader.js +703 -0
- package/lib/config/config.js +13 -10
- package/lib/config/default-config.js +2 -8
- package/lib/eslint/eslint-helpers.js +128 -134
- package/lib/eslint/eslint.js +95 -294
- package/lib/languages/js/index.js +8 -0
- package/lib/linter/linter.js +16 -19
- package/lib/rule-tester/rule-tester.js +39 -18
- package/lib/rules/complexity.js +16 -6
- package/lib/shared/flags.js +1 -0
- package/lib/types/index.d.ts +12 -0
- package/lib/types/rules/best-practices.d.ts +33 -2
- package/lib/types/rules/deprecated.d.ts +18 -77
- package/lib/types/rules/ecmascript-6.d.ts +22 -6
- package/lib/types/rules/possible-errors.d.ts +2 -0
- package/lib/types/rules/stylistic-issues.d.ts +68 -5
- package/lib/types/rules/variables.d.ts +9 -1
- package/lib/unsupported-api.js +2 -1
- package/package.json +28 -14
package/lib/eslint/eslint.js
CHANGED
@@ -12,10 +12,10 @@
|
|
12
12
|
const fs = require("node:fs/promises");
|
13
13
|
const { existsSync } = require("node:fs");
|
14
14
|
const path = require("node:path");
|
15
|
-
const findUp = require("find-up");
|
16
15
|
const { version } = require("../../package.json");
|
17
16
|
const { Linter } = require("../linter");
|
18
17
|
const { getRuleFromConfig } = require("../config/flat-config-helpers");
|
18
|
+
const { defaultConfig } = require("../config/default-config");
|
19
19
|
const {
|
20
20
|
Legacy: {
|
21
21
|
ConfigOps: {
|
@@ -39,9 +39,9 @@ const {
|
|
39
39
|
processOptions
|
40
40
|
} = require("./eslint-helpers");
|
41
41
|
const { pathToFileURL } = require("node:url");
|
42
|
-
const { FlatConfigArray } = require("../config/flat-config-array");
|
43
42
|
const LintResultCache = require("../cli-engine/lint-result-cache");
|
44
43
|
const { Retrier } = require("@humanwhocodes/retry");
|
44
|
+
const { ConfigLoader, LegacyConfigLoader } = require("../config/config-loader");
|
45
45
|
|
46
46
|
/*
|
47
47
|
* This is necessary to allow overwriting writeFile for testing purposes.
|
@@ -53,6 +53,7 @@ const { Retrier } = require("@humanwhocodes/retry");
|
|
53
53
|
//------------------------------------------------------------------------------
|
54
54
|
|
55
55
|
// For VSCode IntelliSense
|
56
|
+
/** @typedef {import("../cli-engine/cli-engine").ConfigArray} ConfigArray */
|
56
57
|
/** @typedef {import("../shared/types").ConfigData} ConfigData */
|
57
58
|
/** @typedef {import("../shared/types").DeprecatedRuleInfo} DeprecatedRuleInfo */
|
58
59
|
/** @typedef {import("../shared/types").LintMessage} LintMessage */
|
@@ -97,24 +98,8 @@ const { Retrier } = require("@humanwhocodes/retry");
|
|
97
98
|
// Helpers
|
98
99
|
//------------------------------------------------------------------------------
|
99
100
|
|
100
|
-
const FLAT_CONFIG_FILENAMES = [
|
101
|
-
"eslint.config.js",
|
102
|
-
"eslint.config.mjs",
|
103
|
-
"eslint.config.cjs"
|
104
|
-
];
|
105
|
-
const FLAT_CONFIG_FILENAMES_WITH_TS = [
|
106
|
-
...FLAT_CONFIG_FILENAMES,
|
107
|
-
"eslint.config.ts",
|
108
|
-
"eslint.config.mts",
|
109
|
-
"eslint.config.cts"
|
110
|
-
];
|
111
101
|
const debug = require("debug")("eslint:eslint");
|
112
102
|
const privateMembers = new WeakMap();
|
113
|
-
|
114
|
-
/**
|
115
|
-
* @type {Map<string, string>}
|
116
|
-
*/
|
117
|
-
const importedConfigFileModificationTime = new Map();
|
118
103
|
const removedFormatters = new Set([
|
119
104
|
"checkstyle",
|
120
105
|
"codeframe",
|
@@ -196,12 +181,13 @@ const usedDeprecatedRulesCache = new WeakMap();
|
|
196
181
|
*/
|
197
182
|
function getOrFindUsedDeprecatedRules(eslint, maybeFilePath) {
|
198
183
|
const {
|
199
|
-
|
200
|
-
|
184
|
+
options: { cwd },
|
185
|
+
configLoader
|
201
186
|
} = privateMembers.get(eslint);
|
202
187
|
const filePath = path.isAbsolute(maybeFilePath)
|
203
188
|
? maybeFilePath
|
204
189
|
: getPlaceholderPath(cwd);
|
190
|
+
const configs = configLoader.getCachedConfigArrayForFile(filePath);
|
205
191
|
const config = configs.getConfig(filePath);
|
206
192
|
|
207
193
|
// Most files use the same config, so cache it.
|
@@ -270,269 +256,38 @@ function compareResultsByFilePath(a, b) {
|
|
270
256
|
return 0;
|
271
257
|
}
|
272
258
|
|
273
|
-
/**
|
274
|
-
* Searches from the current working directory up until finding the
|
275
|
-
* given flat config filename.
|
276
|
-
* @param {string} cwd The current working directory to search from.
|
277
|
-
* @param {boolean} hasUnstableTSConfigFlag `true` if the `unstable_ts_config` flag is enabled, `false` if it's not.
|
278
|
-
* @returns {Promise<string|undefined>} The filename if found or `undefined` if not.
|
279
|
-
*/
|
280
|
-
function findFlatConfigFile(cwd, hasUnstableTSConfigFlag) {
|
281
|
-
const filenames = hasUnstableTSConfigFlag ? FLAT_CONFIG_FILENAMES_WITH_TS : FLAT_CONFIG_FILENAMES;
|
282
|
-
|
283
|
-
return findUp(
|
284
|
-
filenames,
|
285
|
-
{ cwd }
|
286
|
-
);
|
287
|
-
}
|
288
|
-
|
289
|
-
/**
|
290
|
-
* Check if the file is a TypeScript file.
|
291
|
-
* @param {string} filePath The file path to check.
|
292
|
-
* @returns {boolean} `true` if the file is a TypeScript file, `false` if it's not.
|
293
|
-
*/
|
294
|
-
function isFileTS(filePath) {
|
295
|
-
const fileExtension = path.extname(filePath);
|
296
|
-
|
297
|
-
return /^\.[mc]?ts$/u.test(fileExtension);
|
298
|
-
}
|
299
|
-
|
300
|
-
/**
|
301
|
-
* Check if ESLint is running in Bun.
|
302
|
-
* @returns {boolean} `true` if the ESLint is running Bun, `false` if it's not.
|
303
|
-
*/
|
304
|
-
function isRunningInBun() {
|
305
|
-
return !!globalThis.Bun;
|
306
|
-
}
|
307
|
-
|
308
|
-
/**
|
309
|
-
* Check if ESLint is running in Deno.
|
310
|
-
* @returns {boolean} `true` if the ESLint is running in Deno, `false` if it's not.
|
311
|
-
*/
|
312
|
-
function isRunningInDeno() {
|
313
|
-
return !!globalThis.Deno;
|
314
|
-
}
|
315
|
-
|
316
|
-
/**
|
317
|
-
* Load the config array from the given filename.
|
318
|
-
* @param {string} filePath The filename to load from.
|
319
|
-
* @param {boolean} hasUnstableTSConfigFlag `true` if the `unstable_ts_config` flag is enabled, `false` if it's not.
|
320
|
-
* @returns {Promise<any>} The config loaded from the config file.
|
321
|
-
*/
|
322
|
-
async function loadFlatConfigFile(filePath, hasUnstableTSConfigFlag) {
|
323
|
-
debug(`Loading config from ${filePath}`);
|
324
|
-
|
325
|
-
const fileURL = pathToFileURL(filePath);
|
326
|
-
|
327
|
-
debug(`Config file URL is ${fileURL}`);
|
328
|
-
|
329
|
-
const mtime = (await fs.stat(filePath)).mtime.getTime().toString();
|
330
|
-
|
331
|
-
/*
|
332
|
-
* Append a query with the config file's modification time (`mtime`) in order
|
333
|
-
* to import the current version of the config file. Without the query, `import()` would
|
334
|
-
* cache the config file module by the pathname only, and then always return
|
335
|
-
* the same version (the one that was actual when the module was imported for the first time).
|
336
|
-
*
|
337
|
-
* This ensures that the config file module is loaded and executed again
|
338
|
-
* if it has been changed since the last time it was imported.
|
339
|
-
* If it hasn't been changed, `import()` will just return the cached version.
|
340
|
-
*
|
341
|
-
* Note that we should not overuse queries (e.g., by appending the current time
|
342
|
-
* to always reload the config file module) as that could cause memory leaks
|
343
|
-
* because entries are never removed from the import cache.
|
344
|
-
*/
|
345
|
-
fileURL.searchParams.append("mtime", mtime);
|
346
|
-
|
347
|
-
/*
|
348
|
-
* With queries, we can bypass the import cache. However, when import-ing a CJS module,
|
349
|
-
* Node.js uses the require infrastructure under the hood. That includes the require cache,
|
350
|
-
* which caches the config file module by its file path (queries have no effect).
|
351
|
-
* Therefore, we also need to clear the require cache before importing the config file module.
|
352
|
-
* In order to get the same behavior with ESM and CJS config files, in particular - to reload
|
353
|
-
* the config file only if it has been changed, we track file modification times and clear
|
354
|
-
* the require cache only if the file has been changed.
|
355
|
-
*/
|
356
|
-
if (importedConfigFileModificationTime.get(filePath) !== mtime) {
|
357
|
-
delete require.cache[filePath];
|
358
|
-
}
|
359
|
-
|
360
|
-
const isTS = isFileTS(filePath) && hasUnstableTSConfigFlag;
|
361
|
-
|
362
|
-
const isBun = isRunningInBun();
|
363
|
-
|
364
|
-
const isDeno = isRunningInDeno();
|
365
|
-
|
366
|
-
if (isTS && !isDeno && !isBun) {
|
367
|
-
|
368
|
-
const createJiti = await import("jiti").then(jitiModule => jitiModule.default, () => {
|
369
|
-
throw new Error("The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.");
|
370
|
-
});
|
371
|
-
|
372
|
-
/*
|
373
|
-
* Disabling `moduleCache` allows us to reload a
|
374
|
-
* config file when the last modified timestamp changes.
|
375
|
-
*/
|
376
|
-
|
377
|
-
const jiti = createJiti(__filename, { moduleCache: false });
|
378
|
-
|
379
|
-
if (typeof jiti?.import !== "function") {
|
380
|
-
throw new Error("You are using an outdated version of the 'jiti' library. Please update to the latest version of 'jiti' to ensure compatibility and access to the latest features.");
|
381
|
-
}
|
382
|
-
|
383
|
-
const config = await jiti.import(fileURL.href);
|
384
|
-
|
385
|
-
importedConfigFileModificationTime.set(filePath, mtime);
|
386
|
-
|
387
|
-
return config?.default ?? config;
|
388
|
-
}
|
389
|
-
|
390
|
-
const config = (await import(fileURL.href)).default;
|
391
|
-
|
392
|
-
importedConfigFileModificationTime.set(filePath, mtime);
|
393
|
-
|
394
|
-
return config;
|
395
|
-
}
|
396
259
|
|
397
260
|
/**
|
398
261
|
* Determines which config file to use. This is determined by seeing if an
|
399
262
|
* override config file was passed, and if so, using it; otherwise, as long
|
400
263
|
* as override config file is not explicitly set to `false`, it will search
|
401
264
|
* upwards from the cwd for a file named `eslint.config.js`.
|
265
|
+
*
|
266
|
+
* This function is used primarily by the `--inspect-config` option. For now,
|
267
|
+
* we will maintain the existing behavior, which is to search up from the cwd.
|
402
268
|
* @param {ESLintOptions} options The ESLint instance options.
|
403
|
-
* @param {boolean}
|
404
|
-
* @returns {Promise<{configFilePath:string|undefined;basePath:string
|
269
|
+
* @param {boolean} allowTS `true` if the `unstable_ts_config` flag is enabled, `false` if it's not.
|
270
|
+
* @returns {Promise<{configFilePath:string|undefined;basePath:string}>} Location information for
|
405
271
|
* the config file.
|
406
272
|
*/
|
407
|
-
async function locateConfigFileToUse({ configFile, cwd },
|
408
|
-
|
409
|
-
// determine where to load config file from
|
410
|
-
let configFilePath;
|
411
|
-
let basePath = cwd;
|
412
|
-
let error = null;
|
413
|
-
|
414
|
-
if (typeof configFile === "string") {
|
415
|
-
debug(`Override config file path is ${configFile}`);
|
416
|
-
configFilePath = path.resolve(cwd, configFile);
|
417
|
-
} else if (configFile !== false) {
|
418
|
-
debug("Searching for eslint.config.js");
|
419
|
-
configFilePath = await findFlatConfigFile(cwd, hasUnstableTSConfigFlag);
|
420
|
-
|
421
|
-
if (configFilePath) {
|
422
|
-
basePath = path.resolve(path.dirname(configFilePath));
|
423
|
-
} else {
|
424
|
-
error = new Error("Could not find config file.");
|
425
|
-
error.messageTemplate = "config-file-missing";
|
426
|
-
}
|
273
|
+
async function locateConfigFileToUse({ configFile, cwd }, allowTS) {
|
427
274
|
|
275
|
+
const configLoader = new ConfigLoader({
|
276
|
+
cwd,
|
277
|
+
allowTS,
|
278
|
+
configFile
|
279
|
+
});
|
280
|
+
|
281
|
+
const configFilePath = await configLoader.findConfigFileForPath(path.join(cwd, "__placeholder__.js"));
|
282
|
+
|
283
|
+
if (!configFilePath) {
|
284
|
+
throw new Error("No ESLint configuration file was found.");
|
428
285
|
}
|
429
286
|
|
430
287
|
return {
|
431
288
|
configFilePath,
|
432
|
-
basePath
|
433
|
-
error
|
289
|
+
basePath: configFile ? cwd : path.dirname(configFilePath)
|
434
290
|
};
|
435
|
-
|
436
|
-
}
|
437
|
-
|
438
|
-
/**
|
439
|
-
* Calculates the config array for this run based on inputs.
|
440
|
-
* @param {ESLint} eslint The instance to create the config array for.
|
441
|
-
* @param {ESLintOptions} options The ESLint instance options.
|
442
|
-
* @returns {Promise<typeof FlatConfigArray>} The config array for `eslint``.
|
443
|
-
*/
|
444
|
-
async function calculateConfigArray(eslint, {
|
445
|
-
cwd,
|
446
|
-
baseConfig,
|
447
|
-
overrideConfig,
|
448
|
-
configFile,
|
449
|
-
ignore: shouldIgnore,
|
450
|
-
ignorePatterns
|
451
|
-
}) {
|
452
|
-
|
453
|
-
// check for cached instance
|
454
|
-
const slots = privateMembers.get(eslint);
|
455
|
-
|
456
|
-
if (slots.configs) {
|
457
|
-
return slots.configs;
|
458
|
-
}
|
459
|
-
|
460
|
-
const hasUnstableTSConfigFlag = eslint.hasFlag("unstable_ts_config");
|
461
|
-
|
462
|
-
const { configFilePath, basePath, error } = await locateConfigFileToUse({ configFile, cwd }, hasUnstableTSConfigFlag);
|
463
|
-
|
464
|
-
// config file is required to calculate config
|
465
|
-
if (error) {
|
466
|
-
throw error;
|
467
|
-
}
|
468
|
-
|
469
|
-
const configs = new FlatConfigArray(baseConfig || [], { basePath, shouldIgnore });
|
470
|
-
|
471
|
-
// load config file
|
472
|
-
if (configFilePath) {
|
473
|
-
const fileConfig = await loadFlatConfigFile(configFilePath, hasUnstableTSConfigFlag);
|
474
|
-
|
475
|
-
if (Array.isArray(fileConfig)) {
|
476
|
-
configs.push(...fileConfig);
|
477
|
-
} else {
|
478
|
-
configs.push(fileConfig);
|
479
|
-
}
|
480
|
-
}
|
481
|
-
|
482
|
-
// add in any configured defaults
|
483
|
-
configs.push(...slots.defaultConfigs);
|
484
|
-
|
485
|
-
// append command line ignore patterns
|
486
|
-
if (ignorePatterns && ignorePatterns.length > 0) {
|
487
|
-
|
488
|
-
let relativeIgnorePatterns;
|
489
|
-
|
490
|
-
/*
|
491
|
-
* If the config file basePath is different than the cwd, then
|
492
|
-
* the ignore patterns won't work correctly. Here, we adjust the
|
493
|
-
* ignore pattern to include the correct relative path. Patterns
|
494
|
-
* passed as `ignorePatterns` are relative to the cwd, whereas
|
495
|
-
* the config file basePath can be an ancestor of the cwd.
|
496
|
-
*/
|
497
|
-
if (basePath === cwd) {
|
498
|
-
relativeIgnorePatterns = ignorePatterns;
|
499
|
-
} else {
|
500
|
-
|
501
|
-
// In minimatch patterns, only `/` can be used as path separator
|
502
|
-
const relativeIgnorePath = path.relative(basePath, cwd).replaceAll(path.sep, "/");
|
503
|
-
|
504
|
-
relativeIgnorePatterns = ignorePatterns.map(pattern => {
|
505
|
-
const negated = pattern.startsWith("!");
|
506
|
-
const basePattern = negated ? pattern.slice(1) : pattern;
|
507
|
-
|
508
|
-
return (negated ? "!" : "") +
|
509
|
-
path.posix.join(relativeIgnorePath, basePattern);
|
510
|
-
});
|
511
|
-
}
|
512
|
-
|
513
|
-
/*
|
514
|
-
* Ignore patterns are added to the end of the config array
|
515
|
-
* so they can override default ignores.
|
516
|
-
*/
|
517
|
-
configs.push({
|
518
|
-
ignores: relativeIgnorePatterns
|
519
|
-
});
|
520
|
-
}
|
521
|
-
|
522
|
-
if (overrideConfig) {
|
523
|
-
if (Array.isArray(overrideConfig)) {
|
524
|
-
configs.push(...overrideConfig);
|
525
|
-
} else {
|
526
|
-
configs.push(overrideConfig);
|
527
|
-
}
|
528
|
-
}
|
529
|
-
|
530
|
-
await configs.normalize();
|
531
|
-
|
532
|
-
// cache the config array for this instance
|
533
|
-
slots.configs = configs;
|
534
|
-
|
535
|
-
return configs;
|
536
291
|
}
|
537
292
|
|
538
293
|
/**
|
@@ -678,6 +433,12 @@ class ESLint {
|
|
678
433
|
*/
|
679
434
|
static configType = "flat";
|
680
435
|
|
436
|
+
/**
|
437
|
+
* The loader to use for finding config files.
|
438
|
+
* @type {ConfigLoader|LegacyConfigLoader}
|
439
|
+
*/
|
440
|
+
#configLoader;
|
441
|
+
|
681
442
|
/**
|
682
443
|
* Creates a new instance of the main ESLint API.
|
683
444
|
* @param {ESLintOptions} options The options for this instance.
|
@@ -701,15 +462,34 @@ class ESLint {
|
|
701
462
|
? new LintResultCache(cacheFilePath, processedOptions.cacheStrategy)
|
702
463
|
: null;
|
703
464
|
|
465
|
+
const configLoaderOptions = {
|
466
|
+
cwd: processedOptions.cwd,
|
467
|
+
baseConfig: processedOptions.baseConfig,
|
468
|
+
overrideConfig: processedOptions.overrideConfig,
|
469
|
+
configFile: processedOptions.configFile,
|
470
|
+
ignoreEnabled: processedOptions.ignore,
|
471
|
+
ignorePatterns: processedOptions.ignorePatterns,
|
472
|
+
defaultConfigs,
|
473
|
+
allowTS: processedOptions.flags.includes("unstable_ts_config")
|
474
|
+
};
|
475
|
+
|
476
|
+
this.#configLoader = processedOptions.flags.includes("unstable_config_lookup_from_file")
|
477
|
+
? new ConfigLoader(configLoaderOptions)
|
478
|
+
: new LegacyConfigLoader(configLoaderOptions);
|
479
|
+
|
480
|
+
debug(`Using config loader ${this.#configLoader.constructor.name}`);
|
481
|
+
|
704
482
|
privateMembers.set(this, {
|
705
483
|
options: processedOptions,
|
706
484
|
linter,
|
707
485
|
cacheFilePath,
|
708
486
|
lintResultCache,
|
709
487
|
defaultConfigs,
|
710
|
-
configs: null
|
488
|
+
configs: null,
|
489
|
+
configLoader: this.#configLoader
|
711
490
|
});
|
712
491
|
|
492
|
+
|
713
493
|
/**
|
714
494
|
* If additional plugins are passed in, add that to the default
|
715
495
|
* configs for this instance.
|
@@ -744,6 +524,15 @@ class ESLint {
|
|
744
524
|
return version;
|
745
525
|
}
|
746
526
|
|
527
|
+
/**
|
528
|
+
* The default configuration that ESLint uses internally. This is provided for tooling that wants to calculate configurations using the same defaults as ESLint.
|
529
|
+
* Keep in mind that the default configuration may change from version to version, so you shouldn't rely on any particular keys or values to be present.
|
530
|
+
* @type {ConfigArray}
|
531
|
+
*/
|
532
|
+
static get defaultConfig() {
|
533
|
+
return defaultConfig;
|
534
|
+
}
|
535
|
+
|
747
536
|
/**
|
748
537
|
* Outputs fixes from the given results to files.
|
749
538
|
* @param {LintResult[]} results The lint results.
|
@@ -813,20 +602,10 @@ class ESLint {
|
|
813
602
|
|
814
603
|
const resultRules = new Map();
|
815
604
|
const {
|
816
|
-
|
605
|
+
configLoader,
|
817
606
|
options: { cwd }
|
818
607
|
} = privateMembers.get(this);
|
819
608
|
|
820
|
-
/*
|
821
|
-
* We can only accurately return rules meta information for linting results if the
|
822
|
-
* results were created by this instance. Otherwise, the necessary rules data is
|
823
|
-
* not available. So if the config array doesn't already exist, just throw an error
|
824
|
-
* to let the user know we can't do anything here.
|
825
|
-
*/
|
826
|
-
if (!configs) {
|
827
|
-
throw createExtraneousResultsError();
|
828
|
-
}
|
829
|
-
|
830
609
|
for (const result of results) {
|
831
610
|
|
832
611
|
/*
|
@@ -845,6 +624,14 @@ class ESLint {
|
|
845
624
|
* All of the plugin and rule information is contained within the
|
846
625
|
* calculated config for the given file.
|
847
626
|
*/
|
627
|
+
let configs;
|
628
|
+
|
629
|
+
try {
|
630
|
+
configs = configLoader.getCachedConfigArrayForFile(filePath);
|
631
|
+
} catch {
|
632
|
+
throw createExtraneousResultsError();
|
633
|
+
}
|
634
|
+
|
848
635
|
const config = configs.getConfig(filePath);
|
849
636
|
|
850
637
|
if (!config) {
|
@@ -919,7 +706,6 @@ class ESLint {
|
|
919
706
|
|
920
707
|
debug(`Using file patterns: ${normalizedPatterns}`);
|
921
708
|
|
922
|
-
const configs = await calculateConfigArray(this, eslintOptions);
|
923
709
|
const {
|
924
710
|
allowInlineConfig,
|
925
711
|
cache,
|
@@ -955,7 +741,7 @@ class ESLint {
|
|
955
741
|
patterns: normalizedPatterns,
|
956
742
|
cwd,
|
957
743
|
globInputPaths,
|
958
|
-
|
744
|
+
configLoader: this.#configLoader,
|
959
745
|
errorOnUnmatchedPattern
|
960
746
|
});
|
961
747
|
const controller = new AbortController();
|
@@ -972,8 +758,9 @@ class ESLint {
|
|
972
758
|
*/
|
973
759
|
const results = await Promise.all(
|
974
760
|
|
975
|
-
filePaths.map(filePath => {
|
761
|
+
filePaths.map(async filePath => {
|
976
762
|
|
763
|
+
const configs = await this.#configLoader.loadConfigArrayForFile(filePath);
|
977
764
|
const config = configs.getConfig(filePath);
|
978
765
|
|
979
766
|
/*
|
@@ -1111,7 +898,6 @@ class ESLint {
|
|
1111
898
|
linter,
|
1112
899
|
options: eslintOptions
|
1113
900
|
} = privateMembers.get(this);
|
1114
|
-
const configs = await calculateConfigArray(this, eslintOptions);
|
1115
901
|
const {
|
1116
902
|
allowInlineConfig,
|
1117
903
|
cwd,
|
@@ -1125,21 +911,21 @@ class ESLint {
|
|
1125
911
|
const startTime = Date.now();
|
1126
912
|
const fixTypesSet = fixTypes ? new Set(fixTypes) : null;
|
1127
913
|
const resolvedFilename = path.resolve(cwd, filePath || "__placeholder__.js");
|
1128
|
-
const
|
1129
|
-
|
1130
|
-
const fixer = getFixerForFixTypes(fix, fixTypesSet, config);
|
914
|
+
const configs = await this.#configLoader.loadConfigArrayForFile(resolvedFilename);
|
915
|
+
const configStatus = configs?.getConfigStatus(resolvedFilename) ?? "unconfigured";
|
1131
916
|
|
1132
917
|
// Clear the last used config arrays.
|
1133
|
-
if (resolvedFilename &&
|
918
|
+
if (resolvedFilename && configStatus !== "matched") {
|
1134
919
|
const shouldWarnIgnored = typeof warnIgnored === "boolean" ? warnIgnored : constructorWarnIgnored;
|
1135
920
|
|
1136
921
|
if (shouldWarnIgnored) {
|
1137
|
-
const configStatus = configs.getConfigStatus(resolvedFilename);
|
1138
|
-
|
1139
922
|
results.push(createIgnoreResult(resolvedFilename, cwd, configStatus));
|
1140
923
|
}
|
1141
924
|
} else {
|
1142
925
|
|
926
|
+
const config = configs.getConfig(resolvedFilename);
|
927
|
+
const fixer = getFixerForFixTypes(fix, fixTypesSet, config);
|
928
|
+
|
1143
929
|
// Do lint.
|
1144
930
|
results.push(verifyText({
|
1145
931
|
text: code,
|
@@ -1271,7 +1057,14 @@ class ESLint {
|
|
1271
1057
|
}
|
1272
1058
|
const options = privateMembers.get(this).options;
|
1273
1059
|
const absolutePath = path.resolve(options.cwd, filePath);
|
1274
|
-
const configs = await
|
1060
|
+
const configs = await this.#configLoader.loadConfigArrayForFile(absolutePath);
|
1061
|
+
|
1062
|
+
if (!configs) {
|
1063
|
+
const error = new Error("Could not find config file.");
|
1064
|
+
|
1065
|
+
error.messageTemplate = "config-file-missing";
|
1066
|
+
throw error;
|
1067
|
+
}
|
1275
1068
|
|
1276
1069
|
return configs.getConfig(absolutePath);
|
1277
1070
|
}
|
@@ -1279,14 +1072,22 @@ class ESLint {
|
|
1279
1072
|
/**
|
1280
1073
|
* Finds the config file being used by this instance based on the options
|
1281
1074
|
* passed to the constructor.
|
1075
|
+
* @param {string} [filePath] The path of the file to find the config file for.
|
1282
1076
|
* @returns {Promise<string|undefined>} The path to the config file being used or
|
1283
1077
|
* `undefined` if no config file is being used.
|
1284
1078
|
*/
|
1285
|
-
|
1079
|
+
findConfigFile(filePath) {
|
1286
1080
|
const options = privateMembers.get(this).options;
|
1287
|
-
const { configFilePath } = await locateConfigFileToUse(options, this.hasFlag("unstable_ts_config"));
|
1288
1081
|
|
1289
|
-
|
1082
|
+
/*
|
1083
|
+
* Because the new config lookup scheme skips the current directory
|
1084
|
+
* and looks into the parent directories, we need to use a placeholder
|
1085
|
+
* directory to ensure the file in cwd is checked.
|
1086
|
+
*/
|
1087
|
+
const fakeCwd = path.join(options.cwd, "__placeholder__");
|
1088
|
+
|
1089
|
+
return this.#configLoader.findConfigFileForPath(filePath ?? fakeCwd)
|
1090
|
+
.catch(() => void 0);
|
1290
1091
|
}
|
1291
1092
|
|
1292
1093
|
/**
|
@@ -12,6 +12,7 @@
|
|
12
12
|
const { SourceCode } = require("./source-code");
|
13
13
|
const createDebug = require("debug");
|
14
14
|
const astUtils = require("../../shared/ast-utils");
|
15
|
+
const espree = require("espree");
|
15
16
|
const eslintScope = require("eslint-scope");
|
16
17
|
const evk = require("eslint-visitor-keys");
|
17
18
|
const { validateLanguageOptions } = require("./validate-language-options");
|
@@ -69,6 +70,13 @@ module.exports = {
|
|
69
70
|
nodeTypeKey: "type",
|
70
71
|
visitorKeys: evk.KEYS,
|
71
72
|
|
73
|
+
defaultLanguageOptions: {
|
74
|
+
sourceType: "module",
|
75
|
+
ecmaVersion: "latest",
|
76
|
+
parser: espree,
|
77
|
+
parserOptions: {}
|
78
|
+
},
|
79
|
+
|
72
80
|
validateLanguageOptions,
|
73
81
|
|
74
82
|
/**
|
package/lib/linter/linter.js
CHANGED
@@ -1643,29 +1643,26 @@ class Linter {
|
|
1643
1643
|
const options = normalizeVerifyOptions(providedOptions, config);
|
1644
1644
|
const languageOptions = config.languageOptions;
|
1645
1645
|
|
1646
|
-
|
1647
|
-
languageOptions.ecmaVersion
|
1648
|
-
|
1649
|
-
|
1650
|
-
// double check that there is a parser to avoid mysterious error messages
|
1651
|
-
if (!languageOptions.parser) {
|
1652
|
-
throw new TypeError(`No parser specified for ${options.filename}`);
|
1653
|
-
}
|
1646
|
+
if (config.language === jslang) {
|
1647
|
+
languageOptions.ecmaVersion = normalizeEcmaVersionForLanguageOptions(
|
1648
|
+
languageOptions.ecmaVersion
|
1649
|
+
);
|
1654
1650
|
|
1655
|
-
|
1656
|
-
|
1657
|
-
|
1651
|
+
// Espree expects this information to be passed in
|
1652
|
+
if (isEspree(languageOptions.parser)) {
|
1653
|
+
const parserOptions = languageOptions.parserOptions;
|
1658
1654
|
|
1659
|
-
|
1655
|
+
if (languageOptions.sourceType) {
|
1660
1656
|
|
1661
|
-
|
1657
|
+
parserOptions.sourceType = languageOptions.sourceType;
|
1662
1658
|
|
1663
|
-
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
1659
|
+
if (
|
1660
|
+
parserOptions.sourceType === "module" &&
|
1661
|
+
parserOptions.ecmaFeatures &&
|
1662
|
+
parserOptions.ecmaFeatures.globalReturn
|
1663
|
+
) {
|
1664
|
+
parserOptions.ecmaFeatures.globalReturn = false;
|
1665
|
+
}
|
1669
1666
|
}
|
1670
1667
|
}
|
1671
1668
|
}
|