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

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.
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;