@nx/eslint 22.7.2 → 22.7.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/eslint",
3
- "version": "22.7.2",
3
+ "version": "22.7.3",
4
4
  "private": false,
5
5
  "description": "The ESLint plugin for Nx contains executors, generators and utilities used for linting JavaScript/TypeScript projects within an Nx workspace.",
6
6
  "repository": {
@@ -32,19 +32,19 @@
32
32
  "generators": "./generators.json",
33
33
  "executors": "./executors.json",
34
34
  "peerDependencies": {
35
- "@nx/jest": "22.7.2",
35
+ "@nx/jest": "22.7.3",
36
36
  "@zkochan/js-yaml": "0.0.7",
37
37
  "eslint": "^8.0.0 || ^9.0.0 || ^10.0.0"
38
38
  },
39
39
  "dependencies": {
40
- "@nx/devkit": "22.7.2",
41
- "@nx/js": "22.7.2",
40
+ "@nx/devkit": "22.7.3",
41
+ "@nx/js": "22.7.3",
42
42
  "semver": "^7.6.3",
43
43
  "tslib": "^2.3.0",
44
44
  "typescript": "~5.9.2"
45
45
  },
46
46
  "devDependencies": {
47
- "nx": "22.7.2"
47
+ "nx": "22.7.3"
48
48
  },
49
49
  "peerDependenciesMeta": {
50
50
  "@nx/jest": {
@@ -1,5 +1,6 @@
1
1
  import { Tree } from '@nx/devkit';
2
2
  import { ESLint } from 'eslint';
3
+ export declare function renameLegacyEslintrcFile(path: string, format: 'mjs' | 'cjs'): string;
3
4
  /**
4
5
  * Converts an ESLint JSON config to a flat config.
5
6
  * Deletes the original file along with .eslintignore if it exists.
@@ -1 +1 @@
1
- {"version":3,"file":"json-converter.d.ts","sourceRoot":"","sources":["../../../../../../../packages/eslint/src/generators/convert-to-flat-config/converters/json-converter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAS,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAehC;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,CAAC,UAAU,EACzB,WAAW,EAAE,MAAM,EAAE,EACrB,MAAM,EAAE,KAAK,GAAG,KAAK,GACpB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CA8OjE"}
1
+ {"version":3,"file":"json-converter.d.ts","sourceRoot":"","sources":["../../../../../../../packages/eslint/src/generators/convert-to-flat-config/converters/json-converter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAS,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAmBhC,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,KAAK,GAAG,KAAK,GACpB,MAAM,CAOR;AA0DD;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,CAAC,UAAU,EACzB,WAAW,EAAE,MAAM,EAAE,EACrB,MAAM,EAAE,KAAK,GAAG,KAAK,GACpB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CA6PjE"}
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renameLegacyEslintrcFile = renameLegacyEslintrcFile;
3
4
  exports.convertEslintJsonToFlatConfig = convertEslintJsonToFlatConfig;
4
5
  const tslib_1 = require("tslib");
5
6
  const devkit_1 = require("@nx/devkit");
@@ -7,6 +8,57 @@ const ts = tslib_1.__importStar(require("typescript"));
7
8
  const ast_utils_1 = require("../../utils/flat-config/ast-utils");
8
9
  const eslint_file_1 = require("../../utils/eslint-file");
9
10
  const path_utils_1 = require("../../utils/flat-config/path-utils");
11
+ // Rewrites legacy `.eslintrc[.base][.json]` / `.eslintignore` filenames to their flat-config
12
+ // counterparts. Used for `extends` local paths, rule option values that embed these filenames,
13
+ // and nx.json / project.json input globs that referenced the deleted files. Accepts
14
+ // extensionless `.eslintrc` since ESLint treats that as JSON by convention.
15
+ function renameLegacyEslintrcFile(path, format) {
16
+ return path
17
+ .replace(/(^|.*?)\.eslintrc(\.base)?(\.json)?$/, `$1eslint$2.config.${format}`)
18
+ .replace(/(^|.*?)\.eslintignore$/, `$1eslint.config.${format}`);
19
+ }
20
+ // In flat config, `@nx/workspace/<rule>` is parsed as plugin `@nx/workspace`, rule `<rule>`.
21
+ // The `@nx` plugin already exposes workspace rules under both `workspace/<rule>` and `workspace-<rule>` keys.
22
+ // Rewriting to `@nx/workspace-<rule>` makes ESLint resolve them via the already-registered `@nx` plugin.
23
+ function renameLegacyWorkspaceRules(rules) {
24
+ const renamed = {};
25
+ for (const [key, value] of Object.entries(rules)) {
26
+ const newKey = key.startsWith('@nx/workspace/')
27
+ ? '@nx/workspace-' + key.slice('@nx/workspace/'.length)
28
+ : key;
29
+ renamed[newKey] = value;
30
+ }
31
+ return renamed;
32
+ }
33
+ // Rewrites references to the legacy `.eslintrc[.base].json` / `.eslintignore` that may appear
34
+ // inside rule option values (e.g. `@nx/dependency-checks`'s `ignoredFiles`) to point at the
35
+ // generated flat-config files instead. Without this, rule options keep pointing at files that
36
+ // no longer exist after the conversion.
37
+ function rewriteStaleEslintrcRefs(value, format) {
38
+ if (typeof value === 'string') {
39
+ return renameLegacyEslintrcFile(value, format);
40
+ }
41
+ if (Array.isArray(value)) {
42
+ const mapped = value.map((v) => rewriteStaleEslintrcRefs(v, format));
43
+ // Rewriting may collapse distinct strings (e.g. `.eslintrc.json` and
44
+ // `.eslintrc.base.json`) into identical entries; dedupe string arrays.
45
+ if (mapped.every((v) => typeof v === 'string')) {
46
+ return Array.from(new Set(mapped));
47
+ }
48
+ return mapped;
49
+ }
50
+ if (value && typeof value === 'object') {
51
+ const out = {};
52
+ for (const [k, v] of Object.entries(value)) {
53
+ out[k] = rewriteStaleEslintrcRefs(v, format);
54
+ }
55
+ return out;
56
+ }
57
+ return value;
58
+ }
59
+ function preprocessRules(rules, format) {
60
+ return rewriteStaleEslintrcRefs(renameLegacyWorkspaceRules(rules), format);
61
+ }
10
62
  /**
11
63
  * Converts an ESLint JSON config to a flat config.
12
64
  * Deletes the original file along with .eslintignore if it exists.
@@ -18,10 +70,17 @@ function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths, format)
18
70
  let isESLintJSNeeded = false;
19
71
  let combinedConfig = [];
20
72
  let languageOptions = [];
21
- // exclude dist and eslint config from being linted, which matches the default for new workspaces
22
- exportElements.push((0, ast_utils_1.generateAst)({
23
- ignores: ['**/dist', '**/out-tsc'],
24
- }));
73
+ if (config.rules) {
74
+ config.rules = preprocessRules(config.rules, format);
75
+ }
76
+ if (config.overrides) {
77
+ config.overrides = config.overrides.map((override) => override.rules
78
+ ? {
79
+ ...override,
80
+ rules: preprocessRules(override.rules, format),
81
+ }
82
+ : override);
83
+ }
25
84
  if (config.extends) {
26
85
  const extendsResult = addExtends(importsMap, exportElements, config, format);
27
86
  isFlatCompatNeeded = extendsResult.isFlatCompatNeeded;
@@ -101,28 +160,30 @@ function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths, format)
101
160
  if (Object.keys(remainingRest).length > 0 || hasNonEmptyRules) {
102
161
  if (remainingOverride.env ||
103
162
  remainingOverride.extends ||
104
- remainingOverride.plugins ||
105
- remainingOverride.parser) {
163
+ remainingOverride.plugins) {
106
164
  isFlatCompatNeeded = true;
107
165
  }
108
- exportElements.push((0, ast_utils_1.generateFlatOverride)(remainingOverride, format));
166
+ exportElements.push((0, ast_utils_1.generateFlatOverride)(remainingOverride, format, importsMap));
109
167
  }
