diff --git a/.github/scripts/upgrade-deps.ts b/.github/scripts/upgrade-deps.ts index 3f7d4ac1ad..bc478f4914 100644 --- a/.github/scripts/upgrade-deps.ts +++ b/.github/scripts/upgrade-deps.ts @@ -155,8 +155,13 @@ async function updatePnpmWorkspace(versions: PnpmWorkspaceVersions): Promise { - const filePath = path.join(ROOT, 'packages/test/package.json'); - const pkg: PackageJson = readJsonFile(filePath); - const devDependencies = pkg.devDependencies; - if (!devDependencies) { - throw new Error('packages/test/package.json is missing devDependencies'); - } - - // Update all @vitest/* devDependencies - for (const dep of Object.keys(devDependencies)) { - if (dep.startsWith('@vitest/')) { - devDependencies[dep] = vitestVersion; - } - } - - // Update vitest-dev devDependency - if (devDependencies['vitest-dev']) { - devDependencies['vitest-dev'] = `^${vitestVersion}`; - } - - // Update @vitest/ui peerDependency if present - if (pkg.peerDependencies?.['@vitest/ui']) { - pkg.peerDependencies['@vitest/ui'] = vitestVersion; - } - - fs.writeFileSync(filePath, JSON.stringify(pkg, null, 2) + '\n'); - console.log('Updated packages/test/package.json'); -} - // ============ Update packages/core/package.json ============ async function updateCorePackage(devtoolsVersion: string): Promise { const filePath = path.join(ROOT, 'packages/core/package.json'); @@ -430,7 +405,6 @@ await updatePnpmWorkspace({ oxcParser: oxcParserVersion, oxcTransform: oxcTransformVersion, }); -await updateTestPackage(vitestVersion); await updateCorePackage(devtoolsVersion); writeMetaFiles(); diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 03c3830ca3..77a73cf9a5 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -108,9 +108,27 @@ jobs: - name: Pack packages into tgz run: | mkdir -p tmp/tgz + # Pack core and CLI normally (version stays at 0.0.0). cd packages/core && pnpm pack --pack-destination ../../tmp/tgz && cd ../.. - cd packages/test && pnpm pack --pack-destination ../../tmp/tgz && cd ../.. cd packages/cli && pnpm pack --pack-destination ../../tmp/tgz && cd ../.. + # Bun is uniquely strict about peer-dep resolution: + # 1. It checks the *resolved target's* package name and version + # against the peer range (vitest 4.1.5 declares peer + # `vite ^6 || ^7 || ^8`). + # 2. A file: override pointing at the vite-plus-core tgz fails + # both the name check (target is `@voidzero-dev/vite-plus-core`, + # not `vite`) and the version check (0.0.0 is outside `^6|^7|^8`). + # pnpm/npm/yarn don't enforce either, and using the same core tgz as + # the file: target for both `vite` and `@voidzero-dev/vite-plus-core` + # is the only configuration they install cleanly. See + # https://github.com/oven-sh/bun/issues/8406. + # + # Generate a sibling vite-7.99.0.tgz: a copy of the core tgz with + # `package.json#name` rewritten to "vite" and `version` to 7.99.0. + # ecosystem-ci/patch-project.ts points its vite override at this + # tgz only for bun-based projects (e.g. bun-vite-template); pnpm-, + # npm- and yarn-based ecosystem projects use the real core tgz. + pnpm exec tool repack-vite-tgz tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz tmp/tgz/vite-7.99.0.tgz vite 7.99.0 # Copy vp binary for e2e-test job (findVpBinary expects it in target/) cp target/${{ matrix.target }}/release/vp tmp/tgz/vp 2>/dev/null || cp target/${{ matrix.target }}/release/vp.exe tmp/tgz/vp.exe 2>/dev/null || true cp target/${{ matrix.target }}/release/vp-shim.exe tmp/tgz/vp-shim.exe 2>/dev/null || true diff --git a/.github/workflows/prepare_release.yml b/.github/workflows/prepare_release.yml index a12f0987e2..59b722b05a 100644 --- a/.github/workflows/prepare_release.yml +++ b/.github/workflows/prepare_release.yml @@ -54,7 +54,6 @@ jobs: } update_json packages/cli/package.json update_json packages/core/package.json - update_json packages/test/package.json update_toml packages/cli/binding/Cargo.toml update_toml crates/vite_global_cli/Cargo.toml diff --git a/.github/workflows/publish-to-pkg.pr.new.yml b/.github/workflows/publish-to-pkg.pr.new.yml index b75317c9aa..620c9170b5 100644 --- a/.github/workflows/publish-to-pkg.pr.new.yml +++ b/.github/workflows/publish-to-pkg.pr.new.yml @@ -136,5 +136,4 @@ jobs: './packages/cli/cli-npm/*' \ './packages/cli' \ './packages/core' \ - './packages/prompts' \ - './packages/test' + './packages/prompts' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1cf037db85..cdbcf45e06 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -157,7 +157,6 @@ jobs: - name: Publish run: | pnpm publish --filter=./packages/core --tag latest --access public --no-git-checks - pnpm publish --filter=./packages/test --tag latest --access public --no-git-checks pnpm publish --filter=./packages/cli --tag latest --access public --no-git-checks - name: Create release body @@ -173,7 +172,6 @@ jobs: ### Published Packages - \`@voidzero-dev/vite-plus-core@${VERSION}\` - - \`@voidzero-dev/vite-plus-test@${VERSION}\` - \`vite-plus@${VERSION}\` ### Installation @@ -222,7 +220,6 @@ jobs: **Published Packages:** • @voidzero-dev/vite-plus-core@${{ env.VERSION }} - • @voidzero-dev/vite-plus-test@${{ env.VERSION }} • vite-plus@${{ env.VERSION }} **Install:** diff --git a/.github/workflows/test-vp-create.yml b/.github/workflows/test-vp-create.yml index 50fe50e4e0..155438725f 100644 --- a/.github/workflows/test-vp-create.yml +++ b/.github/workflows/test-vp-create.yml @@ -93,9 +93,29 @@ jobs: - name: Pack packages into tgz run: | mkdir -p tmp/tgz + # Pack core and CLI normally (version stays at 0.0.0). cd packages/core && pnpm pack --pack-destination ../../tmp/tgz && cd ../.. - cd packages/test && pnpm pack --pack-destination ../../tmp/tgz && cd ../.. cd packages/cli && pnpm pack --pack-destination ../../tmp/tgz && cd ../.. + # Bun is uniquely strict about peer-dep resolution: + # 1. It checks the *resolved target's* package name and version + # against the peer range (vitest 4.1.5 declares peer + # `vite ^6 || ^7 || ^8`). + # 2. A file: override pointing at the vite-plus-core tgz fails + # both the name check (target is `@voidzero-dev/vite-plus-core`, + # not `vite`) and the version check (0.0.0 is outside `^6|^7|^8`). + # pnpm/npm/yarn don't enforce either, and using the same core tgz as + # the file: target for both `vite` and `@voidzero-dev/vite-plus-core` + # is the only configuration they install cleanly. See + # https://github.com/oven-sh/bun/issues/8406. + # + # Generate a sibling vite-7.99.0.tgz: a copy of the core tgz with + # `package.json#name` rewritten to "vite" and `version` to 7.99.0. + # Only the bun matrix entry below points its vite override at this + # alias tgz; pnpm/npm/yarn keep pointing at the real core tgz so + # pnpm's workspace resolver doesn't trip on a "vite@" + # registry lookup (the renamed tgz makes pnpm register the dep as + # vite@7.99.0 and then probe npmjs.org to validate the version). + pnpm exec tool repack-vite-tgz tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz tmp/tgz/vite-7.99.0.tgz vite 7.99.0 # Copy vp binary for test jobs cp target/x86_64-unknown-linux-gnu/release/vp tmp/tgz/vp ls -la tmp/tgz @@ -152,7 +172,12 @@ jobs: - yarn - bun env: - VP_OVERRIDE_PACKAGES: '{"vite":"file:${{ github.workspace }}/tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz","vitest":"file:${{ github.workspace }}/tmp/tgz/voidzero-dev-vite-plus-test-0.0.0.tgz","@voidzero-dev/vite-plus-core":"file:${{ github.workspace }}/tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz","@voidzero-dev/vite-plus-test":"file:${{ github.workspace }}/tmp/tgz/voidzero-dev-vite-plus-test-0.0.0.tgz"}' + # Bun's strict peer check requires the `vite` override target's tgz to be + # named "vite" with a version satisfying vitest's `peer vite ^6 || ^7 || ^8`. + # The bun matrix entry uses the masquerade tgz (vite-7.99.0.tgz). pnpm/npm/yarn + # point at the real core tgz — anything else trips a registry lookup for + # vite@ when sub-package and override targets are both file: tgz aliases. + VITE_OVERRIDE_TGZ: ${{ matrix.package-manager == 'bun' && 'vite-7.99.0.tgz' || 'voidzero-dev-vite-plus-core-0.0.0.tgz' }} VP_VERSION: 'file:${{ github.workspace }}/tmp/tgz/vite-plus-0.0.0.tgz' # Force full dependency rewriting so the library template's existing # vite-plus dep gets overridden with the local tgz @@ -185,6 +210,8 @@ jobs: - name: Run vp create ${{ matrix.template.name }} with ${{ matrix.package-manager }} working-directory: ${{ runner.temp }} + env: + VP_OVERRIDE_PACKAGES: '{"vite":"file:${{ github.workspace }}/tmp/tgz/${{ env.VITE_OVERRIDE_TGZ }}","@voidzero-dev/vite-plus-core":"file:${{ github.workspace }}/tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz"}' run: | vp create ${{ matrix.template.create-args }} \ --no-interactive \ diff --git a/README.md b/README.md index e9019fc152..c31da0cb13 100644 --- a/README.md +++ b/README.md @@ -189,12 +189,11 @@ If you are manually migrating a project to Vite+, install these dev dependencies npm install -D vite-plus @voidzero-dev/vite-plus-core@latest ``` -You need to add overrides to your package manager for `vite` and `vitest` so that other packages depending on Vite and Vitest will use the Vite+ versions: +You need to add overrides to your package manager for `vite` so that other packages depending on Vite (including Vitest) will use the Vite+ version: ```json "overrides": { - "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + "vite": "npm:@voidzero-dev/vite-plus-core@latest" } ``` @@ -203,15 +202,13 @@ If you are using `pnpm`, add this to your `pnpm-workspace.yaml`: ```yaml overrides: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest ``` Or, if you are using Yarn: ```json "resolutions": { - "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + "vite": "npm:@voidzero-dev/vite-plus-core@latest" } ``` diff --git a/crates/vite_global_cli/src/commands/version.rs b/crates/vite_global_cli/src/commands/version.rs index 6d420c1a0b..2723260eba 100644 --- a/crates/vite_global_cli/src/commands/version.rs +++ b/crates/vite_global_cli/src/commands/version.rs @@ -47,11 +47,7 @@ const TOOL_SPECS: [ToolSpec; 7] = [ package_name: "@voidzero-dev/vite-plus-core", bundled_version_key: Some("rolldown"), }, - ToolSpec { - display_name: "vitest", - package_name: "@voidzero-dev/vite-plus-test", - bundled_version_key: Some("vitest"), - }, + ToolSpec { display_name: "vitest", package_name: "vitest", bundled_version_key: None }, ToolSpec { display_name: "oxfmt", package_name: "oxfmt", bundled_version_key: None }, ToolSpec { display_name: "oxlint", package_name: "oxlint", bundled_version_key: None }, ToolSpec { diff --git a/crates/vite_migration/src/file_walker.rs b/crates/vite_migration/src/file_walker.rs index 9ab86a638c..83e4e48c7e 100644 --- a/crates/vite_migration/src/file_walker.rs +++ b/crates/vite_migration/src/file_walker.rs @@ -3,9 +3,12 @@ use std::path::{Path, PathBuf}; use ignore::WalkBuilder; use vite_error::Error; -// TODO: only support esm files for now -/// File extensions to process for import rewriting -const TS_JS_EXTENSIONS: &[&str] = &["ts", "tsx", "mts", "js", "jsx", "mjs"]; +/// File extensions to process for import rewriting. +/// +/// Includes CommonJS (`.cjs`/`.cts`) variants in addition to ESM, because +/// the legacy reverse-migration rules also cover `require('vite-plus/test/browser-*')` +/// calls that are most commonly found in `.cjs` / `vitest.config.cjs` files. +const TS_JS_EXTENSIONS: &[&str] = &["ts", "tsx", "mts", "cts", "js", "jsx", "mjs", "cjs"]; /// Result of walking TypeScript/JavaScript files #[derive(Debug)] @@ -164,7 +167,7 @@ mod tests { let result = find_ts_files(temp.path()).unwrap(); - assert_eq!(result.files.len(), 6); + assert_eq!(result.files.len(), 8); } #[test] diff --git a/crates/vite_migration/src/import_rewriter.rs b/crates/vite_migration/src/import_rewriter.rs index 175ef58491..23d68b38bd 100644 --- a/crates/vite_migration/src/import_rewriter.rs +++ b/crates/vite_migration/src/import_rewriter.rs @@ -85,7 +85,7 @@ transform: fix: $NEW_IMPORT "#; -/// ast-grep rules for rewriting vitest imports and declare module statements +/// ast-grep rules for rewriting vitest imports. /// /// This rewrites: /// - `import { ... } from 'vitest'` → `import { ... } from 'vite-plus/test'` @@ -99,17 +99,15 @@ fix: $NEW_IMPORT /// - `import { ... } from '@vitest/browser-preview/{name}'` → `import { ... } from 'vite-plus/test/browser-preview/{name}'` /// - `import { ... } from '@vitest/browser-webdriverio'` → `import { ... } from 'vite-plus/test/browser-webdriverio'` /// - `import { ... } from '@vitest/browser-webdriverio/{name}'` → `import { ... } from 'vite-plus/test/browser-webdriverio/{name}'` -/// - `declare module 'vitest' { ... }` → `declare module 'vite-plus/test' { ... }` -/// - `declare module 'vitest/config' { ... }` → `declare module 'vite-plus' { ... }` -/// - `declare module 'vitest/{name}' { ... }` → `declare module 'vite-plus/test/{name}' { ... }` -/// - `declare module '@vitest/browser' { ... }` → `declare module 'vite-plus/test/browser' { ... }` -/// - `declare module '@vitest/browser/{name}' { ... }` → `declare module 'vite-plus/test/browser/{name}' { ... }` -/// - `declare module '@vitest/browser-playwright' { ... }` → `declare module 'vite-plus/test/browser-playwright' { ... }` -/// - `declare module '@vitest/browser-playwright/{name}' { ... }` → `declare module 'vite-plus/test/browser-playwright/{name}' { ... }` -/// - `declare module '@vitest/browser-preview' { ... }` → `declare module 'vite-plus/test/browser-preview' { ... }` -/// - `declare module '@vitest/browser-preview/{name}' { ... }` → `declare module 'vite-plus/test/browser-preview/{name}' { ... }` -/// - `declare module '@vitest/browser-webdriverio' { ... }` → `declare module 'vite-plus/test/browser-webdriverio' { ... }` -/// - `declare module '@vitest/browser-webdriverio/{name}' { ... }` → `declare module 'vite-plus/test/browser-webdriverio/{name}' { ... }` +/// +/// `declare module 'vitest' { ... }` (and the subpath/`@vitest/*` variants) are +/// intentionally NOT rewritten — the `vite-plus/test*` subpaths are thin shims +/// that `export * from 'vitest'` (and the browser provider packages), so the +/// underlying type identity is upstream. Augmenting `'vite-plus/test'` would +/// only augment the shim module and would not merge into the upstream types +/// the user actually sees through their `import { expect } from 'vite-plus/test'` +/// statements. Leaving the `declare module 'vitest' { ... }` alone keeps +/// augmentations targeting the real upstream module identity. const REWRITE_VITEST_RULES: &str = r#"--- id: rewrite-vitest-config-import language: TypeScript @@ -174,70 +172,6 @@ transform: replace: vitest/ by: "vite-plus/test/" fix: $NEW_IMPORT ---- -id: rewrite-declare-module-vitest-config -language: TypeScript -rule: - pattern: $STR - kind: string - regex: ^['\"]vitest/config['\"]$ - inside: - kind: module -transform: - NEW_IMPORT: - replace: - source: $STR - replace: vitest/config - by: "vite-plus" -fix: $NEW_IMPORT ---- -id: rewrite-declare-module-vitest -language: TypeScript -rule: - pattern: $STR - kind: string - regex: ^['\"]vitest['\"]$ - inside: - kind: module -transform: - NEW_IMPORT: - replace: - source: $STR - replace: vitest - by: "vite-plus/test" -fix: $NEW_IMPORT ---- -id: rewrite-declare-module-vitest-scoped -language: TypeScript -rule: - pattern: $STR - kind: string - regex: ^['\"]@vitest/(browser-playwright|browser-preview|browser-webdriverio|browser)(/.*)?['\"]$ - inside: - kind: module -transform: - NEW_IMPORT: - replace: - source: $STR - replace: "@vitest/" - by: "vite-plus/test/" -fix: $NEW_IMPORT ---- -id: rewrite-declare-module-vitest-subpath -language: TypeScript -rule: - pattern: $STR - kind: string - regex: ^['\"]vitest/.+['\"]$ - inside: - kind: module -transform: - NEW_IMPORT: - replace: - source: $STR - replace: vitest/ - by: "vite-plus/test/" -fix: $NEW_IMPORT "#; /// ast-grep rules for rewriting tsdown imports and declare module statements @@ -1468,6 +1402,9 @@ describe('app', () => { #[test] fn test_rewrite_declare_module_vitest() { + // `declare module 'vitest'` is intentionally NOT rewritten — the + // `vite-plus/test` subpath is a thin shim that re-exports vitest's + // types, so augmentations must target the upstream module identity. let content = r#"declare module 'vitest' { interface JestAssertion { toBeCustom(): void; @@ -1475,19 +1412,15 @@ describe('app', () => { }"#; let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); - assert!(result.updated); - assert_eq!( - result.content, - r#"declare module 'vite-plus/test' { - interface JestAssertion { - toBeCustom(): void; - } -}"# - ); + assert!(!result.updated); + assert_eq!(result.content, content); } #[test] fn test_rewrite_declare_module_vitest_config() { + // `declare module 'vitest/config'` is intentionally NOT rewritten — + // `vite-plus` re-exports `vitest/config`, so augmentations must target + // the upstream module identity to merge correctly. let content = r#"declare module 'vitest/config' { interface UserConfig { test?: TestConfig; @@ -1495,15 +1428,8 @@ describe('app', () => { }"#; let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); - assert!(result.updated); - assert_eq!( - result.content, - r#"declare module 'vite-plus' { - interface UserConfig { - test?: TestConfig; - } -}"# - ); + assert!(!result.updated); + assert_eq!(result.content, content); } #[test] @@ -1528,6 +1454,9 @@ describe('app', () => { #[test] fn test_rewrite_declare_module_vitest_subpath() { + // `declare module 'vitest/node'` stays — the `vite-plus/test/node` + // shim re-exports from upstream, so augmentations must target the + // upstream module identity. let content = r#"declare module 'vitest/node' { export interface VitestOptions { custom?: boolean; @@ -1535,19 +1464,14 @@ describe('app', () => { }"#; let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); - assert!(result.updated); - assert_eq!( - result.content, - r#"declare module 'vite-plus/test/node' { - export interface VitestOptions { - custom?: boolean; - } -}"# - ); + assert!(!result.updated); + assert_eq!(result.content, content); } #[test] fn test_rewrite_declare_module_vitest_browser() { + // `declare module '@vitest/browser'` stays — the + // `vite-plus/test/browser` shim re-exports from upstream. let content = r#"declare module '@vitest/browser' { interface BrowserContext { custom?: boolean; @@ -1555,19 +1479,13 @@ describe('app', () => { }"#; let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); - assert!(result.updated); - assert_eq!( - result.content, - r#"declare module 'vite-plus/test/browser' { - interface BrowserContext { - custom?: boolean; - } -}"# - ); + assert!(!result.updated); + assert_eq!(result.content, content); } #[test] fn test_rewrite_declare_module_vitest_browser_subpath() { + // `declare module '@vitest/browser/context'` stays — shim re-exports. let content = r#"declare module '@vitest/browser/context' { export interface Context { custom?: boolean; @@ -1575,19 +1493,13 @@ describe('app', () => { }"#; let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); - assert!(result.updated); - assert_eq!( - result.content, - r#"declare module 'vite-plus/test/browser/context' { - export interface Context { - custom?: boolean; - } -}"# - ); + assert!(!result.updated); + assert_eq!(result.content, content); } #[test] fn test_rewrite_declare_module_vitest_browser_playwright() { + // `declare module '@vitest/browser-playwright'` stays — shim re-exports. let content = r#"declare module '@vitest/browser-playwright' { interface PlaywrightContext { custom?: boolean; @@ -1595,19 +1507,13 @@ describe('app', () => { }"#; let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); - assert!(result.updated); - assert_eq!( - result.content, - r#"declare module 'vite-plus/test/browser-playwright' { - interface PlaywrightContext { - custom?: boolean; - } -}"# - ); + assert!(!result.updated); + assert_eq!(result.content, content); } #[test] fn test_rewrite_declare_module_vitest_browser_preview() { + // `declare module '@vitest/browser-preview'` stays — shim re-exports. let content = r#"declare module '@vitest/browser-preview' { interface PreviewContext { custom?: boolean; @@ -1615,19 +1521,13 @@ describe('app', () => { }"#; let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); - assert!(result.updated); - assert_eq!( - result.content, - r#"declare module 'vite-plus/test/browser-preview' { - interface PreviewContext { - custom?: boolean; - } -}"# - ); + assert!(!result.updated); + assert_eq!(result.content, content); } #[test] fn test_rewrite_declare_module_vitest_browser_webdriverio() { + // `declare module '@vitest/browser-webdriverio'` stays — shim re-exports. let content = r#"declare module '@vitest/browser-webdriverio' { interface WebDriverContext { custom?: boolean; @@ -1635,19 +1535,16 @@ describe('app', () => { }"#; let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); - assert!(result.updated); - assert_eq!( - result.content, - r#"declare module 'vite-plus/test/browser-webdriverio' { - interface WebDriverContext { - custom?: boolean; - } -}"# - ); + assert!(!result.updated); + assert_eq!(result.content, content); } #[test] fn test_rewrite_mixed_imports_and_declare_modules() { + // Imports are rewritten; `declare module 'vite' { ... }` is rewritten + // (vite-plus bundles vite, owning the type identity), but + // `declare module 'vitest' { ... }` stays put — the shim re-exports + // upstream and augmentations must target the upstream identity. let content = r#"import { defineConfig } from 'vite'; import { describe } from 'vitest'; @@ -1678,7 +1575,7 @@ declare module 'vite-plus' { } } -declare module 'vite-plus/test' { +declare module 'vitest' { interface JestAssertion { toBeCustom(): void; } @@ -1703,6 +1600,10 @@ export default defineConfig({});"# #[test] fn test_rewrite_multiple_declare_modules() { + // `declare module 'vite'` / `'vite/'` get rewritten (vite-plus + // bundles vite, owning the type identity), but `declare module 'vitest'` + // and `declare module '@vitest/browser'` are preserved — vite-plus + // shims re-export upstream and augmentations must target upstream. let content = r#"declare module 'vite' { interface UserConfig { custom?: boolean; @@ -1743,13 +1644,13 @@ declare module 'vite-plus/module-runner' { } } -declare module 'vite-plus/test' { +declare module 'vitest' { interface JestAssertion { toBeCustom(): void; } } -declare module 'vite-plus/test/browser' { +declare module '@vitest/browser' { interface BrowserContext { custom?: boolean; } @@ -1759,6 +1660,8 @@ declare module 'vite-plus/test/browser' { #[test] fn test_rewrite_declare_module_vitest_double_quotes() { + // Double-quoted `declare module "vitest"` is preserved for the same + // reason as the single-quoted variant — shim re-exports. let content = r#"declare module "vitest" { interface JestAssertion { toBeCustom(): void; @@ -1766,15 +1669,8 @@ declare module 'vite-plus/test/browser' { }"#; let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); - assert!(result.updated); - assert_eq!( - result.content, - r#"declare module "vite-plus/test" { - interface JestAssertion { - toBeCustom(): void; - } -}"# - ); + assert!(!result.updated); + assert_eq!(result.content, content); } #[test] @@ -1786,15 +1682,8 @@ declare module 'vite-plus/test/browser' { }"#; let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); - assert!(result.updated); - assert_eq!( - result.content, - r#"declare module 'vite-plus/test/browser-playwright/context' { - export interface Context { - custom?: boolean; - } -}"# - ); + assert!(!result.updated); + assert_eq!(result.content, content); } #[test] @@ -1806,15 +1695,8 @@ declare module 'vite-plus/test/browser' { }"#; let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); - assert!(result.updated); - assert_eq!( - result.content, - r#"declare module 'vite-plus/test/browser-preview/context' { - export interface Context { - custom?: boolean; - } -}"# - ); + assert!(!result.updated); + assert_eq!(result.content, content); } #[test] @@ -1826,15 +1708,8 @@ declare module 'vite-plus/test/browser' { }"#; let result = rewrite_import_content(content, &SkipPackages::default()).unwrap(); - assert!(result.updated); - assert_eq!( - result.content, - r#"declare module 'vite-plus/test/browser-webdriverio/context' { - export interface Context { - custom?: boolean; - } -}"# - ); + assert!(!result.updated); + assert_eq!(result.content, content); } #[test] diff --git a/docs/guide/migrate.md b/docs/guide/migrate.md index d84b010cce..3ea26aa27d 100644 --- a/docs/guide/migrate.md +++ b/docs/guide/migrate.md @@ -75,8 +75,8 @@ Migrate this project to Vite+. Vite+ replaces the current split tooling around r After the migration: - Confirm `vite` imports were rewritten to `vite-plus` where needed -- Confirm `vitest` imports were rewritten to `vite-plus/test` where needed -- Remove old `vite` and `vitest` dependencies only after those rewrites are confirmed +- Confirm `vitest` imports were rewritten to `vite-plus/test` (and `@vitest/browser*` to `vite-plus/test/browser*`) where needed +- Remove old `vite`, `vitest`, and `@vitest/browser*` dependencies only after those rewrites are confirmed — `vite-plus` ships them as direct deps - Move remaining tool-specific config into the appropriate blocks in `vite.config.ts` Command mapping to keep in mind: @@ -96,20 +96,26 @@ Summarize the migration at the end and report any manual follow-up still require ### Vitest -Vitest is automatically migrated through `vp migrate`. If you are migrating manually, you have to update all the imports to `vite-plus/test` instead: +Vitest is automatically migrated through `vp migrate`. `vite-plus` re-exports upstream `vitest@4.x` under `vite-plus/test*` (including the browser-provider subpaths), so a single `vite-plus` install is enough — you no longer need to install `vitest` or any `@vitest/browser*` provider directly. If you are migrating manually, update all the imports to `vite-plus/test*` instead: ```ts // before +import { defineConfig } from 'vitest/config'; import { describe, expect, it, vi } from 'vitest'; +import { playwright } from '@vitest/browser-playwright'; const { page } = await import('@vitest/browser/context'); // after +import { defineConfig } from 'vite-plus'; import { describe, expect, it, vi } from 'vite-plus/test'; +import { playwright } from 'vite-plus/test/browser-playwright'; const { page } = await import('vite-plus/test/browser/context'); ``` +`declare module 'vitest'` / `declare module '@vitest/browser*'` augmentations are intentionally **not** rewritten — `vite-plus/test*` is a thin re-export of upstream `vitest*`, so type augmentations have to target the upstream module identity to merge correctly. Leave those `declare module` statements pointing at `'vitest'` / `'@vitest/browser*'`. + ### tsdown If your project uses a `tsdown.config.ts`, move its options into the `pack` block in `vite.config.ts`: diff --git a/docs/guide/upgrade.md b/docs/guide/upgrade.md index 9b5c48e328..e0d5131b5f 100644 --- a/docs/guide/upgrade.md +++ b/docs/guide/upgrade.md @@ -29,21 +29,20 @@ You can also use `vp add vite-plus@latest` if you want to move the dependency ex ### Updating Aliased Packages -Vite+ sets up npm aliases for its core packages during installation: +Vite+ sets up an npm alias for its core package during installation: - `vite` is aliased to `npm:@voidzero-dev/vite-plus-core@latest` -- `vitest` is aliased to `npm:@voidzero-dev/vite-plus-test@latest` -`vp update vite-plus` does not re-resolve these aliases in the lockfile. To fully upgrade, update them separately: +`vp update vite-plus` does not re-resolve this alias in the lockfile. To fully upgrade, update it separately: ```bash -vp update @voidzero-dev/vite-plus-core @voidzero-dev/vite-plus-test +vp update @voidzero-dev/vite-plus-core ``` Or update everything at once: ```bash -vp update vite-plus @voidzero-dev/vite-plus-core @voidzero-dev/vite-plus-test +vp update vite-plus @voidzero-dev/vite-plus-core ``` You can verify with `vp outdated` that no Vite+ packages remain outdated. diff --git a/ecosystem-ci/patch-project.ts b/ecosystem-ci/patch-project.ts index 636fc399f9..0a178c4dec 100644 --- a/ecosystem-ci/patch-project.ts +++ b/ecosystem-ci/patch-project.ts @@ -47,6 +47,31 @@ if (project === 'vinext') { // vp migrate runs full dependency rewriting instead of skipping. const forceFreshMigration = 'forceFreshMigration' in repoConfig && repoConfig.forceFreshMigration; +// Bun is uniquely strict about vitest's `peer vite ^6 || ^7 || ^8` resolution +// (https://github.com/oven-sh/bun/issues/8406): it checks both the override +// target's package name and version. Point bun-based projects at the +// vite-7.99.0 alias tgz (a copy of core renamed to "vite" with a satisfying +// version); pnpm/npm/yarn must keep pointing at the real core tgz, otherwise +// they trip a registry lookup for "vite@" when a workspace +// sub-package and the override both reference the same vite-named alias. +const isBunProject = project === 'bun-vite-template'; +const viteOverrideTgz = isBunProject ? `vite-7.99.0.tgz` : `voidzero-dev-vite-plus-core-0.0.0.tgz`; + +// Keep in sync with VITEST_VERSION in packages/cli/src/utils/constants.ts. +const VITEST_VERSION = '4.1.5'; +const vitestOverrides = { + vitest: VITEST_VERSION, + '@vitest/expect': VITEST_VERSION, + '@vitest/runner': VITEST_VERSION, + '@vitest/snapshot': VITEST_VERSION, + '@vitest/spy': VITEST_VERSION, + '@vitest/utils': VITEST_VERSION, + '@vitest/mocker': VITEST_VERSION, + '@vitest/pretty-format': VITEST_VERSION, + '@vitest/coverage-v8': VITEST_VERSION, + '@vitest/coverage-istanbul': VITEST_VERSION, +}; + execSync(`${cli} migrate --no-agent --no-interactive`, { cwd, stdio: 'inherit', @@ -54,10 +79,9 @@ execSync(`${cli} migrate --no-agent --no-interactive`, { ...process.env, ...(forceFreshMigration ? { VP_FORCE_MIGRATE: '1' } : {}), VP_OVERRIDE_PACKAGES: JSON.stringify({ - vite: `file:${tgzDir}/voidzero-dev-vite-plus-core-0.0.0.tgz`, - vitest: `file:${tgzDir}/voidzero-dev-vite-plus-test-0.0.0.tgz`, + vite: `file:${tgzDir}/${viteOverrideTgz}`, '@voidzero-dev/vite-plus-core': `file:${tgzDir}/voidzero-dev-vite-plus-core-0.0.0.tgz`, - '@voidzero-dev/vite-plus-test': `file:${tgzDir}/voidzero-dev-vite-plus-test-0.0.0.tgz`, + ...vitestOverrides, }), VP_VERSION: `file:${tgzDir}/vite-plus-0.0.0.tgz`, }, diff --git a/justfile b/justfile index 5410c99096..5aa395c8c5 100644 --- a/justfile +++ b/justfile @@ -47,7 +47,6 @@ build: pnpm --filter rolldown build-node pnpm --filter vite build-types pnpm --filter=@voidzero-dev/vite-plus-core build - pnpm --filter=@voidzero-dev/vite-plus-test build pnpm --filter=@voidzero-dev/vite-plus-prompts build pnpm --filter=vite-plus build diff --git a/packages/cli/BUNDLING.md b/packages/cli/BUNDLING.md index fa9ef3d792..9e97564007 100644 --- a/packages/cli/BUNDLING.md +++ b/packages/cli/BUNDLING.md @@ -1,6 +1,6 @@ # CLI Package Build Architecture -This document explains how `vite-plus` is built and how it re-exports from both the core and test packages to serve as a drop-in replacement for `vite`. +This document explains how `vite-plus` is built and how it re-exports from `@voidzero-dev/vite-plus-core` (bundled vite/rolldown/tsdown) and from upstream `vitest` to serve as a drop-in replacement for `vite`. ## Overview @@ -9,9 +9,9 @@ The CLI package uses a **4-step build process**: 1. **tsdown Build** - Bundle all CLI entry points via tsdown 2. **NAPI Binding Build** - Compile Rust code to native Node.js bindings 3. **Core Package Export Sync** - Re-export `@voidzero-dev/vite-plus-core` under `./client`, `./types/*`, etc. -4. **Test Package Export Sync** - Re-export `@voidzero-dev/vite-plus-test` under `./test/*` +4. **Test Package Export Sync** - Re-export upstream `vitest` under `./test/*` -This architecture allows users to import everything from a single package (`vite-plus`) as a drop-in replacement for `vite`, without needing to know about the separate core and test packages. +This architecture allows users to import everything from a single package (`vite-plus`) as a drop-in replacement for `vite`, without needing to know about the separate `@voidzero-dev/vite-plus-core` bundle or `vitest`. ## Build Steps @@ -24,7 +24,7 @@ Bundles all CLI entry points using tsdown (configured in `tsdown.config.ts`). Th - Public API entries: `bin`, `index`, `define-config`, `fmt`, `lint`, `pack`, `pack-bin` - Global command entries: `create`, `migrate`, `version`, `config`, `mcp`, `staged` - All third-party dependencies are inlined at build time -- Only packages that must be resolved at runtime stay external (NAPI binding, `@voidzero-dev/vite-plus-core`, `@voidzero-dev/vite-plus-test`, `oxfmt`, `oxlint`) +- Only packages that must be resolved at runtime stay external (NAPI binding, `@voidzero-dev/vite-plus-core`, `vitest`, `oxfmt`, `oxlint`) - Code splitting creates shared chunks for code used by multiple entries - DTS (`.d.ts`) files are generated for all entries @@ -90,15 +90,22 @@ export type * from '@voidzero-dev/vite-plus-core/types/importMeta.d.ts'; ### Step 4: Test Package Export Sync (`syncTestPackageExports`) -Reads the test package's exports and creates shim files that re-export everything under `./test/*`: +Reads vitest's exports plus the three `@vitest/browser-*` provider packages and creates shim files that re-export everything under `./test/*`: ```typescript -// For each test package export like "./browser-playwright" -// Creates a shim file: dist/test/browser-playwright.js -export * from '@voidzero-dev/vite-plus-test/browser-playwright'; +// For each vitest export like "./node" +// Creates a shim file: dist/test/node.js +export * from 'vitest/node'; + +// For each @vitest/browser-* provider, two shim surfaces are projected: +// dist/test/browser-playwright.js (matches old wrapper path) +// dist/test/browser/providers/playwright.js (alias path) +export * from '@vitest/browser-playwright'; ``` -**Input**: `../test/package.json` exports +Provider `.d.ts` shims are NOT bare re-exports — see the [Provider Type Identity](#why-provider-dts-shims-are-inlined) note below. + +**Input**: resolved `vitest/package.json` exports plus each `@vitest/browser-*` package's exports (all resolved via `createRequire`) **Output**: `dist/test/*.js`, `dist/test/*.d.ts`, updated `package.json` exports --- @@ -336,28 +343,47 @@ This allows TypeScript to pick up types like `import.meta.hot`, CSS module types ### Why Shim Files? -Instead of copying the actual dist files from the test package, we create thin shim files that re-export from `@voidzero-dev/vite-plus-test`. This approach: +Instead of copying vitest's dist files, we create thin shim files that re-export from `vitest`. This approach: -1. **Keeps packages in sync** - No need to rebuild CLI when test package changes +1. **Keeps packages in sync** - No need to rebuild CLI when vitest is upgraded 2. **Reduces duplication** - No file copying, just re-exports -3. **Preserves module resolution** - Node.js resolves to the actual test package +3. **Preserves module resolution** - Node.js resolves to the actual installed vitest ### Export Mapping (Test) -All test package exports are mapped under `./test/*`: +Every entry under vitest's own `exports` is shimmed under `./test/*` (wildcard exports and `./package.json` are skipped). The shim is purely a re-export — `vite-plus/test` and friends are aliases for the matching subpath of upstream `vitest`. Examples: + +| Vitest Export | CLI Package Export | +| ------------------ | -------------------------- | +| `vitest` | `vite-plus/test` | +| `vitest/browser` | `vite-plus/test/browser` | +| `vitest/node` | `vite-plus/test/node` | +| `vitest/config` | `vite-plus/test/config` | +| `vitest/reporters` | `vite-plus/test/reporters` | + +The full set is regenerated on every build from the upstream vitest `package.json`, so the exact list tracks vitest itself. + +In addition to vitest's own exports, the three `@vitest/browser-*` provider packages are projected under two parallel surfaces so existing user code keeps resolving after the deleted `@voidzero-dev/vite-plus-test` wrapper: + +| Provider Package | CLI Package Exports | +| ----------------------------- | ------------------------------------------------------------------------------------ | +| `@vitest/browser-playwright` | `vite-plus/test/browser-playwright`, `vite-plus/test/browser/providers/playwright` | +| `@vitest/browser-preview` | `vite-plus/test/browser-preview`, `vite-plus/test/browser/providers/preview` | +| `@vitest/browser-webdriverio` | `vite-plus/test/browser-webdriverio`, `vite-plus/test/browser/providers/webdriverio` | + +Each provider's own subpaths (e.g. `./context`) are mirrored under both alias prefixes. + +#### Why provider d.ts shims are inlined + +Provider `.d.ts` shims are NOT plain `export * from '@vitest/browser-playwright'` re-exports — they inline the upstream `.d.ts` content with `vitest/node` / `vitest/browser` / `@vitest/browser*` bare specifiers rewritten to relative paths inside `dist/test/`. The two private shims `dist/test/_at-vitest-browser.d.ts` and `dist/test/_at-vitest-browser/context.d.ts` re-export `@vitest/browser`/`@vitest/browser/context` and are referenced from those rewrites. -| Test Package Export | CLI Package Export | -| ------------------------------------------------- | ----------------------------------- | -| `@voidzero-dev/vite-plus-test` | `vite-plus/test` | -| `@voidzero-dev/vite-plus-test/browser` | `vite-plus/test/browser` | -| `@voidzero-dev/vite-plus-test/browser-playwright` | `vite-plus/test/browser-playwright` | -| `@voidzero-dev/vite-plus-test/plugins/runner` | `vite-plus/test/plugins/runner` | +This avoids a pnpm-edge type-identity split: when the upstream `.d.ts` is loaded by reference (`export * from '@vitest/browser-playwright'`), TypeScript resolves its internal `import { BrowserProvider } from 'vitest/node'` through the provider package's own pnpm-edge, which can be a different vitest copy than the one a user's `vite.config.ts` sees through `vite-plus`. The mismatch produces two structurally identical but nominally distinct `BrowserProvider` types, so `provider: playwright()` fails the user's typecheck. Rewriting the specifiers routes every type import through vite-plus's own subpath shims, guaranteeing a single vitest identity across the user's whole config. ### Conditional Export Handling The sync handles complex conditional exports with `import`/`require`/`node`/`types` conditions. -**Test package's main export** (`"."`): +**Vitest's main export** (`"."`): ```json ".": { @@ -390,23 +416,23 @@ For each condition, appropriate shim files are created: ### Shim File Contents -**ESM shim** (`dist/test/browser-playwright.js`): +**ESM shim** (`dist/test/browser.js`): ```javascript -export * from '@voidzero-dev/vite-plus-test/browser-playwright'; +export * from 'vitest/browser'; ``` **CJS shim** (`dist/test/index.cjs`): ```javascript -module.exports = require('@voidzero-dev/vite-plus-test'); +module.exports = require('vitest'); ``` -**Type shim** (`dist/test/browser-playwright.d.ts`): +**Type shim** (`dist/test/browser.d.ts`): ```typescript -import '@voidzero-dev/vite-plus-test/browser-playwright'; -export * from '@voidzero-dev/vite-plus-test/browser-playwright'; +import 'vitest/browser'; +export * from 'vitest/browser'; ``` Note: Type shims include a side-effect import to preserve module augmentations (e.g., `toMatchSnapshot` on the `Assertion` interface). @@ -499,8 +525,8 @@ See `package.json` for the complete list of exports. // Core package name for Vite compatibility exports const CORE_PACKAGE_NAME = '@voidzero-dev/vite-plus-core'; -// Test package name for re-exports -const TEST_PACKAGE_NAME = '@voidzero-dev/vite-plus-test'; +// Test package name for re-exports (vitest itself, not a bundled wrapper) +const TEST_PACKAGE_NAME = 'vitest'; ``` ### Package.json Exports Management @@ -539,7 +565,7 @@ All non-`./test*` exports are manually maintained in `package.json`. These fall All `./test*` exports are fully managed by `syncTestPackageExports()`. The build script: -1. Reads `packages/test/package.json` exports +1. Reads vitest's `package.json` exports (resolved via `createRequire`) 2. Creates shim files in `dist/test/` 3. Removes old `./test*` exports from `package.json` 4. Merges in newly generated test exports diff --git a/packages/cli/README.md b/packages/cli/README.md index 8c3fcd71b0..4bcd953cb7 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -187,12 +187,11 @@ If you are manually migrating a project to Vite+, install these dev dependencies npm install -D vite-plus @voidzero-dev/vite-plus-core@latest ``` -You need to add overrides to your package manager for `vite` and `vitest` so that other packages depending on Vite and Vitest will use the Vite+ versions: +You need to add overrides to your package manager for `vite` so that other packages depending on Vite (including Vitest) will use the Vite+ version: ```json "overrides": { - "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + "vite": "npm:@voidzero-dev/vite-plus-core@latest" } ``` @@ -201,15 +200,13 @@ If you are using `pnpm`, add this to your `pnpm-workspace.yaml`: ```yaml overrides: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest ``` Or, if you are using Yarn: ```json "resolutions": { - "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + "vite": "npm:@voidzero-dev/vite-plus-core@latest" } ``` diff --git a/packages/cli/build.ts b/packages/cli/build.ts index c8ca718e61..617fb1643d 100644 --- a/packages/cli/build.ts +++ b/packages/cli/build.ts @@ -5,7 +5,7 @@ * 1. buildWithTsdown() - Bundles all CLI entry points via tsdown * 2. buildNapiBinding() - Builds the native Rust binding via NAPI * 3. syncCorePackageExports() - Creates shim files to re-export from @voidzero-dev/vite-plus-core - * 4. syncTestPackageExports() - Creates shim files to re-export from @voidzero-dev/vite-plus-test + * 4. syncTestPackageExports() - Creates shim files to re-export from vitest * 5. syncVersionsExport() - Generates ./versions module with bundled tool versions * 6. copyBundledDocs() - Copies docs into docs/ for bundled package access * 7. syncReadmeFromRoot() - Keeps package README in sync @@ -21,6 +21,7 @@ import { execSync } from 'node:child_process'; import { existsSync, readdirSync, statSync } from 'node:fs'; import { copyFile, cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; +import { createRequire } from 'node:module'; import { dirname, join, relative } from 'node:path'; import { fileURLToPath } from 'node:url'; import { parseArgs } from 'node:util'; @@ -30,12 +31,35 @@ import { format } from 'oxfmt'; import { generateLicenseFile } from '../../scripts/generate-license.js'; import corePkg from '../core/package.json' with { type: 'json' }; -import testPkg from '../test/package.json' with { type: 'json' }; const projectDir = dirname(fileURLToPath(import.meta.url)); -const TEST_PACKAGE_NAME = '@voidzero-dev/vite-plus-test'; +const TEST_PACKAGE_NAME = 'vitest'; const CORE_PACKAGE_NAME = '@voidzero-dev/vite-plus-core'; +// Browser providers projected under ./test/* and ./test/browser/providers/* so the +// public surface matches what the deleted `@voidzero-dev/vite-plus-test` wrapper exposed. +// Each entry maps the upstream package name to the short provider name used in the +// `./test/browser/providers/` alias path. +const BROWSER_PROVIDER_PACKAGES: ReadonlyArray<{ pkg: string; short: string }> = [ + { pkg: '@vitest/browser-playwright', short: 'playwright' }, + { pkg: '@vitest/browser-preview', short: 'preview' }, + { pkg: '@vitest/browser-webdriverio', short: 'webdriverio' }, +]; + +/** + * Vitest-related bare specifiers that appear in `@vitest/browser-*` d.ts files + * and the sub-path under `dist/test/` whose shim re-exports the same module. + * Longer prefixes are listed first so substring matches don't shadow them + * (e.g. `vitest/internal/browser` before `vitest/browser`). + */ +const VITEST_TYPE_SPECIFIER_REWRITES: ReadonlyArray = [ + ['@vitest/browser/context', '_at-vitest-browser/context'], + ['@vitest/browser', '_at-vitest-browser'], + ['vitest/internal/browser', 'internal/browser'], + ['vitest/browser', 'browser'], + ['vitest/node', 'node'], +]; + const { values: { ['skip-native']: skipNative, ['skip-ts']: skipTs }, } = parseArgs({ @@ -278,16 +302,21 @@ async function syncTypesDir(srcDir: string, destDir: string, relativePath: strin } /** - * Sync exports from @voidzero-dev/vite-plus-test to vite-plus + * Sync exports from vitest to vite-plus * - * This function reads the test package's exports and creates shim files that + * This function reads vitest's package.json exports and creates shim files that * re-export everything under the ./test/* subpath. This allows users to import - * from vite-plus/test/* instead of @voidzero-dev/vite-plus-test/*. + * from vite-plus/test/* instead of vitest/*. */ async function syncTestPackageExports() { console.log('\nSyncing test package exports...'); - const testPkgPath = join(projectDir, '../test/package.json'); + // Resolve vitest's package.json via Node's resolver so we always read the + // currently installed copy — packages/test/ no longer exists. + const require = createRequire(import.meta.url); + const testPkgPath = require.resolve(`${TEST_PACKAGE_NAME}/package.json`, { + paths: [projectDir], + }); const cliPkgPath = join(projectDir, 'package.json'); const testDistDir = join(projectDir, 'dist/test'); @@ -309,15 +338,86 @@ async function syncTestPackageExports() { // Convert ./foo to ./test/foo, . to ./test const cliExportPath = exportPath === '.' ? './test' : `./test${exportPath.slice(1)}`; + const shimBaseName = exportPath === '.' ? 'index' : exportPath.slice(2); + const importSpecifier = + exportPath === '.' ? TEST_PACKAGE_NAME : `${TEST_PACKAGE_NAME}${exportPath.slice(1)}`; // Create shim files and build export entry - const shimExport = await createShimForExport(exportPath, exportValue, testDistDir); + const shimExport = await createShimForExport( + shimBaseName, + exportValue, + importSpecifier, + testDistDir, + ); if (shimExport) { generatedExports[cliExportPath] = shimExport; console.log(` Created ${cliExportPath}`); } } + // Private shims for `@vitest/browser` and `@vitest/browser/context`. These + // are referenced as relative paths from the inlined browser-provider d.ts + // shims so that `@vitest/browser` resolves through vite-plus's own pnpm-edge + // (same one that owns the `vitest` direct dep) — preventing the two-vitest + // type-identity split that breaks user `provider: playwright()` typechecks. + await writePrivateAtVitestBrowserShims(testDistDir); + + // Mirror upstream @vitest/browser-* provider packages under ./test/ and + // ./test/browser/providers/. Existing vite-plus user code imports from these + // paths (e.g., `vite-plus/test/browser-playwright`) and must keep resolving after + // the bundled `@voidzero-dev/vite-plus-test` wrapper was removed. + for (const { pkg, short } of BROWSER_PROVIDER_PACKAGES) { + let providerPkgPath: string; + try { + providerPkgPath = require.resolve(`${pkg}/package.json`, { paths: [projectDir] }); + } catch (err) { + console.warn(` Skipping ${pkg} — not installed: ${(err as Error).message}`); + continue; + } + const providerPkg = JSON.parse(await readFile(providerPkgPath, 'utf-8')); + const providerPkgRoot = dirname(providerPkgPath); + const providerExports = (providerPkg.exports ?? {}) as Record; + + for (const [providerExportPath, providerExportValue] of Object.entries(providerExports)) { + if (providerExportPath === './package.json' || providerExportPath.includes('*')) { + continue; + } + + const providerSubPath = providerExportPath === '.' ? '' : providerExportPath.slice(1); + // Two CLI surfaces that map to the same provider shim: + // ./test/ → e.g. ./test/browser-playwright + // ./test/browser/providers/ → e.g. ./test/browser/providers/playwright + const pkgShortName = pkg.startsWith('@vitest/') ? pkg.slice('@vitest/'.length) : pkg; + const surfaces = [ + { + cliPath: `./test/${pkgShortName}${providerSubPath}`, + baseName: `${pkgShortName}${providerSubPath}`, + }, + { + cliPath: `./test/browser/providers/${short}${providerSubPath}`, + baseName: `browser/providers/${short}${providerSubPath}`, + }, + ]; + const importSpecifier = + providerExportPath === '.' ? pkg : `${pkg}${providerExportPath.slice(1)}`; + + for (const { cliPath, baseName } of surfaces) { + const shimBaseName = baseName.replace(/^\//, ''); + const shimExport = await createShimForExport( + shimBaseName, + providerExportValue, + importSpecifier, + testDistDir, + { providerPkgRoot }, + ); + if (shimExport) { + generatedExports[cliPath] = shimExport; + console.log(` Created ${cliPath}`); + } + } + } + } + // Update CLI package.json await updateCliPackageJson(cliPkgPath, generatedExports); @@ -350,8 +450,8 @@ async function readDepVersion(packageName: string): Promise { * Generate ./versions export module with bundled tool versions. * * Collects versions from: - * - core/test package.json bundledVersions (vite, rolldown, tsdown, vitest) - * - CLI dependency package.json (oxlint, oxfmt, oxlint-tsgolint) + * - core package.json bundledVersions (vite, rolldown, tsdown) + * - CLI dependency package.json (oxlint, oxfmt, oxlint-tsgolint, vitest) * * Generates dist/versions.js and dist/versions.d.ts with inlined constants. */ @@ -359,15 +459,14 @@ async function syncVersionsExport() { console.log('\nSyncing versions export...'); const distDir = join(projectDir, 'dist'); - // Collect versions from bundledVersions (core + test) + // Collect bundled versions from the core package const versions: Record = { ...(corePkg as Record).bundledVersions, - ...(testPkg as Record).bundledVersions, }; - // Collect versions from CLI dependencies (oxlint, oxfmt, oxlint-tsgolint) - // These don't export ./package.json, so we read from node_modules directly - const depTools = ['oxlint', 'oxfmt', 'oxlint-tsgolint'] as const; + // Read versions from CLI dependencies' installed package.json files + // (these packages don't export ./package.json, so node_modules is the source of truth) + const depTools = ['oxlint', 'oxfmt', 'oxlint-tsgolint', 'vitest'] as const; for (const name of depTools) { const version = await readDepVersion(name); if (version) { @@ -468,19 +567,136 @@ type ExportValue = }; /** - * Create shim file(s) for a single export and return the export entry for package.json + * Write private shims at `dist/test/_at-vitest-browser{.d.ts,/context.d.ts}` + * that re-export the `@vitest/browser` package. These are referenced by the + * inlined browser-provider d.ts shims via relative paths so all of + * `@vitest/browser`, `vitest/node`, etc. resolve through vite-plus's own + * pnpm-edge — the same edge that owns vite-plus's `vitest` direct dep. + * The underscore prefix marks them as private; they are not surfaced in the + * package.json `exports` map (TS resolves the relative paths directly). + */ +async function writePrivateAtVitestBrowserShims(testDistDir: string): Promise { + await mkdir(join(testDistDir, '_at-vitest-browser'), { recursive: true }); + await writeFile( + join(testDistDir, '_at-vitest-browser.d.ts'), + `import '@vitest/browser';\nexport * from '@vitest/browser';\n`, + ); + await writeFile( + join(testDistDir, '_at-vitest-browser/context.d.ts'), + `import '@vitest/browser/context';\nexport * from '@vitest/browser/context';\n`, + ); +} + +/** + * Inline-copy a browser-provider's upstream `.d.ts` file into `outDtsPath` and + * rewrite vitest-related bare specifiers to relative paths inside the + * vite-plus test shim tree. See `VITEST_TYPE_SPECIFIER_REWRITES` and + * `writePrivateAtVitestBrowserShims` for the rationale. + * + * Specifiers that are user peer dependencies (`playwright`, `webdriverio`, + * `tinyrainbow`, etc.) and the `@vitest/browser-*` self-import are left bare. + */ +async function writeInlinedProviderDts( + outDtsPath: string, + upstreamDtsPath: string, + testDistDir: string, +): Promise { + const upstream = await readFile(upstreamDtsPath, 'utf-8'); + const outDir = dirname(outDtsPath); + // Resolve to the file basename appended to the relative dir, never to the + // bare directory. `relative('dist/test/x/', 'dist/test/y')` returns `'../y'` + // but `relative('dist/test/x/', 'dist/test/y/')` returns `'..'` — TS would + // then look for `dist/test/y/index.d.ts` instead of `dist/test/y.d.ts`. We + // always emit `/` so the basename lookup hits the file. + const relToShim = (sub: string): string => { + const r = relative(outDir, testDistDir).replaceAll('\\', '/'); + const prefix = r === '' ? '.' : r.startsWith('.') ? r : `./${r}`; + return `${prefix}/${sub}`; + }; + let result = upstream; + for (const [bare, sub] of VITEST_TYPE_SPECIFIER_REWRITES) { + const escaped = bare.replaceAll('/', '\\/'); + const pattern = new RegExp(`(['"])${escaped}\\1`, 'g'); + result = result.replaceAll(pattern, `'${relToShim(sub)}'`); + } + await mkdir(outDir, { recursive: true }); + await writeFile(outDtsPath, result); +} + +/** + * Resolve the upstream `.d.ts` path for a given export value. Returns null + * when the export does not declare a types file (runtime-only exports). + */ +function resolveUpstreamDtsPath( + providerPkgRoot: string, + exportValue: unknown, + condition: 'types' | 'require-types' = 'types', +): string | null { + if (typeof exportValue === 'string') { + return exportValue.endsWith('.d.ts') || exportValue.endsWith('.d.cts') + ? join(providerPkgRoot, exportValue) + : null; + } + if (typeof exportValue !== 'object' || exportValue === null) { + return null; + } + const value = exportValue as Record; + if (condition === 'types') { + if (typeof value.types === 'string') { + return join(providerPkgRoot, value.types); + } + if (typeof value.import === 'object' && value.import !== null) { + const types = (value.import as Record).types; + if (typeof types === 'string') { + return join(providerPkgRoot, types); + } + } + } else { + if (typeof value.require === 'object' && value.require !== null) { + const types = (value.require as Record).types; + if (typeof types === 'string') { + return join(providerPkgRoot, types); + } + } + } + return null; +} + +async function writeShimDts( + outDtsPath: string, + importSpecifier: string, + upstreamDtsPath: string | null, + testDistDir: string, +): Promise { + if (upstreamDtsPath) { + await writeInlinedProviderDts(outDtsPath, upstreamDtsPath, testDistDir); + return; + } + // Include side-effect import to preserve module augmentations (e.g., toMatchSnapshot on Assertion) + await writeFile( + outDtsPath, + `import '${importSpecifier}';\nexport * from '${importSpecifier}';\n`, + ); +} + +/** + * Create shim file(s) for a single export and return the export entry for package.json. + * + * @param shimBaseName Path under dist/test/ (e.g. 'index', 'config', 'browser-playwright/context'). + * @param exportValue The upstream package's export value for this entry. + * @param testImportSpecifier The bare import specifier the shim should re-export from + * (e.g. 'vitest', 'vitest/node', '@vitest/browser-playwright'). + * @param distDir Output dist/test directory. + * @param opts Optional shim context. Pass `providerPkgRoot` for browser-provider + * packages to inline-copy their upstream d.ts content with specifier rewrites. */ async function createShimForExport( - exportPath: string, + shimBaseName: string, exportValue: unknown, + testImportSpecifier: string, distDir: string, + opts: { providerPkgRoot?: string } = {}, ): Promise { - // Determine the import specifier for the test package - const testImportSpecifier = - exportPath === '.' ? TEST_PACKAGE_NAME : `${TEST_PACKAGE_NAME}${exportPath.slice(1)}`; - - // Convert export path to file path: ./foo/bar -> foo/bar, . -> index - const shimBaseName = exportPath === '.' ? 'index' : exportPath.slice(2); const shimDir = join(distDir, dirname(shimBaseName)); await mkdir(shimDir, { recursive: true }); @@ -493,11 +709,10 @@ async function createShimForExport( // Check if it's a type-only export if (exportValue.endsWith('.d.ts')) { const dtsPath = join(shimDirForFile, `${baseFileName}.d.ts`); - // Include side-effect import to preserve module augmentations (e.g., toMatchSnapshot on Assertion) - await writeFile( - dtsPath, - `import '${testImportSpecifier}';\nexport * from '${testImportSpecifier}';\n`, - ); + const upstream = opts.providerPkgRoot + ? resolveUpstreamDtsPath(opts.providerPkgRoot, exportValue, 'types') + : null; + await writeShimDts(dtsPath, testImportSpecifier, upstream, distDir); return { types: `./dist/test/${shimBaseName}.d.ts` }; } @@ -517,6 +732,8 @@ async function createShimForExport( shimDirForFile, baseFileName, shimBaseName, + distDir, + opts, ); } @@ -525,11 +742,10 @@ async function createShimForExport( if (value.types && typeof value.types === 'string') { const dtsPath = join(shimDirForFile, `${baseFileName}.d.ts`); - // Include side-effect import to preserve module augmentations (e.g., toMatchSnapshot on Assertion) - await writeFile( - dtsPath, - `import '${testImportSpecifier}';\nexport * from '${testImportSpecifier}';\n`, - ); + const upstream = opts.providerPkgRoot + ? resolveUpstreamDtsPath(opts.providerPkgRoot, value, 'types') + : null; + await writeShimDts(dtsPath, testImportSpecifier, upstream, distDir); (result as Record).types = `./dist/test/${shimBaseName}.d.ts`; } @@ -552,6 +768,11 @@ async function createShimForExport( * { import: { types, node, default }, require: { types, default } } * And flat structures like: * { types, require, default } + * + * Insertion order matters: Node.js package-exports conditions are order-sensitive. + * For dual-condition entries, `require` MUST come before `default` so that + * `require('vite-plus/test/config')` resolves to the `.cjs` shim instead of + * matching the catch-all `default` (which would point at the ESM file). */ async function createConditionalShim( value: Record, @@ -559,25 +780,23 @@ async function createConditionalShim( shimDir: string, baseFileName: string, shimBaseName: string, + distDir: string, + opts: { providerPkgRoot?: string } = {}, ): Promise { - const result: ExportValue = {}; + // Build entries as an array of tuples so we control insertion order explicitly. + // Final order for flat entries: types, import (if present), require, default. + // `require` MUST come before `default` — `default` matches everything, so + // putting it first makes the `require` branch unreachable for CJS consumers. + const entries: Array<[string, ExportValue]> = []; // Handle top-level types (flat structure like { types, require, default }) if (value.types && typeof value.types === 'string' && !value.import) { const dtsPath = join(shimDir, `${baseFileName}.d.ts`); - // Include side-effect import to preserve module augmentations (e.g., toMatchSnapshot on Assertion) - await writeFile( - dtsPath, - `import '${testImportSpecifier}';\nexport * from '${testImportSpecifier}';\n`, - ); - (result as Record).types = `./dist/test/${shimBaseName}.d.ts`; - } - - // Handle top-level default (flat structure, only when no import condition) - if (value.default && typeof value.default === 'string' && !value.import) { - const jsPath = join(shimDir, `${baseFileName}.js`); - await writeFile(jsPath, `export * from '${testImportSpecifier}';\n`); - (result as Record).default = `./dist/test/${shimBaseName}.js`; + const upstream = opts.providerPkgRoot + ? resolveUpstreamDtsPath(opts.providerPkgRoot, value, 'types') + : null; + await writeShimDts(dtsPath, testImportSpecifier, upstream, distDir); + entries.push(['types', `./dist/test/${shimBaseName}.d.ts`]); } // Handle import condition @@ -587,17 +806,16 @@ async function createConditionalShim( if (typeof importValue === 'string') { const jsPath = join(shimDir, `${baseFileName}.js`); await writeFile(jsPath, `export * from '${testImportSpecifier}';\n`); - (result as Record).import = `./dist/test/${shimBaseName}.js`; + entries.push(['import', `./dist/test/${shimBaseName}.js`]); } else if (typeof importValue === 'object' && importValue !== null) { const importResult: Record = {}; if (importValue.types && typeof importValue.types === 'string') { const dtsPath = join(shimDir, `${baseFileName}.d.ts`); - // Include side-effect import to preserve module augmentations (e.g., toMatchSnapshot on Assertion) - await writeFile( - dtsPath, - `import '${testImportSpecifier}';\nexport * from '${testImportSpecifier}';\n`, - ); + const upstream = opts.providerPkgRoot + ? resolveUpstreamDtsPath(opts.providerPkgRoot, value, 'types') + : null; + await writeShimDts(dtsPath, testImportSpecifier, upstream, distDir); importResult.types = `./dist/test/${shimBaseName}.d.ts`; } @@ -612,28 +830,28 @@ async function createConditionalShim( importResult.default = `./dist/test/${shimBaseName}.js`; } - result.import = importResult; + entries.push(['import', importResult]); } } - // Handle require condition + // Handle require condition — emitted BEFORE `default` so CJS resolution + // picks the `.cjs` shim instead of the catch-all `default` entry. if (value.require) { const requireValue = value.require as Record; if (typeof requireValue === 'string') { const cjsPath = join(shimDir, `${baseFileName}.cjs`); await writeFile(cjsPath, `module.exports = require('${testImportSpecifier}');\n`); - result.require = `./dist/test/${shimBaseName}.cjs`; + entries.push(['require', `./dist/test/${shimBaseName}.cjs`]); } else if (typeof requireValue === 'object' && requireValue !== null) { const requireResult: Record = {}; if (requireValue.types && typeof requireValue.types === 'string') { const dctsPath = join(shimDir, `${baseFileName}.d.cts`); - // Include side-effect import to preserve module augmentations (e.g., toMatchSnapshot on Assertion) - await writeFile( - dctsPath, - `import '${testImportSpecifier}';\nexport * from '${testImportSpecifier}';\n`, - ); + const upstream = opts.providerPkgRoot + ? resolveUpstreamDtsPath(opts.providerPkgRoot, value, 'require-types') + : null; + await writeShimDts(dctsPath, testImportSpecifier, upstream, distDir); requireResult.types = `./dist/test/${shimBaseName}.d.cts`; } @@ -643,11 +861,20 @@ async function createConditionalShim( requireResult.default = `./dist/test/${shimBaseName}.cjs`; } - result.require = requireResult; + entries.push(['require', requireResult]); } } - return result; + // Handle top-level default (flat structure, only when no import condition). + // Emitted LAST among siblings so `require` (and any specific condition) + // wins resolution against the catch-all `default`. + if (value.default && typeof value.default === 'string' && !value.import) { + const jsPath = join(shimDir, `${baseFileName}.js`); + await writeFile(jsPath, `export * from '${testImportSpecifier}';\n`); + entries.push(['default', `./dist/test/${shimBaseName}.js`]); + } + + return Object.fromEntries(entries) as ExportValue; } /** diff --git a/packages/cli/package.json b/packages/cli/package.json index 1db5aa4dca..23092f7e06 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -89,7 +89,6 @@ "./test": { "import": { "types": "./dist/test/index.d.ts", - "node": "./dist/test/index.js", "default": "./dist/test/index.js" }, "require": { @@ -141,8 +140,8 @@ }, "./test/config": { "types": "./dist/test/config.d.ts", - "default": "./dist/test/config.js", - "require": "./dist/test/config.cjs" + "require": "./dist/test/config.cjs", + "default": "./dist/test/config.js" }, "./test/coverage": { "types": "./dist/test/coverage.d.ts", @@ -164,160 +163,47 @@ "types": "./dist/test/worker.d.ts", "default": "./dist/test/worker.js" }, - "./test/browser-compat": { - "default": "./dist/test/browser-compat.js" - }, - "./test/client": { - "default": "./dist/test/client.js" - }, - "./test/context": { - "types": "./dist/test/context.d.ts", - "default": "./dist/test/context.js" - }, - "./test/browser/context": { - "types": "./dist/test/browser/context.d.ts", - "default": "./dist/test/browser/context.js" - }, - "./test/locators": { - "default": "./dist/test/locators.js" - }, - "./test/matchers": { - "default": "./dist/test/matchers.js" - }, - "./test/utils": { - "default": "./dist/test/utils.js" - }, "./test/browser-playwright": { "types": "./dist/test/browser-playwright.d.ts", "default": "./dist/test/browser-playwright.js" }, - "./test/browser-webdriverio": { - "types": "./dist/test/browser-webdriverio.d.ts", - "default": "./dist/test/browser-webdriverio.js" - }, - "./test/browser-preview": { - "types": "./dist/test/browser-preview.d.ts", - "default": "./dist/test/browser-preview.js" - }, "./test/browser/providers/playwright": { "types": "./dist/test/browser/providers/playwright.d.ts", "default": "./dist/test/browser/providers/playwright.js" }, - "./test/browser/providers/webdriverio": { - "types": "./dist/test/browser/providers/webdriverio.d.ts", - "default": "./dist/test/browser/providers/webdriverio.js" + "./test/browser-playwright/context": { + "types": "./dist/test/browser-playwright/context.d.ts" + }, + "./test/browser/providers/playwright/context": { + "types": "./dist/test/browser/providers/playwright/context.d.ts" + }, + "./test/browser-preview": { + "types": "./dist/test/browser-preview.d.ts", + "default": "./dist/test/browser-preview.js" }, "./test/browser/providers/preview": { "types": "./dist/test/browser/providers/preview.d.ts", "default": "./dist/test/browser/providers/preview.js" }, - "./test/plugins/runner": { - "default": "./dist/test/plugins/runner.js" - }, - "./test/plugins/runner-utils": { - "default": "./dist/test/plugins/runner-utils.js" - }, - "./test/plugins/runner-types": { - "default": "./dist/test/plugins/runner-types.js" - }, - "./test/plugins/utils": { - "default": "./dist/test/plugins/utils.js" - }, - "./test/plugins/utils-source-map": { - "default": "./dist/test/plugins/utils-source-map.js" - }, - "./test/plugins/utils-source-map-node": { - "default": "./dist/test/plugins/utils-source-map-node.js" - }, - "./test/plugins/utils-error": { - "default": "./dist/test/plugins/utils-error.js" - }, - "./test/plugins/utils-helpers": { - "default": "./dist/test/plugins/utils-helpers.js" + "./test/browser-preview/context": { + "types": "./dist/test/browser-preview/context.d.ts" }, - "./test/plugins/utils-display": { - "default": "./dist/test/plugins/utils-display.js" + "./test/browser/providers/preview/context": { + "types": "./dist/test/browser/providers/preview/context.d.ts" }, - "./test/plugins/utils-timers": { - "default": "./dist/test/plugins/utils-timers.js" - }, - "./test/plugins/utils-highlight": { - "default": "./dist/test/plugins/utils-highlight.js" - }, - "./test/plugins/utils-offset": { - "default": "./dist/test/plugins/utils-offset.js" - }, - "./test/plugins/utils-resolver": { - "default": "./dist/test/plugins/utils-resolver.js" - }, - "./test/plugins/utils-serialize": { - "default": "./dist/test/plugins/utils-serialize.js" - }, - "./test/plugins/utils-constants": { - "default": "./dist/test/plugins/utils-constants.js" - }, - "./test/plugins/utils-diff": { - "default": "./dist/test/plugins/utils-diff.js" - }, - "./test/plugins/spy": { - "default": "./dist/test/plugins/spy.js" - }, - "./test/plugins/expect": { - "default": "./dist/test/plugins/expect.js" - }, - "./test/plugins/snapshot": { - "default": "./dist/test/plugins/snapshot.js" - }, - "./test/plugins/snapshot-environment": { - "default": "./dist/test/plugins/snapshot-environment.js" - }, - "./test/plugins/snapshot-manager": { - "default": "./dist/test/plugins/snapshot-manager.js" - }, - "./test/plugins/mocker": { - "default": "./dist/test/plugins/mocker.js" - }, - "./test/plugins/mocker-node": { - "default": "./dist/test/plugins/mocker-node.js" - }, - "./test/plugins/mocker-browser": { - "default": "./dist/test/plugins/mocker-browser.js" - }, - "./test/plugins/mocker-redirect": { - "default": "./dist/test/plugins/mocker-redirect.js" - }, - "./test/plugins/mocker-transforms": { - "default": "./dist/test/plugins/mocker-transforms.js" - }, - "./test/plugins/mocker-automock": { - "default": "./dist/test/plugins/mocker-automock.js" - }, - "./test/plugins/mocker-register": { - "default": "./dist/test/plugins/mocker-register.js" - }, - "./test/plugins/pretty-format": { - "default": "./dist/test/plugins/pretty-format.js" - }, - "./test/plugins/browser": { - "default": "./dist/test/plugins/browser.js" - }, - "./test/plugins/browser-context": { - "default": "./dist/test/plugins/browser-context.js" - }, - "./test/plugins/browser-client": { - "default": "./dist/test/plugins/browser-client.js" - }, - "./test/plugins/browser-locators": { - "default": "./dist/test/plugins/browser-locators.js" + "./test/browser-webdriverio": { + "types": "./dist/test/browser-webdriverio.d.ts", + "default": "./dist/test/browser-webdriverio.js" }, - "./test/plugins/browser-playwright": { - "default": "./dist/test/plugins/browser-playwright.js" + "./test/browser/providers/webdriverio": { + "types": "./dist/test/browser/providers/webdriverio.d.ts", + "default": "./dist/test/browser/providers/webdriverio.js" }, - "./test/plugins/browser-webdriverio": { - "default": "./dist/test/plugins/browser-webdriverio.js" + "./test/browser-webdriverio/context": { + "types": "./dist/test/browser-webdriverio/context.d.ts" }, - "./test/plugins/browser-preview": { - "default": "./dist/test/plugins/browser-preview.js" + "./test/browser/providers/webdriverio/context": { + "types": "./dist/test/browser/providers/webdriverio/context.d.ts" } }, "scripts": { @@ -332,11 +218,15 @@ }, "dependencies": { "@oxc-project/types": "catalog:", + "@vitest/browser": "catalog:", + "@vitest/browser-playwright": "catalog:", + "@vitest/browser-preview": "catalog:", + "@vitest/browser-webdriverio": "catalog:", "@voidzero-dev/vite-plus-core": "workspace:*", - "@voidzero-dev/vite-plus-test": "workspace:*", "oxfmt": "catalog:", "oxlint": "catalog:", - "oxlint-tsgolint": "catalog:" + "oxlint-tsgolint": "catalog:", + "vitest": "catalog:" }, "devDependencies": { "@napi-rs/cli": "catalog:", diff --git a/packages/cli/publish-native-addons.ts b/packages/cli/publish-native-addons.ts index ed9c5c51f2..b9dfb3dd35 100644 --- a/packages/cli/publish-native-addons.ts +++ b/packages/cli/publish-native-addons.ts @@ -53,12 +53,6 @@ if (existsSync(rustCliArtifactsDir)) { } } -// Build test package — versions are already bumped on main by prepare_release.yml. -execSync('pnpm --filter=@voidzero-dev/vite-plus-test build', { - cwd: repoRoot, - stdio: 'inherit', -}); - // Create npm directories for NAPI bindings await cli.createNpmDirs({ cwd: currentDir, diff --git a/packages/cli/snap-tests-global/migration-add-git-hooks/snap.txt b/packages/cli/snap-tests-global/migration-add-git-hooks/snap.txt index c98f4e9d51..d7cc58178d 100644 --- a/packages/cli/snap-tests-global/migration-add-git-hooks/snap.txt +++ b/packages/cli/snap-tests-global/migration-add-git-hooks/snap.txt @@ -21,18 +21,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat .vite-hooks/pre-commit # check pre-commit hook vp staged diff --git a/packages/cli/snap-tests-global/migration-auto-create-vite-config/snap.txt b/packages/cli/snap-tests-global/migration-auto-create-vite-config/snap.txt index fc073592c9..76689d8c11 100644 --- a/packages/cli/snap-tests-global/migration-auto-create-vite-config/snap.txt +++ b/packages/cli/snap-tests-global/migration-auto-create-vite-config/snap.txt @@ -44,15 +44,51 @@ export default defineConfig({ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-baseurl-tsconfig/snap.txt b/packages/cli/snap-tests-global/migration-baseurl-tsconfig/snap.txt index b94b37ad44..26bc0442ab 100644 --- a/packages/cli/snap-tests-global/migration-baseurl-tsconfig/snap.txt +++ b/packages/cli/snap-tests-global/migration-baseurl-tsconfig/snap.txt @@ -37,15 +37,51 @@ export default defineConfig({ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-chained-lint-staged-pre-commit/snap.txt b/packages/cli/snap-tests-global/migration-chained-lint-staged-pre-commit/snap.txt index 917e9ed4f2..bde07ee48f 100644 --- a/packages/cli/snap-tests-global/migration-chained-lint-staged-pre-commit/snap.txt +++ b/packages/cli/snap-tests-global/migration-chained-lint-staged-pre-commit/snap.txt @@ -21,18 +21,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat vite.config.ts # check staged config migrated to vite.config.ts import { defineConfig } from 'vite-plus'; diff --git a/packages/cli/snap-tests-global/migration-composed-husky-custom-dir/snap.txt b/packages/cli/snap-tests-global/migration-composed-husky-custom-dir/snap.txt index 27fed7c01c..0045a275f7 100644 --- a/packages/cli/snap-tests-global/migration-composed-husky-custom-dir/snap.txt +++ b/packages/cli/snap-tests-global/migration-composed-husky-custom-dir/snap.txt @@ -21,18 +21,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat .config/husky/pre-commit # pre-commit hook should be in custom dir vp staged diff --git a/packages/cli/snap-tests-global/migration-composed-husky-prepare/snap.txt b/packages/cli/snap-tests-global/migration-composed-husky-prepare/snap.txt index 0b78cecfe4..9449c4f80b 100644 --- a/packages/cli/snap-tests-global/migration-composed-husky-prepare/snap.txt +++ b/packages/cli/snap-tests-global/migration-composed-husky-prepare/snap.txt @@ -21,15 +21,51 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-env-prefix-lint-staged/snap.txt b/packages/cli/snap-tests-global/migration-env-prefix-lint-staged/snap.txt index e51767b612..cfda7e1ebe 100644 --- a/packages/cli/snap-tests-global/migration-env-prefix-lint-staged/snap.txt +++ b/packages/cli/snap-tests-global/migration-env-prefix-lint-staged/snap.txt @@ -21,18 +21,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat vite.config.ts # check staged config migrated to vite.config.ts import { defineConfig } from 'vite-plus'; diff --git a/packages/cli/snap-tests-global/migration-eslint-lint-staged/snap.txt b/packages/cli/snap-tests-global/migration-eslint-lint-staged/snap.txt index 634ca468f4..28e4652c83 100644 --- a/packages/cli/snap-tests-global/migration-eslint-lint-staged/snap.txt +++ b/packages/cli/snap-tests-global/migration-eslint-lint-staged/snap.txt @@ -21,18 +21,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat vite.config.ts # check oxlint config and staged config merged into vite.config.ts import { defineConfig } from 'vite-plus'; diff --git a/packages/cli/snap-tests-global/migration-eslint-lintstagedrc/snap.txt b/packages/cli/snap-tests-global/migration-eslint-lintstagedrc/snap.txt index 8b308fc525..0b0643b8c9 100644 --- a/packages/cli/snap-tests-global/migration-eslint-lintstagedrc/snap.txt +++ b/packages/cli/snap-tests-global/migration-eslint-lintstagedrc/snap.txt @@ -21,18 +21,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > test ! -f .lintstagedrc.json # check lintstagedrc.json is removed > cat vite.config.ts # check oxlint config merged into vite.config.ts diff --git a/packages/cli/snap-tests-global/migration-eslint-npx-wrapper/snap.txt b/packages/cli/snap-tests-global/migration-eslint-npx-wrapper/snap.txt index ce804c1e0b..6a34937308 100644 --- a/packages/cli/snap-tests-global/migration-eslint-npx-wrapper/snap.txt +++ b/packages/cli/snap-tests-global/migration-eslint-npx-wrapper/snap.txt @@ -26,17 +26,53 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > test ! -f eslint.config.mjs # check eslint config is removed \ No newline at end of file diff --git a/packages/cli/snap-tests-global/migration-eslint/snap.txt b/packages/cli/snap-tests-global/migration-eslint/snap.txt index e1a6319fdb..35ed28c648 100644 --- a/packages/cli/snap-tests-global/migration-eslint/snap.txt +++ b/packages/cli/snap-tests-global/migration-eslint/snap.txt @@ -24,18 +24,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > test ! -f eslint.config.mjs # check eslint config is removed > cat vite.config.ts # check oxlint config merged into vite.config.ts diff --git a/packages/cli/snap-tests-global/migration-existing-husky-lint-staged/snap.txt b/packages/cli/snap-tests-global/migration-existing-husky-lint-staged/snap.txt index b52ced2890..6e51be14b5 100644 --- a/packages/cli/snap-tests-global/migration-existing-husky-lint-staged/snap.txt +++ b/packages/cli/snap-tests-global/migration-existing-husky-lint-staged/snap.txt @@ -21,18 +21,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat vite.config.ts # check staged config migrated to vite.config.ts import { defineConfig } from 'vite-plus'; diff --git a/packages/cli/snap-tests-global/migration-existing-husky-v8-hooks/snap.txt b/packages/cli/snap-tests-global/migration-existing-husky-v8-hooks/snap.txt index 72ac97116d..a99de01fd3 100644 --- a/packages/cli/snap-tests-global/migration-existing-husky-v8-hooks/snap.txt +++ b/packages/cli/snap-tests-global/migration-existing-husky-v8-hooks/snap.txt @@ -24,18 +24,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat .husky/pre-commit # hook file should be unchanged (still has bootstrap) . "$(dirname -- "$0")/_/husky.sh" diff --git a/packages/cli/snap-tests-global/migration-existing-husky-v8-multi-hooks/snap.txt b/packages/cli/snap-tests-global/migration-existing-husky-v8-multi-hooks/snap.txt index e9c4d445c6..c7fdd12381 100644 --- a/packages/cli/snap-tests-global/migration-existing-husky-v8-multi-hooks/snap.txt +++ b/packages/cli/snap-tests-global/migration-existing-husky-v8-multi-hooks/snap.txt @@ -24,18 +24,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat .husky/pre-commit # hook file should be unchanged (still has bootstrap) . "$(dirname -- "$0")/_/husky.sh" diff --git a/packages/cli/snap-tests-global/migration-existing-husky/snap.txt b/packages/cli/snap-tests-global/migration-existing-husky/snap.txt index 260a9e510c..d12d519cac 100644 --- a/packages/cli/snap-tests-global/migration-existing-husky/snap.txt +++ b/packages/cli/snap-tests-global/migration-existing-husky/snap.txt @@ -21,18 +21,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat .vite-hooks/pre-commit # check pre-commit hook rewritten to vp staged vp staged diff --git a/packages/cli/snap-tests-global/migration-existing-lint-staged-config/snap.txt b/packages/cli/snap-tests-global/migration-existing-lint-staged-config/snap.txt index 130df58b91..e36f0470ee 100644 --- a/packages/cli/snap-tests-global/migration-existing-lint-staged-config/snap.txt +++ b/packages/cli/snap-tests-global/migration-existing-lint-staged-config/snap.txt @@ -21,18 +21,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > test ! -f .lintstagedrc.json # check lintstagedrc.json (should be deleted after inlining to vite.config.ts) > cat vite.config.ts # check staged config migrated to vite.config.ts diff --git a/packages/cli/snap-tests-global/migration-existing-pnpm-exec-lint-staged/snap.txt b/packages/cli/snap-tests-global/migration-existing-pnpm-exec-lint-staged/snap.txt index d7ff809e69..5e85d88346 100644 --- a/packages/cli/snap-tests-global/migration-existing-pnpm-exec-lint-staged/snap.txt +++ b/packages/cli/snap-tests-global/migration-existing-pnpm-exec-lint-staged/snap.txt @@ -21,18 +21,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat vite.config.ts # check staged config migrated to vite.config.ts import { defineConfig } from 'vite-plus'; diff --git a/packages/cli/snap-tests-global/migration-existing-prepare-script/snap.txt b/packages/cli/snap-tests-global/migration-existing-prepare-script/snap.txt index 3df5a5ee3e..04fd212766 100644 --- a/packages/cli/snap-tests-global/migration-existing-prepare-script/snap.txt +++ b/packages/cli/snap-tests-global/migration-existing-prepare-script/snap.txt @@ -22,18 +22,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat .vite-hooks/pre-commit # check pre-commit hook vp staged diff --git a/packages/cli/snap-tests-global/migration-from-tsdown-json-config/snap.txt b/packages/cli/snap-tests-global/migration-from-tsdown-json-config/snap.txt index 429f476f27..c9df886406 100644 --- a/packages/cli/snap-tests-global/migration-from-tsdown-json-config/snap.txt +++ b/packages/cli/snap-tests-global/migration-from-tsdown-json-config/snap.txt @@ -46,18 +46,54 @@ export default defineConfig({ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > vp migrate --no-interactive # run migration again to check if it is idempotent This project is already using Vite+! Happy coding! diff --git a/packages/cli/snap-tests-global/migration-from-tsdown/snap.txt b/packages/cli/snap-tests-global/migration-from-tsdown/snap.txt index f01cca33c5..c3ae55c7a9 100644 --- a/packages/cli/snap-tests-global/migration-from-tsdown/snap.txt +++ b/packages/cli/snap-tests-global/migration-from-tsdown/snap.txt @@ -48,18 +48,54 @@ export default defineConfig({ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > vp migrate --no-interactive # run migration again to check if it is idempotent This project is already using Vite+! Happy coding! diff --git a/packages/cli/snap-tests-global/migration-from-vitest-config/snap.txt b/packages/cli/snap-tests-global/migration-from-vitest-config/snap.txt index 0c3d5fe6f3..1ba1a5b5b1 100644 --- a/packages/cli/snap-tests-global/migration-from-vitest-config/snap.txt +++ b/packages/cli/snap-tests-global/migration-from-vitest-config/snap.txt @@ -51,15 +51,51 @@ export default defineConfig({ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-from-vitest-files/snap.txt b/packages/cli/snap-tests-global/migration-from-vitest-files/snap.txt index 0b688b13bf..2715368e19 100644 --- a/packages/cli/snap-tests-global/migration-from-vitest-files/snap.txt +++ b/packages/cli/snap-tests-global/migration-from-vitest-files/snap.txt @@ -26,18 +26,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat test/hello.ts # check test/hello.ts import { server } from 'vite-plus/test/browser-playwright/context'; diff --git a/packages/cli/snap-tests-global/migration-hooks-skip-on-existing-hookspath/snap.txt b/packages/cli/snap-tests-global/migration-hooks-skip-on-existing-hookspath/snap.txt index 2fde12c7ed..8a68364d50 100644 --- a/packages/cli/snap-tests-global/migration-hooks-skip-on-existing-hookspath/snap.txt +++ b/packages/cli/snap-tests-global/migration-hooks-skip-on-existing-hookspath/snap.txt @@ -24,18 +24,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > git config --local core.hooksPath # should still be .custom-hooks .custom-hooks diff --git a/packages/cli/snap-tests-global/migration-husky-latest-dist-tag-v9-installed/snap.txt b/packages/cli/snap-tests-global/migration-husky-latest-dist-tag-v9-installed/snap.txt index 4d39f8f03b..a206964bed 100644 --- a/packages/cli/snap-tests-global/migration-husky-latest-dist-tag-v9-installed/snap.txt +++ b/packages/cli/snap-tests-global/migration-husky-latest-dist-tag-v9-installed/snap.txt @@ -21,15 +21,51 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-husky-latest-dist-tag/snap.txt b/packages/cli/snap-tests-global/migration-husky-latest-dist-tag/snap.txt index 88721e1e3a..24da13436e 100644 --- a/packages/cli/snap-tests-global/migration-husky-latest-dist-tag/snap.txt +++ b/packages/cli/snap-tests-global/migration-husky-latest-dist-tag/snap.txt @@ -23,15 +23,51 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-husky-or-prepare/snap.txt b/packages/cli/snap-tests-global/migration-husky-or-prepare/snap.txt index a98449620e..5ed837570a 100644 --- a/packages/cli/snap-tests-global/migration-husky-or-prepare/snap.txt +++ b/packages/cli/snap-tests-global/migration-husky-or-prepare/snap.txt @@ -21,15 +21,51 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-husky-semicolon-prepare/snap.txt b/packages/cli/snap-tests-global/migration-husky-semicolon-prepare/snap.txt index 42df326a40..8bedb4f985 100644 --- a/packages/cli/snap-tests-global/migration-husky-semicolon-prepare/snap.txt +++ b/packages/cli/snap-tests-global/migration-husky-semicolon-prepare/snap.txt @@ -21,15 +21,51 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-husky-v8-preserves-lint-staged/snap.txt b/packages/cli/snap-tests-global/migration-husky-v8-preserves-lint-staged/snap.txt index d56772a22d..a774cb3326 100644 --- a/packages/cli/snap-tests-global/migration-husky-v8-preserves-lint-staged/snap.txt +++ b/packages/cli/snap-tests-global/migration-husky-v8-preserves-lint-staged/snap.txt @@ -27,15 +27,51 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-lint-staged-in-scripts/snap.txt b/packages/cli/snap-tests-global/migration-lint-staged-in-scripts/snap.txt index 56246b5d98..83f8d62c78 100644 --- a/packages/cli/snap-tests-global/migration-lint-staged-in-scripts/snap.txt +++ b/packages/cli/snap-tests-global/migration-lint-staged-in-scripts/snap.txt @@ -22,18 +22,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat vite.config.ts # check staged config migrated to vite.config.ts import { defineConfig } from 'vite-plus'; diff --git a/packages/cli/snap-tests-global/migration-lint-staged-merge-fail/snap.txt b/packages/cli/snap-tests-global/migration-lint-staged-merge-fail/snap.txt index 910f89ebd1..690f787b31 100644 --- a/packages/cli/snap-tests-global/migration-lint-staged-merge-fail/snap.txt +++ b/packages/cli/snap-tests-global/migration-lint-staged-merge-fail/snap.txt @@ -30,18 +30,54 @@ Please add staged config to vite.config.ts manually, see https://viteplus.dev/gu > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat vite.config.ts # vite config should be unchanged (merge failed) const config = { plugins: [] }; diff --git a/packages/cli/snap-tests-global/migration-lint-staged-ts-config/snap.txt b/packages/cli/snap-tests-global/migration-lint-staged-ts-config/snap.txt index 0644922652..6ba1c88d88 100644 --- a/packages/cli/snap-tests-global/migration-lint-staged-ts-config/snap.txt +++ b/packages/cli/snap-tests-global/migration-lint-staged-ts-config/snap.txt @@ -25,18 +25,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat lint-staged.config.ts # check TS config is not modified export default { diff --git a/packages/cli/snap-tests-global/migration-lintstagedrc-json/snap.txt b/packages/cli/snap-tests-global/migration-lintstagedrc-json/snap.txt index 4369903eff..c03dafecdd 100644 --- a/packages/cli/snap-tests-global/migration-lintstagedrc-json/snap.txt +++ b/packages/cli/snap-tests-global/migration-lintstagedrc-json/snap.txt @@ -93,18 +93,54 @@ Documentation: https://viteplus.dev/guide/migrate > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat vite.config.ts # check staged config migrated to vite.config.ts import { defineConfig } from 'vite-plus'; diff --git a/packages/cli/snap-tests-global/migration-lintstagedrc-merge-fail/snap.txt b/packages/cli/snap-tests-global/migration-lintstagedrc-merge-fail/snap.txt index dc4b6e426a..93995ebc9e 100644 --- a/packages/cli/snap-tests-global/migration-lintstagedrc-merge-fail/snap.txt +++ b/packages/cli/snap-tests-global/migration-lintstagedrc-merge-fail/snap.txt @@ -27,18 +27,54 @@ Please add staged config to vite.config.ts manually, see https://viteplus.dev/gu > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat .lintstagedrc.json # config file should be preserved when merge fails { diff --git a/packages/cli/snap-tests-global/migration-lintstagedrc-not-support/snap.txt b/packages/cli/snap-tests-global/migration-lintstagedrc-not-support/snap.txt index 8171e7d079..bee3bf5eb6 100644 --- a/packages/cli/snap-tests-global/migration-lintstagedrc-not-support/snap.txt +++ b/packages/cli/snap-tests-global/migration-lintstagedrc-not-support/snap.txt @@ -38,15 +38,51 @@ export default { > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-lintstagedrc-staged-exists/snap.txt b/packages/cli/snap-tests-global/migration-lintstagedrc-staged-exists/snap.txt index ee6f45e1c2..eb7bec7406 100644 --- a/packages/cli/snap-tests-global/migration-lintstagedrc-staged-exists/snap.txt +++ b/packages/cli/snap-tests-global/migration-lintstagedrc-staged-exists/snap.txt @@ -22,18 +22,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > test -f .lintstagedrc.json && echo 'lintstagedrc.json still exists' || echo 'lintstagedrc.json was deleted' # should still exist lintstagedrc.json still exists diff --git a/packages/cli/snap-tests-global/migration-merge-vite-config-js/snap.txt b/packages/cli/snap-tests-global/migration-merge-vite-config-js/snap.txt index 4c201a0f2a..98fb0c769a 100644 --- a/packages/cli/snap-tests-global/migration-merge-vite-config-js/snap.txt +++ b/packages/cli/snap-tests-global/migration-merge-vite-config-js/snap.txt @@ -43,15 +43,51 @@ export default { > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-merge-vite-config-ts/snap.txt b/packages/cli/snap-tests-global/migration-merge-vite-config-ts/snap.txt index db3311f886..790da11d59 100644 --- a/packages/cli/snap-tests-global/migration-merge-vite-config-ts/snap.txt +++ b/packages/cli/snap-tests-global/migration-merge-vite-config-ts/snap.txt @@ -77,15 +77,51 @@ export default defineConfig({ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-monorepo-bun/snap.txt b/packages/cli/snap-tests-global/migration-monorepo-bun/snap.txt index 21eea406ef..a1c482bf48 100644 --- a/packages/cli/snap-tests-global/migration-monorepo-bun/snap.txt +++ b/packages/cli/snap-tests-global/migration-monorepo-bun/snap.txt @@ -37,8 +37,17 @@ export default defineConfig({ ], "catalog": { "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest", - "vite-plus": "latest" + "vitest": "4.1.5", + "vite-plus": "latest", + "@vitest/expect": "4.1.5", + "@vitest/runner": "4.1.5", + "@vitest/snapshot": "4.1.5", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", + "@vitest/mocker": "4.1.5", + "@vitest/pretty-format": "4.1.5", + "@vitest/coverage-v8": "4.1.5", + "@vitest/coverage-istanbul": "4.1.5" } }, "scripts": { @@ -61,7 +70,16 @@ export default defineConfig({ "packageManager": "bun@", "overrides": { "vite": "catalog:", - "vitest": "catalog:" + "vitest": "catalog:", + "@vitest/expect": "catalog:", + "@vitest/runner": "catalog:", + "@vitest/snapshot": "catalog:", + "@vitest/spy": "catalog:", + "@vitest/utils": "catalog:", + "@vitest/mocker": "catalog:", + "@vitest/pretty-format": "catalog:", + "@vitest/coverage-v8": "catalog:", + "@vitest/coverage-istanbul": "catalog:" } } diff --git a/packages/cli/snap-tests-global/migration-monorepo-pnpm-overrides-dependency-selector/snap.txt b/packages/cli/snap-tests-global/migration-monorepo-pnpm-overrides-dependency-selector/snap.txt index 33ca5f9468..a64d606403 100644 --- a/packages/cli/snap-tests-global/migration-monorepo-pnpm-overrides-dependency-selector/snap.txt +++ b/packages/cli/snap-tests-global/migration-monorepo-pnpm-overrides-dependency-selector/snap.txt @@ -38,7 +38,16 @@ packages: catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: @@ -46,14 +55,41 @@ overrides: 'supertest>superagent': vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' react-click-away-listener>react: peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat packages/app/package.json # check app package.json { diff --git a/packages/cli/snap-tests-global/migration-monorepo-pnpm/snap.txt b/packages/cli/snap-tests-global/migration-monorepo-pnpm/snap.txt index b4941f0254..049f82eeb8 100644 --- a/packages/cli/snap-tests-global/migration-monorepo-pnpm/snap.txt +++ b/packages/cli/snap-tests-global/migration-monorepo-pnpm/snap.txt @@ -75,20 +75,56 @@ catalog: testnpm2: ^1.0.0 # test comment here to check if the comment is preserved vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest minimumReleaseAge: 1440 overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' minimumReleaseAgeExclude: - vite-plus - '@voidzero-dev/*' diff --git a/packages/cli/snap-tests-global/migration-monorepo-yarn4/snap.txt b/packages/cli/snap-tests-global/migration-monorepo-yarn4/snap.txt index 95e2012d8c..2fa58cacce 100644 --- a/packages/cli/snap-tests-global/migration-monorepo-yarn4/snap.txt +++ b/packages/cli/snap-tests-global/migration-monorepo-yarn4/snap.txt @@ -58,7 +58,16 @@ export default defineConfig({ "packageManager": "yarn@", "resolutions": { "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + "vitest": "4.1.5", + "@vitest/expect": "4.1.5", + "@vitest/runner": "4.1.5", + "@vitest/snapshot": "4.1.5", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", + "@vitest/mocker": "4.1.5", + "@vitest/pretty-format": "4.1.5", + "@vitest/coverage-v8": "4.1.5", + "@vitest/coverage-istanbul": "4.1.5" } } @@ -66,7 +75,16 @@ export default defineConfig({ nodeLinker: node-modules catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest > cat packages/app/package.json # check app package.json diff --git a/packages/cli/snap-tests-global/migration-no-git-repo/snap.txt b/packages/cli/snap-tests-global/migration-no-git-repo/snap.txt index c31403fd00..9afdb35823 100644 --- a/packages/cli/snap-tests-global/migration-no-git-repo/snap.txt +++ b/packages/cli/snap-tests-global/migration-no-git-repo/snap.txt @@ -19,18 +19,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > test -d .vite-hooks && echo 'hooks dir exists' || echo 'no hooks dir' hooks dir exists diff --git a/packages/cli/snap-tests-global/migration-no-hooks-with-husky/snap.txt b/packages/cli/snap-tests-global/migration-no-hooks-with-husky/snap.txt index 74aa2b4f85..8b823c5f5d 100644 --- a/packages/cli/snap-tests-global/migration-no-hooks-with-husky/snap.txt +++ b/packages/cli/snap-tests-global/migration-no-hooks-with-husky/snap.txt @@ -26,18 +26,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > test -d .husky && echo '.husky directory exists' || echo 'No .husky directory' # verify no .husky directory No .husky directory diff --git a/packages/cli/snap-tests-global/migration-no-hooks/snap.txt b/packages/cli/snap-tests-global/migration-no-hooks/snap.txt index 925cb2962f..2f04ba4e65 100644 --- a/packages/cli/snap-tests-global/migration-no-hooks/snap.txt +++ b/packages/cli/snap-tests-global/migration-no-hooks/snap.txt @@ -17,18 +17,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > test -d .vite-hooks && echo '.vite-hooks directory exists' || echo 'No .vite-hooks directory' # verify no .vite-hooks directory No .vite-hooks directory diff --git a/packages/cli/snap-tests-global/migration-other-hook-tool/snap.txt b/packages/cli/snap-tests-global/migration-other-hook-tool/snap.txt index eef56238fe..e6ed2a66c4 100644 --- a/packages/cli/snap-tests-global/migration-other-hook-tool/snap.txt +++ b/packages/cli/snap-tests-global/migration-other-hook-tool/snap.txt @@ -29,15 +29,51 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-oxlintrc-json-with-comments/snap.txt b/packages/cli/snap-tests-global/migration-oxlintrc-json-with-comments/snap.txt index 93c7a68d19..d46a591dd7 100644 --- a/packages/cli/snap-tests-global/migration-oxlintrc-json-with-comments/snap.txt +++ b/packages/cli/snap-tests-global/migration-oxlintrc-json-with-comments/snap.txt @@ -42,15 +42,51 @@ export default defineConfig({ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-oxlintrc-jsonc/snap.txt b/packages/cli/snap-tests-global/migration-oxlintrc-jsonc/snap.txt index b856f33ef6..80355d84ad 100644 --- a/packages/cli/snap-tests-global/migration-oxlintrc-jsonc/snap.txt +++ b/packages/cli/snap-tests-global/migration-oxlintrc-jsonc/snap.txt @@ -44,15 +44,51 @@ export default defineConfig({ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-partially-migrated-pre-commit/snap.txt b/packages/cli/snap-tests-global/migration-partially-migrated-pre-commit/snap.txt index ec77acdd83..10d47cf6d2 100644 --- a/packages/cli/snap-tests-global/migration-partially-migrated-pre-commit/snap.txt +++ b/packages/cli/snap-tests-global/migration-partially-migrated-pre-commit/snap.txt @@ -24,18 +24,54 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat .husky/pre-commit # hook file should be unchanged (still has bootstrap) . "$(dirname -- "$0")/_/husky.sh" diff --git a/packages/cli/snap-tests-global/migration-prettier-eslint-combo/snap.txt b/packages/cli/snap-tests-global/migration-prettier-eslint-combo/snap.txt index e3bb9a225e..596f00f4b4 100644 --- a/packages/cli/snap-tests-global/migration-prettier-eslint-combo/snap.txt +++ b/packages/cli/snap-tests-global/migration-prettier-eslint-combo/snap.txt @@ -28,18 +28,54 @@ Prettier configuration detected. Auto-migrating to Oxfmt... > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > test ! -f eslint.config.mjs # check eslint config is removed > test ! -f .prettierrc.json # check prettier config is removed diff --git a/packages/cli/snap-tests-global/migration-prettier-ignore-unknown/snap.txt b/packages/cli/snap-tests-global/migration-prettier-ignore-unknown/snap.txt index 9bae37b1c3..d126f6faa6 100644 --- a/packages/cli/snap-tests-global/migration-prettier-ignore-unknown/snap.txt +++ b/packages/cli/snap-tests-global/migration-prettier-ignore-unknown/snap.txt @@ -26,17 +26,53 @@ Prettier configuration detected. Auto-migrating to Oxfmt... > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > test ! -f .prettierrc.json # check prettier config is removed \ No newline at end of file diff --git a/packages/cli/snap-tests-global/migration-prettier-lint-staged/snap.txt b/packages/cli/snap-tests-global/migration-prettier-lint-staged/snap.txt index 3ec68f9b1e..683d158c51 100644 --- a/packages/cli/snap-tests-global/migration-prettier-lint-staged/snap.txt +++ b/packages/cli/snap-tests-global/migration-prettier-lint-staged/snap.txt @@ -23,18 +23,54 @@ Prettier configuration detected. Auto-migrating to Oxfmt... > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat vite.config.ts # check oxfmt config and staged config merged into vite.config.ts import { defineConfig } from "vite-plus"; diff --git a/packages/cli/snap-tests-global/migration-prettier-pkg-json/snap.txt b/packages/cli/snap-tests-global/migration-prettier-pkg-json/snap.txt index d781e11238..081c00717c 100644 --- a/packages/cli/snap-tests-global/migration-prettier-pkg-json/snap.txt +++ b/packages/cli/snap-tests-global/migration-prettier-pkg-json/snap.txt @@ -24,18 +24,54 @@ Prettier configuration detected. Auto-migrating to Oxfmt... > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > cat vite.config.ts # check oxfmt config merged into vite.config.ts with semi/singleQuote settings import { defineConfig } from "vite-plus"; diff --git a/packages/cli/snap-tests-global/migration-prettier/snap.txt b/packages/cli/snap-tests-global/migration-prettier/snap.txt index 88fcab928d..c77a503c08 100644 --- a/packages/cli/snap-tests-global/migration-prettier/snap.txt +++ b/packages/cli/snap-tests-global/migration-prettier/snap.txt @@ -26,18 +26,54 @@ Prettier configuration detected. Auto-migrating to Oxfmt... > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' > test ! -f .prettierrc.json # check prettier config is removed > cat vite.config.ts # check oxfmt config merged into vite.config.ts diff --git a/packages/cli/snap-tests-global/migration-rewrite-declare-module/snap.txt b/packages/cli/snap-tests-global/migration-rewrite-declare-module/snap.txt index 20088a9b48..753912fd8d 100644 --- a/packages/cli/snap-tests-global/migration-rewrite-declare-module/snap.txt +++ b/packages/cli/snap-tests-global/migration-rewrite-declare-module/snap.txt @@ -20,7 +20,7 @@ declare module 'vite-plus' { } } -declare module 'vite-plus/test' { +declare module 'vitest' { export const describe: any; export const it: any; export const expect: any; @@ -28,7 +28,7 @@ declare module 'vite-plus/test' { export const afterAll: any; } -declare module 'vite-plus' { +declare module 'vitest/config' { export function defineConfig(config: any): any; const _default: typeof defineConfig; export default _default; @@ -49,15 +49,51 @@ declare module 'vite-plus' { > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-skip-vite-dependency/snap.txt b/packages/cli/snap-tests-global/migration-skip-vite-dependency/snap.txt index eaf7a8b8e1..55d3c2fe1f 100644 --- a/packages/cli/snap-tests-global/migration-skip-vite-dependency/snap.txt +++ b/packages/cli/snap-tests-global/migration-skip-vite-dependency/snap.txt @@ -44,15 +44,51 @@ export default defineConfig({ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-skip-vite-peer-dependency/snap.txt b/packages/cli/snap-tests-global/migration-skip-vite-peer-dependency/snap.txt index 2110d21ce5..ebca02e4f6 100644 --- a/packages/cli/snap-tests-global/migration-skip-vite-peer-dependency/snap.txt +++ b/packages/cli/snap-tests-global/migration-skip-vite-peer-dependency/snap.txt @@ -44,15 +44,51 @@ export default defineConfig({ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-standalone-npm/snap.txt b/packages/cli/snap-tests-global/migration-standalone-npm/snap.txt index 54f57fb5b5..8f06e14f74 100644 --- a/packages/cli/snap-tests-global/migration-standalone-npm/snap.txt +++ b/packages/cli/snap-tests-global/migration-standalone-npm/snap.txt @@ -9,13 +9,22 @@ "name": "migration-standalone-npm", "devDependencies": { "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest", + "vitest": "4.1.5", "vite-plus": "latest" }, "packageManager": "npm@", "overrides": { "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + "vitest": "4.1.5", + "@vitest/expect": "4.1.5", + "@vitest/runner": "4.1.5", + "@vitest/snapshot": "4.1.5", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", + "@vitest/mocker": "4.1.5", + "@vitest/pretty-format": "4.1.5", + "@vitest/coverage-v8": "4.1.5", + "@vitest/coverage-istanbul": "4.1.5" } } diff --git a/packages/cli/snap-tests-global/migration-standalone-pnpm/snap.txt b/packages/cli/snap-tests-global/migration-standalone-pnpm/snap.txt index 93b4928ac8..a156c674eb 100644 --- a/packages/cli/snap-tests-global/migration-standalone-pnpm/snap.txt +++ b/packages/cli/snap-tests-global/migration-standalone-pnpm/snap.txt @@ -18,15 +18,51 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides, peerDependencyRules, and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-subpath/snap.txt b/packages/cli/snap-tests-global/migration-subpath/snap.txt index e9c62e5d63..188bea0ab5 100644 --- a/packages/cli/snap-tests-global/migration-subpath/snap.txt +++ b/packages/cli/snap-tests-global/migration-subpath/snap.txt @@ -38,15 +38,51 @@ core.hooksPath is not set > cat foo/pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-tsconfig-esmoduleinterop/snap.txt b/packages/cli/snap-tests-global/migration-tsconfig-esmoduleinterop/snap.txt index 8a3eeca749..5a69b1f72c 100644 --- a/packages/cli/snap-tests-global/migration-tsconfig-esmoduleinterop/snap.txt +++ b/packages/cli/snap-tests-global/migration-tsconfig-esmoduleinterop/snap.txt @@ -41,15 +41,51 @@ export default defineConfig({ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-vite-version/snap.txt b/packages/cli/snap-tests-global/migration-vite-version/snap.txt index 042250b04c..a3bb23f600 100644 --- a/packages/cli/snap-tests-global/migration-vite-version/snap.txt +++ b/packages/cli/snap-tests-global/migration-vite-version/snap.txt @@ -21,15 +21,51 @@ > cat pnpm-workspace.yaml # check pnpm-workspace.yaml has overrides and catalog catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/migration-vitest-peer-dep/snap.txt b/packages/cli/snap-tests-global/migration-vitest-peer-dep/snap.txt index 588753876e..9c0939021e 100644 --- a/packages/cli/snap-tests-global/migration-vitest-peer-dep/snap.txt +++ b/packages/cli/snap-tests-global/migration-vitest-peer-dep/snap.txt @@ -24,15 +24,51 @@ > cat pnpm-workspace.yaml catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + '@vitest/expect': + '@vitest/runner': + '@vitest/snapshot': + '@vitest/spy': + '@vitest/utils': + '@vitest/mocker': + '@vitest/pretty-format': + '@vitest/coverage-v8': + '@vitest/coverage-istanbul': vite-plus: latest overrides: vite: 'catalog:' vitest: 'catalog:' + '@vitest/expect': 'catalog:' + '@vitest/runner': 'catalog:' + '@vitest/snapshot': 'catalog:' + '@vitest/spy': 'catalog:' + '@vitest/utils': 'catalog:' + '@vitest/mocker': 'catalog:' + '@vitest/pretty-format': 'catalog:' + '@vitest/coverage-v8': 'catalog:' + '@vitest/coverage-istanbul': 'catalog:' peerDependencyRules: allowAny: - vite - vitest + - '@vitest/expect' + - '@vitest/runner' + - '@vitest/snapshot' + - '@vitest/spy' + - '@vitest/utils' + - '@vitest/mocker' + - '@vitest/pretty-format' + - '@vitest/coverage-v8' + - '@vitest/coverage-istanbul' allowedVersions: vite: '*' vitest: '*' + '@vitest/expect': '*' + '@vitest/runner': '*' + '@vitest/snapshot': '*' + '@vitest/spy': '*' + '@vitest/utils': '*' + '@vitest/mocker': '*' + '@vitest/pretty-format': '*' + '@vitest/coverage-v8': '*' + '@vitest/coverage-istanbul': '*' diff --git a/packages/cli/snap-tests-global/new-vite-monorepo-bun/snap.txt b/packages/cli/snap-tests-global/new-vite-monorepo-bun/snap.txt index 7ec03af6f9..0187513526 100644 --- a/packages/cli/snap-tests-global/new-vite-monorepo-bun/snap.txt +++ b/packages/cli/snap-tests-global/new-vite-monorepo-bun/snap.txt @@ -3,6 +3,7 @@ AGENTS.md README.md apps +bunfig.toml package.json packages tsconfig.json @@ -25,9 +26,19 @@ vite.config.ts "prepare": "vp config" }, "devDependencies": { + "vite": "catalog:", "vite-plus": "catalog:" }, "overrides": { + "@vitest/coverage-istanbul": "catalog:", + "@vitest/coverage-v8": "catalog:", + "@vitest/expect": "catalog:", + "@vitest/mocker": "catalog:", + "@vitest/pretty-format": "catalog:", + "@vitest/runner": "catalog:", + "@vitest/snapshot": "catalog:", + "@vitest/spy": "catalog:", + "@vitest/utils": "catalog:", "vite": "catalog:", "vitest": "catalog:" }, @@ -37,7 +48,16 @@ vite.config.ts "packageManager": "bun@", "catalog": { "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest", + "vitest": "4.1.5", + "@vitest/expect": "4.1.5", + "@vitest/runner": "4.1.5", + "@vitest/snapshot": "4.1.5", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", + "@vitest/mocker": "4.1.5", + "@vitest/pretty-format": "4.1.5", + "@vitest/coverage-v8": "4.1.5", + "@vitest/coverage-istanbul": "4.1.5", "vite-plus": "latest" } } diff --git a/packages/cli/snap-tests-global/new-vite-monorepo/snap.txt b/packages/cli/snap-tests-global/new-vite-monorepo/snap.txt index e0fb6cd576..324db25db6 100644 --- a/packages/cli/snap-tests-global/new-vite-monorepo/snap.txt +++ b/packages/cli/snap-tests-global/new-vite-monorepo/snap.txt @@ -55,18 +55,54 @@ catalog: "@types/node": ^24 typescript: ^5 vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + "@vitest/expect": + "@vitest/runner": + "@vitest/snapshot": + "@vitest/spy": + "@vitest/utils": + "@vitest/mocker": + "@vitest/pretty-format": + "@vitest/coverage-v8": + "@vitest/coverage-istanbul": vite-plus: latest overrides: vite: "catalog:" vitest: "catalog:" + "@vitest/expect": "catalog:" + "@vitest/runner": "catalog:" + "@vitest/snapshot": "catalog:" + "@vitest/spy": "catalog:" + "@vitest/utils": "catalog:" + "@vitest/mocker": "catalog:" + "@vitest/pretty-format": "catalog:" + "@vitest/coverage-v8": "catalog:" + "@vitest/coverage-istanbul": "catalog:" peerDependencyRules: allowAny: - vite - vitest + - "@vitest/expect" + - "@vitest/runner" + - "@vitest/snapshot" + - "@vitest/spy" + - "@vitest/utils" + - "@vitest/mocker" + - "@vitest/pretty-format" + - "@vitest/coverage-v8" + - "@vitest/coverage-istanbul" allowedVersions: vite: "*" vitest: "*" + "@vitest/expect": "*" + "@vitest/runner": "*" + "@vitest/snapshot": "*" + "@vitest/spy": "*" + "@vitest/utils": "*" + "@vitest/mocker": "*" + "@vitest/pretty-format": "*" + "@vitest/coverage-v8": "*" + "@vitest/coverage-istanbul": "*" > test -f vite-plus-monorepo/.gitignore && echo '.gitignore exists' || echo 'ERROR: .gitignore missing' # verify gitignore renamed from _gitignore .gitignore exists diff --git a/packages/cli/snap-tests/command-helper/snap.txt b/packages/cli/snap-tests/command-helper/snap.txt index 4321af05fb..fc6c1d1fe7 100644 --- a/packages/cli/snap-tests/command-helper/snap.txt +++ b/packages/cli/snap-tests/command-helper/snap.txt @@ -253,11 +253,11 @@ Options: -h, --help Display this message > vp test -h # test help message -vp test/ +vitest/ WARN: no options were found for your subcommands so we printed the whole output Usage: - $ vp test [...filters] + $ vitest [...filters] Commands: run [...filters] @@ -271,16 +271,16 @@ Commands: complete [shell] For more info, run any command with the `--help` flag: - $ vp test run --help - $ vp test related --help - $ vp test watch --help - $ vp test dev --help - $ vp test bench --help - $ vp test init --help - $ vp test list --help - $ vp test --help - $ vp test complete --help - $ vp test --help --expand-help + $ vitest run --help + $ vitest related --help + $ vitest watch --help + $ vitest dev --help + $ vitest bench --help + $ vitest init --help + $ vitest list --help + $ vitest --help + $ vitest complete --help + $ vitest --help --expand-help Options: -v, --version Display version number diff --git a/packages/cli/snap-tests/create-org-bundled-monorepo/snap.txt b/packages/cli/snap-tests/create-org-bundled-monorepo/snap.txt index 7c4209e2bd..861832d752 100644 --- a/packages/cli/snap-tests/create-org-bundled-monorepo/snap.txt +++ b/packages/cli/snap-tests/create-org-bundled-monorepo/snap.txt @@ -22,18 +22,54 @@ packages: - packages/* catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest + vitest: + "@vitest/expect": + "@vitest/runner": + "@vitest/snapshot": + "@vitest/spy": + "@vitest/utils": + "@vitest/mocker": + "@vitest/pretty-format": + "@vitest/coverage-v8": + "@vitest/coverage-istanbul": vite-plus: latest overrides: vite: "catalog:" vitest: "catalog:" + "@vitest/expect": "catalog:" + "@vitest/runner": "catalog:" + "@vitest/snapshot": "catalog:" + "@vitest/spy": "catalog:" + "@vitest/utils": "catalog:" + "@vitest/mocker": "catalog:" + "@vitest/pretty-format": "catalog:" + "@vitest/coverage-v8": "catalog:" + "@vitest/coverage-istanbul": "catalog:" peerDependencyRules: allowAny: - vite - vitest + - "@vitest/expect" + - "@vitest/runner" + - "@vitest/snapshot" + - "@vitest/spy" + - "@vitest/utils" + - "@vitest/mocker" + - "@vitest/pretty-format" + - "@vitest/coverage-v8" + - "@vitest/coverage-istanbul" allowedVersions: vite: "*" vitest: "*" + "@vitest/expect": "*" + "@vitest/runner": "*" + "@vitest/snapshot": "*" + "@vitest/spy": "*" + "@vitest/utils": "*" + "@vitest/mocker": "*" + "@vitest/pretty-format": "*" + "@vitest/coverage-v8": "*" + "@vitest/coverage-istanbul": "*" > test -d my-mono/.git && echo 'Git initialized' || echo 'No git' # git-init prompt covers bundled monorepo path Git initialized diff --git a/packages/cli/snap-tests/test-inline-snapshot-indent/snap.txt b/packages/cli/snap-tests/test-inline-snapshot-indent/snap.txt index 2fb66bcc52..1cb18f6450 100644 --- a/packages/cli/snap-tests/test-inline-snapshot-indent/snap.txt +++ b/packages/cli/snap-tests/test-inline-snapshot-indent/snap.txt @@ -1,5 +1,6 @@ > vp test run -u src/inline-snapshot.test.ts # write inline snapshot via --update (regression test for #1553) - RUN + + RUN v ✓ src/inline-snapshot.test.ts (1 test) ms diff --git a/packages/cli/snap-tests/vite-plugins-async-test/snap.txt b/packages/cli/snap-tests/vite-plugins-async-test/snap.txt index cb8596d640..cd91b5d731 100644 --- a/packages/cli/snap-tests/vite-plugins-async-test/snap.txt +++ b/packages/cli/snap-tests/vite-plugins-async-test/snap.txt @@ -1,5 +1,6 @@ > vp test # async plugins factory should load vitest plugin with configureVitest hook - RUN + + RUN v ✓ src/index.test.ts (1 test) ms diff --git a/packages/cli/snap-tests/vite-plugins-async-test/src/index.test.ts b/packages/cli/snap-tests/vite-plugins-async-test/src/index.test.ts index 7f37cab022..d6f3f94935 100644 --- a/packages/cli/snap-tests/vite-plugins-async-test/src/index.test.ts +++ b/packages/cli/snap-tests/vite-plugins-async-test/src/index.test.ts @@ -1,7 +1,7 @@ import fs from 'node:fs'; import path from 'node:path'; -import { expect, onTestFinished, test } from '@voidzero-dev/vite-plus-test'; +import { expect, onTestFinished, test } from 'vitest'; test('async plugin factory should load vitest plugin with configureVitest hook', () => { const markerPath = path.join(import.meta.dirname, '..', '.vitest-plugin-loaded'); diff --git a/packages/cli/src/__tests__/define-config-mocker-rewrite.spec.ts b/packages/cli/src/__tests__/define-config-mocker-rewrite.spec.ts new file mode 100644 index 0000000000..1e6782e12a --- /dev/null +++ b/packages/cli/src/__tests__/define-config-mocker-rewrite.spec.ts @@ -0,0 +1,162 @@ +import type { Plugin } from '@voidzero-dev/vite-plus-core'; +import { describe, expect, it } from 'vitest'; + +import { defineConfig, rewriteVitePlusTestSpecifier } from '../define-config.ts'; + +const REWRITE_PLUGIN_NAME = 'vite-plus:vitest-specifier-rewrite'; + +function pluginName(p: unknown): string | undefined { + if ( + p && + typeof p === 'object' && + 'name' in p && + typeof (p as { name: unknown }).name === 'string' + ) { + return (p as { name: string }).name; + } + return undefined; +} + +describe('rewriteVitePlusTestSpecifier', () => { + it('is a no-op when source does not mention vite-plus/test', () => { + const code = "import { describe } from 'vitest';\nimport * as fs from 'node:fs';\n"; + expect(rewriteVitePlusTestSpecifier(code)).toBe(code); + }); + + it("rewrites `from 'vite-plus/test'` to `from 'vitest'`", () => { + const input = "import { vi } from 'vite-plus/test';\nvi.mock('./foo');\n"; + const expected = "import { vi } from 'vitest';\nvi.mock('./foo');\n"; + expect(rewriteVitePlusTestSpecifier(input)).toBe(expected); + }); + + it('rewrites the double-quoted form too', () => { + const input = 'import { vi } from "vite-plus/test";\n'; + const expected = 'import { vi } from "vitest";\n'; + expect(rewriteVitePlusTestSpecifier(input)).toBe(expected); + }); + + it('does NOT rewrite subpaths such as vite-plus/test/browser', () => { + const input = "import { context } from 'vite-plus/test/browser';\n"; + expect(rewriteVitePlusTestSpecifier(input)).toBe(input); + }); + + it('does NOT rewrite a bare string literal containing vite-plus/test', () => { + const input = "const x = 'vite-plus/test';\nconsole.log(x);\n"; + expect(rewriteVitePlusTestSpecifier(input)).toBe(input); + }); + + it("rewrites dynamic `import('vite-plus/test')`", () => { + const input = "const mod = await import('vite-plus/test');\n"; + const expected = "const mod = await import('vitest');\n"; + expect(rewriteVitePlusTestSpecifier(input)).toBe(expected); + }); + + it("rewrites `require('vite-plus/test')` while leaving the subpath form alone", () => { + const input = [ + "const a = require('vite-plus/test');", + "const b = require('vite-plus/test/browser');", + '', + ].join('\n'); + const expected = [ + "const a = require('vitest');", + "const b = require('vite-plus/test/browser');", + '', + ].join('\n'); + expect(rewriteVitePlusTestSpecifier(input)).toBe(expected); + }); + + it('preserves all other imports in the file', () => { + const input = [ + "import { describe, it, expect } from 'vite-plus/test';", + "import * as fs from 'node:fs';", + "import { something } from 'vite-plus/test/browser';", + '', + ].join('\n'); + const expected = [ + "import { describe, it, expect } from 'vitest';", + "import * as fs from 'node:fs';", + "import { something } from 'vite-plus/test/browser';", + '', + ].join('\n'); + expect(rewriteVitePlusTestSpecifier(input)).toBe(expected); + }); +}); + +describe('defineConfig project plugin injection', () => { + it('injects rewrite plugin at the root plugins array', () => { + const existing: Plugin = { name: 'user-existing-root-plugin' }; + const result = defineConfig({ plugins: [existing] }) as { plugins: unknown[] }; + + expect(pluginName(result.plugins[0])).toBe(REWRITE_PLUGIN_NAME); + expect(pluginName(result.plugins[1])).toBe('user-existing-root-plugin'); + }); + + it('injects rewrite plugin into an inline-object project entry, preserving existing plugins', () => { + const existing: Plugin = { name: 'user-unit-project-plugin' }; + const result = defineConfig({ + test: { + projects: [ + { + plugins: [existing], + test: { name: 'unit', include: ['test/unit/**/*.spec.ts'], environment: 'node' }, + }, + ], + }, + }) as { test: { projects: unknown[] } }; + + const project = result.test.projects[0] as { plugins: unknown[]; test: { name: string } }; + expect(project.test.name).toBe('unit'); + expect(pluginName(project.plugins[0])).toBe(REWRITE_PLUGIN_NAME); + expect(pluginName(project.plugins[1])).toBe('user-unit-project-plugin'); + // Sanity: the existing plugin reference is preserved (clone shallow-copies the array). + expect(project.plugins[1]).toBe(existing); + }); + + it('injects rewrite plugin into the return value of a function-shaped project entry', () => { + const existing: Plugin = { name: 'user-fn-project-plugin' }; + const projectFn = () => ({ + plugins: [existing], + test: { name: 'nuxt', environment: 'happy-dom' as const }, + }); + const result = defineConfig({ + test: { projects: [projectFn] }, + }) as { test: { projects: unknown[] } }; + + const wrapped = result.test.projects[0]; + expect(typeof wrapped).toBe('function'); + + // Vitest passes a `ConfigEnv` to the function; we don't depend on its + // shape here, the wrapper just forwards it. + const fakeEnv = { mode: 'test', command: 'serve' as const }; + const resolved = (wrapped as (env: typeof fakeEnv) => { plugins: unknown[] })(fakeEnv); + expect(pluginName(resolved.plugins[0])).toBe(REWRITE_PLUGIN_NAME); + expect(pluginName(resolved.plugins[1])).toBe('user-fn-project-plugin'); + }); + + it('passes string-glob project entries through unchanged', () => { + const result = defineConfig({ + test: { + projects: ['./packages/*', './apps/*'], + }, + }) as { test: { projects: unknown[] } }; + + expect(result.test.projects).toEqual(['./packages/*', './apps/*']); + }); + + it('handles projects with no existing plugins array', () => { + const result = defineConfig({ + test: { + projects: [ + { + test: { name: 'no-plugins', environment: 'node' }, + }, + ], + }, + }) as { test: { projects: unknown[] } }; + + const project = result.test.projects[0] as { plugins: unknown[]; test: { name: string } }; + expect(project.test.name).toBe('no-plugins'); + expect(project.plugins).toHaveLength(1); + expect(pluginName(project.plugins[0])).toBe(REWRITE_PLUGIN_NAME); + }); +}); diff --git a/packages/cli/src/__tests__/define-config-test-field.spec.ts b/packages/cli/src/__tests__/define-config-test-field.spec.ts new file mode 100644 index 0000000000..f3a787b65f --- /dev/null +++ b/packages/cli/src/__tests__/define-config-test-field.spec.ts @@ -0,0 +1,45 @@ +import { describe, expect, it } from 'vitest'; + +import { + configDefaults, + coverageConfigDefaults, + defineConfig, + loadConfigFromFile, + mergeConfig, +} from '../index.js'; + +describe('defineConfig test field typing', () => { + it('accepts test config without TS error', () => { + const cfg = defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['src/**/*.spec.ts'], + }, + }); + void cfg; + }); + + it('accepts test config alongside other vite-plus fields', () => { + const cfg = defineConfig({ + test: { + globals: true, + environment: 'jsdom', + }, + lint: {}, + }); + void cfg; + }); + + it('re-exports shared and vitest-specific names without star-export conflicts', () => { + expect(typeof defineConfig).toBe('function'); + expect(typeof mergeConfig).toBe('function'); + expect(typeof loadConfigFromFile).toBe('function'); + expect(typeof configDefaults).toBe('object'); + expect(typeof coverageConfigDefaults).toBe('object'); + + const merged = mergeConfig({ test: { globals: true } }, { test: { environment: 'node' } }); + expect(merged.test.globals).toBe(true); + expect(merged.test.environment).toBe('node'); + }); +}); diff --git a/packages/cli/src/__tests__/exports-map.spec.ts b/packages/cli/src/__tests__/exports-map.spec.ts new file mode 100644 index 0000000000..d4fcaa709c --- /dev/null +++ b/packages/cli/src/__tests__/exports-map.spec.ts @@ -0,0 +1,88 @@ +/** + * Regression tests for the generated package.json `exports` map. + * + * Node.js package-exports conditions are order-sensitive: when resolving + * `require('vite-plus/test/config')`, Node walks the condition object and + * picks the first matching key. `default` matches everything, so a wrongly + * ordered map like `{ types, default, require }` causes CJS consumers to + * load the ESM shim — the `.cjs` shim becomes unreachable. + * + * These tests pin the invariant that any dual-condition entry emits + * `require` BEFORE `default` and that runtime resolution returns the + * expected file extension for each consumer. + */ +import fs from 'node:fs'; +import { createRequire } from 'node:module'; +import path from 'node:path'; +import url from 'node:url'; + +import { describe, expect, it } from 'vitest'; + +const cliPkgDir = path.resolve(path.dirname(url.fileURLToPath(import.meta.url)), '../..'); +const cliPkgJsonPath = path.join(cliPkgDir, 'package.json'); +const requireFromHere = createRequire(import.meta.url); + +type ExportConditions = Record; + +function isConditionObject(value: unknown): value is ExportConditions { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +describe('package.json exports map', () => { + it('every dual-condition entry emits `require` before `default`', () => { + const pkg = JSON.parse(fs.readFileSync(cliPkgJsonPath, 'utf-8')); + const exports = pkg.exports as Record; + + const offenders: Array<{ path: string; order: string[] }> = []; + + function walk(subpath: string, value: unknown) { + if (!isConditionObject(value)) { + return; + } + const keys = Object.keys(value); + const requireIdx = keys.indexOf('require'); + const defaultIdx = keys.indexOf('default'); + if (requireIdx !== -1 && defaultIdx !== -1 && requireIdx > defaultIdx) { + offenders.push({ path: subpath, order: keys }); + } + for (const [k, v] of Object.entries(value)) { + walk(`${subpath} > ${k}`, v); + } + } + + for (const [subpath, value] of Object.entries(exports)) { + walk(subpath, value); + } + + expect(offenders, 'entries with require ordered after default').toEqual([]); + }); + + it('./test/config has both `require` and `default`, with `require` first', () => { + const pkg = JSON.parse(fs.readFileSync(cliPkgJsonPath, 'utf-8')); + const entry = (pkg.exports as Record)['./test/config']; + expect(isConditionObject(entry)).toBe(true); + const keys = Object.keys(entry as ExportConditions); + expect(keys).toContain('require'); + expect(keys).toContain('default'); + expect(keys.indexOf('require')).toBeLessThan(keys.indexOf('default')); + }); + + it('`require.resolve("vite-plus/test/config")` resolves to the .cjs shim', () => { + const resolved = requireFromHere.resolve('vite-plus/test/config'); + expect(resolved.endsWith('.cjs'), `resolved to ${resolved}`).toBe(true); + }); + + it('ESM `import.meta.resolve("vite-plus/test/config")` resolves to the .js shim', () => { + // import.meta.resolve is sync in modern Node (>= 20.6) and respects the + // `default` (ESM) condition for ESM consumers. + const resolved = import.meta.resolve('vite-plus/test/config'); + expect(resolved.endsWith('.js'), `resolved to ${resolved}`).toBe(true); + }); + + it('CJS shim at ./test/config delegates to vitest/config via require()', () => { + const cfg = requireFromHere('vite-plus/test/config') as Record; + expect(cfg).toBeTypeOf('object'); + // vitest/config re-exports defineConfig / configDefaults — sanity-check one. + expect(typeof cfg.defineConfig).toBe('function'); + }); +}); diff --git a/packages/cli/src/__tests__/index.spec.ts b/packages/cli/src/__tests__/index.spec.ts index 10ff3b8a21..161e082bd6 100644 --- a/packages/cli/src/__tests__/index.spec.ts +++ b/packages/cli/src/__tests__/index.spec.ts @@ -1,4 +1,4 @@ -import { afterEach, beforeEach, expect, test, vi } from '@voidzero-dev/vite-plus-test'; +import { afterEach, beforeEach, expect, test, vi } from 'vitest'; import { configDefaults, @@ -90,6 +90,17 @@ test('lazyPlugins wraps sync function returning a Promise into array', () => { expect(result).not.toBeInstanceOf(Promise); }); +// defineConfig auto-injects a `vite-plus:vitest-specifier-rewrite` plugin at +// index 0 so user-supplied plugins start at index 1. The helpers below let the +// tests assert on user-supplied plugins regardless of the injection. +const REWRITE_PLUGIN_NAME = 'vite-plus:vitest-specifier-rewrite'; +const userPlugins = (plugins: unknown): unknown[] => { + expect(Array.isArray(plugins)).toBe(true); + const arr = plugins as unknown[]; + expect((arr[0] as { name?: string })?.name).toBe(REWRITE_PLUGIN_NAME); + return arr.slice(1); +}; + // lazyPlugins type compatibility tests — these verify at compile time that // lazyPlugins return types satisfy Vite's plugins?: PluginOption[] field. @@ -99,7 +110,7 @@ test('lazyPlugins sync return type satisfies plugins field', () => { const config = defineConfig({ plugins: lazyPlugins(() => [{ name: 'sync-type-test' }]), }); - expect(config.plugins?.length).toBe(1); + expect(userPlugins(config.plugins).length).toBe(1); }); test('lazyPlugins async return type satisfies plugins field', () => { @@ -119,7 +130,8 @@ test('lazyPlugins undefined return satisfies plugins field', () => { const config = defineConfig({ plugins: lazyPlugins(() => [{ name: 'skipped' }]), }); - expect(config.plugins).toBeUndefined(); + // lazyPlugins returns undefined, but defineConfig still injects its rewrite plugin. + expect(userPlugins(config.plugins).length).toBe(0); }); test('lazyPlugins with vitest configureVitest plugin satisfies plugins field', () => { @@ -132,7 +144,7 @@ test('lazyPlugins with vitest configureVitest plugin satisfies plugins field', ( }, ]), }); - expect(config.plugins?.length).toBe(1); + expect(userPlugins(config.plugins).length).toBe(1); }); // defineConfig compatibility tests @@ -141,35 +153,35 @@ test('defineConfig passes through plain plugins array', () => { const config = defineConfig({ plugins: [{ name: 'test-plugin' }], }); - expect(config.plugins?.length).toBe(1); + expect(userPlugins(config.plugins).length).toBe(1); }); test('defineConfig supports Plugin objects in plugins array', () => { const config = defineConfig({ plugins: [{ name: 'plugin-a' }, { name: 'plugin-b' }], }); - expect(config.plugins?.length).toBe(2); + expect(userPlugins(config.plugins).length).toBe(2); }); test('defineConfig supports falsy values in plugins array', () => { const config = defineConfig({ plugins: [{ name: 'real-plugin' }, false, null, undefined], }); - expect(config.plugins?.length).toBe(4); + expect(userPlugins(config.plugins).length).toBe(4); }); test('defineConfig supports nested plugin arrays', () => { const config = defineConfig({ plugins: [[{ name: 'nested-a' }, { name: 'nested-b' }], { name: 'top-level' }], }); - expect(config.plugins?.length).toBe(2); + expect(userPlugins(config.plugins).length).toBe(2); }); test('defineConfig supports Promise in plugins array', () => { const config = defineConfig({ plugins: [Promise.resolve({ name: 'async-plugin' })], }); - expect(config.plugins?.length).toBe(1); + expect(userPlugins(config.plugins).length).toBe(1); }); test('defineConfig supports mixed PluginOption types in array', () => { @@ -183,19 +195,20 @@ test('defineConfig supports mixed PluginOption types in array', () => { undefined, ], }); - expect(config.plugins?.length).toBe(6); + expect(userPlugins(config.plugins).length).toBe(6); }); test('defineConfig supports empty plugins array', () => { const config = defineConfig({ plugins: [], }); - expect(config.plugins?.length).toBe(0); + expect(userPlugins(config.plugins).length).toBe(0); }); test('defineConfig supports config without plugins', () => { const config = defineConfig({}); - expect(config.plugins).toBeUndefined(); + // defineConfig always injects its rewrite plugin even when user omits `plugins`. + expect(userPlugins(config.plugins).length).toBe(0); }); test('defineConfig supports function config with plain plugins array', () => { @@ -203,7 +216,7 @@ test('defineConfig supports function config with plain plugins array', () => { plugins: [{ name: 'fn-plugin' }], })); const config = configFn({ command: 'build', mode: 'production' }); - expect(config.plugins?.length).toBe(1); + expect(userPlugins(config.plugins).length).toBe(1); }); test('defineConfig supports async function config with plain plugins array', async () => { @@ -211,7 +224,7 @@ test('defineConfig supports async function config with plain plugins array', asy plugins: [{ name: 'async-fn-plugin' }], })); const config = await configFn({ command: 'build', mode: 'production' }); - expect(config.plugins?.length).toBe(1); + expect(userPlugins(config.plugins).length).toBe(1); }); test('defineConfig supports vitest plugin with configureVitest hook', () => { @@ -225,6 +238,7 @@ test('defineConfig supports vitest plugin with configureVitest hook', () => { }, ], }); - expect(config.plugins?.length).toBe(1); - expect((config.plugins?.[0] as { name: string })?.name).toBe('vitest-plugin'); + const userOnly = userPlugins(config.plugins); + expect(userOnly.length).toBe(1); + expect((userOnly[0] as { name: string })?.name).toBe('vitest-plugin'); }); diff --git a/packages/cli/src/__tests__/pack.spec.ts b/packages/cli/src/__tests__/pack.spec.ts index 4ab798865c..cda2669b89 100644 --- a/packages/cli/src/__tests__/pack.spec.ts +++ b/packages/cli/src/__tests__/pack.spec.ts @@ -1,4 +1,4 @@ -import { expect, test } from '@voidzero-dev/vite-plus-test'; +import { expect, test } from 'vitest'; import { build, diff --git a/packages/cli/src/__tests__/resolve-lint.spec.ts b/packages/cli/src/__tests__/resolve-lint.spec.ts index de1c7755f9..e0b6492651 100644 --- a/packages/cli/src/__tests__/resolve-lint.spec.ts +++ b/packages/cli/src/__tests__/resolve-lint.spec.ts @@ -1,6 +1,6 @@ import { existsSync } from 'node:fs'; -import { describe, expect, it } from '@voidzero-dev/vite-plus-test'; +import { describe, expect, it } from 'vitest'; import { lint } from '../resolve-lint.js'; diff --git a/packages/cli/src/__tests__/versions.spec.ts b/packages/cli/src/__tests__/versions.spec.ts index c8ef59dd9a..c66900fe7f 100644 --- a/packages/cli/src/__tests__/versions.spec.ts +++ b/packages/cli/src/__tests__/versions.spec.ts @@ -5,15 +5,16 @@ * that syncVersionsExport() produces correct artifacts. */ import fs from 'node:fs'; +import { createRequire } from 'node:module'; import path from 'node:path'; import url from 'node:url'; -import { describe, expect, it } from '@voidzero-dev/vite-plus-test'; +import { describe, expect, it } from 'vitest'; const cliPkgDir = path.resolve(path.dirname(url.fileURLToPath(import.meta.url)), '../..'); const distDir = path.join(cliPkgDir, 'dist'); const corePkgPath = path.join(cliPkgDir, '../core/package.json'); -const testPkgPath = path.join(cliPkgDir, '../test/package.json'); +const vitestPkgPath = createRequire(import.meta.url).resolve('vitest/package.json'); describe('versions export', () => { describe('build artifacts', () => { @@ -48,15 +49,13 @@ describe('versions export', () => { } }); - it('should contain all test bundledVersions', async () => { - const testPkg = JSON.parse(fs.readFileSync(testPkgPath, 'utf-8')); + it('should contain vitest version matching installed package', async () => { + const vitestPkg = JSON.parse(fs.readFileSync(vitestPkgPath, 'utf-8')); const mod = await import('../../dist/versions.js'); const versions = mod.versions as Record; - for (const [key, value] of Object.entries( - testPkg.bundledVersions as Record, - )) { - expect(versions[key], `versions.${key} should match test bundledVersions`).toBe(value); - } + expect(versions.vitest, 'versions.vitest should match installed vitest version').toBe( + vitestPkg.version, + ); }); }); diff --git a/packages/cli/src/define-config.ts b/packages/cli/src/define-config.ts index df4f333c36..fe3f49c707 100644 --- a/packages/cli/src/define-config.ts +++ b/packages/cli/src/define-config.ts @@ -1,10 +1,13 @@ import type { PluginOption, UserConfig } from '@voidzero-dev/vite-plus-core'; +import type { OxfmtConfig } from 'oxfmt'; +import type { OxlintConfig } from 'oxlint'; import { defineConfig as viteDefineConfig, type ConfigEnv, -} from '@voidzero-dev/vite-plus-test/config'; -import type { OxfmtConfig } from 'oxfmt'; -import type { OxlintConfig } from 'oxlint'; + type TestProjectConfiguration, + type UserProjectConfigFn, +} from 'vitest/config'; +import type { InlineConfig as VitestInlineConfig } from 'vitest/node'; import type { PackUserConfig } from './pack.ts'; import type { RunConfig } from './run-config.ts'; @@ -39,6 +42,16 @@ declare module '@voidzero-dev/vite-plus-core' { */ defaultTemplate?: string; }; + + /** + * Vitest test configuration. + * + * Vitest augments vite's `UserConfig` with a `test` field via + * `declare module 'vite'`, but vite-plus-core is a fork of vite so that + * augmentation does not apply here. Re-declare it locally so user + * configs like `defineConfig({ test: { globals: true } })` typecheck. + */ + test?: VitestInlineConfig; } } @@ -52,6 +65,124 @@ type ViteUserConfigExport = | ViteUserConfigFnPromise | ViteUserConfigFn; +/** + * Rewrite bare-root `vite-plus/test` import specifiers to `vitest` so that + * `@vitest/mocker`'s static hoister (which hardcodes `hoistedModule = "vitest"`) + * recognizes calls like `vi.mock(...)`. Subpaths such as + * `vite-plus/test/browser` are intentionally left unchanged. + * + * Task #50 pins `vitest` and the `@vitest/*` family so both specifiers resolve + * to the same physical module, making this rewrite runtime-safe. + * + * Exported for unit testing. + */ +export function rewriteVitePlusTestSpecifier(code: string): string { + if (!code.includes('vite-plus/test')) { + return code; + } + return code + .replace(/(from\s+['"])vite-plus\/test(?=['"])/g, '$1vitest') + .replace(/(import\s*\(\s*['"])vite-plus\/test(?=['"])/g, '$1vitest') + .replace(/(require\s*\(\s*['"])vite-plus\/test(?=['"])/g, '$1vitest'); +} + +function vitePlusTestSpecifierRewritePlugin(): PluginOption { + return { + name: 'vite-plus:vitest-specifier-rewrite', + enforce: 'pre', + transform(code, id) { + if (id.includes('/node_modules/')) { + return null; + } + const newCode = rewriteVitePlusTestSpecifier(code); + if (newCode === code) { + return null; + } + return { code: newCode, map: null }; + }, + }; +} + +/** + * Inject the rewrite plugin into a single inline project config. Used both + * for root configs and for object-shaped entries inside `test.projects`. + * + * The shapes overlap (both have an optional top-level `plugins` array), so a + * shared helper keeps the wiring consistent. + */ +function injectPluginIntoInlineConfig(config: T): T { + return { + ...config, + plugins: [vitePlusTestSpecifierRewritePlugin(), ...(config.plugins ?? [])], + }; +} + +/** + * Walk `config.test?.projects` and inject the rewrite plugin into each + * project entry. Vitest spins up an independent Vite pipeline per project, so + * root-level plugins do NOT propagate — without this, files matched by a + * project's `include` glob never get the `vite-plus/test` → `vitest` rewrite. + * + * Entry shapes (from `TestProjectConfiguration`): + * - string (glob path like `'./packages/*'`) → passed through unchanged. + * - object (inline config with `test: {...}`) → clone and prepend plugin. + * - function (sync or async) → wrap so its result is injected. + * - Promise (resolves to inline config) → chain `.then(injectPlugin)`. + */ +function injectPluginIntoProject(project: TestProjectConfiguration): TestProjectConfiguration { + if (typeof project === 'string') { + return project; + } + if (typeof project === 'function') { + const wrapped: UserProjectConfigFn = (env: ConfigEnv) => { + const result = project(env); + if (result instanceof Promise) { + return result.then(injectPluginIntoInlineConfig); + } + return injectPluginIntoInlineConfig(result); + }; + return wrapped; + } + if (project instanceof Promise) { + return project.then(injectPluginIntoInlineConfig); + } + if (typeof project === 'object' && project !== null) { + return injectPluginIntoInlineConfig(project); + } + return project; +} + +function injectPlugin(config: UserConfig): UserConfig { + const injected = injectPluginIntoInlineConfig(config); + const projects = injected.test?.projects; + if (!projects || projects.length === 0) { + return injected; + } + return { + ...injected, + test: { + ...injected.test, + projects: projects.map(injectPluginIntoProject), + }, + }; +} + +function injectPluginIntoConfig(config: ViteUserConfigExport): ViteUserConfigExport { + if (typeof config === 'function') { + return (env: ConfigEnv) => { + const result = config(env); + if (result instanceof Promise) { + return result.then(injectPlugin); + } + return injectPlugin(result); + }; + } + if (config instanceof Promise) { + return config.then(injectPlugin); + } + return injectPlugin(config); +} + export function defineConfig(config: UserConfig): UserConfig; export function defineConfig(config: Promise): Promise; export function defineConfig(config: ViteUserConfigFnObject): ViteUserConfigFnObject; @@ -59,7 +190,7 @@ export function defineConfig(config: ViteUserConfigFnPromise): ViteUserConfigFnP export function defineConfig(config: ViteUserConfigExport): ViteUserConfigExport; export function defineConfig(config: ViteUserConfigExport): ViteUserConfigExport { - return viteDefineConfig(config); + return viteDefineConfig(injectPluginIntoConfig(config)); } const VITE_COMMANDS = new Set(['dev', 'build', 'test', 'preview']); diff --git a/packages/cli/src/index.cts b/packages/cli/src/index.cts index 02f4874efb..fb19977f1b 100644 --- a/packages/cli/src/index.cts +++ b/packages/cli/src/index.cts @@ -1,6 +1,6 @@ const vite = require('@voidzero-dev/vite-plus-core'); -const vitest = require('@voidzero-dev/vite-plus-test/config'); +const vitest = require('vitest/config'); const { defineConfig, lazyPlugins } = require('./define-config'); diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 1d9d932662..ae6440f7c9 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -2,6 +2,29 @@ import { defineConfig, lazyPlugins } from './define-config.ts'; export * from '@voidzero-dev/vite-plus-core'; -export * from '@voidzero-dev/vite-plus-test/config'; +export { + configDefaults, + coverageConfigDefaults, + defaultBrowserPort, + defaultExclude, + defaultInclude, + defineProject, +} from 'vitest/config'; + +export type { + TestProjectConfiguration, + TestProjectInlineConfiguration, + TestTagDefinition, + TestUserConfig, + UserProjectConfigExport, + UserProjectConfigFn, + UserWorkspaceConfig, + ViteUserConfig, + ViteUserConfigExport, + ViteUserConfigFn, + ViteUserConfigFnObject, + ViteUserConfigFnPromise, + WatcherTriggerPattern, +} from 'vitest/config'; export { defineConfig, lazyPlugins }; diff --git a/packages/cli/src/migration/__tests__/bun-catalog-file-protocol.spec.ts b/packages/cli/src/migration/__tests__/bun-catalog-file-protocol.spec.ts index e4050a529b..d2d773fa75 100644 --- a/packages/cli/src/migration/__tests__/bun-catalog-file-protocol.spec.ts +++ b/packages/cli/src/migration/__tests__/bun-catalog-file-protocol.spec.ts @@ -14,9 +14,7 @@ vi.mock('../../utils/constants.js', async (importOriginal) => { VITE_PLUS_VERSION: 'file:/tmp/tgz/vite-plus-0.0.0.tgz', VITE_PLUS_OVERRIDE_PACKAGES: { vite: 'file:/tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz', - vitest: 'file:/tmp/tgz/voidzero-dev-vite-plus-test-0.0.0.tgz', '@voidzero-dev/vite-plus-core': 'file:/tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz', - '@voidzero-dev/vite-plus-test': 'file:/tmp/tgz/voidzero-dev-vite-plus-test-0.0.0.tgz', }, }; }); @@ -78,13 +76,11 @@ describe('rewriteMonorepo bun catalog with file: protocol', () => { // overrides should use file: paths directly, not catalog: const overrides = pkg.overrides as Record; expect(overrides.vite).toBe('file:/tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz'); - expect(overrides.vitest).toBe('file:/tmp/tgz/voidzero-dev-vite-plus-test-0.0.0.tgz'); + expect(overrides.vitest).toBeUndefined(); expect(overrides['@voidzero-dev/vite-plus-core']).toBe( 'file:/tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz', ); - expect(overrides['@voidzero-dev/vite-plus-test']).toBe( - 'file:/tmp/tgz/voidzero-dev-vite-plus-test-0.0.0.tgz', - ); + expect(overrides['@voidzero-dev/vite-plus-test']).toBeUndefined(); }); it('does not write file: paths into named catalogs', () => { @@ -127,6 +123,64 @@ describe('rewriteMonorepo bun catalog with file: protocol', () => { expect(pkg.devDependencies.vite).toBe('file:/tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz'); }); + it('writes bunfig.toml with `peer = false` so vitest peer-dep on vite does not break install', () => { + // vitest@4.1.5 declares peer vite^6/^7/^8. With overrides.vite pointing at + // file:vite-plus-core@0.0.0 (whose package.json version does not match), + // bun aborts the install. pnpm/yarn/npm tolerate this; bun has no equivalent + // to pnpm's peerDependencyRules and only respects the `[install] peer = false` + // setting in bunfig.toml. The migrator must emit that file or every bun + // user hits `error: vite@^6.0.0 || ^7.0.0 || ^8.0.0 failed to resolve`. + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ + name: 'bun-monorepo', + workspaces: ['packages/*'], + packageManager: 'bun@1.3.11', + }), + ); + rewriteMonorepo(makeWorkspaceInfo(tmpDir, PackageManager.bun), true); + + const bunfigPath = path.join(tmpDir, 'bunfig.toml'); + expect(fs.existsSync(bunfigPath)).toBe(true); + expect(fs.readFileSync(bunfigPath, 'utf8')).toMatch(/^\[install\][\s\S]*peer\s*=\s*false/m); + }); + + it('preserves an existing bunfig.toml `peer` setting (does not overwrite user intent)', () => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ + name: 'bun-monorepo', + workspaces: ['packages/*'], + packageManager: 'bun@1.3.11', + }), + ); + fs.writeFileSync(path.join(tmpDir, 'bunfig.toml'), '[install]\npeer = true\n'); + rewriteMonorepo(makeWorkspaceInfo(tmpDir, PackageManager.bun), true); + + // User's explicit `peer = true` should remain — we don't silently flip it. + expect(fs.readFileSync(path.join(tmpDir, 'bunfig.toml'), 'utf8')).toMatch(/peer\s*=\s*true/); + }); + + it('appends `peer = false` under an existing [install] section without `peer` setting', () => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ + name: 'bun-monorepo', + workspaces: ['packages/*'], + packageManager: 'bun@1.3.11', + }), + ); + fs.writeFileSync( + path.join(tmpDir, 'bunfig.toml'), + '[install]\nregistry = "https://registry.npmjs.org/"\n', + ); + rewriteMonorepo(makeWorkspaceInfo(tmpDir, PackageManager.bun), true); + + const bunfig = fs.readFileSync(path.join(tmpDir, 'bunfig.toml'), 'utf8'); + expect(bunfig).toMatch(/registry\s*=\s*"https:\/\/registry\.npmjs\.org\/"/); + expect(bunfig).toMatch(/peer\s*=\s*false/); + }); + it('does not write file: paths into peer dependencies', () => { const pkg = { peerDependencies: { @@ -141,7 +195,7 @@ describe('rewriteMonorepo bun catalog with file: protocol', () => { rewritePackageJson(pkg, PackageManager.pnpm, true); expect(pkg.peerDependencies.vite).toBe('^7.0.0'); - expect(pkg.peerDependencies.vitest).toBe('*'); + expect(pkg.peerDependencies.vitest).toBe('catalog:test'); expect(pkg.optionalDependencies.vite).toBe( 'file:/tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz', ); diff --git a/packages/cli/src/migration/__tests__/install-failure-guard.spec.ts b/packages/cli/src/migration/__tests__/install-failure-guard.spec.ts new file mode 100644 index 0000000000..6304c1f2fa --- /dev/null +++ b/packages/cli/src/migration/__tests__/install-failure-guard.spec.ts @@ -0,0 +1,77 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { describe, expect, it } from 'vitest'; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const binPath = path.resolve(here, '..', 'bin.ts'); + +/** + * `runViteInstall` returns `{ status: 'failed', exitCode }` (it does not throw) + * when the install process exits non-zero. Earlier versions of `migration/bin.ts` + * only summed `installSummary.durationMs` and reported success regardless of + * `status`, which left the project's `node_modules` desynced from a freshly + * mutated `package.json` (network/auth failures, registry blips, pnpm lockfile + * conflicts after override resolution) while still printing + * "Dependencies installed" to the user. + * + * Two install sites need this handling: + * 1. The full migration path (`executeMigrationPlan`'s final reinstall, run + * AFTER manifest/source rewrites land). + * 2. The early-return path (`main` when `vite-plus` is already a dep but a + * stale-wrapper repair or ESLint/Prettier migration touches package.json). + * + * Both paths must funnel install results through `handleInstallResult` so that + * failures warn the user, append to `report.warnings`, and flip + * `process.exitCode`. This is a guard test — if a future refactor drops the + * helper or stops calling it from either path, this fails loudly so reviewers + * can re-evaluate the install-failure UX before it ships. + */ +describe('migration install failure handling', () => { + const binSource = fs.readFileSync(binPath, 'utf8'); + + describe('handleInstallResult helper', () => { + it('defines a `handleInstallResult` function in bin.ts', () => { + expect(binSource).toMatch(/function handleInstallResult\s*\(/); + }); + + it('branches on `installSummary.status === "installed"` and credits duration', () => { + expect(binSource).toMatch(/installSummary\.status === 'installed'/); + expect(binSource).toMatch(/return installSummary\.durationMs/); + }); + + it('branches on `installSummary.status === "failed"` and warns + flips exitCode', () => { + expect(binSource).toMatch(/installSummary\.status === 'failed'/); + expect(binSource).toMatch(/warnMsg\(/); + expect(binSource).toMatch(/report\.warnings\.push\(/); + expect(binSource).toMatch(/process\.exitCode\s*=/); + }); + }); + + describe('full migration path (executeMigrationPlan)', () => { + it('reconciles `finalInstallSummary` through `handleInstallResult`', () => { + // The full-path final reinstall must run through the helper so a failed + // install after manifest/source rewrites does not silently report a + // desynced project as a successful migration. + expect(binSource).toMatch(/finalInstallSummary[\s\S]{0,1500}handleInstallResult\(/); + }); + + it('does NOT add `finalInstallSummary.durationMs` directly to the return value', () => { + // The buggy round-7 version returned + // `initialInstallSummary.durationMs + finalInstallSummary.durationMs` + // unconditionally. The fix routes `finalInstallSummary` through the + // helper which returns 0 on failure. Catch any regression that re-adds + // the raw `.durationMs` access. + expect(binSource).not.toMatch(/finalInstallSummary\.durationMs/); + }); + }); + + describe('early-return path (main, hasVitePlusDependency branch)', () => { + it('reconciles `installSummary` through `handleInstallResult`', () => { + expect(binSource).toMatch( + /const installSummary = await runViteInstall\([\s\S]{0,1500}handleInstallResult\(/, + ); + }); + }); +}); diff --git a/packages/cli/src/migration/__tests__/migrator.spec.ts b/packages/cli/src/migration/__tests__/migrator.spec.ts index 45b094caa7..b88a79ed05 100644 --- a/packages/cli/src/migration/__tests__/migrator.spec.ts +++ b/packages/cli/src/migration/__tests__/migrator.spec.ts @@ -170,6 +170,8 @@ describe('rewritePackageJson', () => { rewritePackageJson(pkg, PackageManager.yarn, true); expect(pkg.devDependencies.vite).toBe('catalog:'); + // vitest is a managed override key — non-catalog specs are rewritten to + // `catalog:` so the override is resolved through the catalog. expect(pkg.dependencies.vitest).toBe('catalog:'); expect((pkg.devDependencies as Record)['vite-plus']).toBe('catalog:'); }); @@ -189,7 +191,10 @@ describe('rewritePackageJson', () => { expect(pkg.devDependencies.vite).toBe('catalog:'); expect(pkg.optionalDependencies.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); - expect(pkg.optionalDependencies.vitest).toBe('npm:@voidzero-dev/vite-plus-test@latest'); + // vitest is now a managed override key — yarn optional deps receive the + // literal override version so the resolution doesn't depend on catalog + // lookup at the optionalDependency site. + expect(pkg.optionalDependencies.vitest).toBe('4.1.5'); expect((pkg.devDependencies as Record)['vite-plus']).toBe('catalog:'); }); @@ -653,7 +658,9 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { const overrides = pnpm.overrides as Record; expect(overrides['some-pkg']).toBe('1.0.0'); expect(overrides.vite).toBeDefined(); - expect(overrides.vitest).toBeDefined(); + // vitest is pinned via overrides so downstream projects resolve a single + // vitest copy (the one vp-cli ships). + expect(overrides.vitest).toBe('4.1.5'); // peerDependencyRules should be present expect(pnpm.peerDependencyRules).toBeDefined(); @@ -683,8 +690,9 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { const pkg = readJson(path.join(tmpDir, 'package.json')); const pnpm = pkg.pnpm as Record; const rules = pnpm.peerDependencyRules as Record; - // Custom entries preserved, Vite entries merged - expect(rules.allowAny).toEqual(expect.arrayContaining(['react', 'vite', 'vitest'])); + // Custom entries preserved, Vite entries merged (vitest is no longer + // injected as it's not a managed override key anymore). + expect(rules.allowAny).toEqual(expect.arrayContaining(['react', 'vite'])); // ignoreMissing preserved expect(rules.ignoreMissing).toEqual(['@types/node']); }); @@ -698,6 +706,8 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { const yaml = readYaml(path.join(tmpDir, 'pnpm-workspace.yaml')); expect(yaml).toContain("vite: 'catalog:'"); + // vitest is now a managed override key — it resolves through the catalog + // like vite does. expect(yaml).toContain("vitest: 'catalog:'"); }); @@ -741,12 +751,16 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { catalogs: Record>; }; expect(yaml.overrides.vite).toBe('catalog:vite7'); + // vitest is now a managed override key — it is added to overrides as a + // `catalog:` reference, and its catalog entry is rewritten to the pinned + // vitest version vp-cli ships. expect(yaml.overrides.vitest).toBe('catalog:'); - expect(yaml.catalog.vitest).toBe('npm:@voidzero-dev/vite-plus-test@latest'); + expect(yaml.catalog.vitest).toBe('4.1.5'); expect(yaml.catalogs.vite7.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); expect(yaml.catalogs.vite7.react).toBe('^18.0.0'); expect(yaml.catalogs.vite7['vite-plus']).toBe('latest'); - expect(yaml.catalogs.test.vitest).toBe('npm:@voidzero-dev/vite-plus-test@latest'); + // Named catalog vitest entries are also pinned to the managed override version. + expect(yaml.catalogs.test.vitest).toBe('4.1.5'); expect(yaml.catalogs.test.tsdown).toBeUndefined(); expect(yaml.catalogs.test['vite-plus']).toBeUndefined(); @@ -757,6 +771,10 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { expect(pkg.devDependencies.vite).toBe('catalog:vite7'); expect(pkg.devDependencies['vite-plus']).toBe('catalog:'); expect(pkg.peerDependencies.vite).toBe('^7.0.0'); + // vitest peer `catalog:` is resolved against the pre-rewrite catalog + // (which still holds the user's `^4.0.0`); only the catalog file itself + // is later rewritten to the pinned vp-cli version. The peer range stays + // as the user wrote it. expect(pkg.peerDependencies.vitest).toBe('^4.0.0'); expect(pkg.peerDependencies).not.toHaveProperty('tsdown'); }); @@ -788,6 +806,7 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { catalogs: Record>; }; expect(yaml.overrides.vite).toBe('catalog:vite7'); + // vitest is now injected into overrides as a managed override key. expect(yaml.overrides.vitest).toBe('catalog:'); expect(yaml.overrides.react).toBe('^18.0.0'); expect(yaml.catalogs.vite7.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); @@ -832,6 +851,7 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { overrides: Record; }; expect(yaml.overrides.vite).toBe('catalog:'); + // vitest is now a managed override key — added to overrides as catalog: ref. expect(yaml.overrides.vitest).toBe('catalog:'); }); @@ -864,6 +884,8 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { peerDependencies: Record; }; expect(pkg.peerDependencies.vite).toBe('*'); + // vitest is now a managed override key — peer dep catalog refs that + // resolve to the override target are coerced to '*'. expect(pkg.peerDependencies.vitest).toBe('*'); }); }); @@ -913,7 +935,9 @@ describe('rewriteMonorepo yarn catalog', () => { expect(yarnrc.nodeLinker).toBe('node-modules'); expect(yarnrc.catalogs.vite7.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); expect(yarnrc.catalogs.vite7.react).toBe('^18.0.0'); - expect(yarnrc.catalogs.test.vitest).toBe('npm:@voidzero-dev/vite-plus-test@latest'); + // vitest is now a managed override key — existing catalog entries are + // rewritten to the pinned vp-cli vitest version. + expect(yarnrc.catalogs.test.vitest).toBe('4.1.5'); expect(yarnrc.catalogs.test.oxlint).toBeUndefined(); const pkg = readJson(path.join(tmpDir, 'package.json')) as { @@ -922,6 +946,9 @@ describe('rewriteMonorepo yarn catalog', () => { }; expect(pkg.devDependencies.vite).toBe('catalog:vite7'); expect(pkg.peerDependencies.vite).toBe('^7.0.0'); + // vitest peer `catalog:test` is resolved against the pre-rewrite catalog + // (which still holds the user's `^4.0.0`). The peer range stays as the + // user wrote it; only the catalog file itself is later rewritten. expect(pkg.peerDependencies.vitest).toBe('^4.0.0'); }); }); @@ -1015,7 +1042,9 @@ describe('rewriteMonorepo bun catalog', () => { expect(pkg.workspaces.catalog.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); expect(pkg.workspaces.catalog['vite-plus']).toBe('latest'); expect(pkg.catalog.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); - expect(pkg.catalog.vitest).toBe('npm:@voidzero-dev/vite-plus-test@latest'); + // vitest is now a managed override key — pre-existing catalog entries are + // rewritten to the pinned vp-cli vitest version. + expect(pkg.catalog.vitest).toBe('4.1.5'); expect(pkg.catalog.tsdown).toBeUndefined(); expect(pkg.catalog.react).toBe('^19.0.0'); expect(pkg.catalog['vite-plus']).toBeUndefined(); @@ -1075,11 +1104,16 @@ describe('rewriteMonorepo bun catalog', () => { expect(pkg.catalogs.build.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); expect(pkg.catalogs.build.react).toBe('^19.0.0'); expect(pkg.catalogs.build.tsdown).toBeUndefined(); - expect(pkg.catalogs.test.vitest).toBe('npm:@voidzero-dev/vite-plus-test@latest'); + // vitest is now a managed override key — existing catalog entries are + // rewritten to the pinned version and `overrides.vitest` is injected + // as a `catalog:` ref so bun resolves it through the catalog. + expect(pkg.catalogs.test.vitest).toBe('4.1.5'); expect(pkg.overrides.vite).toBe('catalog:build'); expect(pkg.overrides.vitest).toBe('catalog:'); expect(pkg.devDependencies.vite).toBe('catalog:build'); expect(pkg.peerDependencies.vite).toBe('^7.0.0'); + // vitest peer `catalog:test` is resolved against the pre-rewrite catalog + // (which still holds the user's `^4.0.0`). Peer range stays as-is. expect(pkg.peerDependencies.vitest).toBe('^4.0.0'); }); @@ -1115,7 +1149,9 @@ describe('rewriteMonorepo bun catalog', () => { expect(pkg.workspaces.catalog['vite-plus']).toBe('latest'); expect(pkg.workspaces.catalogs.build.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); expect(pkg.workspaces.catalogs.build.oxlint).toBeUndefined(); - expect(pkg.workspaces.catalogs.test.vitest).toBe('npm:@voidzero-dev/vite-plus-test@latest'); + // vitest is a managed override key — existing catalog entries are + // rewritten to the pinned vp-cli vitest version. + expect(pkg.workspaces.catalogs.test.vitest).toBe('4.1.5'); expect(pkg.workspaces.catalogs.test.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); expect(pkg.overrides.vite).toBe('catalog:'); }); diff --git a/packages/cli/src/migration/bin.ts b/packages/cli/src/migration/bin.ts index 925519421a..d487468c89 100644 --- a/packages/cli/src/migration/bin.ts +++ b/packages/cli/src/migration/bin.ts @@ -29,6 +29,7 @@ import { hasVitePlusDependency, readNearestPackageJson } from '../utils/package. import { displayRelative } from '../utils/path.ts'; import { cancelAndExit, + type CommandRunSummary, defaultInteractive, downloadPackageManager, promptGitHooks, @@ -36,7 +37,7 @@ import { selectPackageManager, upgradeYarn, } from '../utils/prompts.ts'; -import { accent, log, muted, printHeader } from '../utils/terminal.ts'; +import { accent, log, muted, printHeader, warnMsg } from '../utils/terminal.ts'; import type { PackageDependencies } from '../utils/types.ts'; import { detectWorkspace } from '../utils/workspace.ts'; import { @@ -459,6 +460,34 @@ function formatDuration(durationMs: number) { return `${Math.round(durationSeconds)}s`; } +/** + * Reconcile a CommandRunSummary from `runViteInstall` with the migration's + * duration counter and exit-code state. `runViteInstall` returns + * `{ status: 'failed', exitCode }` without throwing; treating that as a success + * (incrementing duration unconditionally) would let the migration claim + * "Dependencies installed" while node_modules is desynced from the just-mutated + * package.json. This helper centralizes the right handling: credit duration on + * success, warn + flip exitCode on failure, stay silent on skip. + */ +function handleInstallResult( + installSummary: CommandRunSummary, + rootDir: string, + report: MigrationReport, +): number { + if (installSummary.status === 'installed') { + return installSummary.durationMs; + } + if (installSummary.status === 'failed') { + const exitCode = installSummary.exitCode ?? 1; + const message = `Dependency installation failed (exit code ${exitCode}). Run \`vp install\` manually in ${rootDir} to resync node_modules.`; + warnMsg(message); + report.warnings.push(message); + process.exitCode = exitCode; + return 0; + } + return 0; +} + function showMigrationSummary(options: { projectRoot: string; packageManager: string; @@ -769,12 +798,14 @@ async function executeMigrationPlan( } // 12. Reinstall after migration - // npm needs --force to re-resolve packages with newly added overrides, - // otherwise the stale lockfile prevents override resolution. + // The migration intentionally rewrites overrides/catalogs/deps, so the + // existing lockfile is guaranteed to be stale. Tell each package manager to + // re-resolve instead of refusing the install (pnpm/yarn default to + // frozen-lockfile under CI, npm/bun need an explicit --force). const installArgs = plan.packageManager === PackageManager.npm || plan.packageManager === PackageManager.bun ? ['--force'] - : undefined; + : ['--no-frozen-lockfile']; updateMigrationProgress('Installing dependencies'); const finalInstallSummary = await runViteInstall( workspaceInfo.rootDir, @@ -788,8 +819,15 @@ async function executeMigrationPlan( ); clearMigrationProgress(); + const finalInstallDurationMs = handleInstallResult( + finalInstallSummary, + workspaceInfo.rootDir, + report, + ); return { - installDurationMs: initialInstallSummary.durationMs + finalInstallSummary.durationMs, + installDurationMs: + handleInstallResult(initialInstallSummary, workspaceInfo.rootDir, report) + + finalInstallDurationMs, packageManagerVersion: downloadResult.version, report, }; @@ -890,17 +928,28 @@ async function main() { ); resolvedVersion = resolved.version; } + // ESLint/Prettier migration touched package.json; the lockfile is now + // stale, so disable frozen-lockfile mode (pnpm/yarn) or --force (npm/bun). + const eslintPrettierInstallArgs = + workspaceInfoOptional.packageManager === PackageManager.npm || + workspaceInfoOptional.packageManager === PackageManager.bun + ? ['--force'] + : ['--no-frozen-lockfile']; const installSummary = await runViteInstall( workspaceInfoOptional.rootDir, options.interactive, - undefined, + eslintPrettierInstallArgs, { silent: true, packageManager: workspaceInfoOptional.packageManager, packageManagerVersion: resolvedVersion, }, ); - installDurationMs += installSummary.durationMs; + installDurationMs += handleInstallResult( + installSummary, + workspaceInfoOptional.rootDir, + report, + ); didMigrate = true; report.eslintMigrated = eslintMigrated; report.prettierMigrated = prettierMigrated; diff --git a/packages/cli/src/migration/migrator.ts b/packages/cli/src/migration/migrator.ts index 85998fe058..3835cd01fe 100644 --- a/packages/cli/src/migration/migrator.ts +++ b/packages/cli/src/migration/migrator.ts @@ -23,6 +23,7 @@ import { VITE_PLUS_NAME, VITE_PLUS_OVERRIDE_PACKAGES, VITE_PLUS_VERSION, + VITEST_VERSION, isForceOverrideMode, } from '../utils/constants.ts'; import { editJsonFile, isJsonFile, readJsonFile } from '../utils/json.ts'; @@ -93,6 +94,56 @@ const PUBLIC_PEER_DEPENDENCY_FALLBACKS: Record = { vitest: '*', }; +// Legacy wrapper package names that may appear as the target of override +// aliases left over from earlier vite-plus migrations. `@voidzero-dev/vite-plus-test` +// was deleted; any catalog/override entry still pointing at it is stale. +const LEGACY_WRAPPER_PACKAGE_NAMES = ['@voidzero-dev/vite-plus-test'] as const; + +// Fallback specs used when normalizing a stale wrapper alias. Real user +// ranges (e.g. `vitest: ^3.0.0`) are preserved — only the wrapper alias is +// rewritten. For `vitest`, we substitute the vitest version vite-plus +// bundles so any `catalog:` reference the user still has resolves cleanly. +const LEGACY_WRAPPER_FALLBACK_VERSIONS: Record = { + vitest: `^${VITEST_VERSION}`, +}; + +function isLegacyWrapperSpec(value: string | undefined): boolean { + if (!value) { + return false; + } + for (const name of LEGACY_WRAPPER_PACKAGE_NAMES) { + if (value === `npm:${name}` || value.startsWith(`npm:${name}@`)) { + return true; + } + } + return false; +} + +/** + * Rewrite or remove keys whose value points at a deleted vite-plus wrapper. + * When a fallback exists for the key (e.g. `vitest`), the value is replaced + * so existing `catalog:` references continue to resolve. Otherwise the key + * is dropped entirely. Returns true iff any entry was changed. + */ +function pruneLegacyWrapperAliases(record: Record | undefined): boolean { + if (!record) { + return false; + } + let mutated = false; + for (const key of Object.keys(record)) { + if (isLegacyWrapperSpec(record[key])) { + const fallback = LEGACY_WRAPPER_FALLBACK_VERSIONS[key]; + if (fallback !== undefined) { + record[key] = fallback; + } else { + delete record[key]; + } + mutated = true; + } + } + return mutated; +} + type PackageJsonDependencyField = | 'devDependencies' | 'dependencies' @@ -851,6 +902,11 @@ export function rewriteStandaloneProject( }; }; }>(packageJsonPath, (pkg) => { + // Strip stale `vite-plus-test` wrapper aliases before injecting new overrides + // so the deleted wrapper doesn't survive migration in any sink. + pruneLegacyWrapperAliases(pkg.resolutions); + pruneLegacyWrapperAliases(pkg.overrides); + pruneLegacyWrapperAliases(pkg.pnpm?.overrides); if (packageManager === PackageManager.yarn) { pkg.resolutions = { ...pkg.resolutions, @@ -861,6 +917,19 @@ export function rewriteStandaloneProject( ...pkg.overrides, ...VITE_PLUS_OVERRIDE_PACKAGES, }; + if (packageManager === PackageManager.bun) { + // Bun walks transitive peer-deps before resolving overrides; vitest + // 4.1.5 declares peer `vite ^6 || ^7 || ^8` and aborts with + // "vite@... failed to resolve" if `vite` isn't a direct dep somewhere + // in the tree, even when the override would redirect it. Mirror the + // override as a devDep so bun's resolver sees `vite` immediately; + // the override above still points it at vite-plus-core. + // See https://github.com/oven-sh/bun/issues/8406. + pkg.devDependencies = { + ...pkg.devDependencies, + vite: VITE_PLUS_OVERRIDE_PACKAGES.vite, + }; + } } else if (packageManager === PackageManager.pnpm) { // If package.json already has a "pnpm" field, keep using it; // otherwise use pnpm-workspace.yaml. @@ -950,6 +1019,8 @@ export function rewriteStandaloneProject( if (packageManager === PackageManager.yarn) { rewriteYarnrcYml(projectPath); + } else if (packageManager === PackageManager.bun) { + ensureBunfigPeerSuppression(projectPath); } // Merge extracted staged config into vite.config.ts, then remove lint-staged from package.json @@ -1095,6 +1166,7 @@ function rewritePnpmWorkspaceYaml(projectPath: string): void { // overrides const overrides = doc.getIn(['overrides']); + pruneYamlMapLegacyWrapperAliases(overrides); for (const key of Object.keys(VITE_PLUS_OVERRIDE_PACKAGES)) { const currentVersion = getYamlMapScalarStringValue(overrides, key); const version = getCatalogDependencySpec( @@ -1422,6 +1494,29 @@ function getYamlMapScalarStringValue(map: unknown, key: string): string | undefi return undefined; } +function pruneYamlMapLegacyWrapperAliases(map: unknown): void { + if (!(map instanceof YAMLMap)) { + return; + } + const stale: Array<{ key: Scalar; fallback: string | undefined }> = []; + for (const item of map.items) { + const value = item.value instanceof Scalar ? item.value.value : undefined; + if (typeof value === 'string' && isLegacyWrapperSpec(value) && item.key instanceof Scalar) { + stale.push({ + key: item.key, + fallback: LEGACY_WRAPPER_FALLBACK_VERSIONS[item.key.value], + }); + } + } + for (const { key, fallback } of stale) { + if (fallback !== undefined) { + map.set(key, scalarString(fallback)); + } else { + map.delete(key); + } + } +} + function rewriteCatalog(doc: YamlDocument): void { for (const [key, value] of Object.entries(VITE_PLUS_OVERRIDE_PACKAGES)) { // ERR_PNPM_CATALOG_IN_OVERRIDES  Could not resolve a catalog in the overrides: The entry for 'vite' in catalog 'default' declares a dependency using the 'file' protocol @@ -1440,6 +1535,8 @@ function rewriteCatalog(doc: YamlDocument): void { doc.deleteIn(path); } } + // Drop any entry still pointing at the deleted `vite-plus-test` wrapper. + pruneYamlMapLegacyWrapperAliases(doc.getIn(['catalog'])); const catalogs = doc.getIn(['catalogs']); if (!(catalogs instanceof YAMLMap)) { @@ -1466,6 +1563,7 @@ function rewriteCatalog(doc: YamlDocument): void { doc.deleteIn(catalogPath); } } + pruneYamlMapLegacyWrapperAliases(item.value); } } @@ -1490,6 +1588,42 @@ function rewriteCatalogsObject(catalogs: Record>) } } +/** + * Bun rejects vitest@4.1.5's `vite^6/^7/^8` peer-dep when the user's project + * overrides `vite` to `@voidzero-dev/vite-plus-core` (whose package.json version + * does not match those ranges). pnpm/yarn/npm all tolerate this redirect; bun + * does not, and there is no `peerDependencyRules`-style escape hatch — only the + * `[install] peer = false` setting in `bunfig.toml`. + * + * `vite-plus`/`@voidzero-dev/vite-plus-core` already provide the vite surface + * the user needs, so disabling bun's auto-install of *missing* peers is safe in + * this configuration: any vitest peer that's not already pulled in transitively + * (jsdom, happy-dom, etc.) is marked optional upstream anyway. + * + * Writes/merges `bunfig.toml` at `projectPath` so the suppression applies on + * the migration's reinstall AND every subsequent `bun install` the user runs. + */ +function ensureBunfigPeerSuppression(projectPath: string): void { + const bunfigPath = path.join(projectPath, 'bunfig.toml'); + const block = '[install]\npeer = false\n'; + if (!fs.existsSync(bunfigPath)) { + fs.writeFileSync(bunfigPath, block); + return; + } + const existing = fs.readFileSync(bunfigPath, 'utf8'); + // Already configured? Leave the user's setting alone — they may have set + // `peer = true` deliberately for some other reason and we shouldn't override. + if (/^\s*peer\s*=\s*(true|false)\s*$/m.test(existing)) { + return; + } + // Append under existing [install] section, or add a new section. + const installSectionRe = /^\[install\][^[]*/m; + const next = installSectionRe.test(existing) + ? existing.replace(installSectionRe, (section) => `${section.trimEnd()}\npeer = false\n`) + : `${existing.trimEnd()}\n\n${block}`; + fs.writeFileSync(bunfigPath, next); +} + /** * Write catalog entries to root package.json for bun. * Bun stores catalogs in package.json under the `catalog` key, @@ -1519,27 +1653,37 @@ function rewriteBunCatalog(projectPath: string): void { }; rewriteCatalogObject(catalog, true); + pruneLegacyWrapperAliases(catalog); if (useWorkspacesCatalog) { workspacesObj.catalog = catalog; if (pkg.catalog) { rewriteCatalogObject(pkg.catalog, false); + pruneLegacyWrapperAliases(pkg.catalog); } } else { pkg.catalog = catalog; if (workspacesObj?.catalog) { rewriteCatalogObject(workspacesObj.catalog, false); + pruneLegacyWrapperAliases(workspacesObj.catalog); } } if (workspacesObj?.catalogs) { rewriteCatalogsObject(workspacesObj.catalogs); + for (const named of Object.values(workspacesObj.catalogs)) { + pruneLegacyWrapperAliases(named); + } } if (pkg.catalogs) { rewriteCatalogsObject(pkg.catalogs); + for (const named of Object.values(pkg.catalogs)) { + pruneLegacyWrapperAliases(named); + } } // bun overrides support catalog: references const overrides: Record = { ...pkg.overrides }; + pruneLegacyWrapperAliases(overrides); for (const [key, value] of Object.entries(VITE_PLUS_OVERRIDE_PACKAGES)) { overrides[key] = getCatalogDependencySpec(overrides[key], value, true); } @@ -1547,6 +1691,8 @@ function rewriteBunCatalog(projectPath: string): void { return pkg; }); + + ensureBunfigPeerSuppression(projectPath); } /** @@ -1580,6 +1726,11 @@ function rewriteRootWorkspacePackageJson( }; }; }>(packageJsonPath, (pkg) => { + // Strip stale `vite-plus-test` wrapper aliases before injecting new overrides + // so the deleted wrapper doesn't survive migration in any sink. + pruneLegacyWrapperAliases(pkg.resolutions); + pruneLegacyWrapperAliases(pkg.overrides); + pruneLegacyWrapperAliases(pkg.pnpm?.overrides); if (packageManager === PackageManager.yarn) { pkg.resolutions = { ...pkg.resolutions, @@ -1594,6 +1745,19 @@ function rewriteRootWorkspacePackageJson( }; } else if (packageManager === PackageManager.bun) { // bun overrides are handled in rewriteBunCatalog() with catalog: references + // Bun walks transitive peer-deps before resolving overrides; vitest 4.1.5 + // declares peer `vite ^6 || ^7 || ^8` and aborts unless `vite` is a direct + // dep at the workspace root. Mirror the override as a devDep; the override + // configured in rewriteBunCatalog still redirects it to vite-plus-core. + // See https://github.com/oven-sh/bun/issues/8406. + pkg.devDependencies = { + ...pkg.devDependencies, + vite: getCatalogDependencySpec( + pkg.devDependencies?.vite, + VITE_PLUS_OVERRIDE_PACKAGES.vite, + true, + ), + }; } else if (packageManager === PackageManager.pnpm) { const overrideKeys = Object.keys(VITE_PLUS_OVERRIDE_PACKAGES); if (isForceOverrideMode()) { @@ -1726,6 +1890,14 @@ export function rewritePackageJson( { dependencyField: 'peerDependencies', dependencies: pkg.peerDependencies }, { dependencyField: 'optionalDependencies', dependencies: pkg.optionalDependencies }, ]; + // Scrub stale `npm:@voidzero-dev/vite-plus-test@...` aliases left over from + // earlier vite-plus migrations — the wrapper package no longer exists, so + // these entries would break `pnpm install`. Real user ranges are preserved. + for (const { dependencies } of dependencyGroups) { + if (pruneLegacyWrapperAliases(dependencies)) { + needVitePlus = true; + } + } for (const [key, version] of Object.entries(VITE_PLUS_OVERRIDE_PACKAGES)) { for (const { dependencyField, dependencies } of dependencyGroups) { if (dependencies?.[key]) { @@ -1739,6 +1911,19 @@ export function rewritePackageJson( } } } + // Force-override mode (ecosystem CI / `vp create` E2E) must re-pin any + // pre-existing `vite-plus` range to the local tgz. Otherwise pnpm reads the + // published vite-plus metadata for transitive dep resolution (e.g. + // `@voidzero-dev/vite-plus-test`) even though the override replaces the + // vite-plus package itself, dragging the stale wrapper into node_modules. + if (isForceOverrideMode()) { + for (const { dependencies } of dependencyGroups) { + if (dependencies?.[VITE_PLUS_NAME]) { + dependencies[VITE_PLUS_NAME] = VITE_PLUS_VERSION; + needVitePlus = true; + } + } + } // remove packages that are replaced with vite-plus for (const name of REMOVE_PACKAGES) { let wasRemoved = false; @@ -1765,6 +1950,23 @@ export function rewritePackageJson( pkg.devDependencies[peerDep] = '*'; } } + // Trigger vite-plus install when a project has a vitest-adjacent package + // (e.g. `vitest-browser-svelte`) that declares vitest as a peer dep — even + // if the project has no vite/oxlint/tsdown dep to migrate. The peer dep is + // satisfied by the upstream vitest that vite-plus bundles as a direct dep. + // Note: peerDependencies count as "adjacent signal" but NOT as installed. + const installableNames = [ + ...Object.keys(pkg.dependencies ?? {}), + ...Object.keys(pkg.devDependencies ?? {}), + ...Object.keys(pkg.optionalDependencies ?? {}), + ]; + const adjacentSignals = [...installableNames, ...Object.keys(pkg.peerDependencies ?? {})]; + const isVitestAdjacent = + !installableNames.includes('vitest') && + adjacentSignals.some((name) => name !== 'vitest' && name.includes('vitest')); + if (isVitestAdjacent) { + needVitePlus = true; + } if (needVitePlus) { // add vite-plus to devDependencies const version = @@ -1773,10 +1975,13 @@ export function rewritePackageJson( ...pkg.devDependencies, [VITE_PLUS_NAME]: version, }; - // Add vitest to devDependencies when a remaining dependency likely peer-depends - // on vitest (e.g., vitest-browser-svelte). Without this, pnpm resolves the real - // vitest for peer deps instead of @voidzero-dev/vite-plus-test, causing - // third-party type augmentations to target the wrong module. + // Add vitest to devDependencies when a remaining dependency likely + // peer-depends on vitest (e.g., vitest-browser-svelte). Vite-plus already + // bundles upstream vitest 4.1.5 as a direct dep, so the runtime resolution + // works without this — but strict pnpm / yarn Plug'n'Play refuse to expose a + // transitive `vitest` to satisfy a peer dep declared by a different + // direct dep. Adding `vitest` to the user's devDependencies pins the + // peer-dep target to the same upstream version vite-plus ships with. const installableDeps = { ...pkg.dependencies, ...pkg.devDependencies, @@ -1786,8 +1991,11 @@ export function rewritePackageJson( !installableDeps.vitest && Object.keys(installableDeps).some((name) => name.includes('vitest')) ) { - const ver = VITE_PLUS_OVERRIDE_PACKAGES.vitest; - pkg.devDependencies.vitest = getCatalogDependencySpec(undefined, ver, supportCatalog); + pkg.devDependencies.vitest = getCatalogDependencySpec( + undefined, + VITEST_VERSION, + supportCatalog, + ); } } return extractedStagedConfig; diff --git a/packages/cli/src/resolve-test.ts b/packages/cli/src/resolve-test.ts index 8c547c8d3a..a00c216285 100644 --- a/packages/cli/src/resolve-test.ts +++ b/packages/cli/src/resolve-test.ts @@ -2,16 +2,23 @@ * Vitest tool resolver for the vite-plus CLI. * * This module exports a function that resolves the Vitest binary path - * to the bundled Vitest in the CLI distribution. The resolved path is - * passed back to the Rust core, which then executes Vitest for running tests. + * to the vitest package installed alongside the CLI (or in the user's + * project, resolved from the current working directory first). The + * resolved path is passed back to the Rust core, which then executes + * Vitest for running tests. * * Used for: `vite-plus test` command */ +import { readFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { DEFAULT_ENVS, resolve } from './utils/constants.ts'; +interface VitestPackageJson { + bin?: string | Record; +} + /** * Resolves the Vitest binary path and environment variables. * @@ -21,13 +28,21 @@ import { DEFAULT_ENVS, resolve } from './utils/constants.ts'; * * Vitest is Vite's testing framework that provides a Jest-compatible * testing experience with Vite's fast HMR and transformation pipeline. - * The function points to the bundled Vitest in the CLI's dist directory. + * The function resolves vitest from the user's project first, falling + * back to the copy installed alongside the CLI. */ export async function test(): Promise<{ binPath: string; envs: Record; }> { - const binPath = join(dirname(resolve('@voidzero-dev/vite-plus-test')), 'dist', 'cli.js'); + const pkgJsonPath = resolve('vitest/package.json'); + const pkgRoot = dirname(pkgJsonPath); + const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8')) as VitestPackageJson; + const binRel = typeof pkgJson.bin === 'string' ? pkgJson.bin : pkgJson.bin?.vitest; + if (!binRel) { + throw new Error(`Could not find 'vitest' bin entry in ${pkgJsonPath}`); + } + const binPath = join(pkgRoot, binRel); return { binPath, diff --git a/packages/cli/src/utils/constants.ts b/packages/cli/src/utils/constants.ts index 137416b2b9..71e3ae77d3 100644 --- a/packages/cli/src/utils/constants.ts +++ b/packages/cli/src/utils/constants.ts @@ -3,11 +3,22 @@ import { createRequire } from 'node:module'; export const VITE_PLUS_NAME = 'vite-plus'; export const VITE_PLUS_VERSION = process.env.VP_VERSION || 'latest'; +export const VITEST_VERSION = '4.1.5'; + export const VITE_PLUS_OVERRIDE_PACKAGES: Record = process.env.VP_OVERRIDE_PACKAGES ? JSON.parse(process.env.VP_OVERRIDE_PACKAGES) : { vite: 'npm:@voidzero-dev/vite-plus-core@latest', - vitest: 'npm:@voidzero-dev/vite-plus-test@latest', + vitest: VITEST_VERSION, + '@vitest/expect': VITEST_VERSION, + '@vitest/runner': VITEST_VERSION, + '@vitest/snapshot': VITEST_VERSION, + '@vitest/spy': VITEST_VERSION, + '@vitest/utils': VITEST_VERSION, + '@vitest/mocker': VITEST_VERSION, + '@vitest/pretty-format': VITEST_VERSION, + '@vitest/coverage-v8': VITEST_VERSION, + '@vitest/coverage-istanbul': VITEST_VERSION, }; /** diff --git a/packages/test/.gitignore b/packages/test/.gitignore deleted file mode 100644 index 7f727e288b..0000000000 --- a/packages/test/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -*.d.ts -*.d.cts -/LICENSE -LICENSE.md -*.cjs -*.mjs -browser/ -dist/ diff --git a/packages/test/BUNDLING.md b/packages/test/BUNDLING.md deleted file mode 100644 index 4866da58e1..0000000000 --- a/packages/test/BUNDLING.md +++ /dev/null @@ -1,427 +0,0 @@ -# Test Package Bundling Architecture - -This document explains how `@voidzero-dev/vite-plus-test` bundles vitest and its dependencies. - -## Overview - -The test package uses a **hybrid bundling strategy**: - -1. **COPY** all `@vitest/*` packages (preserves browser/Node.js separation) -2. **BUNDLE** only leaf dependencies like `chai`, `pathe` (reduces install size) -3. **Separate entries** (`index.js` vs `index-node.js`) prevent Node.js code from loading in browsers - -This approach avoids the critical issue of Rolldown creating shared chunks that mix Node.js-only code (like `__vite__injectQuery`) with browser code, which causes runtime crashes. - -## Dependencies Classification - -### Copied Packages (`dist/@vitest/`) - -These 11 `@vitest/*` packages are **copied** (not bundled) to preserve their original file structure: - -| Package | Purpose | -| ----------------------------- | ---------------------------------------------------- | -| `@vitest/runner` | Test runner core | -| `@vitest/utils` | Utilities (source-map, error, display, timers, etc.) | -| `@vitest/spy` | Spy/mock implementation | -| `@vitest/expect` | Assertion library | -| `@vitest/snapshot` | Snapshot testing | -| `@vitest/mocker` | Module mocking (node, browser, automock) | -| `@vitest/pretty-format` | Output formatting | -| `@vitest/browser` | Browser testing support | -| `@vitest/browser-playwright` | Playwright integration | -| `@vitest/browser-webdriverio` | WebdriverIO integration | -| `@vitest/browser-preview` | Preview (testing-library) integration | - -**Why copy instead of bundle?** Bundling would create shared chunks that mix browser-safe and Node.js-only code. Copying preserves the original separation. - -### Bundled Leaf Dependencies (`dist/vendor/`) - -These packages are bundled using Rolldown into `dist/vendor/*.mjs`: - -| Package | Purpose | -| --------------------- | ----------------------------------- | -| `chai` | Assertion library (core of expect) | -| `pathe` | Path utilities | -| `tinyrainbow` | Terminal colors | -| `magic-string` | String manipulation for source maps | -| `estree-walker` | AST traversal | -| `why-is-node-running` | Debug tool for hanging processes | - -These were moved from `dependencies` to `devDependencies` since they're bundled. - -### Runtime Dependencies (NOT Bundled) - -These remain in `dependencies` and are installed with the package: - -| Package | Reason Not Bundled | -| ----------------- | --------------------------------------------- | -| `sirv` | Static file server - complex runtime behavior | -| `ws` | WebSocket server - native bindings | -| `pixelmatch` | Image comparison - optional feature | -| `pngjs` | PNG handling - optional feature | -| `es-module-lexer` | ESM parsing - small, used at runtime | -| `expect-type` | Type testing - small | -| `obug` | Debugging - small | -| `picomatch` | Glob matching - small | -| `std-env` | Environment detection - small | -| `tinybench` | Benchmarking - optional feature | -| `tinyexec` | Command execution - small | -| `tinyglobby` | File globbing - small | - -### External Blocklist (Must NOT Bundle) - -These packages are explicitly kept external in `EXTERNAL_BLOCKLIST` during the Rolldown build: - -| Package | Reason | -| ----------------------- | ----------------------------------------- | -| `playwright` | Native bindings, user must install | -| `webdriverio` | Native bindings, user must install | -| `debug` | Environment detection breaks when bundled | -| `happy-dom` | Optional peer dependency | -| `jsdom` | Optional peer dependency | -| `@edge-runtime/vm` | Optional peer dependency | -| `@standard-schema/spec` | Types-only import from @vitest/expect | -| `msw`, `msw/*` | Optional peer dependency for mocking | - -### Browser Plugin Exclude List - -Additionally, these packages are added to the **browser plugin's exclude list** (in `patchVitestBrowserPackage`), which prevents Vite's optimizer from bundling them during browser tests: - -| Package | Reason | -| --------------------- | ------------------------------------------------ | -| `lightningcss` | Native bindings | -| `@tailwindcss/oxide` | Native bindings | -| `tailwindcss` | Pulls in @tailwindcss/oxide | -| `@vitest/browser` | Needs vendor-aliases plugin resolution | -| `@vitest/ui` | Optional peer dependency | -| `@vitest/mocker/node` | Imports @voidzero-dev/vite-plus-core (Node-only) | - -This is a different mechanism than `EXTERNAL_BLOCKLIST` - it controls runtime optimization, not build-time bundling. - ---- - -## Migration Guide - -For maintainers developing the vitest/vite migration feature, here are the transformations needed. - -### Import Rewrites - -| Original Import | Rewritten Import | -| ------------------------------------ | --------------------------------------------------------- | -| `from "@vitest/browser-playwright"` | `from "@voidzero-dev/vite-plus-test/browser-playwright"` | -| `from "@vitest/browser-webdriverio"` | `from "@voidzero-dev/vite-plus-test/browser-webdriverio"` | -| `from "@vitest/browser-preview"` | `from "@voidzero-dev/vite-plus-test/browser-preview"` | -| `from "vite"` | `from "@voidzero-dev/vite-plus-core"` | -| `from "vite/module-runner"` | `from "@voidzero-dev/vite-plus-core/module-runner"` | -| `import('vitest')` | `import('@voidzero-dev/vite-plus-test')` | - -**Note**: `@voidzero-dev/vite-plus-core` is the bundled version of upstream vite (Vite v8 beta). See [Core Package Bundling](../core/BUNDLING.md) for details on what it contains. - -**Note**: The `import('vitest')` → `import('@voidzero-dev/vite-plus-test')` rewrite is critical for `globals.d.ts`, which declares global types like `typeof import('vitest')['test']`. Without this rewrite, `vitest` is not resolvable from the `@voidzero-dev/vite-plus-test` package context in pnpm's strict `node_modules` layout. TypeScript silently treats unresolved dynamic type imports as `any`, but oxlint's type-aware linting treats them as `error` types, causing `no-unsafe-call` errors. The rewrite turns this into a self-reference that resolves correctly via Node.js package self-referencing. - -**Note:** When using pnpm overrides, you have three options for browser provider imports: - -- `vitest/browser-playwright` (or `vitest/browser-webdriverio`, `vitest/browser-preview`) - works when `vitest` is overridden to our package (Recommended) -- `@voidzero-dev/vite-plus-test/browser-playwright` - direct import from test package -- `vite-plus/test/plugins/browser-playwright` - direct import from CLI package - -Importing from `@vitest/browser-*` packages directly requires additional overrides for those specific packages. - -### package.json Changes - -**Remove these devDependencies** (now bundled): - -```json -{ - "devDependencies": { - "@vitest/browser": "...", // Remove - "@vitest/browser-playwright": "...", // Remove (if using playwright) - "@vitest/browser-webdriverio": "...", // Remove (if using webdriverio) - "@vitest/browser-preview": "...", // Remove (if using testing-library) - "@vitest/ui": "..." // Remove (peer dep, not bundled but optional) - } -} -``` - -**Add pnpm overrides**: - -```yaml -# pnpm-workspace.yaml -overrides: - vite: 'file:path/to/vite-plus-core.tgz' - vitest: 'file:path/to/vite-plus-test.tgz' - '@vitest/browser': 'file:path/to/vite-plus-test.tgz' - '@vitest/browser-playwright': 'file:path/to/vite-plus-test.tgz' - '@vitest/browser-webdriverio': 'file:path/to/vite-plus-test.tgz' - '@vitest/browser-preview': 'file:path/to/vite-plus-test.tgz' -``` - -Or using npm package names: - -```yaml -overrides: - vite: 'npm:@voidzero-dev/vite-plus-core' - vitest: 'npm:@voidzero-dev/vite-plus-test' - '@vitest/browser': 'npm:@voidzero-dev/vite-plus-test' - '@vitest/browser-playwright': 'npm:@voidzero-dev/vite-plus-test' - '@vitest/browser-webdriverio': 'npm:@voidzero-dev/vite-plus-test' - '@vitest/browser-preview': 'npm:@voidzero-dev/vite-plus-test' -``` - -### Config File Updates - -```typescript -// Before (playwright) -import { playwright } from '@vitest/browser-playwright'; - -// After - Option 1 (Recommended): Via vitest subpath (works when vitest is overridden) -import { playwright } from 'vitest/browser-playwright'; - -// After - Option 2: Direct import from test package -import { playwright } from '@voidzero-dev/vite-plus-test/browser-playwright'; - -// After - Option 3: Direct import from CLI package -import { playwright } from 'vite-plus/test/plugins/browser-playwright'; -``` - -Similarly for WebdriverIO: - -```typescript -import { webdriverio } from 'vitest/browser-webdriverio'; -``` - -And for Preview (testing-library): - -```typescript -import { preview } from 'vitest/browser-preview'; -``` - -### Plugin Exports for pnpm Overrides - -The package provides `./plugins/*` exports to enable pnpm overrides for all `@vitest/*` packages: - -``` -@vitest/runner -> @voidzero-dev/vite-plus-test/plugins/runner -@vitest/utils -> @voidzero-dev/vite-plus-test/plugins/utils -@vitest/utils/error -> @voidzero-dev/vite-plus-test/plugins/utils-error -@vitest/spy -> @voidzero-dev/vite-plus-test/plugins/spy -@vitest/expect -> @voidzero-dev/vite-plus-test/plugins/expect -@vitest/snapshot -> @voidzero-dev/vite-plus-test/plugins/snapshot -@vitest/mocker -> @voidzero-dev/vite-plus-test/plugins/mocker -@vitest/pretty-format -> @voidzero-dev/vite-plus-test/plugins/pretty-format -@vitest/browser -> @voidzero-dev/vite-plus-test/plugins/browser -@vitest/browser-playwright -> @voidzero-dev/vite-plus-test/plugins/browser-playwright -@vitest/browser-webdriverio -> @voidzero-dev/vite-plus-test/plugins/browser-webdriverio -@vitest/browser-preview -> @voidzero-dev/vite-plus-test/plugins/browser-preview -``` - ---- - -## Ensuring Bundle Stability - -### Build-time Validation - -The build script includes `validateExternalDeps()` which: - -1. Scans all bundled JS files using `oxc-parser` -2. Extracts all external import specifiers -3. Verifies every external dependency is declared in `dependencies` or `peerDependencies` -4. Reports undeclared externals that would fail at runtime - -If this validation fails, the build will report which packages need to be added. - -### Testing Strategy - -| Test Type | What It Validates | -| --------------------------------------------------------------- | -------------------------------------------------- | -| **Snap tests** (`packages/cli/snap-tests/vitest-browser-mode/`) | Browser mode works after bundling | -| **Ecosystem CI** (`ecosystem-ci/`) | Real-world projects work with bundled vitest | -| **CI workflows** | Multi-platform validation (Ubuntu, Windows, macOS) | - -### Vitest Upgrade Checklist - -When upgrading the vitest version: - -1. **Update version** in `packages/test/package.json`: - - ```json - { - "devDependencies": { - "vitest-dev": "^NEW_VERSION", - "@vitest/runner": "NEW_VERSION", - "@vitest/utils": "NEW_VERSION" - // ... all @vitest/* packages - } - } - ``` - -2. **Run build**: - - ```bash - pnpm -C packages/test build - ``` - -3. **Check for new externals**: If `validateExternalDeps()` reports new undeclared dependencies: - - Add to `dependencies` if it should be installed at runtime - - Add to `EXTERNAL_BLOCKLIST` if it should remain external (native bindings, optional) - - If it's a new leaf dep, it will be automatically bundled - -4. **Run tests**: - - ```bash - pnpm test - ``` - -5. **Run ecosystem CI**: - ```bash - pnpm -C ecosystem-ci test - ``` - -### Common Upgrade Issues - -| Issue | Cause | Solution | -| ----------------------- | ------------------------------ | -------------------------------------------------- | -| New undeclared external | New vitest dependency | Add to `dependencies` or `EXTERNAL_BLOCKLIST` | -| Browser test crashes | Node.js code leaked to browser | Check import rewriting in `rewriteVitestImports()` | -| Missing export | New @vitest/\* subpath export | Add to `VITEST_PACKAGE_TO_PATH` | -| pnpm override fails | New plugin export needed | Add to `createPluginExports()` | - ---- - -## Technical Reference - -### Build Flow - -``` -1. bundleVitest() Copy vitest-dev dist/ -> dist/ -2. copyVitestPackages() Copy @vitest/* -> dist/@vitest/ -3. convertTabsToSpaces() Normalize formatting for patches -4. collectLeafDependencies() Parse imports with oxc-parser -5. bundleLeafDeps() Bundle chai, pathe, etc -> dist/vendor/ -6. rewriteVitestImports() Rewrite @vitest/*, vitest/*, vite -7. patchVitestPkgRootPaths() Fix distRoot for relocated files -8. patchVitestBrowserPackage() Inject vendor-aliases plugin -9. patchBrowserProviderLocators() Fix browser-safe imports -10. Post-processing: - - patchVendorPaths() - - createBrowserCompatShim() - - createModuleRunnerStub() Browser-safe stub - - createNodeEntry() index-node.js with browser-provider - - copyBrowserClientFiles() - - createBrowserEntryFiles() browser/ entry files at package root - - patchModuleAugmentations() Rewrite @vitest/expect, @vitest/runner augmentations - - patchChaiTypeReference() Add @types/chai triple-slash reference - - createPluginExports() dist/plugins/* for pnpm overrides - - mergePackageJson() - - validateExternalDeps() -``` - -### Output Structure - -``` -browser/ # Entry files for ./browser export -├── context.js # Runtime guard (throws if not in browser) -└── context.d.ts # Re-exports from dist/@vitest/browser/context.d.ts -dist/ -├── @vitest/ # Copied packages (browser/Node.js safe) -│ ├── runner/ -│ ├── utils/ -│ ├── spy/ -│ ├── expect/ -│ ├── snapshot/ -│ ├── mocker/ -│ ├── pretty-format/ -│ ├── browser/ -│ └── browser-playwright/ -├── vendor/ # Bundled leaf dependencies -│ ├── chai.mjs -│ ├── pathe.mjs -│ ├── tinyrainbow.mjs -│ ├── magic-string.mjs -│ ├── estree-walker.mjs -│ ├── why-is-node-running.mjs -│ └── vitest_*.mjs # Browser stubs -├── plugins/ # Shims for pnpm overrides -│ ├── runner.mjs -│ ├── utils.mjs -│ └── ... (33+ files) -├── chunks/ # Vitest core chunks -├── client/ # Browser client files -├── index.js # Browser-safe entry -├── index-node.js # Node.js entry (includes browser-provider) -├── module-runner-stub.js # Browser-safe module-runner -└── browser-compat.js # @vitest/browser compatibility shim -``` - -### Browser/Node.js Separation - -The critical design decision is maintaining separation between browser and Node.js code: - -| Entry Point | Used By | Contains | -| -------------------- | --------------------- | --------------------------------- | -| `dist/index.js` | Browser tests | No Node.js-only code | -| `dist/index-node.js` | Node.js (config, CLI) | Includes browser-provider exports | - -This is achieved through: - -1. Conditional exports in package.json (`"node": "./dist/index-node.js"`) -2. Browser-safe stubs for `module-runner` -3. Import rewriting to prevent Node.js code from being pulled into browser bundles -4. `vendor-aliases` plugin injection to resolve imports at runtime: - - Handles `@vitest/*` imports → resolves to copied `dist/@vitest/` files - - Handles `vitest/*` subpaths → resolves to dist files (enables `vitest/browser-playwright` usage) - - Handles `vitest/browser-playwright`, `vitest/browser-webdriverio`, `vitest/browser-preview` → resolves to bundled browser providers - - Handles `@voidzero-dev/vite-plus-test/*` subpaths → maps to equivalent vitest paths - - Handles `vite-plus/test/*` subpaths → maps to equivalent vitest paths (CLI package) - - Intercepts `vitest/browser`, `@voidzero-dev/vite-plus-test/browser`, `vite-plus/test/browser` → returns virtual module ID for BrowserContext plugin - -### Key Constants - -```typescript -// Packages copied to dist/@vitest/ -const VITEST_PACKAGES_TO_COPY = [ - '@vitest/runner', - '@vitest/utils', - '@vitest/spy', - '@vitest/expect', - '@vitest/snapshot', - '@vitest/mocker', - '@vitest/pretty-format', - '@vitest/browser', - '@vitest/browser-playwright', - '@vitest/browser-webdriverio', - '@vitest/browser-preview', -]; - -// Packages that must NOT be bundled (from build.ts lines 131-158) -const EXTERNAL_BLOCKLIST = new Set([ - // Our own packages - resolved at runtime - '@voidzero-dev/vite-plus-core', - '@voidzero-dev/vite-plus-core/module-runner', - 'vite', - 'vitest', - - // Peer dependencies - consumers must provide these - '@edge-runtime/vm', - '@opentelemetry/api', - '@standard-schema/spec', // Types-only import from @vitest/expect - 'happy-dom', - 'jsdom', - - // Optional dependencies with bundling issues or native bindings - 'debug', // environment detection broken when bundled - 'playwright', // native bindings - 'webdriverio', // native bindings - - // Runtime deps (in package.json dependencies) - not bundled, resolved at install time - 'sirv', - 'ws', - 'pixelmatch', - 'pngjs', - - // MSW (Mock Service Worker) - optional peer dep of @vitest/mocker - 'msw', - 'msw/browser', - 'msw/core/http', -]); -``` diff --git a/packages/test/__tests__/build-artifacts.spec.ts b/packages/test/__tests__/build-artifacts.spec.ts deleted file mode 100644 index 641b98260c..0000000000 --- a/packages/test/__tests__/build-artifacts.spec.ts +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Verify that the @voidzero-dev/vite-plus-test build output (dist/) - * contains the expected files and that patches applied during the build - * (in build.ts) produce correct artifacts. - * - * These tests run against the already-built dist/ directory, ensuring - * that re-packaging patches produce correct artifacts. - */ -import fs from 'node:fs'; -import path from 'node:path'; -import url from 'node:url'; - -import { describe, expect, it } from 'vitest'; - -const testPkgDir = path.resolve(path.dirname(url.fileURLToPath(import.meta.url)), '..'); -const distDir = path.join(testPkgDir, 'dist'); - -function findCliApiChunk(): string { - const chunksDir = path.join(distDir, 'chunks'); - const files = fs.readdirSync(chunksDir); - const chunk = files.find((f) => f.startsWith('cli-api.') && f.endsWith('.js')); - if (!chunk) { - throw new Error('cli-api chunk not found in dist/chunks/'); - } - return path.join(chunksDir, chunk); -} - -describe('build artifacts', () => { - describe('@vitest/browser/context.js', () => { - const contextPath = path.join(distDir, '@vitest/browser/context.js'); - - it('should exist', () => { - expect(fs.existsSync(contextPath), `${contextPath} should exist`).toBe(true); - }); - - it('should export page, cdp, and utils', () => { - const content = fs.readFileSync(contextPath, 'utf-8'); - expect(content).toMatch(/export\s*\{[^}]*page[^}]*\}/); - expect(content).toMatch(/export\s*\{[^}]*cdp[^}]*\}/); - expect(content).toMatch(/export\s*\{[^}]*utils[^}]*\}/); - }); - }); - - /** - * The vitest:vendor-aliases plugin must NOT resolve @vitest/browser/context - * to the static file. If it does, the BrowserContext plugin's virtual module - * (which provides the `server` export) is bypassed. - * - * See: https://github.com/voidzero-dev/vite-plus/issues/1086 - */ - describe('vitest:vendor-aliases plugin (regression test for #1086)', () => { - const browserIndexPath = path.join(distDir, '@vitest/browser/index.js'); - - it('should not map @vitest/browser/context in vendorMap', () => { - const content = fs.readFileSync(browserIndexPath, 'utf-8'); - // The vendorMap inside vitest:vendor-aliases should NOT contain - // '@vitest/browser/context' — it must be left for BrowserContext - // plugin to resolve as a virtual module. - const vendorAliasesMatch = content.match( - /name:\s*['"]vitest:vendor-aliases['"][\s\S]*?const vendorMap\s*=\s*\{([\s\S]*?)\}/, - ); - expect(vendorAliasesMatch, 'vitest:vendor-aliases plugin should exist').toBeTruthy(); - const vendorMapContent = vendorAliasesMatch![1]; - expect(vendorMapContent).not.toContain("'@vitest/browser/context'"); - }); - }); - - /** - * `convertTabsToSpaces()` in build.ts must not touch tabs inside string - * literals. Upstream `@vitest/snapshot` decides multi-line snapshot - * indentation via `indent.includes("\t")` — where `"\t"` is a literal - * tab byte in the bundled source. A blanket tab→spaces rewrite turned - * this into `indent.includes(" ")`, so every 2-space indent matched - * and the tab-appending branch always ran, producing tab-indented - * snapshots in 2-space files. - * - * See: https://github.com/voidzero-dev/vite-plus/issues/1553 - */ - describe('snapshot indent check (regression test for #1553)', () => { - const snapshotIndexPath = path.join(distDir, '@vitest/snapshot/index.js'); - - it('preserves the literal tab byte inside the indent.includes string', () => { - const content = fs.readFileSync(snapshotIndexPath, 'utf-8'); - expect(content).toContain('indent.includes("\t")'); - expect(content).not.toMatch(/indent\.includes\(" "\)/); - }); - }); - - /** - * Third-party packages that call `expect.extend()` internally - * (e.g., @testing-library/jest-dom) break under npm override because - * the vitest module instance is split, causing matchers to be registered - * on a different `chai` instance than the test runner uses. - * - * The build patches vitest's ModuleRunnerTransform plugin to auto-add - * these packages to `server.deps.inline`, so they are processed through - * Vite's transform pipeline and share the same module instance. - * - * See: https://github.com/voidzero-dev/vite-plus/issues/897 - */ - describe('server.deps.inline auto-inline (regression test for #897)', () => { - it('should contain the expected auto-inline packages', () => { - const content = fs.readFileSync(findCliApiChunk(), 'utf-8'); - expect(content).toContain('Auto-inline packages'); - expect(content).toContain('"@testing-library/jest-dom"'); - expect(content).toContain('"@storybook/test"'); - expect(content).toContain('"jest-extended"'); - }); - - it('should not override user inline config when set to true', () => { - const content = fs.readFileSync(findCliApiChunk(), 'utf-8'); - expect(content).toContain('server.deps.inline !== true'); - }); - }); -}); diff --git a/packages/test/build.ts b/packages/test/build.ts deleted file mode 100644 index dd313749cf..0000000000 --- a/packages/test/build.ts +++ /dev/null @@ -1,2649 +0,0 @@ -// Build Script for @voidzero-dev/vite-plus-test -// -// Bundles vitest and @vitest/* dependencies with browser/Node.js separation. -// -// ┌─────────────────────────────────────────────────────────────────────┐ -// │ BUILD FLOW │ -// ├─────────────────────────────────────────────────────────────────────┤ -// │ 1. bundleVitest() Copy vitest-dev → dist/ │ -// │ 2. copyVitestPackages() Copy @vitest/* → dist/@vitest/ │ -// │ 3. collectLeafDependencies() Parse imports with oxc-parser │ -// │ 4. bundleLeafDeps() Bundle chai, pathe, etc → dist/vendor/ │ -// │ 5. rewriteVitestImports() Rewrite @vitest/*, vitest/*, vite │ -// │ 6. patchVitestPkgRootPaths() Fix distRoot for relocated files │ -// │ 7. patchVitestBrowserPackage() Inject vendor-aliases plugin │ -// │ 8. patchBrowserProviderLocators() Fix browser-safe imports │ -// │ 9. Post-processing: │ -// │ - patchVendorPaths() │ -// │ - createBrowserCompatShim() │ -// │ - createModuleRunnerStub() Browser-safe stub │ -// │ - createNodeEntry() index-node.js with browser-provider│ -// │ - copyBrowserClientFiles() │ -// │ - createPluginExports() dist/plugins/* for pnpm overrides │ -// │ - mergePackageJson() │ -// │ - validateExternalDeps() │ -// └─────────────────────────────────────────────────────────────────────┘ -// -// Output Structure: -// dist/@vitest/* - Copied packages (browser/Node.js safe) -// dist/vendor/* - Bundled leaf dependencies -// dist/plugins/* - Shims for pnpm overrides -// dist/index.js - Browser-safe entry -// dist/index-node.js - Node.js entry (includes browser-provider) -// -// Key Design: -// - COPY @vitest/* to preserve browser/Node.js separation -// - BUNDLE only leaf deps (chai, etc.) to reduce install size -// - Separate entries prevent __vite__injectQuery errors in browser - -import { existsSync } from 'node:fs'; -import { - copyFile, - glob as fsGlob, - mkdir, - readFile, - readdir, - rm, - stat, - writeFile, -} from 'node:fs/promises'; -import { builtinModules } from 'node:module'; -import { basename, join, parse, resolve, dirname, relative } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import { parseSync } from 'oxc-parser'; -import { format } from 'oxfmt'; -import { build } from 'rolldown'; -import { dts } from 'rolldown-plugin-dts'; - -import { generateLicenseFile } from '../../scripts/generate-license.js'; -import pkg from './package.json' with { type: 'json' }; - -const projectDir = dirname(fileURLToPath(import.meta.url)); -const vitestSourceDir = resolve(projectDir, 'node_modules/vitest-dev'); -const distDir = resolve(projectDir, 'dist'); -const vendorDir = resolve(distDir, 'vendor'); - -const CORE_PACKAGE_NAME = '@voidzero-dev/vite-plus-core'; -const TEST_PACKAGE_NAME = '@voidzero-dev/vite-plus-test'; - -// @vitest/* packages to copy (not bundle) to preserve browser/Node.js separation -// These are copied from node_modules to dist/@vitest/ to avoid shared chunks -// that mix Node.js-only code with browser code -const VITEST_PACKAGES_TO_COPY = [ - '@vitest/runner', - '@vitest/utils', - '@vitest/spy', - '@vitest/expect', - '@vitest/snapshot', - '@vitest/mocker', - '@vitest/pretty-format', - '@vitest/browser', - '@vitest/browser-playwright', - '@vitest/browser-webdriverio', - '@vitest/browser-preview', -] as const; - -// Mapping from @vitest/* package specifiers to their paths within dist/@vitest/ -// Used for import rewriting and vendor-aliases plugin -const VITEST_PACKAGE_TO_PATH: Record = { - // @vitest/runner - '@vitest/runner': '@vitest/runner/index.js', - '@vitest/runner/utils': '@vitest/runner/utils.js', - '@vitest/runner/types': '@vitest/runner/types.js', - // @vitest/utils - '@vitest/utils': '@vitest/utils/index.js', - '@vitest/utils/source-map': '@vitest/utils/source-map.js', - '@vitest/utils/source-map/node': '@vitest/utils/source-map/node.js', - '@vitest/utils/error': '@vitest/utils/error.js', - '@vitest/utils/helpers': '@vitest/utils/helpers.js', - '@vitest/utils/display': '@vitest/utils/display.js', - '@vitest/utils/timers': '@vitest/utils/timers.js', - '@vitest/utils/highlight': '@vitest/utils/highlight.js', - '@vitest/utils/offset': '@vitest/utils/offset.js', - '@vitest/utils/resolver': '@vitest/utils/resolver.js', - '@vitest/utils/serialize': '@vitest/utils/serialize.js', - '@vitest/utils/constants': '@vitest/utils/constants.js', - '@vitest/utils/diff': '@vitest/utils/diff.js', - // @vitest/spy - '@vitest/spy': '@vitest/spy/index.js', - // @vitest/expect - '@vitest/expect': '@vitest/expect/index.js', - // @vitest/snapshot - '@vitest/snapshot': '@vitest/snapshot/index.js', - '@vitest/snapshot/environment': '@vitest/snapshot/environment.js', - '@vitest/snapshot/manager': '@vitest/snapshot/manager.js', - // @vitest/mocker - '@vitest/mocker': '@vitest/mocker/index.js', - '@vitest/mocker/node': '@vitest/mocker/node.js', - '@vitest/mocker/browser': '@vitest/mocker/browser.js', - '@vitest/mocker/redirect': '@vitest/mocker/redirect.js', - '@vitest/mocker/transforms': '@vitest/mocker/transforms.js', - '@vitest/mocker/automock': '@vitest/mocker/automock.js', - '@vitest/mocker/register': '@vitest/mocker/register.js', - // @vitest/pretty-format - '@vitest/pretty-format': '@vitest/pretty-format/index.js', - // @vitest/browser - '@vitest/browser': '@vitest/browser/index.js', - '@vitest/browser/context': '@vitest/browser/context.js', - '@vitest/browser/client': '@vitest/browser/client.js', - '@vitest/browser/locators': '@vitest/browser/locators.js', - // @vitest/browser-playwright - '@vitest/browser-playwright': '@vitest/browser-playwright/index.js', - // @vitest/browser-webdriverio - '@vitest/browser-webdriverio': '@vitest/browser-webdriverio/index.js', - // @vitest/browser-preview - '@vitest/browser-preview': '@vitest/browser-preview/index.js', -}; - -// Packages that should NOT be bundled into dist/vendor/ (remain external at runtime) -// There are two categories: -// 1. Runtime deps (also in package.json dependencies) - installed with the package, not bundled -// 2. Peer/optional deps (also in peerDependencies) - users must install themselves -const EXTERNAL_BLOCKLIST = new Set([ - // Our own packages - resolved at runtime - CORE_PACKAGE_NAME, - `${CORE_PACKAGE_NAME}/module-runner`, - 'vite', - 'vitest', - - // Peer dependencies - consumers must provide these - '@edge-runtime/vm', - '@opentelemetry/api', - '@standard-schema/spec', // Types-only import from @vitest/expect - 'happy-dom', - 'jsdom', - - // Optional dependencies with bundling issues or native bindings - 'debug', // environment detection broken when bundled - 'playwright', // native bindings - 'webdriverio', // native bindings - - // Runtime deps (in package.json dependencies) - not bundled, resolved at install time - 'sirv', - 'ws', - 'pixelmatch', - 'pngjs', - - // MSW (Mock Service Worker) - optional peer dep of @vitest/mocker - 'msw', - 'msw/browser', - 'msw/core/http', -]); - -// CJS packages that need their default export destructured to named exports -const CJS_REEXPORT_PACKAGES = new Set(['expect-type']); - -// Node built-in modules (including node: prefix variants) -const NODE_BUILTINS = new Set([...builtinModules, ...builtinModules.map((m) => `node:${m}`)]); - -// Step 1: Copy vitest-dev dist files (rewriting vite -> core package) -await bundleVitest(); - -// Step 1.5: Rebrand vitest CLI output as "vp test" with vite-plus version -await brandVitest(); - -// Step 2: Copy @vitest/* packages from node_modules to dist/@vitest/ -// This preserves the original file structure to maintain browser/Node.js separation -await copyVitestPackages(); - -// Step 2.5: Convert tabs to spaces in all copied JS files for consistent formatting -await convertTabsToSpaces(); - -// Step 3: Collect leaf dependencies from copied @vitest/* files -// These are external packages like tinyrainbow, pathe, chai, etc. -const leafDeps = await collectLeafDependencies(); - -// Step 4: Bundle only leaf dependencies into dist/vendor/ -// Unlike bundling @vitest/* directly, this avoids shared chunks that mix browser/Node.js code -const leafDepToVendorPath = await bundleLeafDeps(leafDeps); - -// Step 5: Rewrite imports in copied @vitest/* and vitest-dev files -// - @vitest/* -> relative paths to dist/@vitest/ -// - leaf deps -> relative paths to dist/vendor/ -// - vite -> @voidzero-dev/vite-plus-core -await rewriteVitestImports(leafDepToVendorPath); - -// Step 6: Fix pkgRoot resolution in all @vitest/* packages -// Files are now at dist/@vitest/*/index.js, so "../.." needs to become "../../.." -await patchVitestPkgRootPaths(); - -// Step 7: Patch @vitest/browser package (vendor-aliases plugin, exclude list) -await patchVitestBrowserPackage(); - -// Step 8: Patch browser provider locators.js files for browser-safe imports -await patchBrowserProviderLocators(); - -// Step 9: Post-processing -await patchVendorPaths(); -await patchVitestCoreResolver(); -await createBrowserCompatShim(); -await createModuleRunnerStub(); -await createNodeEntry(); -await copyBrowserClientFiles(); -await createBrowserEntryFiles(); -await patchModuleAugmentations(); -await patchChaiTypeReference(); -await patchMockerHoistedModule(); -await patchServerDepsInline(); -const pluginExports = await createPluginExports(); -await mergePackageJson(pluginExports); -generateLicenseFile({ - title: 'Vite-Plus test license', - packageName: 'Vite-Plus', - outputPath: join(projectDir, 'LICENSE'), - coreLicensePath: join(projectDir, '..', '..', 'LICENSE'), - bundledPaths: [distDir], - resolveFrom: [projectDir, join(projectDir, '..', '..')], - extraPackages: [ - { packageDir: vitestSourceDir }, - ...VITEST_PACKAGES_TO_COPY.map((packageName) => ({ - packageDir: resolve(projectDir, 'node_modules', packageName), - })), - ], -}); -if (!existsSync(join(projectDir, 'LICENSE'))) { - throw new Error('LICENSE was not generated during build'); -} -await validateExternalDeps(); - -async function mergePackageJson(pluginExports: Array<{ exportPath: string; shimFile: string }>) { - const vitestPackageJsonPath = join(vitestSourceDir, 'package.json'); - const destPackageJsonPath = resolve(projectDir, 'package.json'); - - const vitestPkg = JSON.parse(await readFile(vitestPackageJsonPath, 'utf-8')); - const destPkg = JSON.parse(await readFile(destPackageJsonPath, 'utf-8')); - - // Fields to merge from vitest-dev package.json (excluding dependencies since we bundle them) - const fieldsToMerge = [ - 'imports', - 'exports', - 'main', - 'module', - 'types', - 'engines', - 'peerDependencies', - 'peerDependenciesMeta', - ] as const; - - for (const field of fieldsToMerge) { - if (vitestPkg[field] !== undefined) { - destPkg[field] = vitestPkg[field]; - } - } - - // Remove bundled @vitest/* packages from peerDependencies - // These browser provider packages are now bundled, so users don't need to install them - const bundledPeerDeps = [ - '@vitest/browser-playwright', - '@vitest/browser-webdriverio', - '@vitest/browser-preview', - ]; - if (destPkg.peerDependencies) { - for (const dep of bundledPeerDeps) { - delete destPkg.peerDependencies[dep]; - } - } - if (destPkg.peerDependenciesMeta) { - for (const dep of bundledPeerDeps) { - delete destPkg.peerDependenciesMeta[dep]; - } - } - - destPkg.bundledVersions = { - ...destPkg.bundledVersions, - vitest: vitestPkg.version, - }; - - // Add @vitest/browser compatible export (for when this package overrides @vitest/browser) - // The main "." export is what's used when code imports from @vitest/browser - if (destPkg.exports) { - // Add conditional Node.js export to the main entry - // Node.js code (like @vitest/browser-playwright) uses index-node.js which includes - // browser-provider exports. Browser code uses index.js which is safe. - // This separation prevents Node.js-only code (like __vite__injectQuery) from being - // loaded in the browser, which would cause "Identifier already declared" errors. - // - // IMPORTANT: The 'browser' condition must come BEFORE 'node' because vitest passes - // custom --conditions (like 'browser') to worker processes when frameworks like Nuxt - // set edge/cloudflare presets. Without the 'browser' condition here, Node.js would - // match 'node' first, loading index-node.js which imports @vitest/browser/index.js, - // which imports 'ws'. With --conditions browser active, 'ws' resolves to its browser - // stub (ws/browser.js) that doesn't export WebSocketServer, causing a SyntaxError. - // See: https://github.com/voidzero-dev/vite-plus/issues/831 - if (destPkg.exports['.'] && destPkg.exports['.'].import) { - destPkg.exports['.'].import = { - types: destPkg.exports['.'].import.types, - browser: destPkg.exports['.'].import.default, - node: './dist/index-node.js', - default: destPkg.exports['.'].import.default, - }; - } - - destPkg.exports['./browser-compat'] = { - default: './dist/browser-compat.js', - }; - - // Add @vitest/browser-compatible subpath exports - // These are needed when this package is used as a pnpm override for @vitest/browser - // Files are copied to dist/ (not dist/vendor/) to match path resolution in bundled code - destPkg.exports['./client'] = { - default: './dist/client.js', - }; - // Point to @vitest/browser/context.js so that tests and init scripts share the same module - // This is critical: the init script (locators.js) calls page.extend() on this module, - // and tests must use the SAME module instance to see the extended methods - destPkg.exports['./context'] = { - types: './browser/context.d.ts', - default: './dist/@vitest/browser/context.js', - }; - // Also export ./browser/context for users importing vite-plus/test/browser/context - destPkg.exports['./browser/context'] = { - types: './browser/context.d.ts', - default: './dist/@vitest/browser/context.js', - }; - destPkg.exports['./locators'] = { - default: './dist/locators.js', - }; - destPkg.exports['./matchers'] = { - default: './dist/dummy.js', // Placeholder - }; - destPkg.exports['./utils'] = { - default: './dist/dummy.js', // Placeholder - }; - - // Add @vitest/browser-playwright compatible export - // Users can import { playwright } from 'vitest/browser-playwright' - destPkg.exports['./browser-playwright'] = { - types: './dist/@vitest/browser-playwright/index.d.ts', - default: './dist/@vitest/browser-playwright/index.js', - }; - - // Add @vitest/browser-webdriverio compatible export - // Users can import { webdriverio } from 'vitest/browser-webdriverio' - destPkg.exports['./browser-webdriverio'] = { - types: './dist/@vitest/browser-webdriverio/index.d.ts', - default: './dist/@vitest/browser-webdriverio/index.js', - }; - - // Add @vitest/browser-preview compatible export - // Users can import { preview } from 'vitest/browser-preview' - destPkg.exports['./browser-preview'] = { - types: './dist/@vitest/browser-preview/index.d.ts', - default: './dist/@vitest/browser-preview/index.js', - }; - - // Add browser/providers/* alias exports for compatibility - // Some vitest examples use the nested path format - destPkg.exports['./browser/providers/playwright'] = { - types: './dist/@vitest/browser-playwright/index.d.ts', - default: './dist/@vitest/browser-playwright/index.js', - }; - destPkg.exports['./browser/providers/webdriverio'] = { - types: './dist/@vitest/browser-webdriverio/index.d.ts', - default: './dist/@vitest/browser-webdriverio/index.js', - }; - destPkg.exports['./browser/providers/preview'] = { - types: './dist/@vitest/browser-preview/index.d.ts', - default: './dist/@vitest/browser-preview/index.js', - }; - - // Add plugin exports for all bundled @vitest/* packages - // This allows pnpm overrides to redirect: @vitest/runner -> vitest/plugins/runner - for (const { exportPath, shimFile } of pluginExports) { - destPkg.exports[exportPath] = { - default: shimFile, - }; - } - } - - // Merge vitest dependencies into devDependencies (since we bundle them) - // Skip packages that are already in dependencies (runtime deps) - if (vitestPkg.dependencies) { - destPkg.devDependencies = destPkg.devDependencies || {}; - for (const [dep, version] of Object.entries(vitestPkg.dependencies)) { - // Skip vite - we use our own core package - if (dep === 'vite') { - continue; - } - // Skip packages already in dependencies (they're runtime deps, not dev-only) - if (destPkg.dependencies && destPkg.dependencies[dep]) { - continue; - } - // Don't override existing devDependencies - if (!destPkg.devDependencies[dep]) { - destPkg.devDependencies[dep] = version; - } - } - } - - const { code, errors } = await format( - destPackageJsonPath, - JSON.stringify(destPkg, null, 2) + '\n', - { - experimentalSortPackageJson: true, - }, - ); - if (errors.length > 0) { - for (const error of errors) { - console.error(error); - } - process.exit(1); - } - await writeFile(destPackageJsonPath, code); -} - -async function bundleVitest() { - const vitestDestDir = projectDir; - - await mkdir(vitestDestDir, { recursive: true }); - - // Get all vitest files excluding node_modules and package.json - const vitestFiles = fsGlob(join(vitestSourceDir, '**/*'), { - exclude: [ - join(vitestSourceDir, 'node_modules/**'), - join(vitestSourceDir, 'package.json'), - join(vitestSourceDir, 'README.md'), - join(vitestSourceDir, 'LICENSE.md'), - ], - }); - - for await (const file of vitestFiles) { - const stats = await stat(file); - if (!stats.isFile()) { - continue; - } - - const relativePath = file.replace(vitestSourceDir, ''); - const destPath = join(vitestDestDir, relativePath); - - await mkdir(parse(destPath).dir, { recursive: true }); - - // Rewrite vite imports in .js, .mjs, and .cjs files - if ( - file.endsWith('.js') || - file.endsWith('.mjs') || - file.endsWith('.cjs') || - file.endsWith('.d.ts') || - file.endsWith('.d.cts') - ) { - let content = await readFile(file, 'utf-8'); - content = content - .replaceAll(/from ['"]vite['"]/g, `from '${CORE_PACKAGE_NAME}'`) - .replaceAll(/import\(['"]vite['"]\)/g, `import('${CORE_PACKAGE_NAME}')`) - .replaceAll(/require\(['"]vite['"]\)/g, `require('${CORE_PACKAGE_NAME}')`) - .replaceAll(/require\("vite"\)/g, `require("${CORE_PACKAGE_NAME}")`) - .replaceAll(`import 'vite';`, `import '${CORE_PACKAGE_NAME}';`) - .replaceAll(`'vite/module-runner'`, `'${CORE_PACKAGE_NAME}/module-runner'`) - .replaceAll(`declare module "vite"`, `declare module "${CORE_PACKAGE_NAME}"`) - .replaceAll(/import\(['"]vitest['"]\)/g, `import('${TEST_PACKAGE_NAME}')`); - console.log(`Replaced vite imports in ${destPath}`); - await writeFile(destPath, content, 'utf-8'); - } else { - await copyFile(file, destPath); - } - } -} - -/** - * Rebrand vitest CLI output as "vp test" with Vite+ banner styling. - * Patches bundled chunks to replace vitest branding and align banner output. - */ -async function brandVitest() { - const chunksDir = resolve(projectDir, 'dist/chunks'); - const cacFiles: string[] = []; - for await (const file of fsGlob(join(chunksDir, 'cac.*.js'))) { - cacFiles.push(file); - } - if (cacFiles.length === 0) { - throw new Error('brandVitest: no cac chunk found in dist/chunks/'); - } - for (const cacFile of cacFiles) { - let content = await readFile(cacFile, 'utf-8'); - - function patchString(label: string, search: string | RegExp, replacement: string) { - const before = content; - content = - typeof search === 'string' - ? content.replace(search, replacement) - : content.replace(search, replacement); - if (content === before) { - throw new Error( - `brandVitest: failed to patch "${label}" — pattern not found in ${cacFile}`, - ); - } - } - - // 1. CLI name: cac("vitest") → cac("vp test") - patchString('cac name', 'cac("vitest")', 'cac("vp test")'); - - // 2. Version: var version = "" → use VP_VERSION env var with fallback - patchString( - 'version', - /var version = "(\d+\.\d+\.\d+[^"]*)"/, - 'var version = process.env.VP_VERSION || "$1"', - ); - - // 3. Banner regex: /^vitest\/\d+\.\d+\.\d+$/ → /^vp test\/[\d.]+$/ - patchString('banner regex', '/^vitest\\/\\d+\\.\\d+\\.\\d+$/', '/^vp test\\/[\\d.]+$/'); - - // 4. Help text: $ vitest --help → $ vp test --help - patchString('help text', '$ vitest --help --expand-help', '$ vp test --help --expand-help'); - - await writeFile(cacFile, content, 'utf-8'); - console.log(`Branded vitest → vp test in ${cacFile}`); - } - - const cliApiFiles: string[] = []; - for await (const file of fsGlob(join(chunksDir, 'cli-api.*.js'))) { - cliApiFiles.push(file); - } - if (cliApiFiles.length === 0) { - throw new Error('brandVitest: no cli-api chunk found in dist/chunks/'); - } - - for (const cliApiFile of cliApiFiles) { - let content = await readFile(cliApiFile, 'utf-8'); - - function patchString(label: string, search: string | RegExp, replacement: string) { - const before = content; - content = - typeof search === 'string' - ? content.replace(search, replacement) - : content.replace(search, replacement); - if (content === before) { - throw new Error( - `brandVitest: failed to patch "${label}" — pattern not found in ${cliApiFile}`, - ); - } - } - - // Remove one extra leading newline before DEV/RUN banner. - patchString( - 'banner leading newline', - /printBanner\(\) \{\n\t\tthis\.log\(\);\n/, - 'printBanner() {\n', - ); - - // Use a blue badge for both DEV and RUN. - patchString( - 'banner color', - /const color = this\.ctx\.config\.watch \? "blue" : "[a-z]+";\n\t\tconst mode = this\.ctx\.config\.watch \? "DEV" : "RUN";/, - 'const mode = this.ctx.config.watch ? "DEV" : "RUN";\n\t\tconst label = c.bold(c.inverse(c.blue(` ${mode} `)));', - ); - - // Remove the version from the banner line and render a high-contrast label. - patchString( - 'banner version text', - /this\.log\(withLabel\(color, mode, (?:""|`v\$\{this\.ctx\.version\} `)\) \+ c\.gray\(this\.ctx\.config\.root\)\);/, - 'this.log(`${label} ${c.gray(this.ctx.config.root)}`);', - ); - - await writeFile(cliApiFile, content, 'utf-8'); - console.log(`Branded vitest banner in ${cliApiFile}`); - } -} - -/** - * Copy @vitest/* packages from node_modules to dist/@vitest/ - * This preserves the original file structure to maintain browser/Node.js separation. - * Unlike bundling with Rolldown, copying avoids creating shared chunks that mix - * Node.js-only code with browser code. - */ -async function copyVitestPackages() { - console.log('\nCopying @vitest/* packages to dist/@vitest/...'); - - const vitestDir = resolve(distDir, '@vitest'); - await rm(vitestDir, { recursive: true, force: true }); - await mkdir(vitestDir, { recursive: true }); - - let totalCopied = 0; - - for (const pkg of VITEST_PACKAGES_TO_COPY) { - const pkgName = pkg.replace('@vitest/', ''); - const srcDir = resolve(projectDir, `node_modules/${pkg}/dist`); - const destPkgDir = resolve(vitestDir, pkgName); - - try { - await stat(srcDir); - } catch { - console.log(` Warning: ${pkg} not installed, skipping`); - continue; - } - - console.log(` Copying ${pkg}...`); - const copied = await copyDirRecursive(srcDir, destPkgDir); - totalCopied += copied; - console.log(` -> ${copied} files`); - - // Copy root .d.ts files from @vitest/browser package directory. - // These are type definitions that live at the package root (not in dist/), - // e.g. context.d.ts, matchers.d.ts, aria-role.d.ts, utils.d.ts. - // Dynamically scan instead of hardcoding to handle future upstream additions. - if (pkg === '@vitest/browser') { - const pkgRoot = resolve(projectDir, `node_modules/${pkg}`); - try { - const pkgEntries = await readdir(pkgRoot); - for (const entry of pkgEntries) { - if (entry.endsWith('.d.ts')) { - await copyFile(join(pkgRoot, entry), join(destPkgDir, entry)); - console.log(` + copied ${entry}`); - totalCopied++; - } - } - } catch { - // Package root not readable, skip - } - } - } - - console.log(`\nCopied ${totalCopied} files to dist/@vitest/`); -} - -/** - * Recursively copy a directory - */ -async function copyDirRecursive(srcDir: string, destDir: string): Promise { - await mkdir(destDir, { recursive: true }); - const entries = await readdir(srcDir, { withFileTypes: true }); - let count = 0; - - for (const entry of entries) { - const srcPath = join(srcDir, entry.name); - const destPath = join(destDir, entry.name); - - if (entry.isDirectory()) { - count += await copyDirRecursive(srcPath, destPath); - } else if (entry.isFile()) { - await copyFile(srcPath, destPath); - count++; - } - } - - return count; -} - -/** - * Collect leaf dependencies from copied @vitest/* files AND vitest core dist files. - * These are external packages that should be bundled (tinyrainbow, pathe, chai, expect-type, etc.) - * but NOT @vitest/*, vitest/*, vite/*, node built-ins, or blocklisted packages. - */ -async function collectLeafDependencies(): Promise> { - console.log('\nCollecting leaf dependencies from dist/...'); - - const leafDeps = new Set(); - const vitestDir = resolve(distDir, '@vitest'); - - // Scan both @vitest/* packages AND vitest core dist files - const jsFiles = fsGlob([ - join(vitestDir, '**/*.js'), - join(distDir, '*.js'), - join(distDir, 'chunks/*.js'), - ]); - - for await (const file of jsFiles) { - const content = await readFile(file, 'utf-8'); - const result = parseSync(file, content, { sourceType: 'module' }); - - // Collect ESM static imports - for (const imp of result.module.staticImports) { - const specifier = imp.moduleRequest.value; - if (isLeafDependency(specifier)) { - leafDeps.add(specifier); - } - } - - // Collect ESM static exports (re-exports) - for (const exp of result.module.staticExports) { - for (const entry of exp.entries) { - if (entry.moduleRequest) { - const specifier = entry.moduleRequest.value; - if (isLeafDependency(specifier)) { - leafDeps.add(specifier); - } - } - } - } - - // Collect dynamic imports (only string literals) - for (const dynImp of result.module.dynamicImports) { - const rawText = content.slice(dynImp.moduleRequest.start, dynImp.moduleRequest.end); - if ( - (rawText.startsWith("'") && rawText.endsWith("'")) || - (rawText.startsWith('"') && rawText.endsWith('"')) - ) { - const specifier = rawText.slice(1, -1); - if (isLeafDependency(specifier)) { - leafDeps.add(specifier); - } - } - } - } - - console.log(`Found ${leafDeps.size} leaf dependencies:`); - for (const dep of leafDeps) { - console.log(` - ${dep}`); - } - - return leafDeps; -} - -/** - * Check if a specifier is a leaf dependency that should be bundled. - * Leaf deps are external packages that are NOT: - * - @vitest/* (we copy these) - * - vitest or vitest/* (we copy vitest-dev) - * - vite or vite/* (we use our core package) - * - Node.js built-ins - * - Blocklisted packages - * - Relative paths - */ -function isLeafDependency(specifier: string): boolean { - // Relative paths - if (specifier.startsWith('.') || specifier.startsWith('/')) { - return false; - } - // @vitest/* packages (we copy these) - if (specifier.startsWith('@vitest/')) { - return false; - } - // vitest or vitest/* (we copy vitest-dev) - if (specifier === 'vitest' || specifier.startsWith('vitest/')) { - return false; - } - // vite or vite/* (we use our core package) - if (specifier === 'vite' || specifier.startsWith('vite/')) { - return false; - } - // Node.js built-ins - if (NODE_BUILTINS.has(specifier)) { - return false; - } - // Blocklisted packages - if (EXTERNAL_BLOCKLIST.has(specifier)) { - return false; - } - // Node.js subpath imports (#module-evaluator, etc.) - if (specifier.startsWith('#')) { - return false; - } - // Invalid specifiers - if (!/^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*/.test(specifier)) { - return false; - } - return true; -} - -/** - * Bundle only leaf dependencies into dist/vendor/. - * Only bundles non-@vitest deps (tinyrainbow, pathe, chai, etc.) - * to avoid shared chunks that mix Node.js and browser code. - */ -async function bundleLeafDeps(leafDeps: Set): Promise> { - console.log('\nBundling leaf dependencies...'); - - await rm(vendorDir, { recursive: true, force: true }); - await mkdir(vendorDir, { recursive: true }); - - const specifierToVendorPath = new Map(); - - if (leafDeps.size === 0) { - console.log(' No leaf dependencies to bundle.'); - return specifierToVendorPath; - } - - // Build input object with all leaf deps - const input: Record = {}; - for (const dep of leafDeps) { - const safeName = safeFileName(dep); - input[safeName] = dep; - } - - try { - await build({ - input, - output: { - dir: vendorDir, - format: 'esm', - entryFileNames: '[name].mjs', - chunkFileNames: 'shared-[hash].mjs', - }, - platform: 'neutral', - treeshake: false, - external: [ - // Keep node built-ins external - ...NODE_BUILTINS, - // Keep blocklisted packages external - ...EXTERNAL_BLOCKLIST, - // Keep @vitest/* external (we copy them) - /@vitest\//, - // Keep vitest external (we copy it) - /^vitest(\/.*)?$/, - // Keep vite external (we use core package) - /^vite(\/.*)?$/, - ], - resolve: { - conditionNames: ['node', 'import', 'default'], - mainFields: ['module', 'main'], - }, - logLevel: 'warn', - }); - - const dtsInput = { ...input }; - - for (const name of Object.keys(dtsInput)) { - const vendorDtsPath = join(vendorDir, `vendor_${name}.d.ts`); - dtsInput[name] = vendorDtsPath; - await writeFile(vendorDtsPath, `export * from '${name}';`, 'utf-8'); - } - - await build({ - input: dtsInput, - output: { - dir: vendorDir, - format: 'esm', - entryFileNames: '[name].mts', - }, - plugins: [ - dts({ - dtsInput: true, - oxc: true, - resolver: 'oxc', - emitDtsOnly: true, - tsconfig: false, - }), - ], - }); - - for (const p of Object.values(dtsInput)) { - await rm(p); - } - - // Register all specifiers - for (const dep of leafDeps) { - const safeName = safeFileName(dep); - const vendorFilePath = join(vendorDir, `${safeName}.mjs`); - specifierToVendorPath.set(dep, vendorFilePath); - console.log(` -> vendor/${safeName}.mjs`); - - // Fix CJS packages that need named exports extracted from default - if (CJS_REEXPORT_PACKAGES.has(dep)) { - await fixCjsNamedExports(vendorFilePath, dep); - } - } - } catch (error) { - console.error('Failed to bundle leaf dependencies:', error); - throw error; - } - - console.log(`\nBundled ${specifierToVendorPath.size} leaf dependencies.`); - return specifierToVendorPath; -} - -/** - * Rewrite imports in all copied @vitest/* files and vitest-dev dist files. - * This handles: - * - @vitest/* -> relative paths to dist/@vitest/ - * - vitest/* -> relative paths to dist/ - * - vite -> @voidzero-dev/vite-plus-core - * - leaf deps -> relative paths to dist/vendor/ - */ -async function rewriteVitestImports(leafDepToVendorPath: Map) { - console.log('\nRewriting imports in @vitest/* and vitest core files...'); - - const vitestDir = resolve(distDir, '@vitest'); - let rewrittenCount = 0; - - // Scan both @vitest/* packages AND vitest core dist files - // Include .d.ts files so TypeScript type imports also get rewritten - const jsFiles = fsGlob([ - join(vitestDir, '**/*.js'), - join(vitestDir, '**/*.d.ts'), - join(distDir, '*.js'), - join(distDir, '*.d.ts'), - join(distDir, 'chunks/*.js'), - join(distDir, 'chunks/*.d.ts'), - ]); - - for await (const file of jsFiles) { - let content = await readFile(file, 'utf-8'); - const fileDir = dirname(file); - - // Build specifier map for this file - const specifierMap = new Map(); - - // Add @vitest/* mappings (relative paths) - for (const [pkg, destPath] of Object.entries(VITEST_PACKAGE_TO_PATH)) { - const absoluteDest = resolve(distDir, destPath); - let relativePath = relative(fileDir, absoluteDest); - relativePath = relativePath.split('\\').join('/'); // Windows fix - if (!relativePath.startsWith('.')) { - relativePath = './' + relativePath; - } - specifierMap.set(pkg, absoluteDest); - } - - // Add vitest/* mappings (relative to dist/) - const vitestSubpathRewrites: Record = { - vitest: resolve(distDir, 'index.js'), - 'vitest/node': resolve(distDir, 'node.js'), - 'vitest/config': resolve(distDir, 'config.js'), - // vitest/browser exports page, server, CDPSession, BrowserCommands, etc from @vitest/browser/context - // This matches vitest's own package.json exports: "./browser" -> "./browser/context.d.ts" - 'vitest/browser': resolve(distDir, '@vitest/browser/context.js'), - // vitest/internal/browser exports browser-safe __INTERNAL and stringify (NOT @vitest/browser/index.js which has Node.js code) - 'vitest/internal/browser': resolve(distDir, 'browser.js'), - 'vitest/runners': resolve(distDir, 'runners.js'), - 'vitest/suite': resolve(distDir, 'suite.js'), - 'vitest/environments': resolve(distDir, 'environments.js'), - 'vitest/coverage': resolve(distDir, 'coverage.js'), - 'vitest/reporters': resolve(distDir, 'reporters.js'), - 'vitest/snapshot': resolve(distDir, 'snapshot.js'), - 'vitest/mocker': resolve(distDir, 'mocker.js'), - }; - for (const [specifier, absolutePath] of Object.entries(vitestSubpathRewrites)) { - specifierMap.set(specifier, absolutePath); - } - - // Add leaf dep mappings (relative to vendor/) - for (const [specifier, vendorPath] of leafDepToVendorPath) { - specifierMap.set(specifier, vendorPath); - } - - // For files inside @vitest/browser/, preserve 'vitest/browser' as a bare specifier. - // These files run in browser context where the vitest:vendor-aliases plugin - // resolves 'vitest/browser' to the virtual module '\0vitest/browser', - // which provides browser-safe context API (page, server, userEvent, utils). - // Without this, 'vitest/browser' gets rewritten to './index.js' which resolves - // to the Node.js server file (~9000 lines of node:fs, ws, etc.) - if (file.includes('@vitest/browser') || file.includes('@vitest\\browser')) { - specifierMap.delete('vitest/browser'); - } - - // Rewrite using AST - const rewritten = rewriteImportsWithAst(content, file, false, specifierMap); - - // Also rewrite vite -> core package (simple string replacement since it's a package name) - let finalContent = rewritten - .replaceAll(/from ['"]vite['"]/g, `from '${CORE_PACKAGE_NAME}'`) - .replaceAll(/import\(['"]vite['"]\)/g, `import('${CORE_PACKAGE_NAME}')`) - .replaceAll(`'vite/module-runner'`, `'${CORE_PACKAGE_NAME}/module-runner'`); - - // Special handling for @vitest/mocker entry files that have redundant side-effect imports - // The original files have: import 'magic-string'; export {...} from './chunk-automock.js'; import 'estree-walker'; - // This is problematic because: - // 1. Side-effect imports are redundant (chunk files already import what they need) - // 2. Having imports after exports can confuse some module parsers - // Fix: Remove redundant side-effect imports from vendor deps in entry files - if (file.includes('@vitest/mocker') || file.includes('@vitest\\mocker')) { - // Get the base filename - const baseName = file.split(/[/\\]/).pop(); - // Only process entry files (not chunk files) - if (baseName && !baseName.startsWith('chunk-')) { - // Remove side-effect imports from vendor deps (these are redundant since chunk files import them) - finalContent = finalContent.replace(/import\s*['"][^'"]*vendor[^'"]*\.mjs['"];?\s*/g, ''); - } - } - - if (finalContent !== content) { - await writeFile(file, finalContent, 'utf-8'); - rewrittenCount++; - } - } - - console.log(` Rewrote imports in ${rewrittenCount} files`); - - // Also rewrite imports in the main vitest-dev dist files - console.log('\nRewriting imports in vitest-dev dist files...'); - let mainRewrittenCount = 0; - - const mainJsFiles = fsGlob(join(distDir, '*.js')); - const chunksJsFiles = fsGlob(join(distDir, 'chunks', '*.js')); - const workersJsFiles = fsGlob(join(distDir, 'workers', '*.js')); - - for await (const file of mainJsFiles) { - const rewritten = await rewriteDistFile(file, leafDepToVendorPath); - if (rewritten) { - mainRewrittenCount++; - } - } - for await (const file of chunksJsFiles) { - const rewritten = await rewriteDistFile(file, leafDepToVendorPath); - if (rewritten) { - mainRewrittenCount++; - } - } - for await (const file of workersJsFiles) { - const rewritten = await rewriteDistFile(file, leafDepToVendorPath); - if (rewritten) { - mainRewrittenCount++; - } - } - - console.log(` Rewrote imports in ${mainRewrittenCount} dist files`); -} - -/** - * Rewrite imports in a vitest-dev dist file. - * Returns true if the file was modified. - */ -async function rewriteDistFile( - file: string, - leafDepToVendorPath: Map, -): Promise { - let content = await readFile(file, 'utf-8'); - - // Build specifier map - const specifierMap = new Map(); - - // Add @vitest/* mappings - for (const [pkg, destPath] of Object.entries(VITEST_PACKAGE_TO_PATH)) { - const absoluteDest = resolve(distDir, destPath); - specifierMap.set(pkg, absoluteDest); - } - - // Add leaf dep mappings - for (const [specifier, vendorPath] of leafDepToVendorPath) { - specifierMap.set(specifier, vendorPath); - } - - // Add vitest/* subpath mappings - // NOTE: Do NOT include 'vitest/browser' - it must be handled by - // the vitest:browser:virtual-module:context plugin at runtime - const vitestSubpathRewrites: Record = { - vitest: resolve(distDir, 'index.js'), - 'vitest/node': resolve(distDir, 'node.js'), - 'vitest/config': resolve(distDir, 'config.js'), - // 'vitest/browser' - intentionally omitted, handled by virtual module plugin - 'vitest/internal/browser': resolve(distDir, 'browser.js'), - 'vitest/runners': resolve(distDir, 'runners.js'), - 'vitest/suite': resolve(distDir, 'suite.js'), - 'vitest/environments': resolve(distDir, 'environments.js'), - 'vitest/coverage': resolve(distDir, 'coverage.js'), - 'vitest/reporters': resolve(distDir, 'reporters.js'), - 'vitest/snapshot': resolve(distDir, 'snapshot.js'), - 'vitest/mocker': resolve(distDir, 'mocker.js'), - }; - for (const [specifier, absolutePath] of Object.entries(vitestSubpathRewrites)) { - specifierMap.set(specifier, absolutePath); - } - - // Add mappings for ./vendor/vitest_*.mjs relative imports - // These are vitest-dev's bundled @vitest/* packages that we've copied to dist/@vitest/ - const vendorToVitest: Record = { - './vendor/vitest_runner.mjs': resolve(distDir, '@vitest/runner/index.js'), - './vendor/vitest_runners.mjs': resolve(distDir, 'runners.js'), - './vendor/vitest_browser.mjs': resolve(distDir, '@vitest/browser/context.js'), - './vendor/vitest_internal_browser.mjs': resolve(distDir, 'browser.js'), - './vendor/vitest_utils.mjs': resolve(distDir, '@vitest/utils/index.js'), - './vendor/vitest_spy.mjs': resolve(distDir, '@vitest/spy/index.js'), - './vendor/vitest_snapshot.mjs': resolve(distDir, '@vitest/snapshot/index.js'), - './vendor/vitest_expect.mjs': resolve(distDir, '@vitest/expect/index.js'), - }; - for (const [vendorPath, destPath] of Object.entries(vendorToVitest)) { - specifierMap.set(vendorPath, destPath); - } - - let rewritten = rewriteImportsWithAst(content, file, false, specifierMap); - - // Strip module-runner side-effect import from index.js - // This import is Node.js-only and causes browser tests to hang when vitest/index.js - // is loaded in browser context (to get describe, it, expect, etc.) - // The module-runner contains Node.js code (process.platform, etc.) that browsers can't execute - if (basename(file) === 'index.js') { - rewritten = rewritten.replace( - /import\s*['"]@voidzero-dev\/vite-plus-core\/module-runner['"];?\s*/g, - '', - ); - } - - if (rewritten !== content) { - await writeFile(file, rewritten, 'utf-8'); - return true; - } - return false; -} - -/** - * Rewrite imports using oxc-parser AST for precise replacements - */ -function rewriteImportsWithAst( - content: string, - filePath: string, - isCjs: boolean, - specifierToVendorPath: Map, -): string { - // Use Map to deduplicate replacements by start position - const replacementMap = new Map(); - - // Helper to get relative path for a specifier - const getRelativePath = (specifier: string): string | null => { - const vendorPath = specifierToVendorPath.get(specifier); - if (!vendorPath) { - return null; - } - let relativePath = relative(dirname(filePath), vendorPath); - // Normalize to forward slashes for ES module imports (Windows uses backslashes) - relativePath = relativePath.split('\\').join('/'); - if (!relativePath.startsWith('.')) { - relativePath = './' + relativePath; - } - return relativePath; - }; - - // Helper to add replacement (deduplicates by start position) - const addReplacement = (start: number, end: number, newValue: string) => { - if (!replacementMap.has(start)) { - replacementMap.set(start, [start, end, newValue]); - } - }; - - // Parse with oxc-parser - const result = parseSync(filePath, content, { - sourceType: isCjs ? 'script' : 'module', - }); - - // Collect ESM static imports - for (const imp of result.module.staticImports) { - const specifier = imp.moduleRequest.value; - const relativePath = getRelativePath(specifier); - if (relativePath) { - // Replace the module request (including quotes) - addReplacement(imp.moduleRequest.start, imp.moduleRequest.end, `'${relativePath}'`); - } - } - - // Collect ESM static exports (re-exports) - for (const exp of result.module.staticExports) { - for (const entry of exp.entries) { - if (entry.moduleRequest) { - const specifier = entry.moduleRequest.value; - const relativePath = getRelativePath(specifier); - if (relativePath) { - addReplacement(entry.moduleRequest.start, entry.moduleRequest.end, `'${relativePath}'`); - } - } - } - } - - // Collect dynamic imports (only string literals) - for (const dynImp of result.module.dynamicImports) { - const rawText = content.slice(dynImp.moduleRequest.start, dynImp.moduleRequest.end); - if ( - (rawText.startsWith("'") && rawText.endsWith("'")) || - (rawText.startsWith('"') && rawText.endsWith('"')) - ) { - const specifier = rawText.slice(1, -1); - const relativePath = getRelativePath(specifier); - if (relativePath) { - addReplacement(dynImp.moduleRequest.start, dynImp.moduleRequest.end, `'${relativePath}'`); - } - } - } - - // For CJS files, also handle require() calls using regex (oxc-parser doesn't track these) - if (isCjs) { - const requireRegex = /require\s*\(\s*(['"])([^'"]+)\1\s*\)/g; - let match; - while ((match = requireRegex.exec(content)) !== null) { - const specifier = match[2]; - const relativePath = getRelativePath(specifier); - if (relativePath) { - // Calculate the position of just the string literal (including quotes) - const stringStart = match.index + match[0].indexOf(match[1]); - const stringEnd = stringStart + match[1].length + specifier.length + match[1].length; - addReplacement(stringStart, stringEnd, `'${relativePath}'`); - } - } - } - - // Sort replacements in reverse order (end to start) to preserve positions - // eslint-disable-next-line unicorn/no-array-sort -- safe: sorting a fresh spread copy - const replacements = [...replacementMap.values()].sort((a, b) => b[0] - a[0]); - - // Apply replacements - let result_content = content; - for (const [start, end, newValue] of replacements) { - result_content = result_content.slice(0, start) + newValue + result_content.slice(end); - } - - return result_content; -} - -/** - * Fix CJS packages that only export default - extract named exports from the default export - */ -async function fixCjsNamedExports(vendorFilePath: string, specifier: string) { - let content = await readFile(vendorFilePath, 'utf-8'); - - // Match pattern like: export default require_xxx(); - // and: export { }; - const defaultExportMatch = content.match(/export default (require_\w+)\(\);/); - - if (defaultExportMatch) { - const requireFn = defaultExportMatch[1]; - console.log(` Fixing CJS named exports for ${specifier}...`); - - const emptyExportMatch = content.match(/export \{\s*\};/); - if (emptyExportMatch) { - // Pattern: export default require_xxx();\nexport { }; - content = content.replace( - /export default (require_\w+)\(\);\s*\nexport \{\s*\};/, - `const __cjs_export__ = ${requireFn}();\nexport const { expectTypeOf } = __cjs_export__;\nexport default __cjs_export__;`, - ); - } else { - // Pattern: export default require_xxx(); (no empty export block) - content = content.replace( - /export default (require_\w+)\(\);/, - `const __cjs_export__ = ${requireFn}();\nexport const { expectTypeOf } = __cjs_export__;\nexport default __cjs_export__;`, - ); - } - - await writeFile(vendorFilePath, content, 'utf-8'); - } -} - -/** - * Create a safe filename from a specifier - */ -function safeFileName(specifier: string): string { - return specifier.replace(/[@/]/g, '_').replace(/^_/, ''); -} - -/** - * Patch pkgRoot/distRoot paths in vendor files. - * The bundled code assumes files are in dist/, but vendor files are in dist/vendor/ - * So "../.." needs to become "../../.." to correctly resolve to package root. - * Also patches relative file references like "context.js" to "../context.js". - */ -async function patchVendorPaths() { - console.log('\nPatching vendor paths...'); - - // Patterns that need one more level up due to vendor subdirectory - const pathPatterns = [ - // Package root calculation: "../.." -> "../../.." - { - original: `resolve$1(fileURLToPath(import.meta.url), "../..")`, - fixed: `resolve$1(fileURLToPath(import.meta.url), "../../..")`, - }, - // context.js reference: "context.js" -> "../context.js" - // This is used in browser server to resolve the vitest/browser/context export - { - original: `resolve$1(__dirname$1, "context.js")`, - fixed: `resolve$1(__dirname$1, "../context.js")`, - }, - ]; - - const vendorFiles = fsGlob(join(vendorDir, '*.mjs')); - let patchedCount = 0; - - for await (const file of vendorFiles) { - let content = await readFile(file, 'utf-8'); - let modified = false; - - for (const { original, fixed } of pathPatterns) { - if (content.includes(original)) { - content = content.replaceAll(original, fixed); - modified = true; - } - } - - if (modified) { - await writeFile(file, content, 'utf-8'); - console.log(` Patched paths in ${relative(distDir, file)}`); - patchedCount++; - } - } - - if (patchedCount === 0) { - console.log(' No vendor files needed path patching'); - } else { - console.log(` Successfully patched ${patchedCount} file(s)`); - } -} - -/** - * Patch VitestCoreResolver to resolve vite-plus/test directly. - * - * Problem: CLI's `export * from '@voidzero-dev/vite-plus-test'` creates a re-export - * chain that breaks module identity in Vite's SSR transform. expect.extend() - * mutations aren't visible through the re-export. - * - * Fix: Make VitestCoreResolver resolve both vite-plus/test and - * @voidzero-dev/vite-plus-test directly to dist/index.js, bypassing re-exports. - */ -async function patchVitestCoreResolver() { - console.log('\nPatching VitestCoreResolver for CLI package alias...'); - - let cliApiChunk: string | undefined; - for await (const chunk of fsGlob(join(distDir, 'chunks/cli-api.*.js'))) { - cliApiChunk = chunk; - break; - } - - if (!cliApiChunk) { - throw new Error('cli-api chunk not found'); - } - let content = await readFile(cliApiChunk, 'utf8'); - - // Find the VitestCoreResolver resolveId function and add our package aliases - const oldPattern = `async resolveId(id) { - if (id === "vitest") return resolve(distDir, "index.js"); - if (id.startsWith("@vitest/") || id.startsWith("vitest/"))`; - - const newCode = `async resolveId(id) { - if (id === "vitest") return resolve(distDir, "index.js"); - // Resolve CLI test path and test package directly to dist/index.js - // This bypasses the re-export chain and ensures module identity is preserved - if (id === "vite-plus/test" || id === "@voidzero-dev/vite-plus-test") { - return resolve(distDir, "index.js"); - } - // Handle subpaths: vite-plus/test/* -> vitest/* - if (id.startsWith("vite-plus/test/")) { - const subpath = id.slice("vite-plus/test/".length); - return this.resolve("vitest/" + subpath, join(ctx.config.root, "index.html"), { skipSelf: true }); - } - // Handle subpaths: @voidzero-dev/vite-plus-test/* -> vitest/* - if (id.startsWith("@voidzero-dev/vite-plus-test/")) { - const subpath = id.slice("@voidzero-dev/vite-plus-test/".length); - return this.resolve("vitest/" + subpath, join(ctx.config.root, "index.html"), { skipSelf: true }); - } - if (id.startsWith("@vitest/") || id.startsWith("vitest/"))`; - - if (!content.includes(oldPattern)) { - throw new Error( - 'Could not find VitestCoreResolver pattern to patch in ' + - cliApiChunk + - '. ' + - 'This likely means vitest code has changed and the patch needs to be updated.', - ); - } - - content = content.replace(oldPattern, newCode); - await writeFile(cliApiChunk, content); - console.log(' Patched VitestCoreResolver to resolve vite-plus/test directly'); -} - -/** - * Convert leading tabs to spaces in all JS files in dist/ for consistent - * formatting. This allows our patching code to use space-based patterns - * instead of tabs. - * - * Only leading whitespace is rewritten — tabs inside string or template - * literals are semantically meaningful (e.g. `indent.includes("\t")` in - * @vitest/snapshot picks the snapshot indent style by checking for a - * literal tab byte) and must be preserved. - * - * See: https://github.com/voidzero-dev/vite-plus/issues/1553 - */ -async function convertTabsToSpaces() { - console.log('\nConverting leading tabs to spaces in dist/...'); - - let convertedCount = 0; - - for await (const file of fsGlob(resolve(distDir, '**/*.js'))) { - const content = await readFile(file, 'utf-8'); - const converted = content.replace(/^\t+/gm, (match) => ' '.repeat(match.length)); - if (converted !== content) { - await writeFile(file, converted); - convertedCount++; - } - } - - console.log(` Converted ${convertedCount} files`); -} - -/** - * Fix pkgRoot path resolution in all `@vitest/*` packages. - * The original packages use resolve(import.meta.url, "../..") to find their package root. - * But our files are at `dist/@vitest/star/index.js`, so we need to go up 3 levels, not 2. - */ -async function patchVitestPkgRootPaths() { - console.log('\nFixing distRoot paths in @vitest/* packages...'); - - const vitestDir = resolve(distDir, '@vitest'); - let patchedCount = 0; - - for (const pkg of VITEST_PACKAGES_TO_COPY) { - const pkgName = pkg.replace('@vitest/', ''); - const indexPath = join(vitestDir, pkgName, 'index.js'); - - try { - await stat(indexPath); - } catch { - continue; - } - - let content = await readFile(indexPath, 'utf-8'); - - // The original @vitest/browser had index.js in the dist/ folder, so: - // pkgRoot = resolve(import.meta.url, "../..") -> @vitest/browser - // distRoot = resolve(pkgRoot, "dist") -> @vitest/browser/dist - // But our file is at dist/@vitest/browser/index.js, so distRoot should just be - // the directory containing index.js (not pkgRoot/dist) - // Replace both lines with just making distRoot = dirname of index.js - // Use regex to handle both top-level and indented occurrences - const oldPattern = - /( *)const pkgRoot = resolve\(fileURLToPath\(import\.meta\.url\), "\.\.\/\.\."\);\n\1const distRoot = resolve\(pkgRoot, "dist"\);/g; - const newContent = content.replace( - oldPattern, - '$1const distRoot = dirname(fileURLToPath(import.meta.url));', - ); - - if (newContent !== content) { - await writeFile(indexPath, newContent, 'utf-8'); - const matchCount = (content.match(oldPattern) || []).length; - console.log(` Fixed ${pkg}/index.js (${matchCount} occurrences)`); - patchedCount++; - } - } - - console.log(` Patched ${patchedCount} packages`); -} - -/** - * Patch the copied @vitest/browser package to: - * 1. Inject vitest:vendor-aliases plugin for @vitest/* resolution - * 2. Add native deps to the exclude list - * 3. Remove include patterns for bundled deps - */ -async function patchVitestBrowserPackage() { - console.log('\nPatching @vitest/browser package...'); - - const browserIndexPath = join(distDir, '@vitest/browser/index.js'); - - try { - await stat(browserIndexPath); - } catch { - console.log(' Warning: @vitest/browser not found in dist, skipping'); - return; - } - - let content = await readFile(browserIndexPath, 'utf-8'); - - // 1. Inject vitest:vendor-aliases plugin into BrowserPlugin return array - // This allows imports like @vitest/runner to be resolved to our copied @vitest files - // Exclude @vitest/browser/context from vendor-aliases so that BrowserContext - // plugin's resolveId can intercept the bare specifier and return the virtual - // module (which includes the dynamically generated `server` export). - // Without this, vendor-aliases resolves the bare specifier to the static - // context.js file (which has no `server`), bypassing BrowserContext entirely. - // See: https://github.com/voidzero-dev/vite-plus/issues/1086 - const VENDOR_ALIASES_EXCLUDE = new Set(['@vitest/browser/context']); - - const mappingEntries = Object.entries(VITEST_PACKAGE_TO_PATH) - .filter(([pkg]) => pkg.startsWith('@vitest/') && !VENDOR_ALIASES_EXCLUDE.has(pkg)) - .map(([pkg, file]) => `'${pkg}': resolve(packageRoot, '${file}')`) - .join(',\n '); - - // distRoot is @vitest/browser/ so we need to go up two levels to reach the actual dist root - const vendorAliasesPlugin = `{ - name: 'vitest:vendor-aliases', - enforce: 'pre', - resolveId(id) { - // distRoot is @vitest/browser/, packageRoot is the actual dist/ directory - const packageRoot = resolve(distRoot, '../..'); - // Resolve module-runner to a browser-safe stub - // This is critical: module-runner contains Node.js-only code (process.platform, etc.) - // that causes browsers to hang when loaded - if (id === '${CORE_PACKAGE_NAME}/module-runner' || id === 'vite/module-runner') { - return resolve(packageRoot, 'module-runner-stub.js'); - } - // Mark vite/core as external to prevent Node.js-only code from being bundled - // This prevents __vite__injectQuery duplication errors in browser tests - if (id === '${CORE_PACKAGE_NAME}' || id === 'vite') { - return { id, external: true }; - } - // Handle vitest/browser and package aliases - // Return virtual module ID so BrowserContext plugin can load it - // Supports: vitest/browser, @voidzero-dev/vite-plus-test/browser, vite-plus/test/browser - if (id === 'vitest/browser' || id === '@voidzero-dev/vite-plus-test/browser' || id === 'vite-plus/test/browser') { - return '\\0vitest/browser'; - } - // Handle vitest/* subpaths (resolve to our dist files) - // Also handle @voidzero-dev package aliases that resolve to the same files - const vitestSubpathMap = { - 'vitest': resolve(packageRoot, 'index.js'), - '@voidzero-dev/vite-plus-test': resolve(packageRoot, 'index.js'), - 'vite-plus/test': resolve(packageRoot, 'index.js'), - 'vitest/node': resolve(packageRoot, 'node.js'), - 'vitest/config': resolve(packageRoot, 'config.js'), - 'vitest/internal/browser': resolve(packageRoot, 'browser.js'), - 'vitest/runners': resolve(packageRoot, 'runners.js'), - 'vitest/suite': resolve(packageRoot, 'suite.js'), - 'vitest/environments': resolve(packageRoot, 'environments.js'), - 'vitest/coverage': resolve(packageRoot, 'coverage.js'), - 'vitest/reporters': resolve(packageRoot, 'reporters.js'), - 'vitest/snapshot': resolve(packageRoot, 'snapshot.js'), - 'vitest/mocker': resolve(packageRoot, 'mocker.js'), - // Browser providers - resolve to our bundled @vitest/browser-* packages - 'vitest/browser-playwright': resolve(packageRoot, '@vitest/browser-playwright/index.js'), - 'vitest/browser-webdriverio': resolve(packageRoot, '@vitest/browser-webdriverio/index.js'), - 'vitest/browser-preview': resolve(packageRoot, '@vitest/browser-preview/index.js'), - }; - if (vitestSubpathMap[id]) { - return vitestSubpathMap[id]; - } - // Handle @voidzero-dev/vite-plus-test/* subpaths (same as vitest/*) - if (id.startsWith('@voidzero-dev/vite-plus-test/')) { - const subpath = id.slice('@voidzero-dev/vite-plus-test/'.length); - const vitestEquiv = 'vitest/' + subpath; - if (vitestSubpathMap[vitestEquiv]) { - return vitestSubpathMap[vitestEquiv]; - } - } - // Handle vite-plus/test/* subpaths (CLI package paths, same as vitest/*) - if (id.startsWith('vite-plus/test/')) { - const subpath = id.slice('vite-plus/test/'.length); - const vitestEquiv = 'vitest/' + subpath; - if (vitestSubpathMap[vitestEquiv]) { - return vitestSubpathMap[vitestEquiv]; - } - } - // Handle @vitest/* packages (resolve to our copied files) - const vendorMap = { - ${mappingEntries} - }; - if (vendorMap[id]) { - return vendorMap[id]; - } - } - }`; - - // Find BrowserPlugin return array and inject plugin - const pluginArrayPattern = /(return \[)(\n +\{\n +enforce: "pre",\n +name: "vitest:browser",)/; - if (pluginArrayPattern.test(content)) { - content = content.replace(pluginArrayPattern, `$1\n ${vendorAliasesPlugin},$2`); - console.log(' Injected vitest:vendor-aliases plugin'); - } else { - throw new Error( - 'Failed to inject vendor-aliases plugin in @vitest/browser/index.js: pattern not found. ' + - 'This likely means vitest code has changed and the patch needs to be updated.', - ); - } - - // 2. Patch exclude list to add native deps - // Pattern: const exclude = ["vitest", ... - const excludePattern = /(const exclude = \[)(\n?\s*"vitest",)/; - // Exclude packages that: - // Packages to exclude from Vite's dependency pre-bundling (optimizeDeps.exclude) - const packagesToExclude = [ - // @vitest packages that need our resolveId plugin - '@vitest/browser', - '@vitest/ui', - '@vitest/ui/reporter', - '@vitest/mocker/node', // imports @voidzero-dev/vite-plus-core - - // Our package aliases - preserve module identity with init scripts - // This ensures both init scripts (loaded via /@fs/) and tests use the same page singleton - '@voidzero-dev/vite-plus-test', - '@voidzero-dev/vite-plus-test/browser', - '@voidzero-dev/vite-plus-test/browser/context', - 'vite-plus/test', - 'vite-plus/test/browser', - 'vite-plus/test/browser/context', - - // Node.js only packages - 'vite', - '@voidzero-dev/vite-plus-core', - '@voidzero-dev/vite-plus-core/module-runner', - - // Native bindings - 'lightningcss', - '@tailwindcss/oxide', - 'tailwindcss', // pulls in @tailwindcss/oxide - ]; - - const excludeListStr = packagesToExclude.map((pkg) => `"${pkg}"`).join(',\n '); - const excludeReplacement = `$1\n ${excludeListStr},$2`; - if (excludePattern.test(content)) { - content = content.replace(excludePattern, excludeReplacement); - console.log(' Patched exclude list with native deps'); - } else { - throw new Error( - 'Failed to patch exclude list in @vitest/browser/index.js: pattern not found. ' + - 'This likely means vitest code has changed and the patch needs to be updated.', - ); - } - - // 3. Remove include patterns that reference bundled deps - // These patterns like "vitest > expect-type" don't work with our bundled setup - // since the deps are already bundled into vendor files - const includePatterns = [ - '"vitest > expect-type"', - '"vitest > @vitest/snapshot > magic-string"', - '"vitest > @vitest/expect > chai"', - ]; - for (const pattern of includePatterns) { - content = content.replace( - new RegExp(`\\s*${pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')},?`, 'g'), - '', - ); - } - console.log(' Removed bundled deps from include list'); - - // 4. Patch BrowserContext to also handle our package aliases as fallback - // This allows direct imports from our package without requiring vitest override - // Supports: vitest/browser, @voidzero-dev/vite-plus-test/browser, vite-plus/test/browser - const browserContextPattern = /if \(id === ID_CONTEXT\) \{/; - if (browserContextPattern.test(content)) { - content = content.replace( - browserContextPattern, - `if (id === ID_CONTEXT || id === "@voidzero-dev/vite-plus-test/browser" || id === "vite-plus/test/browser") {`, - ); - console.log(' Patched BrowserContext to handle package aliases'); - } else { - throw new Error( - 'Failed to patch BrowserContext in @vitest/browser/index.js: pattern not found. ' + - 'This likely means vitest code has changed and the patch needs to be updated.', - ); - } - - // 5. Patch version to use VP_VERSION, preventing the "Running mixed versions" warning - const versionPattern = /var version = "(\d+\.\d+\.\d+[^"]*)"/; - const beforeVersion = content; - content = content.replace(versionPattern, 'var version = process.env.VP_VERSION || "$1"'); - if (content === beforeVersion) { - throw new Error( - 'Failed to patch version in @vitest/browser/index.js: pattern not found. ' + - 'This likely means vitest code has changed and the patch needs to be updated.', - ); - } - console.log(' Patched version to use VP_VERSION env var'); - - await writeFile(browserIndexPath, content, 'utf-8'); - console.log(' Successfully patched @vitest/browser/index.js'); -} - -/** - * Patch browser provider locators.js files to use browser-safe imports. - * - * The original files import from '../browser/index.js' which includes Node.js server code. - * We need to change them to import from browser-safe files instead. - * - * Providers handled: - * - @vitest/browser-playwright: import { page, server } from '../browser/index.js'; - * - @vitest/browser-webdriverio: import { page, server, utils } from '../browser/index.js'; - * - @vitest/browser-preview: import { page, server, utils, userEvent } from '../browser/index.js'; - */ -async function patchBrowserProviderLocators() { - console.log('\nPatching browser provider locators.js files...'); - - const providers = [ - { name: 'browser-playwright', extraImports: [] as string[] }, - { name: 'browser-webdriverio', extraImports: ['utils'] }, - { name: 'browser-preview', extraImports: ['utils', 'userEvent'] }, - ]; - - for (const provider of providers) { - const locatorsPath = join(distDir, `@vitest/${provider.name}/locators.js`); - - try { - await stat(locatorsPath); - } catch { - console.log(` Warning: @vitest/${provider.name}/locators.js not found, skipping`); - continue; - } - - let content = await readFile(locatorsPath, 'utf-8'); - let patched = false; - - // 1. Patch the vitest/browser import to separate page (from context.js) and other imports - // After rewriteVitestImports(), the import is: import { page, server, ... } from '../browser/index.js'; - // We need: - // - page from '../browser/context.js' (browser-safe) - // - server removed (we'll use window.__vitest_worker__.config instead) - // - other imports (utils, userEvent) still from '../browser/index.js' - - if (provider.extraImports.length === 0) { - // playwright: just import page from context.js - const serverImportPattern = - /import \{ page, server \} from ['"]\.\.\/browser\/index\.js['"];?/; - if (serverImportPattern.test(content)) { - content = content.replace( - serverImportPattern, - `import { page } from '../browser/context.js';`, - ); - console.log(` [${provider.name}] Changed server import to browser-safe context import`); - patched = true; - } - } else { - // webdriverio/preview: import page from context.js, keep other imports from index.js - const extraImportsStr = provider.extraImports.join(', '); - const importPattern = new RegExp( - `import \\{ page, server, ${extraImportsStr} \\} from ['"]\\.\\./browser/index\\.js['"];?`, - ); - if (importPattern.test(content)) { - const replacement = `import { page } from '../browser/context.js';\nimport { ${extraImportsStr} } from '../browser/index.js';`; - content = content.replace(importPattern, replacement); - console.log( - ` [${provider.name}] Split imports: page from context.js, {${extraImportsStr}} from index.js`, - ); - patched = true; - } - } - - if (!patched) { - console.log(` Warning: [${provider.name}] Could not find server import to patch`); - } - - // 2. Replace all server.config references with browser-accessible window.__vitest_worker__.config - // This handles both: - // - server.config.browser.locators.testIdAttribute - // - server.config.browser.ui - const serverConfigPattern = /server\.config\./g; - const matchCount = (content.match(serverConfigPattern) || []).length; - if (matchCount > 0) { - content = content.replace(serverConfigPattern, `window.__vitest_worker__.config.`); - console.log( - ` [${provider.name}] Replaced ${matchCount} server.config references with window.__vitest_worker__.config`, - ); - } - - await writeFile(locatorsPath, content, 'utf-8'); - console.log(` Successfully patched @vitest/${provider.name}/locators.js`); - } -} - -/** - * Create browser-compat.js shim that re-exports @vitest/browser compatible symbols. - * This allows our package to be used as an override for @vitest/browser. - */ -async function createBrowserCompatShim() { - console.log('\nCreating browser-compat shim...'); - - const browserIndexPath = join(distDir, '@vitest/browser/index.js'); - - try { - await stat(browserIndexPath); - } catch { - console.log(' Warning: @vitest/browser/index.js not found, skipping'); - return; - } - - const browserSymbols = [ - 'resolveScreenshotPath', - 'defineBrowserProvider', - 'parseKeyDef', - 'defineBrowserCommand', - ]; - - const shimContent = `// Re-export @vitest/browser compatible symbols -// This allows this package to be used as an override for @vitest/browser -export { ${browserSymbols.join(', ')} } from './@vitest/browser/index.js'; -`; - - const shimPath = join(distDir, 'browser-compat.js'); - await writeFile(shimPath, shimContent, 'utf-8'); - console.log(` Created ${relative(projectDir, shimPath)}`); -} - -/** - * Create a browser-safe stub for module-runner. - * The real module-runner contains Node.js-only code (process.platform, Buffer, etc.) - * that causes browsers to hang when loaded. This stub provides empty/placeholder - * exports so that browser code can import without errors. - */ -async function createModuleRunnerStub() { - console.log('\nCreating browser-safe module-runner stub...'); - - const stubContent = `// Browser-safe stub for module-runner -// The real module-runner contains Node.js-only code that crashes browsers -// This stub provides placeholder exports for browser compatibility - -// Stub class - browser doesn't actually use these -export class EvaluatedModules { - constructor() { - this.idToModuleMap = new Map(); - this.fileToModulesMap = new Map(); - this.urlToIdModuleMap = new Map(); - } - getModuleById() { return undefined; } - getModulesByFile() { return []; } - getModuleByUrl() { return undefined; } - ensureModule() { return {}; } - invalidateModule() {} - clear() {} -} - -export class ModuleRunner { - constructor() {} - async import() { throw new Error('ModuleRunner is not available in browser'); } - evaluatedModules = new EvaluatedModules(); -} - -export class ESModulesEvaluator { - constructor() {} - async runExternalModule() { return {}; } - async runViteModule() { return {}; } -} - -// Stub functions -export function createDefaultImportMeta() { return {}; } -export function createNodeImportMeta() { return {}; } -export function createWebSocketModuleRunnerTransport() { return {}; } -export function normalizeModuleId(id) { return id; } - -// SSR-related constants (browser doesn't use these) -export const ssrDynamicImportKey = '__vite_ssr_dynamic_import__'; -export const ssrExportAllKey = '__vite_ssr_exportAll__'; -export const ssrExportNameKey = '__vite_ssr_export__'; -export const ssrImportKey = '__vite_ssr_import__'; -export const ssrImportMetaKey = '__vite_ssr_import_meta__'; -export const ssrModuleExportsKey = '__vite_ssr_exports__'; -`; - - const stubPath = join(distDir, 'module-runner-stub.js'); - await writeFile(stubPath, stubContent, 'utf-8'); - console.log(` Created ${relative(projectDir, stubPath)}`); -} - -/** - * Create a Node.js-specific entry that includes @vitest/browser symbols. - * Browser code will use index.js (no browser-provider imports) to avoid loading Node.js code. - * Node.js code (like @vitest/browser-playwright) will use index-node.js which includes - * the browser symbols needed for pnpm override compatibility. - * - * This separation is critical because @vitest/browser/index.js imports from vitest/node, - * which contains Node.js-only code (including __vite__injectQuery) that crashes browsers. - */ -async function createNodeEntry() { - console.log('\nCreating Node.js-specific entry for @vitest/browser override...'); - - const browserIndexPath = join(distDir, '@vitest/browser/index.js'); - - try { - await stat(browserIndexPath); - } catch { - console.log(' Warning: @vitest/browser/index.js not found, skipping'); - return; - } - - const browserSymbols = [ - 'resolveScreenshotPath', - 'defineBrowserProvider', - 'parseKeyDef', - 'defineBrowserCommand', - ]; - - // Create index-node.js that re-exports everything from index.js plus browser symbols - const nodeEntry = `// Node.js-specific entry that includes @vitest/browser provider symbols -// Browser code should use index.js which doesn't pull in Node.js-only code -export * from './index.js'; - -// Re-export @vitest/browser symbols for pnpm override compatibility -// These are only needed when this package overrides @vitest/browser in Node.js context -export { ${browserSymbols.join(', ')} } from './@vitest/browser/index.js'; -`; - - const nodeEntryPath = join(distDir, 'index-node.js'); - await writeFile(nodeEntryPath, nodeEntry, 'utf-8'); - console.log(` Created dist/index-node.js with @vitest/browser exports`); -} - -/** - * Copy ALL files from @vitest/browser's dist to our dist. - * The bundled code in dist/vendor/ calculates paths like: - * pkgRoot = resolve(import.meta.url, "../..") -> package root - * distRoot = resolve(pkgRoot, "dist") -> dist/ - * Then looks for client/ files at distRoot, so we copy to dist/ not dist/vendor/. - */ -async function copyBrowserClientFiles() { - console.log('\nCopying @vitest/browser files to dist...'); - - // Find @vitest/browser's dist directory - const vitestBrowserDist = resolve(projectDir, 'node_modules/@vitest/browser/dist'); - - // Check if it exists - try { - await stat(vitestBrowserDist); - } catch { - console.log(' Warning: @vitest/browser not installed, skipping'); - return; - } - - // Copy all files from @vitest/browser/dist to our dist/ - // The bundled code at dist/vendor/ resolves paths relative to dist/ - // Use recursive directory traversal to include dotfiles (glob doesn't handle them well) - let copiedCount = 0; - - // Rewrite imports in copied JS files to use our dist files - // The relative path depends on the file's location relative to dist/ - function rewriteImports(content: string, destPath: string): string { - const fileDir = parse(destPath).dir; - - // Calculate relative path from file location to vendor directory - const vendorPath = join(distDir, 'vendor'); - let relativeToVendor = relative(fileDir, vendorPath); - // Ensure path starts with ./ for relative imports - if (!relativeToVendor.startsWith('.')) { - relativeToVendor = './' + relativeToVendor; - } - - // Calculate relative path from file location to dist directory - let relativeToDist = relative(fileDir, distDir); - if (!relativeToDist.startsWith('.')) { - relativeToDist = './' + relativeToDist; - } - - // Rewrite @vitest/* imports to use our copied @vitest files - for (const [pkg, distPath] of Object.entries(VITEST_PACKAGE_TO_PATH)) { - if (!pkg.startsWith('@vitest/')) { - continue; - } - // Pattern: from"@vitest/runner" or from "@vitest/runner" - const importPattern = new RegExp(`from\\s*["']${pkg.replace('/', '\\/')}["']`, 'g'); - content = content.replace(importPattern, `from"${relativeToDist}/${distPath}"`); - } - - // Rewrite vitest/* subpath imports to use our dist files - // These are the actual entry points for vitest's browser-safe exports - const vitestSubpathRewrites: Record = { - 'vitest/browser': `${relativeToDist}/context.js`, // vitest/browser exports context API - 'vitest/internal/browser': `${relativeToDist}/browser.js`, - 'vitest/runners': `${relativeToDist}/runners.js`, - }; - for (const [specifier, destFile] of Object.entries(vitestSubpathRewrites)) { - const importPattern = new RegExp(`from\\s*["']${specifier.replace('/', '\\/')}["']`, 'g'); - content = content.replace(importPattern, `from"${destFile}"`); - } - - // Special handling for @vitest/browser/client -> our client.js - // This is needed because the browser client files import from @vitest/browser/client - const browserClientPattern = /from\s*["']@vitest\/browser\/client["']/g; - content = content.replace(browserClientPattern, `from"${relativeToDist}/client.js"`); - - // Handle imports from ./index.js which is Node.js-only code - // In browser context, 'server' should read from __vitest_browser_runner__ at runtime - // Replace: import{server}from'./index.js' with a browser-safe stub - const serverStub = `const server = { - get browser() { return window.__vitest_browser_runner__?.config?.browser?.name; }, - get config() { return window.__vitest_browser_runner__?.config || {}; }, - get commands() { return window.__vitest_browser_runner__?.commands || {}; }, - get provider() { return window.__vitest_browser_runner__?.provider; }, -};`; - content = content.replace( - /import\s*\{\s*server\s*\}\s*from\s*['"]\.\/index\.js['"];?/g, - serverStub, - ); - - // Remove side-effect imports from ./index.js (Node.js-only) - // Pattern: import'./index.js'; at the end of an import statement - content = content.replace(/import\s*['"]\.\/index\.js['"];?/g, ''); - - return content; - } - - async function copyDirRecursive(srcDir: string, destDir: string) { - const entries = await readdir(srcDir, { withFileTypes: true }); - - for (const entry of entries) { - const srcPath = join(srcDir, entry.name); - const destPath = join(destDir, entry.name); - - if (entry.isDirectory()) { - await mkdir(destPath, { recursive: true }); - await copyDirRecursive(srcPath, destPath); - } else if (entry.isFile()) { - // Skip if file already exists (our bundled code takes precedence) - try { - await stat(destPath); - continue; - } catch { - // File doesn't exist, copy it - } - await mkdir(parse(destPath).dir, { recursive: true }); - - // For JS files, rewrite imports; otherwise just copy - if (entry.name.endsWith('.js')) { - let content = await readFile(srcPath, 'utf-8'); - content = rewriteImports(content, destPath); - await writeFile(destPath, content, 'utf-8'); - } else { - await copyFile(srcPath, destPath); - } - copiedCount++; - } - } - } - - await copyDirRecursive(vitestBrowserDist, distDir); - - // Create dummy.js for placeholder exports (matchers, utils) - const dummyContent = '// Placeholder for browser compatibility\nexport {};\n'; - await writeFile(join(distDir, 'dummy.js'), dummyContent, 'utf-8'); - - console.log(` Copied ${copiedCount} files from @vitest/browser to dist`); - - // Create vendor stubs for browser packages that aren't bundled - // Other dist files reference these vendor paths but we don't bundle browser packages - // to avoid Node.js code leakage. Instead, we create stubs that re-export from actual dist files. - console.log(' Creating vendor stubs for browser packages...'); - const browserVendorStubs = [ - { - vendorFile: 'vitest_browser.mjs', - // vitest/browser exports the context API (page, server, userEvent) - content: `// Stub for browser context - re-exports from our context.js -export * from '../context.js'; -`, - }, - { - vendorFile: 'vitest_internal_browser.mjs', - // vitest/internal/browser is browser.js - content: `// Stub for internal browser API - re-exports from our browser.js -export * from '../browser.js'; -`, - }, - { - vendorFile: 'vitest_runners.mjs', - // vitest/runners - content: `// Stub for runners - re-exports from our runners.js -export * from '../runners.js'; -`, - }, - { - vendorFile: 'vitest_runner.mjs', - // @vitest/runner (note: singular, not plural like vitest_runners which is vitest/runners) - content: `// Stub for @vitest/runner - re-exports from our copied @vitest/runner -export * from '../@vitest/runner/index.js'; -`, - }, - ]; - - for (const { vendorFile, content } of browserVendorStubs) { - const stubPath = join(distDir, 'vendor', vendorFile); - await writeFile(stubPath, content, 'utf-8'); - } - console.log(` Created ${browserVendorStubs.length} vendor stubs`); -} - -/** - * Create browser/ directory at package root with context files. - * The package exports "./browser" pointing to these files: - * - browser/context.js: Runtime guard (throws if used outside browser mode) - * - browser/context.d.ts: Re-exports types from dist/@vitest/browser/context.d.ts - * - * These files are NOT tracked in git (.gitignore excludes browser/) - * but ARE included in the package (package.json files: ["browser/**"]) - */ -async function createBrowserEntryFiles() { - console.log('\nCreating browser/ entry files...'); - - const browserDir = resolve(projectDir, 'browser'); - await mkdir(browserDir, { recursive: true }); - - // 1. Copy context.js from @vitest/browser (runtime guard) - const srcContextJs = resolve(projectDir, 'node_modules/@vitest/browser/context.js'); - const destContextJs = join(browserDir, 'context.js'); - await copyFile(srcContextJs, destContextJs); - console.log(' Created browser/context.js'); - - // 2. Create context.d.ts that re-exports from our bundled types - const contextDtsContent = `// Re-export browser context types from bundled @vitest/browser package -// This provides: page, userEvent, server, commands, utils, locators, cdp, Locator, etc. -// The bundled context.d.ts has imports rewritten to point to our dist files -export * from '../dist/@vitest/browser/context.d.ts' -`; - const destContextDts = join(browserDir, 'context.d.ts'); - await writeFile(destContextDts, contextDtsContent, 'utf-8'); - console.log(' Created browser/context.d.ts'); -} - -/** - * Patch module augmentations in global.d.*.d.ts files. - * - * The original vitest types use module augmentation like: - * declare module "@vitest/expect" { interface Assertion { toMatchSnapshot: ... } } - * - * Since we bundle @vitest/* packages inside dist/@vitest/*, the bare specifier - * "@vitest/expect" doesn't exist as a package for consumers. This breaks the - * module augmentation - TypeScript can't find @vitest/expect to augment. - * - * The fix has two parts: - * 1. Change module augmentation to use relative paths that TypeScript CAN resolve: - * declare module "../@vitest/expect/index.js" { ... } - * 2. Merge augmented interface/type definitions into the target .d.ts files so that - * downstream DTS bundlers (rolldown) can resolve them without cross-file augmentation. - */ -async function patchModuleAugmentations() { - console.log('\nPatching module augmentations in global.d.*.d.ts files...'); - - const chunksDir = join(distDir, 'chunks'); - const globalDtsFiles: string[] = []; - - // Find all global.d.*.d.ts files - for await (const file of fsGlob(join(chunksDir, 'global.d.*.d.ts'))) { - globalDtsFiles.push(file); - } - - if (globalDtsFiles.length === 0) { - console.log(' No global.d.*.d.ts files found'); - return; - } - - // Module augmentation mappings: bare specifier -> [relative path, target .d.ts file] - const augmentationMappings: Record = { - '@vitest/expect': { - relativePath: '../@vitest/expect/index.js', - targetFile: join(distDir, '@vitest/expect/index.d.ts'), - }, - '@vitest/runner': { - relativePath: '../@vitest/runner/index.js', - targetFile: join(distDir, '@vitest/runner/utils.d.ts'), - }, - }; - - for (const file of globalDtsFiles) { - let content = await readFile(file, 'utf-8'); - let modified = false; - - for (const [bareSpecifier, { relativePath, targetFile }] of Object.entries( - augmentationMappings, - )) { - const oldPattern = `declare module "${bareSpecifier}"`; - - // Extract the augmentation block content using brace matching - const startIdx = content.indexOf(oldPattern); - const braceStart = startIdx !== -1 ? content.indexOf('{', startIdx) : -1; - if (braceStart === -1) { - continue; - } - - let depth = 0; - let braceEnd = -1; - for (let i = braceStart; i < content.length; i++) { - if (content[i] === '{') { - depth++; - } else if (content[i] === '}') { - depth--; - if (depth === 0) { - braceEnd = i; - break; - } - } - } - if (braceEnd === -1) { - continue; - } - - const innerContent = content.slice(braceStart + 1, braceEnd).trim(); - - // Merge only NEW type declarations into the target .d.ts file. - // Interfaces that already exist (e.g., ExpectStatic, Assertion, MatcherState) must NOT - // be re-declared, as that would shadow extends clauses and break call signatures. - if (innerContent && existsSync(targetFile)) { - let targetContent = await readFile(targetFile, 'utf-8'); - - // Extract individual interface blocks from the augmentation content - const interfaceRegex = /(?:export\s+)?interface\s+(\w+)(?:<[^>]*>)?\s*\{/g; - let match; - const newDeclarations: string[] = []; - - while ((match = interfaceRegex.exec(innerContent)) !== null) { - const name = match[1]; - // Only merge if this interface does NOT already exist in the target file. - // Check both direct declarations (interface Name) and re-exports (export type { Name }). - const hasDirectDecl = new RegExp(`\\binterface\\s+${name}\\b`).test(targetContent); - const exportTypeMatch = targetContent.match(/export\s+type\s*\{([^}]*)\}/); - const isReExported = - exportTypeMatch != null && new RegExp(`\\b${name}\\b`).test(exportTypeMatch[1]); - if (hasDirectDecl || isReExported) { - console.log( - ` Skipped existing interface "${name}" (already in ${basename(targetFile)})`, - ); - continue; - } - - // Extract this interface block using brace matching - const ifaceStart = match.index; - const ifaceBraceStart = innerContent.indexOf('{', ifaceStart); - let ifaceDepth = 0; - let ifaceBraceEnd = -1; - for (let i = ifaceBraceStart; i < innerContent.length; i++) { - if (innerContent[i] === '{') { - ifaceDepth++; - } else if (innerContent[i] === '}') { - ifaceDepth--; - if (ifaceDepth === 0) { - ifaceBraceEnd = i; - break; - } - } - } - if (ifaceBraceEnd === -1) { - continue; - } - - let block = innerContent.slice(ifaceStart, ifaceBraceEnd + 1).trim(); - if (!block.startsWith('export')) { - block = `export ${block}`; - } - newDeclarations.push(block); - console.log(` Merged new interface "${name}" into ${basename(targetFile)}`); - } - - if (newDeclarations.length > 0) { - targetContent += `\n// Merged from module augmentation: declare module "${bareSpecifier}"\n${newDeclarations.join('\n')}\n`; - await writeFile(targetFile, targetContent, 'utf-8'); - } - } - - // Rewrite declare module path to relative - const newPattern = `declare module "${relativePath}"`; - content = content.replaceAll(oldPattern, newPattern); - modified = true; - console.log(` Patched: ${bareSpecifier} -> ${relativePath} in ${basename(file)}`); - } - - if (modified) { - await writeFile(file, content, 'utf-8'); - } - } - - // Re-export BrowserCommands from context.d.ts (imported but not exported) - const contextDtsPath = join(distDir, '@vitest/browser/context.d.ts'); - if (existsSync(contextDtsPath)) { - let content = await readFile(contextDtsPath, 'utf-8'); - if ( - content.includes('BrowserCommands') && - !content.match(/export\s+(type\s+)?\{[^}]*BrowserCommands/) - ) { - content += '\nexport type { BrowserCommands };\n'; - await writeFile(contextDtsPath, content, 'utf-8'); - console.log(' Added BrowserCommands re-export to context.d.ts'); - } - } - - // Validate: ensure no duplicate top-level interface declarations were introduced by merging. - // Only count interfaces at the module scope (not nested inside declare global, namespace, etc.) - for (const [bareSpecifier, { targetFile }] of Object.entries(augmentationMappings)) { - if (!existsSync(targetFile)) { - continue; - } - const finalContent = await readFile(targetFile, 'utf-8'); - - // Extract top-level interface names by tracking brace depth - const topLevelInterfaces: string[] = []; - let depth = 0; - for (let i = 0; i < finalContent.length; i++) { - if (finalContent[i] === '{') { - depth++; - } else if (finalContent[i] === '}') { - depth--; - } else if (depth === 0) { - const remaining = finalContent.slice(i); - const m = remaining.match(/^interface\s+(\w+)/); - if (m) { - topLevelInterfaces.push(m[1]); - i += m[0].length - 1; - } - } - } - - const counts = new Map(); - for (const name of topLevelInterfaces) { - counts.set(name, (counts.get(name) || 0) + 1); - } - - for (const [name, count] of counts) { - if (count > 1) { - throw new Error( - `Interface "${name}" is declared ${count} times at top level in ${basename(targetFile)}. ` + - `Module augmentation merge for "${bareSpecifier}" likely created a duplicate ` + - `declaration that will shadow extends clauses and break type signatures.`, - ); - } - } - } -} - -/** - * Add triple-slash reference to @types/chai in @vitest/expect types. - * - * The @vitest/expect types use the Chai namespace (e.g., Chai.Assertion) which - * is defined in @types/chai. Without a reference directive, TypeScript won't - * automatically find the Chai types, causing the `not` property and other - * chai-specific features to be missing from the Assertion interface. - */ -async function patchChaiTypeReference() { - console.log('\nAdding @types/chai reference to @vitest/expect types...'); - - const expectIndexDts = join(distDir, '@vitest/expect/index.d.ts'); - - let content = await readFile(expectIndexDts, 'utf-8'); - - // Check if reference already exists - if (content.includes('/// \n${content}`; - - await writeFile(expectIndexDts, content, 'utf-8'); - console.log(' Added /// to @vitest/expect/index.d.ts'); -} - -/** - * Patch the vitest mocker to recognize @voidzero-dev packages as valid sources for vi/vitest. - * - * The mocker's hoistMocks function checks if `vi` is imported from the 'vitest' module. - * When users import from 'vite-plus/test' instead, the mocker doesn't - * recognize it and throws "There are some problems in resolving the mocks API". - * - * This patch modifies the equality check to also accept our package names: - * - vite-plus/test - * - @voidzero-dev/vite-plus-test - */ -async function patchMockerHoistedModule() { - console.log('\nPatching vitest mocker to recognize @voidzero-dev packages...'); - - // The hoistedModule check may be in node.js or chunk-hoistMocks.js depending on the vitest version - const candidateFiles = [ - join(distDir, '@vitest/mocker/node.js'), - join(distDir, '@vitest/mocker/chunk-hoistMocks.js'), - ]; - - // Find and replace the hoistedModule check - // Original: if (hoistedModule === source) { - // New: if (hoistedModule === source || source === "vite-plus/test" || source === "@voidzero-dev/vite-plus-test") { - const originalCheck = 'if (hoistedModule === source) {'; - const newCheck = - 'if (hoistedModule === source || source === "vite-plus/test" || source === "@voidzero-dev/vite-plus-test") {'; - - let patched = false; - for (const candidatePath of candidateFiles) { - let content: string; - try { - content = await readFile(candidatePath, 'utf-8'); - } catch { - continue; - } - if (content.includes(originalCheck)) { - content = content.replace(originalCheck, newCheck); - await writeFile(candidatePath, content, 'utf-8'); - console.log(` Patched hoistMocks to recognize @voidzero-dev packages in ${candidatePath}`); - patched = true; - break; - } - } - - if (!patched) { - throw new Error( - 'Could not find hoistedModule check to patch in @vitest/mocker. ' + - 'This likely means vitest code has changed and the patch needs to be updated.', - ); - } -} - -/** - * Patch vitest's ModuleRunnerTransform plugin to automatically add known - * packages that use `expect.extend()` internally to `server.deps.inline`. - * - * When third-party libraries (e.g., @testing-library/jest-dom) call - * `require('vitest').expect.extend(matchers)`, the npm override causes - * a separate module instance to be created, so matchers are registered - * on a different `chai` instance than the one used by the test runner. - * - * By inlining these packages via `server.deps.inline`, the Vite module - * runner processes them through its transform pipeline, ensuring they - * share the same module instance as the test runner. - * - * See: https://github.com/voidzero-dev/vite-plus/issues/897 - */ -async function patchServerDepsInline() { - console.log('\nPatching server.deps.inline for expect.extend compatibility...'); - - let cliApiChunk: string | undefined; - for await (const chunk of fsGlob(join(distDir, 'chunks/cli-api.*.js'))) { - cliApiChunk = chunk; - break; - } - - if (!cliApiChunk) { - throw new Error('cli-api chunk not found for patchServerDepsInline'); - } - - let content = await readFile(cliApiChunk, 'utf-8'); - - // Packages that internally call expect.extend() and break under npm override. - // These must be inlined so they share the same vitest module instance. - const inlinePackages = ['@testing-library/jest-dom', '@storybook/test', 'jest-extended']; - - // Find the configResolved handler in ModuleRunnerTransform (vitest:environments-module-runner) - // and inject our inline packages after the existing server.deps.inline logic. - const original = `if (external.length) { - testConfig.server.deps.external ??= []; - testConfig.server.deps.external.push(...external); - }`; - - const patched = `if (external.length) { - testConfig.server.deps.external ??= []; - testConfig.server.deps.external.push(...external); - } - // Auto-inline packages that use expect.extend() internally (#897) - // Only inline packages that are actually installed in the project. - if (testConfig.server.deps.inline !== true) { - testConfig.server.deps.inline ??= []; - if (Array.isArray(testConfig.server.deps.inline)) { - const _require = createRequire(config.root + "/package.json"); - const autoInline = ${JSON.stringify(inlinePackages)}; - for (const pkg of autoInline) { - if (testConfig.server.deps.inline.includes(pkg)) continue; - try { - _require.resolve(pkg); - testConfig.server.deps.inline.push(pkg); - } catch { - // Package not installed in the project — skip silently - } - } - } - }`; - - if (!content.includes(original)) { - throw new Error( - 'Could not find server.deps.external pattern in ' + - cliApiChunk + - '. This likely means vitest code has changed and the patch needs to be updated.', - ); - } - - content = content.replace(original, patched); - await writeFile(cliApiChunk, content, 'utf-8'); - console.log(` Added auto-inline for: ${inlinePackages.join(', ')}`); -} - -/** - * Create /plugins/* exports for all copied @vitest/* packages. - * This allows pnpm overrides to redirect @vitest/* imports to our copied versions. - * e.g., @vitest/runner -> vitest/plugins/runner - * @vitest/utils/error -> vitest/plugins/utils-error - */ -async function createPluginExports() { - console.log('\nCreating plugin exports for @vitest/* packages...'); - - const pluginsDir = join(distDir, 'plugins'); - // Clean up stale plugin files from previous builds - await rm(pluginsDir, { recursive: true, force: true }); - await mkdir(pluginsDir, { recursive: true }); - - const createdExports: Array<{ exportPath: string; shimFile: string }> = []; - - for (const [pkg, distPath] of Object.entries(VITEST_PACKAGE_TO_PATH)) { - // Only create exports for @vitest/* packages - if (!pkg.startsWith('@vitest/')) { - continue; - } - // Convert @vitest/runner -> runner, @vitest/utils/error -> utils-error - // @vitest/utils/source-map/node -> utils-source-map-node - const exportName = pkg.replace('@vitest/', '').replaceAll('/', '-'); - const shimFileName = `${exportName}.mjs`; - const shimPath = join(pluginsDir, shimFileName); - - // Create the shim file that re-exports everything from @vitest/ - const shimContent = `// Re-export ${pkg} from copied @vitest package -export * from '../${distPath}'; -`; - - await writeFile(shimPath, shimContent, 'utf-8'); - createdExports.push({ - exportPath: `./plugins/${exportName}`, - shimFile: `./dist/plugins/${shimFileName}`, - }); - console.log(` Created plugins/${shimFileName} -> ${distPath}`); - } - - return createdExports; -} - -/** - * Validate that all external dependencies in dist are listed in package.json - */ -async function validateExternalDeps() { - console.log('\nValidating external dependencies...'); - - // Collect all declared dependencies - const declaredDeps = new Set([ - ...Object.keys(pkg.dependencies || {}), - ...Object.keys(pkg.peerDependencies || {}), - ]); - - // Also include self-references - declaredDeps.add(pkg.name); - declaredDeps.add('vitest'); // Self-reference via vitest name - - // Collect all external specifiers from ALL dist files (including vendor) - const externalSpecifiers = new Map>(); // specifier -> files - - const allJsFiles = fsGlob(join(distDir, '**/*.{js,mjs,cjs}')); - - for await (const file of allJsFiles) { - const content = await readFile(file, 'utf-8'); - const isCjs = file.endsWith('.cjs'); - - // Parse with oxc-parser - const result = parseSync(file, content, { - sourceType: isCjs ? 'script' : 'module', - }); - - const specifiers = new Set(); - - // Collect ESM static imports - for (const imp of result.module.staticImports) { - specifiers.add(imp.moduleRequest.value); - } - - // Collect ESM static exports (re-exports) - for (const exp of result.module.staticExports) { - for (const entry of exp.entries) { - if (entry.moduleRequest) { - specifiers.add(entry.moduleRequest.value); - } - } - } - - // Collect dynamic imports (only string literals) - for (const dynImp of result.module.dynamicImports) { - const rawText = content.slice(dynImp.moduleRequest.start, dynImp.moduleRequest.end); - if ( - (rawText.startsWith("'") && rawText.endsWith("'")) || - (rawText.startsWith('"') && rawText.endsWith('"')) - ) { - specifiers.add(rawText.slice(1, -1)); - } - } - - // For CJS files, also scan for require() calls - if (isCjs) { - const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g; - let match; - while ((match = requireRegex.exec(content)) !== null) { - specifiers.add(match[1]); - } - } - - // Filter and record external specifiers - for (const specifier of specifiers) { - // Skip relative paths - if (specifier.startsWith('.') || specifier.startsWith('/')) { - continue; - } - // Skip node built-ins - if (NODE_BUILTINS.has(specifier)) { - continue; - } - // Skip Node.js subpath imports - if (specifier.startsWith('#')) { - continue; - } - - // Get the package name (handle scoped packages and subpaths) - const packageName = getPackageName(specifier); - if (!packageName) { - continue; - } - - // Check if it's declared - if (declaredDeps.has(packageName)) { - continue; - } - // Check if it's in the blocklist (intentionally external) - if (EXTERNAL_BLOCKLIST.has(packageName) || EXTERNAL_BLOCKLIST.has(specifier)) { - continue; - } - - // Record undeclared external - if (!externalSpecifiers.has(specifier)) { - externalSpecifiers.set(specifier, new Set()); - } - externalSpecifiers.get(specifier)!.add(relative(distDir, file)); - } - } - - if (externalSpecifiers.size === 0) { - console.log(' ✓ All external dependencies are declared in package.json'); - return; - } - - // Group by package name - const byPackage = new Map>(); - for (const [specifier, _files] of externalSpecifiers) { - const packageName = getPackageName(specifier)!; - if (!byPackage.has(packageName)) { - byPackage.set(packageName, new Set()); - } - byPackage.get(packageName)!.add(specifier); - } - - console.log(`\n ⚠ Found ${byPackage.size} undeclared external dependencies:\n`); - for (const [packageName, specifiers] of byPackage.entries()) { - const files = externalSpecifiers.get([...specifiers][0])!; - console.log(` ${packageName}`); - for (const specifier of specifiers) { - if (specifier !== packageName) { - console.log(` - ${specifier}`); - } - } - console.log( - ` (used in: ${[...files].slice(0, 3).join(', ')}${files.size > 3 ? '...' : ''})`, - ); - } -} - -/** - * Extract the package name from a specifier (handles scoped packages and subpaths) - */ -function getPackageName(specifier: string): string | null { - // Scoped package: @scope/name or @scope/name/subpath - if (specifier.startsWith('@')) { - const parts = specifier.split('/'); - if (parts.length >= 2) { - return `${parts[0]}/${parts[1]}`; - } - return null; - } - // Regular package: name or name/subpath - const parts = specifier.split('/'); - return parts[0] || null; -} diff --git a/packages/test/package.json b/packages/test/package.json deleted file mode 100644 index bfd1f53909..0000000000 --- a/packages/test/package.json +++ /dev/null @@ -1,368 +0,0 @@ -{ - "name": "@voidzero-dev/vite-plus-test", - "version": "0.0.0", - "description": "The Unified Toolchain for the Web", - "homepage": "https://viteplus.dev/guide", - "bugs": { - "url": "https://github.com/voidzero-dev/vite-plus/issues" - }, - "license": "MIT", - "author": "VoidZero Inc.", - "repository": { - "type": "git", - "url": "git+https://github.com/voidzero-dev/vite-plus.git", - "directory": "packages/test" - }, - "files": [ - "*.cjs", - "*.cts", - "*.d.ts", - "*.mjs", - "browser/**", - "dist/**" - ], - "type": "module", - "sideEffects": false, - "main": "./dist/index.js", - "module": "./dist/index.js", - "types": "./dist/index.d.ts", - "imports": { - "#module-evaluator": { - "types": "./dist/module-evaluator.d.ts", - "default": "./dist/module-evaluator.js" - }, - "#nodejs-worker-loader": "./dist/nodejs-worker-loader.js" - }, - "exports": { - ".": { - "import": { - "types": "./dist/index.d.ts", - "browser": "./dist/index.js", - "node": "./dist/index-node.js", - "default": "./dist/index.js" - }, - "require": { - "types": "./index.d.cts", - "default": "./index.cjs" - } - }, - "./browser": { - "types": "./browser/context.d.ts", - "default": "./browser/context.js" - }, - "./package.json": "./package.json", - "./optional-types.js": { - "types": "./optional-types.d.ts" - }, - "./optional-runtime-types.js": { - "types": "./optional-runtime-types.d.ts" - }, - "./src/*": "./src/*", - "./globals": { - "types": "./globals.d.ts" - }, - "./jsdom": { - "types": "./jsdom.d.ts" - }, - "./importMeta": { - "types": "./importMeta.d.ts" - }, - "./import-meta": { - "types": "./import-meta.d.ts" - }, - "./node": { - "types": "./dist/node.d.ts", - "default": "./dist/node.js" - }, - "./internal/browser": { - "types": "./dist/browser.d.ts", - "default": "./dist/browser.js" - }, - "./runners": { - "types": "./dist/runners.d.ts", - "default": "./dist/runners.js" - }, - "./suite": { - "types": "./dist/suite.d.ts", - "default": "./dist/suite.js" - }, - "./environments": { - "types": "./dist/environments.d.ts", - "default": "./dist/environments.js" - }, - "./config": { - "types": "./config.d.ts", - "require": "./dist/config.cjs", - "default": "./dist/config.js" - }, - "./coverage": { - "types": "./coverage.d.ts", - "default": "./dist/coverage.js" - }, - "./reporters": { - "types": "./dist/reporters.d.ts", - "default": "./dist/reporters.js" - }, - "./snapshot": { - "types": "./dist/snapshot.d.ts", - "default": "./dist/snapshot.js" - }, - "./runtime": { - "types": "./dist/runtime.d.ts", - "default": "./dist/runtime.js" - }, - "./worker": { - "types": "./worker.d.ts", - "default": "./dist/worker.js" - }, - "./browser-compat": { - "default": "./dist/browser-compat.js" - }, - "./client": { - "default": "./dist/client.js" - }, - "./context": { - "types": "./browser/context.d.ts", - "default": "./dist/@vitest/browser/context.js" - }, - "./browser/context": { - "types": "./browser/context.d.ts", - "default": "./dist/@vitest/browser/context.js" - }, - "./locators": { - "default": "./dist/locators.js" - }, - "./matchers": { - "default": "./dist/dummy.js" - }, - "./utils": { - "default": "./dist/dummy.js" - }, - "./browser-playwright": { - "types": "./dist/@vitest/browser-playwright/index.d.ts", - "default": "./dist/@vitest/browser-playwright/index.js" - }, - "./browser-webdriverio": { - "types": "./dist/@vitest/browser-webdriverio/index.d.ts", - "default": "./dist/@vitest/browser-webdriverio/index.js" - }, - "./browser-preview": { - "types": "./dist/@vitest/browser-preview/index.d.ts", - "default": "./dist/@vitest/browser-preview/index.js" - }, - "./browser/providers/playwright": { - "types": "./dist/@vitest/browser-playwright/index.d.ts", - "default": "./dist/@vitest/browser-playwright/index.js" - }, - "./browser/providers/webdriverio": { - "types": "./dist/@vitest/browser-webdriverio/index.d.ts", - "default": "./dist/@vitest/browser-webdriverio/index.js" - }, - "./browser/providers/preview": { - "types": "./dist/@vitest/browser-preview/index.d.ts", - "default": "./dist/@vitest/browser-preview/index.js" - }, - "./plugins/runner": { - "default": "./dist/plugins/runner.mjs" - }, - "./plugins/runner-utils": { - "default": "./dist/plugins/runner-utils.mjs" - }, - "./plugins/runner-types": { - "default": "./dist/plugins/runner-types.mjs" - }, - "./plugins/utils": { - "default": "./dist/plugins/utils.mjs" - }, - "./plugins/utils-source-map": { - "default": "./dist/plugins/utils-source-map.mjs" - }, - "./plugins/utils-source-map-node": { - "default": "./dist/plugins/utils-source-map-node.mjs" - }, - "./plugins/utils-error": { - "default": "./dist/plugins/utils-error.mjs" - }, - "./plugins/utils-helpers": { - "default": "./dist/plugins/utils-helpers.mjs" - }, - "./plugins/utils-display": { - "default": "./dist/plugins/utils-display.mjs" - }, - "./plugins/utils-timers": { - "default": "./dist/plugins/utils-timers.mjs" - }, - "./plugins/utils-highlight": { - "default": "./dist/plugins/utils-highlight.mjs" - }, - "./plugins/utils-offset": { - "default": "./dist/plugins/utils-offset.mjs" - }, - "./plugins/utils-resolver": { - "default": "./dist/plugins/utils-resolver.mjs" - }, - "./plugins/utils-serialize": { - "default": "./dist/plugins/utils-serialize.mjs" - }, - "./plugins/utils-constants": { - "default": "./dist/plugins/utils-constants.mjs" - }, - "./plugins/utils-diff": { - "default": "./dist/plugins/utils-diff.mjs" - }, - "./plugins/spy": { - "default": "./dist/plugins/spy.mjs" - }, - "./plugins/expect": { - "default": "./dist/plugins/expect.mjs" - }, - "./plugins/snapshot": { - "default": "./dist/plugins/snapshot.mjs" - }, - "./plugins/snapshot-environment": { - "default": "./dist/plugins/snapshot-environment.mjs" - }, - "./plugins/snapshot-manager": { - "default": "./dist/plugins/snapshot-manager.mjs" - }, - "./plugins/mocker": { - "default": "./dist/plugins/mocker.mjs" - }, - "./plugins/mocker-node": { - "default": "./dist/plugins/mocker-node.mjs" - }, - "./plugins/mocker-browser": { - "default": "./dist/plugins/mocker-browser.mjs" - }, - "./plugins/mocker-redirect": { - "default": "./dist/plugins/mocker-redirect.mjs" - }, - "./plugins/mocker-transforms": { - "default": "./dist/plugins/mocker-transforms.mjs" - }, - "./plugins/mocker-automock": { - "default": "./dist/plugins/mocker-automock.mjs" - }, - "./plugins/mocker-register": { - "default": "./dist/plugins/mocker-register.mjs" - }, - "./plugins/pretty-format": { - "default": "./dist/plugins/pretty-format.mjs" - }, - "./plugins/browser": { - "default": "./dist/plugins/browser.mjs" - }, - "./plugins/browser-context": { - "default": "./dist/plugins/browser-context.mjs" - }, - "./plugins/browser-client": { - "default": "./dist/plugins/browser-client.mjs" - }, - "./plugins/browser-locators": { - "default": "./dist/plugins/browser-locators.mjs" - }, - "./plugins/browser-playwright": { - "default": "./dist/plugins/browser-playwright.mjs" - }, - "./plugins/browser-webdriverio": { - "default": "./dist/plugins/browser-webdriverio.mjs" - }, - "./plugins/browser-preview": { - "default": "./dist/plugins/browser-preview.mjs" - } - }, - "scripts": { - "build": "oxnode -C dev ./build.ts" - }, - "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@voidzero-dev/vite-plus-core": "workspace:*", - "es-module-lexer": "^1.7.0", - "obug": "^2.1.1", - "pixelmatch": "^7.1.0", - "pngjs": "^7.0.0", - "sirv": "^3.0.2", - "std-env": "^4.0.0", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "ws": "^8.18.3" - }, - "devDependencies": { - "@blazediff/core": "1.9.1", - "@oxc-node/cli": "catalog:", - "@oxc-node/core": "catalog:", - "@vitest/browser": "4.1.5", - "@vitest/browser-playwright": "4.1.5", - "@vitest/browser-preview": "4.1.5", - "@vitest/browser-webdriverio": "4.1.5", - "@vitest/expect": "4.1.5", - "@vitest/mocker": "4.1.5", - "@vitest/pretty-format": "4.1.5", - "@vitest/runner": "4.1.5", - "@vitest/snapshot": "4.1.5", - "@vitest/spy": "4.1.5", - "@vitest/utils": "4.1.5", - "chai": "^6.2.1", - "convert-source-map": "^2.0.0", - "estree-walker": "^3.0.3", - "expect-type": "^1.2.2", - "magic-string": "^0.30.21", - "oxc-parser": "catalog:", - "oxfmt": "catalog:", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "rolldown": "workspace:*", - "rolldown-plugin-dts": "catalog:", - "tinyrainbow": "^3.1.0", - "vitest-dev": "^4.1.5", - "why-is-node-running": "^2.3.0" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/coverage-istanbul": "4.1.5", - "@vitest/coverage-v8": "4.1.5", - "@vitest/ui": "4.1.5", - "happy-dom": "*", - "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/coverage-istanbul": { - "optional": true - }, - "@vitest/coverage-v8": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "vite": { - "optional": false - } - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "bundledVersions": { - "vitest": "4.1.5" - } -} diff --git a/packages/test/tsconfig.json b/packages/test/tsconfig.json deleted file mode 100644 index 62406593a8..0000000000 --- a/packages/test/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "experimentalDecorators": true - }, - "files": [], - "include": [], - "exclude": ["**/*"] -} diff --git a/packages/tools/package.json b/packages/tools/package.json index 139901c821..f9c7ae6d02 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -12,15 +12,16 @@ }, "dependencies": { "@yarnpkg/fslib": "catalog:", - "@yarnpkg/shell": "catalog:" + "@yarnpkg/shell": "catalog:", + "nanotar": "catalog:" }, "devDependencies": { "@oxc-node/cli": "catalog:", "@oxc-node/core": "catalog:", "@types/semver": "catalog:", - "@voidzero-dev/vite-plus-test": "workspace:*", "minimatch": "catalog:", "semver": "catalog:", + "vitest": "catalog:", "yaml": "catalog:" } } diff --git a/packages/tools/src/__tests__/__snapshots__/utils.spec.ts.snap b/packages/tools/src/__tests__/__snapshots__/utils.spec.ts.snap index e90d2192b4..4bdecf2b09 100644 --- a/packages/tools/src/__tests__/__snapshots__/utils.spec.ts.snap +++ b/packages/tools/src/__tests__/__snapshots__/utils.spec.ts.snap @@ -1,5 +1,7 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`replaceUnstableOutput() > replace bracketed pnpm registry request error warning log 1`] = `"Progress: resolved"`; + exports[`replaceUnstableOutput() > replace date 1`] = ` "Start at " @@ -47,10 +49,7 @@ exports[`replaceUnstableOutput() > replace ignore pnpm request warning log 1`] = Packages:" `; -exports[`replaceUnstableOutput() > replace ignore tarball download average speed warning log 1`] = ` -"WARN  Tarball download average speed 29 KiB/s (size 56 KiB) is below 50 KiB/s: https://registry./qs/-/qs-6.14.0.tgz (GET) - WARN  Tarball download average speed 34 KiB/s (size 347 KiB) is below 50 KiB/s: https://registry./undici/-/undici-7.16.0.tgz (GET)" -`; +exports[`replaceUnstableOutput() > replace ignore tarball download average speed warning log 1`] = `""`; exports[`replaceUnstableOutput() > replace pnpm progress plus markers with 1`] = ` "Scope: all workspace projects diff --git a/packages/tools/src/__tests__/utils.spec.ts b/packages/tools/src/__tests__/utils.spec.ts index 8f72a2137e..ebe71ed357 100644 --- a/packages/tools/src/__tests__/utils.spec.ts +++ b/packages/tools/src/__tests__/utils.spec.ts @@ -3,7 +3,7 @@ import fs from 'node:fs'; import { homedir, tmpdir } from 'node:os'; import path from 'node:path'; -import { describe, expect, test } from '@voidzero-dev/vite-plus-test'; +import { describe, expect, test } from 'vitest'; import { isPassThroughEnv, replaceUnstableOutput } from '../utils.ts'; @@ -73,8 +73,8 @@ Packages: +312 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Progress: resolved 1, reused 0, downloaded 0, added 0 Progress: resolved 316, reused 316, downloaded 0, added 315 -WARN  Skip adding vite to the default catalog because it already exists as npm:vite-plus. Please use \`pnpm update\` to update the catalogs. -WARN  Skip adding vitest to the default catalog because it already exists as beta. Please use \`pnpm update\` to update the catalogs. +WARN Skip adding vite to the default catalog because it already exists as npm:vite-plus. Please use \`pnpm update\` to update the catalogs. +WARN Skip adding vitest to the default catalog because it already exists as beta. Please use \`pnpm update\` to update the catalogs. Progress: resolved 316, reused 316, downloaded 0, added 316, done devDependencies: @@ -185,7 +185,7 @@ Done in 171ms using pnpm v10.16.1 test('replace ignore pnpm request warning log', () => { const output = ` Foo bar - WARN  Request took ms: https://registry.npmjs.org/testnpm2 + WARN Request took ms: https://registry.npmjs.org/testnpm2 Packages: `; expect(replaceUnstableOutput(output.trim())).toMatchSnapshot(); @@ -217,20 +217,31 @@ https://registry.yarnpkg.com/testnpm2/-/testnpm2-1.0.0.tgz test('replace pnpm registry request error warning log', () => { const output = ` - WARN  GET https://registry.npmjs.org/test-vite-plus-install error (ECONNRESET). Will retry in 10 seconds. 2 retries left. + WARN GET https://registry.npmjs.org/test-vite-plus-install error (ECONNRESET). Will retry in 10 seconds. 2 retries left. Progress: resolved `; expect(replaceUnstableOutput(output.trim())).toMatchSnapshot(); }); - test('replace ignore tarball download average speed warning log', () => { + test('replace bracketed pnpm registry request error warning log', () => { + // pnpm v11 prints transient network errors with a bracketed `[WARN]` prefix + // and an ASCII space. Make sure the redactor drops these so single-run + // ECONNRESET/ENOTFOUND flakes don't get baked into snap.txt. const output = ` - WARN  Tarball download average speed 29 KiB/s (size 56 KiB) is below 50 KiB/s: https://registry.npmjs.org/qs/-/qs-6.14.0.tgz (GET) - WARN  Tarball download average speed 34 KiB/s (size 347 KiB) is below 50 KiB/s: https://registry.npmjs.org/undici/-/undici-7.16.0.tgz (GET) +[WARN] GET https://registry.npmjs.org/testnpm2 error (ECONNRESET). Will retry in 10 seconds. 2 retries left. +[WARN] GET https://registry.npmjs.org/testnpm2 error (ETIMEDOUT). Will retry in 10 seconds. 1 retries left. +Progress: resolved `; expect(replaceUnstableOutput(output.trim())).toMatchSnapshot(); }); + test('replace ignore tarball download average speed warning log', () => { + const output = ` WARN Tarball download average speed 29 KiB/s (size 56 KiB) is below 50 KiB/s: https://registry.npmjs.org/qs/-/qs-6.14.0.tgz (GET) + WARN Tarball download average speed 34 KiB/s (size 347 KiB) is below 50 KiB/s: https://registry.npmjs.org/undici/-/undici-7.16.0.tgz (GET) +`; + expect(replaceUnstableOutput(output)).toMatchSnapshot(); + }); + test('replace hash values', () => { const output = ` npm notice shasum: 65c35f9599054722ecde040abd4a19682a723cdc diff --git a/packages/tools/src/index.ts b/packages/tools/src/index.ts index 5a6fa9b58e..d8847ff5fa 100644 --- a/packages/tools/src/index.ts +++ b/packages/tools/src/index.ts @@ -29,10 +29,14 @@ switch (subcommand) { const { brandVite } = await import('./brand-vite.ts'); brandVite(); break; + case 'repack-vite-tgz': + const { repackViteTgz } = await import('./repack-vite-tgz.ts'); + await repackViteTgz(); + break; default: console.error(`Unknown subcommand: ${subcommand}`); console.error( - 'Available subcommands: snap-test, replace-file-content, sync-remote, json-sort, merge-peer-deps, install-global-cli, brand-vite', + 'Available subcommands: snap-test, replace-file-content, sync-remote, json-sort, merge-peer-deps, install-global-cli, brand-vite, repack-vite-tgz', ); process.exit(1); } diff --git a/packages/tools/src/repack-vite-tgz.ts b/packages/tools/src/repack-vite-tgz.ts new file mode 100644 index 0000000000..c97cdf07e5 --- /dev/null +++ b/packages/tools/src/repack-vite-tgz.ts @@ -0,0 +1,81 @@ +import { readFile, writeFile } from 'node:fs/promises'; + +import { createTarGzip, parseTarGzip, type TarFileInput } from 'nanotar'; + +interface PackageJson { + name?: string; + version?: string; + dependencies?: Record; + devDependencies?: Record; + peerDependencies?: Record; + optionalDependencies?: Record; +} + +function stripVitePlusCoreSelfRefs(pkg: PackageJson, newName: string): void { + for (const field of [ + 'dependencies', + 'devDependencies', + 'peerDependencies', + 'optionalDependencies', + ] as const) { + const group = pkg[field]; + if (!group) { + continue; + } + for (const [key, value] of Object.entries(group)) { + if ( + (key === newName || key === '@voidzero-dev/vite-plus-core') && + typeof value === 'string' && + value.includes('@voidzero-dev/vite-plus-core') + ) { + delete group[key]; + } + } + } +} + +export async function repackViteTgz() { + const [inputPath, outputPath, newName, newVersion] = process.argv.slice(3); + + if (!inputPath || !outputPath || !newName) { + console.error('Usage: tool repack-vite-tgz [new-version]'); + process.exit(1); + } + + const inputBytes = await readFile(inputPath); + const entries = await parseTarGzip(inputBytes); + + let patched = 0; + const repacked: TarFileInput[] = entries.map((entry) => { + let data = entry.data; + if (entry.name === 'package/package.json' && data) { + const pkg = JSON.parse(new TextDecoder().decode(data)) as PackageJson; + pkg.name = newName; + if (newVersion) { + pkg.version = newVersion; + } + // Strip any self-ref (`vite: npm:@voidzero-dev/vite-plus-core@...`) + // injected by the workspace-level vite -> vite-plus-core override at + // pnpm pack time. Once we rename the tgz to "vite", this becomes a + // circular self-dependency that confuses pnpm's resolver and triggers a + // registry lookup for the alias target version. + stripVitePlusCoreSelfRefs(pkg, newName); + data = new TextEncoder().encode(JSON.stringify(pkg, null, 2) + '\n'); + patched += 1; + } + return { name: entry.name, data, attrs: entry.attrs }; + }); + + if (patched !== 1) { + console.error(`Expected exactly one package/package.json entry, found ${patched}`); + process.exit(1); + } + + const outBytes = await createTarGzip(repacked); + await writeFile(outputPath, outBytes); + console.log( + `Repacked ${inputPath} -> ${outputPath} (name=${newName}${ + newVersion ? `, version=${newVersion}` : '' + }, ${outBytes.byteLength} bytes)`, + ); +} diff --git a/packages/tools/src/utils.ts b/packages/tools/src/utils.ts index b9762d8ffe..7825bca333 100644 --- a/packages/tools/src/utils.ts +++ b/packages/tools/src/utils.ts @@ -80,12 +80,16 @@ export function replaceUnstableOutput(output: string, cwd?: string) { // ignore pnpm progress .replaceAll(/Progress: resolved \d+, reused \d+, downloaded \d+, added \d+\n/g, '') // ignore pnpm warn - .replaceAll(/ ?WARN\s+Skip\s+adding .+?\n/g, '') - .replaceAll(/ ?WARN\s+Request\s+took .+?\n/g, '') + .replaceAll(/ ?WARN\s+Skip\s+adding .+?\n/g, '') + .replaceAll(/ ?WARN\s+Request\s+took .+?\n/g, '') .replaceAll(/Scope: all \d+ workspace projects/g, 'Scope: all workspace projects') .replaceAll(/\+{2,}\n/g, '+\n') // ignore pnpm registry request error warning log - .replaceAll(/ ?WARN\s+GET\s+https:\/\/registry\..+?\n/g, '') + // Matches both `WARN` (older pnpm) and `[WARN]` (newer pnpm) prefixes. + // Also drops transient network warnings like + // `[WARN] GET https://registry./pkg error (ECONNRESET). Will retry in 10 seconds. 2 retries left.` + // so single-run flakes don't get baked into snapshots. + .replaceAll(/ ?\[?WARN\]?\s+GET\s+https:\/\/registry\..+?\n/g, '') // ignore bun resolution progress (appears intermittently depending on cache state) .replaceAll(/Resolving dependencies\n/g, '') .replaceAll(/Resolved, downloaded and extracted \[\d+\]\n/g, '') @@ -138,7 +142,7 @@ export function replaceUnstableOutput(output: string, cwd?: string) { // ignore npm registry domain .replaceAll(/(https?:\/\/registry\.)[^/\s]+(\/?)/g, '$1$2') // ignore pnpm tarball download average speed warning log - .replaceAll(/ WARN  Tarball download average speed .+?\n/g, '') + .replaceAll(/ ?\[?WARN\]?\s+Tarball download average speed .+?\n/g, '') // ignore npm hash values .replaceAll(/shasum: .+?\n/g, 'shasum: \n') .replaceAll(/integrity: ([\w-]+)-.+?\n/g, 'integrity: $1-\n') diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index de6b9b252a..6aaa1470ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -84,6 +84,18 @@ catalogs: '@typescript/native-preview': specifier: 7.0.0-dev.20260122.2 version: 7.0.0-dev.20260122.2 + '@vitest/browser': + specifier: 4.1.5 + version: 4.1.5 + '@vitest/browser-playwright': + specifier: 4.1.5 + version: 4.1.5 + '@vitest/browser-preview': + specifier: 4.1.5 + version: 4.1.5 + '@vitest/browser-webdriverio': + specifier: 4.1.5 + version: 4.1.5 '@yarnpkg/fslib': specifier: ^3.1.3 version: 3.1.4 @@ -240,6 +252,9 @@ catalogs: validate-npm-package-name: specifier: ^7.0.2 version: 7.0.2 + vitest: + specifier: 4.1.5 + version: 4.1.5 vue: specifier: ^3.5.21 version: 3.5.34 @@ -257,8 +272,7 @@ overrides: '@rolldown/pluginutils': workspace:@rolldown/pluginutils@* rolldown: workspace:rolldown@* vite: workspace:@voidzero-dev/vite-plus-core@* - vitest: workspace:@voidzero-dev/vite-plus-test@* - vitest-dev: npm:vitest@^4.1.5 + vite-plus: workspace:vite-plus@* packageExtensionsChecksum: sha256-Tldxs3DhJEw/FFBonUidqhCBqApA0zxQnop3Y+BTO3U= @@ -320,11 +334,11 @@ importers: specifier: workspace:@voidzero-dev/vite-plus-core@* version: link:packages/core vite-plus: - specifier: workspace:* + specifier: workspace:vite-plus@* version: link:packages/cli vitest: - specifier: workspace:@voidzero-dev/vite-plus-test@* - version: link:packages/test + specifier: 'catalog:' + version: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.3)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) zod: specifier: 'catalog:' version: 4.3.5 @@ -334,12 +348,21 @@ importers: '@oxc-project/types': specifier: 'catalog:' version: 0.129.0 + '@vitest/browser': + specifier: 'catalog:' + version: 4.1.5(vite@packages+core)(vitest@4.1.5) + '@vitest/browser-playwright': + specifier: 'catalog:' + version: 4.1.5(playwright@1.57.0)(vite@packages+core)(vitest@4.1.5) + '@vitest/browser-preview': + specifier: 'catalog:' + version: 4.1.5(vite@packages+core)(vitest@4.1.5) + '@vitest/browser-webdriverio': + specifier: 'catalog:' + version: 4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1) '@voidzero-dev/vite-plus-core': specifier: workspace:* version: link:../core - '@voidzero-dev/vite-plus-test': - specifier: workspace:* - version: link:../test oxfmt: specifier: 'catalog:' version: 0.48.0 @@ -349,6 +372,9 @@ importers: oxlint-tsgolint: specifier: 'catalog:' version: 0.22.1 + vitest: + specifier: 'catalog:' + version: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) devDependencies: '@napi-rs/cli': specifier: 'catalog:' @@ -597,160 +623,6 @@ importers: specifier: 'catalog:' version: 0.22.0(@arethetypeswrong/core@0.18.2)(@tsdown/css@0.22.0)(@tsdown/exe@0.22.0)(@typescript/native-preview@7.0.0-dev.20260122.2)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(publint@0.3.19)(tsx@4.21.0)(typescript@6.0.2)(unplugin-unused@0.5.6)(unrun@0.2.37) - packages/test: - dependencies: - '@edge-runtime/vm': - specifier: '*' - version: 5.0.0 - '@opentelemetry/api': - specifier: ^1.9.0 - version: 1.9.0 - '@standard-schema/spec': - specifier: ^1.1.0 - version: 1.1.0 - '@types/chai': - specifier: ^5.2.2 - version: 5.2.3 - '@types/node': - specifier: ^20.0.0 || ^22.0.0 || >=24.0.0 - version: 24.12.2 - '@vitest/coverage-istanbul': - specifier: 4.1.5 - version: 4.1.5(vitest@4.1.5) - '@vitest/coverage-v8': - specifier: 4.1.5 - version: 4.1.5(@vitest/browser@4.1.5)(vitest@4.1.5) - '@vitest/ui': - specifier: 4.1.5 - version: 4.1.5(vitest@4.1.5) - '@voidzero-dev/vite-plus-core': - specifier: workspace:* - version: link:../core - es-module-lexer: - specifier: ^1.7.0 - version: 1.7.0 - happy-dom: - specifier: '*' - version: 20.0.10 - jsdom: - specifier: '*' - version: 27.2.0 - obug: - specifier: ^2.1.1 - version: 2.1.1 - pixelmatch: - specifier: ^7.1.0 - version: 7.1.0 - pngjs: - specifier: ^7.0.0 - version: 7.0.0 - sirv: - specifier: ^3.0.2 - version: 3.0.2(patch_hash=c07c56eb72faea34341d465cde2314e89db472106ed378181e3447893af6bf95) - std-env: - specifier: ^4.0.0 - version: 4.0.0 - tinybench: - specifier: ^2.9.0 - version: 2.9.0 - tinyexec: - specifier: ^1.0.2 - version: 1.1.2 - tinyglobby: - specifier: ^0.2.15 - version: 0.2.16 - vite: - specifier: workspace:@voidzero-dev/vite-plus-core@* - version: link:../core - ws: - specifier: ^8.18.3 - version: 8.20.0 - devDependencies: - '@blazediff/core': - specifier: 1.9.1 - version: 1.9.1 - '@oxc-node/cli': - specifier: 'catalog:' - version: 0.1.0 - '@oxc-node/core': - specifier: 'catalog:' - version: 0.1.0 - '@vitest/browser': - specifier: 4.1.5 - version: 4.1.5(vite@packages+core)(vitest@4.1.5) - '@vitest/browser-playwright': - specifier: 4.1.5 - version: 4.1.5(playwright@1.57.0)(vite@packages+core)(vitest@4.1.5) - '@vitest/browser-preview': - specifier: 4.1.5 - version: 4.1.5(vite@packages+core)(vitest@4.1.5) - '@vitest/browser-webdriverio': - specifier: 4.1.5 - version: 4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1) - '@vitest/expect': - specifier: 4.1.5 - version: 4.1.5 - '@vitest/mocker': - specifier: 4.1.5 - version: 4.1.5(vite@packages+core) - '@vitest/pretty-format': - specifier: 4.1.5 - version: 4.1.5 - '@vitest/runner': - specifier: 4.1.5 - version: 4.1.5 - '@vitest/snapshot': - specifier: 4.1.5 - version: 4.1.5 - '@vitest/spy': - specifier: 4.1.5 - version: 4.1.5 - '@vitest/utils': - specifier: 4.1.5 - version: 4.1.5 - chai: - specifier: ^6.2.1 - version: 6.2.2 - convert-source-map: - specifier: ^2.0.0 - version: 2.0.0 - estree-walker: - specifier: ^3.0.3 - version: 3.0.3 - expect-type: - specifier: ^1.2.2 - version: 1.3.0 - magic-string: - specifier: ^0.30.21 - version: 0.30.21 - oxc-parser: - specifier: 'catalog:' - version: 0.129.0 - oxfmt: - specifier: 'catalog:' - version: 0.48.0 - pathe: - specifier: ^2.0.3 - version: 2.0.3 - picomatch: - specifier: ^4.0.3 - version: 4.0.4 - rolldown: - specifier: workspace:rolldown@* - version: link:../../rolldown/packages/rolldown - rolldown-plugin-dts: - specifier: 'catalog:' - version: 0.23.2(@typescript/native-preview@7.0.0-dev.20260122.2)(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(rolldown@rolldown+packages+rolldown)(typescript@6.0.2) - tinyrainbow: - specifier: ^3.1.0 - version: 3.1.0 - vitest-dev: - specifier: npm:vitest@^4.1.5 - version: vitest@4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5(playwright@1.57.0)(vite@packages+core)(vitest@4.1.5))(@vitest/browser-preview@4.1.5(vite@packages+core)(vitest@4.1.5))(@vitest/browser-webdriverio@4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1))(@vitest/coverage-istanbul@4.1.5(vitest@4.1.5))(@vitest/coverage-v8@4.1.5(@vitest/browser@4.1.5)(vitest@4.1.5))(@vitest/ui@4.1.5(vitest@4.1.5))(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) - why-is-node-running: - specifier: ^2.3.0 - version: 2.3.0 - packages/tools: dependencies: '@yarnpkg/fslib': @@ -759,6 +631,9 @@ importers: '@yarnpkg/shell': specifier: 'catalog:' version: 4.1.3(typanion@3.14.0) + nanotar: + specifier: 'catalog:' + version: 0.3.0 devDependencies: '@oxc-node/cli': specifier: 'catalog:' @@ -769,15 +644,15 @@ importers: '@types/semver': specifier: 'catalog:' version: 7.7.1 - '@voidzero-dev/vite-plus-test': - specifier: workspace:* - version: link:../test minimatch: specifier: 'catalog:' version: 10.2.4 semver: specifier: 'catalog:' version: 7.7.4 + vitest: + specifier: 'catalog:' + version: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) yaml: specifier: 'catalog:' version: 2.8.2 @@ -815,8 +690,8 @@ importers: specifier: 'catalog:' version: 6.0.2 vite-plus: - specifier: ^0.1.13 - version: 0.1.13(@arethetypeswrong/core@0.18.2)(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@tsdown/css@0.21.4)(@tsdown/exe@0.21.4)(@types/node@24.10.3)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(esbuild@0.27.4)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.2.0)(less@4.4.2)(publint@0.3.19)(sass-embedded@1.99.0(source-map-js@1.2.1))(sass@1.99.0)(stylus@0.64.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.46.2)(tsx@4.21.0)(typescript@6.0.2)(unplugin-unused@0.5.6)(vite@packages+core)(yaml@2.8.2) + specifier: workspace:vite-plus@* + version: link:../packages/cli rolldown/packages/bench: dependencies: @@ -906,8 +781,8 @@ importers: specifier: 'catalog:' version: 6.0.2 vitest: - specifier: workspace:@voidzero-dev/vite-plus-test@* - version: link:../../../packages/test + specifier: 'catalog:' + version: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) rolldown/packages/rolldown: dependencies: @@ -1146,8 +1021,8 @@ importers: specifier: workspace:@voidzero-dev/vite-plus-core@* version: link:../packages/core vitest: - specifier: workspace:@voidzero-dev/vite-plus-test@* - version: link:../packages/test + specifier: ^4.1.5 + version: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) vite/packages/create-vite: devDependencies: @@ -1530,10 +1405,6 @@ packages: resolution: {integrity: sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==} engines: {node: '>=6.9.0'} - '@babel/generator@8.0.0-rc.2': - resolution: {integrity: sha512-oCQ1IKPwkzCeJzAPb7Fv8rQ9k5+1sG8mf2uoHiMInPYvkRfrDJxbTIbH51U+jstlkghus0vAi3EBvkfvEsYNLQ==} - engines: {node: ^20.19.0 || >=22.12.0} - '@babel/generator@8.0.0-rc.3': resolution: {integrity: sha512-em37/13/nR320G4jab/nIIHZgc2Wz2y/D39lxnTyxB4/D/omPQncl/lSdlnJY1OhQcRGugTSIF2l/69o31C9dA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1621,10 +1492,6 @@ packages: resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@8.0.0-rc.2': - resolution: {integrity: sha512-xExUBkuXWJjVuIbO7z6q7/BA9bgfJDEhVL0ggrggLMbg0IzCUWGT1hZGE8qUH7Il7/RD/a6cZ3AAFrrlp1LF/A==} - engines: {node: ^20.19.0 || >=22.12.0} - '@babel/helper-validator-identifier@8.0.0-rc.3': resolution: {integrity: sha512-8AWCJ2VJJyDFlGBep5GpaaQ9AAaE/FjAcrqI7jyssYhtL7WGV0DOKpJsQqM037xDbpRLHXsY8TwU7zDma7coOw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1650,11 +1517,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@8.0.0-rc.2': - resolution: {integrity: sha512-29AhEtcq4x8Dp3T72qvUMZHx0OMXCj4Jy/TEReQa+KWLln524Cj1fWb3QFi0l/xSpptQBR6y9RNEXuxpFvwiUQ==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - '@babel/parser@8.0.0-rc.3': resolution: {integrity: sha512-B20dvP3MfNc/XS5KKCHy/oyWl5IA6Cn9YjXRdDlCjNmUFrjvLXMNUfQq/QUy9fnG2gYkKKcrto2YaF9B32ToOQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2082,10 +1944,6 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@babel/types@8.0.0-rc.2': - resolution: {integrity: sha512-91gAaWRznDwSX4E2tZ1YjBuIfnQVOFDCQ2r0Toby0gu4XEbyF623kXLMA8d4ZbCu+fINcrudkmEcwSUHgDDkNw==} - engines: {node: ^20.19.0 || >=22.12.0} - '@babel/types@8.0.0-rc.3': resolution: {integrity: sha512-mOm5ZrYmphGfqVWoH5YYMTITb3cDXsFgmvFlvkvWDMsR9X8RFnt7a0Wb6yNIdoFsiMO9WjYLq+U/FMtqIYAF8Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3711,17 +3569,10 @@ packages: cpu: [x64] os: [win32] - '@oxc-project/runtime@0.120.0': - resolution: {integrity: sha512-7fvACzS46TkHuzA+Tag8ac40qfwURXRTdc4AtyItF59AoNPOO/QjPMqPyvJH8CaUdGu0ntWDX1CCUNyLMxxX5g==} - engines: {node: ^20.19.0 || >=22.12.0} - '@oxc-project/runtime@0.129.0': resolution: {integrity: sha512-0+S67blQakgeNqoKGozOUp5rQBrz2ynXZ2QIINXZPiafsD0YL0UogB9hAWc1S7k6VSNwKYC/N7MqT0V6IzpHkQ==} engines: {node: ^20.19.0 || >=22.12.0} - '@oxc-project/types@0.120.0': - resolution: {integrity: sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==} - '@oxc-project/types@0.121.0': resolution: {integrity: sha512-CGtOARQb9tyv7ECgdAlFxi0Fv7lmzvmlm2rpD/RdijOO9rfk/JvB1CjT8EnoD+tjna/IYgKKw3IV7objRb+aYw==} @@ -3966,97 +3817,48 @@ packages: cpu: [x64] os: [win32] - '@oxfmt/binding-android-arm-eabi@0.41.0': - resolution: {integrity: sha512-REfrqeMKGkfMP+m/ScX4f5jJBSmVNYcpoDF8vP8f8eYPDuPGZmzp56NIUsYmx3h7f6NzC6cE3gqh8GDWrJHCKw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - '@oxfmt/binding-android-arm-eabi@0.48.0': resolution: {integrity: sha512-uwqk+/KhQvBIpULD8SMM/zAafMRC/+DV/xsEQjkkIsJ/kLmEI/2bxonVowcYTiXqqZ/a0FEW8DPkZY3VvwELDA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxfmt/binding-android-arm64@0.41.0': - resolution: {integrity: sha512-s0b1dxNgb2KomspFV2LfogC2XtSJB42POXF4bMCLJyvQmAGos4ZtjGPfQreToQEaY0FQFjz3030ggI36rF1q5g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - '@oxfmt/binding-android-arm64@0.48.0': resolution: {integrity: sha512-VUCiKuXK5+McVssgHEJdrcGK7hRJzrRb36zm9/jwzMholyYt4BgXhw5Nm1V1DX6Ce717Zi/1jk432b/tgmQgtQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxfmt/binding-darwin-arm64@0.41.0': - resolution: {integrity: sha512-EGXGualADbv/ZmamE7/2DbsrYmjoPlAmHEpTL4vapLF4EfVD6fr8/uQDFnPJkUBjiSWFJZtFNsGeN1B6V3owmA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - '@oxfmt/binding-darwin-arm64@0.48.0': resolution: {integrity: sha512-IkKp8rnIyQLW6Jt+6jragCbUVYSayk55lapiprLjIVvt4NczLyO/nwX2GgefLQ5iaBdfS8UEAFgCs/pLO6Cl0w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxfmt/binding-darwin-x64@0.41.0': - resolution: {integrity: sha512-WxySJEvdQQYMmyvISH3qDpTvoS0ebnIP63IMxLLWowJyPp/AAH0hdWtlo+iGNK5y3eVfa5jZguwNaQkDKWpGSw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - '@oxfmt/binding-darwin-x64@0.48.0': resolution: {integrity: sha512-+aFuhsGIuvnoOjXyKVHMhPKJZR1kQkAl8QyrKoMlA7yJsSTC3N0Asl53La8TChSHhW8epToQ/Q0nvLmEmfNmLg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxfmt/binding-freebsd-x64@0.41.0': - resolution: {integrity: sha512-Y2kzMkv3U3oyuYaR4wTfGjOTYTXiFC/hXmG0yVASKkbh02BJkvD98Ij8bIevr45hNZ0DmZEgqiXF+9buD4yMYQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - '@oxfmt/binding-freebsd-x64@0.48.0': resolution: {integrity: sha512-fbqzQL8FjI9gGnktI7RIo0dksDziTAYBy7xlI7jU7eID5fxLF/25fS4Xj6GydD8Y5oWHL83U4NK160QaOAxtyg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxfmt/binding-linux-arm-gnueabihf@0.41.0': - resolution: {integrity: sha512-ptazDjdUyhket01IjPTT6ULS1KFuBfTUU97osTP96X5y/0oso+AgAaJzuH81oP0+XXyrWIHbRzozSAuQm4p48g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - '@oxfmt/binding-linux-arm-gnueabihf@0.48.0': resolution: {integrity: sha512-hn4i0zhAyTiB3ZHjQfYUZkDvrbVkohw1S7pySWxWUoZ87HnkDoTFThj7QTxk40hNPOTUP0vHbPRNamFIv1HBJQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm-musleabihf@0.41.0': - resolution: {integrity: sha512-UkoL2OKxFD+56bPEBcdGn+4juTW4HRv/T6w1dIDLnvKKWr6DbarB/mtHXlADKlFiJubJz8pRkttOR7qjYR6lTA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - '@oxfmt/binding-linux-arm-musleabihf@0.48.0': resolution: {integrity: sha512-R4WBD9qF3QM9hqgdAa+fBGXmquTvDUujrPQ36t2Sjk8RPOSKGHDeN7l/khr10hqbQaOq9KCgPHG9ubNET/X/RQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm64-gnu@0.41.0': - resolution: {integrity: sha512-gofu0PuumSOHYczD8p62CPY4UF6ee+rSLZJdUXkpwxg6pILiwSDBIouPskjF/5nF3A7QZTz2O9KFNkNxxFN9tA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - '@oxfmt/binding-linux-arm64-gnu@0.48.0': resolution: {integrity: sha512-5bVdwSwlm1M8wbYCorLOxWxUBw/8tBvHYyQNIfwWVPwOJaj5vg1APSGJQVpwJfV5VNE9PSrR91UKEpoNwHhqUA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4064,13 +3866,6 @@ packages: os: [linux] libc: [glibc] - '@oxfmt/binding-linux-arm64-musl@0.41.0': - resolution: {integrity: sha512-VfVZxL0+6RU86T8F8vKiDBa+iHsr8PAjQmKGBzSCAX70b6x+UOMFl+2dNihmKmUwqkCazCPfYjt6SuAPOeQJ3g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - '@oxfmt/binding-linux-arm64-musl@0.48.0': resolution: {integrity: sha512-vCS3Fk7gFslTqE1lUE2IlroyVV7u/9SmMA/uBqDoshuck2psGWcjW0ePyPZI3rM3+qtf2pDaMVIKMHozraifuw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4078,13 +3873,6 @@ packages: os: [linux] libc: [musl] - '@oxfmt/binding-linux-ppc64-gnu@0.41.0': - resolution: {integrity: sha512-bwzokz2eGvdfJbc0i+zXMJ4BBjQPqg13jyWpEEZDOrBCQ91r8KeY2Mi2kUeuMTZNFXju+jcAbAbpyJxRGla0eg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - '@oxfmt/binding-linux-ppc64-gnu@0.48.0': resolution: {integrity: sha512-gKtfFfueUClXDumyoHUbymqRf7prHejOOyzJK0eIJn93GF9JBdFHdo60TM1ZBHxkEwZvjuOgHmKtneKbEOc/Eg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4092,13 +3880,6 @@ packages: os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-gnu@0.41.0': - resolution: {integrity: sha512-POLM//PCH9uqDeNDwWL3b3DkMmI3oI2cU6hwc2lnztD1o7dzrQs3R9nq555BZ6wI7t2lyhT9CS+CRaz5X0XqLA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [glibc] - '@oxfmt/binding-linux-riscv64-gnu@0.48.0': resolution: {integrity: sha512-SYt0UhOvZD/UwZz9sXq6J2uAw8o24f5VZpLB2DH01f6MevshmlgakQlZe2lwek2sZJkd07eLu7mZa0g7yeiw7Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4106,13 +3887,6 @@ packages: os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-musl@0.41.0': - resolution: {integrity: sha512-NNK7PzhFqLUwx/G12Xtm6scGv7UITvyGdAR5Y+TlqsG+essnuRWR4jRNODWRjzLZod0T3SayRbnkSIWMBov33w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [musl] - '@oxfmt/binding-linux-riscv64-musl@0.48.0': resolution: {integrity: sha512-JLbrwck2AopG4ud/XklZO5N+qxGC7cS7ROvXZVNfx0MCLDDL2kGOLvzuWORkVjnjAM0CMAfIMU2zNBtQbM+4dw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4120,13 +3894,6 @@ packages: os: [linux] libc: [musl] - '@oxfmt/binding-linux-s390x-gnu@0.41.0': - resolution: {integrity: sha512-qVf/zDC5cN9eKe4qI/O/m445er1IRl6swsSl7jHkqmOSVfknwCe5JXitYjZca+V/cNJSU/xPlC5EFMabMMFDpw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - '@oxfmt/binding-linux-s390x-gnu@0.48.0': resolution: {integrity: sha512-mdxt5L8OQLxkQH+JVpdC/lknZNe0lX4hlO3d8+xvw2wToo+iDrid9tiGOd5bmHfUVd5wVhrUry0qlu5vq66NkQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4134,13 +3901,6 @@ packages: os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-gnu@0.41.0': - resolution: {integrity: sha512-ojxYWu7vUb6ysYqVCPHuAPVZHAI40gfZ0PDtZAMwVmh2f0V8ExpPIKoAKr7/8sNbAXJBBpZhs2coypIo2jJX4w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - '@oxfmt/binding-linux-x64-gnu@0.48.0': resolution: {integrity: sha512-oEz1BQwMrV7OMEFx/3VPDU3n9TM0AnxpktDYXjEg5i6nTX87wo18wSfBvkl4tzAICdKtoAQAdBIl7Y7hsPlx5w==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4148,13 +3908,6 @@ packages: os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-musl@0.41.0': - resolution: {integrity: sha512-O2exZLBxoCMIv2vlvcbkdedazJPTdG0VSup+0QUCfYQtx751zCZNboX2ZUOiQ/gDTdhtXvSiot0h6GEGkOyalA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - '@oxfmt/binding-linux-x64-musl@0.48.0': resolution: {integrity: sha512-g2SKTTurP5mWjd8Ecait0erYqmltL4IqW1EwttM25BxM6NiTt4ubobJYMR1uox1V2QgG4UfHH10CGRvWlUixjw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4162,205 +3915,102 @@ packages: os: [linux] libc: [musl] - '@oxfmt/binding-openharmony-arm64@0.41.0': - resolution: {integrity: sha512-N+31/VoL+z+NNBt8viy3I4NaIdPbiYeOnB884LKqvXldaE2dRztdPv3q5ipfZYv0RwFp7JfqS4I27K/DSHCakg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - '@oxfmt/binding-openharmony-arm64@0.48.0': resolution: {integrity: sha512-CIg24VgheEpvolHL2gQuax5qcQ602bRMHrJ9g8XsQr3iVj9aSPgopigBKuMqrXsupwkrU+RQCn5cG8PgFntR6w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxfmt/binding-win32-arm64-msvc@0.41.0': - resolution: {integrity: sha512-Z7NAtu/RN8kjCQ1y5oDD0nTAeRswh3GJ93qwcW51srmidP7XPBmZbLlwERu1W5veCevQJtPS9xmkpcDTYsGIwQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - '@oxfmt/binding-win32-arm64-msvc@0.48.0': resolution: {integrity: sha512-zeaWkcxcEULwkGF3I/HgEvcDPN8buYDrxibBUa/IFh5Vmwyge+KpLO+hEwSovW349H0O/C0Z2kaFmEzEDm00/Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxfmt/binding-win32-ia32-msvc@0.41.0': - resolution: {integrity: sha512-uNxxP3l4bJ6VyzIeRqCmBU2Q0SkCFgIhvx9/9dJ9V8t/v+jP1IBsuaLwCXGR8JPHtkj4tFp+RHtUmU2ZYAUpMA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - '@oxfmt/binding-win32-ia32-msvc@0.48.0': resolution: {integrity: sha512-yiEKnIAGvx5CyZQOlMaNlZkAbwT7/Quk0j3WLt+PR5hK+qYjPTRRJYDfD77wCBPLvEYAG41v4KG3iL0H+uxoxg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxfmt/binding-win32-x64-msvc@0.41.0': - resolution: {integrity: sha512-49ZSpbZ1noozyPapE8SUOSm3IN0Ze4b5nkO+4+7fq6oEYQQJFhE0saj5k/Gg4oewVPdjn0L3ZFeWk2Vehjcw7A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - '@oxfmt/binding-win32-x64-msvc@0.48.0': resolution: {integrity: sha512-GSD2+7t2UoVMV2NgxXypa4bKewflPMAjYnF0Xw9/ht82ZfafAHhb8STwrEd7wlH2PFogt5zw3WVCxYJaHUdbeQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@oxlint-tsgolint/darwin-arm64@0.17.1': - resolution: {integrity: sha512-JNWNwyvSDcUQSBlQRl10XrCeNcN66TMvDw3gIDQeop5SNa1F7wFhsEx4zitYb7fGHwGh9095tsNttmuCaNXCbw==} - cpu: [arm64] - os: [darwin] - '@oxlint-tsgolint/darwin-arm64@0.22.1': resolution: {integrity: sha512-4150Lpgc1YM09GcjA6GSrra1JoPjC7aOpfywLjWEY4vW0Sd1qKzqHF1WRaiw0/qUZ40OATYdv3aRd7ipPkWQbw==} cpu: [arm64] os: [darwin] - '@oxlint-tsgolint/darwin-x64@0.17.1': - resolution: {integrity: sha512-SluNf6CW88pgGPqQUGC5GoK5qESWo2ct1PRDbza3vbf9SK2npx3igvylGQIgE9qYYOcjgnVdLOJ0+q0gItgUmQ==} - cpu: [x64] - os: [darwin] - '@oxlint-tsgolint/darwin-x64@0.22.1': resolution: {integrity: sha512-vFWcPWYOgZs4HWcgS1EjUZg33NLcNfEYU49KGImmCfZWkflENrmBYV4HN/C0YeAPum6ZZ/goPSvQrB/cOD+NfA==} cpu: [x64] os: [darwin] - '@oxlint-tsgolint/linux-arm64@0.17.1': - resolution: {integrity: sha512-BJxQ7/cdo2dNdGIBs2PIR6BaPA7cPfe+r1HE/uY+K7g2ygip+0LHB3GUO9GaNDZuWpsnDyjLYYowEGrVK8dokA==} - cpu: [arm64] - os: [linux] - '@oxlint-tsgolint/linux-arm64@0.22.1': resolution: {integrity: sha512-6LiUpP0Zir3+29FvBm7Y28q/dBjSHqTZ5MhG1Ckw4fGhI4cAvbcwXaKvbjx1TP7rRmBNOoq/M5xdpHjTb+GAew==} cpu: [arm64] os: [linux] - '@oxlint-tsgolint/linux-x64@0.17.1': - resolution: {integrity: sha512-s6UjmuaJbZ4zz/wJKdEw/s5mc0t41rgwxQJCSHPuzMumMK6ylrB7nydhDf8ObTtzhTIZdAS/2S/uayJmDcGbxw==} - cpu: [x64] - os: [linux] - '@oxlint-tsgolint/linux-x64@0.22.1': resolution: {integrity: sha512-fuX1hEQfpHauUbXADsfqVhRzrUrGabzGXbj5wsp2vKhV5uk/Rze8Mba9GdjFGECzvXudMGqHqxB4r6jGRdhxVA==} cpu: [x64] os: [linux] - '@oxlint-tsgolint/win32-arm64@0.17.1': - resolution: {integrity: sha512-EO/Oj0ixHX+UQdu9hM7YUzibZI888MvPUo/DF8lSxFBt4JNEt8qGkwJEbCYjB/1LhUNmPHzSw2Tr9dCFVfW9nw==} - cpu: [arm64] - os: [win32] - '@oxlint-tsgolint/win32-arm64@0.22.1': resolution: {integrity: sha512-8SZidAj+jrbZf9ZjBEYW0tiNZ+KasqB2zgW26qdiPpQSF/DzURnPmXz651IeA9YsmbVdHGIooEHUmev6QJdquA==} cpu: [arm64] os: [win32] - '@oxlint-tsgolint/win32-x64@0.17.1': - resolution: {integrity: sha512-jhv7XktAJ1sMRSb//yDYTauFSZ06H81i2SLEBPaSUKxSKoPMK8p1ACUJlnmwZX2MgapRLEj1Ml22B6+HiM2YIA==} - cpu: [x64] - os: [win32] - '@oxlint-tsgolint/win32-x64@0.22.1': resolution: {integrity: sha512-QweSk9H5lFh5Y+WUf2Kq/OAN88V6+62ZwGhP38gqdRotI90luXSMkruFTj7Q2rYrzH4ZVNaSqx7NY8JpSfIzqg==} cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.56.0': - resolution: {integrity: sha512-IyfYPthZyiSKwAv/dLjeO18SaK8MxLI9Yss2JrRDyweQAkuL3LhEy7pwIwI7uA3KQc1Vdn20kdmj3q0oUIQL6A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - '@oxlint/binding-android-arm-eabi@1.63.0': resolution: {integrity: sha512-A9xLtQt7i0OA1PoB/meog6kikXI9CdwEp7ZwQqmgnpKn3G3b1orvTDy8CQ6T7w1HvDrgWGB78PkFKcWgibcTCg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.56.0': - resolution: {integrity: sha512-Ga5zYrzH6vc/VFxhn6MmyUnYEfy9vRpwTIks99mY3j6Nz30yYpIkWryI0QKPCgvGUtDSXVLEaMum5nA+WrNOSg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - '@oxlint/binding-android-arm64@1.63.0': resolution: {integrity: sha512-SQo+ZMvdR9l3CxZp5W5gFNxSiDxclY6lOzzNpKYLF8asESpm3Pwumx0gER5T7aHLF1/2BAAtLD3DiDkdgy4V1A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.56.0': - resolution: {integrity: sha512-ogmbdJysnw/D4bDcpf1sPLpFThZ48lYp4aKYm10Z/6Nh1SON6NtnNhTNOlhEY296tDFItsZUz+2tgcSYqh8Eyw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - '@oxlint/binding-darwin-arm64@1.63.0': resolution: {integrity: sha512-6W82XjJDTmMnjg30427l0dufpnyLoq7wEukKdM6/g2VIybRVuQiBVh43EA4b+UxZ3+tLcKm+Or/pXGNgLCEU8g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.56.0': - resolution: {integrity: sha512-x8QE1h+RAtQ2g+3KPsP6Fk/tdz6zJQUv5c7fTrJxXV3GHOo+Ry5p/PsogU4U+iUZg0rj6hS+E4xi+mnwwlDCWQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - '@oxlint/binding-darwin-x64@1.63.0': resolution: {integrity: sha512-CnWd/YCuVG5W1BYkjJEVbJG11o526O9qAwBEQM+nh8K19CRFUkFdROXCyYkGmroHEYQe4vgQ6+lh3550Lp35Xw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.56.0': - resolution: {integrity: sha512-6G+WMZvwJpMvY7my+/SHEjb7BTk/PFbePqLpmVmUJRIsJMy/UlyYqjpuh0RCgYYkPLcnXm1rUM04kbTk8yS1Yg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - '@oxlint/binding-freebsd-x64@1.63.0': resolution: {integrity: sha512-a4eZAqrmtajqcxfdAzC+l7g3PaE3V8hpAYqqeD3fTxLXOMFdK3eNTZrU80n4dDEVm0JXy1aL5PqvqWldBl6zYA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.56.0': - resolution: {integrity: sha512-YYHBsk/sl7fYwQOok+6W5lBPeUEvisznV/HZD2IfZmF3Bns6cPC3Z0vCtSEOaAWTjYWN3jVsdu55jMxKlsdlhg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - '@oxlint/binding-linux-arm-gnueabihf@1.63.0': resolution: {integrity: sha512-tYUtU9TdbU3uXF5D62g5zXJ13iniFGhXQx5vp9cyEjGdbSAY3VdFBSaldYvyoDmgMZ0ZYuwQP1Y4t2Fhejwa0w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.56.0': - resolution: {integrity: sha512-+AZK8rOUr78y8WT6XkDb04IbMRqauNV+vgT6f8ZLOH8wnpQ9i7Nol0XLxAu+Cq7Sb+J9wC0j6Km5hG8rj47/yQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.63.0': resolution: {integrity: sha512-I5r3twFf776UZg9dmRo2xbrKt00tTkORXEVe0ctg4vdTkQvJAjiCHxnbAU2HL1AiJ9cqADA76MAliuilsAWnvg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.56.0': - resolution: {integrity: sha512-urse2SnugwJRojUkGSSeH2LPMaje5Q50yQtvtL9HFckiyeqXzoFwOAZqD5TR29R2lq7UHidfFDM9EGcchcbb8A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - '@oxlint/binding-linux-arm64-gnu@1.63.0': resolution: {integrity: sha512-t7ltUkg6FFh4b564QyGir8xIj/QZbXu8FlcRkcyW9+ztr/mfRHlvUOFd95pJCXi9s/L5DrUeWWgpXRS+V+6igQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4368,13 +4018,6 @@ packages: os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.56.0': - resolution: {integrity: sha512-rkTZkBfJ4TYLjansjSzL6mgZOdN5IvUnSq3oNJSLwBcNvy3dlgQtpHPrRxrCEbbcp7oQ6If0tkNaqfOsphYZ9g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - '@oxlint/binding-linux-arm64-musl@1.63.0': resolution: {integrity: sha512-Q5mmZy/XWjuYFUuQyYjOvZ5U/JkKEwnpir6hGxhh6HcdP0V/BKxLo8dqkfF/t7r7AguB17dfS/8+go5AQDRR6g==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4382,13 +4025,6 @@ packages: os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.56.0': - resolution: {integrity: sha512-uqL1kMH3u69/e1CH2EJhP3CP28jw2ExLsku4o8RVAZ7fySo9zOyI2fy9pVlTAp4voBLVgzndXi3SgtdyCTa2aA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - '@oxlint/binding-linux-ppc64-gnu@1.63.0': resolution: {integrity: sha512-uBGtuZ0TzLB4x5wVa82HGNvYqY8buwDhyCnCP0R0gkk9szqVsP0MeTtD5HX7EsEuFIt+aYmYxuxeVxs3nTSwtQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4396,13 +4032,6 @@ packages: os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.56.0': - resolution: {integrity: sha512-j0CcMBOgV6KsRaBdsebIeiy7hCjEvq2KdEsiULf2LZqAq0v1M1lWjelhCV57LxsqaIGChXFuFJ0RiFrSRHPhSg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.63.0': resolution: {integrity: sha512-h4s6FwxE+9MeA181o0dnDwHP32Y/bG8EiB/vrD6Ib+AMt6haigDc/0bUtI/sLmQDBMJnUfaCmtSSrEAqjtEVrA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4410,13 +4039,6 @@ packages: os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.56.0': - resolution: {integrity: sha512-7VDOiL8cDG3DQ/CY3yKjbV1c4YPvc4vH8qW09Vv+5ukq3l/Kcyr6XGCd5NvxUmxqDb2vjMpM+eW/4JrEEsUetA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [musl] - '@oxlint/binding-linux-riscv64-musl@1.63.0': resolution: {integrity: sha512-2EaNcCBR8Mcjl5ARtuN3BdEpVkX7KpjSjMGZ/mJMIeaXgTtdz5ytg2VwygMSStA/k0ixfvZFoZOfjDEcouV5vQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4424,13 +4046,6 @@ packages: os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.56.0': - resolution: {integrity: sha512-JGRpX0M+ikD3WpwJ7vKcHKV6Kg0dT52BW2Eu2BupXotYeqGXBrbY+QPkAyKO6MNgKozyTNaRh3r7g+VWgyAQYQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - '@oxlint/binding-linux-s390x-gnu@1.63.0': resolution: {integrity: sha512-p4hlf/fd7TrYYl3QrWWD0GocqJefwMu3cHQhmi2FvEB/YOvFb5DZN3SMBaPi7B1TM5DeypkEtrVib674q1KKPg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4438,13 +4053,6 @@ packages: os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.56.0': - resolution: {integrity: sha512-dNaICPvtmuxFP/VbqdofrLqdS3bM/AKJN3LMJD52si44ea7Be1cBk6NpfIahaysG9Uo+L98QKddU9CD5L8UHnQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.63.0': resolution: {integrity: sha512-Vgq9rkRVcPcjbcH+ihYTfpeR7vCXfqpd+z5ItTGc0yYUV59L5ceHYN1iV4H9bKGV7Rn5hkVc7x3mSvHegduENA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4452,13 +4060,6 @@ packages: os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.56.0': - resolution: {integrity: sha512-pF1vOtM+GuXmbklM1hV8WMsn6tCNPvkUzklj/Ej98JhlanbmA2RB1BILgOpwSuCTRTIYx2MXssmEyQQ90QF5aA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - '@oxlint/binding-linux-x64-musl@1.63.0': resolution: {integrity: sha512-3/Lkq/ncooA61rorrC+ZQed1Bc4VpGj+WnGsp58zmxKgvZ2vhreu+dcVyr3mX8NUpq7mfZ4gDDTou/yrF1Pd7A==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4466,48 +4067,24 @@ packages: os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.56.0': - resolution: {integrity: sha512-bp8NQ4RE6fDIFLa4bdBiOA+TAvkNkg+rslR+AvvjlLTYXLy9/uKAYLQudaQouWihLD/hgkrXIKKzXi5IXOewwg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - '@oxlint/binding-openharmony-arm64@1.63.0': resolution: {integrity: sha512-0/EdD/6hDkx5Mfd769PTjvEM8mZ/6Dfukp1dBCL/2PjlIVGEtYdNZyok6ChqYPsT9JcFnlQnUeQzO0/1L/oC9w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.56.0': - resolution: {integrity: sha512-PxT4OJDfMOQBzo3OlzFb9gkoSD+n8qSBxyVq2wQSZIHFQYGEqIRTo9M0ZStvZm5fdhMqaVYpOnJvH2hUMEDk/g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - '@oxlint/binding-win32-arm64-msvc@1.63.0': resolution: {integrity: sha512-wb0CUkN8ngwPiRQBjD1Cj0LsHeNvm+Xt6YBHDMtj2DVQVD6Oj8Ri7g6BD+KICf6LaBqZlmzOvy6nF9E/8yyGOg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.56.0': - resolution: {integrity: sha512-PTRy6sIEPqy2x8PTP1baBNReN/BNEFmde0L+mYeHmjXE1Vlcc9+I5nsqENsB2yAm5wLkzPoTNCMY/7AnabT4/A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.63.0': resolution: {integrity: sha512-BX5iq+ovdNlVYhSn5qPMUIT0uwAwt2lmEnCnzK+Gkhw4DovIvhGb96OFhV8yzQNUnQxn/xGkOR+X+BLrLDNm8w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.56.0': - resolution: {integrity: sha512-ZHa0clocjLmIDr+1LwoWtxRcoYniAvERotvwKUYKhH41NVfl0Y4LNbyQkwMZzwDvKklKGvGZ5+DAG58/Ik47tQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - '@oxlint/binding-win32-x64-msvc@1.63.0': resolution: {integrity: sha512-QeN/WELOfsXMeYwxvfgQrl6CbVftYUCZsGXHjXQd5Trccm8+i4gmtxaOui4xbJQaiDlviF8F3yLSBloQUeFsfA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4933,28 +4510,6 @@ packages: sass-embedded: optional: true - '@tsdown/css@0.21.4': - resolution: {integrity: sha512-2aU44SVyShHmL6VSefFBB0H8OXPqGqd6KwZ4+SP88DyyM+kZ1nBqzs65xf+HCyL/1NnidQtpA1wWkZLKgLv2SA==} - engines: {node: '>=20.19.0'} - peerDependencies: - postcss: ^8.4.0 - postcss-import: ^16.0.0 - postcss-modules: ^6.0.0 - sass: '*' - sass-embedded: '*' - tsdown: 0.21.4 - peerDependenciesMeta: - postcss: - optional: true - postcss-import: - optional: true - postcss-modules: - optional: true - sass: - optional: true - sass-embedded: - optional: true - '@tsdown/css@0.22.0': resolution: {integrity: sha512-gpkuNYVwgibCotNlHqgn1TJ9qHcE8Tim1rwaiQR7Ee9Rjb9BDYLypraaGMxqZgR1gr8NGRLGtbIv3eJtt5MHbQ==} engines: {node: ^22.18.0 || >=24.0.0} @@ -4983,12 +4538,6 @@ packages: peerDependencies: tsdown: 0.21.10 - '@tsdown/exe@0.21.4': - resolution: {integrity: sha512-aTniFeV/OjKa5Dxie4dbXar2wr3U+jKoascd+0XcK5uGBcadpzLUisks48QKRq7wTW+BF9N7cI0UyGGmEzHysg==} - engines: {node: '>=20.19.0'} - peerDependencies: - tsdown: 0.21.4 - '@tsdown/exe@0.22.0': resolution: {integrity: sha512-xOs2WOgB9R4J2PUfReZPK8h6IgbOXXuJ9JTQiAh3fK6Njhh219fRqPtSEHkNpYRccKYf4Tn0+Zum5AIFeOp7ZA==} engines: {node: ^22.18.0 || >=24.0.0} @@ -5362,201 +4911,78 @@ packages: peerDependencies: vite: workspace:@voidzero-dev/vite-plus-core@* - '@vitejs/release-scripts@1.7.0': - resolution: {integrity: sha512-4C+eoDs6yp/6kmnfOtuOWK+Dq0W3ws0eCs9k7w50P4YD7z+gMRUIyDbs0sGsJ4GjxN1WsS3qNfTT7ZpimtgeyA==} - - '@vitest/browser-playwright@4.1.5': - resolution: {integrity: sha512-CWy0lBQJq97nionyJJdnaU4961IXTl43a7UCu5nHy51IoKxAt6PVIJLo+76rVl7KOOgcWHNkG4kbJu/pW7knvA==} - peerDependencies: - playwright: '*' - vitest: workspace:@voidzero-dev/vite-plus-test@* - - '@vitest/browser-preview@4.1.5': - resolution: {integrity: sha512-UnUeV6/ykOOmrHjtQkOj01p+DZbJD18pNopACcEwt6NY1naL6L+caR+phpzTB6Mmgr5NL+2LDyrITGeTEmM9fQ==} - peerDependencies: - vitest: workspace:@voidzero-dev/vite-plus-test@* - - '@vitest/browser-webdriverio@4.1.5': - resolution: {integrity: sha512-irkLM1yClclWZL38CnklUsywd+DkJXHXys+BGOL4A9qiV2h1riSrXu1E7XVuGaxXvsJ55cUlVyV7x5mw3pDR6A==} - peerDependencies: - vitest: workspace:@voidzero-dev/vite-plus-test@* - webdriverio: '*' - - '@vitest/browser@4.1.5': - resolution: {integrity: sha512-iCDGI8c4yg+xmjUg2VsygdAUSIIB4x5Rht/P68OXy1hPELKXHDkzh87lkuTcdYmemRChDkEpB426MmDjzC0ziA==} - peerDependencies: - vitest: workspace:@voidzero-dev/vite-plus-test@* - - '@vitest/coverage-istanbul@4.1.5': - resolution: {integrity: sha512-X4kQMDEWh9mA0IiLuigtdYv4kXe+W8KLTbucoz15lbyZRPAxT5l+hu0JizI7Am050+G9vQnB7QJNgYi2LnwV4w==} - peerDependencies: - vitest: workspace:@voidzero-dev/vite-plus-test@* - - '@vitest/coverage-v8@4.1.5': - resolution: {integrity: sha512-38C0/Ddb7HcRG0Z4/DUem8x57d2p9jYgp18mkaYswEOQBGsI1CG4f/hjm0ZCeaJfWhSZ4k7jgs29V1Zom7Ki9A==} - peerDependencies: - '@vitest/browser': 4.1.5 - vitest: workspace:@voidzero-dev/vite-plus-test@* - peerDependenciesMeta: - '@vitest/browser': - optional: true - - '@vitest/expect@4.1.5': - resolution: {integrity: sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==} - - '@vitest/mocker@4.1.5': - resolution: {integrity: sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==} - peerDependencies: - msw: ^2.4.9 - vite: workspace:@voidzero-dev/vite-plus-core@* - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - - '@vitest/pretty-format@4.1.5': - resolution: {integrity: sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==} - - '@vitest/runner@4.1.5': - resolution: {integrity: sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==} - - '@vitest/snapshot@4.1.5': - resolution: {integrity: sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==} - - '@vitest/spy@4.1.5': - resolution: {integrity: sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==} - - '@vitest/ui@4.1.5': - resolution: {integrity: sha512-3Z9HNFiV0IF1fk0JPiK+7kE1GcaIPefQQIBYur6PM5yFIq6agys3uqP/0t966e1wXfmjbRCHDe7qW236Xjwnag==} - peerDependencies: - vitest: workspace:@voidzero-dev/vite-plus-test@* - - '@vitest/utils@4.1.5': - resolution: {integrity: sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==} - - '@voidzero-dev/vite-plus-core@0.1.13': - resolution: {integrity: sha512-72dAIYgGrrmh4ap5Tbvzo0EYCrmVRoPQjz3NERpZ34CWCjFB8+WAyBkxG631Jz9/qC1TR/ZThjOKbdYXQ5z9Aw==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - '@arethetypeswrong/core': ^0.18.1 - '@tsdown/css': 0.21.4 - '@tsdown/exe': 0.21.4 - '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.0 - esbuild: ^0.27.0 - jiti: '>=1.21.0' - less: ^4.0.0 - publint: ^0.3.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - typescript: ^5.0.0 - unplugin-unused: ^0.5.0 - yaml: ^2.4.2 - peerDependenciesMeta: - '@arethetypeswrong/core': - optional: true - '@tsdown/css': - optional: true - '@tsdown/exe': - optional: true - '@types/node': - optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true - jiti: - optional: true - less: - optional: true - publint: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - typescript: - optional: true - unplugin-unused: - optional: true - yaml: - optional: true + '@vitejs/release-scripts@1.7.0': + resolution: {integrity: sha512-4C+eoDs6yp/6kmnfOtuOWK+Dq0W3ws0eCs9k7w50P4YD7z+gMRUIyDbs0sGsJ4GjxN1WsS3qNfTT7ZpimtgeyA==} - '@voidzero-dev/vite-plus-darwin-arm64@0.1.13': - resolution: {integrity: sha512-GgQ5dW1VR/Vuc8cRDsdpLMdly2rHiq8ihNKIh1eu8hR85bDjDxE4DSXeadCDMWC0bHTjQiR1HqApzjoPYsVF/w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] + '@vitest/browser-playwright@4.1.5': + resolution: {integrity: sha512-CWy0lBQJq97nionyJJdnaU4961IXTl43a7UCu5nHy51IoKxAt6PVIJLo+76rVl7KOOgcWHNkG4kbJu/pW7knvA==} + peerDependencies: + playwright: '*' + vitest: 4.1.5 - '@voidzero-dev/vite-plus-darwin-x64@0.1.13': - resolution: {integrity: sha512-X4ZXbjIhNg5jxEkPVn7kJZEVIvNiOCWztrY67nHD94yqsWLy2Hs7yo+DhrpEQihsnlZ1hRRtwDirdCncvEulUg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] + '@vitest/browser-preview@4.1.5': + resolution: {integrity: sha512-UnUeV6/ykOOmrHjtQkOj01p+DZbJD18pNopACcEwt6NY1naL6L+caR+phpzTB6Mmgr5NL+2LDyrITGeTEmM9fQ==} + peerDependencies: + vitest: 4.1.5 - '@voidzero-dev/vite-plus-linux-arm64-gnu@0.1.13': - resolution: {integrity: sha512-oPtwztuF1cierDWA68beais5mwm6dXsmOOvccn6ZHjNpKXig84LvgIoY4bMazA3Z0SE9nWqxmP0kePiO5SoiuA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] + '@vitest/browser-webdriverio@4.1.5': + resolution: {integrity: sha512-irkLM1yClclWZL38CnklUsywd+DkJXHXys+BGOL4A9qiV2h1riSrXu1E7XVuGaxXvsJ55cUlVyV7x5mw3pDR6A==} + peerDependencies: + vitest: 4.1.5 + webdriverio: '*' - '@voidzero-dev/vite-plus-linux-x64-gnu@0.1.13': - resolution: {integrity: sha512-RgNHwTXrnYjt60K0g083VxOjaJNXHvZXViBQd/oC7RUwGUvxuHkraq/4mWaI69Pffx2KpyykxgCrtmhWq5Tgjg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] + '@vitest/browser@4.1.5': + resolution: {integrity: sha512-iCDGI8c4yg+xmjUg2VsygdAUSIIB4x5Rht/P68OXy1hPELKXHDkzh87lkuTcdYmemRChDkEpB426MmDjzC0ziA==} + peerDependencies: + vitest: 4.1.5 - '@voidzero-dev/vite-plus-test@0.1.13': - resolution: {integrity: sha512-P3n9adJZsaIUGlgbzyT2YvlA1yr2lCYhNjrZsiLAKMVyQzk2D++ptTre3SnYf9j1TQeMP1VonRXGjtZhTf8wHg==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + '@vitest/coverage-istanbul@4.1.5': + resolution: {integrity: sha512-X4kQMDEWh9mA0IiLuigtdYv4kXe+W8KLTbucoz15lbyZRPAxT5l+hu0JizI7Am050+G9vQnB7QJNgYi2LnwV4w==} peerDependencies: - '@edge-runtime/vm': '*' - '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/ui': 4.1.0 - happy-dom: '*' - jsdom: '*' - vite: workspace:@voidzero-dev/vite-plus-core@* + vitest: 4.1.5 + + '@vitest/coverage-v8@4.1.5': + resolution: {integrity: sha512-38C0/Ddb7HcRG0Z4/DUem8x57d2p9jYgp18mkaYswEOQBGsI1CG4f/hjm0ZCeaJfWhSZ4k7jgs29V1Zom7Ki9A==} + peerDependencies: + '@vitest/browser': 4.1.5 + vitest: 4.1.5 peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@opentelemetry/api': - optional: true - '@types/node': - optional: true - '@vitest/ui': + '@vitest/browser': optional: true - happy-dom: + + '@vitest/expect@4.1.5': + resolution: {integrity: sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==} + + '@vitest/mocker@4.1.5': + resolution: {integrity: sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==} + peerDependencies: + msw: ^2.4.9 + vite: workspace:@voidzero-dev/vite-plus-core@* + peerDependenciesMeta: + msw: optional: true - jsdom: + vite: optional: true - '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.13': - resolution: {integrity: sha512-+oygKTgglu0HkA4y9kFs8/BbHFsvShkHuL+8bK++Zek3x2ArKHRjCMgcYUXyj6nYufMIL2ba/Und7aHUK2ZGiQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] + '@vitest/pretty-format@4.1.5': + resolution: {integrity: sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==} - '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.13': - resolution: {integrity: sha512-+7zTnX/HqYCaBKmSLHjmCXQBRSSIJ6EFry55+4C0R4AMyayfn9w3LL0/NuVeCNkG69u3FnkRuwkqdWpzxztoHQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] + '@vitest/runner@4.1.5': + resolution: {integrity: sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==} + + '@vitest/snapshot@4.1.5': + resolution: {integrity: sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==} + + '@vitest/spy@4.1.5': + resolution: {integrity: sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==} + + '@vitest/ui@4.1.5': + resolution: {integrity: sha512-3Z9HNFiV0IF1fk0JPiK+7kE1GcaIPefQQIBYur6PM5yFIq6agys3uqP/0t966e1wXfmjbRCHDe7qW236Xjwnag==} + peerDependencies: + vitest: 4.1.5 + + '@vitest/utils@4.1.5': + resolution: {integrity: sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==} '@vue-macros/common@3.1.2': resolution: {integrity: sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==} @@ -7039,10 +6465,6 @@ packages: import-meta-resolve@4.2.0: resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} - import-without-cache@0.2.5: - resolution: {integrity: sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A==} - engines: {node: '>=20.19.0'} - import-without-cache@0.3.3: resolution: {integrity: sha512-bDxwDdF04gm550DfZHgffvlX+9kUlcz32UD0AeBTmVPFiWkrexF2XVmiuFFbDhiFuP8fQkrkvI2KdSNPYWAXkQ==} engines: {node: '>=20.19.0'} @@ -7743,34 +7165,15 @@ packages: resolution: {integrity: sha512-RGQZ5pnvWEQmtb51IavGp8mQqyQAB7J+N1TFuXxfQEHwfXinwAkhWPU/VffIIjjUgR63IbpWFAewqIVxnQP87w==} engines: {node: ^20.19.0 || >=22.12.0} - oxfmt@0.41.0: - resolution: {integrity: sha512-sKLdJZdQ3bw6x9qKiT7+eID4MNEXlDHf5ZacfIircrq6Qwjk0L6t2/JQlZZrVHTXJawK3KaMuBoJnEJPcqCEdg==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - oxfmt@0.48.0: resolution: {integrity: sha512-AVaLh+7XeGx+R1zfFV+f6VV61nT2MWVJXVUDhbTm5LBWGyNt64xAyh3NYYyjeY2WykNt9AvqSQLPHcbWquYF9g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - oxlint-tsgolint@0.17.1: - resolution: {integrity: sha512-gJc7hb1ZQFbWjRDYpu1XG+5IRdr1S/Jz/W2ohcpaqIXuDmHU0ujGiM0x05J0nIfwMF3HOEcANi/+j6T0Uecdpg==} - hasBin: true - oxlint-tsgolint@0.22.1: resolution: {integrity: sha512-YUSGSLUnoolsu8gxISEDio3q1rtsCozwfOzASUn3DT2mR2EeQ93uEEnen7s+6LpF+lyTQFln1pQfqwBh/fsVEg==} hasBin: true - oxlint@1.56.0: - resolution: {integrity: sha512-Q+5Mj5PVaH/R6/fhMMFzw4dT+KPB+kQW4kaL8FOIq7tfhlnEVp6+3lcWqFruuTNlUo9srZUW3qH7Id4pskeR6g==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - oxlint-tsgolint: '>=0.15.0' - peerDependenciesMeta: - oxlint-tsgolint: - optional: true - oxlint@1.63.0: resolution: {integrity: sha512-9TGXetdjgIHOJ9OiReomP7nnrMkV9HxC1xM2ramJSLQpzxjsAJtQwa4wqkJN2f/uCrqZuJseFuSlWDdvcruveg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7915,10 +7318,6 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} - pixelmatch@7.1.0: - resolution: {integrity: sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==} - hasBin: true - pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} @@ -8241,25 +7640,6 @@ packages: rgb2hex@0.2.5: resolution: {integrity: sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==} - rolldown-plugin-dts@0.22.5: - resolution: {integrity: sha512-M/HXfM4cboo+jONx9Z0X+CUf3B5tCi7ni+kR5fUW50Fp9AlZk0oVLesibGWgCXDKFp5lpgQ9yhKoImUFjl3VZw==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@ts-macro/tsc': ^0.3.6 - '@typescript/native-preview': '>=7.0.0-dev.20250601.1' - rolldown: workspace:rolldown@* - typescript: ^5.0.0 || ^6.0.0-beta - vue-tsc: ~3.2.0 - peerDependenciesMeta: - '@ts-macro/tsc': - optional: true - '@typescript/native-preview': - optional: true - typescript: - optional: true - vue-tsc: - optional: true - rolldown-plugin-dts@0.23.2: resolution: {integrity: sha512-PbSqLawLgZBGcOGT3yqWBGn4cX+wh2nt5FuBGdcMHyOhoukmjbhYAl8NT9sE4U38Cm9tqLOIQeOrvzeayM0DLQ==} engines: {node: '>=20.19.0'} @@ -8905,34 +8285,6 @@ packages: unplugin-unused: optional: true - tsdown@0.21.4: - resolution: {integrity: sha512-Q/kBi8SXkr4X6JI/NAZKZY1UuiEcbuXtIskL4tZCsgpDiEPM/2W6lC+OonNA31S+V3KsWedFvbFDBs23hvt+Aw==} - engines: {node: '>=20.19.0'} - hasBin: true - peerDependencies: - '@arethetypeswrong/core': ^0.18.1 - '@tsdown/css': 0.21.4 - '@tsdown/exe': 0.21.4 - '@vitejs/devtools': '*' - publint: ^0.3.0 - typescript: ^5.0.0 - unplugin-unused: ^0.5.0 - peerDependenciesMeta: - '@arethetypeswrong/core': - optional: true - '@tsdown/css': - optional: true - '@tsdown/exe': - optional: true - '@vitejs/devtools': - optional: true - publint: - optional: true - typescript: - optional: true - unplugin-unused: - optional: true - tsdown@0.22.0: resolution: {integrity: sha512-FgW0hHb27nGQA/+F3d5+U9wKXkfilk9DVkc5+7x/ZqF03g+Hoz/eeApT32jqxATt9eRoR+1jxk7MUMON+O4CXw==} engines: {node: ^22.18.0 || >=24.0.0} @@ -9249,11 +8601,6 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vite-plus@0.1.13: - resolution: {integrity: sha512-DP87+eRFhYYDdcjm2nr3DOKt0cv6mIXCNXn+zc59YHgR0Wh7uL2E/55mjusJ7ajwcXenpGW+c4KPeoqhQAbhxg==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - vitest@4.1.5: resolution: {integrity: sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -9519,7 +8866,8 @@ packages: snapshots: - '@acemir/cssom@0.9.24': {} + '@acemir/cssom@0.9.24': + optional: true '@adobe/css-tools@4.3.3': {} @@ -9543,6 +8891,7 @@ snapshots: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 lru-cache: 11.2.7 + optional: true '@asamuzakjp/dom-selector@6.7.4': dependencies: @@ -9551,8 +8900,10 @@ snapshots: css-tree: 3.1.0 is-potential-custom-element-name: 1.0.1 lru-cache: 11.2.7 + optional: true - '@asamuzakjp/nwsapi@2.3.9': {} + '@asamuzakjp/nwsapi@2.3.9': + optional: true '@ast-grep/napi-darwin-arm64@0.42.1': optional: true @@ -9629,16 +8980,6 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/generator@8.0.0-rc.2': - dependencies: - '@babel/parser': 8.0.0-rc.4 - '@babel/types': 8.0.0-rc.4 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - '@types/jsesc': 2.5.1 - jsesc: 3.1.0 - optional: true - '@babel/generator@8.0.0-rc.3': dependencies: '@babel/parser': 8.0.0-rc.4 @@ -9762,9 +9103,6 @@ snapshots: '@babel/helper-validator-identifier@7.28.5': {} - '@babel/helper-validator-identifier@8.0.0-rc.2': - optional: true - '@babel/helper-validator-identifier@8.0.0-rc.3': {} '@babel/helper-validator-identifier@8.0.0-rc.4': {} @@ -9788,11 +9126,6 @@ snapshots: dependencies: '@babel/types': 7.29.0 - '@babel/parser@8.0.0-rc.2': - dependencies: - '@babel/types': 8.0.0-rc.4 - optional: true - '@babel/parser@8.0.0-rc.3': dependencies: '@babel/types': 8.0.0-rc.4 @@ -10338,12 +9671,6 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@babel/types@8.0.0-rc.2': - dependencies: - '@babel/helper-string-parser': 8.0.0-rc.4 - '@babel/helper-validator-identifier': 8.0.0-rc.4 - optional: true - '@babel/types@8.0.0-rc.3': dependencies: '@babel/helper-string-parser': 8.0.0-rc.4 @@ -10354,7 +9681,8 @@ snapshots: '@babel/helper-string-parser': 8.0.0-rc.4 '@babel/helper-validator-identifier': 8.0.0-rc.4 - '@bcoe/v8-coverage@1.0.2': {} + '@bcoe/v8-coverage@1.0.2': + optional: true '@blazediff/core@1.9.1': {} @@ -10394,12 +9722,14 @@ snapshots: conventional-commits-filter: 5.0.0 conventional-commits-parser: 6.4.0 - '@csstools/color-helpers@5.1.0': {} + '@csstools/color-helpers@5.1.0': + optional: true '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 + optional: true '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: @@ -10407,20 +9737,26 @@ snapshots: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 + optional: true '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-tokenizer': 3.0.4 + optional: true - '@csstools/css-syntax-patches-for-csstree@1.0.17': {} + '@csstools/css-syntax-patches-for-csstree@1.0.17': + optional: true - '@csstools/css-tokenizer@3.0.4': {} + '@csstools/css-tokenizer@3.0.4': + optional: true - '@edge-runtime/primitives@6.0.0': {} + '@edge-runtime/primitives@6.0.0': + optional: true '@edge-runtime/vm@5.0.0': dependencies: '@edge-runtime/primitives': 6.0.0 + optional: true '@emnapi/core@1.10.0': dependencies: @@ -10931,7 +10267,8 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@istanbuljs/schema@0.1.3': {} + '@istanbuljs/schema@0.1.3': + optional: true '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -11451,7 +10788,8 @@ snapshots: '@octokit/request-error': 7.1.0 '@octokit/webhooks-methods': 6.0.0 - '@opentelemetry/api@1.9.0': {} + '@opentelemetry/api@1.9.0': + optional: true '@oxc-node/cli@0.1.0': dependencies: @@ -11727,12 +11065,8 @@ snapshots: '@oxc-parser/binding-win32-x64-msvc@0.129.0': optional: true - '@oxc-project/runtime@0.120.0': {} - '@oxc-project/runtime@0.129.0': {} - '@oxc-project/types@0.120.0': {} - '@oxc-project/types@0.121.0': {} '@oxc-project/types@0.126.0': {} @@ -11868,267 +11202,135 @@ snapshots: '@oxc-transform/binding-win32-x64-msvc@0.129.0': optional: true - '@oxfmt/binding-android-arm-eabi@0.41.0': - optional: true - '@oxfmt/binding-android-arm-eabi@0.48.0': optional: true - '@oxfmt/binding-android-arm64@0.41.0': - optional: true - '@oxfmt/binding-android-arm64@0.48.0': optional: true - '@oxfmt/binding-darwin-arm64@0.41.0': - optional: true - '@oxfmt/binding-darwin-arm64@0.48.0': optional: true - '@oxfmt/binding-darwin-x64@0.41.0': - optional: true - '@oxfmt/binding-darwin-x64@0.48.0': optional: true - '@oxfmt/binding-freebsd-x64@0.41.0': - optional: true - '@oxfmt/binding-freebsd-x64@0.48.0': optional: true - '@oxfmt/binding-linux-arm-gnueabihf@0.41.0': - optional: true - '@oxfmt/binding-linux-arm-gnueabihf@0.48.0': optional: true - '@oxfmt/binding-linux-arm-musleabihf@0.41.0': - optional: true - '@oxfmt/binding-linux-arm-musleabihf@0.48.0': optional: true - '@oxfmt/binding-linux-arm64-gnu@0.41.0': - optional: true - '@oxfmt/binding-linux-arm64-gnu@0.48.0': optional: true - '@oxfmt/binding-linux-arm64-musl@0.41.0': - optional: true - '@oxfmt/binding-linux-arm64-musl@0.48.0': optional: true - '@oxfmt/binding-linux-ppc64-gnu@0.41.0': - optional: true - '@oxfmt/binding-linux-ppc64-gnu@0.48.0': optional: true - '@oxfmt/binding-linux-riscv64-gnu@0.41.0': - optional: true - '@oxfmt/binding-linux-riscv64-gnu@0.48.0': optional: true - '@oxfmt/binding-linux-riscv64-musl@0.41.0': - optional: true - '@oxfmt/binding-linux-riscv64-musl@0.48.0': optional: true - '@oxfmt/binding-linux-s390x-gnu@0.41.0': - optional: true - '@oxfmt/binding-linux-s390x-gnu@0.48.0': optional: true - '@oxfmt/binding-linux-x64-gnu@0.41.0': - optional: true - '@oxfmt/binding-linux-x64-gnu@0.48.0': optional: true - '@oxfmt/binding-linux-x64-musl@0.41.0': - optional: true - '@oxfmt/binding-linux-x64-musl@0.48.0': optional: true - '@oxfmt/binding-openharmony-arm64@0.41.0': - optional: true - '@oxfmt/binding-openharmony-arm64@0.48.0': optional: true - '@oxfmt/binding-win32-arm64-msvc@0.41.0': - optional: true - '@oxfmt/binding-win32-arm64-msvc@0.48.0': optional: true - '@oxfmt/binding-win32-ia32-msvc@0.41.0': - optional: true - '@oxfmt/binding-win32-ia32-msvc@0.48.0': optional: true - '@oxfmt/binding-win32-x64-msvc@0.41.0': - optional: true - '@oxfmt/binding-win32-x64-msvc@0.48.0': optional: true - '@oxlint-tsgolint/darwin-arm64@0.17.1': - optional: true - '@oxlint-tsgolint/darwin-arm64@0.22.1': optional: true - '@oxlint-tsgolint/darwin-x64@0.17.1': - optional: true - '@oxlint-tsgolint/darwin-x64@0.22.1': optional: true - '@oxlint-tsgolint/linux-arm64@0.17.1': - optional: true - '@oxlint-tsgolint/linux-arm64@0.22.1': optional: true - '@oxlint-tsgolint/linux-x64@0.17.1': - optional: true - '@oxlint-tsgolint/linux-x64@0.22.1': optional: true - '@oxlint-tsgolint/win32-arm64@0.17.1': - optional: true - '@oxlint-tsgolint/win32-arm64@0.22.1': optional: true - '@oxlint-tsgolint/win32-x64@0.17.1': - optional: true - '@oxlint-tsgolint/win32-x64@0.22.1': optional: true - '@oxlint/binding-android-arm-eabi@1.56.0': - optional: true - '@oxlint/binding-android-arm-eabi@1.63.0': optional: true - '@oxlint/binding-android-arm64@1.56.0': - optional: true - '@oxlint/binding-android-arm64@1.63.0': optional: true - '@oxlint/binding-darwin-arm64@1.56.0': - optional: true - - '@oxlint/binding-darwin-arm64@1.63.0': - optional: true - - '@oxlint/binding-darwin-x64@1.56.0': - optional: true - - '@oxlint/binding-darwin-x64@1.63.0': - optional: true - - '@oxlint/binding-freebsd-x64@1.56.0': + '@oxlint/binding-darwin-arm64@1.63.0': optional: true - '@oxlint/binding-freebsd-x64@1.63.0': + '@oxlint/binding-darwin-x64@1.63.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.56.0': + '@oxlint/binding-freebsd-x64@1.63.0': optional: true '@oxlint/binding-linux-arm-gnueabihf@1.63.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.56.0': - optional: true - '@oxlint/binding-linux-arm-musleabihf@1.63.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.56.0': - optional: true - '@oxlint/binding-linux-arm64-gnu@1.63.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.56.0': - optional: true - '@oxlint/binding-linux-arm64-musl@1.63.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.56.0': - optional: true - '@oxlint/binding-linux-ppc64-gnu@1.63.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.56.0': - optional: true - '@oxlint/binding-linux-riscv64-gnu@1.63.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.56.0': - optional: true - '@oxlint/binding-linux-riscv64-musl@1.63.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.56.0': - optional: true - '@oxlint/binding-linux-s390x-gnu@1.63.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.56.0': - optional: true - '@oxlint/binding-linux-x64-gnu@1.63.0': optional: true - '@oxlint/binding-linux-x64-musl@1.56.0': - optional: true - '@oxlint/binding-linux-x64-musl@1.63.0': optional: true - '@oxlint/binding-openharmony-arm64@1.56.0': - optional: true - '@oxlint/binding-openharmony-arm64@1.63.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.56.0': - optional: true - '@oxlint/binding-win32-arm64-msvc@1.63.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.56.0': - optional: true - '@oxlint/binding-win32-ia32-msvc@1.63.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.56.0': - optional: true - '@oxlint/binding-win32-x64-msvc@1.63.0': optional: true @@ -12469,24 +11671,6 @@ snapshots: - yaml optional: true - '@tsdown/css@0.21.4(jiti@2.6.1)(postcss-import@16.1.1(postcss@8.5.14))(postcss-modules@6.0.1(postcss@8.5.14))(postcss@8.5.14)(sass-embedded@1.99.0(source-map-js@1.2.1))(sass@1.99.0)(tsdown@0.21.4)(tsx@4.21.0)(yaml@2.8.2)': - dependencies: - lightningcss: 1.32.0 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.14)(tsx@4.21.0)(yaml@2.8.2) - rolldown: link:rolldown/packages/rolldown - tsdown: 0.21.4(@arethetypeswrong/core@0.18.2)(@tsdown/css@0.21.4)(@tsdown/exe@0.21.4)(@typescript/native-preview@7.0.0-dev.20260122.2)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(publint@0.3.19)(typescript@6.0.2)(unplugin-unused@0.5.6) - optionalDependencies: - postcss: 8.5.14 - postcss-import: 16.1.1(postcss@8.5.14) - postcss-modules: 6.0.1(postcss@8.5.14) - sass: 1.99.0 - sass-embedded: 1.99.0(source-map-js@1.2.1) - transitivePeerDependencies: - - jiti - - tsx - - yaml - optional: true - '@tsdown/css@0.22.0(jiti@2.6.1)(postcss-import@16.1.1(postcss@8.5.14))(postcss-modules@6.0.1(postcss@8.5.14))(postcss@8.5.14)(sass-embedded@1.99.0(source-map-js@1.2.1))(sass@1.99.0)(tsdown@0.22.0)(tsx@4.21.0)(yaml@2.8.2)': dependencies: lightningcss: 1.32.0 @@ -12512,14 +11696,6 @@ snapshots: tsdown: 0.21.10(@arethetypeswrong/core@0.18.2)(@tsdown/css@0.21.10)(@tsdown/exe@0.21.10)(@typescript/native-preview@7.0.0-dev.20260122.2)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(publint@0.3.19)(typescript@6.0.2)(unplugin-unused@0.5.6) optional: true - '@tsdown/exe@0.21.4(tsdown@0.21.4)': - dependencies: - obug: 2.1.1 - semver: 7.7.4 - tinyexec: 1.1.2 - tsdown: 0.21.4(@arethetypeswrong/core@0.18.2)(@tsdown/css@0.21.4)(@tsdown/exe@0.21.4)(@typescript/native-preview@7.0.0-dev.20260122.2)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(publint@0.3.19)(typescript@6.0.2)(unplugin-unused@0.5.6) - optional: true - '@tsdown/exe@0.22.0(tsdown@0.22.0)': dependencies: obug: 2.1.1 @@ -12661,7 +11837,8 @@ snapshots: '@types/validate-npm-package-name@4.0.2': {} - '@types/whatwg-mimetype@3.0.2': {} + '@types/whatwg-mimetype@3.0.2': + optional: true '@types/which@2.0.2': {} @@ -13003,7 +12180,7 @@ snapshots: '@vitest/mocker': 4.1.5(vite@packages+core) playwright: 1.57.0 tinyrainbow: 3.1.0 - vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5(playwright@1.57.0)(vite@packages+core)(vitest@4.1.5))(@vitest/browser-preview@4.1.5(vite@packages+core)(vitest@4.1.5))(@vitest/browser-webdriverio@4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1))(@vitest/coverage-istanbul@4.1.5(vitest@4.1.5))(@vitest/coverage-v8@4.1.5(@vitest/browser@4.1.5)(vitest@4.1.5))(@vitest/ui@4.1.5(vitest@4.1.5))(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) + vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.3)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) transitivePeerDependencies: - bufferutil - msw @@ -13015,7 +12192,7 @@ snapshots: '@testing-library/dom': 10.4.1 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) '@vitest/browser': 4.1.5(vite@packages+core)(vitest@4.1.5) - vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5(playwright@1.57.0)(vite@packages+core)(vitest@4.1.5))(@vitest/browser-preview@4.1.5(vite@packages+core)(vitest@4.1.5))(@vitest/browser-webdriverio@4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1))(@vitest/coverage-istanbul@4.1.5(vitest@4.1.5))(@vitest/coverage-v8@4.1.5(@vitest/browser@4.1.5)(vitest@4.1.5))(@vitest/ui@4.1.5(vitest@4.1.5))(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) + vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.3)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) transitivePeerDependencies: - bufferutil - msw @@ -13025,7 +12202,7 @@ snapshots: '@vitest/browser-webdriverio@4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1)': dependencies: '@vitest/browser': 4.1.5(vite@packages+core)(vitest@4.1.5) - vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5(playwright@1.57.0)(vite@packages+core)(vitest@4.1.5))(@vitest/browser-preview@4.1.5(vite@packages+core)(vitest@4.1.5))(@vitest/browser-webdriverio@4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1))(@vitest/coverage-istanbul@4.1.5(vitest@4.1.5))(@vitest/coverage-v8@4.1.5(@vitest/browser@4.1.5)(vitest@4.1.5))(@vitest/ui@4.1.5(vitest@4.1.5))(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) + vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.3)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) webdriverio: 9.20.1 transitivePeerDependencies: - bufferutil @@ -13042,7 +12219,7 @@ snapshots: pngjs: 7.0.0 sirv: 3.0.2(patch_hash=c07c56eb72faea34341d465cde2314e89db472106ed378181e3447893af6bf95) tinyrainbow: 3.1.0 - vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5(playwright@1.57.0)(vite@packages+core)(vitest@4.1.5))(@vitest/browser-preview@4.1.5(vite@packages+core)(vitest@4.1.5))(@vitest/browser-webdriverio@4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1))(@vitest/coverage-istanbul@4.1.5(vitest@4.1.5))(@vitest/coverage-v8@4.1.5(@vitest/browser@4.1.5)(vitest@4.1.5))(@vitest/ui@4.1.5(vitest@4.1.5))(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) + vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.3)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) ws: 8.20.0 transitivePeerDependencies: - bufferutil @@ -13062,9 +12239,10 @@ snapshots: magicast: 0.5.2 obug: 2.1.1 tinyrainbow: 3.1.0 - vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5(playwright@1.57.0)(vite@packages+core)(vitest@4.1.5))(@vitest/browser-preview@4.1.5(vite@packages+core)(vitest@4.1.5))(@vitest/browser-webdriverio@4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1))(@vitest/coverage-istanbul@4.1.5(vitest@4.1.5))(@vitest/coverage-v8@4.1.5(@vitest/browser@4.1.5)(vitest@4.1.5))(@vitest/ui@4.1.5(vitest@4.1.5))(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) + vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.3)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) transitivePeerDependencies: - supports-color + optional: true '@vitest/coverage-v8@4.1.5(@vitest/browser@4.1.5)(vitest@4.1.5)': dependencies: @@ -13078,9 +12256,10 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.1.0 - vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5(playwright@1.57.0)(vite@packages+core)(vitest@4.1.5))(@vitest/browser-preview@4.1.5(vite@packages+core)(vitest@4.1.5))(@vitest/browser-webdriverio@4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1))(@vitest/coverage-istanbul@4.1.5(vitest@4.1.5))(@vitest/coverage-v8@4.1.5(@vitest/browser@4.1.5)(vitest@4.1.5))(@vitest/ui@4.1.5(vitest@4.1.5))(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) + vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.3)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) optionalDependencies: '@vitest/browser': 4.1.5(vite@packages+core)(vitest@4.1.5) + optional: true '@vitest/expect@4.1.5': dependencies: @@ -13126,7 +12305,8 @@ snapshots: sirv: 3.0.2(patch_hash=c07c56eb72faea34341d465cde2314e89db472106ed378181e3447893af6bf95) tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5(playwright@1.57.0)(vite@packages+core)(vitest@4.1.5))(@vitest/browser-preview@4.1.5(vite@packages+core)(vitest@4.1.5))(@vitest/browser-webdriverio@4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1))(@vitest/coverage-istanbul@4.1.5(vitest@4.1.5))(@vitest/coverage-v8@4.1.5(@vitest/browser@4.1.5)(vitest@4.1.5))(@vitest/ui@4.1.5(vitest@4.1.5))(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) + vitest: 4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.3)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) + optional: true '@vitest/utils@4.1.5': dependencies: @@ -13134,94 +12314,6 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - '@voidzero-dev/vite-plus-core@0.1.13(@arethetypeswrong/core@0.18.2)(@tsdown/css@0.21.4)(@tsdown/exe@0.21.4)(@types/node@24.10.3)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(publint@0.3.19)(sass-embedded@1.99.0(source-map-js@1.2.1))(sass@1.99.0)(stylus@0.64.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.46.2)(tsx@4.21.0)(typescript@6.0.2)(unplugin-unused@0.5.6)(yaml@2.8.2)': - dependencies: - '@oxc-project/runtime': 0.120.0 - '@oxc-project/types': 0.120.0 - lightningcss: 1.32.0 - postcss: 8.5.14 - optionalDependencies: - '@arethetypeswrong/core': 0.18.2 - '@tsdown/css': 0.21.4(jiti@2.6.1)(postcss-import@16.1.1(postcss@8.5.14))(postcss-modules@6.0.1(postcss@8.5.14))(postcss@8.5.14)(sass-embedded@1.99.0(source-map-js@1.2.1))(sass@1.99.0)(tsdown@0.21.4)(tsx@4.21.0)(yaml@2.8.2) - '@tsdown/exe': 0.21.4(tsdown@0.21.4) - '@types/node': 24.10.3 - '@vitejs/devtools': 0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core) - esbuild: 0.27.4 - fsevents: 2.3.3 - jiti: 2.6.1 - less: 4.4.2 - publint: 0.3.19 - sass: 1.99.0 - sass-embedded: 1.99.0(source-map-js@1.2.1) - stylus: 0.64.0 - sugarss: 5.0.1(postcss@8.5.14) - terser: 5.46.2 - tsx: 4.21.0 - typescript: 6.0.2 - unplugin-unused: 0.5.6 - yaml: 2.8.2 - - '@voidzero-dev/vite-plus-darwin-arm64@0.1.13': - optional: true - - '@voidzero-dev/vite-plus-darwin-x64@0.1.13': - optional: true - - '@voidzero-dev/vite-plus-linux-arm64-gnu@0.1.13': - optional: true - - '@voidzero-dev/vite-plus-linux-x64-gnu@0.1.13': - optional: true - - '@voidzero-dev/vite-plus-test@0.1.13(@arethetypeswrong/core@0.18.2)(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@tsdown/css@0.21.4)(@tsdown/exe@0.21.4)(@types/node@24.10.3)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(esbuild@0.27.4)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.2.0)(less@4.4.2)(publint@0.3.19)(sass-embedded@1.99.0(source-map-js@1.2.1))(sass@1.99.0)(stylus@0.64.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.46.2)(tsx@4.21.0)(typescript@6.0.2)(unplugin-unused@0.5.6)(vite@packages+core)(yaml@2.8.2)': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@voidzero-dev/vite-plus-core': 0.1.13(@arethetypeswrong/core@0.18.2)(@tsdown/css@0.21.4)(@tsdown/exe@0.21.4)(@types/node@24.10.3)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(publint@0.3.19)(sass-embedded@1.99.0(source-map-js@1.2.1))(sass@1.99.0)(stylus@0.64.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.46.2)(tsx@4.21.0)(typescript@6.0.2)(unplugin-unused@0.5.6)(yaml@2.8.2) - es-module-lexer: 1.7.0 - obug: 2.1.1 - pixelmatch: 7.1.0 - pngjs: 7.0.0 - sirv: 3.0.2(patch_hash=c07c56eb72faea34341d465cde2314e89db472106ed378181e3447893af6bf95) - std-env: 4.0.0 - tinybench: 2.9.0 - tinyexec: 1.1.2 - tinyglobby: 0.2.16 - vite: link:packages/core - ws: 8.20.0 - optionalDependencies: - '@edge-runtime/vm': 5.0.0 - '@opentelemetry/api': 1.9.0 - '@types/node': 24.10.3 - happy-dom: 20.0.10 - jsdom: 27.2.0 - transitivePeerDependencies: - - '@arethetypeswrong/core' - - '@tsdown/css' - - '@tsdown/exe' - - '@vitejs/devtools' - - bufferutil - - esbuild - - jiti - - less - - publint - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - typescript - - unplugin-unused - - utf-8-validate - - yaml - - '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.13': - optional: true - - '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.13': - optional: true - '@vue-macros/common@3.1.2(vue@3.5.34(typescript@6.0.2))': dependencies: '@vue/compiler-sfc': 3.5.34 @@ -13513,6 +12605,7 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 js-tokens: 10.0.0 + optional: true ast-walker-scope@0.8.3: dependencies: @@ -13601,6 +12694,7 @@ snapshots: bidi-js@1.0.3: dependencies: require-from-string: 2.0.2 + optional: true binary-extensions@2.3.0: {} @@ -13954,6 +13048,7 @@ snapshots: dependencies: mdn-data: 2.12.2 source-map-js: 1.2.1 + optional: true css-value@0.0.1: {} @@ -13966,6 +13061,7 @@ snapshots: '@asamuzakjp/css-color': 4.1.0 '@csstools/css-syntax-patches-for-csstree': 1.0.17 css-tree: 3.1.0 + optional: true csstype@3.2.3: {} @@ -13983,6 +13079,7 @@ snapshots: dependencies: whatwg-mimetype: 4.0.0 whatwg-url: 15.1.0 + optional: true debug@2.6.9: dependencies: @@ -13998,7 +13095,8 @@ snapshots: decamelize@6.0.1: {} - decimal.js@10.6.0: {} + decimal.js@10.6.0: + optional: true decircular@0.1.1: {} @@ -14728,6 +13826,7 @@ snapshots: '@types/node': 20.19.25 '@types/whatwg-mimetype': 3.0.2 whatwg-mimetype: 3.0.0 + optional: true has-flag@3.0.0: {} @@ -14763,8 +13862,10 @@ snapshots: html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 + optional: true - html-escaper@2.0.2: {} + html-escaper@2.0.2: + optional: true htmlfy@0.8.1: {} @@ -14842,9 +13943,6 @@ snapshots: import-meta-resolve@4.2.0: {} - import-without-cache@0.2.5: - optional: true - import-without-cache@0.3.3: {} import-without-cache@0.4.0: {} @@ -14905,7 +14003,8 @@ snapshots: is-plain-obj@4.1.0: {} - is-potential-custom-element-name@1.0.1: {} + is-potential-custom-element-name@1.0.1: + optional: true is-reference@1.2.1: dependencies: @@ -14945,18 +14044,21 @@ snapshots: isexe@3.1.1: {} - istanbul-lib-coverage@3.2.2: {} + istanbul-lib-coverage@3.2.2: + optional: true istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 make-dir: 4.0.0 supports-color: 7.2.0 + optional: true istanbul-reports@3.2.0: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 + optional: true jackspeak@3.4.3: dependencies: @@ -14966,7 +14068,8 @@ snapshots: jiti@2.6.1: {} - js-tokens@10.0.0: {} + js-tokens@10.0.0: + optional: true js-tokens@4.0.0: {} @@ -15009,6 +14112,7 @@ snapshots: - bufferutil - supports-color - utf-8-validate + optional: true jsesc@0.5.0: {} @@ -15257,6 +14361,7 @@ snapshots: '@babel/parser': 7.29.3 '@babel/types': 7.29.0 source-map-js: 1.2.1 + optional: true make-dir@2.1.0: dependencies: @@ -15267,13 +14372,15 @@ snapshots: make-dir@4.0.0: dependencies: semver: 7.7.4 + optional: true matcher-collection@2.0.1: dependencies: '@types/minimatch': 3.0.5 minimatch: 3.1.5 - mdn-data@2.12.2: {} + mdn-data@2.12.2: + optional: true meow@13.2.0: {} @@ -15631,30 +14738,6 @@ snapshots: '@oxc-transform/binding-win32-ia32-msvc': 0.129.0 '@oxc-transform/binding-win32-x64-msvc': 0.129.0 - oxfmt@0.41.0: - dependencies: - tinypool: 2.1.0 - optionalDependencies: - '@oxfmt/binding-android-arm-eabi': 0.41.0 - '@oxfmt/binding-android-arm64': 0.41.0 - '@oxfmt/binding-darwin-arm64': 0.41.0 - '@oxfmt/binding-darwin-x64': 0.41.0 - '@oxfmt/binding-freebsd-x64': 0.41.0 - '@oxfmt/binding-linux-arm-gnueabihf': 0.41.0 - '@oxfmt/binding-linux-arm-musleabihf': 0.41.0 - '@oxfmt/binding-linux-arm64-gnu': 0.41.0 - '@oxfmt/binding-linux-arm64-musl': 0.41.0 - '@oxfmt/binding-linux-ppc64-gnu': 0.41.0 - '@oxfmt/binding-linux-riscv64-gnu': 0.41.0 - '@oxfmt/binding-linux-riscv64-musl': 0.41.0 - '@oxfmt/binding-linux-s390x-gnu': 0.41.0 - '@oxfmt/binding-linux-x64-gnu': 0.41.0 - '@oxfmt/binding-linux-x64-musl': 0.41.0 - '@oxfmt/binding-openharmony-arm64': 0.41.0 - '@oxfmt/binding-win32-arm64-msvc': 0.41.0 - '@oxfmt/binding-win32-ia32-msvc': 0.41.0 - '@oxfmt/binding-win32-x64-msvc': 0.41.0 - oxfmt@0.48.0: dependencies: tinypool: 2.1.0 @@ -15679,15 +14762,6 @@ snapshots: '@oxfmt/binding-win32-ia32-msvc': 0.48.0 '@oxfmt/binding-win32-x64-msvc': 0.48.0 - oxlint-tsgolint@0.17.1: - optionalDependencies: - '@oxlint-tsgolint/darwin-arm64': 0.17.1 - '@oxlint-tsgolint/darwin-x64': 0.17.1 - '@oxlint-tsgolint/linux-arm64': 0.17.1 - '@oxlint-tsgolint/linux-x64': 0.17.1 - '@oxlint-tsgolint/win32-arm64': 0.17.1 - '@oxlint-tsgolint/win32-x64': 0.17.1 - oxlint-tsgolint@0.22.1: optionalDependencies: '@oxlint-tsgolint/darwin-arm64': 0.22.1 @@ -15697,29 +14771,6 @@ snapshots: '@oxlint-tsgolint/win32-arm64': 0.22.1 '@oxlint-tsgolint/win32-x64': 0.22.1 - oxlint@1.56.0(oxlint-tsgolint@0.17.1): - optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.56.0 - '@oxlint/binding-android-arm64': 1.56.0 - '@oxlint/binding-darwin-arm64': 1.56.0 - '@oxlint/binding-darwin-x64': 1.56.0 - '@oxlint/binding-freebsd-x64': 1.56.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.56.0 - '@oxlint/binding-linux-arm-musleabihf': 1.56.0 - '@oxlint/binding-linux-arm64-gnu': 1.56.0 - '@oxlint/binding-linux-arm64-musl': 1.56.0 - '@oxlint/binding-linux-ppc64-gnu': 1.56.0 - '@oxlint/binding-linux-riscv64-gnu': 1.56.0 - '@oxlint/binding-linux-riscv64-musl': 1.56.0 - '@oxlint/binding-linux-s390x-gnu': 1.56.0 - '@oxlint/binding-linux-x64-gnu': 1.56.0 - '@oxlint/binding-linux-x64-musl': 1.56.0 - '@oxlint/binding-openharmony-arm64': 1.56.0 - '@oxlint/binding-win32-arm64-msvc': 1.56.0 - '@oxlint/binding-win32-ia32-msvc': 1.56.0 - '@oxlint/binding-win32-x64-msvc': 1.56.0 - oxlint-tsgolint: 0.17.1 - oxlint@1.63.0(oxlint-tsgolint@0.22.1): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.63.0 @@ -15873,10 +14924,6 @@ snapshots: pirates@4.0.7: {} - pixelmatch@7.1.0: - dependencies: - pngjs: 7.0.0 - pkg-types@1.3.1: dependencies: confbox: 0.1.8 @@ -16167,7 +15214,8 @@ snapshots: require-directory@2.1.1: {} - require-from-string@2.0.2: {} + require-from-string@2.0.2: + optional: true resolve-from@4.0.0: {} @@ -16198,25 +15246,6 @@ snapshots: rgb2hex@0.2.5: {} - rolldown-plugin-dts@0.22.5(@typescript/native-preview@7.0.0-dev.20260122.2)(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(rolldown@rolldown+packages+rolldown)(typescript@6.0.2): - dependencies: - '@babel/generator': 8.0.0-rc.2 - '@babel/helper-validator-identifier': 8.0.0-rc.2 - '@babel/parser': 8.0.0-rc.2 - '@babel/types': 8.0.0-rc.2 - ast-kit: 3.0.0-beta.1 - birpc: 4.0.0 - dts-resolver: 2.1.3(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)) - get-tsconfig: 4.13.7 - obug: 2.1.1 - rolldown: link:rolldown/packages/rolldown - optionalDependencies: - '@typescript/native-preview': 7.0.0-dev.20260122.2 - typescript: 6.0.2 - transitivePeerDependencies: - - oxc-resolver - optional: true - rolldown-plugin-dts@0.23.2(@typescript/native-preview@7.0.0-dev.20260122.2)(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(rolldown@rolldown+packages+rolldown)(typescript@6.0.2): dependencies: '@babel/generator': 8.0.0-rc.3 @@ -16442,6 +15471,7 @@ snapshots: saxes@6.0.0: dependencies: xmlchars: 2.2.0 + optional: true scheduler@0.27.0: {} @@ -16714,7 +15744,8 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - symbol-tree@3.2.4: {} + symbol-tree@3.2.4: + optional: true sync-child-process@1.0.2: dependencies: @@ -16777,11 +15808,13 @@ snapshots: tinyrainbow@3.1.0: {} - tldts-core@7.0.19: {} + tldts-core@7.0.19: + optional: true tldts@7.0.19: dependencies: tldts-core: 7.0.19 + optional: true to-regex-range@5.0.1: dependencies: @@ -16796,10 +15829,12 @@ snapshots: tough-cookie@6.0.0: dependencies: tldts: 7.0.19 + optional: true tr46@6.0.0: dependencies: punycode: 2.3.1 + optional: true tree-kill@1.2.2: {} @@ -16845,40 +15880,6 @@ snapshots: - synckit - vue-tsc - tsdown@0.21.4(@arethetypeswrong/core@0.18.2)(@tsdown/css@0.21.4)(@tsdown/exe@0.21.4)(@typescript/native-preview@7.0.0-dev.20260122.2)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(publint@0.3.19)(typescript@6.0.2)(unplugin-unused@0.5.6): - dependencies: - ansis: 4.2.0 - cac: 7.0.0 - defu: 6.1.7 - empathic: 2.0.0 - hookable: 6.1.1 - import-without-cache: 0.2.5 - obug: 2.1.1 - picomatch: 4.0.4 - rolldown: link:rolldown/packages/rolldown - rolldown-plugin-dts: 0.22.5(@typescript/native-preview@7.0.0-dev.20260122.2)(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(rolldown@rolldown+packages+rolldown)(typescript@6.0.2) - semver: 7.7.4 - tinyexec: 1.1.2 - tinyglobby: 0.2.16 - tree-kill: 1.2.2 - unconfig-core: 7.5.0 - unrun: 0.2.37 - optionalDependencies: - '@arethetypeswrong/core': 0.18.2 - '@tsdown/css': 0.21.4(jiti@2.6.1)(postcss-import@16.1.1(postcss@8.5.14))(postcss-modules@6.0.1(postcss@8.5.14))(postcss@8.5.14)(sass-embedded@1.99.0(source-map-js@1.2.1))(sass@1.99.0)(tsdown@0.21.4)(tsx@4.21.0)(yaml@2.8.2) - '@tsdown/exe': 0.21.4(tsdown@0.21.4) - '@vitejs/devtools': 0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core) - publint: 0.3.19 - typescript: 6.0.2 - unplugin-unused: 0.5.6 - transitivePeerDependencies: - - '@ts-macro/tsc' - - '@typescript/native-preview' - - oxc-resolver - - synckit - - vue-tsc - optional: true - tsdown@0.22.0(@arethetypeswrong/core@0.18.2)(@tsdown/css@0.22.0)(@tsdown/exe@0.22.0)(@typescript/native-preview@7.0.0-dev.20260122.2)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(publint@0.3.19)(tsx@4.21.0)(typescript@6.0.2)(unplugin-unused@0.5.6)(unrun@0.2.37): dependencies: ansis: 4.2.0 @@ -17117,53 +16118,44 @@ snapshots: vary@1.1.2: {} - vite-plus@0.1.13(@arethetypeswrong/core@0.18.2)(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@tsdown/css@0.21.4)(@tsdown/exe@0.21.4)(@types/node@24.10.3)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(esbuild@0.27.4)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.2.0)(less@4.4.2)(publint@0.3.19)(sass-embedded@1.99.0(source-map-js@1.2.1))(sass@1.99.0)(stylus@0.64.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.46.2)(tsx@4.21.0)(typescript@6.0.2)(unplugin-unused@0.5.6)(vite@packages+core)(yaml@2.8.2): + vitest@4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.3)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core): dependencies: - '@oxc-project/types': 0.120.0 - '@voidzero-dev/vite-plus-core': 0.1.13(@arethetypeswrong/core@0.18.2)(@tsdown/css@0.21.4)(@tsdown/exe@0.21.4)(@types/node@24.10.3)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(publint@0.3.19)(sass-embedded@1.99.0(source-map-js@1.2.1))(sass@1.99.0)(stylus@0.64.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.46.2)(tsx@4.21.0)(typescript@6.0.2)(unplugin-unused@0.5.6)(yaml@2.8.2) - '@voidzero-dev/vite-plus-test': 0.1.13(@arethetypeswrong/core@0.18.2)(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@tsdown/css@0.21.4)(@tsdown/exe@0.21.4)(@types/node@24.10.3)(@vitejs/devtools@0.1.21(@pnpm/logger@1001.0.1)(typescript@6.0.2)(vite@packages+core))(esbuild@0.27.4)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.2.0)(less@4.4.2)(publint@0.3.19)(sass-embedded@1.99.0(source-map-js@1.2.1))(sass@1.99.0)(stylus@0.64.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.46.2)(tsx@4.21.0)(typescript@6.0.2)(unplugin-unused@0.5.6)(vite@packages+core)(yaml@2.8.2) - cac: 7.0.0 - cross-spawn: 7.0.6 - oxfmt: 0.41.0 - oxlint: 1.56.0(oxlint-tsgolint@0.17.1) - oxlint-tsgolint: 0.17.1 - picocolors: 1.1.1 + '@vitest/expect': 4.1.5 + '@vitest/mocker': 4.1.5(vite@packages+core) + '@vitest/pretty-format': 4.1.5 + '@vitest/runner': 4.1.5 + '@vitest/snapshot': 4.1.5 + '@vitest/spy': 4.1.5 + '@vitest/utils': 4.1.5 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.1.2 + tinyglobby: 0.2.16 + tinyrainbow: 3.1.0 + vite: link:packages/core + why-is-node-running: 2.3.0 optionalDependencies: - '@voidzero-dev/vite-plus-darwin-arm64': 0.1.13 - '@voidzero-dev/vite-plus-darwin-x64': 0.1.13 - '@voidzero-dev/vite-plus-linux-arm64-gnu': 0.1.13 - '@voidzero-dev/vite-plus-linux-x64-gnu': 0.1.13 - '@voidzero-dev/vite-plus-win32-arm64-msvc': 0.1.13 - '@voidzero-dev/vite-plus-win32-x64-msvc': 0.1.13 + '@edge-runtime/vm': 5.0.0 + '@opentelemetry/api': 1.9.0 + '@types/node': 24.10.3 + '@vitest/browser-playwright': 4.1.5(playwright@1.57.0)(vite@packages+core)(vitest@4.1.5) + '@vitest/browser-preview': 4.1.5(vite@packages+core)(vitest@4.1.5) + '@vitest/browser-webdriverio': 4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1) + '@vitest/coverage-istanbul': 4.1.5(vitest@4.1.5) + '@vitest/coverage-v8': 4.1.5(@vitest/browser@4.1.5)(vitest@4.1.5) + '@vitest/ui': 4.1.5(vitest@4.1.5) + happy-dom: 20.0.10 + jsdom: 27.2.0 transitivePeerDependencies: - - '@arethetypeswrong/core' - - '@edge-runtime/vm' - - '@opentelemetry/api' - - '@tsdown/css' - - '@tsdown/exe' - - '@types/node' - - '@vitejs/devtools' - - '@vitest/ui' - - bufferutil - - esbuild - - happy-dom - - jiti - - jsdom - - less - - publint - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - typescript - - unplugin-unused - - utf-8-validate - - vite - - yaml + - msw - vitest@4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5(playwright@1.57.0)(vite@packages+core)(vitest@4.1.5))(@vitest/browser-preview@4.1.5(vite@packages+core)(vitest@4.1.5))(@vitest/browser-webdriverio@4.1.5(vite@packages+core)(vitest@4.1.5)(webdriverio@9.20.1))(@vitest/coverage-istanbul@4.1.5(vitest@4.1.5))(@vitest/coverage-v8@4.1.5(@vitest/browser@4.1.5)(vitest@4.1.5))(@vitest/ui@4.1.5(vitest@4.1.5))(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core): + vitest@4.1.5(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.5)(@vitest/browser-preview@4.1.5)(@vitest/browser-webdriverio@4.1.5)(@vitest/coverage-istanbul@4.1.5)(@vitest/coverage-v8@4.1.5)(@vitest/ui@4.1.5)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core): dependencies: '@vitest/expect': 4.1.5 '@vitest/mocker': 4.1.5(vite@packages+core) @@ -17240,6 +16232,7 @@ snapshots: w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 + optional: true wait-port@1.1.0: dependencies: @@ -17316,7 +16309,8 @@ snapshots: - supports-color - utf-8-validate - webidl-conversions@8.0.0: {} + webidl-conversions@8.0.0: + optional: true webpack-virtual-modules@0.6.2: {} @@ -17324,7 +16318,8 @@ snapshots: dependencies: iconv-lite: 0.6.3 - whatwg-mimetype@3.0.0: {} + whatwg-mimetype@3.0.0: + optional: true whatwg-mimetype@4.0.0: {} @@ -17332,6 +16327,7 @@ snapshots: dependencies: tr46: 6.0.0 webidl-conversions: 8.0.0 + optional: true which@2.0.2: dependencies: @@ -17399,9 +16395,11 @@ snapshots: is-wsl: 3.1.0 powershell-utils: 0.1.0 - xml-name-validator@5.0.0: {} + xml-name-validator@5.0.0: + optional: true - xmlchars@2.2.0: {} + xmlchars@2.2.0: + optional: true y18n@5.0.8: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 396e9ed0bd..4a1ebd5abe 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -40,8 +40,10 @@ catalog: '@types/ws': ^8.18.0 '@typescript/native-preview': 7.0.0-dev.20260122.2 '@vitejs/plugin-react': ^5.1.2 - '@vitest/browser': ^4.0.9 - '@vitest/browser-playwright': ^4.0.9 + '@vitest/browser': 4.1.5 + '@vitest/browser-playwright': 4.1.5 + '@vitest/browser-preview': 4.1.5 + '@vitest/browser-webdriverio': 4.1.5 '@voidzero-dev/vitepress-theme': 4.8.3 '@vueuse/core': ^14.0.0 '@yarnpkg/fslib': ^3.1.3 @@ -116,7 +118,7 @@ catalog: vitepress-plugin-group-icons: ^1.7.1 vitepress-plugin-llms: ^1.1.0 vitepress-plugin-og: ^0.0.5 - vitest: ^4.0.15 + vitest: 4.1.5 vue: ^3.5.21 web-tree-sitter: ^0.26.0 ws: ^8.18.1 @@ -169,8 +171,7 @@ overrides: '@rolldown/pluginutils': workspace:@rolldown/pluginutils@* rolldown: workspace:rolldown@* vite: workspace:@voidzero-dev/vite-plus-core@* - vitest: workspace:@voidzero-dev/vite-plus-test@* - vitest-dev: npm:vitest@^4.1.5 + vite-plus: workspace:vite-plus@* packageExtensions: sass-embedded: peerDependencies: diff --git a/rfcs/cli-output-polish.md b/rfcs/cli-output-polish.md index c3f4010d8b..97427add66 100644 --- a/rfcs/cli-output-polish.md +++ b/rfcs/cli-output-polish.md @@ -298,7 +298,9 @@ The `vite_install` crate also has `Warning:` and `Note:` messages across multipl ### Phase 3: Rebrand vitest Output -Vitest is bundled (not cloned source) via `@voidzero-dev/vite-plus-test`. Its build script (`packages/test/build.ts`) copies and rewrites vitest's dist files. We patch the bundled cac chunk during the build to rebrand CLI output. +> **Note:** This phase has been reverted. The `@voidzero-dev/vite-plus-test` bundled wrapper was removed in favor of consuming upstream `vitest` directly, since the `vite` → `@voidzero-dev/vite-plus-core` package manager override already handles the dependency redirection. Vitest output is no longer rebranded. + +Historical context (no longer applies): Vitest was bundled (not cloned source) via `@voidzero-dev/vite-plus-test`. Its build script (`packages/test/build.ts`) copied and rewrote vitest's dist files. We patched the bundled cac chunk during the build to rebrand CLI output. #### 3.1 Approach: Build-time patching of bundled cac chunk diff --git a/rfcs/migration-command.md b/rfcs/migration-command.md index aa2509dd5c..bf18611e61 100644 --- a/rfcs/migration-command.md +++ b/rfcs/migration-command.md @@ -203,12 +203,10 @@ Wrote agent instructions to AGENTS.md }, "devDependencies": { "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest", "@vitejs/plugin-react": "^4.2.0" }, "overrides": { - "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + "vite": "npm:@voidzero-dev/vite-plus-core@latest" } } ``` @@ -223,7 +221,6 @@ Wrote agent instructions to AGENTS.md }, "devDependencies": { "vite": "catalog:", - "vitest": "catalog:", "@vitejs/plugin-react": "^4.2.0", "vite-plus": "catalog:" }, @@ -236,15 +233,12 @@ Wrote agent instructions to AGENTS.md ```yaml catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest vite-plus: latest overrides: vite: 'catalog:' - vitest: 'catalog:' peerDependencyRules: allowAny: - vite - - vitest allowedVersions: vite: '*' vitest: '*' @@ -259,16 +253,14 @@ Projects that already have a `pnpm` field in `package.json` (e.g., with `overrid "name": "my-package", "devDependencies": { "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest", "vite-plus": "latest" }, "pnpm": { "overrides": { - "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + "vite": "npm:@voidzero-dev/vite-plus-core@latest" }, "peerDependencyRules": { - "allowAny": ["vite", "vitest"], + "allowAny": ["vite"], "allowedVersions": { "vite": "*", "vitest": "*" } } } @@ -289,6 +281,7 @@ Projects that already have a `pnpm` field in `package.json` (e.g., with `overrid - rewrite `import from '@vitest/browser/{name}'` to `import from 'vite-plus/test/browser/{name}'`, e.g.: `import from '@vitest/browser/context'` to `import from 'vite-plus/test/browser/context'` - rewrite `import from '@vitest/browser-playwright'` to `import from 'vite-plus/test/browser-playwright'` - rewrite `import from '@vitest/browser-playwright/{name}'` to `import from 'vite-plus/test/browser-playwright/{name}'` +- `declare module 'vitest'`, `declare module 'vitest/{name}'`, and `declare module '@vitest/browser*'` are intentionally **not** rewritten — `vite-plus/test*` is a thin re-export of upstream `vitest*`, so type augmentations have to target the upstream module identity to merge correctly **Note**: For Yarn, use `resolutions` instead of `overrides`. @@ -503,15 +496,12 @@ For monorepo projects and standalone projects without existing `pnpm` config in ```yaml catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest vite-plus: latest overrides: vite: 'catalog:' - vitest: 'catalog:' peerDependencyRules: allowAny: - vite - - vitest allowedVersions: vite: '*' vitest: '*' @@ -524,12 +514,10 @@ peerDependencyRules: ```json { "devDependencies": { - "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + "vite": "npm:@voidzero-dev/vite-plus-core@latest" }, "overrides": { - "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + "vite": "npm:@voidzero-dev/vite-plus-core@latest" } } ``` @@ -541,7 +529,6 @@ peerDependencyRules: ```yaml catalog: vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest ``` `package.json` @@ -549,8 +536,7 @@ catalog: ```json { "resolutions": { - "vite": "catalog:", - "vitest": "catalog:" + "vite": "catalog:" } } ``` diff --git a/vite.config.ts b/vite.config.ts index 73d6ccca86..e7218a9b23 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -70,12 +70,6 @@ export default defineConfig({ 'packages/cli/snap-tests/fmt-ignore-patterns/src/ignored', 'packages/cli/snap-tests-global/migration-lint-staged-ts-config', 'ecosystem-ci/*/**', - 'packages/test/**.cjs', - 'packages/test/**.cts', - 'packages/test/**.d.mjs', - 'packages/test/**.d.ts', - 'packages/test/**.mjs', - 'packages/test/browser/', 'packages/cli/src/run-config.ts', 'vite', 'rolldown', @@ -111,7 +105,6 @@ export default defineConfig({ 'vp run rolldown#build-node', 'vp run vite#build-types', 'vp run @voidzero-dev/vite-plus-core#build', - 'vp run @voidzero-dev/vite-plus-test#build', 'vp run vite-plus#build', ].join(' && '), },