tsdown-migrate 0.17.0-beta.4 → 0.17.0-beta.6
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/index.mjs +1 -1
- package/dist/run.mjs +1 -1
- package/dist/src-CxBgk5SI.mjs +326 -0
- package/package.json +18 -17
- package/dist/src-D55VvIEl.mjs +0 -141
package/dist/index.mjs
CHANGED
package/dist/run.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as name, r as version, t as migrate } from "./src-
|
|
2
|
+
import { n as name, r as version, t as migrate } from "./src-CxBgk5SI.mjs";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
import consola from "consola";
|
|
5
5
|
import { cac } from "cac";
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { getCliCommand, parseNi, run } from "@antfu/ni";
|
|
3
|
+
import { dim, green, red, underline } from "ansis";
|
|
4
|
+
import consola from "consola";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
import { readFile, unlink, writeFile } from "node:fs/promises";
|
|
7
|
+
import { createPatch, createTwoFilesPatch } from "diff";
|
|
8
|
+
import { Lang, parse } from "@ast-grep/napi";
|
|
9
|
+
|
|
10
|
+
//#region ../../src/utils/format.ts
|
|
11
|
+
function detectIndentation(jsonText) {
|
|
12
|
+
const lines = jsonText.split(/\r?\n/);
|
|
13
|
+
for (const line of lines) {
|
|
14
|
+
const match = line.match(/^(\s+)\S/);
|
|
15
|
+
if (!match) continue;
|
|
16
|
+
if (match[1].includes(" ")) return " ";
|
|
17
|
+
return match[1].length;
|
|
18
|
+
}
|
|
19
|
+
return 2;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region package.json
|
|
24
|
+
var name = "tsdown-migrate";
|
|
25
|
+
var version = "0.17.0-beta.6";
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/utils.ts
|
|
29
|
+
function renameKey(obj, oldKey, newKey, newValue) {
|
|
30
|
+
const newObj = {};
|
|
31
|
+
for (const key of Object.keys(obj)) if (key === oldKey) newObj[newKey] = newValue || obj[oldKey];
|
|
32
|
+
else newObj[key] = obj[key];
|
|
33
|
+
return newObj;
|
|
34
|
+
}
|
|
35
|
+
function outputDiff(text) {
|
|
36
|
+
for (const line of text.split("\n")) {
|
|
37
|
+
const color = line[0] === "+" ? green : line[0] === "-" ? red : dim;
|
|
38
|
+
console.info(color(line));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/helpers/package-json.ts
|
|
44
|
+
const DEP_FIELDS = {
|
|
45
|
+
dependencies: `^${version}`,
|
|
46
|
+
devDependencies: `^${version}`,
|
|
47
|
+
optionalDependencies: `^${version}`,
|
|
48
|
+
peerDependencies: "*",
|
|
49
|
+
peerDependenciesMeta: null
|
|
50
|
+
};
|
|
51
|
+
async function migratePackageJson(dryRun) {
|
|
52
|
+
if (!existsSync("package.json")) {
|
|
53
|
+
consola.error("No package.json found");
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const pkgRaw = await readFile("package.json", "utf8");
|
|
57
|
+
let pkg = JSON.parse(pkgRaw);
|
|
58
|
+
let found = false;
|
|
59
|
+
for (const [field, semver] of Object.entries(DEP_FIELDS)) if (pkg[field]?.tsup) {
|
|
60
|
+
consola.info(`Migrating \`${field}\` to tsdown.`);
|
|
61
|
+
found = true;
|
|
62
|
+
pkg[field] = renameKey(pkg[field], "tsup", "tsdown", semver);
|
|
63
|
+
}
|
|
64
|
+
if (pkg.scripts) {
|
|
65
|
+
for (const key of Object.keys(pkg.scripts)) if (pkg.scripts[key].includes("tsup")) {
|
|
66
|
+
consola.info(`Migrating \`${key}\` script to tsdown`);
|
|
67
|
+
found = true;
|
|
68
|
+
pkg.scripts[key] = pkg.scripts[key].replaceAll(/tsup(?:-node)?/g, "tsdown");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (pkg.tsup) {
|
|
72
|
+
consola.info("Migrating `tsup` field in package.json to `tsdown`.");
|
|
73
|
+
found = true;
|
|
74
|
+
pkg = renameKey(pkg, "tsup", "tsdown");
|
|
75
|
+
}
|
|
76
|
+
if (!found) {
|
|
77
|
+
consola.warn("No tsup-related fields found in package.json");
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const eol = pkgRaw.endsWith("\n") ? "\n" : "";
|
|
81
|
+
const newPkgRaw = `${JSON.stringify(pkg, null, detectIndentation(pkgRaw))}${eol}`;
|
|
82
|
+
if (dryRun) {
|
|
83
|
+
consola.info("[dry-run] package.json:");
|
|
84
|
+
outputDiff(createPatch("package.json", pkgRaw, newPkgRaw));
|
|
85
|
+
} else {
|
|
86
|
+
await writeFile("package.json", newPkgRaw);
|
|
87
|
+
consola.success("Migrated `package.json`");
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/helpers/tsup-config.ts
|
|
94
|
+
const RE_TS = /\.[cm]?ts$/;
|
|
95
|
+
const WARNING_MESSAGES = {
|
|
96
|
+
plugins: "The `plugins` option in tsup is experimental. Please migrate your plugins manually.",
|
|
97
|
+
splitting: "The `splitting` option is currently unsupported in tsdown. Code splitting is always enabled and cannot be disabled.",
|
|
98
|
+
metafile: "The `metafile` option is not available in tsdown. Consider using Vite DevTools as an alternative.",
|
|
99
|
+
injectStyle: "The `injectStyle` option has not yet been implemented in tsdown.",
|
|
100
|
+
swc: "The `swc` option is not supported in tsdown. Please use oxc instead.",
|
|
101
|
+
experimentalDts: "The `experimentalDts` option is not supported in tsdown. Use the `dts` option instead.",
|
|
102
|
+
legacyOutput: "The `legacyOutput` option is not supported in tsdown."
|
|
103
|
+
};
|
|
104
|
+
const PROPERTY_RENAMES = {
|
|
105
|
+
entryPoints: "entry",
|
|
106
|
+
esbuildPlugins: "plugins",
|
|
107
|
+
publicDir: "copy",
|
|
108
|
+
cjsInterop: "cjsDefault"
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Transform tsup config code to tsdown config code.
|
|
112
|
+
* This function applies all migration rules and returns the transformed code
|
|
113
|
+
* along with any warnings for unsupported options.
|
|
114
|
+
*/
|
|
115
|
+
function transformTsupConfig(code, filename) {
|
|
116
|
+
const warnings = [];
|
|
117
|
+
const edits = [];
|
|
118
|
+
const lang = filename.endsWith(".tsx") ? Lang.Tsx : RE_TS.test(filename) ? Lang.TypeScript : Lang.JavaScript;
|
|
119
|
+
let ast = parse(lang, code);
|
|
120
|
+
let root = ast.root();
|
|
121
|
+
const findPropertyPair = (propName) => {
|
|
122
|
+
return root.find({ rule: {
|
|
123
|
+
kind: "pair",
|
|
124
|
+
has: {
|
|
125
|
+
field: "key",
|
|
126
|
+
kind: "property_identifier",
|
|
127
|
+
regex: `^${propName}$`
|
|
128
|
+
}
|
|
129
|
+
} });
|
|
130
|
+
};
|
|
131
|
+
for (const [optionName, message] of Object.entries(WARNING_MESSAGES)) if (findPropertyPair(optionName)) warnings.push(message);
|
|
132
|
+
const importStrings = root.findAll({ rule: {
|
|
133
|
+
kind: "string",
|
|
134
|
+
inside: { kind: "import_statement" },
|
|
135
|
+
has: {
|
|
136
|
+
kind: "string_fragment",
|
|
137
|
+
regex: "unplugin-.*/esbuild"
|
|
138
|
+
}
|
|
139
|
+
} });
|
|
140
|
+
for (const node of importStrings) {
|
|
141
|
+
const text = node.text();
|
|
142
|
+
edits.push(node.replace(text.replace("/esbuild", "/rolldown")));
|
|
143
|
+
}
|
|
144
|
+
const findPropertyIdentifier = (propName) => {
|
|
145
|
+
return root.find({ rule: {
|
|
146
|
+
kind: "property_identifier",
|
|
147
|
+
regex: `^${propName}$`,
|
|
148
|
+
inside: {
|
|
149
|
+
kind: "pair",
|
|
150
|
+
field: "key"
|
|
151
|
+
}
|
|
152
|
+
} });
|
|
153
|
+
};
|
|
154
|
+
for (const [oldName, newName] of Object.entries(PROPERTY_RENAMES)) {
|
|
155
|
+
const propIdentifier = findPropertyIdentifier(oldName);
|
|
156
|
+
if (propIdentifier) edits.push(propIdentifier.replace(newName));
|
|
157
|
+
}
|
|
158
|
+
const bundleTruePairs = root.findAll({ rule: {
|
|
159
|
+
kind: "pair",
|
|
160
|
+
all: [{ has: {
|
|
161
|
+
field: "key",
|
|
162
|
+
kind: "property_identifier",
|
|
163
|
+
regex: "^bundle$"
|
|
164
|
+
} }, { has: {
|
|
165
|
+
field: "value",
|
|
166
|
+
kind: "true"
|
|
167
|
+
} }]
|
|
168
|
+
} });
|
|
169
|
+
for (const node of bundleTruePairs) edits.push(node.replace(""));
|
|
170
|
+
const bundleFalsePairs = root.findAll({ rule: {
|
|
171
|
+
kind: "pair",
|
|
172
|
+
all: [{ has: {
|
|
173
|
+
field: "key",
|
|
174
|
+
kind: "property_identifier",
|
|
175
|
+
regex: "^bundle$"
|
|
176
|
+
} }, { has: {
|
|
177
|
+
field: "value",
|
|
178
|
+
kind: "false"
|
|
179
|
+
} }]
|
|
180
|
+
} });
|
|
181
|
+
for (const node of bundleFalsePairs) edits.push(node.replace("unbundle: true"));
|
|
182
|
+
const removeNodeProtocolPairs = root.findAll({ rule: {
|
|
183
|
+
kind: "pair",
|
|
184
|
+
all: [{ has: {
|
|
185
|
+
field: "key",
|
|
186
|
+
kind: "property_identifier",
|
|
187
|
+
regex: "^removeNodeProtocol$"
|
|
188
|
+
} }, { has: {
|
|
189
|
+
field: "value",
|
|
190
|
+
kind: "true"
|
|
191
|
+
} }]
|
|
192
|
+
} });
|
|
193
|
+
for (const node of removeNodeProtocolPairs) edits.push(node.replace("nodeProtocol: 'strip'"));
|
|
194
|
+
const tsupIdentifiers = root.findAll({ rule: {
|
|
195
|
+
kind: "identifier",
|
|
196
|
+
regex: "^tsup$"
|
|
197
|
+
} });
|
|
198
|
+
for (const node of tsupIdentifiers) edits.push(node.replace("tsdown"));
|
|
199
|
+
const tsupUpperIdentifiers = root.findAll({ rule: {
|
|
200
|
+
kind: "identifier",
|
|
201
|
+
regex: "^TSUP$"
|
|
202
|
+
} });
|
|
203
|
+
for (const node of tsupUpperIdentifiers) edits.push(node.replace("TSDOWN"));
|
|
204
|
+
const tsupImportStrings = root.findAll({ rule: {
|
|
205
|
+
kind: "string",
|
|
206
|
+
inside: { kind: "import_statement" },
|
|
207
|
+
has: {
|
|
208
|
+
kind: "string_fragment",
|
|
209
|
+
regex: "tsup"
|
|
210
|
+
}
|
|
211
|
+
} });
|
|
212
|
+
for (const node of tsupImportStrings) {
|
|
213
|
+
const text = node.text();
|
|
214
|
+
edits.push(node.replace(text.replace("tsup", "tsdown")));
|
|
215
|
+
}
|
|
216
|
+
code = root.commitEdits(edits);
|
|
217
|
+
ast = parse(lang, code);
|
|
218
|
+
root = ast.root();
|
|
219
|
+
const hasOption = (optionName) => {
|
|
220
|
+
return root.find({ rule: {
|
|
221
|
+
kind: "pair",
|
|
222
|
+
has: {
|
|
223
|
+
field: "key",
|
|
224
|
+
kind: "property_identifier",
|
|
225
|
+
regex: `^${optionName}$`
|
|
226
|
+
}
|
|
227
|
+
} }) !== null;
|
|
228
|
+
};
|
|
229
|
+
const exportDefaultDirect = root.find("export default { $$$OPTS }");
|
|
230
|
+
const exportDefaultDefineConfig = root.find("export default defineConfig({ $$$OPTS })");
|
|
231
|
+
let configObjectNode = null;
|
|
232
|
+
if (exportDefaultDirect) configObjectNode = exportDefaultDirect.find({ rule: {
|
|
233
|
+
kind: "object",
|
|
234
|
+
inside: { kind: "export_statement" }
|
|
235
|
+
} });
|
|
236
|
+
else if (exportDefaultDefineConfig) configObjectNode = exportDefaultDefineConfig.find({ rule: {
|
|
237
|
+
kind: "object",
|
|
238
|
+
inside: { kind: "arguments" }
|
|
239
|
+
} });
|
|
240
|
+
const missingDefaults = [];
|
|
241
|
+
if (configObjectNode) {
|
|
242
|
+
if (!hasOption("format")) missingDefaults.push("format: 'cjs'");
|
|
243
|
+
if (!hasOption("clean")) missingDefaults.push("clean: false");
|
|
244
|
+
if (!hasOption("dts")) missingDefaults.push("dts: false");
|
|
245
|
+
if (!hasOption("target")) missingDefaults.push("target: false");
|
|
246
|
+
}
|
|
247
|
+
if (missingDefaults.length > 0 && configObjectNode) {
|
|
248
|
+
const children = configObjectNode.children();
|
|
249
|
+
const closeBrace = children.find((c) => c.text() === "}");
|
|
250
|
+
if (closeBrace) {
|
|
251
|
+
const additionsStr = missingDefaults.join(",\n ");
|
|
252
|
+
const lastChild = children.findLast((c) => c.kind() === "pair");
|
|
253
|
+
const insertText = lastChild && !lastChild.text().endsWith(",") ? `,\n ${additionsStr},\n` : `\n ${additionsStr},\n`;
|
|
254
|
+
const edit = {
|
|
255
|
+
startPos: closeBrace.range().start.index,
|
|
256
|
+
endPos: closeBrace.range().start.index,
|
|
257
|
+
insertedText: insertText
|
|
258
|
+
};
|
|
259
|
+
code = root.commitEdits([edit]);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
code = code.replaceAll(/,\s*,/g, ",").replaceAll(/\n\s*,\s*\n/g, "\n").replaceAll(/([^\s,])\n\s*,/g, "$1,").replaceAll(/\n[ \t]*\n[ \t]*\n/g, "\n\n").replaceAll(/\{[ \t]*\n[ \t]*,/g, "{\n");
|
|
263
|
+
return {
|
|
264
|
+
code,
|
|
265
|
+
warnings
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
const TSUP_FILES = [
|
|
269
|
+
"tsup.config.ts",
|
|
270
|
+
"tsup.config.cts",
|
|
271
|
+
"tsup.config.mts",
|
|
272
|
+
"tsup.config.js",
|
|
273
|
+
"tsup.config.cjs",
|
|
274
|
+
"tsup.config.mjs",
|
|
275
|
+
"tsup.config.json"
|
|
276
|
+
];
|
|
277
|
+
async function migrateTsupConfig(dryRun) {
|
|
278
|
+
let found = false;
|
|
279
|
+
for (const file of TSUP_FILES) {
|
|
280
|
+
if (!existsSync(file)) continue;
|
|
281
|
+
consola.info(`Found \`${file}\``);
|
|
282
|
+
found = true;
|
|
283
|
+
const tsupConfigRaw = await readFile(file, "utf8");
|
|
284
|
+
const { code: tsupConfig, warnings } = transformTsupConfig(tsupConfigRaw, file);
|
|
285
|
+
for (const warning of warnings) consola.warn(warning);
|
|
286
|
+
const renamed = file.replaceAll("tsup", "tsdown");
|
|
287
|
+
if (dryRun) {
|
|
288
|
+
consola.info(`[dry-run] ${file} -> ${renamed}:`);
|
|
289
|
+
outputDiff(createTwoFilesPatch(file, renamed, tsupConfigRaw, tsupConfig));
|
|
290
|
+
} else {
|
|
291
|
+
await writeFile(renamed, tsupConfig, "utf8");
|
|
292
|
+
await unlink(file);
|
|
293
|
+
consola.success(`Migrated \`${file}\` to \`${renamed}\``);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
if (!found) consola.warn("No tsup config found");
|
|
297
|
+
return found;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region src/index.ts
|
|
302
|
+
async function migrate({ cwd, dryRun }) {
|
|
303
|
+
if (dryRun) consola.info("Dry run enabled. No changes were made.");
|
|
304
|
+
else if (!await consola.prompt(`Before proceeding, review the migration guide at ${underline`https://tsdown.dev/guide/migrate-from-tsup`}, as this process will modify your files.\nUncommitted changes will be lost. Use the ${green`--dry-run`} flag to preview changes without applying them.\n\nContinue?`, { type: "confirm" })) {
|
|
305
|
+
consola.warn("Migration cancelled.");
|
|
306
|
+
process.exitCode = 1;
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (cwd) process.chdir(cwd);
|
|
310
|
+
let migrated = await migratePackageJson(dryRun);
|
|
311
|
+
if (await migrateTsupConfig(dryRun)) migrated = true;
|
|
312
|
+
if (!migrated) {
|
|
313
|
+
consola.error("No migration performed.");
|
|
314
|
+
process.exitCode = 1;
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
consola.info("Migration completed. Installing dependencies...");
|
|
318
|
+
if (dryRun) consola.info("[dry-run] would run:", await getCliCommand(parseNi, []));
|
|
319
|
+
else {
|
|
320
|
+
await run(parseNi, [], { cwd });
|
|
321
|
+
consola.success("Dependencies installed.");
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
//#endregion
|
|
326
|
+
export { name as n, version as r, migrate as t };
|
package/package.json
CHANGED
|
@@ -1,31 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tsdown-migrate",
|
|
3
|
-
"version": "0.17.0-beta.4",
|
|
4
|
-
"description": "A CLI tool to help migrate your project to tsdown.",
|
|
5
3
|
"type": "module",
|
|
4
|
+
"version": "0.17.0-beta.6",
|
|
5
|
+
"description": "A CLI tool to help migrate your project to tsdown.",
|
|
6
|
+
"author": "Kevin Deng <sxzz@sxzz.moe>",
|
|
6
7
|
"license": "MIT",
|
|
8
|
+
"funding": "https://github.com/sponsors/sxzz",
|
|
7
9
|
"homepage": "http://tsdown.dev/",
|
|
8
|
-
"bugs": {
|
|
9
|
-
"url": "https://github.com/rolldown/tsdown/issues"
|
|
10
|
-
},
|
|
11
10
|
"repository": {
|
|
12
11
|
"type": "git",
|
|
13
12
|
"url": "git+https://github.com/rolldown/tsdown.git",
|
|
14
13
|
"directory": "packages/migrate"
|
|
15
14
|
},
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"dist"
|
|
20
|
-
],
|
|
21
|
-
"main": "./dist/index.mjs",
|
|
22
|
-
"module": "./dist/index.mjs",
|
|
23
|
-
"types": "./dist/index.d.mts",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/rolldown/tsdown/issues"
|
|
17
|
+
},
|
|
24
18
|
"exports": {
|
|
25
19
|
".": "./dist/index.mjs",
|
|
26
20
|
"./run": "./dist/run.mjs",
|
|
27
21
|
"./package.json": "./package.json"
|
|
28
22
|
},
|
|
23
|
+
"main": "./dist/index.mjs",
|
|
24
|
+
"module": "./dist/index.mjs",
|
|
25
|
+
"types": "./dist/index.d.mts",
|
|
29
26
|
"typesVersions": {
|
|
30
27
|
"*": {
|
|
31
28
|
"*": [
|
|
@@ -37,19 +34,23 @@
|
|
|
37
34
|
"bin": {
|
|
38
35
|
"tsdown-migrate": "./dist/run.mjs"
|
|
39
36
|
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist"
|
|
39
|
+
],
|
|
40
40
|
"publishConfig": {
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=20.19.0"
|
|
45
|
+
},
|
|
43
46
|
"dependencies": {
|
|
44
|
-
"@antfu/ni": "^
|
|
47
|
+
"@antfu/ni": "^28.0.0",
|
|
48
|
+
"@ast-grep/napi": "^0.40.0",
|
|
45
49
|
"ansis": "^4.2.0",
|
|
46
50
|
"cac": "^6.7.14",
|
|
47
51
|
"consola": "^3.4.2",
|
|
48
52
|
"diff": "^8.0.2"
|
|
49
53
|
},
|
|
50
|
-
"engines": {
|
|
51
|
-
"node": ">=20.19.0"
|
|
52
|
-
},
|
|
53
54
|
"scripts": {
|
|
54
55
|
"dev": "node ./src/run.ts",
|
|
55
56
|
"build": "unrun ../../src/run.ts -c ../../tsdown.config.ts -F ."
|
package/dist/src-D55VvIEl.mjs
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { readFile, unlink, writeFile } from "node:fs/promises";
|
|
3
|
-
import process from "node:process";
|
|
4
|
-
import { getCliCommand, parseNi, run } from "@antfu/ni";
|
|
5
|
-
import { dim, green, red, underline } from "ansis";
|
|
6
|
-
import consola from "consola";
|
|
7
|
-
import { createPatch, createTwoFilesPatch } from "diff";
|
|
8
|
-
|
|
9
|
-
//#region ../../src/utils/format.ts
|
|
10
|
-
function detectIndentation(jsonText) {
|
|
11
|
-
const lines = jsonText.split(/\r?\n/);
|
|
12
|
-
for (const line of lines) {
|
|
13
|
-
const match = line.match(/^(\s+)\S/);
|
|
14
|
-
if (!match) continue;
|
|
15
|
-
if (match[1].includes(" ")) return " ";
|
|
16
|
-
return match[1].length;
|
|
17
|
-
}
|
|
18
|
-
return 2;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
//#endregion
|
|
22
|
-
//#region package.json
|
|
23
|
-
var name = "tsdown-migrate";
|
|
24
|
-
var version = "0.17.0-beta.4";
|
|
25
|
-
|
|
26
|
-
//#endregion
|
|
27
|
-
//#region src/index.ts
|
|
28
|
-
async function migrate({ cwd, dryRun }) {
|
|
29
|
-
if (dryRun) consola.info("Dry run enabled. No changes were made.");
|
|
30
|
-
else if (!await consola.prompt(`Before proceeding, review the migration guide at ${underline`https://tsdown.dev/guide/migrate-from-tsup`}, as this process will modify your files.\nUncommitted changes will be lost. Use the ${green`--dry-run`} flag to preview changes without applying them.\n\nContinue?`, { type: "confirm" })) {
|
|
31
|
-
consola.warn("Migration cancelled.");
|
|
32
|
-
process.exitCode = 1;
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
if (cwd) process.chdir(cwd);
|
|
36
|
-
let migrated = await migratePackageJson(dryRun);
|
|
37
|
-
if (await migrateTsupConfig(dryRun)) migrated = true;
|
|
38
|
-
if (!migrated) {
|
|
39
|
-
consola.error("No migration performed.");
|
|
40
|
-
process.exitCode = 1;
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
consola.info("Migration completed. Installing dependencies...");
|
|
44
|
-
if (dryRun) consola.info("[dry-run] would run:", await getCliCommand(parseNi, []));
|
|
45
|
-
else {
|
|
46
|
-
await run(parseNi, [], { cwd });
|
|
47
|
-
consola.success("Dependencies installed.");
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
const DEP_FIELDS = {
|
|
51
|
-
dependencies: `^${version}`,
|
|
52
|
-
devDependencies: `^${version}`,
|
|
53
|
-
optionalDependencies: `^${version}`,
|
|
54
|
-
peerDependencies: "*",
|
|
55
|
-
peerDependenciesMeta: null
|
|
56
|
-
};
|
|
57
|
-
async function migratePackageJson(dryRun) {
|
|
58
|
-
if (!existsSync("package.json")) {
|
|
59
|
-
consola.error("No package.json found");
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
const pkgRaw = await readFile("package.json", "utf8");
|
|
63
|
-
let pkg = JSON.parse(pkgRaw);
|
|
64
|
-
let found = false;
|
|
65
|
-
for (const [field, semver] of Object.entries(DEP_FIELDS)) if (pkg[field]?.tsup) {
|
|
66
|
-
consola.info(`Migrating \`${field}\` to tsdown.`);
|
|
67
|
-
found = true;
|
|
68
|
-
pkg[field] = renameKey(pkg[field], "tsup", "tsdown", semver);
|
|
69
|
-
}
|
|
70
|
-
if (pkg.scripts) {
|
|
71
|
-
for (const key of Object.keys(pkg.scripts)) if (pkg.scripts[key].includes("tsup")) {
|
|
72
|
-
consola.info(`Migrating \`${key}\` script to tsdown`);
|
|
73
|
-
found = true;
|
|
74
|
-
pkg.scripts[key] = pkg.scripts[key].replaceAll(/tsup(?:-node)?/g, "tsdown");
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (pkg.tsup) {
|
|
78
|
-
consola.info("Migrating `tsup` field in package.json to `tsdown`.");
|
|
79
|
-
found = true;
|
|
80
|
-
pkg = renameKey(pkg, "tsup", "tsdown");
|
|
81
|
-
}
|
|
82
|
-
if (!found) {
|
|
83
|
-
consola.warn("No tsup-related fields found in package.json");
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
const eol = pkgRaw.endsWith("\n") ? "\n" : "";
|
|
87
|
-
const newPkgRaw = `${JSON.stringify(pkg, null, detectIndentation(pkgRaw))}${eol}`;
|
|
88
|
-
if (dryRun) {
|
|
89
|
-
consola.info("[dry-run] package.json:");
|
|
90
|
-
outputDiff(createPatch("package.json", pkgRaw, newPkgRaw));
|
|
91
|
-
} else {
|
|
92
|
-
await writeFile("package.json", newPkgRaw);
|
|
93
|
-
consola.success("Migrated `package.json`");
|
|
94
|
-
}
|
|
95
|
-
return true;
|
|
96
|
-
}
|
|
97
|
-
const TSUP_FILES = [
|
|
98
|
-
"tsup.config.ts",
|
|
99
|
-
"tsup.config.cts",
|
|
100
|
-
"tsup.config.mts",
|
|
101
|
-
"tsup.config.js",
|
|
102
|
-
"tsup.config.cjs",
|
|
103
|
-
"tsup.config.mjs",
|
|
104
|
-
"tsup.config.json"
|
|
105
|
-
];
|
|
106
|
-
async function migrateTsupConfig(dryRun) {
|
|
107
|
-
let found = false;
|
|
108
|
-
for (const file of TSUP_FILES) {
|
|
109
|
-
if (!existsSync(file)) continue;
|
|
110
|
-
consola.info(`Found \`${file}\``);
|
|
111
|
-
found = true;
|
|
112
|
-
const tsupConfigRaw = await readFile(file, "utf8");
|
|
113
|
-
const tsupConfig = tsupConfigRaw.replaceAll(/\btsup\b/g, "tsdown").replaceAll(/\bTSUP\b/g, "TSDOWN");
|
|
114
|
-
const renamed = file.replaceAll("tsup", "tsdown");
|
|
115
|
-
if (dryRun) {
|
|
116
|
-
consola.info(`[dry-run] ${file} -> ${renamed}:`);
|
|
117
|
-
outputDiff(createTwoFilesPatch(file, renamed, tsupConfigRaw, tsupConfig));
|
|
118
|
-
} else {
|
|
119
|
-
await writeFile(renamed, tsupConfig, "utf8");
|
|
120
|
-
await unlink(file);
|
|
121
|
-
consola.success(`Migrated \`${file}\` to \`${renamed}\``);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
if (!found) consola.warn("No tsup config found");
|
|
125
|
-
return found;
|
|
126
|
-
}
|
|
127
|
-
function renameKey(obj, oldKey, newKey, newValue) {
|
|
128
|
-
const newObj = {};
|
|
129
|
-
for (const key of Object.keys(obj)) if (key === oldKey) newObj[newKey] = newValue || obj[oldKey];
|
|
130
|
-
else newObj[key] = obj[key];
|
|
131
|
-
return newObj;
|
|
132
|
-
}
|
|
133
|
-
function outputDiff(text) {
|
|
134
|
-
for (const line of text.split("\n")) {
|
|
135
|
-
const color = line[0] === "+" ? green : line[0] === "-" ? red : dim;
|
|
136
|
-
console.info(color(line));
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
//#endregion
|
|
141
|
-
export { name as n, version as r, migrate as t };
|