@nx/eslint 17.2.0-beta.1 → 17.2.0-beta.10

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
@@ -32,6 +32,11 @@
32
32
  "version": "17.1.0-beta.1",
33
33
  "description": "Updates for @typescript-utils/utils v6.9.1+",
34
34
  "implementation": "./src/migrations/update-17-1-0/update-typescript-eslint"
35
+ },
36
+ "simplify-eslint-patterns": {
37
+ "version": "17.2.0-beta.0",
38
+ "description": "Simplify eslintFilePatterns",
39
+ "implementation": "./src/migrations/update-17-2-0/simplify-eslint-patterns"
35
40
  }
36
41
  },
37
42
  "packageJsonUpdates": {
@@ -101,6 +106,14 @@
101
106
  "version": "^6.9.1"
102
107
  }
103
108
  }
109
+ },
110
+ "17.2.0": {
111
+ "version": "17.2.0-beta.2",
112
+ "packages": {
113
+ "eslint": {
114
+ "version": "~8.48.0"
115
+ }
116
+ }
104
117
  }
105
118
  }
106
119
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/eslint",
3
- "version": "17.2.0-beta.1",
3
+ "version": "17.2.0-beta.10",
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": {
@@ -30,18 +30,22 @@
30
30
  "executors": "./executors.json",
31
31
  "generators": "./generators.json",
32
32
  "peerDependencies": {
33
- "eslint": "^8.0.0"
33
+ "eslint": "^8.0.0",
34
+ "js-yaml": "4.1.0"
34
35
  },
35
36
  "dependencies": {
36
37
  "tslib": "^2.3.0",
37
- "@nx/devkit": "17.2.0-beta.1",
38
- "@nx/js": "17.2.0-beta.1",
38
+ "@nx/devkit": "17.2.0-beta.10",
39
+ "@nx/js": "17.2.0-beta.10",
39
40
  "typescript": "~5.2.2",
40
- "@nx/linter": "17.2.0-beta.1"
41
+ "@nx/linter": "17.2.0-beta.10"
41
42
  },
42
43
  "peerDependenciesMeta": {
43
44
  "eslint": {
44
45
  "optional": true
46
+ },
47
+ "js-yaml": {
48
+ "optional": true
45
49
  }
46
50
  },
