@nx/eslint 20.3.0-canary.20241218-fb40366 → 20.3.0-canary.20241220-0980006

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/migrations.json CHANGED
@@ -24,6 +24,11 @@
24
24
  "version": "20.2.0-beta.5",
25
25
  "description": "Update TypeScript ESLint packages to v8.13.0 if they are already on v8",
26
26
  "implementation": "./src/migrations/update-20-2-0/update-typescript-eslint-v8-13-0"
27
+ },
28
+ "add-file-extensions-to-overrides": {
29
+ "version": "20.3.0-beta.1",
30
+ "description": "Update ESLint flat config to include .cjs, .mjs, .cts, and .mts files in overrides (if needed)",
31
+ "implementation": "./src/migrations/update-20-3-0/add-file-extensions-to-overrides"
27
32
  }
28
33
  },
29
34
  "packageJsonUpdates": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/eslint",
3
- "version": "20.3.0-canary.20241218-fb40366",
3
+ "version": "20.3.0-canary.20241220-0980006",
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": {
@@ -35,8 +35,8 @@
35
35
  "eslint": "^8.0.0 || ^9.0.0"
36
36
  },
37
37
  "dependencies": {
38
- "@nx/devkit": "20.3.0-canary.20241218-fb40366",
39
- "@nx/js": "20.3.0-canary.20241218-fb40366",
38
+ "@nx/devkit": "20.3.0-canary.20241220-0980006",
39
+ "@nx/js": "20.3.0-canary.20241220-0980006",
40
40
  "semver": "^7.5.3",
41
41
  "tslib": "^2.3.0",
42
42
  "typescript": "~5.6.2"
@@ -17,6 +17,10 @@ function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths) {
17
17
  let isESLintJSNeeded = false;
18
18
  let combinedConfig = [];
19
19
  let languageOptions = [];
20
+ // exclude dist and eslint config from being linted, which matches the default for new workspaces
21
+ exportElements.push((0, ast_utils_1.generateAst)({
22
+ ignores: ['**/dist'],
23
+ }));
20
24
  if (config.extends) {
21
25
  const extendsResult = addExtends(importsMap, exportElements, config);
22
26
  isFlatCompatNeeded = extendsResult.isFlatCompatNeeded;
@@ -122,7 +126,7 @@ function addExtends(importsMap, configBlocks, config) {
122
126
  if (imp.match(/\.eslintrc(.base)?\.json$/)) {
123
127
  const localName = index ? `baseConfig${index}` : 'baseConfig';
124
128
  configBlocks.push((0, ast_utils_1.generateSpreadElement)(localName));
125
- const newImport = imp.replace(/^(.*)\.eslintrc(.base)?\.json$/, '$1eslint$2.config.js');
129
+ const newImport = imp.replace(/^(.*)\.eslintrc(.base)?\.json$/, '$1eslint$2.config.cjs');
126
130
  importsMap.set(newImport, localName);
127
131
  }
128
132
  else {
@@ -15,9 +15,9 @@ async function convertToFlatConfigGenerator(tree, options) {
15
15
  throw new Error('Only json and yaml eslint config files are supported for conversion');
16
16
  }
17
17
  const eslintIgnoreFiles = new Set(['.eslintignore']);
18
- // convert root eslint config to eslint.config.js
18
+ // convert root eslint config to eslint.config.cjs
19
19
  convertRootToFlatConfig(tree, eslintFile);
20
- // convert project eslint files to eslint.config.js
20
+ // convert project eslint files to eslint.config.cjs
21
21
  const projects = (0, devkit_1.getProjects)(tree);
22
22
  for (const [project, projectConfig] of projects) {
23
23
  convertProjectToFlatConfig(tree, project, projectConfig, (0, devkit_1.readNxJson)(tree), eslintIgnoreFiles);
@@ -37,9 +37,9 @@ async function convertToFlatConfigGenerator(tree, options) {
37
37
  exports.default = convertToFlatConfigGenerator;
38
38
  function convertRootToFlatConfig(tree, eslintFile) {
39
39
  if (/\.base\.(js|json|yml|yaml)$/.test(eslintFile)) {
40
- convertConfigToFlatConfig(tree, '', eslintFile, 'eslint.base.config.js');
40
+ convertConfigToFlatConfig(tree, '', eslintFile, 'eslint.base.config.cjs');
41
41
  }
42
- convertConfigToFlatConfig(tree, '', eslintFile.replace('.base.', '.'), 'eslint.config.js');
42
+ convertConfigToFlatConfig(tree, '', eslintFile.replace('.base.', '.'), 'eslint.config.cjs');
43
43
  }
44
44
  function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslintIgnoreFiles) {
45
45
  const eslintFile = (0, eslint_file_1.findEslintFile)(tree, projectConfig.root);
@@ -67,7 +67,7 @@ function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslint
67
67
  ? p === '@nx/eslint/plugin'
68
68
  : p.plugin === '@nx/eslint/plugin');
69
69
  if (nxHasEsLintTargets || nxHasEsLintPlugin || eslintTargets.length > 0) {
70
- convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, 'eslint.config.js', ignorePath);
70
+ convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, 'eslint.config.cjs', ignorePath);
71
71
  eslintIgnoreFiles.add(`${projectConfig.root}/.eslintignore`);
72
72
  if (ignorePath) {
73
73
  eslintIgnoreFiles.add(ignorePath);
@@ -83,17 +83,17 @@ function updateNxJsonConfig(tree) {
83
83
  (0, devkit_1.updateJson)(tree, 'nx.json', (json) => {
84
84
  if (json.targetDefaults?.lint?.inputs) {
85
85
  const inputSet = new Set(json.targetDefaults.lint.inputs);
86
- inputSet.add('{workspaceRoot}/eslint.config.js');
86
+ inputSet.add('{workspaceRoot}/eslint.config.cjs');
87
87
  json.targetDefaults.lint.inputs = Array.from(inputSet);
88
88
  }
89
89
  if (json.targetDefaults?.['@nx/eslint:lint']?.inputs) {
90
90
  const inputSet = new Set(json.targetDefaults['@nx/eslint:lint'].inputs);
91
- inputSet.add('{workspaceRoot}/eslint.config.js');
91
+ inputSet.add('{workspaceRoot}/eslint.config.cjs');
92
92
  json.targetDefaults['@nx/eslint:lint'].inputs = Array.from(inputSet);
93
93
  }
94
94
  if (json.namedInputs?.production) {
95
95
  const inputSet = new Set(json.namedInputs.production);
96
- inputSet.add('!{projectRoot}/eslint.config.js');
96
+ inputSet.add('!{projectRoot}/eslint.config.cjs');
97
97
  json.namedInputs.production = Array.from(inputSet);
98
98
  }
99
99
  return json;
@@ -33,7 +33,7 @@ function postTargetTransformer(target, tree, projectDetails, inferredTargetConfi
33
33
  'default',
34
34
  '{workspaceRoot}/.eslintrc.json',
35
35
  '{workspaceRoot}/.eslintignore',
36
- '{workspaceRoot}/eslint.config.js',
36
+ '{workspaceRoot}/eslint.config.cjs',
37
37
  ].includes(input));
38
38
  if (inputs.length === 0) {
39
39
  delete target.inputs;
@@ -85,7 +85,9 @@ const getGlobalFlatEslintConfiguration = (rootProject) => {
85
85
  content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatPredefinedConfig)('flat/base'), { insertAtTheEnd: false });
86
86
  content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatPredefinedConfig)('flat/typescript'));
87
87
  content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatPredefinedConfig)('flat/javascript'));
88
- content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)({ ignores: ['**/dist'] }));
88
+ content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)({
89
+ ignores: ['**/dist'],
90
+ }));
89
91
  if (!rootProject) {
90
92
  content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)({
91
93
  files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
@@ -108,7 +110,14 @@ const getGlobalFlatEslintConfiguration = (rootProject) => {
108
110
  }));
