@nx/eslint 20.4.0-canary.20250116-a127177 → 20.4.0-canary.20250118-ee135b2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. package/migrations.json +40 -0
  2. package/package.json +4 -4
  3. package/src/generators/convert-to-flat-config/converters/json-converter.d.ts +1 -1
  4. package/src/generators/convert-to-flat-config/converters/json-converter.js +6 -6
  5. package/src/generators/convert-to-flat-config/generator.js +17 -16
  6. package/src/generators/convert-to-flat-config/schema.d.ts +2 -0
  7. package/src/generators/convert-to-inferred/convert-to-inferred.js +1 -0
  8. package/src/generators/init/global-eslint-config.d.ts +1 -1
  9. package/src/generators/init/global-eslint-config.js +5 -5
  10. package/src/generators/init/init-migration.d.ts +1 -1
  11. package/src/generators/init/init-migration.js +15 -5
  12. package/src/generators/init/init.d.ts +1 -0
  13. package/src/generators/init/init.js +17 -6
  14. package/src/generators/lint-project/lint-project.d.ts +1 -0
  15. package/src/generators/lint-project/lint-project.js +20 -6
  16. package/src/generators/lint-project/setup-root-eslint.d.ts +1 -0
  17. package/src/generators/lint-project/setup-root-eslint.js +2 -1
  18. package/src/generators/utils/eslint-file.d.ts +1 -0
  19. package/src/generators/utils/eslint-file.js +54 -14
  20. package/src/generators/utils/flat-config/ast-utils.d.ts +10 -4
  21. package/src/generators/utils/flat-config/ast-utils.js +328 -59
  22. package/src/plugins/plugin.js +1 -1
  23. package/src/utils/config-file.d.ts +2 -1
  24. package/src/utils/config-file.js +3 -2
  25. package/src/utils/flat-config.d.ts +1 -0
  26. package/src/utils/flat-config.js +8 -2
  27. package/src/utils/versions.d.ts +1 -1
  28. package/src/utils/versions.js +1 -1
package/migrations.json CHANGED
@@ -106,6 +106,46 @@
106
106
  "version": "^7.16.0"
107
107
  }
108
108
  }
109
+ },
110
+ "20.4.0-typescript-eslint": {
111
+ "version": "20.4.0-beta.1",
112
+ "requires": {
113
+ "typescript-eslint": ">8.0.0 <8.19.0"
114
+ },
115
+ "packages": {
116
+ "typescript-eslint": {
117
+ "version": "^8.19.0"
118
+ },
119
+ "@typescript-eslint/parser": {
120
+ "version": "^8.19.0"
121
+ },
122
+ "@typescript-eslint/eslint-plugin": {
123
+ "version": "^8.19.0"
124
+ },
125
+ "@typescript-eslint/utils": {
126
+ "version": "^8.19.0"
127
+ }
128
+ }
129
+ },
130
+ "20.4.0-@typescript-eslint": {
131
+ "version": "20.4.0-beta.1",
132
+ "requires": {
133
+ "@typescript-eslint/eslint-plugin": ">8.0.0 <8.19.0"
134
+ },
135
+ "packages": {
136
+ "typescript-eslint": {
137
+ "version": "^8.19.0"
138
+ },
139
+ "@typescript-eslint/parser": {
140
+ "version": "^8.19.0"
141
+ },
142
+ "@typescript-eslint/eslint-plugin": {
143
+ "version": "^8.19.0"
144
+ },
145
+ "@typescript-eslint/utils": {
146
+ "version": "^8.19.0"
147
+ }
148
+ }
109
149
  }
110
150
  }
111
151
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/eslint",
3
- "version": "20.4.0-canary.20250116-a127177",
3
+ "version": "20.4.0-canary.20250118-ee135b2",
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,11 +35,11 @@
35
35
  "eslint": "^8.0.0 || ^9.0.0"
36
36
  },
37
37
  "dependencies": {
38
- "@nx/devkit": "20.4.0-canary.20250116-a127177",
39
- "@nx/js": "20.4.0-canary.20250116-a127177",
38
+ "@nx/devkit": "20.4.0-canary.20250118-ee135b2",
39
+ "@nx/js": "20.4.0-canary.20250118-ee135b2",
40
40
  "semver": "^7.5.3",
41
41
  "tslib": "^2.3.0",
42
- "typescript": "~5.6.2"
42
+ "typescript": "~5.7.2"
43
43
  },
