@nx/js 23.1.0-pr.36127.8b9019b → 23.1.0-rc.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/dist/src/executors/prune-lockfile/prune-lockfile.d.ts +2 -0
- package/dist/src/executors/prune-lockfile/prune-lockfile.js +53 -1
- package/dist/src/executors/tsc/tsc.impl.js +6 -2
- package/dist/src/generators/setup-build/generator.js +1 -3
- package/dist/src/migrations/update-22-0-0/remove-external-options-from-js-executors.js +37 -17
- package/dist/src/migrations/update-23-1-0/add-ignore-deprecations-for-ts6.d.ts +37 -22
- package/dist/src/migrations/update-23-1-0/add-ignore-deprecations-for-ts6.js +201 -137
- package/dist/src/migrations/update-23-1-0/add-ignore-deprecations-for-ts6.md +10 -7
- package/dist/src/migrations/update-23-1-0/set-tsconfig-root-dir-for-ts6.d.ts +26 -0
- package/dist/src/migrations/update-23-1-0/set-tsconfig-root-dir-for-ts6.js +215 -0
- package/dist/src/migrations/update-23-1-0/set-tsconfig-root-dir-for-ts6.md +36 -0
- package/dist/src/utils/buildable-libs-utils.js +9 -1
- package/dist/src/utils/prettier.js +17 -13
- package/dist/src/utils/swc/compile-swc.js +4 -1
- package/dist/src/utils/typescript/run-type-check.js +4 -0
- package/migrations.json +11 -2
- package/package.json +4 -4
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type ExecutorContext } from '@nx/devkit';
|
|
2
|
+
import { type PackageJson } from 'nx/src/utils/package-json';
|
|
2
3
|
import { type PruneLockfileOptions } from './schema';
|
|
3
4
|
export default function pruneLockfileExecutor(schema: PruneLockfileOptions, context: ExecutorContext): Promise<{
|
|
4
5
|
success: boolean;
|
|
5
6
|
}>;
|
|
7
|
+
export declare function resolveCatalogReferences(packageJson: PackageJson): PackageJson;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = pruneLockfileExecutor;
|
|
4
|
+
exports.resolveCatalogReferences = resolveCatalogReferences;
|
|
4
5
|
const devkit_1 = require("@nx/devkit");
|
|
6
|
+
const internal_1 = require("@nx/devkit/internal");
|
|
5
7
|
const fs_1 = require("fs");
|
|
6
8
|
const path_1 = require("path");
|
|
7
9
|
const utils_1 = require("nx/src/tasks-runner/utils");
|
|
@@ -13,7 +15,8 @@ const strip_glob_to_base_dir_1 = require("../../utils/strip-glob-to-base-dir");
|
|
|
13
15
|
async function pruneLockfileExecutor(schema, context) {
|
|
14
16
|
devkit_1.logger.log('Pruning lockfile...');
|
|
15
17
|
const outputDirectory = getOutputDir(schema, context);
|
|
16
|
-
const packageJson = getPackageJson(schema, context);
|
|
18
|
+
const packageJson = resolveCatalogReferences(getPackageJson(schema, context));
|
|
19
|
+
mergeAllowScripts(packageJson);
|
|
17
20
|
const packageManager = (0, devkit_1.detectPackageManager)(devkit_1.workspaceRoot);
|
|
18
21
|
if (packageManager === 'bun') {
|
|
19
22
|
devkit_1.logger.warn('Bun lockfile generation is not supported. Only package.json will be generated. Run "bun install" in the output directory if needed.');
|
|
@@ -48,6 +51,55 @@ function createPrunedLockfile(packageJson, graph) {
|
|
|
48
51
|
lockFile,
|
|
49
52
|
};
|
|
50
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* npm reads the `allowScripts` install-script allowlist only from the install
|
|
56
|
+
* root, but `npm approve-scripts` writes it to the workspace root, so it never
|
|
57
|
+
* lives in the project package.json the prune output is built from. Carry the
|
|
58
|
+
* root allowlist over, with project-level entries preserved and winning on
|
|
59
|
+
* conflict. Mirrors the `pnpm.allowBuilds` handling in createPackageJson.
|
|
60
|
+
*/
|
|
61
|
+
function mergeAllowScripts(packageJson) {
|
|
62
|
+
const rootPackageJson = (0, devkit_1.readJsonFile)((0, path_1.join)(devkit_1.workspaceRoot, 'package.json'));
|
|
63
|
+
if (!rootPackageJson.allowScripts) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
packageJson.allowScripts = {
|
|
67
|
+
...rootPackageJson.allowScripts,
|
|
68
|
+
...packageJson.allowScripts,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function resolveCatalogReferences(packageJson) {
|
|
72
|
+
const manager = (0, internal_1.getCatalogManager)(devkit_1.workspaceRoot);
|
|
73
|
+
if (!manager) {
|
|
74
|
+
return packageJson;
|
|
75
|
+
}
|
|
76
|
+
const sections = [
|
|
77
|
+
'dependencies',
|
|
78
|
+
'optionalDependencies',
|
|
79
|
+
'devDependencies',
|
|
80
|
+
'peerDependencies',
|
|
81
|
+
];
|
|
82
|
+
const resolved = { ...packageJson };
|
|
83
|
+
for (const section of sections) {
|
|
84
|
+
const deps = packageJson[section];
|
|
85
|
+
if (!deps) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const resolvedDeps = { ...deps };
|
|
89
|
+
for (const [packageName, version] of Object.entries(deps)) {
|
|
90
|
+
if (!manager.isCatalogReference(version)) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const resolvedVersion = manager.resolveCatalogReference(devkit_1.workspaceRoot, packageName, version);
|
|
94
|
+
if (!resolvedVersion) {
|
|
95
|
+
throw new Error(`Could not resolve catalog reference for package ${packageName}@${version}.`);
|
|
96
|
+
}
|
|
97
|
+
resolvedDeps[packageName] = resolvedVersion;
|
|
98
|
+
}
|
|
99
|
+
resolved[section] = resolvedDeps;
|
|
100
|
+
}
|
|
101
|
+
return resolved;
|
|
102
|
+
}
|
|
51
103
|
function getPackageJson(schema, context) {
|
|
52
104
|
const target = (0, devkit_1.parseTargetString)(schema.buildTarget, context);
|
|
53
105
|
const project = context.projectGraph.nodes[target.project].data;
|
|
@@ -55,8 +55,12 @@ function createTypeScriptCompilationOptions(normalizedOptions, context) {
|
|
|
55
55
|
outputPath: (0, devkit_1.joinPathFragments)(normalizedOptions.outputPath),
|
|
56
56
|
projectName: context.projectName,
|
|
57
57
|
projectRoot: normalizedOptions.projectRoot,
|
|
58
|
-
rootDir
|
|
59
|
-
|
|
58
|
+
// Keep the Windows drive letter on rootDir/tsConfig (only forward-slash them).
|
|
59
|
+
// joinPathFragments strips it via normalizePath, leaving them drive-less while
|
|
60
|
+
// the generated path mappings stay absolute drive-full, so alias-resolved files
|
|
61
|
+
// fail TypeScript's rootDir containment check (TS6059) on Windows.
|
|
62
|
+
rootDir: normalizedOptions.rootDir.replace(/\\/g, '/'),
|
|
63
|
+
tsConfig: normalizedOptions.tsConfig.replace(/\\/g, '/'),
|
|
60
64
|
watch: normalizedOptions.watch,
|
|
61
65
|
deleteOutputPath: normalizedOptions.clean,
|
|
62
66
|
getCustomTransformers: (0, lib_1.getCustomTrasformersFactory)(normalizedOptions.transformers),
|
|
@@ -249,7 +249,5 @@ function updatePackageJson(tree, projectName, projectRoot, main, outputPath, roo
|
|
|
249
249
|
function mergeTargetDefaults(tree, project, buildTarget) {
|
|
250
250
|
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
251
251
|
const projectTarget = project.targets[buildTarget];
|
|
252
|
-
return (0, devkit_internals_1.mergeTargetConfigurations)(projectTarget, (projectTarget.executor
|
|
253
|
-
? nxJson.targetDefaults?.[projectTarget.executor]
|
|
254
|
-
: undefined) ?? nxJson.targetDefaults?.[buildTarget]);
|
|
252
|
+
return (0, devkit_internals_1.mergeTargetConfigurations)(projectTarget, (0, internal_1.readTargetDefaultsForTarget)(buildTarget, nxJson.targetDefaults, projectTarget.executor));
|
|
255
253
|
}
|
|
@@ -35,30 +35,50 @@ async function default_1(tree) {
|
|
|
35
35
|
if (!nxJson.targetDefaults) {
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
delete targetConfig.options.external;
|
|
45
|
-
delete targetConfig.options.externalBuildTargets;
|
|
46
|
-
if (!Object.keys(targetConfig.options).length) {
|
|
47
|
-
delete targetConfig.options;
|
|
38
|
+
const cleanEntry = (entry) => {
|
|
39
|
+
if (entry.options) {
|
|
40
|
+
delete entry.options.external;
|
|
41
|
+
delete entry.options.externalBuildTargets;
|
|
42
|
+
if (!Object.keys(entry.options).length) {
|
|
43
|
+
delete entry.options;
|
|
48
44
|
}
|
|
49
45
|
}
|
|
50
|
-
Object.
|
|
46
|
+
Object.values(entry.configurations ?? {}).forEach((config) => {
|
|
51
47
|
delete config.external;
|
|
52
48
|
delete config.externalBuildTargets;
|
|
53
49
|
});
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
};
|
|
51
|
+
const targetDefaults = nxJson.targetDefaults;
|
|
52
|
+
for (const key of Object.keys(targetDefaults)) {
|
|
53
|
+
const value = targetDefaults[key];
|
|
54
|
+
const entries = Array.isArray(value)
|
|
55
|
+
? value
|
|
56
|
+
: [value];
|
|
57
|
+
const usesExecutor = (entry) => exports.executors.includes(key) ||
|
|
58
|
+
exports.executors.includes(entry.executor) ||
|
|
59
|
+
exports.executors.includes(entry.filter?.executor);
|
|
60
|
+
const kept = entries.filter((entry) => {
|
|
61
|
+
if (usesExecutor(entry)) {
|
|
62
|
+
cleanEntry(entry);
|
|
63
|
+
}
|
|
64
|
+
// Drop entries left with nothing but their `filter`/`executor` locator.
|
|
65
|
+
return Object.keys(entry).some((k) => k !== 'filter' && k !== 'executor');
|
|
66
|
+
});
|
|
67
|
+
if (kept.length === 0) {
|
|
68
|
+
delete targetDefaults[key];
|
|
58
69
|
}
|
|
59
|
-
if (
|
|
60
|
-
|
|
70
|
+
else if (kept.length === 1 && kept[0].filter === undefined) {
|
|
71
|
+
// A lone unfiltered entry is stored as the plain object form (which
|
|
72
|
+
// omits `filter`).
|
|
73
|
+
const { filter: _filter, ...config } = kept[0];
|
|
74
|
+
targetDefaults[key] = config;
|
|
61
75
|
}
|
|
76
|
+
else {
|
|
77
|
+
targetDefaults[key] = kept;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (Object.keys(targetDefaults).length === 0) {
|
|
81
|
+
delete nxJson.targetDefaults;
|
|
62
82
|
}
|
|
63
83
|
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
64
84
|
await (0, devkit_1.formatFiles)(tree);
|
|
@@ -1,28 +1,43 @@
|
|
|
1
1
|
import { type Tree } from '@nx/devkit';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Runs on TypeScript 6 workspaces (gated by `requires` in migrations.json) in
|
|
4
|
+
* two passes over every `tsconfig*.json`.
|
|
4
5
|
*
|
|
5
|
-
* 1
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* Pass 1 writes what pass 2's `extends` resolution reads back:
|
|
7
|
+
* - Default-preserving pins: on every chain root (no `extends`) that is not a
|
|
8
|
+
* pure solution container (`files: []` with no `include`), pin the TS6
|
|
9
|
+
* defaults that changed in a breaking way, but only where the root leaves
|
|
10
|
+
* them unset:
|
|
11
|
+
* - `strict: false`. TS6 treats an absent `strict` as true, TS5 as false.
|
|
12
|
+
* - `noUncheckedSideEffectImports: false`. TS6 defaults it true, turning a
|
|
13
|
+
* bare side-effect import of an asset without an ambient declaration
|
|
14
|
+
* (`import './styles.css'`) into a hard TS2882; a semantic diagnostic,
|
|
15
|
+
* not a deprecation, so `ignoreDeprecations` cannot silence it.
|
|
16
|
+
* - `types: ["*"]`. TS6 loads no @types when `types` is unset (TS5 loaded
|
|
17
|
+
* all); the wildcard restores that so a config relying on it (ts-node
|
|
18
|
+
* type-checking jest.config.ts) keeps finding @types/node.
|
|
19
|
+
* - `esModuleInterop: false`. TS6 flips the default false->true, changing
|
|
20
|
+
* `import * as x from '<cjs>'` call semantics at runtime; false preserves
|
|
21
|
+
* the pre-TS6 behavior. It is itself deprecated (removed in TS7), so pass
|
|
22
|
+
* 2 silences it, deferring the interop change to the eventual TS7 work.
|
|
23
|
+
* - Config-load flag: set `ignoreDeprecations: "6.0"` on every file named
|
|
24
|
+
* exactly `tsconfig.json`, the name jest/ts-node auto-resolve (walking up
|
|
25
|
+
* from the file they compile, such as jest.config.ts). ts-node injects a
|
|
26
|
+
* `target: es5` when the config leaves it unset, and es5 is a TS6-deprecated
|
|
27
|
+
* value (TS5107); the flag (which ts-node passes through) keeps that load
|
|
28
|
+
* silent. Set unconditionally, since any `tsconfig.json` is a potential
|
|
29
|
+
* loader target, and inert when nothing is deprecated. It cannot silence a
|
|
30
|
+
* module/moduleResolution mismatch (TS5110) when ts-node's forced
|
|
31
|
+
* `module: commonjs` meets an inherited `nodenext` resolution.
|
|
11
32
|
*
|
|
12
|
-
* 2
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* Files with "extends" inherit from their chain root and are left untouched.
|
|
22
|
-
* Pure solution-style containers (root has `"files": []` and no "include")
|
|
23
|
-
* select no source files, so pinning there is noise and they are skipped.
|
|
24
|
-
*
|
|
25
|
-
* Only runs on TS6 workspaces (gated by `requires` in migrations.json), because
|
|
26
|
-
* `ignoreDeprecations: "6.0"` is itself a hard error (TS5103) on TS 5.x.
|
|
33
|
+
* Pass 2 silences the remaining hard-deprecated values. For each config,
|
|
34
|
+
* TypeScript resolves its `extends`-merged compiler options; when they carry a
|
|
35
|
+
* value TS6 hard-deprecates (see `hasDeprecatedOption`) and their effective
|
|
36
|
+
* `ignoreDeprecations` is not already `"6.0"`, add the flag. Because the check
|
|
37
|
+
* runs on the merged options, it covers a value the config inherits from a base
|
|
38
|
+
* this migration never edits, respects an inherited `"6.0"` (no redundant flag),
|
|
39
|
+
* and upgrades a stale local `"5.0"` that overrides one. The
|
|
40
|
+
* `ts-node.compilerOptions` overlay, which `tsc` does not merge, is checked on
|
|
41
|
+
* its own.
|
|
27
42
|
*/
|
|
28
43
|
export default function (tree: Tree): Promise<void>;
|
|
@@ -4,192 +4,256 @@ exports.default = default_1;
|
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
5
|
const node_path_1 = require("node:path");
|
|
6
6
|
const jsonc_parser_1 = require("jsonc-parser");
|
|
7
|
+
const ensure_typescript_1 = require("../../utils/typescript/ensure-typescript");
|
|
7
8
|
const FORMATTING_OPTIONS = {
|
|
8
9
|
formattingOptions: { keepLines: true, insertSpaces: true, tabSize: 2 },
|
|
9
10
|
};
|
|
11
|
+
let tsModule;
|
|
10
12
|
/**
|
|
11
|
-
*
|
|
13
|
+
* Runs on TypeScript 6 workspaces (gated by `requires` in migrations.json) in
|
|
14
|
+
* two passes over every `tsconfig*.json`.
|
|
12
15
|
*
|
|
13
|
-
* 1
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* Pass 1 writes what pass 2's `extends` resolution reads back:
|
|
17
|
+
* - Default-preserving pins: on every chain root (no `extends`) that is not a
|
|
18
|
+
* pure solution container (`files: []` with no `include`), pin the TS6
|
|
19
|
+
* defaults that changed in a breaking way, but only where the root leaves
|
|
20
|
+
* them unset:
|
|
21
|
+
* - `strict: false`. TS6 treats an absent `strict` as true, TS5 as false.
|
|
22
|
+
* - `noUncheckedSideEffectImports: false`. TS6 defaults it true, turning a
|
|
23
|
+
* bare side-effect import of an asset without an ambient declaration
|
|
24
|
+
* (`import './styles.css'`) into a hard TS2882; a semantic diagnostic,
|
|
25
|
+
* not a deprecation, so `ignoreDeprecations` cannot silence it.
|
|
26
|
+
* - `types: ["*"]`. TS6 loads no @types when `types` is unset (TS5 loaded
|
|
27
|
+
* all); the wildcard restores that so a config relying on it (ts-node
|
|
28
|
+
* type-checking jest.config.ts) keeps finding @types/node.
|
|
29
|
+
* - `esModuleInterop: false`. TS6 flips the default false->true, changing
|
|
30
|
+
* `import * as x from '<cjs>'` call semantics at runtime; false preserves
|
|
31
|
+
* the pre-TS6 behavior. It is itself deprecated (removed in TS7), so pass
|
|
32
|
+
* 2 silences it, deferring the interop change to the eventual TS7 work.
|
|
33
|
+
* - Config-load flag: set `ignoreDeprecations: "6.0"` on every file named
|
|
34
|
+
* exactly `tsconfig.json`, the name jest/ts-node auto-resolve (walking up
|
|
35
|
+
* from the file they compile, such as jest.config.ts). ts-node injects a
|
|
36
|
+
* `target: es5` when the config leaves it unset, and es5 is a TS6-deprecated
|
|
37
|
+
* value (TS5107); the flag (which ts-node passes through) keeps that load
|
|
38
|
+
* silent. Set unconditionally, since any `tsconfig.json` is a potential
|
|
39
|
+
* loader target, and inert when nothing is deprecated. It cannot silence a
|
|
40
|
+
* module/moduleResolution mismatch (TS5110) when ts-node's forced
|
|
41
|
+
* `module: commonjs` meets an inherited `nodenext` resolution.
|
|
19
42
|
*
|
|
20
|
-
* 2
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* Files with "extends" inherit from their chain root and are left untouched.
|
|
30
|
-
* Pure solution-style containers (root has `"files": []` and no "include")
|
|
31
|
-
* select no source files, so pinning there is noise and they are skipped.
|
|
32
|
-
*
|
|
33
|
-
* Only runs on TS6 workspaces (gated by `requires` in migrations.json), because
|
|
34
|
-
* `ignoreDeprecations: "6.0"` is itself a hard error (TS5103) on TS 5.x.
|
|
43
|
+
* Pass 2 silences the remaining hard-deprecated values. For each config,
|
|
44
|
+
* TypeScript resolves its `extends`-merged compiler options; when they carry a
|
|
45
|
+
* value TS6 hard-deprecates (see `hasDeprecatedOption`) and their effective
|
|
46
|
+
* `ignoreDeprecations` is not already `"6.0"`, add the flag. Because the check
|
|
47
|
+
* runs on the merged options, it covers a value the config inherits from a base
|
|
48
|
+
* this migration never edits, respects an inherited `"6.0"` (no redundant flag),
|
|
49
|
+
* and upgrades a stale local `"5.0"` that overrides one. The
|
|
50
|
+
* `ts-node.compilerOptions` overlay, which `tsc` does not merge, is checked on
|
|
51
|
+
* its own.
|
|
35
52
|
*/
|
|
36
53
|
async function default_1(tree) {
|
|
37
|
-
|
|
54
|
+
tsModule ??= (0, ensure_typescript_1.ensureTypescript)();
|
|
55
|
+
const ts = tsModule;
|
|
56
|
+
// Tree-backed host so TypeScript resolves `extends` against pass 1's pending
|
|
57
|
+
// writes; the `readDirectory` no-op skips the source-file scan, since only the
|
|
58
|
+
// merged compiler options matter here, not the file list.
|
|
59
|
+
const parseHost = {
|
|
60
|
+
...ts.sys,
|
|
61
|
+
readFile: (filePath) => tree.read(filePath, 'utf-8') ?? undefined,
|
|
62
|
+
readDirectory: () => [],
|
|
63
|
+
};
|
|
64
|
+
const tsconfigPaths = await (0, devkit_1.globAsync)(tree, ['**/tsconfig*.json']);
|
|
65
|
+
// Pass 1: pins and config-load flags, so pass 2's inheritance check sees them.
|
|
38
66
|
let defaultsPinCount = 0;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
if (addIgnoreDeprecations(tree, filePath)) {
|
|
45
|
-
deprecationCount += 1;
|
|
46
|
-
}
|
|
47
|
-
if (pinPreTs6Defaults(tree, filePath)) {
|
|
67
|
+
let configLoadCount = 0;
|
|
68
|
+
for (const tsconfigPath of tsconfigPaths) {
|
|
69
|
+
const { pinned, flagged } = applyDefaultsAndConfigLoadFlag(tree, tsconfigPath);
|
|
70
|
+
if (pinned)
|
|
48
71
|
defaultsPinCount += 1;
|
|
72
|
+
if (flagged)
|
|
73
|
+
configLoadCount += 1;
|
|
74
|
+
}
|
|
75
|
+
// Pass 2: silence a deprecated value the config carries or inherits.
|
|
76
|
+
let deprecationCount = 0;
|
|
77
|
+
for (const tsconfigPath of tsconfigPaths) {
|
|
78
|
+
if (silenceDeprecations(tree, ts, parseHost, tsconfigPath)) {
|
|
79
|
+
deprecationCount += 1;
|
|
49
80
|
}
|
|
50
|
-
}
|
|
81
|
+
}
|
|
82
|
+
if (configLoadCount > 0) {
|
|
83
|
+
devkit_1.logger.info(`Ensured "ignoreDeprecations": "6.0" on ${configLoadCount} "tsconfig.json" file(s) so config loaders (jest/ts-node) keep working on TypeScript 6.`);
|
|
84
|
+
}
|
|
51
85
|
if (deprecationCount > 0) {
|
|
52
86
|
devkit_1.logger.info(`Added "ignoreDeprecations": "6.0" to ${deprecationCount} tsconfig file(s) carrying TS6-deprecated options.`);
|
|
53
87
|
}
|
|
54
88
|
if (defaultsPinCount > 0) {
|
|
55
|
-
devkit_1.logger.info(`Pinned pre-TS6 compiler option defaults ("strict", "noUncheckedSideEffectImports") on ${defaultsPinCount} tsconfig chain root(s)
|
|
89
|
+
devkit_1.logger.info(`Pinned pre-TS6 compiler option defaults ("strict", "noUncheckedSideEffectImports", "types", "esModuleInterop") on ${defaultsPinCount} tsconfig chain root(s).`);
|
|
56
90
|
}
|
|
57
91
|
await (0, devkit_1.formatFiles)(tree);
|
|
58
92
|
}
|
|
59
|
-
|
|
93
|
+
// The pre-TS6 default values pinned on chain roots that leave them unset; pass 1
|
|
94
|
+
// above explains why each one changed in a breaking way.
|
|
95
|
+
const DEFAULT_PRESERVING_PINS = [
|
|
96
|
+
['strict', false],
|
|
97
|
+
['noUncheckedSideEffectImports', false],
|
|
98
|
+
['types', ['*']],
|
|
99
|
+
['esModuleInterop', false],
|
|
100
|
+
];
|
|
101
|
+
// Pass 1 for one file: pin pre-TS6 defaults on a chain root and set the
|
|
102
|
+
// config-load flag on a `tsconfig.json`, combined into a single write.
|
|
103
|
+
function applyDefaultsAndConfigLoadFlag(tree, tsconfigPath) {
|
|
60
104
|
const original = tree.read(tsconfigPath, 'utf-8');
|
|
61
105
|
if (!original) {
|
|
106
|
+
return { pinned: false, flagged: false };
|
|
107
|
+
}
|
|
108
|
+
const root = (0, jsonc_parser_1.parseTree)(original);
|
|
109
|
+
if (!root || root.type !== 'object') {
|
|
110
|
+
return { pinned: false, flagged: false };
|
|
111
|
+
}
|
|
112
|
+
const own = (0, jsonc_parser_1.getNodeValue)(root);
|
|
113
|
+
const compilerOptions = own.compilerOptions;
|
|
114
|
+
// A present-but-non-object compilerOptions can't receive keys; leave the file
|
|
115
|
+
// alone so modify() doesn't throw and abort the whole migration.
|
|
116
|
+
if (compilerOptions !== undefined && !isObject(compilerOptions)) {
|
|
117
|
+
return { pinned: false, flagged: false };
|
|
118
|
+
}
|
|
119
|
+
const options = (compilerOptions ?? {});
|
|
120
|
+
let contents = original;
|
|
121
|
+
let pinned = false;
|
|
122
|
+
let flagged = false;
|
|
123
|
+
// Only chain roots; a file with "extends" inherits the defaults. Skip pure
|
|
124
|
+
// solution containers ("files": [] and no "include"): they select no sources.
|
|
125
|
+
const isSolutionContainer = Array.isArray(own.files) && own.files.length === 0 && !('include' in own);
|
|
126
|
+
if (own.extends === undefined && !isSolutionContainer) {
|
|
127
|
+
for (const [key, value] of DEFAULT_PRESERVING_PINS) {
|
|
128
|
+
if (key in options)
|
|
129
|
+
continue; // An explicit value means the user opted in.
|
|
130
|
+
contents = (0, jsonc_parser_1.applyEdits)(contents, (0, jsonc_parser_1.modify)(contents, ['compilerOptions', key], value, FORMATTING_OPTIONS));
|
|
131
|
+
pinned = true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if ((0, node_path_1.basename)(tsconfigPath) === 'tsconfig.json' &&
|
|
135
|
+
options.ignoreDeprecations !== '6.0') {
|
|
136
|
+
contents = (0, jsonc_parser_1.applyEdits)(contents, (0, jsonc_parser_1.modify)(contents, ['compilerOptions', 'ignoreDeprecations'], '6.0', FORMATTING_OPTIONS));
|
|
137
|
+
flagged = true;
|
|
138
|
+
}
|
|
139
|
+
if (pinned || flagged) {
|
|
140
|
+
tree.write(tsconfigPath, contents);
|
|
141
|
+
}
|
|
142
|
+
return { pinned, flagged };
|
|
143
|
+
}
|
|
144
|
+
// Pass 2 for one file: silence a deprecated value it carries or inherits, in the
|
|
145
|
+
// main block and the ts-node overlay, combined into a single write.
|
|
146
|
+
function silenceDeprecations(tree, ts, parseHost, tsconfigPath) {
|
|
147
|
+
const original = tree.read(tsconfigPath, 'utf-8');
|
|
148
|
+
if (!original) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
const root = (0, jsonc_parser_1.parseTree)(original);
|
|
152
|
+
if (!root || root.type !== 'object') {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
const own = (0, jsonc_parser_1.getNodeValue)(root);
|
|
156
|
+
const mainBlock = own.compilerOptions;
|
|
157
|
+
const mainIsObject = isObject(mainBlock);
|
|
158
|
+
const mainFlag = mainIsObject
|
|
159
|
+
? mainBlock.ignoreDeprecations
|
|
160
|
+
: undefined;
|
|
161
|
+
const tsNodeBlock = isObject(own['ts-node'])
|
|
162
|
+
? own['ts-node'].compilerOptions
|
|
163
|
+
: undefined;
|
|
164
|
+
const tsNodeIsObject = isObject(tsNodeBlock);
|
|
165
|
+
const tsNodeFlag = tsNodeIsObject
|
|
166
|
+
? tsNodeBlock.ignoreDeprecations
|
|
167
|
+
: undefined;
|
|
168
|
+
// No own options and no `extends` to inherit through, and no overlay to check:
|
|
169
|
+
// nothing can be deprecated here, so skip without parsing.
|
|
170
|
+
if (!mainIsObject && own.extends === undefined && !tsNodeIsObject) {
|
|
62
171
|
return false;
|
|
63
172
|
}
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
173
|
+
// Main is already silenced and there is no overlay: nothing to do, skip the
|
|
174
|
+
// parse entirely (the common case for a config-load-flagged `tsconfig.json`).
|
|
175
|
+
if (mainFlag === '6.0' && !tsNodeIsObject) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
// The `extends`-merged main options, normalized by TypeScript. Passing the
|
|
179
|
+
// config object (not the path) keeps TypeScript from re-reading this file; it
|
|
180
|
+
// reads only the ancestors.
|
|
181
|
+
const mainOptions = ts.parseJsonConfigFileContent({ extends: own.extends, compilerOptions: mainIsObject ? mainBlock : {} }, parseHost, (0, node_path_1.dirname)(tsconfigPath)).options;
|
|
182
|
+
const mainDeprecated = hasDeprecatedOption(ts, mainOptions);
|
|
69
183
|
let contents = original;
|
|
70
184
|
let changed = false;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
// An existing non-"6.0" value (e.g. "5.0") does NOT silence 6.0-class
|
|
83
|
-
// deprecations, so upgrade it; only "6.0" is already correct.
|
|
84
|
-
if (compilerOptions.ignoreDeprecations === '6.0') {
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
const edits = (0, jsonc_parser_1.modify)(contents, [...blockPath, 'ignoreDeprecations'], '6.0', FORMATTING_OPTIONS);
|
|
88
|
-
contents = (0, jsonc_parser_1.applyEdits)(contents, edits);
|
|
185
|
+
// Main block: silence a deprecated value it carries or inherits, unless an
|
|
186
|
+
// effective "6.0" (own or inherited) already covers it. A stale local "5.0"
|
|
187
|
+
// that overrides an inherited "6.0" shows through the merge and is upgraded.
|
|
188
|
+
// An absent block is created; a present-but-non-object one is left alone so
|
|
189
|
+
// modify() neither corrupts it nor throws.
|
|
190
|
+
const mainWritable = mainBlock === undefined || mainIsObject;
|
|
191
|
+
if (mainWritable &&
|
|
192
|
+
mainFlag !== '6.0' &&
|
|
193
|
+
mainDeprecated &&
|
|
194
|
+
mainOptions.ignoreDeprecations !== '6.0') {
|
|
195
|
+
contents = (0, jsonc_parser_1.applyEdits)(contents, (0, jsonc_parser_1.modify)(contents, ['compilerOptions', 'ignoreDeprecations'], '6.0', FORMATTING_OPTIONS));
|
|
89
196
|
changed = true;
|
|
90
197
|
}
|
|
198
|
+
// ts-node overlay: `tsc` does not merge it, so check it directly. ts-node
|
|
199
|
+
// overlays the resolved main options at runtime; a "6.0" the main block just
|
|
200
|
+
// received does not reliably reach the overlay across ts-node versions, so
|
|
201
|
+
// silence it on its own whenever it or the resolved main carries a deprecated
|
|
202
|
+
// value.
|
|
203
|
+
if (tsNodeIsObject && tsNodeFlag !== '6.0') {
|
|
204
|
+
const overlayOptions = ts.parseJsonConfigFileContent({ compilerOptions: tsNodeBlock }, parseHost, (0, node_path_1.dirname)(tsconfigPath)).options;
|
|
205
|
+
if (hasDeprecatedOption(ts, overlayOptions) || mainDeprecated) {
|
|
206
|
+
contents = (0, jsonc_parser_1.applyEdits)(contents, (0, jsonc_parser_1.modify)(contents, ['ts-node', 'compilerOptions', 'ignoreDeprecations'], '6.0', FORMATTING_OPTIONS));
|
|
207
|
+
changed = true;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
91
210
|
if (changed) {
|
|
92
211
|
tree.write(tsconfigPath, contents);
|
|
93
212
|
}
|
|
94
213
|
return changed;
|
|
95
214
|
}
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
215
|
+
// Whether TypeScript-parsed, `extends`-merged compiler options carry a value
|
|
216
|
+
// that compiles silently on TS 5.8 but is a hard deprecation error (TS5101/
|
|
217
|
+
// TS5107) on TS 6.0, derived by differential 5.8-vs-6.0 probing. Options are
|
|
218
|
+
// read from the normalized enums TypeScript produces; an unset option stays
|
|
219
|
+
// undefined (TypeScript does not fill in the module-derived `moduleResolution`
|
|
220
|
+
// default here), so an implied resolution is not misread as deprecated.
|
|
221
|
+
function hasDeprecatedOption(ts, options) {
|
|
222
|
+
const moduleResolution = options.moduleResolution;
|
|
223
|
+
if (moduleResolution === ts.ModuleResolutionKind.Node10 ||
|
|
224
|
+
moduleResolution === ts.ModuleResolutionKind.Classic) {
|
|
103
225
|
return true;
|
|
104
226
|
}
|
|
105
|
-
|
|
106
|
-
// is inert on TS6.
|
|
107
|
-
if (compilerOptions.baseUrl != null) {
|
|
227
|
+
if (options.baseUrl != null) {
|
|
108
228
|
return true;
|
|
109
229
|
}
|
|
110
|
-
if (
|
|
230
|
+
if (options.target === ts.ScriptTarget.ES5) {
|
|
111
231
|
return true;
|
|
112
232
|
}
|
|
113
|
-
if (
|
|
233
|
+
if (options.esModuleInterop === false) {
|
|
114
234
|
return true;
|
|
115
235
|
}
|
|
116
|
-
if (
|
|
236
|
+
if (options.outFile != null) {
|
|
117
237
|
return true;
|
|
118
238
|
}
|
|
119
|
-
const
|
|
120
|
-
if (
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
239
|
+
const module = options.module;
|
|
240
|
+
if (module === ts.ModuleKind.AMD ||
|
|
241
|
+
module === ts.ModuleKind.UMD ||
|
|
242
|
+
module === ts.ModuleKind.System ||
|
|
243
|
+
module === ts.ModuleKind.None) {
|
|
124
244
|
return true;
|
|
125
245
|
}
|
|
126
|
-
|
|
127
|
-
if (compilerOptions.alwaysStrict === false) {
|
|
246
|
+
if (options.alwaysStrict === false) {
|
|
128
247
|
return true;
|
|
129
248
|
}
|
|
130
|
-
if (
|
|
249
|
+
if (options.allowSyntheticDefaultImports === false) {
|
|
131
250
|
return true;
|
|
132
251
|
}
|
|
133
|
-
|
|
134
|
-
// non-boolean JSON, but that only adds a harmless no-op `ignoreDeprecations`.
|
|
135
|
-
if (compilerOptions.downlevelIteration != null) {
|
|
252
|
+
if (options.downlevelIteration != null) {
|
|
136
253
|
return true;
|
|
137
254
|
}
|
|
138
255
|
return false;
|
|
139
256
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
// workspaces keep building without adopting a legit TS6 setup.
|
|
143
|
-
const DEFAULT_PRESERVING_PINS = [
|
|
144
|
-
['strict', false],
|
|
145
|
-
['noUncheckedSideEffectImports', false],
|
|
146
|
-
];
|
|
147
|
-
function pinPreTs6Defaults(tree, tsconfigPath) {
|
|
148
|
-
const original = tree.read(tsconfigPath, 'utf-8');
|
|
149
|
-
if (!original) {
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
const root = (0, jsonc_parser_1.parseTree)(original);
|
|
153
|
-
if (!root || root.type !== 'object') {
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
const rootValue = (0, jsonc_parser_1.getNodeValue)(root);
|
|
157
|
-
// Only touch chain roots - files with "extends" inherit from their ancestor.
|
|
158
|
-
if ('extends' in rootValue) {
|
|
159
|
-
return false;
|
|
160
|
-
}
|
|
161
|
-
// Skip pure solution-style containers: root has "files": [] and no "include".
|
|
162
|
-
// They select no source files, so pinning defaults there is noise.
|
|
163
|
-
const filesNode = (0, jsonc_parser_1.findNodeAtLocation)(root, ['files']);
|
|
164
|
-
const hasEmptyFiles = filesNode?.type === 'array' && filesNode.children?.length === 0;
|
|
165
|
-
if (hasEmptyFiles && !('include' in rootValue)) {
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
const compilerOptionsNode = (0, jsonc_parser_1.findNodeAtLocation)(root, ['compilerOptions']);
|
|
169
|
-
// A present-but-non-object compilerOptions can't receive pinned keys; bailing
|
|
170
|
-
// avoids modify() throwing and aborting the whole migration.
|
|
171
|
-
if (compilerOptionsNode && compilerOptionsNode.type !== 'object') {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
const compilerOptions = compilerOptionsNode
|
|
175
|
-
? (0, jsonc_parser_1.getNodeValue)(compilerOptionsNode)
|
|
176
|
-
: {};
|
|
177
|
-
let contents = original;
|
|
178
|
-
let changed = false;
|
|
179
|
-
for (const [key, value] of DEFAULT_PRESERVING_PINS) {
|
|
180
|
-
// An explicit value (true or false) means the user opted in - leave it.
|
|
181
|
-
if (key in compilerOptions) {
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
const edits = (0, jsonc_parser_1.modify)(contents, ['compilerOptions', key], value, FORMATTING_OPTIONS);
|
|
185
|
-
contents = (0, jsonc_parser_1.applyEdits)(contents, edits);
|
|
186
|
-
changed = true;
|
|
187
|
-
}
|
|
188
|
-
if (changed) {
|
|
189
|
-
tree.write(tsconfigPath, contents);
|
|
190
|
-
}
|
|
191
|
-
return changed;
|
|
192
|
-
}
|
|
193
|
-
function asLowerString(value) {
|
|
194
|
-
return typeof value === 'string' ? value.toLowerCase() : undefined;
|
|
257
|
+
function isObject(value) {
|
|
258
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
195
259
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#### Keep Existing Workspaces Compiling on TypeScript 6
|
|
2
2
|
|
|
3
|
-
TypeScript 6 turns several long-deprecated compiler options into hard errors and flips a few option defaults to stricter values. So that an existing workspace keeps compiling on TypeScript 6 without being migrated to a full TypeScript 6 setup, this migration
|
|
3
|
+
TypeScript 6 turns several long-deprecated compiler options into hard errors and flips a few option defaults to stricter values. So that an existing workspace keeps compiling on TypeScript 6 without being migrated to a full TypeScript 6 setup, this migration edits the `tsconfig*.json` files in the workspace:
|
|
4
4
|
|
|
5
|
-
- Adds `"ignoreDeprecations": "6.0"` to any `compilerOptions` (or `ts-node.compilerOptions`) block
|
|
6
|
-
- Pins `"strict": false` and `"
|
|
5
|
+
- Adds `"ignoreDeprecations": "6.0"` to any `compilerOptions` (or `ts-node.compilerOptions`) block whose effective options carry a TypeScript 6 deprecated option, set directly or inherited through `extends` (including from a base this migration does not edit, such as a package-provided config). Examples: `moduleResolution` set to `node`/`node10`/`classic`, `baseUrl`, `target` set to `es5`, `esModuleInterop: false`, `outFile`, `module` set to `amd`/`umd`/`system`/`none`, `alwaysStrict: false`, `allowSyntheticDefaultImports: false`, or `downlevelIteration`. A block that already inherits an effective `"6.0"` and sets no local value is left alone; a stale local value such as `"5.0"` is upgraded to `"6.0"`, since it would otherwise override the inherited flag and still error.
|
|
6
|
+
- Pins `"strict": false`, `"noUncheckedSideEffectImports": false`, `"types": ["*"]`, and `"esModuleInterop": false` on every chain-root tsconfig (one without an `extends`) that does not already set them. TypeScript 6 treats an absent `strict` as `true` (it was `false` when unset before), defaults `noUncheckedSideEffectImports` to `true` (which turns a bare side-effect import such as `import './styles.css'` without an ambient module declaration into an error), no longer auto-loads every `@types` package when `types` is unset the way TypeScript 5 did (the `"*"` wildcard restores that last default), and flips `esModuleInterop` from `false` to `true` (so an `import * as x from '<cjs>'` binds a non-callable namespace object and a call or `new` on that import fails at runtime). Pinning all four preserves the pre-TypeScript 6 behavior. Because `esModuleInterop: false` is itself a TypeScript 6 deprecated value, this pin runs before the `ignoreDeprecations` edit above, so the added `false` is silenced in the same run.
|
|
7
|
+
- Adds `"ignoreDeprecations": "6.0"` to every `tsconfig.json` (the exact file name jest and ts-node auto-resolve), even one that carries no deprecated option of its own. Those loaders compile config files such as `jest.config.ts`, and ts-node injects a default `target: es5` when the config leaves it unset. TypeScript 6 rejects `es5` as a deprecated value, so the flag keeps that load working. It is inert wherever nothing is actually deprecated.
|
|
7
8
|
|
|
8
|
-
Files that use `extends` inherit
|
|
9
|
+
Files that use `extends` inherit the pinned settings from their chain root, so the pins are not repeated on them, and pure solution-style tsconfigs (`"files": []` with no `include`) receive no pins either, though a solution-style `tsconfig.json` still gets the config-load flag. The migration only runs when the workspace is on TypeScript 6.
|
|
9
10
|
|
|
10
11
|
#### Sample Code Changes
|
|
11
12
|
|
|
@@ -23,15 +24,17 @@ Files that use `extends` inherit these settings from their chain root and are le
|
|
|
23
24
|
|
|
24
25
|
##### After
|
|
25
26
|
|
|
26
|
-
```json title="tsconfig.json" {6-
|
|
27
|
+
```json title="tsconfig.json" {6-10}
|
|
27
28
|
{
|
|
28
29
|
"compilerOptions": {
|
|
29
30
|
"target": "es5",
|
|
30
31
|
"module": "esnext",
|
|
31
32
|
"moduleResolution": "bundler",
|
|
32
|
-
"ignoreDeprecations": "6.0",
|
|
33
33
|
"strict": false,
|
|
34
|
-
"noUncheckedSideEffectImports": false
|
|
34
|
+
"noUncheckedSideEffectImports": false,
|
|
35
|
+
"types": ["*"],
|
|
36
|
+
"esModuleInterop": false,
|
|
37
|
+
"ignoreDeprecations": "6.0"
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Tree } from '@nx/devkit';
|
|
2
|
+
/**
|
|
3
|
+
* TypeScript 6.0 changed the implicit `rootDir`. Before 6.0 an unset `rootDir`
|
|
4
|
+
* was inferred as the common directory of a program's non-declaration input
|
|
5
|
+
* files; 6.0 defaults it to the tsconfig's own directory instead. A program
|
|
6
|
+
* whose files resolve outside that directory (most commonly a spec/e2e tsconfig
|
|
7
|
+
* importing another project's source through a `paths` alias) then hard-fails
|
|
8
|
+
* with TS5011 or TS6059.
|
|
9
|
+
*
|
|
10
|
+
* For every project `tsconfig*.json` that lacks an explicit `rootDir`, this pins
|
|
11
|
+
* `rootDir` to exactly the directory TypeScript 5 would have inferred, so both
|
|
12
|
+
* compilation and emit layout are unchanged under 6.0. The value is computed by
|
|
13
|
+
* the compiler itself: a throwaway program built with `configFilePath` cleared
|
|
14
|
+
* takes the file-derived branch of `getCommonSourceDirectory`, so it matches
|
|
15
|
+
* `tsc` exactly, including project-reference redirects. Configs already at the
|
|
16
|
+
* 6.0 default are left untouched: their inferred directory equals the tsconfig
|
|
17
|
+
* directory, or they are composite (which defaulted there before 6.0 too).
|
|
18
|
+
*
|
|
19
|
+
* Each config is written on its own; nothing is written to a shared `extends`
|
|
20
|
+
* base, so a config never inherits a `rootDir` computed for a sibling. The one
|
|
21
|
+
* case that needs care is a config that both needs a `rootDir` and is itself an
|
|
22
|
+
* `extends` base: its own-directory children would inherit the new value and
|
|
23
|
+
* shift their emit layout, so each such child is pinned to its own directory to
|
|
24
|
+
* block it. Runs only on TypeScript 6 workspaces (gated by `requires`).
|
|
25
|
+
*/
|
|
26
|
+
export default function (tree: Tree): Promise<void>;
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = default_1;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const jsonc_parser_1 = require("jsonc-parser");
|
|
7
|
+
const ensure_typescript_1 = require("../../utils/typescript/ensure-typescript");
|
|
8
|
+
const FORMATTING_OPTIONS = {
|
|
9
|
+
formattingOptions: { keepLines: true, insertSpaces: true, tabSize: 2 },
|
|
10
|
+
};
|
|
11
|
+
let tsModule;
|
|
12
|
+
/**
|
|
13
|
+
* TypeScript 6.0 changed the implicit `rootDir`. Before 6.0 an unset `rootDir`
|
|
14
|
+
* was inferred as the common directory of a program's non-declaration input
|
|
15
|
+
* files; 6.0 defaults it to the tsconfig's own directory instead. A program
|
|
16
|
+
* whose files resolve outside that directory (most commonly a spec/e2e tsconfig
|
|
17
|
+
* importing another project's source through a `paths` alias) then hard-fails
|
|
18
|
+
* with TS5011 or TS6059.
|
|
19
|
+
*
|
|
20
|
+
* For every project `tsconfig*.json` that lacks an explicit `rootDir`, this pins
|
|
21
|
+
* `rootDir` to exactly the directory TypeScript 5 would have inferred, so both
|
|
22
|
+
* compilation and emit layout are unchanged under 6.0. The value is computed by
|
|
23
|
+
* the compiler itself: a throwaway program built with `configFilePath` cleared
|
|
24
|
+
* takes the file-derived branch of `getCommonSourceDirectory`, so it matches
|
|
25
|
+
* `tsc` exactly, including project-reference redirects. Configs already at the
|
|
26
|
+
* 6.0 default are left untouched: their inferred directory equals the tsconfig
|
|
27
|
+
* directory, or they are composite (which defaulted there before 6.0 too).
|
|
28
|
+
*
|
|
29
|
+
* Each config is written on its own; nothing is written to a shared `extends`
|
|
30
|
+
* base, so a config never inherits a `rootDir` computed for a sibling. The one
|
|
31
|
+
* case that needs care is a config that both needs a `rootDir` and is itself an
|
|
32
|
+
* `extends` base: its own-directory children would inherit the new value and
|
|
33
|
+
* shift their emit layout, so each such child is pinned to its own directory to
|
|
34
|
+
* block it. Runs only on TypeScript 6 workspaces (gated by `requires`).
|
|
35
|
+
*/
|
|
36
|
+
async function default_1(tree) {
|
|
37
|
+
tsModule ??= (0, ensure_typescript_1.ensureTypescript)();
|
|
38
|
+
const ts = tsModule;
|
|
39
|
+
const parseConfigHost = {
|
|
40
|
+
...ts.sys,
|
|
41
|
+
onUnRecoverableConfigFileDiagnostic: () => { },
|
|
42
|
+
};
|
|
43
|
+
const relPaths = collectProjectTsconfigs(tree);
|
|
44
|
+
// Phase 1: analyze every candidate against the on-disk configs.
|
|
45
|
+
const candidates = relPaths.map((relPath) => {
|
|
46
|
+
const absPath = toPosix((0, node_path_1.join)(tree.root, relPath));
|
|
47
|
+
return {
|
|
48
|
+
relPath,
|
|
49
|
+
dirAbs: toPosix((0, node_path_1.dirname)(absPath)),
|
|
50
|
+
analysis: analyze(ts, absPath, parseConfigHost),
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
// Phase 2: pin each config that needs a `rootDir` on its own.
|
|
54
|
+
let changed = 0;
|
|
55
|
+
for (const c of candidates) {
|
|
56
|
+
if (c.analysis.kind === 'write') {
|
|
57
|
+
const rootDir = toRelativeRootDir(c.dirAbs, c.analysis.dirAbs);
|
|
58
|
+
if (setRootDir(tree, c.relPath, rootDir)) {
|
|
59
|
+
changed++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Phase 3: shield own-dir configs that now inherit a pinned `rootDir` from a
|
|
64
|
+
// base. Re-parse each from the tree (so Phase 2's writes are visible); when
|
|
65
|
+
// TypeScript reports an inherited `rootDir` where there was none, pin the
|
|
66
|
+
// config to its own directory so its emit layout does not shift. Repeat until
|
|
67
|
+
// stable, since shielding one config can turn it into a base for another. The
|
|
68
|
+
// tree-backed host lets TypeScript resolve `extends`; the `readDirectory`
|
|
69
|
+
// no-op skips the unused file scan.
|
|
70
|
+
const readFile = (filePath) => tree.read(filePath, 'utf-8') ?? undefined;
|
|
71
|
+
const treeParseHost = {
|
|
72
|
+
...ts.sys,
|
|
73
|
+
readFile,
|
|
74
|
+
readDirectory: () => [],
|
|
75
|
+
};
|
|
76
|
+
const shielded = new Set();
|
|
77
|
+
let added = true;
|
|
78
|
+
while (added) {
|
|
79
|
+
added = false;
|
|
80
|
+
for (const c of candidates) {
|
|
81
|
+
if (c.analysis.kind !== 'own-dir' || shielded.has(c.relPath)) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (inheritsRootDir(ts, treeParseHost, readFile, c.relPath)) {
|
|
85
|
+
if (setRootDir(tree, c.relPath, '.')) {
|
|
86
|
+
changed++;
|
|
87
|
+
}
|
|
88
|
+
shielded.add(c.relPath);
|
|
89
|
+
added = true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (changed > 0) {
|
|
94
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function analyze(ts, absPath, parseConfigHost) {
|
|
98
|
+
const parsed = ts.getParsedCommandLineOfConfigFile(absPath, undefined, parseConfigHost);
|
|
99
|
+
if (!parsed) {
|
|
100
|
+
return { kind: 'inert' };
|
|
101
|
+
}
|
|
102
|
+
const { options, fileNames, projectReferences } = parsed;
|
|
103
|
+
if (options.rootDir != null) {
|
|
104
|
+
return { kind: 'has-rootDir' };
|
|
105
|
+
}
|
|
106
|
+
if (!setsEmitGate(options) || fileNames.length === 0) {
|
|
107
|
+
return { kind: 'inert' };
|
|
108
|
+
}
|
|
109
|
+
// Composite already defaults `rootDir` to the tsconfig's own directory in both
|
|
110
|
+
// 5.x and 6.0, so the 6.0 change leaves it alone. Treat it as own-dir: never
|
|
111
|
+
// pin a file-derived value, and shield it from a `rootDir` this migration pins
|
|
112
|
+
// on an `extends` base.
|
|
113
|
+
if (options.composite) {
|
|
114
|
+
return { kind: 'own-dir' };
|
|
115
|
+
}
|
|
116
|
+
const commonDir = computeCommonSourceDirectory(ts, fileNames, options, projectReferences);
|
|
117
|
+
if (!commonDir) {
|
|
118
|
+
return { kind: 'inert' };
|
|
119
|
+
}
|
|
120
|
+
if (equalPaths(ts, commonDir, (0, node_path_1.dirname)(absPath))) {
|
|
121
|
+
return { kind: 'own-dir' };
|
|
122
|
+
}
|
|
123
|
+
return { kind: 'write', dirAbs: toPosix(commonDir).replace(/\/+$/, '') };
|
|
124
|
+
}
|
|
125
|
+
// True when TypeScript resolves an inherited `rootDir` for the config. An own-dir
|
|
126
|
+
// config sets none of its own, so any `rootDir` reported here comes from a base
|
|
127
|
+
// this migration just pinned, and inheriting it would shift the config's emit
|
|
128
|
+
// layout.
|
|
129
|
+
function inheritsRootDir(ts, parseHost, readFile, relPath) {
|
|
130
|
+
const config = ts.readConfigFile(relPath, readFile).config;
|
|
131
|
+
if (!config) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
const { options } = ts.parseJsonConfigFileContent(config, parseHost, (0, node_path_1.dirname)(relPath));
|
|
135
|
+
return options.rootDir != null;
|
|
136
|
+
}
|
|
137
|
+
// Any of these makes TypeScript run the source-file containment / common-source
|
|
138
|
+
// computation that emits TS5011 / TS6059 when `rootDir` is absent.
|
|
139
|
+
function setsEmitGate(o) {
|
|
140
|
+
return !!(o.outDir ||
|
|
141
|
+
o.outFile ||
|
|
142
|
+
o.sourceRoot ||
|
|
143
|
+
o.mapRoot ||
|
|
144
|
+
(o.declaration && o.declarationDir));
|
|
145
|
+
}
|
|
146
|
+
function computeCommonSourceDirectory(ts, rootNames, parsedOptions, projectReferences) {
|
|
147
|
+
// Clearing `configFilePath` makes `getCommonSourceDirectory` take the
|
|
148
|
+
// file-derived branch (the pre-6.0 inference) instead of returning the
|
|
149
|
+
// tsconfig's own directory. `noLib` skips lib.d.ts (declarations, irrelevant
|
|
150
|
+
// to the calc). `projectReferences` preserves reference-redirect semantics, so
|
|
151
|
+
// a source file provided by a referenced project is excluded via its `.d.ts`.
|
|
152
|
+
const options = {
|
|
153
|
+
...parsedOptions,
|
|
154
|
+
noLib: true,
|
|
155
|
+
configFilePath: undefined,
|
|
156
|
+
};
|
|
157
|
+
// A fresh host per program so each config resolves on its own, with no parse or
|
|
158
|
+
// module-resolution state shared across configs. Letting the program resolve
|
|
159
|
+
// modules itself (no custom `resolveModuleNameLiterals`) keeps resolution
|
|
160
|
+
// mode-aware under node16/nodenext/bundler, matching tsc.
|
|
161
|
+
const host = ts.createCompilerHost(options, /* setParentNodes */ false);
|
|
162
|
+
const program = ts.createProgram({
|
|
163
|
+
rootNames,
|
|
164
|
+
options,
|
|
165
|
+
host,
|
|
166
|
+
projectReferences,
|
|
167
|
+
});
|
|
168
|
+
// `getCommonSourceDirectory` is a real Program method but is absent from the
|
|
169
|
+
// public `Program` type, so widen it here.
|
|
170
|
+
const commonSourceDirectory = program.getCommonSourceDirectory();
|
|
171
|
+
return commonSourceDirectory || undefined;
|
|
172
|
+
}
|
|
173
|
+
function collectProjectTsconfigs(tree) {
|
|
174
|
+
const projectRoots = [...(0, devkit_1.getProjects)(tree).values()].map((p) => p.root === '.' ? '' : p.root);
|
|
175
|
+
const tsconfigs = [];
|
|
176
|
+
(0, devkit_1.visitNotIgnoredFiles)(tree, '.', (filePath) => {
|
|
177
|
+
const name = (0, node_path_1.basename)(filePath);
|
|
178
|
+
if (!name.startsWith('tsconfig') || !name.endsWith('.json')) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const normalized = toPosix(filePath);
|
|
182
|
+
// Only touch tsconfigs owned by a project; never a workspace-root base
|
|
183
|
+
// whose (unknown) extenders we would silently affect.
|
|
184
|
+
if (projectRoots.some((root) => root === '' || normalized.startsWith(`${root}/`))) {
|
|
185
|
+
tsconfigs.push(filePath);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
return tsconfigs;
|
|
189
|
+
}
|
|
190
|
+
function setRootDir(tree, tsconfigPath, rootDir) {
|
|
191
|
+
const contents = tree.read(tsconfigPath, 'utf-8');
|
|
192
|
+
if (!contents) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
const edits = (0, jsonc_parser_1.modify)(contents, ['compilerOptions', 'rootDir'], rootDir, FORMATTING_OPTIONS);
|
|
196
|
+
if (edits.length === 0) {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
tree.write(tsconfigPath, (0, jsonc_parser_1.applyEdits)(contents, edits));
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
function toRelativeRootDir(tsconfigDir, commonDir) {
|
|
203
|
+
const rel = node_path_1.posix.relative(toPosix(tsconfigDir), toPosix(commonDir));
|
|
204
|
+
return rel === '' ? '.' : rel;
|
|
205
|
+
}
|
|
206
|
+
function equalPaths(ts, a, b) {
|
|
207
|
+
const normalize = (p) => {
|
|
208
|
+
const stripped = toPosix(p).replace(/\/+$/, '');
|
|
209
|
+
return ts.sys.useCaseSensitiveFileNames ? stripped : stripped.toLowerCase();
|
|
210
|
+
};
|
|
211
|
+
return normalize(a) === normalize(b);
|
|
212
|
+
}
|
|
213
|
+
function toPosix(p) {
|
|
214
|
+
return p.split('\\').join('/');
|
|
215
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#### Pin the Inferred `rootDir` for TypeScript 6
|
|
2
|
+
|
|
3
|
+
Before TypeScript 6, a tsconfig that did not set `rootDir` had it inferred as the common directory of the program's non-declaration input files. TypeScript 6 changed that default to the tsconfig's own directory. A program whose files resolve outside that directory (most commonly a spec or e2e tsconfig that imports another project's source through a `paths` alias) now hard-fails with `TS5011` or `TS6059` because a file falls outside the assumed root.
|
|
4
|
+
|
|
5
|
+
For every project `tsconfig*.json` that does not already set `rootDir` (directly or through `extends`), this migration pins `rootDir` to exactly the directory TypeScript 5 would have inferred, so both compilation and emit layout stay the same under TypeScript 6. The value is computed by the TypeScript compiler itself, so it matches `tsc` exactly, including project-reference redirects. Configs that cannot hit the error are skipped: ones without an output option (`outDir`, `outFile`, `sourceRoot`, `mapRoot`, or `declaration` + `declarationDir`), ones with no input files, composite projects (whose `rootDir` already defaulted to the tsconfig directory before TypeScript 6), and ones whose inferred directory already equals the tsconfig directory. The migration only runs when the workspace is on TypeScript 6.
|
|
6
|
+
|
|
7
|
+
Each config is updated on its own; the migration never writes `rootDir` to a shared `extends` base, so a config never inherits a value computed for a sibling. The one case that needs care is a config that both needs a `rootDir` and is itself an `extends` base: its self-contained children would inherit the new value and emit to the wrong place, so each such child is pinned to its own directory to keep its layout. This includes a composite child, whose own-directory default would otherwise be overridden by the inherited value.
|
|
8
|
+
|
|
9
|
+
#### Sample Code Changes
|
|
10
|
+
|
|
11
|
+
##### Before
|
|
12
|
+
|
|
13
|
+
A `libs/products/e2e/tsconfig.json` whose specs import a shared library's source:
|
|
14
|
+
|
|
15
|
+
```json title="libs/products/e2e/tsconfig.json"
|
|
16
|
+
{
|
|
17
|
+
"extends": "../../../tsconfig.base.json",
|
|
18
|
+
"compilerOptions": {
|
|
19
|
+
"outDir": "../../../dist/out-tsc"
|
|
20
|
+
},
|
|
21
|
+
"include": ["src/**/*.ts"]
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
##### After
|
|
26
|
+
|
|
27
|
+
```json title="libs/products/e2e/tsconfig.json" {4}
|
|
28
|
+
{
|
|
29
|
+
"extends": "../../../tsconfig.base.json",
|
|
30
|
+
"compilerOptions": {
|
|
31
|
+
"rootDir": "../../..",
|
|
32
|
+
"outDir": "../../../dist/out-tsc"
|
|
33
|
+
},
|
|
34
|
+
"include": ["src/**/*.ts"]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
@@ -282,7 +282,15 @@ function updatePaths(dependencies, paths) {
|
|
|
282
282
|
const { root } = dep.node.data;
|
|
283
283
|
// Update nested mappings to point to the dependency's output paths
|
|
284
284
|
mappedPaths = mappedPaths.concat(paths[path].flatMap((p) => dep.outputs.flatMap((output) => {
|
|
285
|
-
|
|
285
|
+
// Re-map the root prefix to the output. Match root only as a
|
|
286
|
+
// leading segment (after an optional `./`) so a root that
|
|
287
|
+
// also appears later in the value (e.g. output `dist/libs/base`
|
|
288
|
+
// for root `base`) isn't doubled.
|
|
289
|
+
const dotPrefix = p.startsWith('./') ? './' : '';
|
|
290
|
+
const value = dotPrefix ? p.slice(2) : p;
|
|
291
|
+
const basePath = value === root || value.startsWith(`${root}/`)
|
|
292
|
+
? `${dotPrefix}${output}${value.slice(root.length)}`
|
|
293
|
+
: p;
|
|
286
294
|
return [
|
|
287
295
|
// extension-less path to support compiled output
|
|
288
296
|
basePath.replace(new RegExp(`${(0, path_1.extname)(basePath)}$`, 'gi'), ''),
|
|
@@ -5,14 +5,23 @@ exports.generatePrettierSetup = generatePrettierSetup;
|
|
|
5
5
|
exports.resolvePrettierConfigPath = resolvePrettierConfigPath;
|
|
6
6
|
const devkit_1 = require("@nx/devkit");
|
|
7
7
|
const versions_1 = require("./versions");
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// Prettier v3 (ESM) exposes its API as named exports; v2 (CJS) exposes it under
|
|
9
|
+
// `.default` when loaded via `import()`. Return whichever carries the API, or
|
|
10
|
+
// null if prettier isn't installed.
|
|
11
|
+
async function importPrettier() {
|
|
10
12
|
try {
|
|
11
|
-
|
|
13
|
+
const imported = await import('prettier');
|
|
14
|
+
return (imported.resolveConfig ? imported : imported.default);
|
|
12
15
|
}
|
|
13
16
|
catch {
|
|
14
17
|
return null;
|
|
15
18
|
}
|
|
19
|
+
}
|
|
20
|
+
async function resolveUserExistingPrettierConfig() {
|
|
21
|
+
const prettier = await importPrettier();
|
|
22
|
+
if (!prettier) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
16
25
|
try {
|
|
17
26
|
const filepath = await prettier.resolveConfigFile();
|
|
18
27
|
if (!filepath) {
|
|
@@ -76,18 +85,13 @@ function generatePrettierSetup(tree, options) {
|
|
|
76
85
|
: (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { prettier: versions_1.prettierVersion });
|
|
77
86
|
}
|
|
78
87
|
async function resolvePrettierConfigPath(tree) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
prettier = await import('prettier');
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
88
|
+
const prettier = await importPrettier();
|
|
89
|
+
if (!prettier) {
|
|
84
90
|
return null;
|
|
85
91
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return filePath;
|
|
90
|
-
}
|
|
92
|
+
const configFilePath = await prettier.resolveConfigFile();
|
|
93
|
+
if (configFilePath) {
|
|
94
|
+
return configFilePath;
|
|
91
95
|
}
|
|
92
96
|
if (!tree) {
|
|
93
97
|
return null;
|
|
@@ -44,7 +44,10 @@ function getTypeCheckOptions(normalizedOptions) {
|
|
|
44
44
|
};
|
|
45
45
|
if (watch) {
|
|
46
46
|
typeCheckOptions.incremental = true;
|
|
47
|
-
|
|
47
|
+
// Scope the incremental .tsbuildinfo per project (in its own subdir, not
|
|
48
|
+
// alongside Nx's cache files) so concurrent watch type-checks don't collide
|
|
49
|
+
// on a single file.
|
|
50
|
+
typeCheckOptions.cacheDir = (0, node_path_1.join)(devkit_1.cacheDir, 'swc', projectRoot);
|
|
48
51
|
}
|
|
49
52
|
if (normalizedOptions.isTsSolutionSetup && normalizedOptions.skipTypeCheck) {
|
|
50
53
|
typeCheckOptions.ignoreDiagnostics = true;
|
|
@@ -43,6 +43,10 @@ async function runTypeCheck(options) {
|
|
|
43
43
|
options: {
|
|
44
44
|
...compilerOptions,
|
|
45
45
|
incremental: true,
|
|
46
|
+
// Set after the spread so it overrides any user-set tsBuildInfoFile.
|
|
47
|
+
// This is a dedicated type-check program with Nx-injected options that
|
|
48
|
+
// differ from the real build, so its build info must not share a file
|
|
49
|
+
// with the build, or it corrupts the build's incremental cache.
|
|
46
50
|
tsBuildInfoFile: path.join(cacheDir, '.tsbuildinfo'),
|
|
47
51
|
},
|
|
48
52
|
});
|
package/migrations.json
CHANGED
|
@@ -30,13 +30,22 @@
|
|
|
30
30
|
"documentation": "./dist/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes.md"
|
|
31
31
|
},
|
|
32
32
|
"23-1-0-add-ignore-deprecations-for-ts6": {
|
|
33
|
-
"version": "23.1.0-beta.
|
|
34
|
-
"description": "Adds `\"ignoreDeprecations\": \"6.0\"` to tsconfig files whose compilerOptions (or ts-node.compilerOptions)
|
|
33
|
+
"version": "23.1.0-beta.8",
|
|
34
|
+
"description": "Adds `\"ignoreDeprecations\": \"6.0\"` to tsconfig files whose compilerOptions (or ts-node.compilerOptions) carry a TypeScript 6 deprecated option value, set directly or inherited through `extends` including from a base this migration does not edit (e.g. moduleResolution node/node10/classic, baseUrl, target es5, esModuleInterop false, outFile, module amd/umd/system/none, alwaysStrict false, allowSyntheticDefaultImports false, downlevelIteration set). Also pins `\"strict\": false`, `\"noUncheckedSideEffectImports\": false`, `\"types\": [\"*\"]`, and `\"esModuleInterop\": false` in chain-root tsconfigs (no \"extends\") that lack each key, preserving pre-TS6 behavior where these defaults changed; `esModuleInterop` false is itself deprecated (removed in TS7) so it also receives `ignoreDeprecations`, deferring the interop change to the TS7 migration. Also adds `ignoreDeprecations` to every `tsconfig.json` (the exact name jest/ts-node auto-resolve when compiling a config file; ts-node injects a deprecated default `target: es5` there, so the load hits a TS6 error even on a clean config), even one with no deprecated value of its own; a stale local `ignoreDeprecations` (e.g. `5.0`) that would otherwise override the inherited flag is upgraded.",
|
|
35
35
|
"requires": {
|
|
36
36
|
"typescript": ">=6.0.0"
|
|
37
37
|
},
|
|
38
38
|
"factory": "./dist/src/migrations/update-23-1-0/add-ignore-deprecations-for-ts6",
|
|
39
39
|
"documentation": "./dist/src/migrations/update-23-1-0/add-ignore-deprecations-for-ts6.md"
|
|
40
|
+
},
|
|
41
|
+
"23-1-0-set-tsconfig-root-dir-for-ts6": {
|
|
42
|
+
"version": "23.1.0-beta.8",
|
|
43
|
+
"description": "Sets an explicit `rootDir` on project `tsconfig*.json` files that lack one, pinned to the source directory TypeScript 5 inferred implicitly, so programs whose input files span more than one directory (for example a spec tsconfig importing another project's source through a `paths` alias) keep compiling under TypeScript 6, which otherwise hard-fails with TS5011 or TS6059. The value is computed by the compiler, so emit layout is unchanged. Each config is written on its own; the migration never writes to a shared `extends` base, so a config never inherits a value computed for a sibling. Composite projects are not given an inferred `rootDir`, since it already defaulted to the tsconfig directory before TypeScript 6; a composite that extends a base receiving a pinned `rootDir` is itself pinned to its own directory to preserve that default.",
|
|
44
|
+
"requires": {
|
|
45
|
+
"typescript": ">=6.0.0"
|
|
46
|
+
},
|
|
47
|
+
"factory": "./dist/src/migrations/update-23-1-0/set-tsconfig-root-dir-for-ts6",
|
|
48
|
+
"documentation": "./dist/src/migrations/update-23-1-0/set-tsconfig-root-dir-for-ts6.md"
|
|
40
49
|
}
|
|
41
50
|
},
|
|
42
51
|
"packageJsonUpdates": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/js",
|
|
3
|
-
"version": "23.1.0-
|
|
3
|
+
"version": "23.1.0-rc.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"files": [
|
|
@@ -144,11 +144,11 @@
|
|
|
144
144
|
"source-map-support": "0.5.19",
|
|
145
145
|
"tinyglobby": "^0.2.12",
|
|
146
146
|
"tslib": "^2.3.0",
|
|
147
|
-
"@nx/workspace": "23.1.0-
|
|
148
|
-
"@nx/devkit": "23.1.0-
|
|
147
|
+
"@nx/workspace": "23.1.0-rc.0",
|
|
148
|
+
"@nx/devkit": "23.1.0-rc.0"
|
|
149
149
|
},
|
|
150
150
|
"devDependencies": {
|
|
151
|
-
"nx": "23.1.0-
|
|
151
|
+
"nx": "23.1.0-rc.0"
|
|
152
152
|
},
|
|
153
153
|
"peerDependencies": {
|
|
154
154
|
"@swc/cli": ">=0.6.0 <0.9.0",
|