ts6to7 0.1.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 +82 -0
- package/bin/ts6to7.js +10 -0
- package/package.json +30 -0
- package/src/cli.js +88 -0
- package/src/find-files.js +36 -0
- package/src/transform-package-json.js +49 -0
- package/src/transform-tsconfig.js +172 -0
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# ts6to7
|
|
2
|
+
|
|
3
|
+
Codemod that migrates a **TypeScript 6** project to **TypeScript 7 (tsgo)**.
|
|
4
|
+
No install needed — try it in 10 seconds:
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npx ts6to7 --dry
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
TypeScript 7 is the native (Go) rewrite of the compiler. It removes every option
|
|
13
|
+
that TypeScript 6 marked as deprecated and flips some defaults. This tool
|
|
14
|
+
rewrites your config files to the TS7 equivalents and prints a checklist of the
|
|
15
|
+
things it cannot safely change for you.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# preview changes without writing anything
|
|
21
|
+
npx ts6to7 --dry
|
|
22
|
+
|
|
23
|
+
# apply to the current directory (monorepos: scans every package)
|
|
24
|
+
npx ts6to7
|
|
25
|
+
|
|
26
|
+
# apply to a specific directory
|
|
27
|
+
npx ts6to7 packages/app
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install # picks up typescript ^7.0.0
|
|
34
|
+
npx tsc --noEmit # fix any remaining errors it reports
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## What it rewrites
|
|
38
|
+
|
|
39
|
+
### `tsconfig*.json` (comments and formatting are preserved)
|
|
40
|
+
|
|
41
|
+
| Before (TS6) | After (TS7) |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| `"target": "es3"` / `"es5"` | `"ES2015"` — ES5 output was removed |
|
|
44
|
+
| `"module": "amd"` / `"umd"` / `"system"` / `"none"` | `"ESNext"` |
|
|
45
|
+
| `"moduleResolution": "node"` / `"node10"` / `"classic"` | `"NodeNext"` (Node-style projects) or `"Bundler"` |
|
|
46
|
+
| `"importsNotUsedAsValues"`, `"preserveValueImports"` | `"verbatimModuleSyntax": true` |
|
|
47
|
+
| `"baseUrl"` | folded into `"paths"` (mappings become tsconfig-relative) |
|
|
48
|
+
| `charset`, `keyofStringsOnly`, `out`, `noImplicitUseStrict`, `noStrictGenericChecks`, `suppressExcessPropertyErrors`, `suppressImplicitAnyIndexErrors` | removed |
|
|
49
|
+
| `strict` unset | pinned to `false` to preserve behavior (TS7 defaults to `true`) — delete it when you're ready |
|
|
50
|
+
|
|
51
|
+
### `package.json`
|
|
52
|
+
|
|
53
|
+
- Bumps the `typescript` dependency to `^7.0.0`.
|
|
54
|
+
- Warns about tools built on the TS compiler API (`ts-node`, `ts-jest`,
|
|
55
|
+
`ts-patch`, `ttypescript`, `ts-loader`, `fork-ts-checker-webpack-plugin`) —
|
|
56
|
+
tsgo 7.0 does not expose the old JS compiler API (a new one ships in 7.1), so
|
|
57
|
+
each of these needs a TS7-compatible version or a replacement.
|
|
58
|
+
|
|
59
|
+
## What it can't do for you
|
|
60
|
+
|
|
61
|
+
- **ES5 runtimes**: if you still ship to ES5-only environments, transpile TS7's
|
|
62
|
+
output with Babel/SWC.
|
|
63
|
+
- **NodeNext strictness**: relative ESM imports need explicit `.js` extensions;
|
|
64
|
+
`tsc` will list them.
|
|
65
|
+
- **`verbatimModuleSyntax` errors**: type-only imports must become
|
|
66
|
+
`import type { ... }`; editors can auto-fix these.
|
|
67
|
+
- **Ambient types**: TS7 no longer auto-includes every `@types/*` package —
|
|
68
|
+
add `"types": ["node", ...]` explicitly if you relied on that.
|
|
69
|
+
|
|
70
|
+
Everything in this list is also printed as a `Needs manual review` item when
|
|
71
|
+
the codemod runs, scoped to the file that triggered it.
|
|
72
|
+
|
|
73
|
+
## Development
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm install
|
|
77
|
+
npm test
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
MIT
|
package/bin/ts6to7.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ts6to7",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Codemod that migrates a TypeScript 6 project to TypeScript 7 (tsgo): rewrites tsconfig.json options removed in TS7 and flags changes that need manual review.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ts6to7": "bin/ts6to7.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=18"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"test": "node --test"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"typescript",
|
|
21
|
+
"codemod",
|
|
22
|
+
"migration",
|
|
23
|
+
"tsgo",
|
|
24
|
+
"typescript-7"
|
|
25
|
+
],
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"jsonc-parser": "^3.3.1"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT"
|
|
30
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { resolve, relative } from 'node:path';
|
|
3
|
+
import { findFiles } from './find-files.js';
|
|
4
|
+
import { transformTsconfig } from './transform-tsconfig.js';
|
|
5
|
+
import { transformPackageJson } from './transform-package-json.js';
|
|
6
|
+
|
|
7
|
+
const tty = process.stdout.isTTY;
|
|
8
|
+
const bold = (s) => (tty ? `\x1b[1m${s}\x1b[0m` : s);
|
|
9
|
+
const green = (s) => (tty ? `\x1b[32m${s}\x1b[0m` : s);
|
|
10
|
+
const yellow = (s) => (tty ? `\x1b[33m${s}\x1b[0m` : s);
|
|
11
|
+
const dim = (s) => (tty ? `\x1b[2m${s}\x1b[0m` : s);
|
|
12
|
+
|
|
13
|
+
const HELP = `ts6to7 — migrate a TypeScript 6 project to TypeScript 7 (tsgo)
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
npx ts6to7 [directory] [options]
|
|
17
|
+
|
|
18
|
+
Options:
|
|
19
|
+
--dry, -d Show what would change without writing files
|
|
20
|
+
--help, -h Show this help
|
|
21
|
+
|
|
22
|
+
What it does:
|
|
23
|
+
tsconfig*.json
|
|
24
|
+
- target es3/es5 -> ES2015 (removed in TS7)
|
|
25
|
+
- module amd/umd/system -> ESNext (removed in TS7)
|
|
26
|
+
- moduleResolution node10/classic -> NodeNext or Bundler
|
|
27
|
+
- importsNotUsedAsValues / preserveValueImports -> verbatimModuleSyntax
|
|
28
|
+
- baseUrl -> folded into "paths" (removed in TS7)
|
|
29
|
+
- removes charset, keyofStringsOnly, out, noImplicitUseStrict, ...
|
|
30
|
+
- pins strict: false if unset (TS7 defaults strict to true)
|
|
31
|
+
package.json
|
|
32
|
+
- typescript dependency -> ^7.0.0
|
|
33
|
+
- warns about compiler-API tools (ts-node, ts-patch, ts-jest, ...)
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
export async function run(argv) {
|
|
37
|
+
const args = [...argv];
|
|
38
|
+
const dry = args.includes('--dry') || args.includes('-d');
|
|
39
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
40
|
+
console.log(HELP);
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
const dirArg = args.find((a) => !a.startsWith('-'));
|
|
44
|
+
const root = resolve(process.cwd(), dirArg ?? '.');
|
|
45
|
+
|
|
46
|
+
const { tsconfigs, packageJsons } = findFiles(root);
|
|
47
|
+
if (tsconfigs.length === 0 && packageJsons.length === 0) {
|
|
48
|
+
console.error(`No tsconfig*.json or package.json found under ${root}`);
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let filesChanged = 0;
|
|
53
|
+
const allWarnings = [];
|
|
54
|
+
|
|
55
|
+
const process1 = (file, transform) => {
|
|
56
|
+
const original = readFileSync(file, 'utf8');
|
|
57
|
+
const { text, changes, warnings } = transform(original);
|
|
58
|
+
const rel = relative(root, file) || file;
|
|
59
|
+
|
|
60
|
+
if (changes.length > 0) {
|
|
61
|
+
filesChanged++;
|
|
62
|
+
console.log(`\n${bold(rel)}`);
|
|
63
|
+
for (const c of changes) console.log(` ${green('~')} ${c}`);
|
|
64
|
+
if (!dry && text !== original) writeFileSync(file, text);
|
|
65
|
+
}
|
|
66
|
+
for (const w of warnings) allWarnings.push({ rel, w });
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
for (const file of tsconfigs) process1(file, transformTsconfig);
|
|
70
|
+
for (const file of packageJsons) process1(file, transformPackageJson);
|
|
71
|
+
|
|
72
|
+
if (allWarnings.length > 0) {
|
|
73
|
+
console.log(`\n${bold('Needs manual review:')}`);
|
|
74
|
+
for (const { rel, w } of allWarnings) {
|
|
75
|
+
console.log(` ${yellow('!')} ${dim(`[${rel}]`)} ${w}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
console.log(
|
|
80
|
+
dry
|
|
81
|
+
? `\n${filesChanged} file(s) would be updated (dry run — nothing written).`
|
|
82
|
+
: `\n${filesChanged} file(s) updated.`,
|
|
83
|
+
);
|
|
84
|
+
if (!dry && filesChanged > 0) {
|
|
85
|
+
console.log(dim('Next: reinstall dependencies, then run `tsc --noEmit` (or `tsgo`) and fix remaining errors.'));
|
|
86
|
+
}
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { readdirSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', 'out', 'coverage', '.next', '.turbo']);
|
|
5
|
+
const TSCONFIG_RE = /^tsconfig(\..+)?\.json$/;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Recursively collect tsconfig*.json and package.json files under root.
|
|
9
|
+
* Returns { tsconfigs: string[], packageJsons: string[] }.
|
|
10
|
+
*/
|
|
11
|
+
export function findFiles(root) {
|
|
12
|
+
const tsconfigs = [];
|
|
13
|
+
const packageJsons = [];
|
|
14
|
+
|
|
15
|
+
const walk = (dir) => {
|
|
16
|
+
let entries;
|
|
17
|
+
try {
|
|
18
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
19
|
+
} catch {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
const full = join(dir, entry.name);
|
|
24
|
+
if (entry.isDirectory()) {
|
|
25
|
+
if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith('.')) walk(full);
|
|
26
|
+
} else if (TSCONFIG_RE.test(entry.name)) {
|
|
27
|
+
tsconfigs.push(full);
|
|
28
|
+
} else if (entry.name === 'package.json') {
|
|
29
|
+
packageJsons.push(full);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
walk(root);
|
|
35
|
+
return { tsconfigs, packageJsons };
|
|
36
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { parse, modify, applyEdits } from 'jsonc-parser';
|
|
2
|
+
|
|
3
|
+
const FORMAT = { formattingOptions: { insertSpaces: true, tabSize: 2 } };
|
|
4
|
+
|
|
5
|
+
/** Packages built on the TS compiler API, which tsgo (TS7) does not expose (new API lands in 7.1). */
|
|
6
|
+
const API_DEPENDENT = ['ts-patch', 'ttypescript', 'ts-node', 'ts-loader', 'ts-jest', 'fork-ts-checker-webpack-plugin'];
|
|
7
|
+
|
|
8
|
+
const DEP_FIELDS = ['dependencies', 'devDependencies'];
|
|
9
|
+
|
|
10
|
+
function majorOf(range) {
|
|
11
|
+
const m = String(range).match(/(\d+)\./);
|
|
12
|
+
return m ? Number(m[1]) : null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Bump the typescript dependency to ^7 and warn about compiler-API tooling.
|
|
17
|
+
* Returns { text, changes, warnings }.
|
|
18
|
+
*/
|
|
19
|
+
export function transformPackageJson(text) {
|
|
20
|
+
const changes = [];
|
|
21
|
+
const warnings = [];
|
|
22
|
+
let result = text;
|
|
23
|
+
|
|
24
|
+
const json = parse(text) ?? {};
|
|
25
|
+
|
|
26
|
+
for (const field of DEP_FIELDS) {
|
|
27
|
+
const deps = json[field];
|
|
28
|
+
if (typeof deps !== 'object' || deps === null) continue;
|
|
29
|
+
|
|
30
|
+
if (typeof deps.typescript === 'string') {
|
|
31
|
+
const major = majorOf(deps.typescript);
|
|
32
|
+
if (major !== null && major < 7) {
|
|
33
|
+
result = applyEdits(result, modify(result, [field, 'typescript'], '^7.0.0', FORMAT));
|
|
34
|
+
changes.push(`${field}.typescript: "${deps.typescript}" -> "^7.0.0"`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
for (const name of API_DEPENDENT) {
|
|
39
|
+
if (deps[name]) {
|
|
40
|
+
warnings.push(
|
|
41
|
+
`"${name}" uses the TypeScript compiler API, which tsgo does not expose in 7.0 ` +
|
|
42
|
+
'(a new API ships with 7.1). Check that your version supports TS7 or find an alternative.',
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return { text: result, changes, warnings };
|
|
49
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { parse, modify, applyEdits } from 'jsonc-parser';
|
|
2
|
+
|
|
3
|
+
const FORMAT = { formattingOptions: { insertSpaces: true, tabSize: 2 } };
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Options that were deprecated in TS 5/6 and are removed in TS 7.
|
|
7
|
+
* They are deleted outright; some carry an extra note for the report.
|
|
8
|
+
*/
|
|
9
|
+
const REMOVED_OPTIONS = {
|
|
10
|
+
charset: null,
|
|
11
|
+
keyofStringsOnly: null,
|
|
12
|
+
noImplicitUseStrict: null,
|
|
13
|
+
noStrictGenericChecks: null,
|
|
14
|
+
suppressExcessPropertyErrors: null,
|
|
15
|
+
suppressImplicitAnyIndexErrors: null,
|
|
16
|
+
out: 'use "outFile" instead if you relied on single-file output',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function lower(value) {
|
|
20
|
+
return typeof value === 'string' ? value.toLowerCase() : value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Join a paths-mapping entry onto the old baseUrl, tsconfig-dir relative. */
|
|
24
|
+
function joinBaseUrl(baseUrl, entry) {
|
|
25
|
+
if (entry.startsWith('/')) return entry;
|
|
26
|
+
const base = baseUrl.replace(/\/+$/, '');
|
|
27
|
+
const rest = entry.replace(/^\.\//, '');
|
|
28
|
+
const joined = base === '.' || base === '' ? rest : `${base}/${rest}`;
|
|
29
|
+
return joined.startsWith('.') || joined.startsWith('/') ? joined : `./${joined}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Transform the text of one tsconfig(-like) JSONC file for TypeScript 7.
|
|
34
|
+
* Comment/format preserving. Returns { text, changes, warnings }.
|
|
35
|
+
*/
|
|
36
|
+
export function transformTsconfig(text) {
|
|
37
|
+
const changes = [];
|
|
38
|
+
const warnings = [];
|
|
39
|
+
let result = text;
|
|
40
|
+
|
|
41
|
+
const json = parse(text) ?? {};
|
|
42
|
+
const co = json.compilerOptions;
|
|
43
|
+
if (typeof co !== 'object' || co === null) {
|
|
44
|
+
return { text: result, changes, warnings };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const edit = (key, value) => {
|
|
48
|
+
result = applyEdits(result, modify(result, ['compilerOptions', key], value, FORMAT));
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// --- target: es3/es5 removed; minimum is ES2015 -------------------------
|
|
52
|
+
const target = lower(co.target);
|
|
53
|
+
if (target === 'es3' || target === 'es5') {
|
|
54
|
+
edit('target', 'ES2015');
|
|
55
|
+
changes.push(`target: "${co.target}" -> "ES2015" (ES5 and below removed in TS7)`);
|
|
56
|
+
warnings.push(
|
|
57
|
+
'target was raised to ES2015: emitted JS now uses classes, let/const, arrow functions etc. ' +
|
|
58
|
+
'If you must ship ES5 (e.g. IE11), transpile the TS7 output with Babel/SWC.',
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// --- module: amd/umd/system/none removed --------------------------------
|
|
63
|
+
const module_ = lower(co.module);
|
|
64
|
+
const removedModules = ['amd', 'umd', 'system', 'none'];
|
|
65
|
+
if (removedModules.includes(module_)) {
|
|
66
|
+
edit('module', 'ESNext');
|
|
67
|
+
changes.push(`module: "${co.module}" -> "ESNext" (removed in TS7)`);
|
|
68
|
+
warnings.push(
|
|
69
|
+
`module "${co.module}" no longer exists: the emitted module format changes to ESM. ` +
|
|
70
|
+
'Your loader/bundler setup needs a manual review.',
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// --- moduleResolution: node10/node/classic removed ----------------------
|
|
75
|
+
const resolution = lower(co.moduleResolution);
|
|
76
|
+
if (resolution === 'node' || resolution === 'node10' || resolution === 'classic') {
|
|
77
|
+
// nodenext requires module nodenext; bundler requires module es2015+/preserve.
|
|
78
|
+
const nodeLike =
|
|
79
|
+
module_ === 'commonjs' || module_ === 'node16' || module_ === 'nodenext' || module_ === undefined;
|
|
80
|
+
if (nodeLike) {
|
|
81
|
+
edit('module', 'NodeNext');
|
|
82
|
+
edit('moduleResolution', 'NodeNext');
|
|
83
|
+
changes.push(
|
|
84
|
+
`moduleResolution: "${co.moduleResolution}" -> "NodeNext"` +
|
|
85
|
+
(lower(co.module) !== 'nodenext' ? ` (module set to "NodeNext" to match)` : ''),
|
|
86
|
+
);
|
|
87
|
+
warnings.push(
|
|
88
|
+
'NodeNext resolution is stricter than the old "node": relative ESM imports need explicit ' +
|
|
89
|
+
'file extensions and package.json "exports" is honored. Run tsc once and fix reported imports.',
|
|
90
|
+
);
|
|
91
|
+
} else {
|
|
92
|
+
edit('moduleResolution', 'Bundler');
|
|
93
|
+
changes.push(`moduleResolution: "${co.moduleResolution}" -> "Bundler"`);
|
|
94
|
+
warnings.push(
|
|
95
|
+
'moduleResolution "Bundler" assumes a bundler (Vite/webpack/esbuild) resolves imports at build time.',
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// --- importsNotUsedAsValues / preserveValueImports -> verbatimModuleSyntax
|
|
101
|
+
const hasINUAV = Object.prototype.hasOwnProperty.call(co, 'importsNotUsedAsValues');
|
|
102
|
+
const hasPVI = Object.prototype.hasOwnProperty.call(co, 'preserveValueImports');
|
|
103
|
+
if (hasINUAV || hasPVI) {
|
|
104
|
+
const wantsVerbatim =
|
|
105
|
+
co.preserveValueImports === true ||
|
|
106
|
+
lower(co.importsNotUsedAsValues) === 'error' ||
|
|
107
|
+
lower(co.importsNotUsedAsValues) === 'preserve';
|
|
108
|
+
if (hasINUAV) edit('importsNotUsedAsValues', undefined);
|
|
109
|
+
if (hasPVI) edit('preserveValueImports', undefined);
|
|
110
|
+
if (wantsVerbatim) {
|
|
111
|
+
edit('verbatimModuleSyntax', true);
|
|
112
|
+
changes.push('importsNotUsedAsValues/preserveValueImports -> verbatimModuleSyntax: true');
|
|
113
|
+
warnings.push(
|
|
114
|
+
'verbatimModuleSyntax requires type-only imports to be written as `import type`. ' +
|
|
115
|
+
'tsc will point at each offending import; most editors can auto-fix them.',
|
|
116
|
+
);
|
|
117
|
+
} else {
|
|
118
|
+
changes.push('removed importsNotUsedAsValues/preserveValueImports (defaults match old behavior)');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// --- baseUrl removed: fold it into paths ---------------------------------
|
|
123
|
+
if (Object.prototype.hasOwnProperty.call(co, 'baseUrl')) {
|
|
124
|
+
const baseUrl = String(co.baseUrl);
|
|
125
|
+
if (co.paths && typeof co.paths === 'object') {
|
|
126
|
+
const newPaths = {};
|
|
127
|
+
for (const [pattern, targets] of Object.entries(co.paths)) {
|
|
128
|
+
newPaths[pattern] = Array.isArray(targets)
|
|
129
|
+
? targets.map((t) => joinBaseUrl(baseUrl, String(t)))
|
|
130
|
+
: targets;
|
|
131
|
+
}
|
|
132
|
+
edit('paths', newPaths);
|
|
133
|
+
changes.push(`baseUrl "${baseUrl}" folded into paths (entries now tsconfig-relative)`);
|
|
134
|
+
} else {
|
|
135
|
+
edit('paths', { '*': [joinBaseUrl(baseUrl, '*')] });
|
|
136
|
+
changes.push(`baseUrl "${baseUrl}" -> paths: { "*": ["${joinBaseUrl(baseUrl, '*')}"] }`);
|
|
137
|
+
warnings.push(
|
|
138
|
+
'baseUrl-style bare imports (e.g. `import x from "utils/x"`) now rely on the generated ' +
|
|
139
|
+
'"*" paths mapping. Verify your runtime/bundler resolves them the same way.',
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
edit('baseUrl', undefined);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// --- options removed without replacement ---------------------------------
|
|
146
|
+
for (const [key, note] of Object.entries(REMOVED_OPTIONS)) {
|
|
147
|
+
if (Object.prototype.hasOwnProperty.call(co, key)) {
|
|
148
|
+
edit(key, undefined);
|
|
149
|
+
changes.push(`removed ${key} (option no longer exists in TS7)${note ? ` — ${note}` : ''}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// --- strict becomes the default in TS7 -----------------------------------
|
|
154
|
+
if (!Object.prototype.hasOwnProperty.call(co, 'strict')) {
|
|
155
|
+
edit('strict', false);
|
|
156
|
+
changes.push('added explicit strict: false (TS7 flips the default to true)');
|
|
157
|
+
warnings.push(
|
|
158
|
+
'strict: false was added to preserve current behavior. Consider deleting it and fixing ' +
|
|
159
|
+
'strict-mode errors instead — TS7 projects are strict by default.',
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// --- types auto-inclusion behavior change (report only) -------------------
|
|
164
|
+
if (!Object.prototype.hasOwnProperty.call(co, 'types')) {
|
|
165
|
+
warnings.push(
|
|
166
|
+
'No "types" array: TS7 no longer auto-includes every @types/* package. If you rely on ' +
|
|
167
|
+
'ambient types (e.g. @types/node), list them explicitly: "types": ["node"].',
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return { text: result, changes, warnings };
|
|
172
|
+
}
|