109
111
  }
110
112
  content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)({
111
- files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
113
+ files: [
114
+ '**/*.ts',
115
+ '**/*.tsx',
116
+ '**/*.js',
117
+ '**/*.jsx',
118
+ '**/*.cjs',
119
+ '**/*.mjs',
120
+ ],
112
121
  rules: {},
113
122
  }));
114
123
  return content;
@@ -27,9 +27,9 @@ function migrateConfigToMonorepoStyle(projects, tree, unitTestRunner, keepExisti
27
27
  (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
28
28
  '@eslint/js': versions_1.eslintVersion,
29
29
  }, undefined, keepExistingVersions);
30
- tree.write(tree.exists('eslint.config.js')
31
- ? 'eslint.base.config.js'
32
- : 'eslint.config.js', (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)());
30
+ tree.write(tree.exists('eslint.config.cjs')
31
+ ? 'eslint.base.config.cjs'
32
+ : 'eslint.config.cjs', (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)());
33
33
  }
34
34
  else {
35
35
  const eslintFile = (0, eslint_file_1.findEslintFile)(tree, '.');
@@ -80,7 +80,7 @@ function migrateEslintFile(projectEslintPath, tree) {
80
80
  let config = tree.read(projectEslintPath, 'utf-8');
81
81
  // remove @nx plugin
82
82
  config = (0, ast_utils_1.removePlugin)(config, '@nx', '@nx/eslint-plugin-nx');
83
- // extend eslint.base.config.js
83
+ // extend eslint.base.config.cjs
84
84
  config = (0, ast_utils_1.addImportToFlatConfig)(config, 'baseConfig', `${(0, devkit_1.offsetFromRoot)((0, path_1.dirname)(projectEslintPath))}${baseFile}`);
85
85
  config = (0, ast_utils_1.addBlockToFlatConfigExport)(config, (0, ast_utils_1.generateSpreadElement)('baseConfig'), { insertAtTheEnd: false });
86
86
  // cleanup file extends
@@ -13,7 +13,7 @@ function updateProductionFileset(tree) {
13
13
  const productionFileSet = nxJson.namedInputs?.production;
14
14
  if (productionFileSet) {
15
15
  productionFileSet.push('!{projectRoot}/.eslintrc.json');
16
- productionFileSet.push('!{projectRoot}/eslint.config.js');
16
+ productionFileSet.push('!{projectRoot}/eslint.config.cjs');
17
17
  // Dedupe and set
18
18
  nxJson.namedInputs.production = Array.from(new Set(productionFileSet));
19
19
  }
@@ -28,7 +28,7 @@ function addTargetDefaults(tree) {
28
28
  'default',
29
29
  `{workspaceRoot}/.eslintrc.json`,
30
30
  `{workspaceRoot}/.eslintignore`,
31
- `{workspaceRoot}/eslint.config.js`,
31
+ `{workspaceRoot}/eslint.config.cjs`,
32
32
  ];
33
33
  (0, devkit_1.updateNxJson)(tree, nxJson);
34
34
  }
@@ -184,8 +184,7 @@ function createEsLintConfiguration(tree, options, projectConfig, setParserOption
184
184
  });
185
185
  const nodeList = (0, ast_utils_1.createNodeList)(importMap, nodes);
186
186
  const content = (0, ast_utils_1.stringifyNodeList)(nodeList);
187
- const ext = extendedRootConfig?.endsWith('.cjs') ? '.cjs' : '.js';
188
- tree.write((0, path_1.join)(projectConfig.root, `eslint.config${ext}`), content);
187
+ tree.write((0, path_1.join)(projectConfig.root, `eslint.config.cjs`), content);
189
188
  }