110
168
  return;
111
169
  }
112
170
  }
113
- if (override.env ||
114
- override.extends ||
115
- override.plugins ||
116
- override.parser) {
171
+ if (override.env || override.extends || override.plugins) {
117
172
  isFlatCompatNeeded = true;
118
173
  }
119
- exportElements.push((0, ast_utils_1.generateFlatOverride)(override, format));
174
+ exportElements.push((0, ast_utils_1.generateFlatOverride)(override, format, importsMap));
120
175
  });
121
176
  }
122
177
  if (config.ignorePatterns) {
123
178
  const patterns = (Array.isArray(config.ignorePatterns)
124
179
  ? config.ignorePatterns
125
- : [config.ignorePatterns]).filter((pattern) => !['**/*', '!**/*', 'node_modules'].includes(pattern)); // these are useless in a flat config
180
+ : [config.ignorePatterns]).filter((pattern) =>
181
+ // Drop patterns that are meaningless in flat config. `'**/*'` and
182
+ // `'!**/*'` were eslintrc cascading toggles; `node_modules` is already
183
+ // ignored by default. Real negations like `['dist/**', '!dist/keep.js']`
184
+ // are preserved — flat config still supports un-ignoring within a
185
+ // broader ignores block.
186
+ !['**/*', '!**/*', 'node_modules'].includes(pattern));
126
187
  if (patterns.length > 0) {
127
188
  exportElements.push((0, ast_utils_1.generateAst)({
128
189
  ignores: patterns.map((path) => (0, path_utils_1.mapFilePath)(path)),
@@ -165,11 +226,10 @@ function addExtends(importsMap, configBlocks, config, format) {
165
226
  extendsConfig
166
227
  .filter((imp) => imp.match(/^\.?(\.\/)/))
167
228
  .forEach((imp, index) => {
168
- if (imp.match(/\.eslintrc(.base)?\.json$/)) {
229
+ if (imp.match(/\.eslintrc(\.base)?(\.json)?$/)) {
169
230
  const localName = index ? `baseConfig${index}` : 'baseConfig';
170
231
  configBlocks.push((0, ast_utils_1.generateSpreadElement)(localName));
171
- const newImport = imp.replace(/^(.*)\.eslintrc(.base)?\.json$/, `$1eslint$2.config.${format}`);
172
- importsMap.set(newImport, localName);
232
+ importsMap.set(renameLegacyEslintrcFile(imp, format), localName);
173
233
  }
174
234
  else {
175
235
  eslintrcConfigs.push(imp);
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../../../../packages/eslint/src/generators/convert-to-flat-config/generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,iBAAiB,EASjB,IAAI,EAGL,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kCAAkC,EAAE,MAAM,UAAU,CAAC;AAc9D,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,kCAAkC,GAC1C,OAAO,CAAC,IAAI,GAAG,iBAAiB,CAAC,CA6CnC;AAED,eAAe,4BAA4B,CAAC"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../../../../packages/eslint/src/generators/convert-to-flat-config/generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,iBAAiB,EASjB,IAAI,EAGL,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,kCAAkC,EAAE,MAAM,UAAU,CAAC;AAiB9D,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,kCAAkC,GAC1C,OAAO,CAAC,IAAI,GAAG,iBAAiB,CAAC,CA8CnC;AAED,eAAe,4BAA4B,CAAC"}
@@ -28,8 +28,9 @@ async function convertToFlatConfigGenerator(tree, options) {
28
28
  for (const ignoreFile of eslintIgnoreFiles) {
29
29
  tree.delete(ignoreFile);
30
30
  }
31
- // replace references in nx.json
31
+ // replace references in nx.json and project.json files
32
32
  updateNxJsonConfig(tree, options.eslintConfigFormat);
33
+ updateProjectConfigsInputs(tree, options.eslintConfigFormat);
33
34
  // install missing packages
34
35
  if (!options.skipFormat) {
35
36
  await (0, devkit_1.formatFiles)(tree);
@@ -86,35 +87,108 @@ function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslint
86
87
  eslintIgnoreFiles.add(ignorePath);
87
88
  }
88
89
  }
89
- // update names of eslint files in nx.json
90
- // and remove eslintignore
90
+ // Rewrites input entries that reference legacy `.eslintrc[.base].json` / `.eslintignore`
91
+ // files to their flat-config counterparts, then dedupes so the rewrite doesn't produce
92
+ // duplicates of entries that already pointed at the flat config. Leaves non-string /
93
+ // non-fileset inputs (runtime/env/dependentTasksOutputFiles/etc.) untouched.
94
+ function rewriteLegacyInputs(inputs, format) {
95
+ const seenStrings = new Set();
96
+ const result = [];
97
+ for (const entry of inputs) {
98
+ if (typeof entry === 'string') {
99
+ const rewritten = (0, json_converter_1.renameLegacyEslintrcFile)(entry, format);
100
+ if (seenStrings.has(rewritten))
101
+ continue;
102
+ seenStrings.add(rewritten);
103
+ result.push(rewritten);
104
+ }
105
+ else if ('fileset' in entry) {
106
+ const rewritten = (0, json_converter_1.renameLegacyEslintrcFile)(entry.fileset, format);
107
+ // Preserve the original reference when nothing changed so downstream identity
108
+ // checks (e.g. `inputsEqual`) don't see a spurious mutation.
109
+ result.push(rewritten === entry.fileset ? entry : { ...entry, fileset: rewritten });
110
+ }
111
+ else {
112
+ result.push(entry);
113
+ }
114
+ }
115
+ return result;
116
+ }
117
+ // Adds `value` to `inputs` (after rewriting) when the rewritten set doesn't already contain it.
118
+ function ensureInputPresent(inputs, value, format) {
119
+ const rewritten = rewriteLegacyInputs(inputs, format);
120
+ if (!rewritten.some((entry) => entry === value)) {
121
+ rewritten.push(value);
122
+ }
123
+ return rewritten;
124
+ }
125
+ // Updates nx.json: rewrites stale eslintrc/eslintignore references across all targetDefaults
126
+ // inputs and namedInputs, and ensures lint targets include the new flat config file as an input
127
+ // (and `production` excludes it).
91
128
  function updateNxJsonConfig(tree, format) {
92
- if (tree.exists('nx.json')) {
93
- (0, devkit_1.updateJson)(tree, 'nx.json', (json) => {
94
- if (json.targetDefaults?.lint?.inputs) {
95
- const inputSet = new Set(json.targetDefaults.lint.inputs);
96
- inputSet.add(`{workspaceRoot}/eslint.config.${format}`);
97
- json.targetDefaults.lint.inputs = Array.from(inputSet);
129
+ if (!tree.exists('nx.json')) {
130
+ return;
131
+ }
132
+ (0, devkit_1.updateJson)(tree, 'nx.json', (json) => {
133
+ if (json.targetDefaults) {
134
+ for (const [name, target] of Object.entries(json.targetDefaults)) {
135
+ if (!target.inputs)
136
+ continue;
137
+ const isLintTarget = name === 'lint' || name === ESLINT_LINT_EXECUTOR;
138
+ target.inputs = isLintTarget
139
+ ? ensureInputPresent(target.inputs, `{workspaceRoot}/eslint.config.${format}`, format)
140
+ : rewriteLegacyInputs(target.inputs, format);
98
141
  }
99
- if (json.targetDefaults?.['@nx/eslint:lint']?.inputs) {
100
- const inputSet = new Set(json.targetDefaults['@nx/eslint:lint'].inputs);
101
- inputSet.add(`{workspaceRoot}/eslint.config.${format}`);
102
- json.targetDefaults['@nx/eslint:lint'].inputs = Array.from(inputSet);
142
+ }
143
+ if (json.namedInputs) {
144
+ for (const [name, inputs] of Object.entries(json.namedInputs)) {
145
+ json.namedInputs[name] =
146
+ name === 'production'
147
+ ? ensureInputPresent(inputs, `!{projectRoot}/eslint.config.${format}`, format)
148
+ : rewriteLegacyInputs(inputs, format);
103
149
  }
104
- if (json.namedInputs?.production) {
105
- const inputSet = new Set(json.namedInputs.production);
106
- inputSet.add(`!{projectRoot}/eslint.config.${format}`);
107
- json.namedInputs.production = Array.from(inputSet);
150
+ }
151
+ return json;
152
+ });
153
+ }
154
+ // Walks every project's `targets.*.inputs` and `namedInputs.*`, rewriting stale references.
155
+ function updateProjectConfigsInputs(tree, format) {
156
+ for (const [project, projectConfig] of (0, devkit_1.getProjects)(tree)) {
157
+ let changed = false;
158
+ if (projectConfig.targets) {
159
+ for (const target of Object.values(projectConfig.targets)) {
160
+ if (!target.inputs)
161
+ continue;
162
+ const rewritten = rewriteLegacyInputs(target.inputs, format);
163
+ if (!inputsEqual(target.inputs, rewritten)) {
164
+ target.inputs = rewritten;
165
+ changed = true;
166
+ }
108
167
  }
109
- return json;
110
- });
168
+ }
169
+ if (projectConfig.namedInputs) {
170
+ for (const [name, inputs] of Object.entries(projectConfig.namedInputs)) {
171
+ const rewritten = rewriteLegacyInputs(inputs, format);
172
+ if (!inputsEqual(inputs, rewritten)) {
173
+ projectConfig.namedInputs[name] = rewritten;
174
+ changed = true;
175
+ }
176
+ }
177
+ }
178
+ if (changed) {
179
+ (0, devkit_1.updateProjectConfiguration)(tree, project, projectConfig);
180
+ }
111
181
  }
112
182
  }
183
+ function inputsEqual(a, b) {
184
+ return a.length === b.length && a.every((entry, i) => entry === b[i]);
185
+ }
113
186
  function convertConfigToFlatConfig(tree, root, source, target, format, ignorePath) {
114
187
  const ignorePaths = ignorePath
115
188
  ? [ignorePath, `${root}/.eslintignore`]
116
189
  : [`${root}/.eslintignore`];
117
- if (source.endsWith('.json')) {
190
+ // `.eslintrc` (no extension) is JSON by convention.
191
+ if (source.endsWith('.json') || (0, path_1.basename)(source) === '.eslintrc') {
118
192
  const config = (0, devkit_1.readJson)(tree, `${root}/${source}`);
119
193
  const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths, format);
120
194
  return processConvertedConfig(tree, root, source, target, conversionResult);
@@ -10,6 +10,13 @@
10
10
  "description": "Skip formatting files.",
11
11
  "default": false,
12
12
  "x-priority": "internal"
13
+ },
14
+ "eslintConfigFormat": {
15
+ "type": "string",
16
+ "description": "The format of the generated ESLint flat config files.",
17
+ "enum": ["mjs", "cjs"],
18
+ "default": "mjs",
19
+ "x-priority": "internal"
13
20
  }
14
21
  },
15
22
  "additionalProperties": false,
@@ -73,7 +73,7 @@ export declare function overrideNeedsCompat(override: Partial<Linter.ConfigOverr
73
73
  */
74
74
  export declare function generateFlatOverride(_override: Partial<Linter.ConfigOverride<Linter.RulesRecord>> & {
75
75
  ignores?: Linter.FlatConfig['ignores'];
76
- }, format: 'mjs' | 'cjs'): ts.ObjectLiteralExpression | ts.SpreadElement;
76
+ }, format: 'mjs' | 'cjs', importsMap?: Map<string, string>): ts.ObjectLiteralExpression | ts.SpreadElement;
77
77
  export declare function generateFlatPredefinedConfig(predefinedConfigName: string, moduleName?: string, spread?: boolean): ts.ObjectLiteralExpression | ts.SpreadElement | ts.ElementAccessExpression;
78
78
  export declare function mapFilePaths<T extends Partial<Linter.ConfigOverride<Linter.RulesRecord>>>(_override: T): T;
79
79
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ast-utils.d.ts","sourceRoot":"","sources":["../../../../../../../packages/eslint/src/generators/utils/flat-config/ast-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ast-utils.d.ts","sourceRoot":"","sources":["../../../../../../../packages/eslint/src/generators/utils/flat-config/ast-utils.ts"],"names":[],"mappings":"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"}
@@ -1101,7 +1101,7 @@ function overrideNeedsCompat(override) {
1101
1101
  * Generates an AST object or spread element representing a modern flat config entry,
1102
1102
  * based on a given legacy eslintrc JSON override object
1103
1103
  */
1104
- function generateFlatOverride(_override, format) {
1104
+ function generateFlatOverride(_override, format, importsMap) {
1105
1105
  const override = mapFilePaths(_override);
1106
1106
  // We do not need the compat tooling for this override
1107
1107
  if (!overrideNeedsCompat(override)) {
@@ -1159,7 +1159,7 @@ function generateFlatOverride(_override, format) {
1159
1159
  else {
1160
1160
  // Change parser to import statement.
1161
1161
  return format === 'mjs'
1162
- ? generateESMParserImport(override)
1162
+ ? generateESMParserImport(override, importsMap)
1163
1163
  : generateCJSParserImport(override);
1164
1164
  }
1165
1165
  },
@@ -1215,12 +1215,19 @@ function generateFlatOverride(_override, format) {
1215
1215
  ], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createParenthesizedExpression(ts.factory.createObjectLiteralExpression(objectLiteralElements, true))),
1216
1216
  ]));
1217
1217
  }
1218
- function generateESMParserImport(override) {
1219
- return ts.factory.createPropertyAssignment('parser', ts.factory.createAwaitExpression(ts.factory.createCallExpression(ts.factory.createIdentifier('import'), undefined, [
1220
- ts.factory.createStringLiteral(override['languageOptions']?.['parserOptions']?.parser ??
1221
- override['languageOptions']?.parser ??
1222
- override.parser),
1223
- ])));
1218
+ function generateESMParserImport(override, importsMap) {
1219
+ const parser = override['languageOptions']?.['parserOptions']?.parser ??
1220
+ override['languageOptions']?.parser ??
1221
+ override.parser;
1222
+ // Dynamic `await import()` doesn't expose top-level CJS exports (e.g. `parseForESLint`)
1223
+ // because those are nested under `.default`. Use a hoisted static import instead so the
1224
+ // resolved binding matches the parser's module.exports shape.
1225
+ if (importsMap) {
1226
+ const parserName = importsMap.get(parser) ?? (0, devkit_1.names)(parser).propertyName;
1227
+ importsMap.set(parser, parserName);
1228
+ return ts.factory.createPropertyAssignment('parser', ts.factory.createIdentifier(parserName));
1229
+ }
1230
+ return ts.factory.createPropertyAssignment('parser', ts.factory.createAwaitExpression(ts.factory.createCallExpression(ts.factory.createIdentifier('import'), undefined, [ts.factory.createStringLiteral(parser)])));
1224
1231
  }
1225
1232
  function generateCJSParserImport(override) {
1226
1233
  return ts.factory.createPropertyAssignment('parser', ts.factory.createCallExpression(ts.factory.createIdentifier('require'), undefined, [
@@ -1237,17 +1244,13 @@ function mapFilePaths(_override) {
1237
1244
  const override = {
1238
1245
  ..._override,
1239
1246
  };
1247
+ // Dedupe after mapping — both source-side duplicates and glob-mapping collisions collapse.
1248
+ const normalize = (value) => Array.from(new Set((Array.isArray(value) ? value : [value]).map(path_utils_1.mapFilePath)));
1240
1249
  if (override.files) {
1241
- override.files = Array.isArray(override.files)
1242
- ? override.files
1243
- : [override.files];
1244
- override.files = override.files.map((file) => (0, path_utils_1.mapFilePath)(file));
1250
+ override.files = normalize(override.files);
1245
1251
  }
1246
1252
  if (override.excludedFiles) {
1247
- override.excludedFiles = Array.isArray(override.excludedFiles)
1248
- ? override.excludedFiles
1249
- : [override.excludedFiles];
1250
- override.excludedFiles = override.excludedFiles.map((file) => (0, path_utils_1.mapFilePath)(file));
1253
+ override.excludedFiles = normalize(override.excludedFiles);
1251
1254
  }
1252
1255
  return override;
1253
1256
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../packages/eslint/src/plugins/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,aAAa,EAMd,MAAM,YAAY,CAAC;AAwBpB,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAuHD,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,mBAAmB,CAoF1D,CAAC;AAEF,eAAO,MAAM,aAAa,oCAAc,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../packages/eslint/src/plugins/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,aAAa,EAMd,MAAM,YAAY,CAAC;AAwBpB,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAoID,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,mBAAmB,CAoF1D,CAAC;AAEF,eAAO,MAAM,aAAa,oCAAc,CAAC"}
@@ -53,13 +53,17 @@ const internalCreateNodesV2 = async (ESLint, configFilePath, options, context, p
53
53
  });
54
54
  return sharedEslint;
55
55
  };
56
- const projects = {};
57
- await Promise.all(projectRootsByEslintRoots.get(configDir).map(async (projectRoot) => {
56
+ // Collect each project root's contribution in parallel, but write
57
+ // them into `projects` afterwards in input order so insertion order
58
+ // (and therefore downstream merge order) is deterministic. Mutating
59
+ // `projects` from inside `Promise.all` would order keys by which
60
+ // async branch resolves first.
61
+ const orderedProjectRoots = projectRootsByEslintRoots.get(configDir) ?? [];
62
+ const contributions = await Promise.all(orderedProjectRoots.map(async (projectRoot) => {
58
63
  const hash = hashByRoot.get(projectRoot);
59
64
  if (projectsCache[hash]) {
60
65
  // We can reuse the projects in the cache.
61
- Object.assign(projects, projectsCache[hash]);
62
- return;
66
+ return projectsCache[hash];
63
67
  }
64
68
  let hasNonIgnoredLintableFiles = false;
65
69
  if (configDir !== projectRoot || projectRoot === '.') {
@@ -77,19 +81,25 @@ const internalCreateNodesV2 = async (ESLint, configFilePath, options, context, p
77
81
  if (!hasNonIgnoredLintableFiles) {
78
82
  // No lintable files in the project, store in the cache and skip further processing
79
83
  projectsCache[hash] = {};
80
- return;
84
+ return null;
81
85
  }
82
86
  const project = getProjectUsingESLintConfig(configFilePath, projectRoot, eslintVersion, options, context, pmc, tsconfigChainsByProjectRoot.get(projectRoot) ?? []);
83
87
  if (project) {
84
- projects[projectRoot] = project;
88
+ const entry = { [projectRoot]: project };
85
89
  // Store project into the cache
86
- projectsCache[hash] = { [projectRoot]: project };
87
- }
88
- else {
89
- // No project found, store in the cache
90
- projectsCache[hash] = {};
90
+ projectsCache[hash] = entry;
91
+ return entry;
91
92
  }
93
+ // No project found, store in the cache
94
+ projectsCache[hash] = {};
95
+ return null;
92
96
  }));
97
+ const projects = {};
98
+ for (const contribution of contributions) {
99
+ if (contribution) {
100
+ Object.assign(projects, contribution);
101
+ }
102
+ }
93
103
  return {
94
104
  projects,
95
105
  };