Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ VITE+ - The Unified Toolchain for the Web

◇ Migrated . to Vite+ <version>
• Node <version> pnpm <version>
• 3 config updates applied, 1 file had imports rewritten
• 4 config updates applied, 1 file had imports rewritten
• Inline Vite plugins wrapped with lazyPlugins for check/lint/fmt
! Warnings:
- Vitest v5: 1 review item

Expand All @@ -35,7 +36,7 @@ import { join } from 'node:path';

import react from '@vitejs/plugin-react';
import { playwright } from 'vite-plus/test/browser-playwright';
import { defineConfig } from 'vite-plus';
import { defineConfig, lazyPlugins } from 'vite-plus';

import type { UserConfigFn } from 'vite-plus';

Expand Down Expand Up @@ -67,7 +68,7 @@ export default defineConfig(<UserConfigFn>(((() => {
}
]
},
plugins: [react()],
plugins: lazyPlugins(() => [react()]),
test: {
dir: join(import.meta.dirname, 'test'),
browser: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,13 @@ steps = [
{ argv = ["vpt", "print-file", "dist/method/index.mjs"] },
{ argv = ["vpt", "print-file", "dist/control/index.mjs"] },
]

[[case]]
name = "migration_pack_tsdown_023_wrapped"
vp = "global"
comment = "Upgrade a pack config whose config object is wrapped in a type assertion."
steps = [
{ argv = ["vpt", "write-file", "vite.config.ts", "import { defineConfig } from 'vite-plus';\nimport type { UserConfig } from 'vite-plus';\n\nexport default defineConfig({\n pack: {\n entry: 'src/index.ts',\n bundle: false,\n },\n} as UserConfig);\n"], snapshot = false },
{ argv = ["vp", "migrate", "--no-interactive"] },
{ argv = ["vpt", "print-file", "vite.config.ts"] },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# migration_pack_tsdown_023_wrapped

Upgrade a pack config whose config object is wrapped in a type assertion.

## `vpt write-file vite.config.ts 'import { defineConfig } from '\''vite-plus'\'';
import type { UserConfig } from '\''vite-plus'\'';

export default defineConfig({
pack: {
entry: '\''src/index.ts'\'',
bundle: false,
},
} as UserConfig);
'`


## `vp migrate --no-interactive`

```
VITE+ - The Unified Toolchain for the Web

◇ Updated . to Vite+ <version>
• Node <version> npm <version>
• Dependencies:
vite-plus 0.2.0 → <version>
vite → <version>
• 1 file had imports rewritten
• Package manager settings configured
```

## `vpt print-file vite.config.ts`

```
import { defineConfig } from 'vite-plus';
import type { UserConfig } from 'vite-plus';

export default defineConfig({
pack: { deps: {
// tsdown <0.23 compatibility: resolve external dependency subpaths.
// Remove to preserve subpath imports as written (the new default).
// https://tsdown.dev/options/dependencies#deps-resolvedepsubpath
resolveDepSubpath: true },
entry: 'src/index.ts',
unbundle: true,
},
} as UserConfig);
```
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,13 @@ steps = [
{ argv = ["vpt", "print-file", "vite.config.ts"] },
{ argv = ["vp", "migrate", "--no-interactive"] },
]

[[case]]
name = "migration_task_cache_fields_wrapped"
vp = "global"
comment = "Move task cache settings when the defineConfig callback is wrapped in a type assertion."
steps = [
{ argv = ["vpt", "write-file", "vite.config.ts", "import { defineConfig } from 'vite-plus';\nimport type { UserConfigFn } from 'vite-plus';\n\nexport default defineConfig((() => {\n return {\n run: { tasks: { build: { command: 'vp build', env: ['DEPLOY_TARGET'] } } },\n };\n}) as UserConfigFn);\n"], snapshot = false },
{ argv = ["vp", "migrate", "--no-interactive"] },
{ argv = ["vpt", "print-file", "vite.config.ts"] },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# migration_task_cache_fields_wrapped

Move task cache settings when the defineConfig callback is wrapped in a type assertion.

## `vpt write-file vite.config.ts 'import { defineConfig } from '\''vite-plus'\'';
import type { UserConfigFn } from '\''vite-plus'\'';

export default defineConfig((() => {
return {
run: { tasks: { build: { command: '\''vp build'\'', env: ['\''DEPLOY_TARGET'\''] } } },
};
}) as UserConfigFn);
'`


## `vp migrate --no-interactive`

```
VITE+ - The Unified Toolchain for the Web

◇ Updated . to Vite+ <version>
• Node <version> npm <version>
• Dependencies:
vite-plus 0.2.0 → <version>
vite → <version>
• 1 config update applied
• Task cache settings moved under `cache`
• Package manager settings configured
```

## `vpt print-file vite.config.ts`

```
import { defineConfig } from 'vite-plus';
import type { UserConfigFn } from 'vite-plus';

export default defineConfig((() => {
return {
run: { tasks: { build: { command: 'vp build', cache: { env: ['DEPLOY_TARGET'] } } } },
};
}) as UserConfigFn);
```
42 changes: 41 additions & 1 deletion crates/vp_migration/src/pack_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,12 @@ pub(crate) fn is_pack_object<D: Doc>(object: &Node<'_, D>, standalone: bool) ->
}
let Some(parent) = value.parent() else { break };
match parent.kind().as_ref() {
"array" | "parenthesized_expression" | "satisfies_expression" | "as_expression" => {
"array"
| "parenthesized_expression"
| "satisfies_expression"
| "as_expression"
| "type_assertion"
| "non_null_expression" => {
value = parent;
}
_ => break,
Expand Down Expand Up @@ -890,6 +895,11 @@ mod tests {
"export default defineConfig(() => ([{ bundle: false, dts: { tsgo: true } }]));",
"export default defineConfig(() => (({ bundle: false, dts: { tsgo: true } }) satisfies UserConfig));",
"export default defineConfig(() => { return { bundle: false, dts: { tsgo: true } }; });",
"export default defineConfig(() => ({ bundle: false, dts: { tsgo: true } }) as UserConfig);",
"export default defineConfig((() => ({ bundle: false, dts: { tsgo: true } })) as UserConfigFn);",
"export default defineConfig(<UserConfigFn>(() => ({ bundle: false, dts: { tsgo: true } })));",
"export default defineConfig((() => ({ bundle: false, dts: { tsgo: true } }))!);",
"export default defineConfig((() => { return { bundle: false, dts: { tsgo: true } }; }) satisfies UserConfigFn);",
] {
let actual = rewrite_pack_config(input, true, true);
assert!(actual.contains("unbundle: true"), "{actual}");
Expand Down Expand Up @@ -1075,6 +1085,34 @@ mod tests {
),
("export default { pack: ({ bundle: false } satisfies PackConfig) };", false),
("export default { pack: { \"bundle\": false, \"dts\": { \"tsgo\": true } } };", false),
("export default defineConfig({ pack: { bundle: false } } as UserConfig);", false),
("export default defineConfig(({ pack: { bundle: false } }));", false),
("export default defineConfig(<UserConfig>{ pack: { bundle: false } });", false),
("export default defineConfig({ pack: <PackConfig>{ bundle: false } });", false),
(
"export default defineConfig(() => ({ pack: { bundle: false } }) as UserConfig);",
false,
),
(
"export default defineConfig(() => ({ pack: { bundle: false } } satisfies UserConfig));",
false,
),
(
"export default defineConfig((() => ({ pack: { bundle: false } })) as UserConfigFn);",
false,
),
(
"export default defineConfig(() => { return { pack: { bundle: false } } as UserConfig; });",
false,
),
(
"export default defineConfig(() => { return ({ pack: { bundle: false } }); });",
false,
),
(
"export default defineConfig(<UserConfigFn>((() => { return { pack: { bundle: false } }; }) satisfies UserConfigFn)!);",
false,
),
] {
let actual = rewrite_pack_config(input, standalone, true);
assert!(!actual.contains("bundle: false"), "{actual}");
Expand All @@ -1086,6 +1124,8 @@ mod tests {
"export default { test: { pack: { bundle: false } } };",
"export default defineConfig({ plugins: [{ config() { return { pack: { bundle: false } }; } }] });",
"const config = { bundle: false }; export default config;",
"export default defineConfig(() => { function* pack() { return { pack: { bundle: false } }; } return pack().next().value; });",
"export default defineConfig(wrap((() => ({ pack: { bundle: false } })) as Fn));",
] {
assert_eq!(rewrite_pack_config(input, false, true), input);
}
Expand Down
57 changes: 19 additions & 38 deletions crates/vp_migration/src/task_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use vp_error::Error;

use crate::{
pack_config::can_edit_object,
vite_config::{is_define_config_call, is_direct_recognized_config_object, pair_key_matches},
vite_config::{is_direct_recognized_config_object, pair_key_matches},
};

/// Task settings that Vite Task only accepts inside a task's `cache` object.
Expand Down Expand Up @@ -95,42 +95,10 @@ fn task_name<D: Doc>(object: &Node<'_, D>) -> Option<(String, bool)> {
return None;
}
let key = task.field("key")?;
Some((key.text().trim_matches(['\'', '"']).to_owned(), is_direct_config(&config)))
}

/// Whether `object` is a direct config object, looking through parentheses and
/// type assertions around it and around a `defineConfig` callback, as in
/// `defineConfig((env) => ({ ... }) as UserConfig)` and
/// `defineConfig(((env) => ({ ... })) as UserConfigFn)`.
fn is_direct_config<D: Doc>(object: &Node<'_, D>) -> bool {
let outer = outermost_wrapper(object);
if is_direct_recognized_config_object(&outer) {
return true;
}
outer
.parent()
.filter(|arrow| {
arrow.kind() == "arrow_function"
&& arrow.field("body").is_some_and(|body| body.range() == outer.range())
})
.and_then(|arrow| outermost_wrapper(&arrow).parent())
.filter(|arguments| arguments.kind() == "arguments")
.and_then(|arguments| arguments.parent())
.is_some_and(|call| is_define_config_call(&call))
}

/// The outermost parenthesized or type-asserted expression around `node`.
fn outermost_wrapper<'a, D: Doc>(node: &Node<'a, D>) -> Node<'a, D> {
let mut outer = node.clone();
while let Some(parent) = outer.parent().filter(|parent| {
matches!(
parent.kind().as_ref(),
"parenthesized_expression" | "satisfies_expression" | "as_expression"
)
}) {
outer = parent;
}
outer
Some((
key.text().trim_matches(['\'', '"']).to_owned(),
is_direct_recognized_config_object(&config),
))
}

/// Returns the pair whose value is `node`, looking through parentheses and
Expand All @@ -140,7 +108,11 @@ fn value_pair<'a, D: Doc>(node: &Node<'a, D>) -> Option<Node<'a, D>> {
loop {
let parent = value.parent()?;
match parent.kind().as_ref() {
"parenthesized_expression" | "satisfies_expression" | "as_expression" => {
"parenthesized_expression"
| "satisfies_expression"
| "as_expression"
| "type_assertion"
| "non_null_expression" => {
value = parent;
}
"pair" => {
Expand Down Expand Up @@ -633,6 +605,13 @@ mod tests {
"export default defineConfig(() => ({ run: { tasks: { build: { command: 'x', env: ['A'] } } } }) satisfies UserConfig);",
"export default defineConfig(((env: Env) => ({ run: { tasks: { build: { command: 'x', env: ['A'] } } } })) as UserConfigFn);",
"export default ({ run: { tasks: { build: { command: 'x', env: ['A'] } } } });",
"export default defineConfig(<UserConfig>{ run: { tasks: { build: { command: 'x', env: ['A'] } } } });",
"export default defineConfig({ run: { tasks: { build: { command: 'x', env: ['A'] } } } }!);",
"export default defineConfig(<UserConfigFn>(() => ({ run: { tasks: { build: { command: 'x', env: ['A'] } } } })));",
"export default defineConfig((() => ({ run: { tasks: { build: { command: 'x', env: ['A'] } } } }))!);",
"export default defineConfig((() => { return { run: { tasks: { build: { command: 'x', env: ['A'] } } } }; }));",
"export default defineConfig((function () { return { run: { tasks: { build: { command: 'x', env: ['A'] } } } }; }) as UserConfigFn);",
"export default defineConfig(<UserConfigFn>((() => { return { run: { tasks: { build: { command: 'x', env: ['A'] } } } }; }) satisfies UserConfigFn)!);",
] {
let result = migrate(input);
assert!(result.content.contains("cache: { env: ['A'] }"), "{}", result.content);
Expand Down Expand Up @@ -665,6 +644,8 @@ mod tests {
"export default mergeConfig(base, { run: { tasks: { build: { command: 'x', env: ['A'] } } } });",
"export default withTests((() => ({ run: { tasks: { build: { command: 'x', env: ['A'] } } } })) as Fn);",
"export function withTasks() { return { run: { tasks: { build: { command: 'x', env: ['A'] } } } }; }",
"export default defineConfig(() => { function* tasks() { return { run: { tasks: { build: { command: 'x', env: ['A'] } } } }; } return tasks().next().value; });",
"export default defineConfig(() => { const tasks = function* () { return { run: { tasks: { build: { command: 'x', env: ['A'] } } } }; }; return tasks().next().value; });",
] {
let result = migrate(input);
assert_eq!(result.content, input);
Expand Down
Loading
Loading