44
44
  "peerDependenciesMeta": {
45
45
  "@zkochan/js-yaml": {
@@ -4,7 +4,7 @@ import { ESLint } from 'eslint';
4
4
  * Converts an ESLint JSON config to a flat config.
5
5
  * Deletes the original file along with .eslintignore if it exists.
6
6
  */
7
- export declare function convertEslintJsonToFlatConfig(tree: Tree, root: string, config: ESLint.ConfigData, ignorePaths: string[]): {
7
+ export declare function convertEslintJsonToFlatConfig(tree: Tree, root: string, config: ESLint.ConfigData, ignorePaths: string[], format: 'cjs' | 'mjs'): {
8
8
  content: string;
9
9
  addESLintRC: boolean;
10
10
  addESLintJS: boolean;
@@ -10,7 +10,7 @@ const path_utils_1 = require("../../utils/flat-config/path-utils");
10
10
  * Converts an ESLint JSON config to a flat config.
11
11
  * Deletes the original file along with .eslintignore if it exists.
12
12
  */
13
- function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths) {
13
+ function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths, format) {
14
14
  const importsMap = new Map();
15
15
  const exportElements = [];
16
16
  let isFlatCompatNeeded = false;
@@ -22,7 +22,7 @@ function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths) {
22
22
  ignores: ['**/dist'],
23
23
  }));
24
24
  if (config.extends) {
25
- const extendsResult = addExtends(importsMap, exportElements, config);
25
+ const extendsResult = addExtends(importsMap, exportElements, config, format);
26
26
  isFlatCompatNeeded = extendsResult.isFlatCompatNeeded;
27
27
  isESLintJSNeeded = extendsResult.isESLintJSNeeded;
28
28
  }
@@ -74,7 +74,7 @@ function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths) {
74
74
  override.parser) {
75
75
  isFlatCompatNeeded = true;
76
76
  }
77
- exportElements.push((0, ast_utils_1.generateFlatOverride)(override));
77
+ exportElements.push((0, ast_utils_1.generateFlatOverride)(override, format));
78
78
  });
79
79
  }
80
80
  if (config.ignorePatterns) {
@@ -100,7 +100,7 @@ function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths) {
100
100
  }
101
101
  }
102
102
  // create the node list and print it to new file
103
- const nodeList = (0, ast_utils_1.createNodeList)(importsMap, exportElements);
103
+ const nodeList = (0, ast_utils_1.createNodeList)(importsMap, exportElements, format);
104
104
  let content = (0, ast_utils_1.stringifyNodeList)(nodeList);
105
105
  if (isFlatCompatNeeded) {
106
106
  content = (0, ast_utils_1.addFlatCompatToFlatConfig)(content);
@@ -112,7 +112,7 @@ function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths) {
112
112
  };
113
113
  }
114
114
  // add parsed extends to export blocks and add import statements