47
51
  "publishConfig": {
@@ -17,7 +17,7 @@ async function run(task, context) {
17
17
  }
18
18
  const nodes = {};
19
19
  const hashes = [];
20
- for (const d of Object.keys(res.details.nodes)) {
20
+ for (const d of Object.keys(res.details.nodes).sort()) {
21
21
  if (d.indexOf('$fileset') === -1) {
22
22
  nodes[d] = res.details.nodes[d];
23
23
  hashes.push(res.details.nodes[d]);
@@ -4,6 +4,7 @@ const devkit_1 = require("@nx/devkit");
4
4
  const fs_1 = require("fs");
5
5
  const path_1 = require("path");
6
6
  const eslint_utils_1 = require("./utility/eslint-utils");
7
+ const utils_1 = require("nx/src/tasks-runner/utils");
7
8
  async function run(options, context) {
8
9
  // this is only used for the hasher
9
10
  delete options.hasTypeAwareRules;
@@ -58,8 +59,15 @@ async function run(options, context) {
58
59
  }
59
60
  }
60
61
  let lintResults = [];
62
+ const normalizedLintFilePatterns = normalizedOptions.lintFilePatterns.map((pattern) => {
63
+ return (0, utils_1.interpolate)(pattern, {
64
+ workspaceRoot: '',
65
+ projectRoot: context.projectsConfigurations.projects[context.projectName].root,
66
+ projectName: context.projectName,
67
+ });
68
+ });
61
69
  try {
62
- lintResults = await eslint.lintFiles(normalizedOptions.lintFilePatterns);
70
+ lintResults = await eslint.lintFiles(normalizedLintFilePatterns);
63
71
  }
64
72
  catch (err) {
65
73
  if (err.message.includes('You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser')) {
@@ -81,7 +89,7 @@ Please see https://nx.dev/guides/eslint for full guidance on how to resolve this
81
89
  throw err;
82
90
  }
83
91
  if (lintResults.length === 0 && errorOnUnmatchedPattern) {
84
- const ignoredPatterns = (await Promise.all(normalizedOptions.lintFilePatterns.map(async (pattern) => (await eslint.isPathIgnored(pattern)) ? pattern : null)))
92
+ const ignoredPatterns = (await Promise.all(normalizedLintFilePatterns.map(async (pattern) => (await eslint.isPathIgnored(pattern)) ? pattern : null)))
85
93
  .filter((pattern) => !!pattern)
86
94
  .map((pattern) => `- '${pattern}'`);
87
95
  if (ignoredPatterns.length) {
@@ -17,7 +17,7 @@
17
17
  "lintFilePatterns": {
18
18
  "type": "array",
19
19
  "description": "One or more files/dirs/globs to pass directly to ESLint's `lintFiles()` method.",
20
- "default": [],
20
+ "default": ["{projectRoot}"],
21
21
  "items": {
22
22
  "type": "string"
23
23
  }
@@ -144,6 +144,5 @@
144
144
  "default": true
145
145
  }
146
146
  },
147
- "required": ["lintFilePatterns"],
148
147
  "examplesFile": "../../../docs/eslint-examples.md"
149
148
  }
@@ -1,6 +1,11 @@
1
1
  import { Tree } from '@nx/devkit';
2
+ import { ESLint } from 'eslint';
2
3
  /**
3
4
  * Converts an ESLint JSON config to a flat config.
4
5
  * Deletes the original file along with .eslintignore if it exists.
5
6
  */
6
- export declare function convertEslintJsonToFlatConfig(tree: Tree, root: string, sourceFile: string, destinationFile: string, ignorePaths: string[]): void;
7
+ export declare function convertEslintJsonToFlatConfig(tree: Tree, root: string, config: ESLint.ConfigData, ignorePaths: string[]): {
8
+ content: string;
9
+ addESLintRC: boolean;
10
+ addESLintJS: boolean;
11
+ };
@@ -2,25 +2,25 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.convertEslintJsonToFlatConfig = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
- const path_1 = require("path");
6
5
  const ts = require("typescript");
7
- const versions_1 = require("../../../utils/versions");
8
6
  const ast_utils_1 = require("../../utils/flat-config/ast-utils");
9
7
  const eslint_file_1 = require("../../utils/eslint-file");
8
+ const path_utils_1 = require("../../utils/flat-config/path-utils");
10
9
  /**
11
10
  * Converts an ESLint JSON config to a flat config.
12
11
  * Deletes the original file along with .eslintignore if it exists.
13
12
  */
14
- function convertEslintJsonToFlatConfig(tree, root, sourceFile, destinationFile, ignorePaths) {
13
+ function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths) {
15
14
  const importsMap = new Map();
16
15
  const exportElements = [];
17
16
  let isFlatCompatNeeded = false;
17
+ let isESLintJSNeeded = false;
18
18
  let combinedConfig = [];
19
19
  let languageOptions = [];
20
- // read original config
21
- const config = (0, devkit_1.readJson)(tree, `${root}/${sourceFile}`);
22
20
  if (config.extends) {
23
- isFlatCompatNeeded = addExtends(importsMap, exportElements, config, tree);
21
+ const extendsResult = addExtends(importsMap, exportElements, config);
22
+ isFlatCompatNeeded = extendsResult.isFlatCompatNeeded;
23
+ isESLintJSNeeded = extendsResult.isESLintJSNeeded;
24
24
  }
25
25
  if (config.plugins) {
26
26
  addPlugins(importsMap, exportElements, config);
@@ -70,7 +70,7 @@ function convertEslintJsonToFlatConfig(tree, root, sourceFile, destinationFile,
70
70
  override.parser) {
71
71
  isFlatCompatNeeded = true;
72
72
  }
73
- exportElements.push((0, ast_utils_1.generateFlatOverride)(override, root));
73
+ exportElements.push((0, ast_utils_1.generateFlatOverride)(override));
74
74
  });
75
75
  }
76
76
  if (config.ignorePatterns) {
@@ -79,7 +79,7 @@ function convertEslintJsonToFlatConfig(tree, root, sourceFile, destinationFile,
79
79
  : [config.ignorePatterns]).filter((pattern) => !['**/*', '!**/*', 'node_modules'].includes(pattern)); // these are useless in a flat config
80
80
  if (patterns.length > 0) {
81
81
  exportElements.push((0, ast_utils_1.generateAst)({
82
- ignores: patterns.map((path) => (0, ast_utils_1.mapFilePath)(path, root)),
82
+ ignores: patterns.map((path) => (0, path_utils_1.mapFilePath)(path)),
83
83
  }));
84
84
  }
85
85
  }
@@ -89,27 +89,25 @@ function convertEslintJsonToFlatConfig(tree, root, sourceFile, destinationFile,
89
89
  .read(ignorePath, 'utf-8')
90
90
  .split('\n')
91
91
  .filter((line) => line.length > 0 && line !== 'node_modules')
92
- .map((path) => (0, ast_utils_1.mapFilePath)(path, root));
92
+ .map((path) => (0, path_utils_1.mapFilePath)(path));
93
93
  if (patterns.length > 0) {
94
94
  exportElements.push((0, ast_utils_1.generateAst)({ ignores: patterns }));
95
95
  }
96
96
  }
97
97
  }
98
- tree.delete((0, path_1.join)(root, sourceFile));
99
98
  // create the node list and print it to new file
100
99
  const nodeList = (0, ast_utils_1.createNodeList)(importsMap, exportElements, isFlatCompatNeeded);
101
- const content = (0, ast_utils_1.stringifyNodeList)(nodeList, root, destinationFile);
102
- tree.write((0, path_1.join)(root, destinationFile), content);
103
- if (isFlatCompatNeeded) {
104
- (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
105
- '@eslint/eslintrc': versions_1.eslintrcVersion,
106
- });
107
- }
100
+ return {
101
+ content: (0, ast_utils_1.stringifyNodeList)(nodeList),
102
+ addESLintRC: isFlatCompatNeeded,
103
+ addESLintJS: isESLintJSNeeded,
104
+ };
108
105
  }
109
106
  exports.convertEslintJsonToFlatConfig = convertEslintJsonToFlatConfig;
110
107
  // add parsed extends to export blocks and add import statements
111
- function addExtends(importsMap, configBlocks, config, tree) {
108
+ function addExtends(importsMap, configBlocks, config) {
112
109
  let isFlatCompatNeeded = false;
110
+ let isESLintJSNeeded = false;
113
111
  const extendsConfig = Array.isArray(config.extends)
114
112
  ? config.extends
115
113
  : [config.extends];
@@ -138,9 +136,7 @@ function addExtends(importsMap, configBlocks, config, tree) {
138
136
  }
139
137
  });
140
138
  if (eslintPluginExtends.length) {
141
- (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
142
- '@eslint/js': versions_1.eslintVersion,
143
- });
139
+ isESLintJSNeeded = true;
144
140
  importsMap.set('@eslint/js', 'js');
145
141
  eslintPluginExtends.forEach((plugin) => {
146
142
  configBlocks.push(ts.factory.createPropertyAccessExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('js'), ts.factory.createIdentifier('configs')), ts.factory.createIdentifier(plugin.slice(7)) // strip 'eslint:' prefix
@@ -150,12 +146,10 @@ function addExtends(importsMap, configBlocks, config, tree) {
150
146
  }
151
147
  if (eslintrcConfigs.length) {
152
148
  isFlatCompatNeeded = true;
153
- (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
154
- '@eslint/js': versions_1.eslintVersion,
155
- });
149
+ isESLintJSNeeded = true;
156
150
  configBlocks.push((0, ast_utils_1.generatePluginExtendsElement)(eslintrcConfigs));
157
151
  }
158
- return isFlatCompatNeeded;
152
+ return { isFlatCompatNeeded, isESLintJSNeeded };
159
153
  }
160
154
  function addPlugins(importsMap, configBlocks, config) {
161
155
  const mappedPlugins = [];
@@ -3,14 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.convertToFlatConfigGenerator = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const eslint_file_1 = require("../utils/eslint-file");
6
+ const path_1 = require("path");
7
+ const versions_1 = require("../../utils/versions");
6
8
  const json_converter_1 = require("./converters/json-converter");
9
+ const js_yaml_1 = require("js-yaml");
7
10
  async function convertToFlatConfigGenerator(tree, options) {
8
11
  const eslintFile = (0, eslint_file_1.findEslintFile)(tree);
9
12
  if (!eslintFile) {
10
13
  throw new Error('Could not find root eslint file');
11
14
  }
12
- if (!eslintFile.endsWith('.json')) {
13
- throw new Error('Only json eslint config files are supported for conversion');
15
+ if (eslintFile.endsWith('.js')) {
16
+ throw new Error('Only json and yaml eslint config files are supported for conversion');
14
17
  }
15
18
  const eslintIgnoreFiles = new Set(['.eslintignore']);
16
19
  // convert root eslint config to eslint.config.js
@@ -34,13 +37,14 @@ async function convertToFlatConfigGenerator(tree, options) {
34
37
  exports.convertToFlatConfigGenerator = convertToFlatConfigGenerator;
35
38
  exports.default = convertToFlatConfigGenerator;
36
39
  function convertRootToFlatConfig(tree, eslintFile) {
37
- if (eslintFile.endsWith('.base.json')) {
38
- convertConfigToFlatConfig(tree, '', '.eslintrc.base.json', 'eslint.base.config.js');
40
+ if (/\.base\.(js|json|yml|yaml)$/.test(eslintFile)) {
41
+ convertConfigToFlatConfig(tree, '', eslintFile, 'eslint.base.config.js');
39
42
  }
40
- convertConfigToFlatConfig(tree, '', '.eslintrc.json', 'eslint.config.js');
43
+ convertConfigToFlatConfig(tree, '', eslintFile.replace('.base.', '.'), 'eslint.config.js');
41
44
  }
42
45
  function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslintIgnoreFiles) {
43
- if (tree.exists(`${projectConfig.root}/.eslintrc.json`)) {
46
+ const eslintFile = (0, eslint_file_1.findEslintFile)(tree, projectConfig.root);
47
+ if (eslintFile && !eslintFile.endsWith('.js')) {
44
48
  if (projectConfig.targets) {
45
49
  const eslintTargets = Object.keys(projectConfig.targets || {}).filter((t) => projectConfig.targets[t].executor === '@nx/eslint:lint');
46
50
  let ignorePath;
@@ -59,7 +63,7 @@ function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslint
59
63
  nxJson.targetDefaults[t].executor === '@nx/eslint:lint') &&
60
64
  projectConfig.targets?.[t]);
61
65
  if (nxHasLintTargets || eslintTargets.length > 0) {
62
- convertConfigToFlatConfig(tree, projectConfig.root, '.eslintrc.json', 'eslint.config.js', ignorePath);
66
+ convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, 'eslint.config.js', ignorePath);
63
67
  eslintIgnoreFiles.add(`${projectConfig.root}/.eslintignore`);
64
68
  if (ignorePath) {
65
69
  eslintIgnoreFiles.add(ignorePath);
@@ -96,5 +100,35 @@ function convertConfigToFlatConfig(tree, root, source, target, ignorePath) {
96
100
  const ignorePaths = ignorePath
97
101
  ? [ignorePath, `${root}/.eslintignore`]
98
102
  : [`${root}/.eslintignore`];
99
- (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, source, target, ignorePaths);
103
+ if (source.endsWith('.json')) {
104
+ const config = (0, devkit_1.readJson)(tree, `${root}/${source}`);
105
+ const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths);
106
+ return processConvertedConfig(tree, root, source, target, conversionResult);
107
+ }
108
+ if (source.endsWith('.yaml') || source.endsWith('.yml')) {
109
+ const originalContent = tree.read(`${root}/${source}`, 'utf-8');
110
+ const config = (0, js_yaml_1.load)(originalContent, {
111
+ json: true,
112
+ filename: source,
113
+ });
114
+ const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths);
115
+ return processConvertedConfig(tree, root, source, target, conversionResult);
116
+ }
117
+ }
118
+ function processConvertedConfig(tree, root, source, target, { content, addESLintRC, addESLintJS, }) {
119
+ // remove original config file
120
+ tree.delete((0, path_1.join)(root, source));
121
+ // save new
122
+ tree.write((0, path_1.join)(root, target), content);
123
+ // add missing packages
124
+ if (addESLintRC) {
125
+ (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
126
+ '@eslint/eslintrc': versions_1.eslintrcVersion,
127
+ });
128
+ }
129
+ if (addESLintJS) {
130
+ (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
131
+ '@eslint/js': versions_1.eslintVersion,
132
+ });
133
+ }
100
134
  }
@@ -80,18 +80,18 @@ const getGlobalEsLintConfiguration = (unitTestRunner, rootProject) => {
80
80
  exports.getGlobalEsLintConfiguration = getGlobalEsLintConfiguration;
81
81
  const getGlobalFlatEslintConfiguration = (unitTestRunner, rootProject) => {
82
82
  const nodeList = (0, ast_utils_1.createNodeList)(new Map(), [], true);
83
- let content = (0, ast_utils_1.stringifyNodeList)(nodeList, '', 'eslint.config.js');
83
+ let content = (0, ast_utils_1.stringifyNodeList)(nodeList);
84
84
  content = (0, ast_utils_1.addImportToFlatConfig)(content, 'nxPlugin', '@nx/eslint-plugin');
85
85
  content = (0, ast_utils_1.addPluginsToExportsBlock)(content, [
86
86
  { name: '@nx', varName: 'nxPlugin', imp: '@nx/eslint-plugin' },
87
87
  ]);
88
88
  if (!rootProject) {
89
- content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)(moduleBoundariesOverride, ''));
89
+ content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)(moduleBoundariesOverride));
90
90
  }
91
- content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)(exports.typeScriptOverride, ''));
92
- content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)(exports.javaScriptOverride, ''));
91
+ content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)(exports.typeScriptOverride));
92
+ content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)(exports.javaScriptOverride));
93
93
  if (unitTestRunner === 'jest') {
94
- content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)(jestOverride, ''));
94
+ content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)(jestOverride));
95
95
  }
