@nx/eslint 17.0.3 → 17.0.5

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 (55) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +9 -4
  3. package/generators.json +6 -0
  4. package/migrations.json +68 -0
  5. package/package.json +9 -8
  6. package/plugin.d.ts +1 -0
  7. package/plugin.js +5 -0
  8. package/src/executors/lint/hasher.js +1 -1
  9. package/src/executors/lint/lint.impl.js +67 -33
  10. package/src/executors/lint/schema.d.ts +1 -0
  11. package/src/executors/lint/schema.json +7 -3
  12. package/src/executors/lint/utility/eslint-utils.js +5 -1
  13. package/src/generators/convert-to-flat-config/converters/json-converter.d.ts +6 -1
  14. package/src/generators/convert-to-flat-config/converters/json-converter.js +28 -33
  15. package/src/generators/convert-to-flat-config/generator.js +73 -17
  16. package/src/generators/convert-to-flat-config/schema.json +1 -1
  17. package/src/generators/init/global-eslint-config.js +9 -5
  18. package/src/generators/init/init-migration.d.ts +1 -1
  19. package/src/generators/init/init-migration.js +53 -14
  20. package/src/generators/init/init.d.ts +5 -5
  21. package/src/generators/init/init.js +63 -35
  22. package/src/generators/init/schema.json +28 -0
  23. package/src/generators/lint-project/lint-project.d.ts +9 -3
  24. package/src/generators/lint-project/lint-project.js +76 -40
  25. package/src/generators/lint-project/setup-root-eslint.d.ts +7 -0
  26. package/src/generators/lint-project/setup-root-eslint.js +33 -0
  27. package/src/generators/utils/eslint-file.d.ts +2 -5
  28. package/src/generators/utils/eslint-file.js +37 -30
  29. package/src/generators/utils/flat-config/ast-utils.d.ts +4 -5
  30. package/src/generators/utils/flat-config/ast-utils.js +35 -38
  31. package/src/generators/utils/flat-config/path-utils.d.ts +2 -1
  32. package/src/generators/utils/flat-config/path-utils.js +9 -12
  33. package/src/generators/utils/plugin.d.ts +2 -0
  34. package/src/generators/utils/plugin.js +11 -0
  35. package/src/generators/workspace-rule/files/__name__.ts__tmpl__ +2 -2
  36. package/src/generators/workspace-rule/schema.json +1 -1
  37. package/src/generators/workspace-rule/workspace-rule.js +7 -2
  38. package/src/generators/workspace-rules-project/files/tsconfig.json__tmpl__ +2 -1
  39. package/src/generators/workspace-rules-project/schema.json +1 -1
  40. package/src/generators/workspace-rules-project/workspace-rules-project.d.ts +3 -2
  41. package/src/generators/workspace-rules-project/workspace-rules-project.js +11 -9
  42. package/src/migrations/update-15-0-0/add-eslint-inputs.js +2 -2
  43. package/src/migrations/update-15-7-1/add-eslint-ignore.js +2 -2
  44. package/src/migrations/update-17-1-0/update-typescript-eslint.d.ts +2 -0
  45. package/src/migrations/update-17-1-0/update-typescript-eslint.js +74 -0
  46. package/src/migrations/update-17-2-0/simplify-eslint-patterns.d.ts +2 -0
  47. package/src/migrations/update-17-2-0/simplify-eslint-patterns.js +46 -0
  48. package/src/migrations/update-17-2-9/move-options-to-target-defaults.d.ts +2 -0
  49. package/src/migrations/update-17-2-9/move-options-to-target-defaults.js +107 -0
  50. package/src/plugins/plugin.d.ts +6 -0
  51. package/src/plugins/plugin.js +117 -0
  52. package/src/utils/config-file.d.ts +4 -0
  53. package/src/utils/config-file.js +18 -0
  54. package/src/utils/versions.d.ts +2 -2
  55. package/src/utils/versions.js +2 -2