115
- function addExtends(importsMap, configBlocks, config) {
115
+ function addExtends(importsMap, configBlocks, config, format) {
116
116
  let isFlatCompatNeeded = false;
117
117
  let isESLintJSNeeded = false;
118
118
  const extendsConfig = Array.isArray(config.extends)
@@ -126,7 +126,7 @@ function addExtends(importsMap, configBlocks, config) {
126
126
  if (imp.match(/\.eslintrc(.base)?\.json$/)) {
127
127
  const localName = index ? `baseConfig${index}` : 'baseConfig';
128
128
  configBlocks.push((0, ast_utils_1.generateSpreadElement)(localName));
129
- const newImport = imp.replace(/^(.*)\.eslintrc(.base)?\.json$/, '$1eslint$2.config.cjs');
129
+ const newImport = imp.replace(/^(.*)\.eslintrc(.base)?\.json$/, `$1eslint$2.config.${format}`);
130
130
  importsMap.set(newImport, localName);
131
131
  }
132
132
  else {
@@ -14,20 +14,21 @@ async function convertToFlatConfigGenerator(tree, options) {
14
14
  if (eslintFile.endsWith('.js')) {
15
15
  throw new Error('Only json and yaml eslint config files are supported for conversion');
16
16
  }
17
+ options.eslintConfigFormat ??= 'mjs';
17
18
  const eslintIgnoreFiles = new Set(['.eslintignore']);
18
- // convert root eslint config to eslint.config.cjs
19
- convertRootToFlatConfig(tree, eslintFile);
19
+ // convert root eslint config to eslint.config.cjs or eslint.base.config.mjs based on eslintConfigFormat
20
+ convertRootToFlatConfig(tree, eslintFile, options.eslintConfigFormat);
20
21
  // convert project eslint files to eslint.config.cjs
21
22
  const projects = (0, devkit_1.getProjects)(tree);
22
23
  for (const [project, projectConfig] of projects) {
23
- convertProjectToFlatConfig(tree, project, projectConfig, (0, devkit_1.readNxJson)(tree), eslintIgnoreFiles);
24
+ convertProjectToFlatConfig(tree, project, projectConfig, (0, devkit_1.readNxJson)(tree), eslintIgnoreFiles, options.eslintConfigFormat);
24
25
  }
25
26
  // delete all .eslintignore files
26
27
  for (const ignoreFile of eslintIgnoreFiles) {
27
28
  tree.delete(ignoreFile);
28
29
  }
29
30
  // replace references in nx.json
30
- updateNxJsonConfig(tree);
31
+ updateNxJsonConfig(tree, options.eslintConfigFormat);
31
32
  // install missing packages
32
33
  if (!options.skipFormat) {
33
34
  await (0, devkit_1.formatFiles)(tree);
@@ -35,13 +36,13 @@ async function convertToFlatConfigGenerator(tree, options) {
35
36
  return () => (0, devkit_1.installPackagesTask)(tree);
36
37
  }
37
38
  exports.default = convertToFlatConfigGenerator;
38
- function convertRootToFlatConfig(tree, eslintFile) {
39
+ function convertRootToFlatConfig(tree, eslintFile, format) {
39
40
  if (/\.base\.(js|json|yml|yaml)$/.test(eslintFile)) {
40
- convertConfigToFlatConfig(tree, '', eslintFile, 'eslint.base.config.cjs');
41
+ convertConfigToFlatConfig(tree, '', eslintFile, `eslint.base.config.${format}`, format);
41
42
  }
42
- convertConfigToFlatConfig(tree, '', eslintFile.replace('.base.', '.'), 'eslint.config.cjs');
43
+ convertConfigToFlatConfig(tree, '', eslintFile.replace('.base.', '.'), `eslint.config.${format}`, format);
43
44
  }
44
- function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslintIgnoreFiles) {
45
+ function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslintIgnoreFiles, format) {
45
46
  const eslintFile = (0, eslint_file_1.findEslintFile)(tree, projectConfig.root);
46
47
  if (eslintFile && !eslintFile.endsWith('.js')) {
47
48
  if (projectConfig.targets) {
@@ -67,7 +68,7 @@ function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslint
67
68
  ? p === '@nx/eslint/plugin'
68
69
  : p.plugin === '@nx/eslint/plugin');
69
70
  if (nxHasEsLintTargets || nxHasEsLintPlugin || eslintTargets.length > 0) {
70
- convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, 'eslint.config.cjs', ignorePath);
71
+ convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, `eslint.config.${format}`, format, ignorePath);
71
72
  eslintIgnoreFiles.add(`${projectConfig.root}/.eslintignore`);
72
73
  if (ignorePath) {
73
74
  eslintIgnoreFiles.add(ignorePath);
@@ -78,35 +79,35 @@ function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslint
78
79
  }
79
80
  // update names of eslint files in nx.json
80
81
  // and remove eslintignore
81
- function updateNxJsonConfig(tree) {
82
+ function updateNxJsonConfig(tree, format) {
82
83
  if (tree.exists('nx.json')) {
83
84
  (0, devkit_1.updateJson)(tree, 'nx.json', (json) => {
84
85
  if (json.targetDefaults?.lint?.inputs) {
85
86
  const inputSet = new Set(json.targetDefaults.lint.inputs);
86
- inputSet.add('{workspaceRoot}/eslint.config.cjs');
87
+ inputSet.add(`{workspaceRoot}/eslint.config.${format}`);
87
88
  json.targetDefaults.lint.inputs = Array.from(inputSet);
88
89
  }
89
90
  if (json.targetDefaults?.['@nx/eslint:lint']?.inputs) {
90
91
  const inputSet = new Set(json.targetDefaults['@nx/eslint:lint'].inputs);
91
- inputSet.add('{workspaceRoot}/eslint.config.cjs');
92
+ inputSet.add(`{workspaceRoot}/eslint.config.${format}`);
92
93
  json.targetDefaults['@nx/eslint:lint'].inputs = Array.from(inputSet);
93
94
  }
94
95
  if (json.namedInputs?.production) {
95
96
  const inputSet = new Set(json.namedInputs.production);
96
- inputSet.add('!{projectRoot}/eslint.config.cjs');
97
+ inputSet.add(`!{projectRoot}/eslint.config.${format}`);
97
98
  json.namedInputs.production = Array.from(inputSet);
98
99
  }
99
100
  return json;
100
101
  });
101
102
  }
102
103
  }
103
- function convertConfigToFlatConfig(tree, root, source, target, ignorePath) {
104
+ function convertConfigToFlatConfig(tree, root, source, target, format, ignorePath) {
104
105
  const ignorePaths = ignorePath
105
106
  ? [ignorePath, `${root}/.eslintignore`]
106
107
  : [`${root}/.eslintignore`];
107
108
  if (source.endsWith('.json')) {
108
109
  const config = (0, devkit_1.readJson)(tree, `${root}/${source}`);
109
- const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths);
110
+ const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths, format);
110
111
  return processConvertedConfig(tree, root, source, target, conversionResult);
111
112
  }
112
113
  if (source.endsWith('.yaml') || source.endsWith('.yml')) {
@@ -116,7 +117,7 @@ function convertConfigToFlatConfig(tree, root, source, target, ignorePath) {
116
117
  json: true,
117
118
  filename: source,
118
119
  });
119
- const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths);
120
+ const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths, format);
120
121
  return processConvertedConfig(tree, root, source, target, conversionResult);
121
122
  }
122
123
  }
@@ -1,3 +1,5 @@
1
1
  export interface ConvertToFlatConfigGeneratorSchema {
2
2
  skipFormat?: boolean;
3
+ // Internal option
4
+ eslintConfigFormat?: 'mjs' | 'cjs';
3
5
  }
@@ -34,6 +34,7 @@ function postTargetTransformer(target, tree, projectDetails, inferredTargetConfi
34
34
  '{workspaceRoot}/.eslintrc.json',
35
35
  '{workspaceRoot}/.eslintignore',
36
36
  '{workspaceRoot}/eslint.config.cjs',
37
+ '{workspaceRoot}/eslint.config.mjs',
37
38
  ].includes(input));
38
39
  if (inputs.length === 0) {
39
40
  delete target.inputs;
@@ -26,4 +26,4 @@ export declare const javaScriptOverride: {
26
26
  rules: {};
27
27
  };
28
28
  export declare const getGlobalEsLintConfiguration: (unitTestRunner?: string, rootProject?: boolean) => Linter.Config;
29
- export declare const getGlobalFlatEslintConfiguration: (rootProject?: boolean) => string;
29
+ export declare const getGlobalFlatEslintConfiguration: (format: "cjs" | "mjs", rootProject?: boolean) => string;
@@ -78,8 +78,8 @@ const getGlobalEsLintConfiguration = (unitTestRunner, rootProject) => {
78
78
  return config;
79
79
  };
80
80
  exports.getGlobalEsLintConfiguration = getGlobalEsLintConfiguration;
81
- const getGlobalFlatEslintConfiguration = (rootProject) => {
82
- const nodeList = (0, ast_utils_1.createNodeList)(new Map(), []);
81
+ const getGlobalFlatEslintConfiguration = (format, rootProject) => {
82
+ const nodeList = (0, ast_utils_1.createNodeList)(new Map(), [], format);
83
83
  let content = (0, ast_utils_1.stringifyNodeList)(nodeList);
84
84
  content = (0, ast_utils_1.addImportToFlatConfig)(content, 'nx', '@nx/eslint-plugin');
85
85
  content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatPredefinedConfig)('flat/base'), { insertAtTheEnd: false });
@@ -87,7 +87,7 @@ const getGlobalFlatEslintConfiguration = (rootProject) => {
87
87
  content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatPredefinedConfig)('flat/javascript'));
88
88
  content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)({
89
89
  ignores: ['**/dist'],
90
- }));
90
+ }, format));
91
91
  if (!rootProject) {
92
92
  content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)({
93
93
  files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
@@ -107,7 +107,7 @@ const getGlobalFlatEslintConfiguration = (rootProject) => {
107
107
  },
108
108
  ],
109
109
  },