96
96
  return content;
97
97
  };
@@ -23,7 +23,7 @@ function migrateConfigToMonorepoStyle(projects, tree, unitTestRunner) {
23
23
  projects.forEach((project) => {
24
24
  const lintTarget = findLintTarget(project);
25
25
  if (lintTarget) {
26
- const eslintFile = lintTarget.options.eslintConfig || (0, eslint_file_1.findEslintFile)(tree, project.root);
26
+ const eslintFile = lintTarget.options?.eslintConfig || (0, eslint_file_1.findEslintFile)(tree, project.root);
27
27
  if (eslintFile) {
28
28
  const projectEslintPath = (0, devkit_1.joinPathFragments)(project.root, eslintFile);
29
29
  migrateEslintFile(projectEslintPath, tree);
@@ -11,6 +11,5 @@ interface LintProjectOptions {
11
11
  unitTestRunner?: string;
12
12
  rootProject?: boolean;
13
13
  }
14
- export declare function mapLintPattern(projectRoot: string, extension: string, rootProject?: boolean): string;
15
14
  export declare function lintProjectGenerator(tree: Tree, options: LintProjectOptions): Promise<import("@nx/devkit").GeneratorCallback>;
16
15
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.lintProjectGenerator = exports.mapLintPattern = void 0;
3
+ exports.lintProjectGenerator = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const eslint_file_1 = require("../utils/eslint-file");
6
6
  const path_1 = require("path");
@@ -9,15 +9,6 @@ const init_migration_1 = require("../init/init-migration");
9
9
  const project_configuration_1 = require("nx/src/generators/utils/project-configuration");
10
10
  const flat_config_1 = require("../../utils/flat-config");
11
11
  const ast_utils_1 = require("../utils/flat-config/ast-utils");
12
- function mapLintPattern(projectRoot, extension, rootProject) {
13
- if (rootProject && (projectRoot === '.' || projectRoot === '')) {
14
- return `${projectRoot}/src/**/*.${extension}`;
15
- }
16
- else {
17
- return `${projectRoot}/**/*.${extension}`;
18
- }
19
- }
20
- exports.mapLintPattern = mapLintPattern;
21
12
  async function lintProjectGenerator(tree, options) {
22
13
  const installTask = (0, init_1.lintInitGenerator)(tree, {
23
14
  linter: options.linter,
@@ -26,17 +17,24 @@ async function lintProjectGenerator(tree, options) {
26
17
  rootProject: options.rootProject,
27
18
  });
28
19
  const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
29
- const lintFilePatterns = options.eslintFilePatterns ?? [];
30
- if (isBuildableLibraryProject(projectConfig)) {
31
- lintFilePatterns.push(`${projectConfig.root}/package.json`);
32
- }
33
20
  projectConfig.targets['lint'] = {
34
21
  executor: '@nx/eslint:lint',
35
22
  outputs: ['{options.outputFile}'],
36
- options: {
37
- lintFilePatterns: lintFilePatterns,
38
- },
39
23
  };
24
+ let lintFilePatterns = options.eslintFilePatterns;
25
+ if (!lintFilePatterns && options.rootProject && projectConfig.root === '.') {
26
+ lintFilePatterns = ['./src'];
27
+ }
28
+ if (lintFilePatterns && lintFilePatterns.length) {
29
+ if (isBuildableLibraryProject(projectConfig) &&
30
+ !lintFilePatterns.includes('{projectRoot}')) {
31
+ lintFilePatterns.push(`{projectRoot}/package.json`);
32
+ }
33
+ // only add lintFilePatterns if they are explicitly defined
34
+ projectConfig.targets['lint'].options = {
35
+ lintFilePatterns,
36
+ };
37
+ }
40
38
  // we are adding new project which is not the root project or
41
39
  // companion e2e app so we should check if migration to
42
40
  // monorepo style is needed
@@ -58,7 +56,7 @@ async function lintProjectGenerator(tree, options) {
58
56
  // additionally, the companion e2e app would have `rootProject: true`
59
57
  // so we need to check for the root path as well
60
58
  if (!options.rootProject || projectConfig.root !== '.') {
61
- createEsLintConfiguration(tree, projectConfig, options.setParserOptionsProject);
59
+ createEsLintConfiguration(tree, projectConfig, options.setParserOptionsProject, options.rootProject);
62
60
  }
63
61
  // Buildable libs need source analysis enabled for linting `package.json`.
64
62
  if (isBuildableLibraryProject(projectConfig) &&
@@ -77,10 +75,11 @@ async function lintProjectGenerator(tree, options) {
77
75
  return installTask;
78
76
  }
79
77
  exports.lintProjectGenerator = lintProjectGenerator;
80
- function createEsLintConfiguration(tree, projectConfig, setParserOptionsProject) {
81
- const eslintConfig = (0, eslint_file_1.findEslintFile)(tree);
82
- const pathToRootConfig = eslintConfig
83
- ? `${(0, devkit_1.offsetFromRoot)(projectConfig.root)}${eslintConfig}`
78
+ function createEsLintConfiguration(tree, projectConfig, setParserOptionsProject, rootProject) {
79
+ // we are only extending root for non-standalone projects or their complementary e2e apps
80
+ const extendedRootConfig = rootProject ? undefined : (0, eslint_file_1.findEslintFile)(tree);
81
+ const pathToRootConfig = extendedRootConfig
82
+ ? `${(0, devkit_1.offsetFromRoot)(projectConfig.root)}${extendedRootConfig}`
84
83
  : undefined;
85
84
  const addDependencyChecks = isBuildableLibraryProject(projectConfig);
86
85
  const overrides = [
@@ -132,20 +131,20 @@ function createEsLintConfiguration(tree, projectConfig, setParserOptionsProject)
132
131
  const isCompatNeeded = addDependencyChecks;
133
132
  const nodes = [];
134
133
  const importMap = new Map();
135
- if (eslintConfig) {
134
+ if (extendedRootConfig) {
136
135
  importMap.set(pathToRootConfig, 'baseConfig');
137
136
  nodes.push((0, ast_utils_1.generateSpreadElement)('baseConfig'));
138
137
  }
139
138
  overrides.forEach((override) => {
140
- nodes.push((0, ast_utils_1.generateFlatOverride)(override, projectConfig.root));
139
+ nodes.push((0, ast_utils_1.generateFlatOverride)(override));
141
140
  });
142
141
  const nodeList = (0, ast_utils_1.createNodeList)(importMap, nodes, isCompatNeeded);
143
- const content = (0, ast_utils_1.stringifyNodeList)(nodeList, projectConfig.root, 'eslint.config.js');
142
+ const content = (0, ast_utils_1.stringifyNodeList)(nodeList);
144
143
  tree.write((0, path_1.join)(projectConfig.root, 'eslint.config.js'), content);
145
144
  }
146
145
  else {
147
146
  (0, devkit_1.writeJson)(tree, (0, path_1.join)(projectConfig.root, `.eslintrc.json`), {
148
- extends: eslintConfig ? [pathToRootConfig] : undefined,
147
+ extends: extendedRootConfig ? [pathToRootConfig] : undefined,
149
148
  // Include project files to be linted since the global one excludes all files.
150
149
  ignorePatterns: ['!**/*'],
151
150
  overrides,
@@ -4,6 +4,7 @@ exports.getPluginImport = exports.addIgnoresToLintConfig = exports.addPluginsToL
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const flat_config_1 = require("../../utils/flat-config");
6
6
  const ast_utils_1 = require("./flat-config/ast-utils");
7
+ const path_utils_1 = require("./flat-config/path-utils");
7
8
  exports.eslintConfigFileWhitelist = [
8
9
  '.eslintrc',
9
10
  '.eslintrc.js',
@@ -112,7 +113,7 @@ function addOverrideToLintConfig(tree, root, override, options = {
112
113
  const isBase = options.checkBaseConfig && findEslintFile(tree, root).includes('.base');
113
114
  if ((0, flat_config_1.useFlatConfig)(tree)) {
114
115
  const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? exports.baseEsLintFlatConfigFile : 'eslint.config.js');
115
- const flatOverride = (0, ast_utils_1.generateFlatOverride)(override, root);
116
+ const flatOverride = (0, ast_utils_1.generateFlatOverride)(override);
116
117
  let content = tree.read(fileName, 'utf8');
117
118
  // we will be using compat here so we need to make sure it's added
118
119
  if (overrideNeedsCompat(override)) {
@@ -123,7 +124,7 @@ function addOverrideToLintConfig(tree, root, override, options = {
123
124
  else {
124
125
  const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? exports.baseEsLintConfigFile : '.eslintrc.json');
125
126
  (0, devkit_1.updateJson)(tree, fileName, (json) => {
126
- json.overrides ?? [];
127
+ json.overrides ??= [];
127
128
  if (options.insertAtTheEnd) {
128
129
  json.overrides.push(override);
129
130
  }
@@ -183,7 +184,7 @@ function replaceOverridesInLintConfig(tree, root, overrides) {
183
184
  }
184
185
  content = (0, ast_utils_1.removeOverridesFromLintConfig)(content);
185
186
  overrides.forEach((override) => {
186
- const flatOverride = (0, ast_utils_1.generateFlatOverride)(override, root);
187
+ const flatOverride = (0, ast_utils_1.generateFlatOverride)(override);
187
188
  (0, ast_utils_1.addBlockToFlatConfigExport)(content, flatOverride);
188
189
  });
189
190
  tree.write(fileName, content);
@@ -247,7 +248,7 @@ function addIgnoresToLintConfig(tree, root, ignorePatterns) {
247
248
  if ((0, flat_config_1.useFlatConfig)(tree)) {
248
249
  const fileName = (0, devkit_1.joinPathFragments)(root, 'eslint.config.js');
249
250
  const block = (0, ast_utils_1.generateAst)({
250
- ignores: ignorePatterns.map((path) => (0, ast_utils_1.mapFilePath)(path, root)),
251
+ ignores: ignorePatterns.map((path) => (0, path_utils_1.mapFilePath)(path)),
251
252
  });
252
253
  tree.write(fileName, (0, ast_utils_1.addBlockToFlatConfigExport)(tree.read(fileName, 'utf8'), block));
253
254
  }
@@ -44,7 +44,7 @@ export declare function generatePluginExtendsElement(plugins: string[]): ts.Spre
44
44
  /**
45
45
  * Stringifies TS nodes to file content string
46
46
  */
47
- export declare function stringifyNodeList(nodes: ts.NodeArray<ts.VariableStatement | ts.Identifier | ts.ExpressionStatement | ts.SourceFile>, root: string, fileName: string): string;
47
+ export declare function stringifyNodeList(nodes: ts.NodeArray<ts.VariableStatement | ts.Identifier | ts.ExpressionStatement | ts.SourceFile>): string;
48
48
  /**
49
49
  * generates AST require statement
50
50
  */
@@ -52,9 +52,8 @@ export declare function generateRequire(variableName: string | ts.ObjectBindingP
52
52
  /**
53
53
  * Generates AST object or spread element based on JSON override object
54
54
  */
55
- export declare function generateFlatOverride(override: Linter.ConfigOverride<Linter.RulesRecord>, root: string): ts.ObjectLiteralExpression | ts.SpreadElement;
56
- export declare function mapFilePaths(override: Linter.ConfigOverride<Linter.RulesRecord>, root: string): void;
57
- export declare function mapFilePath(filePath: string, root: string): string;
55
+ export declare function generateFlatOverride(override: Linter.ConfigOverride<Linter.RulesRecord>): ts.ObjectLiteralExpression | ts.SpreadElement;
56
+ export declare function mapFilePaths(override: Linter.ConfigOverride<Linter.RulesRecord>): void;
58
57
  /**
59
58
  * Generates an AST from a JSON-type input
60
59
  */
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateAst = exports.mapFilePath = exports.mapFilePaths = exports.generateFlatOverride = exports.generateRequire = exports.stringifyNodeList = exports.generatePluginExtendsElement = exports.generateSpreadElement = exports.createNodeList = exports.addCompatToFlatConfig = exports.addPluginsToExportsBlock = exports.removeCompatExtends = exports.removePlugin = exports.addBlockToFlatConfigExport = exports.addImportToFlatConfig = exports.replaceOverride = exports.hasOverride = exports.removeOverridesFromLintConfig = void 0;
3
+ exports.generateAst = exports.mapFilePaths = exports.generateFlatOverride = exports.generateRequire = exports.stringifyNodeList = exports.generatePluginExtendsElement = exports.generateSpreadElement = exports.createNodeList = exports.addCompatToFlatConfig = exports.addPluginsToExportsBlock = exports.removeCompatExtends = exports.removePlugin = exports.addBlockToFlatConfigExport = exports.addImportToFlatConfig = exports.replaceOverride = exports.hasOverride = exports.removeOverridesFromLintConfig = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const ts = require("typescript");
6
+ const path_utils_1 = require("./path-utils");
6
7
  /**
7
8
  * Remove all overrides from the config file
8
9
  */
@@ -63,7 +64,7 @@ function hasOverride(content, lookup) {
63
64
  // strip any spread elements
64
65
  objSource = fullNodeText.replace(/\s*\.\.\.[a-zA-Z0-9_]+,?\n?/, '');
65
66
  }
66
- const data = JSON.parse(objSource
67
+ const data = (0, devkit_1.parseJson)(objSource
67
68
  // ensure property names have double quotes so that JSON.parse works
68
69
  .replace(/'/g, '"')
69
70
  .replace(/\s([a-zA-Z0-9_]+)\s*:/g, ' "$1": '));
@@ -77,7 +78,7 @@ function hasOverride(content, lookup) {
77
78
  exports.hasOverride = hasOverride;
78
79
  const STRIP_SPREAD_ELEMENTS = /\s*\.\.\.[a-zA-Z0-9_]+,?\n?/g;
79
80
  function parseTextToJson(text) {
80
- return JSON.parse(text
81
+ return (0, devkit_1.parseJson)(text
81
82
  // ensure property names have double quotes so that JSON.parse works
82
83
  .replace(/'/g, '"')
83
84
  .replace(/\s([a-zA-Z0-9_]+)\s*:/g, ' "$1": '));
@@ -118,7 +119,7 @@ function replaceOverride(content, root, lookup, update) {
118
119
  length: end - start,
119
120
  });
120
121
  const updatedData = update(data);
121
- mapFilePaths(updatedData, root);
122
+ mapFilePaths(updatedData);
122
123
  changes.push({
123
124
  type: devkit_1.ChangeType.Insert,
124
125
  index: start,
@@ -470,10 +471,15 @@ exports.generatePluginExtendsElement = generatePluginExtendsElement;
470
471
  /**
471
472
  * Stringifies TS nodes to file content string
472
473
  */
473
- function stringifyNodeList(nodes, root, fileName) {
474
+ function stringifyNodeList(nodes) {
474
475
  const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
475
- const resultFile = ts.createSourceFile((0, devkit_1.joinPathFragments)(root, fileName), '', ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
476
- return printer.printList(ts.ListFormat.MultiLine, nodes, resultFile);
476
+ const resultFile = ts.createSourceFile('', '', ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
477
+ return (printer
478
+ .printList(ts.ListFormat.MultiLine, nodes, resultFile)
479
+ // add new line before compat initialization
480
+ .replace(/const compat = new FlatCompat/, '\nconst compat = new FlatCompat')
481
+ // add new line before module.exports = ...
482
+ .replace(/module\.exports/, '\nmodule.exports'));
477
483
  }
478
484
  exports.stringifyNodeList = stringifyNodeList;
479
485
  /**
@@ -488,8 +494,8 @@ exports.generateRequire = generateRequire;
488
494
  /**
489
495
  * Generates AST object or spread element based on JSON override object
490
496
  */
491
- function generateFlatOverride(override, root) {
492
- mapFilePaths(override, root);
497
+ function generateFlatOverride(override) {
498
+ mapFilePaths(override);
493
499
  if (!override.env &&
494
500
  !override.extends &&
495
501
  !override.plugins &&
@@ -510,41 +516,21 @@ function generateFlatOverride(override, root) {
510
516
  ]));
511
517
  }
512
518
  exports.generateFlatOverride = generateFlatOverride;
513
- function mapFilePaths(override, root) {
519
+ function mapFilePaths(override) {
514
520
  if (override.files) {
515
521
  override.files = Array.isArray(override.files)
516
522
  ? override.files
517
523
  : [override.files];
518
- override.files = override.files.map((file) => mapFilePath(file, root));
524
+ override.files = override.files.map((file) => (0, path_utils_1.mapFilePath)(file));
519
525
  }
520
526
  if (override.excludedFiles) {
521
527
  override.excludedFiles = Array.isArray(override.excludedFiles)
522
528
  ? override.excludedFiles
523
529
  : [override.excludedFiles];
524
- override.excludedFiles = override.excludedFiles.map((file) => mapFilePath(file, root));
530
+ override.excludedFiles = override.excludedFiles.map((file) => (0, path_utils_1.mapFilePath)(file));
525
531
  }
526
532
  }
527
533
  exports.mapFilePaths = mapFilePaths;
528
- function mapFilePath(filePath, root) {
529
- if (filePath.startsWith('!')) {
530
- const fileWithoutBang = filePath.slice(1);
531
- if (fileWithoutBang.startsWith('*.')) {
532
- return `!${(0, devkit_1.joinPathFragments)(root, '**', fileWithoutBang)}`;
533
- }
534
- else if (!fileWithoutBang.startsWith(root)) {
535
- return `!${(0, devkit_1.joinPathFragments)(root, fileWithoutBang)}`;
536
- }
537
- return filePath;
538
- }
539
- if (filePath.startsWith('*.')) {
540
- return (0, devkit_1.joinPathFragments)(root, '**', filePath);
541
- }
542
- else if (!filePath.startsWith(root)) {
543
- return (0, devkit_1.joinPathFragments)(root, filePath);
544
- }
545
- return filePath;
546
- }
547
- exports.mapFilePath = mapFilePath;
548
534
  function addTSObjectProperty(elements, key, value) {
549
535
  if (value) {
550
536
  elements.push(ts.factory.createPropertyAssignment(key, generateAst(value)));
@@ -1,2 +1,3 @@
1
1
  import type { Linter } from 'eslint';
2
- export declare function updateFiles(override: Linter.ConfigOverride<Linter.RulesRecord>, root: string): Linter.ConfigOverride<Linter.RulesRecord>;
2
+ export declare function updateFiles(override: Linter.ConfigOverride<Linter.RulesRecord>): Linter.ConfigOverride<Linter.RulesRecord>;
3
+ export declare function mapFilePath(filePath: string): string;
@@ -1,31 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.updateFiles = void 0;
3
+ exports.mapFilePath = exports.updateFiles = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
- function updateFiles(override, root) {
5
+ function updateFiles(override) {
6
6
  if (override.files) {
7
7
  override.files = Array.isArray(override.files)
8
8
  ? override.files
9
9
  : [override.files];
10
- override.files = override.files.map((file) => mapFilePath(file, root));
10
+ override.files = override.files.map((file) => mapFilePath(file));
11
11
  }
12
12
  return override;
13
13
  }
14
14
  exports.updateFiles = updateFiles;
15
- function mapFilePath(filePath, root) {
15
+ function mapFilePath(filePath) {
16
16
  if (filePath.startsWith('!')) {
17
17
  const fileWithoutBang = filePath.slice(1);
18
18
  if (fileWithoutBang.startsWith('*.')) {
19
- return `!${(0, devkit_1.joinPathFragments)(root, '**', fileWithoutBang)}`;
20
- }
21
- else {
22
- return `!${(0, devkit_1.joinPathFragments)(root, fileWithoutBang)}`;
19
+ return `!${(0, devkit_1.joinPathFragments)('**', fileWithoutBang)}`;
23
20
  }
21
+ return filePath;
24
22
  }
25
23
  if (filePath.startsWith('*.')) {
26
- return (0, devkit_1.joinPathFragments)(root, '**', filePath);
27
- }
28
- else {
29
- return (0, devkit_1.joinPathFragments)(root, filePath);
24
+ return (0, devkit_1.joinPathFragments)('**', filePath);
30
25
  }
26
+ return filePath;
31
27
  }
28
+ exports.mapFilePath = mapFilePath;
@@ -0,0 +1,2 @@
1
+ import { Tree } from '@nx/devkit';
2
+ export default function update(tree: Tree): Promise<void>;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const devkit_1 = require("@nx/devkit");
4
+ async function update(tree) {
5
+ const projects = (0, devkit_1.getProjects)(tree);
6
+ for (const [projectName, projectConfiguration] of projects) {
7
+ let needsUpdate = false;
8
+ for (const [targetName, targetConfig] of Object.entries(projectConfiguration.targets ?? {})) {
9
+ if (targetConfig.executor !== '@nx/eslint:lint') {
10
+ continue;
11
+ }
12
+ needsUpdate = true;
13
+ if (projectConfiguration.targets[targetName].options?.lintFilePatterns) {
14
+ const rootPattern = getLintRoot(projectConfiguration);
15
+ const nonRootPatterns = projectConfiguration.targets[targetName].options.lintFilePatterns.filter((p) => !p.startsWith(rootPattern) && !p.startsWith('{projectRoot}'));
16
+ if (nonRootPatterns.length === 0 &&
17
+ rootPattern === projectConfiguration.root) {
18
+ // delete the lintFilePatterns option if it's the only option and matches the root of the project
19
+ delete projectConfiguration.targets[targetName].options
20
+ .lintFilePatterns;
21
+ if (Object.keys(projectConfiguration.targets[targetName].options)
22
+ .length === 0) {
23
+ delete projectConfiguration.targets[targetName].options;
24
+ }
25
+ }
26
+ else {
27
+ projectConfiguration.targets[targetName].options.lintFilePatterns = [
28
+ rootPattern,
29
+ ...nonRootPatterns,
30
+ ];
31
+ }
32
+ }
33
+ }
34
+ if (needsUpdate) {
35
+ (0, devkit_1.updateProjectConfiguration)(tree, projectName, projectConfiguration);
36
+ }
37
+ }
38
+ await (0, devkit_1.formatFiles)(tree);
39
+ }
40
+ exports.default = update;
41
+ function getLintRoot({ root, sourceRoot }) {
42
+ if (root === '' || root === '.') {
43
+ return sourceRoot || './src';
44
+ }
45
+ return root;
46
+ }
@@ -1,5 +1,5 @@
1
1
  export declare const nxVersion: any;
2
- export declare const eslintVersion = "~8.46.0";
2
+ export declare const eslintVersion = "~8.48.0";
3
3
  export declare const eslintrcVersion = "^2.1.1";
4
4
  export declare const eslintConfigPrettierVersion = "^9.0.0";
5
5
  export declare const typescriptESLintVersion = "^6.9.1";
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.typescriptESLintVersion = exports.eslintConfigPrettierVersion = exports.eslintrcVersion = exports.eslintVersion = exports.nxVersion = void 0;
4
4
  exports.nxVersion = require('../../package.json').version;
5
- exports.eslintVersion = '~8.46.0';
5
+ exports.eslintVersion = '~8.48.0';
6
6
  exports.eslintrcVersion = '^2.1.1';
7
7
  exports.eslintConfigPrettierVersion = '^9.0.0';
8
8
  exports.typescriptESLintVersion = '^6.9.1';