@nx/eslint 23.1.0-beta.3 → 23.1.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/generators/convert-to-flat-config/generator.js +58 -11
- package/dist/src/generators/init/init.js +26 -13
- package/dist/src/generators/workspace-rules-project/workspace-rules-project.js +18 -2
- package/dist/src/migrations/update-21-6-0/update-executor-lint-inputs.js +6 -3
- package/dist/src/migrations/update-23-1-0/convert-to-flat-config.js +8 -0
- package/dist/src/migrations/update-23-1-0/migrate-ban-types-rule.md +15 -0
- package/dist/src/migrations/update-23-1-0/remove-removed-typescript-eslint-extension-rules.d.ts +2 -0
- package/dist/src/migrations/update-23-1-0/remove-removed-typescript-eslint-extension-rules.js +128 -0
- package/migrations.json +16 -0
- package/package.json +5 -5
|
@@ -8,6 +8,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
10
|
const config_file_1 = require("../../utils/config-file");
|
|
11
|
+
const semver_1 = require("semver");
|
|
11
12
|
const json_converter_1 = require("./converters/json-converter");
|
|
12
13
|
async function convertToFlatConfigGenerator(tree, options) {
|
|
13
14
|
(0, assert_supported_eslint_version_1.assertSupportedEslintVersion)(tree);
|
|
@@ -65,6 +66,25 @@ function isEslintTarget(target) {
|
|
|
65
66
|
return (target.executor === ESLINT_LINT_EXECUTOR ||
|
|
66
67
|
target.command?.includes('eslint'));
|
|
67
68
|
}
|
|
69
|
+
function hasMatchingEslintTargetDefault(projectConfig, targetDefaults) {
|
|
70
|
+
if (!projectConfig.targets || !targetDefaults) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return Object.entries(targetDefaults).some(([targetName, value]) => {
|
|
74
|
+
if (projectConfig.targets[targetName] === undefined) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (targetName === ESLINT_LINT_EXECUTOR) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
// A target default value can be a plain config object or an array of
|
|
81
|
+
// filtered entries; match against the filter-less (catch-all) entry.
|
|
82
|
+
const targetConfig = Array.isArray(value)
|
|
83
|
+
? value.find((e) => e.filter === undefined)
|
|
84
|
+
: value;
|
|
85
|
+
return targetConfig ? isEslintTarget(targetConfig) : false;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
68
88
|
function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslintIgnoreFiles, format, keepExistingVersions) {
|
|
69
89
|
const eslintFile = (0, eslint_file_1.findEslintFile)(tree, projectConfig.root);
|
|
70
90
|
if (!eslintFile) {
|
|
@@ -95,10 +115,7 @@ function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslint
|
|
|
95
115
|
if (eslintTargets.length > 0) {
|
|
96
116
|
(0, devkit_1.updateProjectConfiguration)(tree, project, projectConfig);
|
|
97
117
|
}
|
|
98
|
-
const hasEslintTargetDefaults = projectConfig.
|
|
99
|
-
Object.keys(nxJson.targetDefaults || {}).some((t) => (t === ESLINT_LINT_EXECUTOR ||
|
|
100
|
-
isEslintTarget(nxJson.targetDefaults[t])) &&
|
|
101
|
-
projectConfig.targets[t]);
|
|
118
|
+
const hasEslintTargetDefaults = hasMatchingEslintTargetDefault(projectConfig, nxJson.targetDefaults);
|
|
102
119
|
if (eslintTargets.length === 0 &&
|
|
103
120
|
!hasEslintTargetDefaults &&
|
|
104
121
|
!(0, plugin_1.hasEslintPlugin)(tree)) {
|
|
@@ -148,20 +165,33 @@ function ensureInputPresent(inputs, value, format) {
|
|
|
148
165
|
}
|
|
149
166
|
// Updates nx.json: rewrites stale eslintrc/eslintignore references across all targetDefaults
|
|
150
167
|
// inputs and namedInputs, and ensures lint targets include the new flat config file as an input
|
|
151
|
-
// (and `production` excludes it).
|
|
168
|
+
// (and `production` excludes it). Handles both the legacy record shape and the new array shape
|
|
169
|
+
// of `targetDefaults`.
|
|
152
170
|
function updateNxJsonConfig(tree, format) {
|
|
153
171
|
if (!tree.exists('nx.json')) {
|
|
154
172
|
return;
|
|
155
173
|
}
|
|
156
174
|
(0, devkit_1.updateJson)(tree, 'nx.json', (json) => {
|
|
175
|
+
const rewriteTargetInputs = (target, isLintTarget) => {
|
|
176
|
+
if (!target.inputs)
|
|
177
|
+
return;
|
|
178
|
+
target.inputs = isLintTarget
|
|
179
|
+
? ensureInputPresent(target.inputs, `{workspaceRoot}/eslint.config.${format}`, format)
|
|
180
|
+
: rewriteLegacyInputs(target.inputs, format);
|
|
181
|
+
};
|
|
157
182
|
if (json.targetDefaults) {
|
|
158
|
-
for (const [name,
|
|
159
|
-
if (!target.inputs)
|
|
160
|
-
continue;
|
|
183
|
+
for (const [name, value] of Object.entries(json.targetDefaults)) {
|
|
161
184
|
const isLintTarget = name === 'lint' || name === ESLINT_LINT_EXECUTOR;
|
|
162
|
-
target
|
|
163
|
-
|
|
164
|
-
|
|
185
|
+
// A target default value can be a plain config object or an array of
|
|
186
|
+
// filtered entries; rewrite inputs on each entry in the array case.
|
|
187
|
+
if (Array.isArray(value)) {
|
|
188
|
+
for (const entry of value) {
|
|
189
|
+
rewriteTargetInputs(entry, isLintTarget);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
rewriteTargetInputs(value, isLintTarget);
|
|
194
|
+
}
|
|
165
195
|
}
|
|
166
196
|
}
|
|
167
197
|
if (json.namedInputs) {
|
|
@@ -256,9 +286,26 @@ function processConvertedConfig(tree, root, source, target, { content, addESLint
|
|
|
256
286
|
if (addESLintJS) {
|
|
257
287
|
devDependencies['@eslint/js'] = versions_1.eslintVersion;
|
|
258
288
|
}
|
|
289
|
+
// The flat/angular presets import the umbrella `angular-eslint` package; add
|
|
290
|
+
// it when the converted config references them so the result resolves.
|
|
291
|
+
if (content.includes('flat/angular')) {
|
|
292
|
+
devDependencies['angular-eslint'] = resolveAngularEslintVersion(tree);
|
|
293
|
+
}
|
|
259
294
|
// Direct invocation is an opt-in upgrade, so by default existing pins are
|
|
260
295
|
// overwritten to land the workspace on the latest flat-config-ready stack.
|
|
261
296
|
// Migrations pass `keepExistingVersions` so the version bump stays owned by
|
|
262
297
|
// `packageJsonUpdates` and only newly added packages are installed here.
|
|
263
298
|
(0, devkit_1.addDependenciesToPackageJson)(tree, {}, devDependencies, 'package.json', keepExistingVersions);
|
|
264
299
|
}
|
|
300
|
+
// The umbrella `angular-eslint` and the scoped `@angular-eslint/*` packages
|
|
301
|
+
// release in lockstep, so pin the umbrella to the major already installed,
|
|
302
|
+
// falling back to the latest major nx generates when none is present. @nx/eslint
|
|
303
|
+
// can't read the canonical pin from @nx/angular without inverting the package
|
|
304
|
+
// dependency (@nx/angular depends on @nx/eslint), so the fallback is hardcoded;
|
|
305
|
+
// keep it in sync with `angularEslintVersion` in packages/angular/src/utils/versions.ts.
|
|
306
|
+
function resolveAngularEslintVersion(tree) {
|
|
307
|
+
const installed = (0, devkit_1.getDependencyVersionFromPackageJson)(tree, '@angular-eslint/eslint-plugin') ??
|
|
308
|
+
(0, devkit_1.getDependencyVersionFromPackageJson)(tree, '@angular-eslint/template-parser');
|
|
309
|
+
const installedMajor = installed ? (0, semver_1.coerce)(installed)?.major : undefined;
|
|
310
|
+
return installedMajor != null ? `^${installedMajor}.0.0` : '^22.0.0';
|
|
311
|
+
}
|
|
@@ -22,19 +22,32 @@ function updateProductionFileset(tree, format = 'mjs') {
|
|
|
22
22
|
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
23
23
|
}
|
|
24
24
|
function addTargetDefaults(tree, format) {
|
|
25
|
-
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
nxJson.targetDefaults
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
const nxJson = (0, devkit_1.readNxJson)(tree) ?? {};
|
|
26
|
+
// `@nx/eslint:lint` is an executor identifier — match defaults keyed on
|
|
27
|
+
// the executor, not on a target named that string.
|
|
28
|
+
const existing = (0, internal_1.findTargetDefault)(nxJson.targetDefaults, {
|
|
29
|
+
executor: '@nx/eslint:lint',
|
|
30
|
+
});
|
|
31
|
+
const patch = {};
|
|
32
|
+
if (existing?.cache === undefined)
|
|
33
|
+
patch.cache = true;
|
|
34
|
+
if (existing?.inputs === undefined) {
|
|
35
|
+
patch.inputs = [
|
|
36
|
+
'default',
|
|
37
|
+
'^default',
|
|
38
|
+
`{workspaceRoot}/.eslintrc.json`,
|
|
39
|
+
`{workspaceRoot}/.eslintignore`,
|
|
40
|
+
`{workspaceRoot}/eslint.config.${format}`,
|
|
41
|
+
'{workspaceRoot}/tools/eslint-rules/**/*',
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
if (Object.keys(patch).length > 0) {
|
|
45
|
+
(0, internal_1.upsertTargetDefault)(tree, nxJson, {
|
|
46
|
+
executor: '@nx/eslint:lint',
|
|
47
|
+
...patch,
|
|
48
|
+
});
|
|
49
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
50
|
+
}
|
|
38
51
|
}
|
|
39
52
|
function updateVsCodeRecommendedExtensions(host) {
|
|
40
53
|
if (!host.exists('.vscode/extensions.json')) {
|
|
@@ -38,8 +38,9 @@ async function lintWorkspaceRulesProjectGenerator(tree, options = {}) {
|
|
|
38
38
|
* TODO: Explore writing a ProjectGraph plugin to make this more surgical.
|
|
39
39
|
*/
|
|
40
40
|
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
const lintEntry = findLintTargetDefault(nxJson.targetDefaults);
|
|
42
|
+
if (lintEntry?.inputs) {
|
|
43
|
+
lintEntry.inputs.push(`{workspaceRoot}/${exports.WORKSPACE_PLUGIN_DIR}/**/*`);
|
|
43
44
|
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
44
45
|
}
|
|
45
46
|
// Add jest to the project and return installation task
|
|
@@ -92,3 +93,18 @@ async function lintWorkspaceRulesProjectGenerator(tree, options = {}) {
|
|
|
92
93
|
}
|
|
93
94
|
return (0, devkit_1.runTasksInSerial)(...tasks);
|
|
94
95
|
}
|
|
96
|
+
function findLintTargetDefault(td) {
|
|
97
|
+
const value = td?.['lint'];
|
|
98
|
+
if (value === undefined)
|
|
99
|
+
return undefined;
|
|
100
|
+
// A target default value can be a plain config object or an array of
|
|
101
|
+
// filtered entries; use the filter-less (catch-all) entry.
|
|
102
|
+
if (Array.isArray(value)) {
|
|
103
|
+
const found = value.find((e) => e.filter === undefined);
|
|
104
|
+
if (!found)
|
|
105
|
+
return undefined;
|
|
106
|
+
const { filter: _filter, ...rest } = found;
|
|
107
|
+
return rest;
|
|
108
|
+
}
|
|
109
|
+
return value;
|
|
110
|
+
}
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = default_1;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const internal_1 = require("@nx/devkit/internal");
|
|
5
6
|
async function default_1(tree) {
|
|
6
|
-
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
7
|
+
const nxJson = (0, devkit_1.readNxJson)(tree) ?? {};
|
|
7
8
|
const executor = '@nx/eslint:lint';
|
|
8
|
-
|
|
9
|
+
const existing = (0, internal_1.findTargetDefault)(nxJson.targetDefaults, { executor });
|
|
10
|
+
if (!existing?.inputs) {
|
|
9
11
|
return;
|
|
10
12
|
}
|
|
11
|
-
const inputs =
|
|
13
|
+
const inputs = [...existing.inputs];
|
|
12
14
|
if (!inputs.includes('^default')) {
|
|
13
15
|
// Add after 'default' if present, otherwise at the beginning
|
|
14
16
|
const defaultIndex = inputs.indexOf('default');
|
|
@@ -22,6 +24,7 @@ async function default_1(tree) {
|
|
|
22
24
|
if (!inputs.includes('{workspaceRoot}/tools/eslint-rules/**/*')) {
|
|
23
25
|
inputs.push('{workspaceRoot}/tools/eslint-rules/**/*');
|
|
24
26
|
}
|
|
27
|
+
(0, internal_1.upsertTargetDefault)(tree, nxJson, { executor, inputs });
|
|
25
28
|
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
26
29
|
await (0, devkit_1.formatFiles)(tree);
|
|
27
30
|
}
|
|
@@ -181,6 +181,10 @@ function findRemovedFormatterTargets(tree) {
|
|
|
181
181
|
if (name !== 'lint' && name !== ESLINT_LINT_EXECUTOR) {
|
|
182
182
|
continue;
|
|
183
183
|
}
|
|
184
|
+
if (Array.isArray(target)) {
|
|
185
|
+
// This migration predates the filtered array value form; values are plain objects here.
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
184
188
|
const optionSets = [[null, target.options], ...Object.entries(target.configurations ?? {})];
|
|
185
189
|
collectRemovedFormatters(`targetDefaults["${name}"]`, optionSets);
|
|
186
190
|
}
|
|
@@ -231,6 +235,10 @@ function findUnsupportedFlatConfigOptionTargets(tree) {
|
|
|
231
235
|
if (name !== 'lint' && name !== ESLINT_LINT_EXECUTOR) {
|
|
232
236
|
continue;
|
|
233
237
|
}
|
|
238
|
+
if (Array.isArray(target)) {
|
|
239
|
+
// This migration predates the filtered array value form; values are plain objects here.
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
234
242
|
const optionSets = [[null, target.options], ...Object.entries(target.configurations ?? {})];
|
|
235
243
|
collect(`targetDefaults["${name}"]`, optionSets, FLAT_CONFIG_UNSUPPORTED_OPTIONS);
|
|
236
244
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Migrate the removed `@typescript-eslint/ban-types` rule
|
|
2
|
+
|
|
3
|
+
typescript-eslint v8 removed `@typescript-eslint/ban-types`, so an ESLint flat
|
|
4
|
+
config that still references it fails to load. It was split into three rules:
|
|
5
|
+
|
|
6
|
+
- `@typescript-eslint/no-empty-object-type` - the `{}` type
|
|
7
|
+
- `@typescript-eslint/no-unsafe-function-type` - the `Function` type
|
|
8
|
+
- `@typescript-eslint/no-wrapper-object-types` - wrapper types (`String`, `Number`, `Boolean`, `Object`, ...)
|
|
9
|
+
|
|
10
|
+
In every ESLint flat config (`eslint.config.{mjs,cjs,js,cts,ts,mts}`) that sets
|
|
11
|
+
`@typescript-eslint/ban-types`, replace that single entry with the three rules
|
|
12
|
+
above. The options do not map 1:1: if the old entry was just `'error'`/`'warn'`,
|
|
13
|
+
set all three to that level; if it customized `types`/`extendDefaults`, translate
|
|
14
|
+
the intent to whichever successor rule covers each banned type and drop anything
|
|
15
|
+
with no equivalent. Then run `nx run-many -t lint` and confirm the configs load.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = update;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const devkit_1 = require("@nx/devkit");
|
|
6
|
+
const ts = tslib_1.__importStar(require("typescript"));
|
|
7
|
+
// Inlined rather than imported from the @nx/eslint utils so this migration stays
|
|
8
|
+
// self-contained - a migration should not depend on a shared list that can change
|
|
9
|
+
// in a later version.
|
|
10
|
+
const ESLINT_FLAT_CONFIG_FILENAMES = [
|
|
11
|
+
'eslint.config.cjs',
|
|
12
|
+
'eslint.config.js',
|
|
13
|
+
'eslint.config.mjs',
|
|
14
|
+
'eslint.config.cts',
|
|
15
|
+
'eslint.config.ts',
|
|
16
|
+
'eslint.config.mts',
|
|
17
|
+
];
|
|
18
|
+
// Formatting/extension rules typescript-eslint removed in v8 (moved to
|
|
19
|
+
// @stylistic). A flat config that still references one fails to load: "Could not
|
|
20
|
+
// find <rule> in plugin @typescript-eslint".
|
|
21
|
+
//
|
|
22
|
+
// These are DELETED, not rewritten to the base ESLint rule (e.g.
|
|
23
|
+
// `@typescript-eslint/no-extra-semi` -> `no-extra-semi`), on purpose: the base
|
|
24
|
+
// equivalents are themselves deprecated and frozen in ESLint 9 (slated for
|
|
25
|
+
// removal), so resurrecting one just defers the same break to the next ESLint
|
|
26
|
+
// major. And Prettier - which nx workspaces run - already enforces this
|
|
27
|
+
// formatting, so the rules were redundant. The long-term home is @stylistic,
|
|
28
|
+
// which we will not auto-add as a dependency.
|
|
29
|
+
const REMOVED_TS_ESLINT_RULES = new Set([
|
|
30
|
+
'block-spacing',
|
|
31
|
+
'brace-style',
|
|
32
|
+
'comma-dangle',
|
|
33
|
+
'comma-spacing',
|
|
34
|
+
'func-call-spacing',
|
|
35
|
+
'indent',
|
|
36
|
+
'key-spacing',
|
|
37
|
+
'keyword-spacing',
|
|
38
|
+
'lines-around-comment',
|
|
39
|
+
'lines-between-class-members',
|
|
40
|
+
'member-delimiter-style',
|
|
41
|
+
'no-extra-parens',
|
|
42
|
+
'no-extra-semi',
|
|
43
|
+
'object-curly-spacing',
|
|
44
|
+
'padding-line-between-statements',
|
|
45
|
+
'quotes',
|
|
46
|
+
'semi',
|
|
47
|
+
'space-before-blocks',
|
|
48
|
+
'space-before-function-paren',
|
|
49
|
+
'space-infix-ops',
|
|
50
|
+
'type-annotation-spacing',
|
|
51
|
+
].map((rule) => `@typescript-eslint/${rule}`));
|
|
52
|
+
// Semantic rules typescript-eslint renamed 1:1 in v8. Unlike the formatting
|
|
53
|
+
// rules these enforce real behavior, so we rewrite the key to the successor to
|
|
54
|
+
// preserve enforcement rather than drop it.
|
|
55
|
+
//
|
|
56
|
+
// `ban-types` is intentionally NOT here: it split into three rules
|
|
57
|
+
// (no-empty-object-type, no-unsafe-function-type, no-wrapper-object-types) whose
|
|
58
|
+
// options do not map cleanly, so it is handled by the companion prompt-based
|
|
59
|
+
// migration instead.
|
|
60
|
+
const RENAMED_TS_ESLINT_RULES = new Map([
|
|
61
|
+
[
|
|
62
|
+
'@typescript-eslint/no-throw-literal',
|
|
63
|
+
'@typescript-eslint/only-throw-error',
|
|
64
|
+
],
|
|
65
|
+
[
|
|
66
|
+
'@typescript-eslint/no-useless-template-literals',
|
|
67
|
+
'@typescript-eslint/no-unnecessary-template-expression',
|
|
68
|
+
],
|
|
69
|
+
]);
|
|
70
|
+
async function update(tree) {
|
|
71
|
+
let changed = false;
|
|
72
|
+
(0, devkit_1.visitNotIgnoredFiles)(tree, '.', (path) => {
|
|
73
|
+
const fileName = path.split('/').pop();
|
|
74
|
+
if (!ESLINT_FLAT_CONFIG_FILENAMES.includes(fileName)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const content = tree.read(path, 'utf-8');
|
|
78
|
+
if (!content?.includes('@typescript-eslint/')) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const source = ts.createSourceFile(path, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
82
|
+
// {start, end, newText} edits, applied high offset -> low so earlier offsets
|
|
83
|
+
// stay valid. Covers both deletes (newText '') and key rewrites uniformly.
|
|
84
|
+
const edits = [];
|
|
85
|
+
const visit = (node) => {
|
|
86
|
+
if (ts.isPropertyAssignment(node) &&
|
|
87
|
+
(ts.isStringLiteral(node.name) ||
|
|
88
|
+
ts.isNoSubstitutionTemplateLiteral(node.name))) {
|
|
89
|
+
const ruleName = node.name.text;
|
|
90
|
+
if (REMOVED_TS_ESLINT_RULES.has(ruleName)) {
|
|
91
|
+
// Remove the whole rule entry, including its leading whitespace and the
|
|
92
|
+
// trailing comma, so the surrounding rules object stays valid.
|
|
93
|
+
let end = node.end;
|
|
94
|
+
const trailingComma = content.slice(end).match(/^\s*,/);
|
|
95
|
+
if (trailingComma) {
|
|
96
|
+
end += trailingComma[0].length;
|
|
97
|
+
}
|
|
98
|
+
edits.push({ start: node.getFullStart(), end, newText: '' });
|
|
99
|
+
}
|
|
100
|
+
else if (RENAMED_TS_ESLINT_RULES.has(ruleName)) {
|
|
101
|
+
// Rewrite only the key, preserving the existing quote style and value.
|
|
102
|
+
const keyStart = node.name.getStart(source);
|
|
103
|
+
const quote = content[keyStart];
|
|
104
|
+
edits.push({
|
|
105
|
+
start: keyStart,
|
|
106
|
+
end: node.name.getEnd(),
|
|
107
|
+
newText: `${quote}${RENAMED_TS_ESLINT_RULES.get(ruleName)}${quote}`,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
ts.forEachChild(node, visit);
|
|
112
|
+
};
|
|
113
|
+
visit(source);
|
|
114
|
+
if (edits.length) {
|
|
115
|
+
edits.sort((a, b) => b.start - a.start);
|
|
116
|
+
let updated = content;
|
|
117
|
+
for (const edit of edits) {
|
|
118
|
+
updated =
|
|
119
|
+
updated.slice(0, edit.start) + edit.newText + updated.slice(edit.end);
|
|
120
|
+
}
|
|
121
|
+
tree.write(path, updated);
|
|
122
|
+
changed = true;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
if (changed) {
|
|
126
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
127
|
+
}
|
|
128
|
+
}
|
package/migrations.json
CHANGED
|
@@ -24,6 +24,22 @@
|
|
|
24
24
|
"description": "Convert remaining ESLint configs to flat config for ESLint v9 and keep the workspace lint-passing, disabling rules whose preset defaults changed.",
|
|
25
25
|
"implementation": "./dist/src/migrations/update-23-1-0/convert-to-flat-config",
|
|
26
26
|
"prompt": "./dist/src/migrations/update-23-1-0/convert-to-flat-config.md"
|
|
27
|
+
},
|
|
28
|
+
"update-23-1-0-remove-removed-typescript-eslint-extension-rules": {
|
|
29
|
+
"version": "23.1.0-beta.5",
|
|
30
|
+
"requires": {
|
|
31
|
+
"typescript-eslint": ">=8.0.0"
|
|
32
|
+
},
|
|
33
|
+
"description": "Handle typescript-eslint rules removed in v8 in ESLint flat configs, since referencing a removed rule stops the config from loading. Deletes the removed formatting/extension rules (e.g. @typescript-eslint/no-extra-semi) and rewrites the safe 1:1 renames (no-throw-literal -> only-throw-error, no-useless-template-literals -> no-unnecessary-template-expression) to preserve enforcement.",
|
|
34
|
+
"implementation": "./dist/src/migrations/update-23-1-0/remove-removed-typescript-eslint-extension-rules"
|
|
35
|
+
},
|
|
36
|
+
"update-23-1-0-migrate-ban-types-rule": {
|
|
37
|
+
"version": "23.1.0-beta.5",
|
|
38
|
+
"requires": {
|
|
39
|
+
"typescript-eslint": ">=8.0.0"
|
|
40
|
+
},
|
|
41
|
+
"description": "Migrate the removed @typescript-eslint/ban-types rule to its v8 successors (no-empty-object-type, no-unsafe-function-type, no-wrapper-object-types), whose options do not map 1:1 - so it is driven by an AI prompt rather than a deterministic codemod.",
|
|
42
|
+
"prompt": "./dist/src/migrations/update-23-1-0/migrate-ban-types-rule.md"
|
|
27
43
|
}
|
|
28
44
|
},
|
|
29
45
|
"packageJsonUpdates": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/eslint",
|
|
3
|
-
"version": "23.1.0-beta.
|
|
3
|
+
"version": "23.1.0-beta.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"files": [
|
|
@@ -73,17 +73,17 @@
|
|
|
73
73
|
"peerDependencies": {
|
|
74
74
|
"@zkochan/js-yaml": "0.0.7",
|
|
75
75
|
"eslint": "^9.0.0 || ^10.0.0",
|
|
76
|
-
"@nx/jest": "23.1.0-beta.
|
|
76
|
+
"@nx/jest": "23.1.0-beta.5"
|
|
77
77
|
},
|
|
78
78
|
"dependencies": {
|
|
79
79
|
"semver": "^7.6.3",
|
|
80
80
|
"tslib": "^2.3.0",
|
|
81
81
|
"typescript": "~6.0.3",
|
|
82
|
-
"@nx/
|
|
83
|
-
"@nx/
|
|
82
|
+
"@nx/devkit": "23.1.0-beta.5",
|
|
83
|
+
"@nx/js": "23.1.0-beta.5"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
|
-
"nx": "23.1.0-beta.
|
|
86
|
+
"nx": "23.1.0-beta.5"
|
|
87
87
|
},
|
|
88
88
|
"peerDependenciesMeta": {
|
|
89
89
|
"@nx/jest": {
|