110
- }));
110
+ }, format));
111
111
  }
112
112
  content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)({
113
113
  files: [
@@ -119,7 +119,7 @@ const getGlobalFlatEslintConfiguration = (rootProject) => {
119
119
  '**/*.mjs',
120
120
  ],
121
121
  rules: {},
122
- }));
122
+ }, format));
123
123
  return content;
124
124
  };
125
125
  exports.getGlobalFlatEslintConfiguration = getGlobalFlatEslintConfiguration;
@@ -1,3 +1,3 @@
1
1
  import { GeneratorCallback, ProjectConfiguration, TargetConfiguration, Tree } from '@nx/devkit';
2
- export declare function migrateConfigToMonorepoStyle(projects: ProjectConfiguration[], tree: Tree, unitTestRunner: string, keepExistingVersions?: boolean): GeneratorCallback;
2
+ export declare function migrateConfigToMonorepoStyle(projects: ProjectConfiguration[], tree: Tree, unitTestRunner: string, eslintConfigFormat: 'mjs' | 'cjs', keepExistingVersions?: boolean): GeneratorCallback;
3
3
  export declare function findLintTarget(project: ProjectConfiguration): TargetConfiguration;
@@ -11,9 +11,19 @@ const versions_1 = require("../../utils/versions");
11
11
  const ast_utils_1 = require("../utils/flat-config/ast-utils");
