Skip to content

Commit 1d90b46

Browse files
fengmk2claude
andcommitted
feat(migration): add tsdown to vite lib migration support
- Add import rewriting: `import { defineConfig } from 'tsdown'` → `import { defineConfig } from '@voidzero-dev/vite-plus/lib'` - Add declare module rewriting for tsdown - Add script rewriting: `tsdown` → `vite lib` - Add unit tests for tsdown import and declare module rewriting - Add snap test fixture for migration-from-tsdown 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ea8c676 commit 1d90b46

11 files changed

Lines changed: 248 additions & 26 deletions

File tree

crates/vite_migration/src/import_rewriter.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crate::{ast_grep, file_walker};
2222
/// - `import { ... } from '@vitest/browser-preview/{name}'` → `import { ... } from '@voidzero-dev/vite-plus/test/browser-preview/{name}'`
2323
/// - `import { ... } from '@vitest/browser-webdriverio'` → `import { ... } from '@voidzero-dev/vite-plus/test/browser-webdriverio'`
2424
/// - `import { ... } from '@vitest/browser-webdriverio/{name}'` → `import { ... } from '@voidzero-dev/vite-plus/test/browser-webdriverio/{name}'`
25+
/// - `import { ... } from 'tsdown'` → `import { ... } from '@voidzero-dev/vite-plus/lib'`
2526
///
2627
/// **Declare module statements:**
2728
/// - `declare module 'vite' { ... }` → `declare module '@voidzero-dev/vite-plus' { ... }`
@@ -37,6 +38,7 @@ use crate::{ast_grep, file_walker};
3738
/// - `declare module '@vitest/browser-preview/{name}' { ... }` → `declare module '@voidzero-dev/vite-plus/test/browser-preview/{name}' { ... }`
3839
/// - `declare module '@vitest/browser-webdriverio' { ... }` → `declare module '@voidzero-dev/vite-plus/test/browser-webdriverio' { ... }`
3940
/// - `declare module '@vitest/browser-webdriverio/{name}' { ... }` → `declare module '@voidzero-dev/vite-plus/test/browser-webdriverio/{name}' { ... }`
41+
/// - `declare module 'tsdown' { ... }` → `declare module '@voidzero-dev/vite-plus/lib' { ... }`
4042
const REWRITE_IMPORT_RULES: &str = r#"---
4143
id: rewrite-vitest-config-import
4244
language: TypeScript
@@ -229,6 +231,38 @@ transform:
229231
replace: vitest/
230232
by: "@voidzero-dev/vite-plus/test/"
231233
fix: $NEW_IMPORT
234+
---
235+
id: rewrite-tsdown-import
236+
language: TypeScript
237+
rule:
238+
pattern: $STR
239+
kind: string
240+
regex: ^['"]tsdown['"]$
241+
inside:
242+
kind: import_statement
243+
transform:
244+
NEW_IMPORT:
245+
replace:
246+
source: $STR
247+
replace: tsdown
248+
by: "@voidzero-dev/vite-plus/lib"
249+
fix: $NEW_IMPORT
250+
---
251+
id: rewrite-declare-module-tsdown
252+
language: TypeScript
253+
rule:
254+
pattern: $STR
255+
kind: string
256+
regex: ^['"]tsdown['"]$
257+
inside:
258+
kind: module
259+
transform:
260+
NEW_IMPORT:
261+
replace:
262+
source: $STR
263+
replace: tsdown
264+
by: "@voidzero-dev/vite-plus/lib"
265+
fix: $NEW_IMPORT
232266
"#;
233267

234268
/// Result of rewriting imports in a file
@@ -1393,6 +1427,86 @@ declare module '@voidzero-dev/vite-plus/test/browser' {
13931427
name: string;
13941428
configResolved?: (config: ResolvedConfig) => void;
13951429
}
1430+
}"#
1431+
);
1432+
}
1433+
1434+
#[test]
1435+
fn test_rewrite_import_content_tsdown() {
1436+
let tsdown_config = r#"import { defineConfig } from 'tsdown';
1437+
1438+
export default defineConfig({
1439+
entry: 'src/index.ts',
1440+
});"#;
1441+
1442+
let result = rewrite_import_content(tsdown_config).unwrap();
1443+
assert!(result.updated);
1444+
assert_eq!(
1445+
result.content,
1446+
r#"import { defineConfig } from '@voidzero-dev/vite-plus/lib';
1447+
1448+
export default defineConfig({
1449+
entry: 'src/index.ts',
1450+
});"#
1451+
);
1452+
}
1453+
1454+
#[test]
1455+
fn test_rewrite_import_content_tsdown_double_quotes() {
1456+
let tsdown_config = r#"import { defineConfig } from "tsdown";
1457+
1458+
export default defineConfig({
1459+
entry: "src/index.ts",
1460+
});"#;
1461+
1462+
let result = rewrite_import_content(tsdown_config).unwrap();
1463+
assert!(result.updated);
1464+
assert_eq!(
1465+
result.content,
1466+
r#"import { defineConfig } from "@voidzero-dev/vite-plus/lib";
1467+
1468+
export default defineConfig({
1469+
entry: "src/index.ts",
1470+
});"#
1471+
);
1472+
}
1473+
1474+
#[test]
1475+
fn test_rewrite_declare_module_tsdown() {
1476+
let content = r#"declare module 'tsdown' {
1477+
interface BuildConfig {
1478+
custom?: boolean;
1479+
}
1480+
}"#;
1481+
1482+
let result = rewrite_import_content(content).unwrap();
1483+
assert!(result.updated);
1484+
assert_eq!(
1485+
result.content,
1486+
r#"declare module '@voidzero-dev/vite-plus/lib' {
1487+
interface BuildConfig {
1488+
custom?: boolean;
1489+
}
1490+
}"#
1491+
);
1492+
}
1493+
1494+
#[test]
1495+
fn test_rewrite_declare_module_tsdown_double_quotes() {
1496+
let content = r#"declare module "tsdown" {
1497+
interface BuildConfig {
1498+
custom?: boolean;
1499+
}
1500+
}"#;
1501+
1502+
let result = rewrite_import_content(content).unwrap();
1503+
assert!(result.updated);
1504+
assert_eq!(
1505+
result.content,
1506+
r#"declare module "@voidzero-dev/vite-plus/lib" {
1507+
interface BuildConfig {
1508+
custom?: boolean;
1509+
}
13961510
}"#
13971511
);
13981512
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"typecheck": "tsc -b tsconfig.json",
1515
"lint": "vite lint --type-aware --threads 4",
1616
"test": "vite test run && pnpm -r snap-test",
17+
"test:unit": "vite test run",
1718
"prepare": "husky"
1819
},
1920
"devDependencies": {

packages/global/rules/vite-tools.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,12 @@ rule:
4141
kind: command_name
4242
regex: '^vitest$'
4343
fix: vite test
44+
45+
# tsdown => vite lib
46+
---
47+
id: replace-tsdown
48+
language: bash
49+
rule:
50+
kind: command_name
51+
regex: '^tsdown$'
52+
fix: vite lib
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "migration-from-tsdown",
3+
"devDependencies": {
4+
"vite": "^7.0.0",
5+
"tsdown": "^0.5.0"
6+
},
7+
"scripts": {
8+
"build": "tsdown",
9+
"build:watch": "tsdown --watch",
10+
"build:dts": "tsdown --dts"
11+
}
12+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
> vp migration # migration should rewrite imports to vite-plus
2+
┌ Vite+ Migration
3+
4+
● Using default package manager: pnpm
5+
6+
● pnpm@latest installing...
7+
8+
● pnpm@<semver> installed
9+
10+
│ 📦 Found tsdown.config.ts. You can optionally merge it into vite.config.ts
11+
12+
● See: https://viteplus.dev/migration/#tsdown
13+
14+
◆ ✅ Rewrote imports in 1 file(s)
15+
16+
● tsdown.config.ts
17+
18+
└ ✨ Migration completed!
19+
20+
21+
> cat tsdown.config.ts # check tsdown.config.ts
22+
import { defineConfig } from '@voidzero-dev/vite-plus/lib';
23+
24+
export default defineConfig({
25+
entry: 'src/index.ts',
26+
outDir: 'dist',
27+
format: ['esm', 'cjs'],
28+
dts: true,
29+
});
30+
31+
> cat package.json # check package.json
32+
{
33+
"name": "migration-from-tsdown",
34+
"devDependencies": {
35+
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
36+
"@voidzero-dev/vite-plus": "latest"
37+
},
38+
"scripts": {
39+
"build": "vite lib",
40+
"build:watch": "vite lib --watch",
41+
"build:dts": "vite lib --dts"
42+
},
43+
"pnpm": {
44+
"overrides": {
45+
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
46+
"vitest": "npm:@voidzero-dev/vite-plus-test@latest"
47+
}
48+
},
49+
"packageManager": "pnpm@<semver>"
50+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function hello(name: string): string {
2+
return `Hello, ${name}!`;
3+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"env": {
3+
"VITE_DISABLE_AUTO_INSTALL": "1"
4+
},
5+
"commands": [
6+
"vp migration # migration should rewrite imports to vite-plus",
7+
"cat tsdown.config.ts # check tsdown.config.ts",
8+
"cat package.json # check package.json"
9+
]
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { defineConfig } from 'tsdown';
2+
3+
export default defineConfig({
4+
entry: 'src/index.ts',
5+
outDir: 'dist',
6+
format: ['esm', 'cjs'],
7+
dts: true,
8+
});

packages/global/src/migration/__tests__/__snapshots__/migrator.spec.ts.snap

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ exports[`rewritePackageJson > should rewrite devDependencies and dependencies on
44
{
55
"dependencies": {
66
"foo": "1.0.0",
7-
"tsdown": "1.0.0",
87
},
98
"devDependencies": {
109
"@voidzero-dev/vite-plus": "latest",
@@ -16,7 +15,6 @@ exports[`rewritePackageJson > should rewrite devDependencies and dependencies on
1615
{
1716
"dependencies": {
1817
"foo": "1.0.0",
19-
"tsdown": "1.0.0",
2018
},
2119
"devDependencies": {
2220
"@voidzero-dev/vite-plus": "catalog:",
@@ -28,7 +26,6 @@ exports[`rewritePackageJson > should rewrite devDependencies and dependencies on
2826
{
2927
"dependencies": {
3028
"foo": "1.0.0",
31-
"tsdown": "1.0.0",
3229
},
3330
"devDependencies": {
3431
"@voidzero-dev/vite-plus": "latest",
@@ -40,7 +37,6 @@ exports[`rewritePackageJson > should rewrite devDependencies and dependencies on
4037
{
4138
"dependencies": {
4239
"foo": "1.0.0",
43-
"tsdown": "1.0.0",
4440
},
4541
"devDependencies": {
4642
"@voidzero-dev/vite-plus": "catalog:",
@@ -58,7 +54,7 @@ exports[`rewritePackageJson > should rewrite package.json scripts 1`] = `
5854
"*.ts": "vite fmt --fix",
5955
},
6056
"scripts": {
61-
"build": "pnpm install &&vite build -r && vite run build --watch && tsdown && tsc || exit 1",
57+
"build": "pnpm install &&vite build -r && vite run build --watch && vite lib && tsc || exit 1",
6258
"dev": "vite dev",
6359
"dev_analyze": "vite dev --analyze",
6460
"dev_cjs": "VITE_CJS_IGNORE_WARNING=true vite dev",
@@ -74,15 +70,15 @@ exports[`rewritePackageJson > should rewrite package.json scripts 1`] = `
7470
"dev_verbose": "vite dev --verbose",
7571
"fmt": "vite fmt",
7672
"fmt_config": "vite fmt --config .oxfmt.json",
77-
"lib": "tsdown",
78-
"lib_watch": "tsdown --watch",
73+
"lib": "vite lib",
74+
"lib_watch": "vite lib --watch",
7975
"lint": "vite lint",
8076
"lint_config": "vite lint --config .oxlint.json",
8177
"lint_type_aware": "vite lint --type-aware",
8278
"optimize": "vite optimize",
8379
"preview": "vite preview",
84-
"ready": "vite lint --fix --type-aware && vite test run && tsdown && vite fmt --fix",
85-
"ready_env": "NODE_ENV=test FOO=bar vite lint --fix --type-aware && NODE_ENV=test FOO=bar vite test run && NODE_ENV=test FOO=bar tsdown && NODE_ENV=test FOO=bar vite fmt --fix",
80+
"ready": "vite lint --fix --type-aware && vite test run && vite lib && vite fmt --fix",
81+
"ready_env": "NODE_ENV=test FOO=bar vite lint --fix --type-aware && NODE_ENV=test FOO=bar vite test run && NODE_ENV=test FOO=bar vite lib && NODE_ENV=test FOO=bar vite fmt --fix",
8682
"ready_new": "vite install && vite fmt && vite lint --type-aware && vite test -r && vite build -r",
8783
"test": "vite test",
8884
"test_run": "vite test run && vite test --ui",

packages/global/src/migration/detector.ts

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import path from 'node:path';
44
export interface ConfigFiles {
55
viteConfig?: string;
66
vitestConfig?: string;
7+
tsdownConfig?: string;
78
oxlintConfig?: string;
89
oxfmtConfig?: string;
910
}
@@ -31,25 +32,25 @@ export function detectConfigs(projectPath: string): ConfigFiles {
3132
}
3233
}
3334

34-
// TODO: Check for tsdown.config.*
35+
// Check for tsdown.config.*
3536
// https://tsdown.dev/options/config-file
36-
// const tsdownConfigs = [
37-
// 'tsdown.config.ts',
38-
// 'tsdown.config.mts',
39-
// 'tsdown.config.cts',
40-
// 'tsdown.config.js',
41-
// 'tsdown.config.mjs',
42-
// 'tsdown.config.cjs',
43-
// 'tsdown.config.json',
44-
// 'tsdown.config',
45-
// ];
37+
const tsdownConfigs = [
38+
'tsdown.config.ts',
39+
'tsdown.config.mts',
40+
'tsdown.config.cts',
41+
'tsdown.config.js',
42+
'tsdown.config.mjs',
43+
'tsdown.config.cjs',
44+
'tsdown.config.json',
45+
'tsdown.config',
46+
];
4647
// Additionally, you can define your configuration directly in the `tsdown` field of your package.json file
47-
// for (const config of tsdownConfigs) {
48-
// if (fs.existsSync(path.join(projectPath, config))) {
49-
// configs.tsdownConfig = config;
50-
// break;
51-
// }
52-
// }
48+
for (const config of tsdownConfigs) {
49+
if (fs.existsSync(path.join(projectPath, config))) {
50+
configs.tsdownConfig = config;
51+
break;
52+
}
53+
}
5354

5455
// Check for oxlint configs
5556
// https://oxc.rs/docs/guide/usage/linter/config.html#configuration-file-format

0 commit comments

Comments
 (0)