@@ -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.lintProjectGeneratorInternal = 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,34 +9,64 @@ 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
- }
12
+ const config_file_1 = require("../../utils/config-file");
13
+ const plugin_1 = require("../utils/plugin");
14
+ const setup_root_eslint_1 = require("./setup-root-eslint");
15
+ function lintProjectGenerator(tree, options) {
16
+ return lintProjectGeneratorInternal(tree, { addPlugin: false, ...options });
19
17
  }
20
- exports.mapLintPattern = mapLintPattern;
21
- async function lintProjectGenerator(tree, options) {
22
- const installTask = (0, init_1.lintInitGenerator)(tree, {
23
- linter: options.linter,
18
+ exports.lintProjectGenerator = lintProjectGenerator;
19
+ async function lintProjectGeneratorInternal(tree, options) {
20
+ const nxJson = (0, devkit_1.readNxJson)(tree);
21
+ const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
22
+ nxJson.useInferencePlugins !== false;
23
+ options.addPlugin ??= addPluginDefault;
24
+ const tasks = [];
25
+ const initTask = await (0, init_1.lintInitGenerator)(tree, {
26
+ skipPackageJson: options.skipPackageJson,
27
+ addPlugin: options.addPlugin,
28
+ });
29
+ tasks.push(initTask);
30
+ const rootEsLintTask = (0, setup_root_eslint_1.setupRootEsLint)(tree, {
24
31
  unitTestRunner: options.unitTestRunner,
25
32
  skipPackageJson: options.skipPackageJson,
26
33
  rootProject: options.rootProject,
27
34
  });
35
+ tasks.push(rootEsLintTask);
28
36
  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`);
37
+ let lintFilePatterns = options.eslintFilePatterns;
38
+ if (!lintFilePatterns && options.rootProject && projectConfig.root === '.') {
39
+ lintFilePatterns = ['./src'];
40
+ }
41
+ if (lintFilePatterns &&
42
+ lintFilePatterns.length &&
43
+ !lintFilePatterns.includes('{projectRoot}') &&
44
+ isBuildableLibraryProject(projectConfig)) {
45
+ lintFilePatterns.push(`{projectRoot}/package.json`);
46
+ }
47
+ const hasPlugin = (0, plugin_1.hasEslintPlugin)(tree);
48
+ if (hasPlugin && !options.addExplicitTargets) {
49
+ if (lintFilePatterns &&
50
+ lintFilePatterns.length &&
51
+ lintFilePatterns.some((p) => !['./src', '{projectRoot}', projectConfig.root].includes(p))) {
52
+ projectConfig.targets['lint'] = {
53
+ command: `eslint ${lintFilePatterns
54
+ .join(' ')
55
+ .replace('{projectRoot}', projectConfig.root)}`,
56
+ };
57
+ }
58
+ }
59
+ else {
60
+ projectConfig.targets['lint'] = {
61
+ executor: '@nx/eslint:lint',
62
+ };
63
+ if (lintFilePatterns && lintFilePatterns.length) {
64
+ // only add lintFilePatterns if they are explicitly defined
65
+ projectConfig.targets['lint'].options = {
66
+ lintFilePatterns,
67
+ };
68
+ }
32
69
  }
33
- projectConfig.targets['lint'] = {
34
- executor: '@nx/eslint:lint',
35
- outputs: ['{options.outputFile}'],
36
- options: {
37
- lintFilePatterns: lintFilePatterns,
38
- },
39
- };
40
70
  // we are adding new project which is not the root project or
41
71
  // companion e2e app so we should check if migration to
42
72
  // monorepo style is needed
@@ -51,14 +81,14 @@ async function lintProjectGenerator(tree, options) {
51
81
  filteredProjects.push(project);
52
82
  }
53
83
  });
54
- (0, init_migration_1.migrateConfigToMonorepoStyle)(filteredProjects, tree, options.unitTestRunner);
84
+ (0, init_migration_1.migrateConfigToMonorepoStyle)(filteredProjects, tree, options.unitTestRunner, options.keepExistingVersions);
55
85
  }
56
86
  }
57
87
  // our root `.eslintrc` is already the project config, so we should not override it
58
88
  // additionally, the companion e2e app would have `rootProject: true`
59
89
  // so we need to check for the root path as well
60
90
  if (!options.rootProject || projectConfig.root !== '.') {
61
- createEsLintConfiguration(tree, projectConfig, options.setParserOptionsProject);
91
+ createEsLintConfiguration(tree, projectConfig, options.setParserOptionsProject, options.rootProject);
62
92
  }
63
93
  // Buildable libs need source analysis enabled for linting `package.json`.
64
94
  if (isBuildableLibraryProject(projectConfig) &&
@@ -74,13 +104,14 @@ async function lintProjectGenerator(tree, options) {
74
104
  if (!options.skipFormat) {
75
105
  await (0, devkit_1.formatFiles)(tree);
76
106
  }
77
- return installTask;
107
+ return (0, devkit_1.runTasksInSerial)(...tasks);
78
108
  }
79
- 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}`
109
+ exports.lintProjectGeneratorInternal = lintProjectGeneratorInternal;
110
+ function createEsLintConfiguration(tree, projectConfig, setParserOptionsProject, rootProject) {
111
+ // we are only extending root for non-standalone projects or their complementary e2e apps
112
+ const extendedRootConfig = rootProject ? undefined : (0, eslint_file_1.findEslintFile)(tree);
113
+ const pathToRootConfig = extendedRootConfig
114
+ ? `${(0, devkit_1.offsetFromRoot)(projectConfig.root)}${extendedRootConfig}`
84
115
  : undefined;
85
116
  const addDependencyChecks = isBuildableLibraryProject(projectConfig);
86
117
  const overrides = [
@@ -132,20 +163,20 @@ function createEsLintConfiguration(tree, projectConfig, setParserOptionsProject)
132
163
  const isCompatNeeded = addDependencyChecks;
133
164
  const nodes = [];
134
165
  const importMap = new Map();
135
- if (eslintConfig) {
166
+ if (extendedRootConfig) {
136
167
  importMap.set(pathToRootConfig, 'baseConfig');
137
168
  nodes.push((0, ast_utils_1.generateSpreadElement)('baseConfig'));
138
169
  }
139
170
  overrides.forEach((override) => {
140
- nodes.push((0, ast_utils_1.generateFlatOverride)(override, projectConfig.root));
171
+ nodes.push((0, ast_utils_1.generateFlatOverride)(override));
141
172
  });
142
173
  const nodeList = (0, ast_utils_1.createNodeList)(importMap, nodes, isCompatNeeded);
143
- const content = (0, ast_utils_1.stringifyNodeList)(nodeList, projectConfig.root, 'eslint.config.js');
174
+ const content = (0, ast_utils_1.stringifyNodeList)(nodeList);
144
175
  tree.write((0, path_1.join)(projectConfig.root, 'eslint.config.js'), content);
145
176
  }
146
177
  else {
147
178
  (0, devkit_1.writeJson)(tree, (0, path_1.join)(projectConfig.root, `.eslintrc.json`), {
148
- extends: eslintConfig ? [pathToRootConfig] : undefined,
179
+ extends: extendedRootConfig ? [pathToRootConfig] : undefined,
149
180
  // Include project files to be linted since the global one excludes all files.
150
181
  ignorePatterns: ['!**/*'],
151
182
  overrides,
@@ -169,8 +200,8 @@ function isBuildableLibraryProject(projectConfig) {
169
200
  */
170
201
  function isMigrationToMonorepoNeeded(projects, tree) {
171
202
  // the base config is already created, migration has been done
172
- if (tree.exists(eslint_file_1.baseEsLintConfigFile) ||
173
- tree.exists(eslint_file_1.baseEsLintFlatConfigFile)) {
203
+ if (tree.exists(config_file_1.baseEsLintConfigFile) ||
204
+ tree.exists(config_file_1.baseEsLintFlatConfigFile)) {
174
205
  return false;
175
206
  }
176
207
  const configs = Object.values(projects);
@@ -182,10 +213,15 @@ function isMigrationToMonorepoNeeded(projects, tree) {
182
213
  if (!rootProject || !rootProject.targets) {
183
214
  return false;
184
215
  }
216
+ // check if we're inferring lint target from `@nx/eslint/plugin`
217
+ if ((0, plugin_1.hasEslintPlugin)(tree)) {
218
+ for (const f of config_file_1.ESLINT_CONFIG_FILENAMES) {
219
+ if (tree.exists(f)) {
220
+ return true;
221
+ }
222
+ }
223
+ }
185
224
  // find if root project has lint target
186
225
  const lintTarget = (0, init_migration_1.findLintTarget)(rootProject);
187
- if (!lintTarget) {
188
- return false;
189
- }
190
- return true;
226
+ return !!lintTarget;
191
227
  }
@@ -0,0 +1,7 @@
1
+ import { type GeneratorCallback, type Tree } from '@nx/devkit';
2
+ export type SetupRootEsLintOptions = {
3
+ unitTestRunner?: string;
4
+ skipPackageJson?: boolean;
5
+ rootProject?: boolean;
6
+ };
7
+ export declare function setupRootEsLint(tree: Tree, options: SetupRootEsLintOptions): GeneratorCallback;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupRootEsLint = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const versions_1 = require("../../utils/versions");
6
+ const global_eslint_config_1 = require("../init/global-eslint-config");
7
+ const eslint_file_1 = require("../utils/eslint-file");
8
+ function setupRootEsLint(tree, options) {
9
+ const rootEslintFile = (0, eslint_file_1.findEslintFile)(tree);
10
+ if (rootEslintFile) {
11
+ return () => { };
12
+ }
13
+ (0, devkit_1.writeJson)(tree, '.eslintrc.json', (0, global_eslint_config_1.getGlobalEsLintConfiguration)(options.unitTestRunner, options.rootProject));
14
+ if (tree.exists('.eslintignore')) {
15
+ let content = tree.read('.eslintignore', 'utf-8');
16
+ if (!/^node_modules$/gm.test(content)) {
17
+ content = `${content}\nnode_modules\n`;
18
+ tree.write('.eslintignore', content);
19
+ }
20
+ }
21
+ else {
22
+ tree.write('.eslintignore', 'node_modules\n');
23
+ }
24
+ return !options.skipPackageJson
25
+ ? (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
26
+ '@nx/eslint-plugin': versions_1.nxVersion,
27
+ '@typescript-eslint/parser': versions_1.typescriptESLintVersion,
28
+ '@typescript-eslint/eslint-plugin': versions_1.typescriptESLintVersion,
29
+ 'eslint-config-prettier': versions_1.eslintConfigPrettierVersion,
30
+ })
31
+ : () => { };
32
+ }
33
+ exports.setupRootEsLint = setupRootEsLint;
@@ -1,8 +1,5 @@
1
- import { Tree } from '@nx/devkit';
2
- import { Linter } from 'eslint';
3
- export declare const eslintConfigFileWhitelist: string[];
4
- export declare const baseEsLintConfigFile = ".eslintrc.base.json";
5
- export declare const baseEsLintFlatConfigFile = "eslint.base.config.js";
1
+ import type { Tree } from '@nx/devkit';
2
+ import type { Linter } from 'eslint';
6
3
  export declare function findEslintFile(tree: Tree, projectRoot?: string): string | null;
7
4
  export declare function isEslintConfigSupported(tree: Tree, projectRoot?: string): boolean;
8
5
  export declare function updateRelativePathsInConfig(tree: Tree, sourcePath: string, destinationPath: string): void;
@@ -1,28 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPluginImport = exports.addIgnoresToLintConfig = exports.addPluginsToLintConfig = exports.addExtendsToLintConfig = exports.replaceOverridesInLintConfig = exports.lintConfigHasOverride = exports.updateOverrideInLintConfig = exports.addOverrideToLintConfig = exports.updateRelativePathsInConfig = exports.isEslintConfigSupported = exports.findEslintFile = exports.baseEsLintFlatConfigFile = exports.baseEsLintConfigFile = exports.eslintConfigFileWhitelist = void 0;
3
+ exports.getPluginImport = exports.addIgnoresToLintConfig = exports.addPluginsToLintConfig = exports.addExtendsToLintConfig = exports.replaceOverridesInLintConfig = exports.lintConfigHasOverride = exports.updateOverrideInLintConfig = exports.addOverrideToLintConfig = exports.updateRelativePathsInConfig = exports.isEslintConfigSupported = exports.findEslintFile = void 0;
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
- exports.eslintConfigFileWhitelist = [
8
- '.eslintrc',
9
- '.eslintrc.js',
10
- '.eslintrc.cjs',
11
- '.eslintrc.yaml',
12
- '.eslintrc.yml',
13
- '.eslintrc.json',
14
- 'eslint.config.js',
15
- ];
16
- exports.baseEsLintConfigFile = '.eslintrc.base.json';
17
- exports.baseEsLintFlatConfigFile = 'eslint.base.config.js';
18
- function findEslintFile(tree, projectRoot = '') {
19
- if (projectRoot === '' && tree.exists(exports.baseEsLintConfigFile)) {
20
- return exports.baseEsLintConfigFile;
7
+ const path_utils_1 = require("./flat-config/path-utils");
8
+ const config_file_1 = require("../../utils/config-file");
9
+ function findEslintFile(tree, projectRoot) {
10
+ if (projectRoot === undefined && tree.exists(config_file_1.baseEsLintConfigFile)) {
11
+ return config_file_1.baseEsLintConfigFile;
21
12
  }
22
- if (projectRoot === '' && tree.exists(exports.baseEsLintFlatConfigFile)) {
23
- return exports.baseEsLintFlatConfigFile;
13
+ if (projectRoot === undefined && tree.exists(config_file_1.baseEsLintFlatConfigFile)) {
14
+ return config_file_1.baseEsLintFlatConfigFile;
24
15
  }
25
- for (const file of exports.eslintConfigFileWhitelist) {
16
+ projectRoot ??= '';
17
+ for (const file of config_file_1.ESLINT_CONFIG_FILENAMES) {
26
18
  if (tree.exists((0, devkit_1.joinPathFragments)(projectRoot, file))) {
27
19
  return file;
28
20
  }
@@ -93,7 +85,7 @@ function replaceFlatConfigPaths(config, sourceRoot, offset, destinationRoot, tre
93
85
  return newConfig;
94
86
  }
95
87
  function offsetFilePath(projectRoot, pathToFile, offset, tree) {
96
- if (exports.eslintConfigFileWhitelist.some((eslintFile) => pathToFile.includes(eslintFile))) {
88
+ if (config_file_1.ESLINT_CONFIG_FILENAMES.some((eslintFile) => pathToFile.includes(eslintFile))) {
97
89
  // if the file is point to base eslint
98
90
  const rootEslint = findEslintFile(tree);
99
91
  if (rootEslint) {
@@ -111,8 +103,8 @@ function addOverrideToLintConfig(tree, root, override, options = {
111
103
  }) {
112
104
  const isBase = options.checkBaseConfig && findEslintFile(tree, root).includes('.base');
113
105
  if ((0, flat_config_1.useFlatConfig)(tree)) {
114
- const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? exports.baseEsLintFlatConfigFile : 'eslint.config.js');
115
- const flatOverride = (0, ast_utils_1.generateFlatOverride)(override, root);
106
+ const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? config_file_1.baseEsLintFlatConfigFile : 'eslint.config.js');
107
+ const flatOverride = (0, ast_utils_1.generateFlatOverride)(override);
116
108
  let content = tree.read(fileName, 'utf8');
117
109
  // we will be using compat here so we need to make sure it's added
118
110
  if (overrideNeedsCompat(override)) {
@@ -121,9 +113,9 @@ function addOverrideToLintConfig(tree, root, override, options = {
121
113
  tree.write(fileName, (0, ast_utils_1.addBlockToFlatConfigExport)(content, flatOverride, options));
122
114
  }
123
115
  else {
124
- const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? exports.baseEsLintConfigFile : '.eslintrc.json');
116
+ const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? config_file_1.baseEsLintConfigFile : '.eslintrc.json');
125
117
  (0, devkit_1.updateJson)(tree, fileName, (json) => {
126
- json.overrides ?? [];
118
+ json.overrides ??= [];
127
119
  if (options.insertAtTheEnd) {
128
120
  json.overrides.push(override);
129
121
  }
@@ -136,7 +128,7 @@ function addOverrideToLintConfig(tree, root, override, options = {
136
128
  }
137
129
  exports.addOverrideToLintConfig = addOverrideToLintConfig;
138
130
  function overrideNeedsCompat(override) {
139
- return (!override.env && !override.extends && !override.plugins && !override.parser);
131
+ return (override.env || override.extends || override.plugins || override.parser);
140
132
  }
141
133
  function updateOverrideInLintConfig(tree, root, lookup, update) {
142
134
  if ((0, flat_config_1.useFlatConfig)(tree)) {
@@ -147,10 +139,23 @@ function updateOverrideInLintConfig(tree, root, lookup, update) {
147
139
  }
148
140
  else {
149
141
  const fileName = (0, devkit_1.joinPathFragments)(root, '.eslintrc.json');
142
+ if (!tree.exists(fileName)) {
143
+ return;
144
+ }
145
+ const existingJson = (0, devkit_1.readJson)(tree, fileName);
146
+ if (!existingJson.overrides || !existingJson.overrides.some(lookup)) {
147
+ return;
148
+ }
150
149
  (0, devkit_1.updateJson)(tree, fileName, (json) => {
151
150
  const index = json.overrides.findIndex(lookup);
152
151
  if (index !== -1) {
153
- json.overrides[index] = update(json.overrides[index]);
152
+ const newOverride = update(json.overrides[index]);
153
+ if (newOverride) {
154
+ json.overrides[index] = newOverride;
155
+ }
156
+ else {
157
+ json.overrides.splice(index, 1);
158
+ }
154
159
  }
155
160
  return json;
156
161
  });
@@ -163,12 +168,12 @@ function lintConfigHasOverride(tree, root, lookup, checkBaseConfig = false) {
163
168
  }
164
169
  const isBase = checkBaseConfig && findEslintFile(tree, root).includes('.base');
165
170
  if ((0, flat_config_1.useFlatConfig)(tree)) {
166
- const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? exports.baseEsLintFlatConfigFile : 'eslint.config.js');
171
+ const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? config_file_1.baseEsLintFlatConfigFile : 'eslint.config.js');
167
172
  const content = tree.read(fileName, 'utf8');
168
173
  return (0, ast_utils_1.hasOverride)(content, lookup);
169
174
  }
170
175
  else {
171
- const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? exports.baseEsLintConfigFile : '.eslintrc.json');
176
+ const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? config_file_1.baseEsLintConfigFile : '.eslintrc.json');
172
177
  return (0, devkit_1.readJson)(tree, fileName).overrides?.some(lookup) || false;
173
178
  }
174
179
  }
@@ -183,7 +188,7 @@ function replaceOverridesInLintConfig(tree, root, overrides) {
183
188
  }
184
189
  content = (0, ast_utils_1.removeOverridesFromLintConfig)(content);
185
190
  overrides.forEach((override) => {
186
- const flatOverride = (0, ast_utils_1.generateFlatOverride)(override, root);
191
+ const flatOverride = (0, ast_utils_1.generateFlatOverride)(override);
187
192
  (0, ast_utils_1.addBlockToFlatConfigExport)(content, flatOverride);
188
193
  });
189
194
  tree.write(fileName, content);
@@ -202,7 +207,9 @@ function addExtendsToLintConfig(tree, root, plugin) {
202
207
  if ((0, flat_config_1.useFlatConfig)(tree)) {
203
208
  const fileName = (0, devkit_1.joinPathFragments)(root, 'eslint.config.js');
204
209
  const pluginExtends = (0, ast_utils_1.generatePluginExtendsElement)(plugins);
205
- tree.write(fileName, (0, ast_utils_1.addBlockToFlatConfigExport)(tree.read(fileName, 'utf8'), pluginExtends));
210
+ let content = tree.read(fileName, 'utf8');
211
+ content = (0, ast_utils_1.addCompatToFlatConfig)(content);
212
+ tree.write(fileName, (0, ast_utils_1.addBlockToFlatConfigExport)(content, pluginExtends));
206
213
  }
207
214
  else {
208
215
  const fileName = (0, devkit_1.joinPathFragments)(root, '.eslintrc.json');
@@ -247,7 +254,7 @@ function addIgnoresToLintConfig(tree, root, ignorePatterns) {
247
254
  if ((0, flat_config_1.useFlatConfig)(tree)) {
248
255
  const fileName = (0, devkit_1.joinPathFragments)(root, 'eslint.config.js');
249
256
  const block = (0, ast_utils_1.generateAst)({
250
- ignores: ignorePatterns.map((path) => (0, ast_utils_1.mapFilePath)(path, root)),
257
+ ignores: ignorePatterns.map((path) => (0, path_utils_1.mapFilePath)(path)),
251
258
  });
252
259
  tree.write(fileName, (0, ast_utils_1.addBlockToFlatConfigExport)(tree.read(fileName, 'utf8'), block));
253
260
  }
@@ -8,7 +8,7 @@ export declare function hasOverride(content: string, lookup: (override: Linter.C
8
8
  /**
9
9
  * Finds an override matching the lookup function and applies the update function to it
10
10
  */
11
- export declare function replaceOverride(content: string, root: string, lookup: (override: Linter.ConfigOverride<Linter.RulesRecord>) => boolean, update: (override: Linter.ConfigOverride<Linter.RulesRecord>) => Linter.ConfigOverride<Linter.RulesRecord>): string;
11
+ export declare function replaceOverride(content: string, root: string, lookup: (override: Linter.ConfigOverride<Linter.RulesRecord>) => boolean, update?: (override: Linter.ConfigOverride<Linter.RulesRecord>) => Linter.ConfigOverride<Linter.RulesRecord>): string;
12
12
  /**
13
13
  * Adding require statement to the top of the file
14
14
  */
@@ -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,12 +119,14 @@ function replaceOverride(content, root, lookup, update) {
118
119
  length: end - start,
119
120
  });
120
121
  const updatedData = update(data);
121
- mapFilePaths(updatedData, root);
122
- changes.push({
123
- type: devkit_1.ChangeType.Insert,
124
- index: start,
125
- text: JSON.stringify(updatedData, null, 2).slice(2, -2), // remove curly braces and start/end line breaks since we are injecting just properties
126
- });
122
+ if (updatedData) {
123
+ mapFilePaths(updatedData);
124
+ changes.push({
125
+ type: devkit_1.ChangeType.Insert,
126
+ index: start,
127
+ text: JSON.stringify(updatedData, null, 2).slice(2, -2), // remove curly braces and start/end line breaks since we are injecting just properties
128
+ });
129
+ }
127
130
  }
128
131
  }
129
132
  });
@@ -470,10 +473,15 @@ exports.generatePluginExtendsElement = generatePluginExtendsElement;
470
473
  /**
471
474
  * Stringifies TS nodes to file content string
472
475
  */
473
- function stringifyNodeList(nodes, root, fileName) {
476
+ function stringifyNodeList(nodes) {
474
477
  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);
478
+ const resultFile = ts.createSourceFile('', '', ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
479
+ return (printer
480
+ .printList(ts.ListFormat.MultiLine, nodes, resultFile)
481
+ // add new line before compat initialization
482
+ .replace(/const compat = new FlatCompat/, '\nconst compat = new FlatCompat')
483
+ // add new line before module.exports = ...
484
+ .replace(/module\.exports/, '\nmodule.exports'));
477
485
  }
478
486
  exports.stringifyNodeList = stringifyNodeList;
479
487
  /**
@@ -488,21 +496,30 @@ exports.generateRequire = generateRequire;
488
496
  /**
489
497
  * Generates AST object or spread element based on JSON override object
490
498
  */
491
- function generateFlatOverride(override, root) {
492
- mapFilePaths(override, root);
499
+ function generateFlatOverride(override) {
500
+ mapFilePaths(override);
493
501
  if (!override.env &&
494
502
  !override.extends &&
495
503
  !override.plugins &&
496
504
  !override.parser) {
505
+ if (override.parserOptions) {
506
+ const { parserOptions, ...rest } = override;
507
+ return generateAst({ ...rest, languageSettings: { parserOptions } });
508
+ }
497
509
  return generateAst(override);
498
510
  }
499
- const { files, excludedFiles, rules, ...rest } = override;
511
+ const { files, excludedFiles, rules, parserOptions, ...rest } = override;
500
512
  const objectLiteralElements = [
501
513
  ts.factory.createSpreadAssignment(ts.factory.createIdentifier('config')),
502
514
  ];
503
515
  addTSObjectProperty(objectLiteralElements, 'files', files);
504
516
  addTSObjectProperty(objectLiteralElements, 'excludedFiles', excludedFiles);
505
517
  addTSObjectProperty(objectLiteralElements, 'rules', rules);
518
+ if (parserOptions) {
519
+ addTSObjectProperty(objectLiteralElements, 'languageSettings', {
520
+ parserOptions,
521
+ });
522
+ }
506
523
  return ts.factory.createSpreadElement(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('compat'), ts.factory.createIdentifier('config')), undefined, [generateAst(rest)]), ts.factory.createIdentifier('map')), undefined, [
507
524
  ts.factory.createArrowFunction(undefined, undefined, [
508
525
  ts.factory.createParameterDeclaration(undefined, undefined, 'config'),
@@ -510,41 +527,21 @@ function generateFlatOverride(override, root) {
510
527
  ]));
511
528
  }
512
529
  exports.generateFlatOverride = generateFlatOverride;
513
- function mapFilePaths(override, root) {
530
+ function mapFilePaths(override) {
514
531
  if (override.files) {
515
532
  override.files = Array.isArray(override.files)
516
533
  ? override.files
517
534
  : [override.files];
518
- override.files = override.files.map((file) => mapFilePath(file, root));
535
+ override.files = override.files.map((file) => (0, path_utils_1.mapFilePath)(file));
519
536
  }
520
537
  if (override.excludedFiles) {
521
538
  override.excludedFiles = Array.isArray(override.excludedFiles)
522
539
  ? override.excludedFiles
523
540
  : [override.excludedFiles];
524
- override.excludedFiles = override.excludedFiles.map((file) => mapFilePath(file, root));
541
+ override.excludedFiles = override.excludedFiles.map((file) => (0, path_utils_1.mapFilePath)(file));
525
542
  }
526
543
  }
527
544
  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
545
  function addTSObjectProperty(elements, key, value) {
549
546
  if (value) {
550
547
  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 declare function hasEslintPlugin(tree: Tree): boolean;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hasEslintPlugin = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ function hasEslintPlugin(tree) {
6
+ const nxJson = (0, devkit_1.readNxJson)(tree);
7
+ return nxJson.plugins?.some((p) => typeof p === 'string'
8
+ ? p === '@nx/eslint/plugin'
9
+ : p.plugin === '@nx/eslint/plugin');
10
+ }
11
+ exports.hasEslintPlugin = hasEslintPlugin;
@@ -16,7 +16,7 @@
16
16
 
17
17
  import { ESLintUtils } from '@typescript-eslint/utils';
18
18
 
19
- // NOTE: The rule will be available in ESLint configs as "@nx/workspace/<%= name %>"
19
+ // NOTE: The rule will be available in ESLint configs as "@nx/workspace-<%= name %>"
20
20
  export const RULE_NAME = '<%= name %>';
21
21
 
22
22
  export const rule = ESLintUtils.RuleCreator(() => __filename)({
@@ -25,7 +25,7 @@ export const rule = ESLintUtils.RuleCreator(() => __filename)({
25
25
  type: 'problem',
26
26
  docs: {
27
27
  description: ``,
28
- recommended: 'error',
28
+ recommended: 'recommended',
29
29
  },
30
30
  schema: [],
31
31
  messages: {},