diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index bab6e6b6bf..8a9565eda7 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -96,6 +96,14 @@ jobs: vite run lint vite run type vite run test -- --coverage + - name: vite-plugin-react + node-version: 22 + command: | + vite run format + vite run lint -- --fix + # TODO(fengmk2): run all builds and tests after tsdown version upgrade + vite run @vitejs/plugin-rsc#build + vite run @vitejs/plugin-rsc#test steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 diff --git a/CLAUDE.md b/CLAUDE.md index 0a409b3935..fd7f325236 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -79,3 +79,29 @@ vite dev # runs dev script from package.json - Run `cargo test` to execute all tests - You never need to run `pnpm install` in the test fixtures dir, vite-plus should able to load and parse the workspace without `pnpm install`. + +## Build + +- Run `pnpm bootstrap-cli` from the project root to build all packages and install the global CLI + - This builds all `@voidzero-dev/*` packages + - Compiles the Rust NAPI bindings + - Installs the CLI globally via npm + +## Snap Tests + +Snap tests are located in `packages/global/snap-tests/`. Each test case is a directory containing: + +- `package.json` - Package configuration for the test +- `steps.json` - Commands to run and environment variables +- `src/` - Source files for the test +- `snap.txt` - Expected output (generated/updated by running the test) + +```bash +# Run all snap tests +pnpm -F @voidzero-dev/global snap-test + +# Run a specific snap test by name filter +pnpm -F @voidzero-dev/global snap-test migration-skip-vite-peer-dependency +``` + +The snap test will automatically generate/update the `snap.txt` file with the command outputs. diff --git a/crates/vite_migration/src/import_rewriter.rs b/crates/vite_migration/src/import_rewriter.rs index 6a07524b28..1677bec984 100644 --- a/crates/vite_migration/src/import_rewriter.rs +++ b/crates/vite_migration/src/import_rewriter.rs @@ -1,16 +1,88 @@ -use std::path::{Path, PathBuf}; +use std::{ + collections::HashMap, + path::{Path, PathBuf}, +}; use vite_error::Error; use crate::{ast_grep, file_walker}; -/// ast-grep rules for rewriting imports and declare module statements to @voidzero-dev/vite-plus +/// ast-grep rules for rewriting vite imports and declare module statements /// /// This rewrites: -/// -/// **Import statements:** /// - `import { ... } from 'vite'` → `import { ... } from '@voidzero-dev/vite-plus'` /// - `import { ... } from 'vite/{name}'` → `import { ... } from '@voidzero-dev/vite-plus/{name}'` +/// - `declare module 'vite' { ... }` → `declare module '@voidzero-dev/vite-plus' { ... }` +/// - `declare module 'vite/{name}' { ... }` → `declare module '@voidzero-dev/vite-plus/{name}' { ... }` +const REWRITE_VITE_RULES: &str = r#"--- +id: rewrite-vite-import +language: TypeScript +rule: + pattern: $STR + kind: string + regex: ^['"]vite['"]$ + inside: + kind: import_statement +transform: + NEW_IMPORT: + replace: + source: $STR + replace: vite + by: "@voidzero-dev/vite-plus" +fix: $NEW_IMPORT +--- +id: rewrite-vite-subpath-import +language: TypeScript +rule: + pattern: $STR + kind: string + regex: ^['"]vite/.+['"]$ + inside: + kind: import_statement +transform: + NEW_IMPORT: + replace: + source: $STR + replace: vite/ + by: "@voidzero-dev/vite-plus/" +fix: $NEW_IMPORT +--- +id: rewrite-declare-module-vite +language: TypeScript +rule: + pattern: $STR + kind: string + regex: ^['\"]vite['\"]$ + inside: + kind: module +transform: + NEW_IMPORT: + replace: + source: $STR + replace: vite + by: "@voidzero-dev/vite-plus" +fix: $NEW_IMPORT +--- +id: rewrite-declare-module-vite-subpath +language: TypeScript +rule: + pattern: $STR + kind: string + regex: ^['\"]vite/.+['\"]$ + inside: + kind: module +transform: + NEW_IMPORT: + replace: + source: $STR + replace: vite/ + by: "@voidzero-dev/vite-plus/" +fix: $NEW_IMPORT +"#; + +/// ast-grep rules for rewriting vitest imports and declare module statements +/// +/// This rewrites: /// - `import { ... } from 'vitest'` → `import { ... } from '@voidzero-dev/vite-plus/test'` /// - `import { ... } from 'vitest/config'` → `import { ... } from '@voidzero-dev/vite-plus'` /// - `import { ... } from 'vitest/{name}'` → `import { ... } from '@voidzero-dev/vite-plus/test/{name}'` @@ -22,11 +94,6 @@ use crate::{ast_grep, file_walker}; /// - `import { ... } from '@vitest/browser-preview/{name}'` → `import { ... } from '@voidzero-dev/vite-plus/test/browser-preview/{name}'` /// - `import { ... } from '@vitest/browser-webdriverio'` → `import { ... } from '@voidzero-dev/vite-plus/test/browser-webdriverio'` /// - `import { ... } from '@vitest/browser-webdriverio/{name}'` → `import { ... } from '@voidzero-dev/vite-plus/test/browser-webdriverio/{name}'` -/// - `import { ... } from 'tsdown'` → `import { ... } from '@voidzero-dev/vite-plus/lib'` -/// -/// **Declare module statements:** -/// - `declare module 'vite' { ... }` → `declare module '@voidzero-dev/vite-plus' { ... }` -/// - `declare module 'vite/{name}' { ... }` → `declare module '@voidzero-dev/vite-plus/{name}' { ... }` /// - `declare module 'vitest' { ... }` → `declare module '@voidzero-dev/vite-plus/test' { ... }` /// - `declare module 'vitest/config' { ... }` → `declare module '@voidzero-dev/vite-plus' { ... }` /// - `declare module 'vitest/{name}' { ... }` → `declare module '@voidzero-dev/vite-plus/test/{name}' { ... }` @@ -38,8 +105,7 @@ use crate::{ast_grep, file_walker}; /// - `declare module '@vitest/browser-preview/{name}' { ... }` → `declare module '@voidzero-dev/vite-plus/test/browser-preview/{name}' { ... }` /// - `declare module '@vitest/browser-webdriverio' { ... }` → `declare module '@voidzero-dev/vite-plus/test/browser-webdriverio' { ... }` /// - `declare module '@vitest/browser-webdriverio/{name}' { ... }` → `declare module '@voidzero-dev/vite-plus/test/browser-webdriverio/{name}' { ... }` -/// - `declare module 'tsdown' { ... }` → `declare module '@voidzero-dev/vite-plus/lib' { ... }` -const REWRITE_IMPORT_RULES: &str = r#"--- +const REWRITE_VITEST_RULES: &str = r#"--- id: rewrite-vitest-config-import language: TypeScript rule: @@ -56,22 +122,6 @@ transform: by: "@voidzero-dev/vite-plus" fix: $NEW_IMPORT --- -id: rewrite-vite-import -language: TypeScript -rule: - pattern: $STR - kind: string - regex: ^['"]vite['"]$ - inside: - kind: import_statement -transform: - NEW_IMPORT: - replace: - source: $STR - replace: vite - by: "@voidzero-dev/vite-plus" -fix: $NEW_IMPORT ---- id: rewrite-vitest-import language: TypeScript rule: @@ -104,22 +154,6 @@ transform: by: "@voidzero-dev/vite-plus/test/" fix: $NEW_IMPORT --- -id: rewrite-vite-subpath-import -language: TypeScript -rule: - pattern: $STR - kind: string - regex: ^['"]vite/.+['"]$ - inside: - kind: import_statement -transform: - NEW_IMPORT: - replace: - source: $STR - replace: vite/ - by: "@voidzero-dev/vite-plus/" -fix: $NEW_IMPORT ---- id: rewrite-vitest-subpath-import language: TypeScript rule: @@ -152,22 +186,6 @@ transform: by: "@voidzero-dev/vite-plus" fix: $NEW_IMPORT --- -id: rewrite-declare-module-vite -language: TypeScript -rule: - pattern: $STR - kind: string - regex: ^['\"]vite['\"]$ - inside: - kind: module -transform: - NEW_IMPORT: - replace: - source: $STR - replace: vite - by: "@voidzero-dev/vite-plus" -fix: $NEW_IMPORT ---- id: rewrite-declare-module-vitest language: TypeScript rule: @@ -200,22 +218,6 @@ transform: by: "@voidzero-dev/vite-plus/test/" fix: $NEW_IMPORT --- -id: rewrite-declare-module-vite-subpath -language: TypeScript -rule: - pattern: $STR - kind: string - regex: ^['\"]vite/.+['\"]$ - inside: - kind: module -transform: - NEW_IMPORT: - replace: - source: $STR - replace: vite/ - by: "@voidzero-dev/vite-plus/" -fix: $NEW_IMPORT ---- id: rewrite-declare-module-vitest-subpath language: TypeScript rule: @@ -231,7 +233,14 @@ transform: replace: vitest/ by: "@voidzero-dev/vite-plus/test/" fix: $NEW_IMPORT ---- +"#; + +/// ast-grep rules for rewriting tsdown imports and declare module statements +/// +/// This rewrites: +/// - `import { ... } from 'tsdown'` → `import { ... } from '@voidzero-dev/vite-plus/lib'` +/// - `declare module 'tsdown' { ... }` → `declare module '@voidzero-dev/vite-plus/lib' { ... }` +const REWRITE_TSDOWN_RULES: &str = r#"--- id: rewrite-tsdown-import language: TypeScript rule: @@ -265,6 +274,78 @@ transform: fix: $NEW_IMPORT "#; +/// Packages to skip rewriting based on peerDependencies or dependencies +#[derive(Debug, Clone, Default)] +struct SkipPackages { + /// Skip rewriting vite imports (vite is in peerDependencies or dependencies) + skip_vite: bool, + /// Skip rewriting vitest imports (vitest is in peerDependencies or dependencies) + skip_vitest: bool, + /// Skip rewriting tsdown imports (tsdown is in peerDependencies or dependencies) + skip_tsdown: bool, +} + +impl SkipPackages { + /// Check if all packages should be skipped (file can be skipped entirely) + fn all_skipped(&self) -> bool { + self.skip_vite && self.skip_vitest && self.skip_tsdown + } +} + +/// Find the nearest package.json by walking up from the file's directory. +/// Stops at the root directory. +fn find_nearest_package_json(file_path: &Path, root: &Path) -> Option { + let mut current = file_path.parent()?; + + loop { + let package_json = current.join("package.json"); + if package_json.exists() { + return Some(package_json); + } + + // Stop if we've reached the root + if current == root { + break; + } + + // Move to parent directory + current = current.parent()?; + } + + None +} + +/// Parse package.json and check which packages are in peerDependencies or dependencies. +/// Returns default (no skipping) if package.json doesn't exist or can't be parsed. +fn get_skip_packages_from_package_json(package_json_path: &Path) -> SkipPackages { + let content = match std::fs::read_to_string(package_json_path) { + Ok(c) => c, + Err(_) => return SkipPackages::default(), + }; + + let pkg: serde_json::Value = match serde_json::from_str(&content) { + Ok(p) => p, + Err(_) => return SkipPackages::default(), + }; + + // Helper to check if a package exists in a dependencies object + let has_package = |deps_key: &str, package_name: &str| -> bool { + pkg.get(deps_key) + .and_then(|v| v.as_object()) + .map(|deps| deps.contains_key(package_name)) + .unwrap_or(false) + }; + + // Check both peerDependencies and dependencies + SkipPackages { + skip_vite: has_package("peerDependencies", "vite") || has_package("dependencies", "vite"), + skip_vitest: has_package("peerDependencies", "vitest") + || has_package("dependencies", "vitest"), + skip_tsdown: has_package("peerDependencies", "tsdown") + || has_package("dependencies", "tsdown"), + } +} + /// Result of rewriting imports in a file #[derive(Debug)] struct RewriteResult { @@ -323,8 +404,28 @@ pub fn rewrite_imports_in_directory(root: &Path) -> Result = HashMap::new(); + for file_path in walk_result.files { - match rewrite_import(&file_path) { + // Find the nearest package.json for this file + let skip_packages = + if let Some(package_json_path) = find_nearest_package_json(&file_path, root) { + skip_packages_cache + .entry(package_json_path.clone()) + .or_insert_with(|| get_skip_packages_from_package_json(&package_json_path)) + .clone() + } else { + SkipPackages::default() + }; + + // If all packages are in peerDeps for this file's package, skip it + if skip_packages.all_skipped() { + result.unchanged_files.push(file_path); + continue; + } + + match rewrite_import(&file_path, &skip_packages) { Ok(rewrite_result) => { if rewrite_result.updated { // Write the modified content back @@ -350,41 +451,66 @@ pub fn rewrite_imports_in_directory(root: &Path) -> Result Result { +fn rewrite_import(file_path: &Path, skip_packages: &SkipPackages) -> Result { // Read the file let content = std::fs::read_to_string(file_path)?; // Rewrite the imports - rewrite_import_content(&content) + rewrite_import_content(&content, skip_packages) } /// Rewrite imports in content from vite/vitest to @voidzero-dev/vite-plus /// /// This is the internal function that performs the actual rewrite using ast-grep. -fn rewrite_import_content(content: &str) -> Result { - let (new_content, updated) = ast_grep::apply_rules(content, REWRITE_IMPORT_RULES)?; +/// Packages that are in peerDependencies or dependencies will be skipped. +fn rewrite_import_content( + content: &str, + skip_packages: &SkipPackages, +) -> Result { + let mut new_content = content.to_string(); + let mut updated = false; + + // Apply vite rules if not skipped + if !skip_packages.skip_vite { + let (vite_content, vite_updated) = ast_grep::apply_rules(&new_content, REWRITE_VITE_RULES)?; + if vite_updated { + new_content = vite_content; + updated = true; + } + } + + // Apply vitest rules if not skipped + if !skip_packages.skip_vitest { + let (vitest_content, vitest_updated) = + ast_grep::apply_rules(&new_content, REWRITE_VITEST_RULES)?; + if vitest_updated { + new_content = vitest_content; + updated = true; + } + } + + // Apply tsdown rules if not skipped + if !skip_packages.skip_tsdown { + let (tsdown_content, tsdown_updated) = + ast_grep::apply_rules(&new_content, REWRITE_TSDOWN_RULES)?; + if tsdown_updated { + new_content = tsdown_content; + updated = true; + } + } + Ok(RewriteResult { content: new_content, updated }) } @@ -404,7 +530,7 @@ export default defineConfig({ plugins: [], });"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -424,7 +550,7 @@ export default defineConfig({ plugins: [], });"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -446,7 +572,7 @@ export default defineConfig({ }, });"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -469,7 +595,7 @@ export default defineConfig({ plugins: [react()], });"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -490,7 +616,7 @@ export default defineConfig({ plugins: [], });"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(!result.updated); assert_eq!(result.content, vite_config); } @@ -515,7 +641,7 @@ export default defineConfig({{ .unwrap(); // Run the rewrite - let result = rewrite_import(&vite_config_path).unwrap(); + let result = rewrite_import(&vite_config_path, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( @@ -538,7 +664,7 @@ describe('test', () => { }); });"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -558,7 +684,7 @@ describe('test', () => { describe('test', () => {});"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -574,7 +700,7 @@ describe('test', () => {});"# export default page;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -590,7 +716,7 @@ export default page;"# export default page;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -606,7 +732,7 @@ export default page;"# export default playwright;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -622,7 +748,7 @@ export default playwright;"# export default playwright;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -638,7 +764,7 @@ export default playwright;"# export default context;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -654,7 +780,7 @@ export default context;"# export default something;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -670,7 +796,7 @@ export default something;"# export default preview;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -686,7 +812,7 @@ export default preview;"# export default something;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -702,7 +828,7 @@ export default something;"# export default webdriverio;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -718,7 +844,7 @@ export default webdriverio;"# export default something;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -734,7 +860,7 @@ export default something;"# export default ModuleRunner;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -750,7 +876,7 @@ export default ModuleRunner;"# export default ModuleRunner;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -767,7 +893,7 @@ export default ModuleRunner;"# export default startVitest;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -781,7 +907,7 @@ export default startVitest;"# export default somePlugin;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -797,7 +923,7 @@ export default somePlugin;"# export default startVitest;"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -822,7 +948,7 @@ export default defineConfig({ plugins: [react()], });"#; - let result = rewrite_import_content(vite_config).unwrap(); + let result = rewrite_import_content(vite_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -984,7 +1110,7 @@ describe('app', () => { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1004,7 +1130,7 @@ describe('app', () => { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1024,7 +1150,7 @@ describe('app', () => { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1044,7 +1170,7 @@ describe('app', () => { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1064,7 +1190,7 @@ describe('app', () => { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1084,7 +1210,7 @@ describe('app', () => { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1104,7 +1230,7 @@ describe('app', () => { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1124,7 +1250,7 @@ describe('app', () => { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1144,7 +1270,7 @@ describe('app', () => { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1164,7 +1290,7 @@ describe('app', () => { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1184,7 +1310,7 @@ describe('app', () => { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1215,7 +1341,7 @@ declare module 'vitest' { export default defineConfig({});"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1246,7 +1372,7 @@ export default defineConfig({});"# } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(!result.updated); assert_eq!(result.content, content); } @@ -1277,7 +1403,7 @@ declare module '@vitest/browser' { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1315,7 +1441,7 @@ declare module '@voidzero-dev/vite-plus/test/browser' { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1335,7 +1461,7 @@ declare module '@voidzero-dev/vite-plus/test/browser' { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1355,7 +1481,7 @@ declare module '@voidzero-dev/vite-plus/test/browser' { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1375,7 +1501,7 @@ declare module '@voidzero-dev/vite-plus/test/browser' { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1407,7 +1533,7 @@ declare module '@voidzero-dev/vite-plus/test/browser' { } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1439,7 +1565,7 @@ export default defineConfig({ entry: 'src/index.ts', });"#; - let result = rewrite_import_content(tsdown_config).unwrap(); + let result = rewrite_import_content(tsdown_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1459,7 +1585,7 @@ export default defineConfig({ entry: "src/index.ts", });"#; - let result = rewrite_import_content(tsdown_config).unwrap(); + let result = rewrite_import_content(tsdown_config, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1479,7 +1605,7 @@ export default defineConfig({ } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1499,7 +1625,7 @@ export default defineConfig({ } }"#; - let result = rewrite_import_content(content).unwrap(); + let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); assert!(result.updated); assert_eq!( result.content, @@ -1510,4 +1636,434 @@ export default defineConfig({ }"# ); } + + // ======================== + // PeerDependencies Tests + // ======================== + + #[test] + fn test_skip_vite_when_peer_dependency() { + // When vite is a peerDependency, vite imports should NOT be rewritten + let content = r#"import { defineConfig } from 'vite'; +import { describe } from 'vitest'; + +export default defineConfig({});"#; + + let skip_packages = + SkipPackages { skip_vite: true, skip_vitest: false, skip_tsdown: false }; + + let result = rewrite_import_content(content, &skip_packages).unwrap(); + assert!(result.updated); + // vite import should NOT be rewritten, vitest import SHOULD be rewritten + assert_eq!( + result.content, + r#"import { defineConfig } from 'vite'; +import { describe } from '@voidzero-dev/vite-plus/test'; + +export default defineConfig({});"# + ); + } + + #[test] + fn test_skip_vitest_when_peer_dependency() { + // When vitest is a peerDependency, vitest imports should NOT be rewritten + let content = r#"import { defineConfig } from 'vite'; +import { describe } from 'vitest'; + +export default defineConfig({});"#; + + let skip_packages = + SkipPackages { skip_vite: false, skip_vitest: true, skip_tsdown: false }; + + let result = rewrite_import_content(content, &skip_packages).unwrap(); + assert!(result.updated); + // vite import SHOULD be rewritten, vitest import should NOT be rewritten + assert_eq!( + result.content, + r#"import { defineConfig } from '@voidzero-dev/vite-plus'; +import { describe } from 'vitest'; + +export default defineConfig({});"# + ); + } + + #[test] + fn test_skip_all_when_all_peer_dependencies() { + // When all packages are peerDependencies, nothing should be rewritten + let content = r#"import { defineConfig } from 'vite'; +import { describe } from 'vitest'; +import { build } from 'tsdown'; + +export default defineConfig({});"#; + + let skip_packages = SkipPackages { skip_vite: true, skip_vitest: true, skip_tsdown: true }; + + let result = rewrite_import_content(content, &skip_packages).unwrap(); + assert!(!result.updated); + assert_eq!(result.content, content); + } + + #[test] + fn test_skip_packages_all_skipped() { + let skip_all = SkipPackages { skip_vite: true, skip_vitest: true, skip_tsdown: true }; + assert!(skip_all.all_skipped()); + + let skip_some = SkipPackages { skip_vite: true, skip_vitest: false, skip_tsdown: true }; + assert!(!skip_some.all_skipped()); + + let skip_none = SkipPackages::default(); + assert!(!skip_none.all_skipped()); + } + + #[test] + fn test_get_skip_packages_from_package_json_with_vite_peer_dep() { + use std::fs; + + let temp = tempdir().unwrap(); + + // Create package.json with vite as peerDependency + let pkg_json = r#"{ + "name": "my-vite-plugin", + "peerDependencies": { + "vite": "^5.0.0" + } +}"#; + let package_json_path = temp.path().join("package.json"); + fs::write(&package_json_path, pkg_json).unwrap(); + + let skip = get_skip_packages_from_package_json(&package_json_path); + assert!(skip.skip_vite); + assert!(!skip.skip_vitest); + assert!(!skip.skip_tsdown); + } + + #[test] + fn test_get_skip_packages_from_package_json_with_all_peer_deps() { + use std::fs; + + let temp = tempdir().unwrap(); + + let pkg_json = r#"{ + "name": "my-plugin", + "peerDependencies": { + "vite": "^5.0.0", + "vitest": "^1.0.0", + "tsdown": "^1.0.0" + } +}"#; + let package_json_path = temp.path().join("package.json"); + fs::write(&package_json_path, pkg_json).unwrap(); + + let skip = get_skip_packages_from_package_json(&package_json_path); + assert!(skip.skip_vite); + assert!(skip.skip_vitest); + assert!(skip.skip_tsdown); + assert!(skip.all_skipped()); + } + + #[test] + fn test_get_skip_packages_from_package_json_with_vite_dependency() { + use std::fs; + + let temp = tempdir().unwrap(); + + // vite in dependencies should also skip rewriting + let pkg_json = r#"{ + "name": "my-app", + "dependencies": { + "vite": "^5.0.0" + } +}"#; + let package_json_path = temp.path().join("package.json"); + fs::write(&package_json_path, pkg_json).unwrap(); + + let skip = get_skip_packages_from_package_json(&package_json_path); + assert!(skip.skip_vite); // NOW skips because vite is in dependencies + assert!(!skip.skip_vitest); + assert!(!skip.skip_tsdown); + } + + #[test] + fn test_get_skip_packages_from_package_json_no_file() { + let temp = tempdir().unwrap(); + + // No package.json created - should return default (no skipping) + let package_json_path = temp.path().join("package.json"); + let skip = get_skip_packages_from_package_json(&package_json_path); + assert!(!skip.skip_vite); + assert!(!skip.skip_vitest); + assert!(!skip.skip_tsdown); + } + + #[test] + fn test_get_skip_packages_from_package_json_no_deps() { + use std::fs; + + let temp = tempdir().unwrap(); + + // Package with no dependencies at all + let pkg_json = r#"{ + "name": "my-app" +}"#; + let package_json_path = temp.path().join("package.json"); + fs::write(&package_json_path, pkg_json).unwrap(); + + let skip = get_skip_packages_from_package_json(&package_json_path); + assert!(!skip.skip_vite); + assert!(!skip.skip_vitest); + assert!(!skip.skip_tsdown); + } + + #[test] + fn test_get_skip_packages_mixed_peer_and_regular_deps() { + use std::fs; + + let temp = tempdir().unwrap(); + + // vite in dependencies, vitest in peerDependencies + let pkg_json = r#"{ + "name": "my-package", + "dependencies": { + "vite": "^5.0.0" + }, + "peerDependencies": { + "vitest": "^1.0.0" + } +}"#; + let package_json_path = temp.path().join("package.json"); + fs::write(&package_json_path, pkg_json).unwrap(); + + let skip = get_skip_packages_from_package_json(&package_json_path); + assert!(skip.skip_vite); // in dependencies + assert!(skip.skip_vitest); // in peerDependencies + assert!(!skip.skip_tsdown); + } + + #[test] + fn test_rewrite_imports_in_directory_with_vite_dependency() { + use std::fs; + + let temp = tempdir().unwrap(); + + // Create package.json with vite as dependency (not peerDependency) + let pkg_json = r#"{ + "name": "my-app", + "dependencies": { + "vite": "^5.0.0" + } +}"#; + fs::write(temp.path().join("package.json"), pkg_json).unwrap(); + + // Create src directory + fs::create_dir(temp.path().join("src")).unwrap(); + + // Create source file with vite and vitest imports + let original_content = r#"import { defineConfig } from 'vite'; +import { describe } from 'vitest'; + +export default defineConfig({});"#; + fs::write(temp.path().join("src/index.ts"), original_content).unwrap(); + + // Run the batch rewrite + let result = rewrite_imports_in_directory(temp.path()).unwrap(); + + // File should be modified (vitest was rewritten) + assert_eq!(result.modified_files.len(), 1); + assert!(result.errors.is_empty()); + + // Verify vite import NOT rewritten (in dependencies), vitest IS rewritten + let content = fs::read_to_string(temp.path().join("src/index.ts")).unwrap(); + assert_eq!( + content, + r#"import { defineConfig } from 'vite'; +import { describe } from '@voidzero-dev/vite-plus/test'; + +export default defineConfig({});"# + ); + } + + #[test] + fn test_rewrite_imports_in_directory_with_peer_deps() { + use std::fs; + + let temp = tempdir().unwrap(); + + // Create package.json with vite as peerDependency + let pkg_json = r#"{ + "name": "my-vite-plugin", + "peerDependencies": { + "vite": "^5.0.0" + } +}"#; + fs::write(temp.path().join("package.json"), pkg_json).unwrap(); + + // Create src directory + fs::create_dir(temp.path().join("src")).unwrap(); + + // Create source file with vite and vitest imports + let original_content = r#"import { defineConfig } from 'vite'; +import { describe } from 'vitest'; + +export default defineConfig({});"#; + fs::write(temp.path().join("src/index.ts"), original_content).unwrap(); + + // Run the batch rewrite + let result = rewrite_imports_in_directory(temp.path()).unwrap(); + + // File should be modified (vitest was rewritten) + assert_eq!(result.modified_files.len(), 1); + assert!(result.errors.is_empty()); + + // Verify vite import NOT rewritten, vitest IS rewritten + let content = fs::read_to_string(temp.path().join("src/index.ts")).unwrap(); + assert_eq!( + content, + r#"import { defineConfig } from 'vite'; +import { describe } from '@voidzero-dev/vite-plus/test'; + +export default defineConfig({});"# + ); + } + + #[test] + fn test_rewrite_imports_skips_file_when_all_peer_deps() { + use std::fs; + + let temp = tempdir().unwrap(); + + // Create package.json with all packages as peerDependencies + let pkg_json = r#"{ + "name": "my-plugin", + "peerDependencies": { + "vite": "^5.0.0", + "vitest": "^1.0.0", + "tsdown": "^1.0.0" + } +}"#; + fs::write(temp.path().join("package.json"), pkg_json).unwrap(); + + // Create source file + let original_content = r#"import { defineConfig } from 'vite'; +import { describe } from 'vitest'; +import { build } from 'tsdown';"#; + fs::write(temp.path().join("index.ts"), original_content).unwrap(); + + // Run the batch rewrite + let result = rewrite_imports_in_directory(temp.path()).unwrap(); + + // File should be unchanged (all skipped) + assert!(result.modified_files.is_empty()); + assert_eq!(result.unchanged_files.len(), 1); + + // Verify content unchanged + let content = fs::read_to_string(temp.path().join("index.ts")).unwrap(); + assert_eq!(content, original_content); + } + + #[test] + fn test_find_nearest_package_json() { + use std::fs; + + let temp = tempdir().unwrap(); + + // Create monorepo structure + fs::create_dir_all(temp.path().join("packages/vite-plugin/src")).unwrap(); + fs::create_dir_all(temp.path().join("packages/app/src")).unwrap(); + + // Root package.json (no peerDeps) + fs::write(temp.path().join("package.json"), r#"{"name": "monorepo"}"#).unwrap(); + + // vite-plugin package.json (has vite in peerDeps) + fs::write( + temp.path().join("packages/vite-plugin/package.json"), + r#"{"name": "vite-plugin", "peerDependencies": {"vite": "^5.0.0"}}"#, + ) + .unwrap(); + + // app package.json (no peerDeps) + fs::write(temp.path().join("packages/app/package.json"), r#"{"name": "app"}"#).unwrap(); + + // Test finding package.json from vite-plugin/src/index.ts + let file_path = temp.path().join("packages/vite-plugin/src/index.ts"); + let result = find_nearest_package_json(&file_path, temp.path()); + assert_eq!(result, Some(temp.path().join("packages/vite-plugin/package.json"))); + + // Test finding package.json from app/src/index.ts + let file_path = temp.path().join("packages/app/src/index.ts"); + let result = find_nearest_package_json(&file_path, temp.path()); + assert_eq!(result, Some(temp.path().join("packages/app/package.json"))); + + // Test finding package.json from root level file + let file_path = temp.path().join("vite.config.ts"); + let result = find_nearest_package_json(&file_path, temp.path()); + assert_eq!(result, Some(temp.path().join("package.json"))); + } + + #[test] + fn test_rewrite_imports_monorepo_different_peer_deps() { + use std::fs; + + let temp = tempdir().unwrap(); + + // Create monorepo structure + fs::create_dir_all(temp.path().join("packages/vite-plugin/src")).unwrap(); + fs::create_dir_all(temp.path().join("packages/app/src")).unwrap(); + + // Root package.json (no peerDeps) + fs::write(temp.path().join("package.json"), r#"{"name": "monorepo"}"#).unwrap(); + + // vite-plugin package.json (has vite in peerDeps) + fs::write( + temp.path().join("packages/vite-plugin/package.json"), + r#"{"name": "vite-plugin", "peerDependencies": {"vite": "^5.0.0"}}"#, + ) + .unwrap(); + + // app package.json (no peerDeps) + fs::write(temp.path().join("packages/app/package.json"), r#"{"name": "app"}"#).unwrap(); + + // vite-plugin source file with vite and vitest imports + fs::write( + temp.path().join("packages/vite-plugin/src/index.ts"), + r#"import { defineConfig } from 'vite'; +import { describe } from 'vitest'; +export default defineConfig({});"#, + ) + .unwrap(); + + // app source file with vite and vitest imports + fs::write( + temp.path().join("packages/app/src/index.ts"), + r#"import { defineConfig } from 'vite'; +import { describe } from 'vitest'; +export default defineConfig({});"#, + ) + .unwrap(); + + // Run the batch rewrite + let result = rewrite_imports_in_directory(temp.path()).unwrap(); + + // Both files should be modified + assert_eq!(result.modified_files.len(), 2); + + // vite-plugin: vite NOT rewritten (has peerDep), vitest IS rewritten + let vite_plugin_content = + fs::read_to_string(temp.path().join("packages/vite-plugin/src/index.ts")).unwrap(); + assert_eq!( + vite_plugin_content, + r#"import { defineConfig } from 'vite'; +import { describe } from '@voidzero-dev/vite-plus/test'; +export default defineConfig({});"# + ); + + // app: vite IS rewritten (no peerDep), vitest IS rewritten + let app_content = + fs::read_to_string(temp.path().join("packages/app/src/index.ts")).unwrap(); + assert_eq!( + app_content, + r#"import { defineConfig } from '@voidzero-dev/vite-plus'; +import { describe } from '@voidzero-dev/vite-plus/test'; +export default defineConfig({});"# + ); + } } diff --git a/ecosystem-ci/.gitignore b/ecosystem-ci/.gitignore index e9a52ff72a..d809c2f203 100644 --- a/ecosystem-ci/.gitignore +++ b/ecosystem-ci/.gitignore @@ -3,3 +3,4 @@ skeleton rollipop frm-stack vue-mini +vite-plugin-react diff --git a/ecosystem-ci/repo.json b/ecosystem-ci/repo.json index aeb01ee43a..5006a8d9bb 100644 --- a/ecosystem-ci/repo.json +++ b/ecosystem-ci/repo.json @@ -23,5 +23,10 @@ "repository": "https://github.com/vue-mini/vue-mini.git", "branch": "master", "hash": "c51332662993dde44f665822bdea94cd0abf368b" + }, + "vite-plugin-react": { + "repository": "https://github.com/vitejs/vite-plugin-react.git", + "branch": "main", + "hash": "0d3912b73d3aa1dc8f64619c82b3dacb0769e49e" } } diff --git a/packages/global/snap-tests/migration-monorepo-pnpm/package.json b/packages/global/snap-tests/migration-monorepo-pnpm/package.json index 823813feef..73c000685c 100644 --- a/packages/global/snap-tests/migration-monorepo-pnpm/package.json +++ b/packages/global/snap-tests/migration-monorepo-pnpm/package.json @@ -3,8 +3,7 @@ "version": "1.0.0", "packageManager": "pnpm@10.18.0", "dependencies": { - "testnpm2": "1.0.0", - "vite": "catalog:" + "testnpm2": "1.0.0" }, "resolutions": { "vue": "3.5.25", @@ -12,6 +11,7 @@ "vitest": "catalog:" }, "devDependencies": { + "vite": "catalog:", "vitest": "catalog:", "oxlint": "catalog:", "oxfmt": "catalog:" diff --git a/packages/global/snap-tests/migration-monorepo-pnpm/snap.txt b/packages/global/snap-tests/migration-monorepo-pnpm/snap.txt index e9c488ed8f..5c2faddf4c 100644 --- a/packages/global/snap-tests/migration-monorepo-pnpm/snap.txt +++ b/packages/global/snap-tests/migration-monorepo-pnpm/snap.txt @@ -52,13 +52,13 @@ cat: .oxfmtrc.json: No such file or directory "version": "1.0.0", "packageManager": "pnpm@", "dependencies": { - "testnpm2": "1.0.0", - "vite": "catalog:" + "testnpm2": "1.0.0" }, "resolutions": { "vue": "3.5.25" }, "devDependencies": { + "vite": "catalog:", "vitest": "catalog:", "@voidzero-dev/vite-plus": "catalog:" }, diff --git a/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/package.json b/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/package.json new file mode 100644 index 0000000000..e9aeb67550 --- /dev/null +++ b/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/package.json @@ -0,0 +1,3 @@ +{ + "name": "migration-monorepo-skip-vite-peer-dependency" +} diff --git a/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/packages/vite-plugin/package.json b/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/packages/vite-plugin/package.json new file mode 100644 index 0000000000..9613d932cf --- /dev/null +++ b/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/packages/vite-plugin/package.json @@ -0,0 +1,6 @@ +{ + "name": "my-vite-plugin", + "peerDependencies": { + "vite": "^6.0.0" + } +} diff --git a/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/packages/vite-plugin/src/index.ts b/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/packages/vite-plugin/src/index.ts new file mode 100644 index 0000000000..aa72e9b40d --- /dev/null +++ b/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/packages/vite-plugin/src/index.ts @@ -0,0 +1,21 @@ +import { defineConfig, type Plugin } from 'vite'; +import { describe, it, expect } from 'vitest'; + +export function myVitePlugin(): Plugin { + return { + name: 'my-vite-plugin', + configResolved(config) { + console.log(config); + }, + }; +} + +describe('myVitePlugin', () => { + it('should work', () => { + expect(myVitePlugin()).toBeDefined(); + }); +}); + +export default defineConfig({ + plugins: [myVitePlugin()], +}); diff --git a/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/pnpm-workspace.yaml b/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/pnpm-workspace.yaml new file mode 100644 index 0000000000..924b55f42e --- /dev/null +++ b/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - packages/* diff --git a/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/snap.txt b/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/snap.txt new file mode 100644 index 0000000000..c463a04291 --- /dev/null +++ b/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/snap.txt @@ -0,0 +1,53 @@ +> vp migration # migration should check each package's peerDependencies +┌ Vite+ Migration +│ +● pnpm@latest installing... +│ +● pnpm@ installed +│ +◆ ✅ Rewrote imports in 1 file(s) +│ +● packages/vite-plugin/src/index.ts +│ +└ ✨ Migration completed! + + +> cat packages/vite-plugin/src/index.ts # vite-plugin has vite in peerDeps: vite NOT rewritten, vitest rewritten +import { defineConfig, type Plugin } from 'vite'; +import { describe, it, expect } from '@voidzero-dev/vite-plus/test'; + +export function myVitePlugin(): Plugin { + return { + name: 'my-vite-plugin', + configResolved(config) { + console.log(config); + }, + }; +} + +describe('myVitePlugin', () => { + it('should work', () => { + expect(myVitePlugin()).toBeDefined(); + }); +}); + +export default defineConfig({ + plugins: [myVitePlugin()], +}); + +> cat package.json # check root package.json (no peerDependencies) +{ + "name": "migration-monorepo-skip-vite-peer-dependency", + "devDependencies": { + "@voidzero-dev/vite-plus": "catalog:" + }, + "packageManager": "pnpm@" +} + +> cat packages/vite-plugin/package.json # has vite in peerDependencies +{ + "name": "my-vite-plugin", + "peerDependencies": { + "vite": "^6.0.0" + } +} diff --git a/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/steps.json b/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/steps.json new file mode 100644 index 0000000000..579a5a0380 --- /dev/null +++ b/packages/global/snap-tests/migration-monorepo-skip-vite-peer-dependency/steps.json @@ -0,0 +1,11 @@ +{ + "env": { + "VITE_DISABLE_AUTO_INSTALL": "1" + }, + "commands": [ + "vp migration # migration should check each package's peerDependencies", + "cat packages/vite-plugin/src/index.ts # vite-plugin has vite in peerDeps: vite NOT rewritten, vitest rewritten", + "cat package.json # check root package.json (no peerDependencies)", + "cat packages/vite-plugin/package.json # has vite in peerDependencies" + ] +} diff --git a/packages/global/snap-tests/migration-monorepo-yarn4/package.json b/packages/global/snap-tests/migration-monorepo-yarn4/package.json index 98494d5553..c62f12cb89 100644 --- a/packages/global/snap-tests/migration-monorepo-yarn4/package.json +++ b/packages/global/snap-tests/migration-monorepo-yarn4/package.json @@ -3,10 +3,10 @@ "version": "1.0.0", "packageManager": "yarn@4.12.0", "dependencies": { - "testnpm2": "1.0.0", - "vite": "catalog:" + "testnpm2": "1.0.0" }, "devDependencies": { + "vite": "catalog:", "vitest": "catalog:", "oxlint": "catalog:", "oxfmt": "catalog:" diff --git a/packages/global/snap-tests/migration-monorepo-yarn4/snap.txt b/packages/global/snap-tests/migration-monorepo-yarn4/snap.txt index b5475a2ceb..0b117d3589 100644 --- a/packages/global/snap-tests/migration-monorepo-yarn4/snap.txt +++ b/packages/global/snap-tests/migration-monorepo-yarn4/snap.txt @@ -36,10 +36,10 @@ cat: .oxlintrc.json: No such file or directory "version": "1.0.0", "packageManager": "yarn@", "dependencies": { - "testnpm2": "1.0.0", - "vite": "catalog:" + "testnpm2": "1.0.0" }, "devDependencies": { + "vite": "catalog:", "vitest": "catalog:", "@voidzero-dev/vite-plus": "catalog:" }, diff --git a/packages/global/snap-tests/migration-skip-vite-dependency/package.json b/packages/global/snap-tests/migration-skip-vite-dependency/package.json new file mode 100644 index 0000000000..cc2ea31195 --- /dev/null +++ b/packages/global/snap-tests/migration-skip-vite-dependency/package.json @@ -0,0 +1,6 @@ +{ + "name": "migration-skip-vite-dependency", + "dependencies": { + "vite": "^6.0.0" + } +} diff --git a/packages/global/snap-tests/migration-skip-vite-dependency/snap.txt b/packages/global/snap-tests/migration-skip-vite-dependency/snap.txt new file mode 100644 index 0000000000..a1e661accd --- /dev/null +++ b/packages/global/snap-tests/migration-skip-vite-dependency/snap.txt @@ -0,0 +1,56 @@ +> vp migration # migration should skip rewriting vite imports when vite is in dependencies +┌ Vite+ Migration +│ +● Using default package manager: pnpm +│ +● pnpm@latest installing... +│ +● pnpm@ installed +│ +◆ ✅ Rewrote imports in 1 file(s) +│ +● src/index.ts +│ +└ ✨ Migration completed! + + +> cat src/index.ts # vite imports should NOT be rewritten, vitest imports SHOULD be rewritten +import { defineConfig, type Plugin } from 'vite'; +import { describe, it, expect } from '@voidzero-dev/vite-plus/test'; + +export function myApp(): Plugin { + return { + name: 'my-app', + configResolved(config) { + console.log(config); + }, + }; +} + +describe('myApp', () => { + it('should work', () => { + expect(myApp()).toBeDefined(); + }); +}); + +export default defineConfig({ + plugins: [myApp()], +}); + +> cat package.json # check package.json +{ + "name": "migration-skip-vite-dependency", + "dependencies": { + "vite": "npm:@voidzero-dev/vite-plus-core@latest" + }, + "pnpm": { + "overrides": { + "vite": "npm:@voidzero-dev/vite-plus-core@latest", + "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + } + }, + "devDependencies": { + "@voidzero-dev/vite-plus": "latest" + }, + "packageManager": "pnpm@" +} diff --git a/packages/global/snap-tests/migration-skip-vite-dependency/src/index.ts b/packages/global/snap-tests/migration-skip-vite-dependency/src/index.ts new file mode 100644 index 0000000000..32e61aea0c --- /dev/null +++ b/packages/global/snap-tests/migration-skip-vite-dependency/src/index.ts @@ -0,0 +1,21 @@ +import { defineConfig, type Plugin } from 'vite'; +import { describe, it, expect } from 'vitest'; + +export function myApp(): Plugin { + return { + name: 'my-app', + configResolved(config) { + console.log(config); + }, + }; +} + +describe('myApp', () => { + it('should work', () => { + expect(myApp()).toBeDefined(); + }); +}); + +export default defineConfig({ + plugins: [myApp()], +}); diff --git a/packages/global/snap-tests/migration-skip-vite-dependency/steps.json b/packages/global/snap-tests/migration-skip-vite-dependency/steps.json new file mode 100644 index 0000000000..f6a840b91b --- /dev/null +++ b/packages/global/snap-tests/migration-skip-vite-dependency/steps.json @@ -0,0 +1,10 @@ +{ + "env": { + "VITE_DISABLE_AUTO_INSTALL": "1" + }, + "commands": [ + "vp migration # migration should skip rewriting vite imports when vite is in dependencies", + "cat src/index.ts # vite imports should NOT be rewritten, vitest imports SHOULD be rewritten", + "cat package.json # check package.json" + ] +} diff --git a/packages/global/snap-tests/migration-skip-vite-peer-dependency/package.json b/packages/global/snap-tests/migration-skip-vite-peer-dependency/package.json new file mode 100644 index 0000000000..13dc63d527 --- /dev/null +++ b/packages/global/snap-tests/migration-skip-vite-peer-dependency/package.json @@ -0,0 +1,6 @@ +{ + "name": "migration-skip-vite-peer-dependency", + "peerDependencies": { + "vite": "^6.0.0" + } +} diff --git a/packages/global/snap-tests/migration-skip-vite-peer-dependency/snap.txt b/packages/global/snap-tests/migration-skip-vite-peer-dependency/snap.txt new file mode 100644 index 0000000000..0e33b16e3f --- /dev/null +++ b/packages/global/snap-tests/migration-skip-vite-peer-dependency/snap.txt @@ -0,0 +1,56 @@ +> vp migration # migration should skip rewriting vite imports when vite is in peerDependencies +┌ Vite+ Migration +│ +● Using default package manager: pnpm +│ +● pnpm@latest installing... +│ +● pnpm@ installed +│ +◆ ✅ Rewrote imports in 1 file(s) +│ +● src/index.ts +│ +└ ✨ Migration completed! + + +> cat src/index.ts # vite imports should NOT be rewritten, vitest imports SHOULD be rewritten +import { defineConfig, type Plugin } from 'vite'; +import { describe, it, expect } from '@voidzero-dev/vite-plus/test'; + +export function myVitePlugin(): Plugin { + return { + name: 'my-vite-plugin', + configResolved(config) { + console.log(config); + }, + }; +} + +describe('myVitePlugin', () => { + it('should work', () => { + expect(myVitePlugin()).toBeDefined(); + }); +}); + +export default defineConfig({ + plugins: [myVitePlugin()], +}); + +> cat package.json # check package.json +{ + "name": "migration-skip-vite-peer-dependency", + "peerDependencies": { + "vite": "^6.0.0" + }, + "pnpm": { + "overrides": { + "vite": "npm:@voidzero-dev/vite-plus-core@latest", + "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + } + }, + "devDependencies": { + "@voidzero-dev/vite-plus": "latest" + }, + "packageManager": "pnpm@" +} diff --git a/packages/global/snap-tests/migration-skip-vite-peer-dependency/src/index.ts b/packages/global/snap-tests/migration-skip-vite-peer-dependency/src/index.ts new file mode 100644 index 0000000000..aa72e9b40d --- /dev/null +++ b/packages/global/snap-tests/migration-skip-vite-peer-dependency/src/index.ts @@ -0,0 +1,21 @@ +import { defineConfig, type Plugin } from 'vite'; +import { describe, it, expect } from 'vitest'; + +export function myVitePlugin(): Plugin { + return { + name: 'my-vite-plugin', + configResolved(config) { + console.log(config); + }, + }; +} + +describe('myVitePlugin', () => { + it('should work', () => { + expect(myVitePlugin()).toBeDefined(); + }); +}); + +export default defineConfig({ + plugins: [myVitePlugin()], +}); diff --git a/packages/global/snap-tests/migration-skip-vite-peer-dependency/steps.json b/packages/global/snap-tests/migration-skip-vite-peer-dependency/steps.json new file mode 100644 index 0000000000..187b0b5c5a --- /dev/null +++ b/packages/global/snap-tests/migration-skip-vite-peer-dependency/steps.json @@ -0,0 +1,10 @@ +{ + "env": { + "VITE_DISABLE_AUTO_INSTALL": "1" + }, + "commands": [ + "vp migration # migration should skip rewriting vite imports when vite is in peerDependencies", + "cat src/index.ts # vite imports should NOT be rewritten, vitest imports SHOULD be rewritten", + "cat package.json # check package.json" + ] +} diff --git a/packages/global/src/utils/workspace.ts b/packages/global/src/utils/workspace.ts index aac837eba8..891877c1d3 100644 --- a/packages/global/src/utils/workspace.ts +++ b/packages/global/src/utils/workspace.ts @@ -113,6 +113,7 @@ export function discoverWorkspacePackages( { absolute: false, cwd: rootDir, + ignore: ['**/node_modules/**'], }, ); for (const packageJsonRelativePath of packageJsonRelativePaths) {