@nx/eslint 17.0.2 → 17.0.4

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 -15
  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 +41 -40
  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
  });
@@ -223,19 +226,23 @@ function addBlockToFlatConfigExport(content, config, options = {
223
226
  });
224
227
  const insert = printer.printNode(ts.EmitHint.Expression, config, source);
225
228
  if (options.insertAtTheEnd) {
229
+ const index = exportsArray.length > 0
230
+ ? exportsArray.at(exportsArray.length - 1).end
231
+ : exportsArray.pos;
226
232
  return (0, devkit_1.applyChangesToString)(content, [
227
233
  {
228
234
  type: devkit_1.ChangeType.Insert,
229
- index: exportsArray[exportsArray.length - 1].end,
235
+ index,
230
236
  text: `,\n${insert}`,
231
237
  },
232
238
  ]);
233
239
  }
234
240
  else {
241
+ const index = exportsArray.length > 0 ? exportsArray.at(0).pos : exportsArray.pos;
235
242
  return (0, devkit_1.applyChangesToString)(content, [
236
243
  {
237
244
  type: devkit_1.ChangeType.Insert,
238
- index: exportsArray[0].pos,
245
+ index,
239
246
  text: `\n${insert},`,
240
247
  },
241
248
  ]);
@@ -466,10 +473,15 @@ exports.generatePluginExtendsElement = generatePluginExtendsElement;
466
473
  /**
467
474
  * Stringifies TS nodes to file content string
468
475
  */
469
- function stringifyNodeList(nodes, root, fileName) {
476
+ function stringifyNodeList(nodes) {
470
477
  const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
471
- const resultFile = ts.createSourceFile((0, devkit_1.joinPathFragments)(root, fileName), '', ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
472
- 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'));
473
485
  }
474
486
  exports.stringifyNodeList = stringifyNodeList;
475
487
  /**
@@ -484,21 +496,30 @@ exports.generateRequire = generateRequire;
484
496
  /**
485
497
  * Generates AST object or spread element based on JSON override object
486
498
  */
487
- function generateFlatOverride(override, root) {
488
- mapFilePaths(override, root);
499
+ function generateFlatOverride(override) {
500
+ mapFilePaths(override);
489
501
  if (!override.env &&
490
502
  !override.extends &&
491
503
  !override.plugins &&
492
504
  !override.parser) {
505
+ if (override.parserOptions) {
506
+ const { parserOptions, ...rest } = override;
507
+ return generateAst({ ...rest, languageSettings: { parserOptions } });
508
+ }
493
509
  return generateAst(override);
494
510
  }
495
- const { files, excludedFiles, rules, ...rest } = override;
511
+ const { files, excludedFiles, rules, parserOptions, ...rest } = override;
496
512
  const objectLiteralElements = [
497
513
  ts.factory.createSpreadAssignment(ts.factory.createIdentifier('config')),
498
514
  ];
499
515
  addTSObjectProperty(objectLiteralElements, 'files', files);
500
516
  addTSObjectProperty(objectLiteralElements, 'excludedFiles', excludedFiles);
501
517
  addTSObjectProperty(objectLiteralElements, 'rules', rules);
518
+ if (parserOptions) {
519
+ addTSObjectProperty(objectLiteralElements, 'languageSettings', {
520
+ parserOptions,
521
+ });
522
+ }
502
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, [
503
524
  ts.factory.createArrowFunction(undefined, undefined, [
504
525
  ts.factory.createParameterDeclaration(undefined, undefined, 'config'),
@@ -506,41 +527,21 @@ function generateFlatOverride(override, root) {
506
527
  ]));
507
528
  }
508
529
  exports.generateFlatOverride = generateFlatOverride;
509
- function mapFilePaths(override, root) {
530
+ function mapFilePaths(override) {
510
531
  if (override.files) {
511
532
  override.files = Array.isArray(override.files)
512
533
  ? override.files
513
534
  : [override.files];
514
- override.files = override.files.map((file) => mapFilePath(file, root));
535
+ override.files = override.files.map((file) => (0, path_utils_1.mapFilePath)(file));
515
536
  }
516
537
  if (override.excludedFiles) {
517
538
  override.excludedFiles = Array.isArray(override.excludedFiles)
518
539
  ? override.excludedFiles
519
540
  : [override.excludedFiles];
520
- override.excludedFiles = override.excludedFiles.map((file) => mapFilePath(file, root));
541
+ override.excludedFiles = override.excludedFiles.map((file) => (0, path_utils_1.mapFilePath)(file));
521
542
  }
522
543
  }
523
544
  exports.mapFilePaths = mapFilePaths;
524
- function mapFilePath(filePath, root) {
525
- if (filePath.startsWith('!')) {
526
- const fileWithoutBang = filePath.slice(1);
527
- if (fileWithoutBang.startsWith('*.')) {
528
- return `!${(0, devkit_1.joinPathFragments)(root, '**', fileWithoutBang)}`;
529
- }
530
- else if (!fileWithoutBang.startsWith(root)) {
531
- return `!${(0, devkit_1.joinPathFragments)(root, fileWithoutBang)}`;
532
- }
533
- return filePath;
534
- }
535
- if (filePath.startsWith('*.')) {
536
- return (0, devkit_1.joinPathFragments)(root, '**', filePath);
537
- }
538
- else if (!filePath.startsWith(root)) {
539
- return (0, devkit_1.joinPathFragments)(root, filePath);
540
- }
541
- return filePath;
542
- }
543
- exports.mapFilePath = mapFilePath;
544
545
  function addTSObjectProperty(elements, key, value) {
545
546
  if (value) {
546
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;