@nx/eslint 23.0.0 → 23.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/dist/src/executors/lint/lint.impl.js +0 -5
- package/dist/src/executors/lint/schema.d.ts +1 -14
- package/dist/src/executors/lint/schema.json +1 -15
- package/dist/src/executors/lint/utility/eslint-utils.js +7 -5
- package/dist/src/generators/convert-to-flat-config/generator.js +42 -19
- package/dist/src/generators/convert-to-flat-config/schema.d.ts +3 -0
- package/dist/src/generators/convert-to-flat-config/schema.json +6 -0
- package/dist/src/generators/init/global-eslint-config.d.ts +1 -1
- package/dist/src/generators/utils/eslint-file.js +20 -28
- package/dist/src/generators/workspace-rule/files/__name__.spec.ts__tmpl__ +1 -7
- package/dist/src/generators/workspace-rule/workspace-rule.js +4 -15
- package/dist/src/migrations/update-23-1-0/convert-to-flat-config.d.ts +15 -0
- package/dist/src/migrations/update-23-1-0/convert-to-flat-config.js +283 -0
- package/dist/src/migrations/update-23-1-0/convert-to-flat-config.md +286 -0
- package/dist/src/plugins/plugin.js +8 -11
- package/dist/src/utils/assert-supported-eslint-version.js +0 -4
- package/dist/src/utils/config-file.js +1 -8
- package/dist/src/utils/deprecation.d.ts +0 -2
- package/dist/src/utils/deprecation.js +1 -11
- package/dist/src/utils/flat-config.d.ts +1 -0
- package/dist/src/utils/flat-config.js +20 -18
- package/dist/src/utils/resolve-eslint-class.js +11 -17
- package/dist/src/utils/versions.d.ts +3 -4
- package/dist/src/utils/versions.js +5 -16
- package/migrations.json +121 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -7,13 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
<div style="text-align: center;">
|
|
9
9
|
|
|
10
|
-
[](https://circleci.com/gh/nrwl/nx)
|
|
11
10
|
[]()
|
|
12
11
|
[](https://www.npmjs.com/package/nx)
|
|
13
12
|
[]()
|
|
14
13
|
[](http://commitizen.github.io/cz-cli/)
|
|
15
|
-
[](https://gitter.im/nrwl-nx/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
|
16
14
|
[](https://go.nx.dev/community)
|
|
15
|
+
[](https://nx.dev/docs/features/ci-features/sandboxing)
|
|
17
16
|
|
|
18
17
|
</div>
|
|
19
18
|
|
|
@@ -6,7 +6,6 @@ const internal_1 = require("@nx/devkit/internal");
|
|
|
6
6
|
const fs_1 = require("fs");
|
|
7
7
|
const utils_1 = require("nx/src/tasks-runner/utils");
|
|
8
8
|
const path_1 = require("path");
|
|
9
|
-
const semver_1 = require("semver");
|
|
10
9
|
const config_file_1 = require("../../utils/config-file");
|
|
11
10
|
const deprecation_1 = require("../../utils/deprecation");
|
|
12
11
|
const versions_1 = require("../../utils/versions");
|
|
@@ -48,10 +47,6 @@ async function run(options, context) {
|
|
|
48
47
|
: undefined;
|
|
49
48
|
const { eslint, ESLint } = await (0, eslint_utils_1.resolveAndInstantiateESLint)(eslintConfigPath, normalizedOptions, hasFlatConfig);
|
|
50
49
|
(0, internal_1.assertSupportedInstalledPackageVersion)('eslint', versions_1.minSupportedEslintVersion);
|
|
51
|
-
const installedEslintVersion = (0, internal_1.getInstalledPackageVersion)('eslint');
|
|
52
|
-
if (installedEslintVersion && (0, semver_1.major)(installedEslintVersion) === 8) {
|
|
53
|
-
(0, deprecation_1.warnEslintV8Deprecation)();
|
|
54
|
-
}
|
|
55
50
|
if (printConfig) {
|
|
56
51
|
try {
|
|
57
52
|
const fileConfig = await eslint.calculateConfigForFile(printConfig);
|
|
@@ -29,17 +29,4 @@ export interface Schema extends JsonObject {
|
|
|
29
29
|
suppressionsLocation?: string;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
type Formatter =
|
|
33
|
-
| 'stylish'
|
|
34
|
-
| 'compact'
|
|
35
|
-
| 'codeframe'
|
|
36
|
-
| 'unix'
|
|
37
|
-
| 'visualstudio'
|
|
38
|
-
| 'table'
|
|
39
|
-
| 'checkstyle'
|
|
40
|
-
| 'html'
|
|
41
|
-
| 'jslint-xml'
|
|
42
|
-
| 'json'
|
|
43
|
-
| 'json-with-metadata'
|
|
44
|
-
| 'junit'
|
|
45
|
-
| 'tap';
|
|
32
|
+
type Formatter = 'stylish' | 'html' | 'json' | 'json-with-metadata';
|
|
@@ -29,21 +29,7 @@
|
|
|
29
29
|
"default": "stylish",
|
|
30
30
|
"anyOf": [
|
|
31
31
|
{
|
|
32
|
-
"enum": [
|
|
33
|
-
"stylish",
|
|
34
|
-
"compact",
|
|
35
|
-
"codeframe",
|
|
36
|
-
"unix",
|
|
37
|
-
"visualstudio",
|
|
38
|
-
"table",
|
|
39
|
-
"checkstyle",
|
|
40
|
-
"html",
|
|
41
|
-
"jslint-xml",
|
|
42
|
-
"json",
|
|
43
|
-
"json-with-metadata",
|
|
44
|
-
"junit",
|
|
45
|
-
"tap"
|
|
46
|
-
]
|
|
32
|
+
"enum": ["stylish", "html", "json", "json-with-metadata"]
|
|
47
33
|
},
|
|
48
34
|
{
|
|
49
35
|
"minLength": 1
|
|
@@ -11,9 +11,10 @@ async function resolveAndInstantiateESLint(eslintConfigPath, options, useFlatCon
|
|
|
11
11
|
const ESLint = await (0, resolve_eslint_class_1.resolveESLintClass)({
|
|
12
12
|
useFlatConfigOverrideVal: useFlatConfig,
|
|
13
13
|
});
|
|
14
|
-
// Use the broader legacy options shape so the
|
|
15
|
-
// below type-check.
|
|
16
|
-
// in
|
|
14
|
+
// Use the broader legacy (eslintrc) options shape so the legacy-only fields
|
|
15
|
+
// assigned below type-check. The flat-only fields (ruleFilter, suppress*) are
|
|
16
|
+
// intersected in and set conditionally below, since LegacyESLint rejects
|
|
17
|
+
// unknown options.
|
|
17
18
|
const eslintOptions = {
|
|
18
19
|
overrideConfigFile: eslintConfigPath,
|
|
19
20
|
fix: !!options.fix &&
|
|
@@ -60,8 +61,9 @@ async function resolveAndInstantiateESLint(eslintConfigPath, options, useFlatCon
|
|
|
60
61
|
eslintOptions.reportUnusedDisableDirectives =
|
|
61
62
|
options.reportUnusedDisableDirectives || undefined;
|
|
62
63
|
}
|
|
63
|
-
//
|
|
64
|
-
|
|
64
|
+
// `ruleFilter` is flat-config only; LegacyESLint (eslintrc) throws on unknown
|
|
65
|
+
// options, so only set it for flat config.
|
|
66
|
+
if (options.quiet && useFlatConfig) {
|
|
65
67
|
eslintOptions.ruleFilter = (rule) => rule.severity === 2;
|
|
66
68
|
}
|
|
67
69
|
// Handle bulk suppression options (ESLint v9.24.0+)
|
|
@@ -7,9 +7,18 @@ const plugin_1 = require("../utils/plugin");
|
|
|
7
7
|
const path_1 = require("path");
|
|
8
8
|
const assert_supported_eslint_version_1 = require("../../utils/assert-supported-eslint-version");
|
|
9
9
|
const versions_1 = require("../../utils/versions");
|
|
10
|
+
const config_file_1 = require("../../utils/config-file");
|
|
10
11
|
const json_converter_1 = require("./converters/json-converter");
|
|
11
12
|
async function convertToFlatConfigGenerator(tree, options) {
|
|
12
13
|
(0, assert_supported_eslint_version_1.assertSupportedEslintVersion)(tree);
|
|
14
|
+
// Already on flat config at the root? There is nothing to convert.
|
|
15
|
+
const hasRootFlatConfig = [
|
|
16
|
+
...config_file_1.ESLINT_FLAT_CONFIG_FILENAMES,
|
|
17
|
+
...config_file_1.BASE_ESLINT_CONFIG_FILENAMES,
|
|
18
|
+
].some((file) => tree.exists(file));
|
|
19
|
+
if (hasRootFlatConfig) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
13
22
|
const eslintFile = (0, eslint_file_1.findEslintFile)(tree);
|
|
14
23
|
if (!eslintFile) {
|
|
15
24
|
throw new Error('Could not find root eslint file');
|
|
@@ -20,11 +29,11 @@ async function convertToFlatConfigGenerator(tree, options) {
|
|
|
20
29
|
options.eslintConfigFormat ??= 'mjs';
|
|
21
30
|
const eslintIgnoreFiles = new Set(['.eslintignore']);
|
|
22
31
|
// convert root eslint config to eslint.config.cjs or eslint.base.config.mjs based on eslintConfigFormat
|
|
23
|
-
convertRootToFlatConfig(tree, eslintFile, options.eslintConfigFormat);
|
|
32
|
+
convertRootToFlatConfig(tree, eslintFile, options.eslintConfigFormat, options.keepExistingVersions);
|
|
24
33
|
// convert project eslint files to eslint.config.cjs
|
|
25
34
|
const projects = (0, devkit_1.getProjects)(tree);
|
|
26
35
|
for (const [project, projectConfig] of projects) {
|
|
27
|
-
convertProjectToFlatConfig(tree, project, projectConfig, (0, devkit_1.readNxJson)(tree), eslintIgnoreFiles, options.eslintConfigFormat);
|
|
36
|
+
convertProjectToFlatConfig(tree, project, projectConfig, (0, devkit_1.readNxJson)(tree), eslintIgnoreFiles, options.eslintConfigFormat, options.keepExistingVersions);
|
|
28
37
|
}
|
|
29
38
|
// delete all .eslintignore files
|
|
30
39
|
for (const ignoreFile of eslintIgnoreFiles) {
|
|
@@ -40,20 +49,33 @@ async function convertToFlatConfigGenerator(tree, options) {
|
|
|
40
49
|
return () => (0, devkit_1.installPackagesTask)(tree);
|
|
41
50
|
}
|
|
42
51
|
exports.default = convertToFlatConfigGenerator;
|
|
43
|
-
function convertRootToFlatConfig(tree, eslintFile, format) {
|
|
52
|
+
function convertRootToFlatConfig(tree, eslintFile, format, keepExistingVersions) {
|
|
44
53
|
if (/\.base\.(js|json|yml|yaml)$/.test(eslintFile)) {
|
|
45
|
-
convertConfigToFlatConfig(tree, '', eslintFile, `eslint.base.config.${format}`, format);
|
|
54
|
+
convertConfigToFlatConfig(tree, '', eslintFile, `eslint.base.config.${format}`, format, undefined, keepExistingVersions);
|
|
55
|
+
}
|
|
56
|
+
// A workspace can ship `.eslintrc.base.json` without a sibling root config, so
|
|
57
|
+
// only convert the non-base root config when it actually exists.
|
|
58
|
+
const rootEslintFile = eslintFile.replace('.base.', '.');
|
|
59
|
+
if (tree.exists(rootEslintFile)) {
|
|
60
|
+
convertConfigToFlatConfig(tree, '', rootEslintFile, `eslint.config.${format}`, format, undefined, keepExistingVersions);
|
|
46
61
|
}
|
|
47
|
-
convertConfigToFlatConfig(tree, '', eslintFile.replace('.base.', '.'), `eslint.config.${format}`, format);
|
|
48
62
|
}
|
|
49
63
|
const ESLINT_LINT_EXECUTOR = '@nx/eslint:lint';
|
|
50
64
|
function isEslintTarget(target) {
|
|
51
65
|
return (target.executor === ESLINT_LINT_EXECUTOR ||
|
|
52
66
|
target.command?.includes('eslint'));
|
|
53
67
|
}
|
|
54
|
-
function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslintIgnoreFiles, format) {
|
|
68
|
+
function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslintIgnoreFiles, format, keepExistingVersions) {
|
|
55
69
|
const eslintFile = (0, eslint_file_1.findEslintFile)(tree, projectConfig.root);
|
|
56
|
-
if (!eslintFile
|
|
70
|
+
if (!eslintFile) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (eslintFile === '.eslintrc.js' || eslintFile === '.eslintrc.cjs') {
|
|
74
|
+
devkit_1.logger.warn(`Skipping "${project}": ${eslintFile} is a JavaScript-based ESLint config, which cannot be converted automatically. Convert it to flat config manually.`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (eslintFile.endsWith('.js')) {
|
|
78
|
+
// Already on a JavaScript-based flat config (eslint.config.js); nothing to convert.
|
|
57
79
|
return;
|
|
58
80
|
}
|
|
59
81
|
// Clean up obsolete target options and detect explicit ESLint targets
|
|
@@ -83,7 +105,7 @@ function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslint
|
|
|
83
105
|
devkit_1.logger.warn(`Skipping "${project}": found ${eslintFile} but no ESLint lint target detected. Convert manually if needed.`);
|
|
84
106
|
return;
|
|
85
107
|
}
|
|
86
|
-
convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, `eslint.config.${format}`, format, ignorePath);
|
|
108
|
+
convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, `eslint.config.${format}`, format, ignorePath, keepExistingVersions);
|
|
87
109
|
eslintIgnoreFiles.add(`${projectConfig.root}/.eslintignore`);
|
|
88
110
|
if (ignorePath) {
|
|
89
111
|
eslintIgnoreFiles.add(ignorePath);
|
|
@@ -185,7 +207,7 @@ function updateProjectConfigsInputs(tree, format) {
|
|
|
185
207
|
function inputsEqual(a, b) {
|
|
186
208
|
return a.length === b.length && a.every((entry, i) => entry === b[i]);
|
|
187
209
|
}
|
|
188
|
-
function convertConfigToFlatConfig(tree, root, source, target, format, ignorePath) {
|
|
210
|
+
function convertConfigToFlatConfig(tree, root, source, target, format, ignorePath, keepExistingVersions) {
|
|
189
211
|
const ignorePaths = ignorePath
|
|
190
212
|
? [ignorePath, `${root}/.eslintignore`]
|
|
191
213
|
: [`${root}/.eslintignore`];
|
|
@@ -193,7 +215,7 @@ function convertConfigToFlatConfig(tree, root, source, target, format, ignorePat
|
|
|
193
215
|
if (source.endsWith('.json') || (0, path_1.basename)(source) === '.eslintrc') {
|
|
194
216
|
const config = (0, devkit_1.readJson)(tree, `${root}/${source}`);
|
|
195
217
|
const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths, format);
|
|
196
|
-
return processConvertedConfig(tree, root, source, target, conversionResult);
|
|
218
|
+
return processConvertedConfig(tree, root, source, target, conversionResult, keepExistingVersions);
|
|
197
219
|
}
|
|
198
220
|
if (source.endsWith('.yaml') || source.endsWith('.yml')) {
|
|
199
221
|
const originalContent = tree.read(`${root}/${source}`, 'utf-8');
|
|
@@ -203,18 +225,17 @@ function convertConfigToFlatConfig(tree, root, source, target, format, ignorePat
|
|
|
203
225
|
filename: source,
|
|
204
226
|
});
|
|
205
227
|
const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths, format);
|
|
206
|
-
return processConvertedConfig(tree, root, source, target, conversionResult);
|
|
228
|
+
return processConvertedConfig(tree, root, source, target, conversionResult, keepExistingVersions);
|
|
207
229
|
}
|
|
208
230
|
}
|
|
209
|
-
function processConvertedConfig(tree, root, source, target, { content, addESLintRC, addESLintJS, }) {
|
|
231
|
+
function processConvertedConfig(tree, root, source, target, { content, addESLintRC, addESLintJS, }, keepExistingVersions) {
|
|
210
232
|
// remove original config file
|
|
211
233
|
tree.delete((0, path_1.join)(root, source));
|
|
212
234
|
// save new
|
|
213
235
|
tree.write((0, path_1.join)(root, target), content);
|
|
214
|
-
// Once converted to flat config, the workspace
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
// on the pre-conversion `eslintrc` workspace state.
|
|
236
|
+
// Once converted to flat config, the workspace should use the latest ESLint
|
|
237
|
+
// stack. Install the versions directly instead of routing through
|
|
238
|
+
// `versions(tree)`, which keys off the pre-conversion declared ESLint version.
|
|
218
239
|
const devDependencies = {
|
|
219
240
|
eslint: versions_1.eslintVersion,
|
|
220
241
|
'eslint-config-prettier': versions_1.eslintConfigPrettierVersion,
|
|
@@ -235,7 +256,9 @@ function processConvertedConfig(tree, root, source, target, { content, addESLint
|
|
|
235
256
|
if (addESLintJS) {
|
|
236
257
|
devDependencies['@eslint/js'] = versions_1.eslintVersion;
|
|
237
258
|
}
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
|
|
259
|
+
// Direct invocation is an opt-in upgrade, so by default existing pins are
|
|
260
|
+
// overwritten to land the workspace on the latest flat-config-ready stack.
|
|
261
|
+
// Migrations pass `keepExistingVersions` so the version bump stays owned by
|
|
262
|
+
// `packageJsonUpdates` and only newly added packages are installed here.
|
|
263
|
+
(0, devkit_1.addDependenciesToPackageJson)(tree, {}, devDependencies, 'package.json', keepExistingVersions);
|
|
241
264
|
}
|
|
@@ -2,4 +2,7 @@ export interface ConvertToFlatConfigGeneratorSchema {
|
|
|
2
2
|
skipFormat?: boolean;
|
|
3
3
|
// Internal option
|
|
4
4
|
eslintConfigFormat?: 'mjs' | 'cjs';
|
|
5
|
+
// Internal option. When true, existing ESLint-related pins in package.json are
|
|
6
|
+
// preserved and only newly added packages are installed.
|
|
7
|
+
keepExistingVersions?: boolean;
|
|
5
8
|
}
|
|
@@ -17,6 +17,12 @@
|
|
|
17
17
|
"enum": ["mjs", "cjs"],
|
|
18
18
|
"default": "mjs",
|
|
19
19
|
"x-priority": "internal"
|
|
20
|
+
},
|
|
21
|
+
"keepExistingVersions": {
|
|
22
|
+
"type": "boolean",
|
|
23
|
+
"description": "Keep the existing versions of any ESLint-related packages already declared in `package.json` instead of overwriting them. Only newly added packages are installed at the latest supported versions.",
|
|
24
|
+
"default": false,
|
|
25
|
+
"x-priority": "internal"
|
|
20
26
|
}
|
|
21
27
|
},
|
|
22
28
|
"additionalProperties": false,
|
|
@@ -26,4 +26,4 @@ export declare const javaScriptOverride: {
|
|
|
26
26
|
rules: {};
|
|
27
27
|
};
|
|
28
28
|
export declare const getGlobalEsLintConfiguration: (unitTestRunner?: string, rootProject?: boolean) => Linter.LegacyConfig;
|
|
29
|
-
export declare const getGlobalFlatEslintConfiguration: (format:
|
|
29
|
+
export declare const getGlobalFlatEslintConfiguration: (format: 'cjs' | 'mjs', rootProject?: boolean) => string;
|
|
@@ -310,36 +310,28 @@ function addExtendsToLintConfig(tree, root, plugin, insertAtTheEnd = false) {
|
|
|
310
310
|
? 'cjs'
|
|
311
311
|
: 'mjs';
|
|
312
312
|
let shouldImportEslintCompat = false;
|
|
313
|
-
//
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
// flush the current batch of compatible plugins and reset it
|
|
323
|
-
pluginExtends.push((0, ast_utils_1.generatePluginExtendsElement)(compatiblePluginsBatch));
|
|
324
|
-
compatiblePluginsBatch = [];
|
|
325
|
-
}
|
|
326
|
-
// generate the extends for the incompatible plugin
|
|
327
|
-
pluginExtends.push((0, ast_utils_1.generatePluginExtendsElementWithCompatFixup)(name));
|
|
328
|
-
shouldImportEslintCompat = true;
|
|
313
|
+
// eslint v9 requires the incompatible plugins to be wrapped with a helper from @eslint/compat
|
|
314
|
+
const plugins = (Array.isArray(plugin) ? plugin : [plugin]).map((p) => typeof p === 'string' ? { name: p, needCompatFixup: false } : p);
|
|
315
|
+
let compatiblePluginsBatch = [];
|
|
316
|
+
plugins.forEach(({ name, needCompatFixup }) => {
|
|
317
|
+
if (needCompatFixup) {
|
|
318
|
+
if (compatiblePluginsBatch.length > 0) {
|
|
319
|
+
// flush the current batch of compatible plugins and reset it
|
|
320
|
+
pluginExtends.push((0, ast_utils_1.generatePluginExtendsElement)(compatiblePluginsBatch));
|
|
321
|
+
compatiblePluginsBatch = [];
|
|
329
322
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
if (compatiblePluginsBatch.length > 0) {
|
|
336
|
-
// flush the batch of compatible plugins
|
|
337
|
-
pluginExtends.push((0, ast_utils_1.generatePluginExtendsElement)(compatiblePluginsBatch));
|
|
323
|
+
// generate the extends for the incompatible plugin
|
|
324
|
+
pluginExtends.push((0, ast_utils_1.generatePluginExtendsElementWithCompatFixup)(name));
|
|
325
|
+
shouldImportEslintCompat = true;
|
|
338
326
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
327
|
+
else {
|
|
328
|
+
// add the compatible plugin to the current batch
|
|
329
|
+
compatiblePluginsBatch.push(name);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
if (compatiblePluginsBatch.length > 0) {
|
|
333
|
+
// flush the batch of compatible plugins
|
|
334
|
+
pluginExtends.push((0, ast_utils_1.generatePluginExtendsElement)(compatiblePluginsBatch));
|
|
343
335
|
}
|
|
344
336
|
let content = tree.read(fileName, 'utf8');
|
|
345
337
|
if (shouldImportEslintCompat) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { RuleTester } from '@typescript-eslint/rule-tester';
|
|
2
2
|
import type { RuleTesterConfig } from '@typescript-eslint/rule-tester';
|
|
3
3
|
import { rule, RULE_NAME } from './<%= name %>';
|
|
4
4
|
|
|
@@ -7,13 +7,7 @@ const ruleTester = new RuleTester({
|
|
|
7
7
|
parser: require('@typescript-eslint/parser'),
|
|
8
8
|
},
|
|
9
9
|
} as RuleTesterConfig);
|
|
10
|
-
<% } else { %>import { TSESLint } from '@typescript-eslint/utils';
|
|
11
|
-
import { rule, RULE_NAME } from './<%= name %>';
|
|
12
10
|
|
|
13
|
-
const ruleTester = new TSESLint.RuleTester({
|
|
14
|
-
parser: require.resolve('@typescript-eslint/parser'),
|
|
15
|
-
});
|
|
16
|
-
<% } %>
|
|
17
11
|
ruleTester.run(RULE_NAME, rule, {
|
|
18
12
|
valid: [`const example = true;`],
|
|
19
13
|
invalid: [],
|
|
@@ -5,26 +5,18 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const internal_1 = require("@nx/devkit/internal");
|
|
6
6
|
const devkit_1 = require("@nx/devkit");
|
|
7
7
|
const path_1 = require("path");
|
|
8
|
-
const semver_1 = require("semver");
|
|
9
8
|
const ts = tslib_1.__importStar(require("typescript"));
|
|
10
9
|
const workspace_lint_rules_1 = require("../../utils/workspace-lint-rules");
|
|
11
10
|
const workspace_rules_project_1 = require("../workspace-rules-project/workspace-rules-project");
|
|
12
11
|
const assert_supported_eslint_version_1 = require("../../utils/assert-supported-eslint-version");
|
|
13
|
-
const flat_config_1 = require("../../utils/flat-config");
|
|
14
12
|
const versions_1 = require("../../utils/versions");
|
|
15
13
|
async function lintWorkspaceRuleGenerator(tree, options) {
|
|
16
14
|
(0, assert_supported_eslint_version_1.assertSupportedEslintVersion)(tree);
|
|
17
15
|
const tasks = [];
|
|
18
|
-
const flatConfig = (0, flat_config_1.useFlatConfig)(tree);
|
|
19
16
|
// ESLint v9 dropped the eslintrc-style `RuleTester` API. typescript-eslint's
|
|
20
|
-
// recommended replacement
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
// major from `versions(tree)` to cover both declared workspaces and fresh
|
|
24
|
-
// installs that will be bumped to v9.
|
|
25
|
-
const { eslintVersion, typescriptESLintVersion } = (0, versions_1.versions)(tree);
|
|
26
|
-
const effectiveEslintMajor = (0, semver_1.major)((0, semver_1.coerce)(eslintVersion));
|
|
27
|
-
const useFlatRuleTester = flatConfig || effectiveEslintMajor >= 9;
|
|
17
|
+
// recommended replacement is the separate `@typescript-eslint/rule-tester`
|
|
18
|
+
// package, whose flat-style API works for both flat and eslintrc workspaces.
|
|
19
|
+
const { typescriptESLintVersion } = (0, versions_1.versions)(tree);
|
|
28
20
|
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
29
21
|
// Ensure that the workspace rules project has been created
|
|
30
22
|
tasks.push(await (0, workspace_rules_project_1.lintWorkspaceRulesProjectGenerator)(tree, {
|
|
@@ -32,15 +24,12 @@ async function lintWorkspaceRuleGenerator(tree, options) {
|
|
|
32
24
|
addPlugin: process.env.NX_ADD_PLUGINS !== 'false' &&
|
|
33
25
|
nxJson.useInferencePlugins !== false,
|
|
34
26
|
}));
|
|
35
|
-
|
|
36
|
-
tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, { '@typescript-eslint/rule-tester': typescriptESLintVersion }, undefined, true));
|
|
37
|
-
}
|
|
27
|
+
tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, { '@typescript-eslint/rule-tester': typescriptESLintVersion }, undefined, true));
|
|
38
28
|
const ruleDir = (0, devkit_1.joinPathFragments)(workspace_lint_rules_1.workspaceLintPluginDir, options.directory ?? '');
|
|
39
29
|
// Generate the required files for the new rule
|
|
40
30
|
(0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files'), ruleDir, {
|
|
41
31
|
tmpl: '',
|
|
42
32
|
name: options.name,
|
|
43
|
-
useFlatRuleTester,
|
|
44
33
|
});
|
|
45
34
|
const nameCamelCase = (0, internal_1.camelize)(options.name);
|
|
46
35
|
/**
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Tree } from '@nx/devkit';
|
|
2
|
+
/**
|
|
3
|
+
* Hybrid migration paired with `convert-to-flat-config.md`. The deterministic
|
|
4
|
+
* half reuses the `@nx/eslint:convert-to-flat-config` generator to convert
|
|
5
|
+
* JSON/YAML eslintrc configs to flat config (the version bump is owned by
|
|
6
|
+
* `packageJsonUpdates`, so it runs with `keepExistingVersions`). It then returns
|
|
7
|
+
* `agentContext` describing the work the generator could not do deterministically
|
|
8
|
+
* (JavaScript-based configs, removed output formatters, the passing-state
|
|
9
|
+
* baseline) so the paired prompt's agent can finish the job and keep the
|
|
10
|
+
* workspace lint-passing.
|
|
11
|
+
*/
|
|
12
|
+
export default function update(tree: Tree): Promise<{
|
|
13
|
+
agentContext: string[];
|
|
14
|
+
nextSteps: string[];
|
|
15
|
+
} | void>;
|