@nx/eslint 22.6.0-rc.2 → 22.7.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/eslint",
3
- "version": "22.6.0-rc.2",
3
+ "version": "22.7.0-beta.0",
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,14 +35,14 @@
35
35
  "eslint": "^8.0.0 || ^9.0.0 || ^10.0.0"
36
36
  },
37
37
  "dependencies": {
38
- "@nx/devkit": "22.6.0-rc.2",
39
- "@nx/js": "22.6.0-rc.2",
38
+ "@nx/devkit": "22.7.0-beta.0",
39
+ "@nx/js": "22.7.0-beta.0",
40
40
  "semver": "^7.6.3",
41
41
  "tslib": "^2.3.0",
42
42
  "typescript": "~5.9.2"
43
43
  },
44
44
  "devDependencies": {
45
- "nx": "22.6.0-rc.2"
45
+ "nx": "22.7.0-beta.0"
46
46
  },
47
47
  "peerDependenciesMeta": {
48
48
  "@zkochan/js-yaml": {
@@ -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;AAchC;;;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,CAuLjE"}
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"}
@@ -68,6 +68,47 @@ function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths, format)
68
68
  }
69
69
  if (config.overrides) {
70
70
  config.overrides.forEach((override) => {
71
+ if (override.extends) {
72
+ const extendsArr = Array.isArray(override.extends)
73
+ ? override.extends
74
+ : [override.extends];
75
+ const mapped = extendsArr.map((e) => ({
76
+ original: e,
77
+ flatConfig: mapNxPluginToFlatConfig(e),
78
+ }));
79
+ const nxExtends = mapped.filter((m) => m.flatConfig);
80
+ const nonNxExtends = mapped
81
+ .filter((m) => !m.flatConfig)
82
+ .map((m) => m.original);
83
+ if (nxExtends.length > 0) {
84
+ const nxVar = importsMap.get('@nx/eslint-plugin') ?? 'nx';
85
+ importsMap.set('@nx/eslint-plugin', nxVar);
86
+ nxExtends.forEach((ext) => {
87
+ exportElements.push((0, ast_utils_1.generateFlatPredefinedConfig)(ext.flatConfig, nxVar, true));
88
+ });
89
+ // Build remaining override without Nx extends
90
+ const remainingOverride = { ...override };
91
+ if (nonNxExtends.length > 0) {
92
+ remainingOverride.extends = nonNxExtends;
93
+ }
94
+ else {
95
+ delete remainingOverride.extends;
96
+ }
97
+ // Emit remaining override if it has content beyond files and empty rules
98
+ const { files: _files, rules: remainingRules, ...remainingRest } = remainingOverride;
99
+ const hasNonEmptyRules = remainingRules && Object.keys(remainingRules).length > 0;
100
+ if (Object.keys(remainingRest).length > 0 || hasNonEmptyRules) {
101
+ if (remainingOverride.env ||
102
+ remainingOverride.extends ||
103
+ remainingOverride.plugins ||
104
+ remainingOverride.parser) {
105
+ isFlatCompatNeeded = true;
106
+ }
107
+ exportElements.push((0, ast_utils_1.generateFlatOverride)(remainingOverride, format));
108
+ }
109
+ return;
110
+ }
111
+ }
71
112
  if (override.env ||
72
113
  override.extends ||
73
114
  override.plugins ||
@@ -138,7 +179,16 @@ function addExtends(importsMap, configBlocks, config, format) {
138
179
  if (pluginExtends.length) {
139
180
  const eslintPluginExtends = pluginExtends.filter((imp) => imp.startsWith('eslint:'));
140
181
  pluginExtends.forEach((imp) => {
141
- if (!imp.startsWith('eslint:')) {
182
+ if (imp.startsWith('eslint:')) {
183
+ return;
184
+ }
185
+ const nxFlatConfig = mapNxPluginToFlatConfig(imp);
186
+ if (nxFlatConfig) {
187
+ const nxVar = importsMap.get('@nx/eslint-plugin') ?? 'nx';
188
+ importsMap.set('@nx/eslint-plugin', nxVar);
189
+ configBlocks.push((0, ast_utils_1.generateFlatPredefinedConfig)(nxFlatConfig, nxVar, true));
190
+ }
191
+ else {
142
192
  eslintrcConfigs.push(imp);
143
193
  }
144
194
  });
@@ -159,10 +209,22 @@ function addExtends(importsMap, configBlocks, config, format) {
159
209
  return { isFlatCompatNeeded, isESLintJSNeeded };
160
210
  }
161
211
  function addPlugins(importsMap, configBlocks, config) {
212
+ // Replace @nx plugin with flat/base predefined config to match fresh generation.
213
+ // flat/base registers the @nx plugin and ignores .nx directory.
214
+ // This runs before overrides are processed, so we set the import name here
215
+ // for Nx extends that may appear in overrides later.
216
+ if (config.plugins.includes('@nx')) {
217
+ importsMap.set('@nx/eslint-plugin', 'nx');
218
+ configBlocks.push((0, ast_utils_1.generateFlatPredefinedConfig)('flat/base', 'nx', true));
219
+ }
220
+ const remainingPlugins = config.plugins.filter((name) => name !== '@nx');
221
+ if (remainingPlugins.length === 0) {
222
+ return;
223
+ }
162
224
  const mappedPlugins = [];
163
- config.plugins.forEach((name) => {
225
+ remainingPlugins.forEach((name) => {
164
226
  const imp = (0, eslint_file_1.getPluginImport)(name);
165
- const varName = (0, devkit_1.names)(imp).propertyName;
227
+ const varName = importsMap.get(imp) ?? (0, devkit_1.names)(imp).propertyName;
166
228
  mappedPlugins.push({ name, varName, imp });
167
229
  });
168
230
  mappedPlugins.forEach(({ varName, imp }) => {
@@ -180,3 +242,18 @@ function addPlugins(importsMap, configBlocks, config) {
180
242
  ], false);
181
243
  configBlocks.push(pluginsAst);
182
244
  }
245
+ const nxPluginToFlatConfigMap = {
246
+ 'plugin:@nx/typescript': 'flat/typescript',
247
+ 'plugin:@nx/javascript': 'flat/javascript',
248
+ 'plugin:@nx/react': 'flat/react',
249
+ 'plugin:@nx/react-base': 'flat/react-base',
250
+ 'plugin:@nx/react-typescript': 'flat/react-typescript',
251
+ 'plugin:@nx/react-jsx': 'flat/react-jsx',
252
+ 'plugin:@nx/angular': 'flat/angular',
253
+ 'plugin:@nx/angular-template': 'flat/angular-template',
254
+ 'plugin:@nrwl/nx/typescript': 'flat/typescript',
255
+ 'plugin:@nrwl/nx/javascript': 'flat/javascript',
256
+ };
257
+ function mapNxPluginToFlatConfig(pluginExtend) {
258
+ return nxPluginToFlatConfigMap[pluginExtend];
259
+ }
@@ -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,EAQjB,IAAI,EAGL,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kCAAkC,EAAE,MAAM,UAAU,CAAC;AAa9D,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;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"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.convertToFlatConfigGenerator = convertToFlatConfigGenerator;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const eslint_file_1 = require("../utils/eslint-file");
6
+ const plugin_1 = require("../utils/plugin");
6
7
  const path_1 = require("path");
7
8
  const versions_1 = require("../../utils/versions");
8
9
  const json_converter_1 = require("./converters/json-converter");
@@ -42,39 +43,47 @@ function convertRootToFlatConfig(tree, eslintFile, format) {
42
43
  }
43
44
  convertConfigToFlatConfig(tree, '', eslintFile.replace('.base.', '.'), `eslint.config.${format}`, format);
44
45
  }
46
+ const ESLINT_LINT_EXECUTOR = '@nx/eslint:lint';
47
+ function isEslintTarget(target) {
48
+ return (target.executor === ESLINT_LINT_EXECUTOR ||
49
+ target.command?.includes('eslint'));
50
+ }
45
51
  function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslintIgnoreFiles, format) {
46
52
  const eslintFile = (0, eslint_file_1.findEslintFile)(tree, projectConfig.root);
47
- if (eslintFile && !eslintFile.endsWith('.js')) {
48
- if (projectConfig.targets) {
49
- const eslintTargets = Object.keys(projectConfig.targets || {}).filter((t) => projectConfig.targets[t].executor === '@nx/eslint:lint' ||
50
- projectConfig.targets[t].command?.includes('eslint'));
51
- let ignorePath;
52
- for (const target of eslintTargets) {
53
- // remove any obsolete `eslintConfig` options pointing to the old config file
54
- if (projectConfig.targets[target].options?.eslintConfig) {
55
- delete projectConfig.targets[target].options.eslintConfig;
56
- }
57
- if (projectConfig.targets[target].options?.ignorePath) {
58
- ignorePath = projectConfig.targets[target].options.ignorePath;
59
- delete projectConfig.targets[target].options.ignorePath;
60
- }
61
- (0, devkit_1.updateProjectConfiguration)(tree, project, projectConfig);
62
- }
63
- const nxHasEsLintTargets = Object.keys(nxJson.targetDefaults || {}).some((t) => (t === '@nx/eslint:lint' ||
64
- nxJson.targetDefaults[t].executor === '@nx/eslint:lint' ||
65
- nxJson.targetDefaults[t].command?.includes('eslint')) &&
66
- projectConfig.targets?.[t]);
67
- const nxHasEsLintPlugin = (nxJson.plugins || []).some((p) => typeof p === 'string'
68
- ? p === '@nx/eslint/plugin'
69
- : p.plugin === '@nx/eslint/plugin');
70
- if (nxHasEsLintTargets || nxHasEsLintPlugin || eslintTargets.length > 0) {
71
- convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, `eslint.config.${format}`, format, ignorePath);
72
- eslintIgnoreFiles.add(`${projectConfig.root}/.eslintignore`);
73
- if (ignorePath) {
74
- eslintIgnoreFiles.add(ignorePath);
75
- }
76
- }
53
+ if (!eslintFile || eslintFile.endsWith('.js')) {
54
+ return;
55
+ }
56
+ // Clean up obsolete target options and detect explicit ESLint targets
57
+ let ignorePath;
58
+ const eslintTargets = projectConfig.targets
59
+ ? Object.keys(projectConfig.targets).filter((t) => isEslintTarget(projectConfig.targets[t]))
60
+ : [];
61
+ for (const target of eslintTargets) {
62
+ if (projectConfig.targets[target].options?.eslintConfig) {
63
+ delete projectConfig.targets[target].options.eslintConfig;
77
64
  }
65
+ if (projectConfig.targets[target].options?.ignorePath) {
66
+ ignorePath = projectConfig.targets[target].options.ignorePath;
67
+ delete projectConfig.targets[target].options.ignorePath;
68
+ }
69
+ }
70
+ if (eslintTargets.length > 0) {
71
+ (0, devkit_1.updateProjectConfiguration)(tree, project, projectConfig);
72
+ }
73
+ const hasEslintTargetDefaults = projectConfig.targets &&
74
+ Object.keys(nxJson.targetDefaults || {}).some((t) => (t === ESLINT_LINT_EXECUTOR ||
75
+ isEslintTarget(nxJson.targetDefaults[t])) &&
76
+ projectConfig.targets[t]);
77
+ if (eslintTargets.length === 0 &&
78
+ !hasEslintTargetDefaults &&
79
+ !(0, plugin_1.hasEslintPlugin)(tree)) {
80
+ devkit_1.logger.warn(`Skipping "${project}": found ${eslintFile} but no ESLint lint target detected. Convert manually if needed.`);
81
+ return;
82
+ }
83
+ convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, `eslint.config.${format}`, format, ignorePath);
84
+ eslintIgnoreFiles.add(`${projectConfig.root}/.eslintignore`);
85
+ if (ignorePath) {
86
+ eslintIgnoreFiles.add(ignorePath);
78
87
  }
79
88
  }
80
89
  // update names of eslint files in nx.json
@@ -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;AAqBpB,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAmHD,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,mBAAmB,CA8D1D,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;AAqBpB,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAmHD,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,mBAAmB,CAsE1D,CAAC;AAEF,eAAO,MAAM,aAAa,oCAAc,CAAC"}
@@ -112,8 +112,14 @@ exports.createNodes = [
112
112
  if (eslintConfigFiles.length === 0) {
113
113
  return [];
114
114
  }
115
+ // Determine flat vs legacy from root config, matching ESLint's own
116
+ // behavior (find-up from cwd). Nested .eslintrc.* files are irrelevant
117
+ // when a root flat config exists. Prefer flat config at root when both
118
+ // flat and legacy root configs coexist (e.g., mid-migration).
119
+ const rootConfigs = eslintConfigFiles.filter((f) => (0, posix_1.dirname)(f) === '.');
120
+ const rootConfig = rootConfigs.find(config_file_1.isFlatConfig) ?? rootConfigs[0];
115
121
  const ESLint = await (0, resolve_eslint_class_1.resolveESLintClass)({
116
- useFlatConfigOverrideVal: (0, config_file_1.isFlatConfig)(eslintConfigFiles[0]),
122
+ useFlatConfigOverrideVal: (0, config_file_1.isFlatConfig)(rootConfig ?? eslintConfigFiles[0]),
117
123
  });
118
124
  return await (0, devkit_1.createNodesFromFiles)((configFile, options, context) => internalCreateNodesV2(ESLint, configFile, options, context, projectRootsByEslintRoots, lintableFilesPerProjectRoot, targetsCache, hashByRoot), eslintConfigFiles, options, context);
119
125
  }