12
12
  const plugin_1 = require("../utils/plugin");
13
13
  const config_file_1 = require("../../utils/config-file");
14
- function migrateConfigToMonorepoStyle(projects, tree, unitTestRunner, keepExistingVersions) {
14
+ function migrateConfigToMonorepoStyle(projects, tree, unitTestRunner, eslintConfigFormat, keepExistingVersions) {
15
15
  const rootEslintConfig = (0, eslint_file_1.findEslintFile)(tree);
16
16
  let skipCleanup = false;
17
+ if (rootEslintConfig) {
18
+ // We do not want to mix the formats
19
+ const fileExtension = (0, path_1.extname)(rootEslintConfig);
20
+ if (fileExtension === '.mjs' || fileExtension === '.cjs') {
21
+ eslintConfigFormat = fileExtension.slice(1);
22
+ }
23
+ else {
24
+ eslintConfigFormat = (0, eslint_file_1.determineEslintConfigFormat)(tree.read(rootEslintConfig, 'utf-8'));
25
+ }
26
+ }
17
27
  if (rootEslintConfig?.match(/\.base\./) &&
18
28
  !projects.some((p) => p.root === '.')) {
19
29
  // if the migration has been run already, we need to rename the base config
@@ -27,9 +37,9 @@ function migrateConfigToMonorepoStyle(projects, tree, unitTestRunner, keepExisti
27
37
  (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
28
38
  '@eslint/js': versions_1.eslintVersion,
29
39
  }, undefined, keepExistingVersions);
30
- tree.write(tree.exists('eslint.config.cjs')
31
- ? 'eslint.base.config.cjs'
32
- : 'eslint.config.cjs', (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)());
40
+ tree.write(tree.exists(`eslint.config.${eslintConfigFormat}`)
41
+ ? `eslint.base.config.${eslintConfigFormat}`
42
+ : `eslint.config.${eslintConfigFormat}`, (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)(eslintConfigFormat));
33
43
  }
34
44
  else {
35
45
  const eslintFile = (0, eslint_file_1.findEslintFile)(tree, '.');
@@ -80,7 +90,7 @@ function migrateEslintFile(projectEslintPath, tree) {
80
90
  let config = tree.read(projectEslintPath, 'utf-8');
81
91
  // remove @nx plugin
82
92
  config = (0, ast_utils_1.removePlugin)(config, '@nx', '@nx/eslint-plugin-nx');
83
- // extend eslint.base.config.cjs
93
+ // if base config is cjs, we will need to import it using async import
84
94
  config = (0, ast_utils_1.addImportToFlatConfig)(config, 'baseConfig', `${(0, devkit_1.offsetFromRoot)((0, path_1.dirname)(projectEslintPath))}${baseFile}`);
85
95
  config = (0, ast_utils_1.addBlockToFlatConfigExport)(config, (0, ast_utils_1.generateSpreadElement)('baseConfig'), { insertAtTheEnd: false });
86
96
  // cleanup file extends
@@ -4,6 +4,7 @@ export interface LinterInitOptions {
4
4
  keepExistingVersions?: boolean;
5
5
  updatePackageScripts?: boolean;
6
6
  addPlugin?: boolean;
7
+ eslintConfigFormat?: 'mjs' | 'cjs';
7
8
  }
8
9
  export declare function initEsLint(tree: Tree, options: LinterInitOptions): Promise<GeneratorCallback>;
9
10
  export declare function lintInitGenerator(tree: Tree, options: LinterInitOptions): Promise<GeneratorCallback>;
@@ -8,18 +8,19 @@ const versions_1 = require("../../utils/versions");
8
8
  const eslint_file_1 = require("../utils/eslint-file");
9
9
  const plugin_1 = require("../../plugins/plugin");
10
10
  const plugin_2 = require("../utils/plugin");
11
- function updateProductionFileset(tree) {
11
+ const path_1 = require("path");
12
+ function updateProductionFileset(tree, format = 'mjs') {
12
13
  const nxJson = (0, devkit_1.readNxJson)(tree);
13
14
  const productionFileSet = nxJson.namedInputs?.production;
14
15
  if (productionFileSet) {
15
16
  productionFileSet.push('!{projectRoot}/.eslintrc.json');
16
- productionFileSet.push('!{projectRoot}/eslint.config.cjs');
17
+ productionFileSet.push(`!{projectRoot}/eslint.config.${format}`);
17
18
  // Dedupe and set
18
19
  nxJson.namedInputs.production = Array.from(new Set(productionFileSet));
19
20
  }
20
21
  (0, devkit_1.updateNxJson)(tree, nxJson);
21
22
  }
22
- function addTargetDefaults(tree) {
23
+ function addTargetDefaults(tree, format) {
23
24
  const nxJson = (0, devkit_1.readNxJson)(tree);
24
25
  nxJson.targetDefaults ??= {};
25
26
  nxJson.targetDefaults['@nx/eslint:lint'] ??= {};
@@ -28,7 +29,7 @@ function addTargetDefaults(tree) {
28
29
  'default',
29
30
  `{workspaceRoot}/.eslintrc.json`,
30
31
  `{workspaceRoot}/.eslintignore`,
31
- `{workspaceRoot}/eslint.config.cjs`,
32
+ `{workspaceRoot}/eslint.config.${format}`,
32
33
  ];
33
34
  (0, devkit_1.updateNxJson)(tree, nxJson);
34
35
  }
@@ -50,8 +51,18 @@ async function initEsLint(tree, options) {
50
51
  const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
51
52
  nxJson.useInferencePlugins !== false;
52
53
  options.addPlugin ??= addPluginDefault;
54
+ options.eslintConfigFormat ??= 'mjs';
53
55
  const hasPlugin = (0, plugin_2.hasEslintPlugin)(tree);
54
56
  const rootEslintFile = (0, eslint_file_1.findEslintFile)(tree);
57
+ if (rootEslintFile) {
58
+ const fileExtension = (0, path_1.extname)(rootEslintFile);
59
+ if (fileExtension === '.mjs' || fileExtension === '.cjs') {
60
+ options.eslintConfigFormat = fileExtension.slice(1);
61
+ }
62
+ else {
63
+ options.eslintConfigFormat = (0, eslint_file_1.determineEslintConfigFormat)(tree.read(rootEslintFile, 'utf-8'));
64
+ }
65
+ }
55
66
  const graph = await (0, devkit_1.createProjectGraphAsync)();
56
67
  const lintTargetNames = [
57
68
  'lint',
@@ -70,7 +81,7 @@ async function initEsLint(tree, options) {
70
81
  if (rootEslintFile) {
71
82
  return () => { };
72
83
  }
73
- updateProductionFileset(tree);
84
+ updateProductionFileset(tree, options.eslintConfigFormat);
74
85
  updateVsCodeRecommendedExtensions(tree);
75
86
  if (options.addPlugin) {
76
87
  await (0, add_plugin_1.addPlugin)(tree, graph, '@nx/eslint/plugin', plugin_1.createNodesV2, {
@@ -78,7 +89,7 @@ async function initEsLint(tree, options) {
78
89
  }, options.updatePackageScripts);
79
90
  }
80
91
  else {
81
- addTargetDefaults(tree);
92
+ addTargetDefaults(tree, options.eslintConfigFormat);
82
93
  }
83
94
  const tasks = [];
84
95
  if (!options.skipPackageJson) {
@@ -12,6 +12,7 @@ interface LintProjectOptions {
12
12
  rootProject?: boolean;
13
13
  keepExistingVersions?: boolean;
14
14
  addPlugin?: boolean;
15
+ eslintConfigFormat?: 'mjs' | 'cjs';
15
16
  /**
16
17
  * @internal
17
18
  */
@@ -18,6 +18,7 @@ function lintProjectGenerator(tree, options) {
18
18
  }
19
19
  async function lintProjectGeneratorInternal(tree, options) {
20
20
  const nxJson = (0, devkit_1.readNxJson)(tree);
21
+ options.eslintConfigFormat ??= 'mjs';
21
22
  const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
22
23
  nxJson.useInferencePlugins !== false;
23
24
  options.addPlugin ??= addPluginDefault;
@@ -25,12 +26,14 @@ async function lintProjectGeneratorInternal(tree, options) {
25
26
  const initTask = await (0, init_1.lintInitGenerator)(tree, {
26
27
  skipPackageJson: options.skipPackageJson,
27
28
  addPlugin: options.addPlugin,
29
+ eslintConfigFormat: options.eslintConfigFormat,
28
30
  });
29
31
  tasks.push(initTask);
30
32
  const rootEsLintTask = (0, setup_root_eslint_1.setupRootEsLint)(tree, {
31
33
  unitTestRunner: options.unitTestRunner,
32
34
  skipPackageJson: options.skipPackageJson,
33
35
  rootProject: options.rootProject,
36
+ eslintConfigFormat: options.eslintConfigFormat,
34
37
  });
35
38
  tasks.push(rootEsLintTask);
36
39
  const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
@@ -84,7 +87,7 @@ async function lintProjectGeneratorInternal(tree, options) {
84
87
  filteredProjects.push(project);
85
88
  }
86
89
  });
87
- const migrateTask = (0, init_migration_1.migrateConfigToMonorepoStyle)(filteredProjects, tree, options.unitTestRunner, options.keepExistingVersions);
90
+ const migrateTask = (0, init_migration_1.migrateConfigToMonorepoStyle)(filteredProjects, tree, options.unitTestRunner, options.eslintConfigFormat, options.keepExistingVersions);
88
91
  tasks.push(migrateTask);
89
92
  }
90
93
  }
@@ -116,6 +119,18 @@ function createEsLintConfiguration(tree, options, projectConfig, setParserOption
116
119
  const pathToRootConfig = extendedRootConfig
117
120
  ? `${(0, devkit_1.offsetFromRoot)(projectConfig.root)}${extendedRootConfig}`
118
121
  : undefined;
122
+ if (extendedRootConfig) {
123
+ // We do not want to mix the formats
124
+ // if the base file extension is `.mjs` we should use `mjs` for the new file
125
+ // or if base the file extension is `.cjs` then the format should be `cjs`
126
+ const fileExtension = (0, path_1.extname)(extendedRootConfig);
127
+ if (fileExtension === '.mjs' || fileExtension === '.cjs') {
128
+ options.eslintConfigFormat = fileExtension.slice(1);
129
+ }
130
+ else {
131
+ options.eslintConfigFormat = (0, eslint_file_1.determineEslintConfigFormat)(tree.read(extendedRootConfig, 'utf-8'));
132
+ }
133
+ }
119
134
  const addDependencyChecks = options.addPackageJsonDependencyChecks ||
120
135
  isBuildableLibraryProject(projectConfig);
121
136
  const overrides = (0, flat_config_1.useFlatConfig)(tree)
@@ -180,11 +195,11 @@ function createEsLintConfiguration(tree, options, projectConfig, setParserOption
180
195
  nodes.push((0, ast_utils_1.generateSpreadElement)('baseConfig'));
181
196
  }
182
197
  overrides.forEach((override) => {
183
- nodes.push((0, ast_utils_1.generateFlatOverride)(override));
198
+ nodes.push((0, ast_utils_1.generateFlatOverride)(override, options.eslintConfigFormat));
184
199
  });
185
- const nodeList = (0, ast_utils_1.createNodeList)(importMap, nodes);
200
+ const nodeList = (0, ast_utils_1.createNodeList)(importMap, nodes, options.eslintConfigFormat);
186
201
  const content = (0, ast_utils_1.stringifyNodeList)(nodeList);
187
- tree.write((0, path_1.join)(projectConfig.root, `eslint.config.cjs`), content);
202
+ tree.write((0, path_1.join)(projectConfig.root, `eslint.config.${options.eslintConfigFormat}`), content);
188
203
  }
189
204
  else {
190
205
  (0, devkit_1.writeJson)(tree, (0, path_1.join)(projectConfig.root, `.eslintrc.json`), {
@@ -212,8 +227,7 @@ function isBuildableLibraryProject(projectConfig) {
212
227
  */
213
228
  function isMigrationToMonorepoNeeded(tree, graph) {
214
229
  // the base config is already created, migration has been done
215
- if (tree.exists(config_file_1.baseEsLintConfigFile) ||
216
- tree.exists(config_file_1.baseEsLintFlatConfigFile)) {
230
+ if ([config_file_1.baseEsLintConfigFile, ...config_file_1.BASE_ESLINT_CONFIG_FILENAMES].some((f) => tree.exists(f))) {
217
231
  return false;
218
232
  }
219
233
  const nodes = Object.values(graph.nodes);
@@ -3,5 +3,6 @@ export type SetupRootEsLintOptions = {
3
3
  unitTestRunner?: string;
4
4
  skipPackageJson?: boolean;
5
5
  rootProject?: boolean;
6
+ eslintConfigFormat?: 'mjs' | 'cjs';
6
7
  };
7
8
  export declare function setupRootEsLint(tree: Tree, options: SetupRootEsLintOptions): GeneratorCallback;
@@ -11,6 +11,7 @@ function setupRootEsLint(tree, options) {
11
11
  if (rootEslintFile) {
12
12
  return () => { };
13
13
  }
14
+ options.eslintConfigFormat ??= 'mjs';
14
15
  if (!(0, flat_config_1.useFlatConfig)(tree)) {
15
16
  return setUpLegacyRootEslintRc(tree, options);
16
17
  }
@@ -38,7 +39,7 @@ function setUpLegacyRootEslintRc(tree, options) {
38
39
  : () => { };
39
40
  }
40
41
  function setUpRootFlatConfig(tree, options) {
41
- tree.write('eslint.config.cjs', (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)(options.rootProject));
42
+ tree.write(`eslint.config.${options.eslintConfigFormat}`, (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)(options.eslintConfigFormat, options.rootProject));
42
43
  return !options.skipPackageJson
43
44
  ? (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
44
45
  '@eslint/js': versions_1.eslint9__eslintVersion,
@@ -3,6 +3,7 @@ import type { Linter } from 'eslint';
3
3
  export declare function findEslintFile(tree: Tree, projectRoot?: string): string | null;
4
4
  export declare function isEslintConfigSupported(tree: Tree, projectRoot?: string): boolean;
5
5
  export declare function updateRelativePathsInConfig(tree: Tree, sourcePath: string, destinationPath: string): void;
6
+ export declare function determineEslintConfigFormat(content: string): 'mjs' | 'cjs';
6
7
  export declare function addOverrideToLintConfig(tree: Tree, root: string, override: Partial<Linter.ConfigOverride<Linter.RulesRecord>>, options?: {
7
8
  insertAtTheEnd?: boolean;
8
9
  checkBaseConfig?: boolean;