@nx/eslint 17.0.0-beta.8

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 (69) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +61 -0
  3. package/executors.json +10 -0
  4. package/generators.json +22 -0
  5. package/index.d.ts +4 -0
  6. package/index.js +14 -0
  7. package/migrations.json +79 -0
  8. package/package.json +51 -0
  9. package/src/executors/lint/hasher.d.ts +9 -0
  10. package/src/executors/lint/hasher.js +43 -0
  11. package/src/executors/lint/lint.impl.d.ts +5 -0
  12. package/src/executors/lint/lint.impl.js +140 -0
  13. package/src/executors/lint/schema.d.ts +39 -0
  14. package/src/executors/lint/schema.json +144 -0
  15. package/src/executors/lint/utility/eslint-utils.d.ts +6 -0
  16. package/src/executors/lint/utility/eslint-utils.js +71 -0
  17. package/src/generators/convert-to-flat-config/converters/json-converter.d.ts +6 -0
  18. package/src/generators/convert-to-flat-config/converters/json-converter.js +180 -0
  19. package/src/generators/convert-to-flat-config/generator.d.ts +4 -0
  20. package/src/generators/convert-to-flat-config/generator.js +83 -0
  21. package/src/generators/convert-to-flat-config/schema.d.ts +3 -0
  22. package/src/generators/convert-to-flat-config/schema.json +17 -0
  23. package/src/generators/init/global-eslint-config.d.ts +29 -0
  24. package/src/generators/init/global-eslint-config.js +98 -0
  25. package/src/generators/init/init-migration.d.ts +3 -0
  26. package/src/generators/init/init-migration.js +103 -0
  27. package/src/generators/init/init.d.ts +9 -0
  28. package/src/generators/init/init.js +65 -0
  29. package/src/generators/lint-project/lint-project.d.ts +16 -0
  30. package/src/generators/lint-project/lint-project.js +191 -0
  31. package/src/generators/utils/eslint-file.d.ts +19 -0
  32. package/src/generators/utils/eslint-file.js +269 -0
  33. package/src/generators/utils/eslint-targets.d.ts +2 -0
  34. package/src/generators/utils/eslint-targets.js +18 -0
  35. package/src/generators/utils/flat-config/ast-utils.d.ts +61 -0
  36. package/src/generators/utils/flat-config/ast-utils.js +581 -0
  37. package/src/generators/utils/flat-config/path-utils.d.ts +2 -0
  38. package/src/generators/utils/flat-config/path-utils.js +31 -0
  39. package/src/generators/utils/linter.d.ts +4 -0
  40. package/src/generators/utils/linter.js +8 -0
  41. package/src/generators/workspace-rule/files/__name__.spec.ts__tmpl__ +11 -0
  42. package/src/generators/workspace-rule/files/__name__.ts__tmpl__ +37 -0
  43. package/src/generators/workspace-rule/schema.json +26 -0
  44. package/src/generators/workspace-rule/workspace-rule.d.ts +6 -0
  45. package/src/generators/workspace-rule/workspace-rule.js +73 -0
  46. package/src/generators/workspace-rules-project/files/index.ts__tmpl__ +27 -0
  47. package/src/generators/workspace-rules-project/files/tsconfig.json__tmpl__ +13 -0
  48. package/src/generators/workspace-rules-project/files/tsconfig.lint.json__tmpl__ +9 -0
  49. package/src/generators/workspace-rules-project/schema.json +23 -0
  50. package/src/generators/workspace-rules-project/workspace-rules-project.d.ts +7 -0
  51. package/src/generators/workspace-rules-project/workspace-rules-project.js +80 -0
  52. package/src/migrations/update-15-0-0/add-eslint-inputs.d.ts +2 -0
  53. package/src/migrations/update-15-0-0/add-eslint-inputs.js +27 -0
  54. package/src/migrations/update-15-7-1/add-eslint-ignore.d.ts +2 -0
  55. package/src/migrations/update-15-7-1/add-eslint-ignore.js +36 -0
  56. package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.d.ts +2 -0
  57. package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.js +9 -0
  58. package/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.d.ts +2 -0
  59. package/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.js +44 -0
  60. package/src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint.d.ts +2 -0
  61. package/src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint.js +45 -0
  62. package/src/utils/flat-config.d.ts +2 -0
  63. package/src/utils/flat-config.js +7 -0
  64. package/src/utils/rules-requiring-type-checking.d.ts +3 -0
  65. package/src/utils/rules-requiring-type-checking.js +84 -0
  66. package/src/utils/versions.d.ts +5 -0
  67. package/src/utils/versions.js +8 -0
  68. package/src/utils/workspace-lint-rules.d.ts +1 -0
  69. package/src/utils/workspace-lint-rules.js +5 -0
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lintInitGenerator = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const versions_1 = require("../../utils/versions");
6
+ const eslint_file_1 = require("../utils/eslint-file");
7
+ const global_eslint_config_1 = require("./global-eslint-config");
8
+ function addTargetDefaults(tree) {
9
+ const nxJson = (0, devkit_1.readNxJson)(tree);
10
+ const productionFileSet = nxJson.namedInputs?.production;
11
+ if (productionFileSet) {
12
+ // Remove .eslintrc.json
13
+ productionFileSet.push('!{projectRoot}/.eslintrc.json');
14
+ productionFileSet.push('!{projectRoot}/eslint.config.js');
15
+ // Dedupe and set
16
+ nxJson.namedInputs.production = Array.from(new Set(productionFileSet));
17
+ }
18
+ nxJson.targetDefaults ??= {};
19
+ nxJson.targetDefaults.lint ??= {};
20
+ nxJson.targetDefaults.lint.inputs ??= [
21
+ 'default',
22
+ `{workspaceRoot}/.eslintrc.json`,
23
+ `{workspaceRoot}/.eslintignore`,
24
+ `{workspaceRoot}/eslint.config.js`,
25
+ ];
26
+ (0, devkit_1.updateNxJson)(tree, nxJson);
27
+ }
28
+ /**
29
+ * Initializes ESLint configuration in a workspace and adds necessary dependencies.
30
+ */
31
+ function initEsLint(tree, options) {
32
+ if ((0, eslint_file_1.findEslintFile)(tree)) {
33
+ return () => { };
34
+ }
35
+ if (!options.skipPackageJson) {
36
+ (0, devkit_1.removeDependenciesFromPackageJson)(tree, ['@nx/eslint'], []);
37
+ }
38
+ (0, devkit_1.writeJson)(tree, '.eslintrc.json', (0, global_eslint_config_1.getGlobalEsLintConfiguration)(options.unitTestRunner, options.rootProject));
39
+ tree.write('.eslintignore', 'node_modules\n');
40
+ addTargetDefaults(tree);
41
+ if (tree.exists('.vscode/extensions.json')) {
42
+ (0, devkit_1.updateJson)(tree, '.vscode/extensions.json', (json) => {
43
+ json.recommendations ||= [];
44
+ const extension = 'dbaeumer.vscode-eslint';
45
+ if (!json.recommendations.includes(extension)) {
46
+ json.recommendations.push(extension);
47
+ }
48
+ return json;
49
+ });
50
+ }
51
+ return !options.skipPackageJson
52
+ ? (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
53
+ '@nx/eslint': versions_1.nxVersion,
54
+ '@nx/eslint-plugin': versions_1.nxVersion,
55
+ '@typescript-eslint/parser': versions_1.typescriptESLintVersion,
56
+ '@typescript-eslint/eslint-plugin': versions_1.typescriptESLintVersion,
57
+ eslint: versions_1.eslintVersion,
58
+ 'eslint-config-prettier': versions_1.eslintConfigPrettierVersion,
59
+ })
60
+ : () => { };
61
+ }
62
+ function lintInitGenerator(tree, options) {
63
+ return initEsLint(tree, options);
64
+ }
65
+ exports.lintInitGenerator = lintInitGenerator;
@@ -0,0 +1,16 @@
1
+ import type { Tree } from '@nx/devkit';
2
+ import { Linter as LinterEnum } from '../utils/linter';
3
+ interface LintProjectOptions {
4
+ project: string;
5
+ linter?: LinterEnum;
6
+ eslintFilePatterns?: string[];
7
+ tsConfigPaths?: string[];
8
+ skipFormat: boolean;
9
+ setParserOptionsProject?: boolean;
10
+ skipPackageJson?: boolean;
11
+ unitTestRunner?: string;
12
+ rootProject?: boolean;
13
+ }
14
+ export declare function mapLintPattern(projectRoot: string, extension: string, rootProject?: boolean): string;
15
+ export declare function lintProjectGenerator(tree: Tree, options: LintProjectOptions): Promise<import("@nx/devkit").GeneratorCallback>;
16
+ export {};
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lintProjectGenerator = exports.mapLintPattern = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const eslint_file_1 = require("../utils/eslint-file");
6
+ const path_1 = require("path");
7
+ const init_1 = require("../init/init");
8
+ const init_migration_1 = require("../init/init-migration");
9
+ const project_configuration_1 = require("nx/src/generators/utils/project-configuration");
10
+ const flat_config_1 = require("../../utils/flat-config");
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
+ async function lintProjectGenerator(tree, options) {
22
+ const installTask = (0, init_1.lintInitGenerator)(tree, {
23
+ linter: options.linter,
24
+ unitTestRunner: options.unitTestRunner,
25
+ skipPackageJson: options.skipPackageJson,
26
+ rootProject: options.rootProject,
27
+ });
28
+ 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
+ projectConfig.targets['lint'] = {
34
+ executor: '@nx/eslint:lint',
35
+ outputs: ['{options.outputFile}'],
36
+ options: {
37
+ lintFilePatterns: lintFilePatterns,
38
+ },
39
+ };
40
+ // we are adding new project which is not the root project or
41
+ // companion e2e app so we should check if migration to
42
+ // monorepo style is needed
43
+ if (!options.rootProject) {
44
+ const projects = {};
45
+ (0, project_configuration_1.getProjects)(tree).forEach((v, k) => (projects[k] = v));
46
+ if (isMigrationToMonorepoNeeded(projects, tree)) {
47
+ // we only migrate project configurations that have been created
48
+ const filteredProjects = [];
49
+ Object.entries(projects).forEach(([name, project]) => {
50
+ if (name !== options.project) {
51
+ filteredProjects.push(project);
52
+ }
53
+ });
54
+ (0, init_migration_1.migrateConfigToMonorepoStyle)(filteredProjects, tree, options.unitTestRunner);
55
+ }
56
+ }
57
+ // our root `.eslintrc` is already the project config, so we should not override it
58
+ // additionally, the companion e2e app would have `rootProject: true`
59
+ // so we need to check for the root path as well
60
+ if (!options.rootProject || projectConfig.root !== '.') {
61
+ createEsLintConfiguration(tree, projectConfig, options.setParserOptionsProject);
62
+ }
63
+ // Buildable libs need source analysis enabled for linting `package.json`.
64
+ if (isBuildableLibraryProject(projectConfig) &&
65
+ !isJsAnalyzeSourceFilesEnabled(tree)) {
66
+ (0, devkit_1.updateJson)(tree, 'nx.json', (json) => {
67
+ json.pluginsConfig ??= {};
68
+ json.pluginsConfig['@nx/js'] ??= {};
69
+ json.pluginsConfig['@nx/js'].analyzeSourceFiles = true;
70
+ return json;
71
+ });
72
+ }
73
+ (0, devkit_1.updateProjectConfiguration)(tree, options.project, projectConfig);
74
+ if (!options.skipFormat) {
75
+ await (0, devkit_1.formatFiles)(tree);
76
+ }
77
+ return installTask;
78
+ }
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}`
84
+ : undefined;
85
+ const addDependencyChecks = isBuildableLibraryProject(projectConfig);
86
+ const overrides = [
87
+ {
88
+ files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
89
+ /**
90
+ * NOTE: We no longer set parserOptions.project by default when creating new projects.
91
+ *
92
+ * We have observed that users rarely add rules requiring type-checking to their Nx workspaces, and therefore
93
+ * do not actually need the capabilites which parserOptions.project provides. When specifying parserOptions.project,
94
+ * typescript-eslint needs to create full TypeScript Programs for you. When omitting it, it can perform a simple
95
+ * parse (and AST tranformation) of the source files it encounters during a lint run, which is much faster and much
96
+ * less memory intensive.
97
+ *
98
+ * In the rare case that users attempt to add rules requiring type-checking to their setup later on (and haven't set
99
+ * parserOptions.project), the executor will attempt to look for the particular error typescript-eslint gives you
100
+ * and provide feedback to the user.
101
+ */
102
+ parserOptions: !setParserOptionsProject
103
+ ? undefined
104
+ : {
105
+ project: [`${projectConfig.root}/tsconfig.*?.json`],
106
+ },
107
+ /**
108
+ * Having an empty rules object present makes it more obvious to the user where they would
109
+ * extend things from if they needed to
110
+ */
111
+ rules: {},
112
+ },
113
+ {
114
+ files: ['*.ts', '*.tsx'],
115
+ rules: {},
116
+ },
117
+ {
118
+ files: ['*.js', '*.jsx'],
119
+ rules: {},
120
+ },
121
+ ];
122
+ if (isBuildableLibraryProject(projectConfig)) {
123
+ overrides.push({
124
+ files: ['*.json'],
125
+ parser: 'jsonc-eslint-parser',
126
+ rules: {
127
+ '@nx/dependency-checks': 'error',
128
+ },
129
+ });
130
+ }
131
+ if ((0, flat_config_1.useFlatConfig)(tree)) {
132
+ const isCompatNeeded = addDependencyChecks;
133
+ const nodes = [];
134
+ const importMap = new Map();
135
+ if (eslintConfig) {
136
+ importMap.set(pathToRootConfig, 'baseConfig');
137
+ nodes.push((0, ast_utils_1.generateSpreadElement)('baseConfig'));
138
+ }
139
+ overrides.forEach((override) => {
140
+ nodes.push((0, ast_utils_1.generateFlatOverride)(override, projectConfig.root));
141
+ });
142
+ const nodeList = (0, ast_utils_1.createNodeList)(importMap, nodes, isCompatNeeded);
143
+ const content = (0, ast_utils_1.stringifyNodeList)(nodeList, projectConfig.root, 'eslint.config.js');
144
+ tree.write((0, path_1.join)(projectConfig.root, 'eslint.config.js'), content);
145
+ }
146
+ else {
147
+ (0, devkit_1.writeJson)(tree, (0, path_1.join)(projectConfig.root, `.eslintrc.json`), {
148
+ extends: eslintConfig ? [pathToRootConfig] : undefined,
149
+ // Include project files to be linted since the global one excludes all files.
150
+ ignorePatterns: ['!**/*'],
151
+ overrides,
152
+ });
153
+ }
154
+ }
155
+ function isJsAnalyzeSourceFilesEnabled(tree) {
156
+ const nxJson = (0, devkit_1.readJson)(tree, 'nx.json');
157
+ const jsPluginConfig = nxJson.pluginsConfig?.['@nx/js'];
158
+ return (jsPluginConfig?.analyzeSourceFiles ??
159
+ nxJson.extends !== 'nx/presets/npm.json');
160
+ }
161
+ function isBuildableLibraryProject(projectConfig) {
162
+ return (projectConfig.projectType === 'library' &&
163
+ projectConfig.targets?.build &&
164
+ !!projectConfig.targets.build);
165
+ }
166
+ /**
167
+ * Detect based on the state of lint target configuration of the root project
168
+ * if we should migrate eslint configs to monorepo style
169
+ */
170
+ function isMigrationToMonorepoNeeded(projects, tree) {
171
+ // 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)) {
174
+ return false;
175
+ }
176
+ const configs = Object.values(projects);
177
+ if (configs.length === 1) {
178
+ return false;
179
+ }
180
+ // get root project
181
+ const rootProject = configs.find((p) => p.root === '.');
182
+ if (!rootProject || !rootProject.targets) {
183
+ return false;
184
+ }
185
+ // find if root project has lint target
186
+ const lintTarget = (0, init_migration_1.findLintTarget)(rootProject);
187
+ if (!lintTarget) {
188
+ return false;
189
+ }
190
+ return true;
191
+ }
@@ -0,0 +1,19 @@
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";
6
+ export declare function findEslintFile(tree: Tree, projectRoot?: string): string | null;
7
+ export declare function isEslintConfigSupported(tree: Tree, projectRoot?: string): boolean;
8
+ export declare function updateRelativePathsInConfig(tree: Tree, sourcePath: string, destinationPath: string): void;
9
+ export declare function addOverrideToLintConfig(tree: Tree, root: string, override: Linter.ConfigOverride<Linter.RulesRecord>, options?: {
10
+ insertAtTheEnd?: boolean;
11
+ checkBaseConfig?: boolean;
12
+ }): void;
13
+ export declare function updateOverrideInLintConfig(tree: Tree, root: string, lookup: (override: Linter.ConfigOverride<Linter.RulesRecord>) => boolean, update: (override: Linter.ConfigOverride<Linter.RulesRecord>) => Linter.ConfigOverride<Linter.RulesRecord>): void;
14
+ export declare function lintConfigHasOverride(tree: Tree, root: string, lookup: (override: Linter.ConfigOverride<Linter.RulesRecord>) => boolean, checkBaseConfig?: boolean): boolean;
15
+ export declare function replaceOverridesInLintConfig(tree: Tree, root: string, overrides: Linter.ConfigOverride<Linter.RulesRecord>[]): void;
16
+ export declare function addExtendsToLintConfig(tree: Tree, root: string, plugin: string | string[]): void;
17
+ export declare function addPluginsToLintConfig(tree: Tree, root: string, plugin: string | string[]): void;
18
+ export declare function addIgnoresToLintConfig(tree: Tree, root: string, ignorePatterns: string[]): void;
19
+ export declare function getPluginImport(pluginName: string): string;
@@ -0,0 +1,269 @@
1
+ "use strict";
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;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const flat_config_1 = require("../../utils/flat-config");
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;
21
+ }
22
+ if (projectRoot === '' && tree.exists(exports.baseEsLintFlatConfigFile)) {
23
+ return exports.baseEsLintFlatConfigFile;
24
+ }
25
+ for (const file of exports.eslintConfigFileWhitelist) {
26
+ if (tree.exists((0, devkit_1.joinPathFragments)(projectRoot, file))) {
27
+ return file;
28
+ }
29
+ }
30
+ return null;
31
+ }
32
+ exports.findEslintFile = findEslintFile;
33
+ function isEslintConfigSupported(tree, projectRoot = '') {
34
+ const eslintFile = findEslintFile(tree, projectRoot);
35
+ if (!eslintFile) {
36
+ return false;
37
+ }
38
+ return eslintFile.endsWith('.json') || eslintFile.endsWith('.config.js');
39
+ }
40
+ exports.isEslintConfigSupported = isEslintConfigSupported;
41
+ function updateRelativePathsInConfig(tree, sourcePath, destinationPath) {
42
+ if (sourcePath === destinationPath ||
43
+ !isEslintConfigSupported(tree, destinationPath)) {
44
+ return;
45
+ }
46
+ const configPath = (0, devkit_1.joinPathFragments)(destinationPath, findEslintFile(tree, destinationPath));
47
+ const offset = (0, devkit_1.offsetFromRoot)(destinationPath);
48
+ if ((0, flat_config_1.useFlatConfig)(tree)) {
49
+ const config = tree.read(configPath, 'utf-8');
50
+ tree.write(configPath, replaceFlatConfigPaths(config, sourcePath, offset, destinationPath));
51
+ }
52
+ else {
53
+ (0, devkit_1.updateJson)(tree, configPath, (json) => {
54
+ if (typeof json.extends === 'string') {
55
+ json.extends = offsetFilePath(sourcePath, json.extends, offset);
56
+ }
57
+ else if (json.extends) {
58
+ json.extends = json.extends.map((extend) => offsetFilePath(sourcePath, extend, offset));
59
+ }
60
+ json.overrides?.forEach((o) => {
61
+ if (o.parserOptions?.project) {
62
+ o.parserOptions.project = Array.isArray(o.parserOptions.project)
63
+ ? o.parserOptions.project.map((p) => p.replace(sourcePath, destinationPath))
64
+ : o.parserOptions.project.replace(sourcePath, destinationPath);
65
+ }
66
+ });
67
+ return json;
68
+ });
69
+ }
70
+ }
71
+ exports.updateRelativePathsInConfig = updateRelativePathsInConfig;
72
+ function replaceFlatConfigPaths(config, sourceRoot, offset, destinationRoot) {
73
+ let match;
74
+ let newConfig = config;
75
+ // replace requires
76
+ const requireRegex = RegExp(/require\(['"](.*)['"]\)/g);
77
+ while ((match = requireRegex.exec(newConfig)) !== null) {
78
+ const newPath = offsetFilePath(sourceRoot, match[1], offset);
79
+ newConfig =
80
+ newConfig.slice(0, match.index) +
81
+ `require('${newPath}')` +
82
+ newConfig.slice(match.index + match[0].length);
83
+ }
84
+ // replace projects
85
+ const projectRegex = RegExp(/project:\s?\[?['"](.*)['"]\]?/g);
86
+ while ((match = projectRegex.exec(newConfig)) !== null) {
87
+ const newProjectDef = match[0].replaceAll(sourceRoot, destinationRoot);
88
+ newConfig =
89
+ newConfig.slice(0, match.index) +
90
+ newProjectDef +
91
+ newConfig.slice(match.index + match[0].length);
92
+ }
93
+ return newConfig;
94
+ }
95
+ function offsetFilePath(projectRoot, pathToFile, offset) {
96
+ if (!pathToFile.startsWith('..')) {
97
+ // not a relative path
98
+ return pathToFile;
99
+ }
100
+ return (0, devkit_1.joinPathFragments)(offset, projectRoot, pathToFile);
101
+ }
102
+ function addOverrideToLintConfig(tree, root, override, options = {
103
+ insertAtTheEnd: true,
104
+ }) {
105
+ const isBase = options.checkBaseConfig && findEslintFile(tree, root).includes('.base');
106
+ if ((0, flat_config_1.useFlatConfig)(tree)) {
107
+ const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? exports.baseEsLintFlatConfigFile : 'eslint.config.js');
108
+ const flatOverride = (0, ast_utils_1.generateFlatOverride)(override, root);
109
+ let content = tree.read(fileName, 'utf8');
110
+ // we will be using compat here so we need to make sure it's added
111
+ if (overrideNeedsCompat(override)) {
112
+ content = (0, ast_utils_1.addCompatToFlatConfig)(content);
113
+ }
114
+ tree.write(fileName, (0, ast_utils_1.addBlockToFlatConfigExport)(content, flatOverride, options));
115
+ }
116
+ else {
117
+ const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? exports.baseEsLintConfigFile : '.eslintrc.json');
118
+ (0, devkit_1.updateJson)(tree, fileName, (json) => {
119
+ json.overrides ?? [];
120
+ if (options.insertAtTheEnd) {
121
+ json.overrides.push(override);
122
+ }
123
+ else {
124
+ json.overrides.unshift(override);
125
+ }
126
+ return json;
127
+ });
128
+ }
129
+ }
130
+ exports.addOverrideToLintConfig = addOverrideToLintConfig;
131
+ function overrideNeedsCompat(override) {
132
+ return (!override.env && !override.extends && !override.plugins && !override.parser);
133
+ }
134
+ function updateOverrideInLintConfig(tree, root, lookup, update) {
135
+ if ((0, flat_config_1.useFlatConfig)(tree)) {
136
+ const fileName = (0, devkit_1.joinPathFragments)(root, 'eslint.config.js');
137
+ let content = tree.read(fileName, 'utf8');
138
+ content = (0, ast_utils_1.replaceOverride)(content, root, lookup, update);
139
+ tree.write(fileName, content);
140
+ }
141
+ else {
142
+ const fileName = (0, devkit_1.joinPathFragments)(root, '.eslintrc.json');
143
+ (0, devkit_1.updateJson)(tree, fileName, (json) => {
144
+ const index = json.overrides.findIndex(lookup);
145
+ if (index !== -1) {
146
+ json.overrides[index] = update(json.overrides[index]);
147
+ }
148
+ return json;
149
+ });
150
+ }
151
+ }
152
+ exports.updateOverrideInLintConfig = updateOverrideInLintConfig;
153
+ function lintConfigHasOverride(tree, root, lookup, checkBaseConfig = false) {
154
+ if (!isEslintConfigSupported(tree, root)) {
155
+ return false;
156
+ }
157
+ const isBase = checkBaseConfig && findEslintFile(tree, root).includes('.base');
158
+ if ((0, flat_config_1.useFlatConfig)(tree)) {
159
+ const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? exports.baseEsLintFlatConfigFile : 'eslint.config.js');
160
+ const content = tree.read(fileName, 'utf8');
161
+ return (0, ast_utils_1.hasOverride)(content, lookup);
162
+ }
163
+ else {
164
+ const fileName = (0, devkit_1.joinPathFragments)(root, isBase ? exports.baseEsLintConfigFile : '.eslintrc.json');
165
+ return (0, devkit_1.readJson)(tree, fileName).overrides?.some(lookup) || false;
166
+ }
167
+ }
168
+ exports.lintConfigHasOverride = lintConfigHasOverride;
169
+ function replaceOverridesInLintConfig(tree, root, overrides) {
170
+ if ((0, flat_config_1.useFlatConfig)(tree)) {
171
+ const fileName = (0, devkit_1.joinPathFragments)(root, 'eslint.config.js');
172
+ let content = tree.read(fileName, 'utf8');
173
+ // we will be using compat here so we need to make sure it's added
174
+ if (overrides.some(overrideNeedsCompat)) {
175
+ content = (0, ast_utils_1.addCompatToFlatConfig)(content);
176
+ }
177
+ content = (0, ast_utils_1.removeOverridesFromLintConfig)(content);
178
+ overrides.forEach((override) => {
179
+ const flatOverride = (0, ast_utils_1.generateFlatOverride)(override, root);
180
+ (0, ast_utils_1.addBlockToFlatConfigExport)(content, flatOverride);
181
+ });
182
+ tree.write(fileName, content);
183
+ }
184
+ else {
185
+ const fileName = (0, devkit_1.joinPathFragments)(root, '.eslintrc.json');
186
+ (0, devkit_1.updateJson)(tree, fileName, (json) => {
187
+ json.overrides = overrides;
188
+ return json;
189
+ });
190
+ }
191
+ }
192
+ exports.replaceOverridesInLintConfig = replaceOverridesInLintConfig;
193
+ function addExtendsToLintConfig(tree, root, plugin) {
194
+ const plugins = Array.isArray(plugin) ? plugin : [plugin];
195
+ if ((0, flat_config_1.useFlatConfig)(tree)) {
196
+ const fileName = (0, devkit_1.joinPathFragments)(root, 'eslint.config.js');
197
+ const pluginExtends = (0, ast_utils_1.generatePluginExtendsElement)(plugins);
198
+ tree.write(fileName, (0, ast_utils_1.addBlockToFlatConfigExport)(tree.read(fileName, 'utf8'), pluginExtends));
199
+ }
200
+ else {
201
+ const fileName = (0, devkit_1.joinPathFragments)(root, '.eslintrc.json');
202
+ (0, devkit_1.updateJson)(tree, fileName, (json) => {
203
+ json.extends = [...plugins, ...(json.extends ?? [])];
204
+ return json;
205
+ });
206
+ }
207
+ }
208
+ exports.addExtendsToLintConfig = addExtendsToLintConfig;
209
+ function addPluginsToLintConfig(tree, root, plugin) {
210
+ const plugins = Array.isArray(plugin) ? plugin : [plugin];
211
+ if ((0, flat_config_1.useFlatConfig)(tree)) {
212
+ const fileName = (0, devkit_1.joinPathFragments)(root, 'eslint.config.js');
213
+ let content = tree.read(fileName, 'utf8');
214
+ const mappedPlugins = [];
215
+ plugins.forEach((name) => {
216
+ const imp = getPluginImport(name);
217
+ const varName = (0, devkit_1.names)(imp).propertyName;
218
+ mappedPlugins.push({ name, varName, imp });
219
+ });
220
+ mappedPlugins.forEach(({ varName, imp }) => {
221
+ content = (0, ast_utils_1.addImportToFlatConfig)(content, varName, imp);
222
+ });
223
+ content = (0, ast_utils_1.addPluginsToExportsBlock)(content, mappedPlugins);
224
+ tree.write(fileName, content);
225
+ }
226
+ else {
227
+ const fileName = (0, devkit_1.joinPathFragments)(root, '.eslintrc.json');
228
+ (0, devkit_1.updateJson)(tree, fileName, (json) => {
229
+ json.plugins = [...plugins, ...(json.plugins ?? [])];
230
+ return json;
231
+ });
232
+ }
233
+ }
234
+ exports.addPluginsToLintConfig = addPluginsToLintConfig;
235
+ function addIgnoresToLintConfig(tree, root, ignorePatterns) {
236
+ if ((0, flat_config_1.useFlatConfig)(tree)) {
237
+ const fileName = (0, devkit_1.joinPathFragments)(root, 'eslint.config.js');
238
+ const block = (0, ast_utils_1.generateAst)({
239
+ ignores: ignorePatterns.map((path) => (0, ast_utils_1.mapFilePath)(path, root)),
240
+ });
241
+ tree.write(fileName, (0, ast_utils_1.addBlockToFlatConfigExport)(tree.read(fileName, 'utf8'), block));
242
+ }
243
+ else {
244
+ const fileName = (0, devkit_1.joinPathFragments)(root, '.eslintrc.json');
245
+ (0, devkit_1.updateJson)(tree, fileName, (json) => {
246
+ const ignoreSet = new Set([
247
+ ...(json.ignorePatterns ?? []),
248
+ ...ignorePatterns,
249
+ ]);
250
+ json.ignorePatterns = Array.from(ignoreSet);
251
+ return json;
252
+ });
253
+ }
254
+ }
255
+ exports.addIgnoresToLintConfig = addIgnoresToLintConfig;
256
+ function getPluginImport(pluginName) {
257
+ if (pluginName.includes('eslint-plugin-')) {
258
+ return pluginName;
259
+ }
260
+ if (!pluginName.startsWith('@')) {
261
+ return `eslint-plugin-${pluginName}`;
262
+ }
263
+ if (!pluginName.includes('/')) {
264
+ return `${pluginName}/eslint-plugin`;
265
+ }
266
+ const [scope, name] = pluginName.split('/');
267
+ return `${scope}/eslint-plugin-${name}`;
268
+ }
269
+ exports.getPluginImport = getPluginImport;
@@ -0,0 +1,2 @@
1
+ import { Tree } from '@nx/devkit';
2
+ export declare function getEslintTargets(tree: Tree): Set<string>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getEslintTargets = void 0;
4
+ const executor_options_utils_1 = require("@nx/devkit/src/generators/executor-options-utils");
5
+ function getEslintTargets(tree) {
6
+ const eslintTargetNames = new Set();
7
+ (0, executor_options_utils_1.forEachExecutorOptions)(tree, '@nx/eslint:lint', (_, __, target) => {
8
+ eslintTargetNames.add(target);
9
+ });
10
+ (0, executor_options_utils_1.forEachExecutorOptions)(tree, '@nx/linter:eslint', (_, __, target) => {
11
+ eslintTargetNames.add(target);
12
+ });
13
+ (0, executor_options_utils_1.forEachExecutorOptions)(tree, '@nrwl/linter:eslint', (_, __, target) => {
14
+ eslintTargetNames.add(target);
15
+ });
16
+ return eslintTargetNames;
17
+ }
18
+ exports.getEslintTargets = getEslintTargets;
@@ -0,0 +1,61 @@
1
+ import { Linter } from 'eslint';
2
+ import * as ts from 'typescript';
3
+ /**
4
+ * Remove all overrides from the config file
5
+ */
6
+ export declare function removeOverridesFromLintConfig(content: string): string;
7
+ export declare function hasOverride(content: string, lookup: (override: Linter.ConfigOverride<Linter.RulesRecord>) => boolean): boolean;
8
+ /**
9
+ * Finds an override matching the lookup function and applies the update function to it
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;
12
+ /**
13
+ * Adding require statement to the top of the file
14
+ */
15
+ export declare function addImportToFlatConfig(content: string, variable: string | string[], imp: string): string;
16
+ /**
17
+ * Injects new ts.expression to the end of the module.exports array.
18
+ */
19
+ export declare function addBlockToFlatConfigExport(content: string, config: ts.Expression | ts.SpreadElement, options?: {
20
+ insertAtTheEnd?: boolean;
21
+ checkBaseConfig?: boolean;
22
+ }): string;
23
+ export declare function removePlugin(content: string, pluginName: string, pluginImport: string): string;
24
+ export declare function removeCompatExtends(content: string, compatExtends: string[]): string;
25
+ /**
26
+ * Add plugins block to the top of the export blocks
27
+ */
28
+ export declare function addPluginsToExportsBlock(content: string, plugins: {
29
+ name: string;
30
+ varName: string;
31
+ imp: string;
32
+ }[]): string;
33
+ /**
34
+ * Adds compat if missing to flat config
35
+ */
36
+ export declare function addCompatToFlatConfig(content: string): string;
37
+ /**
38
+ * Generate node list representing the imports and the exports blocks
39
+ * Optionally add flat compat initialization
40
+ */
41
+ export declare function createNodeList(importsMap: Map<string, string>, exportElements: ts.Expression[], isFlatCompatNeeded: boolean): ts.NodeArray<ts.VariableStatement | ts.Identifier | ts.ExpressionStatement | ts.SourceFile>;
42
+ export declare function generateSpreadElement(name: string): ts.SpreadElement;
43
+ export declare function generatePluginExtendsElement(plugins: string[]): ts.SpreadElement;
44
+ /**
45
+ * Stringifies TS nodes to file content string
46
+ */
47
+ export declare function stringifyNodeList(nodes: ts.NodeArray<ts.VariableStatement | ts.Identifier | ts.ExpressionStatement | ts.SourceFile>, root: string, fileName: string): string;
48
+ /**
49
+ * generates AST require statement
50
+ */
51
+ export declare function generateRequire(variableName: string | ts.ObjectBindingPattern, imp: string): ts.VariableStatement;
52
+ /**
53
+ * Generates AST object or spread element based on JSON override object
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;
58
+ /**
59
+ * Generates an AST from a JSON-type input
60
+ */
61
+ export declare function generateAst<T>(input: unknown): T;