190
189
  else {
191
190
  (0, devkit_1.writeJson)(tree, (0, path_1.join)(projectConfig.root, `.eslintrc.json`), {
@@ -38,7 +38,7 @@ function setUpLegacyRootEslintRc(tree, options) {
38
38
  : () => { };
39
39
  }
40
40
  function setUpRootFlatConfig(tree, options) {
41
- tree.write('eslint.config.js', (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)(options.rootProject));
41
+ tree.write('eslint.config.cjs', (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)(options.rootProject));
42
42
  return !options.skipPackageJson
43
43
  ? (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
44
44
  '@eslint/js': versions_1.eslint9__eslintVersion,
@@ -28,6 +28,10 @@ function findEslintFile(tree, projectRoot) {
28
28
  if (projectRoot === undefined && tree.exists(config_file_1.baseEsLintFlatConfigFile)) {
29
29
  return config_file_1.baseEsLintFlatConfigFile;
30
30
  }
31
+ if (projectRoot === undefined &&
32
+ tree.exists(config_file_1.legacyBaseEsLintFlatConfigFile)) {
33
+ return config_file_1.legacyBaseEsLintFlatConfigFile;
34
+ }
31
35
  projectRoot ??= '';
32
36
  for (const file of config_file_1.ESLINT_CONFIG_FILENAMES) {
33
37
  if (tree.exists((0, devkit_1.joinPathFragments)(projectRoot, file))) {
@@ -117,7 +121,18 @@ function addOverrideToLintConfig(tree, root, override, options = {
117
121
  }) {
118
122
  const isBase = options.checkBaseConfig && findEslintFile(tree, root).includes('.base');
119
123
  if ((0, flat_config_1.useFlatConfig)(tree)) {
120
- const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? config_file_1.baseEsLintFlatConfigFile : (0, flat_config_1.getRootESLintFlatConfigFilename)(tree));
124
+ let fileName;
125
+ if (isBase) {
126
+ fileName = (0, devkit_1.joinPathFragments)(root, config_file_1.baseEsLintFlatConfigFile);
127
+ }
128
+ else {
129
+ for (const f of flat_config_1.eslintFlatConfigFilenames) {
130
+ if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
131
+ fileName = (0, devkit_1.joinPathFragments)(root, f);
132
+ break;
133
+ }
134
+ }
135
+ }
121
136
  const flatOverride = (0, ast_utils_1.generateFlatOverride)(override);
122
137
  let content = tree.read(fileName, 'utf8');
123
138
  // Check if the provided override using legacy eslintrc properties or plugins, if so we need to add compat
@@ -148,7 +163,14 @@ function updateOverrideInLintConfig(tree, rootOrFile, lookup, update) {
148
163
  root = (0, posix_1.dirname)(rootOrFile);
149
164
  }
150
165
  if ((0, flat_config_1.useFlatConfig)(tree)) {
151
- fileName ??= (0, devkit_1.joinPathFragments)(root, (0, flat_config_1.getRootESLintFlatConfigFilename)(tree));
166
+ if (!fileName) {
167
+ for (const f of flat_config_1.eslintFlatConfigFilenames) {
168
+ if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
169
+ fileName = (0, devkit_1.joinPathFragments)(root, f);
170
+ break;
171
+ }
172
+ }
173
+ }
152
174
  let content = tree.read(fileName, 'utf8');
153
175
  content = (0, ast_utils_1.replaceOverride)(content, root, lookup, update);
154
176
  tree.write(fileName, content);
@@ -190,8 +212,18 @@ function lintConfigHasOverride(tree, rootOrFile, lookup, checkBaseConfig = false
190
212
  const isBase = !fileName &&
191
213
  checkBaseConfig &&
192
214
  findEslintFile(tree, root).includes('.base');
215
+ if (isBase) {
216
+ fileName = (0, devkit_1.joinPathFragments)(root, config_file_1.baseEsLintFlatConfigFile);
217
+ }
193
218
  if ((0, flat_config_1.useFlatConfig)(tree)) {
194
- fileName ??= (0, devkit_1.joinPathFragments)(root, isBase ? config_file_1.baseEsLintFlatConfigFile : (0, flat_config_1.getRootESLintFlatConfigFilename)(tree));
219
+ if (!fileName) {
220
+ for (const f of flat_config_1.eslintFlatConfigFilenames) {
221
+ if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
222
+ fileName = (0, devkit_1.joinPathFragments)(root, f);
223
+ break;
224
+ }
225
+ }
226
+ }
195
227
  const content = tree.read(fileName, 'utf8');
196
228
  return (0, ast_utils_1.hasOverride)(content, lookup);
197
229
  }
@@ -202,7 +234,13 @@ function lintConfigHasOverride(tree, rootOrFile, lookup, checkBaseConfig = false
202
234
  }
203
235
  function replaceOverridesInLintConfig(tree, root, overrides) {
204
236
  if ((0, flat_config_1.useFlatConfig)(tree)) {
205
- const fileName = (0, devkit_1.joinPathFragments)(root, (0, flat_config_1.getRootESLintFlatConfigFilename)(tree));
237
+ let fileName;
238
+ for (const f of flat_config_1.eslintFlatConfigFilenames) {
239
+ if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
240
+ fileName = (0, devkit_1.joinPathFragments)(root, f);
241
+ break;
242
+ }
243
+ }
206
244
  let content = tree.read(fileName, 'utf8');
207
245
  // Check if any of the provided overrides using legacy eslintrc properties or plugins, if so we need to add compat
208
246
  if (overrides.some(ast_utils_1.overrideNeedsCompat)) {
@@ -226,7 +264,13 @@ function replaceOverridesInLintConfig(tree, root, overrides) {
226
264
  function addExtendsToLintConfig(tree, root, plugin, insertAtTheEnd = false) {
227
265
  if ((0, flat_config_1.useFlatConfig)(tree)) {
228
266
  const pluginExtends = [];
229
- const fileName = (0, devkit_1.joinPathFragments)(root, (0, flat_config_1.getRootESLintFlatConfigFilename)(tree));
267
+ let fileName;
268
+ for (const f of flat_config_1.eslintFlatConfigFilenames) {
269
+ if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
270
+ fileName = (0, devkit_1.joinPathFragments)(root, f);
271
+ break;
272
+ }
273
+ }
230
274
  let shouldImportEslintCompat = false;
231
275
  // assume eslint version is 9 if not found, as it's what we'd be generating by default
232
276
  const eslintVersion = (0, version_utils_1.getInstalledEslintVersion)(tree) ?? versions_1.eslint9__eslintVersion;
@@ -294,7 +338,13 @@ function addExtendsToLintConfig(tree, root, plugin, insertAtTheEnd = false) {
294
338
  function addPredefinedConfigToFlatLintConfig(tree, root, predefinedConfigName, moduleName = 'nx', moduleImportPath = '@nx/eslint-plugin', spread = true, insertAtTheEnd = true) {
295
339
  if (!(0, flat_config_1.useFlatConfig)(tree))
296
340
  throw new Error('Predefined configs can only be used with flat configs');
297
- const fileName = (0, devkit_1.joinPathFragments)(root, (0, flat_config_1.getRootESLintFlatConfigFilename)(tree));
341
+ let fileName;
342
+ for (const f of flat_config_1.eslintFlatConfigFilenames) {
343
+ if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
344
+ fileName = (0, devkit_1.joinPathFragments)(root, f);
345
+ break;
346
+ }
347
+ }
298
348
  let content = tree.read(fileName, 'utf8');
299
349
  content = (0, ast_utils_1.addImportToFlatConfig)(content, moduleName, moduleImportPath);
300
350
  content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatPredefinedConfig)(predefinedConfigName, moduleName, spread), { insertAtTheEnd });
@@ -303,7 +353,13 @@ function addPredefinedConfigToFlatLintConfig(tree, root, predefinedConfigName, m
303
353
  function addPluginsToLintConfig(tree, root, plugin) {
304
354
  const plugins = Array.isArray(plugin) ? plugin : [plugin];
305
355
  if ((0, flat_config_1.useFlatConfig)(tree)) {
306
- const fileName = (0, devkit_1.joinPathFragments)(root, (0, flat_config_1.getRootESLintFlatConfigFilename)(tree));
356
+ let fileName;
357
+ for (const f of flat_config_1.eslintFlatConfigFilenames) {
358
+ if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
359
+ fileName = (0, devkit_1.joinPathFragments)(root, f);
360
+ break;
361
+ }
362
+ }
307
363
  let content = tree.read(fileName, 'utf8');
308
364
  const mappedPlugins = [];
309
365
  plugins.forEach((name) => {
@@ -327,7 +383,13 @@ function addPluginsToLintConfig(tree, root, plugin) {
327
383
  }
328
384
  function addIgnoresToLintConfig(tree, root, ignorePatterns) {
329
385
  if ((0, flat_config_1.useFlatConfig)(tree)) {
330
- const fileName = (0, devkit_1.joinPathFragments)(root, (0, flat_config_1.getRootESLintFlatConfigFilename)(tree));
386
+ let fileName;
387
+ for (const f of flat_config_1.eslintFlatConfigFilenames) {
388
+ if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
389
+ fileName = (0, devkit_1.joinPathFragments)(root, f);
390
+ break;
391
+ }
392
+ }
331
393
  const block = (0, ast_utils_1.generateAst)({
332
394
  ignores: ignorePatterns.map((path) => (0, path_utils_1.mapFilePath)(path)),
333
395
  });
@@ -670,10 +670,32 @@ function generateFlatOverride(_override) {
670
670
  });
671
671
  }
672
672
  // At this point we are applying the flat config compat tooling to the override
673
- const { excludedFiles, parser, parserOptions, rules, files, ...rest } = override;
673
+ let { excludedFiles, parser, parserOptions, rules, files, ...rest } = override;
674
674
  const objectLiteralElements = [
675
675
  ts.factory.createSpreadAssignment(ts.factory.createIdentifier('config')),
676
676
  ];
677
+ // If converting the JS rule, then we need to match ESLint default and also include .cjs and .mjs files.
678
+ if ((Array.isArray(rest.extends) &&
679
+ rest.extends.includes('plugin:@nx/javascript')) ||
680
+ rest.extends === 'plugin:@nx/javascript') {
681
+ const newFiles = new Set(files);
682
+ newFiles.add('**/*.js');
683
+ newFiles.add('**/*.jsx');
684
+ newFiles.add('**/*.cjs');
685
+ newFiles.add('**/*.mjs');
686
+ files = Array.from(newFiles);
687
+ }
688
+ // If converting the TS rule, then we need to match ESLint default and also include .cts and .mts files.
689
+ if ((Array.isArray(rest.extends) &&
690
+ rest.extends.includes('plugin:@nx/typescript')) ||
691
+ rest.extends === 'plugin:@nx/typescript') {
692
+ const newFiles = new Set(files);
693
+ newFiles.add('**/*.ts');
694
+ newFiles.add('**/*.tsx');
695
+ newFiles.add('**/*.cts');
696
+ newFiles.add('**/*.mts');
697
+ files = Array.from(newFiles);
698
+ }
677
699
  addTSObjectProperty(objectLiteralElements, 'files', files);
678
700
  addTSObjectProperty(objectLiteralElements, 'excludedFiles', excludedFiles);
679
701
  // Apply rules (and spread ...config.rules into it as the first assignment)
@@ -0,0 +1,2 @@
1
+ import { type Tree } from '@nx/devkit';
2
+ export default function (tree: Tree): Promise<void>;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = default_1;
4
+ const ts = require("typescript");
5
+ const js_1 = require("@nx/js");
6
+ async function default_1(tree) {
7
+ let rootConfig;
8
+ // NOTE: we don't support generating ESM base config currently so they are not handled.
9
+ for (const candidate of ['eslint.config.js', 'eslint.config.cjs']) {
10
+ if (tree.exists(candidate)) {
11
+ rootConfig = candidate;
12
+ break;
13
+ }
14
+ }
15
+ if (!rootConfig)
16
+ return;
17
+ updateOverrideFileExtensions(tree, rootConfig, 'plugin:@nx/typescript', [`'**/*.ts'`, `'**/*.tsx'`], [`'**/*.cts'`, `'**/*.mts'`]);
18
+ updateOverrideFileExtensions(tree, rootConfig, 'plugin:@nx/javascript', [`'**/*.js'`, `'**/*.jsx'`], [`'**/*.cjs'`, `'**/*.mjs'`]);
19
+ }
20
+ function updateOverrideFileExtensions(tree, configFile, plugin, matchingExts, newExts) {
21
+ const content = tree.read(configFile, 'utf-8');
22
+ const source = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
23
+ let compatNode;
24
+ const spreadElementNodes = (0, js_1.findNodes)(source, ts.SyntaxKind.SpreadElement);
25
+ for (const a of spreadElementNodes) {
26
+ const assignmentNodes = (0, js_1.findNodes)(a, ts.SyntaxKind.PropertyAssignment);
27
+ if (assignmentNodes.length === 0)
28
+ continue;
29
+ for (const b of assignmentNodes) {
30
+ if (b.name.getText() === 'extends' &&
31
+ b.initializer.getText().includes(plugin)) {
32
+ compatNode = a;
33
+ break;
34
+ }
35
+ }
36
+ }
37
+ if (compatNode) {
38
+ const arrayNodes = (0, js_1.findNodes)(compatNode, ts.SyntaxKind.ArrayLiteralExpression);
39
+ for (const a of arrayNodes) {
40
+ if (matchingExts.every((ext) => a.elements.some((e) => e.getText() === ext))) {
41
+ const exts = new Set(a.elements.map((e) => e.getText()));
42
+ for (const ext of newExts) {
43
+ exts.add(ext);
44
+ }
45
+ (0, js_1.replaceChange)(tree, source, configFile, a.getStart(a.getSourceFile()), `[${Array.from(exts).join(', ')}]`, a.getText()).getText();
46
+ }
47
+ }
48
+ }
49
+ }
@@ -2,7 +2,8 @@ export declare const ESLINT_FLAT_CONFIG_FILENAMES: string[];
2
2
  export declare const ESLINT_OLD_CONFIG_FILENAMES: string[];
3
3
  export declare const ESLINT_CONFIG_FILENAMES: string[];
4
4
  export declare const baseEsLintConfigFile = ".eslintrc.base.json";
5
- export declare const baseEsLintFlatConfigFile = "eslint.base.config.js";
5
+ export declare const baseEsLintFlatConfigFile = "eslint.base.config.cjs";
6
+ export declare const legacyBaseEsLintFlatConfigFile = "eslint.base.config.js";
6
7
  export declare function isFlatConfig(configFilePath: string): boolean;
7
8
  export declare function findFlatConfigFile(directory: string, workspaceRoot: string): string | null;
8
9
  export declare function findOldConfigFile(filePathOrDirectory: string, workspaceRoot: string): string | null;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.baseEsLintFlatConfigFile = exports.baseEsLintConfigFile = exports.ESLINT_CONFIG_FILENAMES = exports.ESLINT_OLD_CONFIG_FILENAMES = exports.ESLINT_FLAT_CONFIG_FILENAMES = void 0;
3
+ exports.legacyBaseEsLintFlatConfigFile = exports.baseEsLintFlatConfigFile = exports.baseEsLintConfigFile = exports.ESLINT_CONFIG_FILENAMES = exports.ESLINT_OLD_CONFIG_FILENAMES = exports.ESLINT_FLAT_CONFIG_FILENAMES = void 0;
4
4
  exports.isFlatConfig = isFlatConfig;
5
5
  exports.findFlatConfigFile = findFlatConfigFile;
6
6
  exports.findOldConfigFile = findOldConfigFile;
@@ -21,7 +21,9 @@ exports.ESLINT_CONFIG_FILENAMES = [
21
21
  ...exports.ESLINT_FLAT_CONFIG_FILENAMES,
22
22
  ];
23
23
  exports.baseEsLintConfigFile = '.eslintrc.base.json';
24
- exports.baseEsLintFlatConfigFile = 'eslint.base.config.js';
24
+ exports.baseEsLintFlatConfigFile = 'eslint.base.config.cjs';
25
+ // Make sure we can handle previous file extension as well for migrations or custom generators.
26
+ exports.legacyBaseEsLintFlatConfigFile = 'eslint.base.config.js';
25
27
  function isFlatConfig(configFilePath) {
26
28
  const configFileName = (0, path_1.basename)(configFilePath);
27
29
  return exports.ESLINT_FLAT_CONFIG_FILENAMES.includes(configFileName);
@@ -6,8 +6,8 @@ exports.useFlatConfig = useFlatConfig;
6
6
  const semver_1 = require("semver");
7
7
  // todo: add support for eslint.config.mjs,
8
8
  exports.eslintFlatConfigFilenames = [
9
- 'eslint.config.js',
10
9
  'eslint.config.cjs',
10
+ 'eslint.config.js',
11
11
  ];
12
12
  function getRootESLintFlatConfigFilename(tree) {
13
13
  for (const file of exports.eslintFlatConfigFilenames) {