From ffa9ff0660b7911bd7aafd35e169cd8d8d643683 Mon Sep 17 00:00:00 2001 From: MK Date: Wed, 12 Aug 2026 08:33:53 +0800 Subject: [PATCH 1/9] fix(migrate): keep `catalog:` specs intact through `vp up` under pnpm pnpm applies overrides through a read-package hook that replaces the declared spec on every manifest, importers included, before resolution runs. A bare override key carries no range, and pnpm treats "no range" as "matches every declared spec", `catalog:` included. An importer declaring `vite: "catalog:"` therefore loses its catalog provenance during resolution, so `pnpm update` writes the resolved core alias back into its package.json (`vite: "npm:@voidzero-dev/vite-plus-core@0.2.7"`). Range-qualify the managed pnpm override keys (`vite@*`, `vitest@*`). `*` is a valid range and intersects every real semver range, which is what the transitive and peer `vite` declarations the override exists for always use, while `catalog:` is not a valid range and so never matches. Nothing changes about what gets installed: an importer referencing the catalog already resolves to the aliased core through its catalog entry. Migration re-keys a project still carrying the bare key, preserving its `catalog:` choice, and pending-detection reads a bare managed key as unsatisfied so one `vp migrate` repairs an existing project. npm/bun `overrides` and yarn `resolutions` keep bare keys; they have no `catalog:` importer specs to lose. Closes #2309 --- .../.gitignore | 1 + .../package.json | 9 ++ .../pnpm-workspace.yaml | 10 ++ .../snapshots.toml | 38 +++++++ ...mand_update_catalog_protocol_legacy_key.md | 84 ++++++++++++++ .../.gitignore | 1 + .../package.json | 7 ++ .../snapshots.toml | 35 ++++++ .../command_update_catalog_protocol_pnpm.md | 75 ++++++++++++ .../create_approve_builds_migrate_pnpm11.md | 6 +- .../snapshots/create_approve_builds_pnpm11.md | 6 +- .../snapshots/create_org_bundled_monorepo.md | 2 +- .../snapshots/migration_add_git_hooks.md | 2 +- ...igration_chained_lint_staged_pre_commit.md | 2 +- .../migration_composed_husky_custom_dir.md | 2 +- .../migration_composed_husky_prepare.md | 2 +- .../migration_env_prefix_lint_staged.md | 2 +- .../snapshots/migration_eslint.md | 2 +- .../snapshots/migration_eslint_lint_staged.md | 2 +- .../migration_eslint_lintstagedrc.md | 2 +- .../snapshots/migration_eslint_npx_wrapper.md | 2 +- .../snapshots/migration_existing_husky.md | 2 +- .../migration_existing_husky_lint_staged.md | 2 +- .../migration_existing_husky_v8_hooks.md | 2 +- ...migration_existing_husky_v8_multi_hooks.md | 2 +- .../migration_existing_lint_staged_config.md | 2 +- .../migration_existing_prepare_script.md | 2 +- .../snapshots/migration_from_tsdown.md | 2 +- .../migration_from_tsdown_json_config.md | 2 +- .../snapshots/migration_from_vitest_config.md | 4 +- .../snapshots/migration_from_vitest_files.md | 4 +- .../migration_husky_latest_dist_tag.md | 2 +- ...tion_husky_latest_dist_tag_v9_installed.md | 2 +- .../migration_husky_semicolon_prepare.md | 2 +- ...igration_husky_v8_preserves_lint_staged.md | 2 +- .../snapshots/migration_lazy_plugins_await.md | 2 +- .../migration_lint_staged_in_scripts.md | 2 +- .../migration_lint_staged_ts_config.md | 2 +- .../snapshots/migration_lintstagedrc_json.md | 2 +- .../migration_lintstagedrc_merge_fail.md | 2 +- .../migration_lintstagedrc_not_support.md | 2 +- .../migration_lintstagedrc_staged_exists.md | 2 +- .../migration_merge_vite_config_js.md | 2 +- .../migration_merge_vite_config_ts.md | 4 +- .../snapshots/migration_monorepo_pnpm.md | 4 +- ...repo_pnpm_overrides_dependency_selector.md | 2 +- .../snapshots/migration_no_git_repo.md | 2 +- .../snapshots/migration_no_hooks.md | 2 +- .../migration_no_hooks_with_husky.md | 2 +- .../snapshots/migration_npmx_dev.md | 4 +- .../snapshots/migration_other_hook_tool.md | 2 +- .../migration_oxlintrc_json_with_comments.md | 2 +- .../snapshots/migration_oxlintrc_jsonc.md | 2 +- ...migration_partially_installed_vite_plus.md | 2 +- ...migration_partially_migrated_pre_commit.md | 2 +- .../snapshots/migration_prettier.md | 2 +- .../migration_prettier_eslint_combo.md | 2 +- .../migration_prettier_ignore_unknown.md | 2 +- .../migration_prettier_lint_staged.md | 2 +- .../snapshots/migration_prettier_pkg_json.md | 2 +- .../migration_rewrite_declare_module.md | 4 +- .../migration_skip_vite_dependency.md | 2 +- .../migration_skip_vite_peer_dependency.md | 2 +- .../snapshots/migration_subpath.md | 2 +- .../migration_tsconfig_esmoduleinterop.md | 2 +- ...igration_upgrade_browser_peer_only_pnpm.md | 4 +- ...ration_upgrade_browser_source_only_pnpm.md | 4 +- ...ration_upgrade_browser_webdriverio_pnpm.md | 4 +- ..._upgrade_monorepo_vitest_localized_pnpm.md | 4 +- ...ration_upgrade_nuxt_test_utils_monorepo.md | 4 +- ...ration_upgrade_peer_vitest_catalog_pnpm.md | 2 +- .../migration_upgrade_pkg_pr_new_pnpm.md | 8 +- .../migration_upgrade_pnpm9_overrides.md | 4 +- ...ration_upgrade_pnpm_bundled_catalog_dep.md | 2 +- ...migration_upgrade_pnpm_catalogs_default.md | 4 +- .../migration_upgrade_pnpm_named_catalog.md | 4 +- ...tion_upgrade_setup_skipped_default_pnpm.md | 2 +- .../migration_upgrade_stale_local_pnpm.md | 2 +- ...pgrade_vitest_reference_whitespace_pnpm.md | 2 +- ...igration_vite_plus_in_dependencies_pnpm.md | 2 +- .../snapshots/migration_vitest_peer_dep.md | 4 +- .../migration_vitest_unmanaged_override.md | 2 +- .../snapshots/new_vite_monorepo.md | 2 +- .../tests/cli_snapshots/redact.rs | 7 +- docs/guide/migrate-rules.md | 8 ++ docs/guide/upgrade.md | 4 +- packages/cli/src/create/templates/monorepo.ts | 19 ++-- .../src/migration/__tests__/migrator.spec.ts | 107 +++++++++++++++--- .../cli/src/migration/migrator/catalog.ts | 44 +++++-- .../src/migration/migrator/orchestrators.ts | 18 ++- packages/cli/src/migration/migrator/shared.ts | 41 +++++++ .../migration/migrator/vite-plus-bootstrap.ts | 56 ++++++--- .../migration/migrator/vitest-ecosystem.ts | 39 +++++-- 93 files changed, 642 insertions(+), 153 deletions(-) create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/.gitignore create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/package.json create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/pnpm-workspace.yaml create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots.toml create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots/command_update_catalog_protocol_legacy_key.md create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/.gitignore create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/package.json create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/snapshots.toml create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/snapshots/command_update_catalog_protocol_pnpm.md diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/.gitignore b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/.gitignore new file mode 100644 index 0000000000..c2658d7d1b --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/package.json new file mode 100644 index 0000000000..7287fafd0b --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/package.json @@ -0,0 +1,9 @@ +{ + "name": "command-update-catalog-protocol-legacy-key", + "private": true, + "devDependencies": { + "vite": "catalog:", + "vite-plus": "catalog:" + }, + "packageManager": "pnpm@11.20.0" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/pnpm-workspace.yaml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/pnpm-workspace.yaml new file mode 100644 index 0000000000..d9df99abda --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/pnpm-workspace.yaml @@ -0,0 +1,10 @@ +catalog: + vite: npm:@voidzero-dev/vite-plus-core@latest + vite-plus: latest +overrides: + vite: 'catalog:' +peerDependencyRules: + allowAny: + - vite + allowedVersions: + vite: '*' diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots.toml new file mode 100644 index 0000000000..dbfeb886e5 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots.toml @@ -0,0 +1,38 @@ +[[case]] +name = "command_update_catalog_protocol_legacy_key" +vp = "global" +skip-platforms = ["windows"] +unset-env = ["CI", "VP_SKIP_INSTALL"] +local-registry = true +comment = "#2309 repair path: a project migrated before the fix carries the bare `vite` override key, which `vp up` uses to clobber `catalog:`. One `vp migrate` re-keys it." +steps = [ + { argv = [ + "vp", + "up", + ], comment = "the bare override key resolves the catalog reference away", snapshot = false, continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "package.json", + ], comment = "`vite` lost `catalog:`; `vite-plus` (no override) kept it", continue-on-failure = true }, + { argv = [ + "vp", + "migrate", + "--no-interactive", + "--no-hooks", + ], comment = "migrate repairs both the override key and the clobbered spec", continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "pnpm-workspace.yaml", + ], comment = "the bare key is replaced by the range-qualified one", continue-on-failure = true }, + { argv = [ + "vp", + "up", + ], comment = "update is now a no-op on the catalog reference", continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "package.json", + ], comment = "`vite` stays `catalog:` across the update", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots/command_update_catalog_protocol_legacy_key.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots/command_update_catalog_protocol_legacy_key.md new file mode 100644 index 0000000000..69c2d2ee08 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots/command_update_catalog_protocol_legacy_key.md @@ -0,0 +1,84 @@ +# command_update_catalog_protocol_legacy_key + +#2309 repair path: a project migrated before the fix carries the bare `vite` override key, which `vp up` uses to clobber `catalog:`. One `vp migrate` re-keys it. + +## `vp up` + +the bare override key resolves the catalog reference away + + +## `vpt print-file package.json` + +`vite` lost `catalog:`; `vite-plus` (no override) kept it + +``` +{ + "name": "command-update-catalog-protocol-legacy-key", + "private": true, + "devDependencies": { + "vite": "npm:@voidzero-dev/vite-plus-core@^", + "vite-plus": "catalog:" + }, + "packageManager": "pnpm@11.20.0" +} +``` + +## `vp migrate --no-interactive --no-hooks` + +migrate repairs both the override key and the clobbered spec + +``` +VITE+ - The Unified Toolchain for the Web + +Formatting code... + +Code formatted +◇ Updated . to Vite+ +• Node pnpm +✓ Dependencies installed in +• Package manager settings configured +``` + +## `vpt print-file pnpm-workspace.yaml` + +the bare key is replaced by the range-qualified one + +``` +catalog: + vite: npm:@voidzero-dev/vite-plus-core@ + vite-plus: +overrides: + vite@*: "catalog:" +peerDependencyRules: + allowAny: + - vite + allowedVersions: + vite: "*" +``` + +## `vp up` + +update is now a no-op on the catalog reference + +``` +✓ Lockfile passes supply-chain policies (verified ago) +Already up to date + +Done in using pnpm +``` + +## `vpt print-file package.json` + +`vite` stays `catalog:` across the update + +``` +{ + "name": "command-update-catalog-protocol-legacy-key", + "private": true, + "devDependencies": { + "vite": "catalog:", + "vite-plus": "catalog:" + }, + "packageManager": "pnpm@11.20.0" +} +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/.gitignore b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/.gitignore new file mode 100644 index 0000000000..c2658d7d1b --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/package.json new file mode 100644 index 0000000000..544cc6848a --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/package.json @@ -0,0 +1,7 @@ +{ + "name": "command-update-catalog-protocol-pnpm", + "devDependencies": { + "vite": "^7.0.0" + }, + "packageManager": "pnpm@11.20.0" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/snapshots.toml new file mode 100644 index 0000000000..39c7b8383f --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/snapshots.toml @@ -0,0 +1,35 @@ +[[case]] +name = "command_update_catalog_protocol_pnpm" +vp = "global" +skip-platforms = ["windows"] +unset-env = ["CI", "VP_SKIP_INSTALL"] +local-registry = true +steps = [ + { argv = [ + "vp", + "migrate", + "--no-interactive", + "--no-hooks", + "--package-manager", + "pnpm", + ], comment = "migrate pins the toolchain through the workspace catalog", continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "package.json", + ], comment = "the migrated project references the catalog", continue-on-failure = true }, + { argv = [ + "vp", + "up", + ], comment = "#2309: update must not resolve the catalog reference away", continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "package.json", + ], comment = "`vite` stays `catalog:` instead of the concrete core alias", continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "pnpm-workspace.yaml", + ], comment = "the catalog keeps owning the resolved toolchain version", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/snapshots/command_update_catalog_protocol_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/snapshots/command_update_catalog_protocol_pnpm.md new file mode 100644 index 0000000000..dcebd89b54 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/snapshots/command_update_catalog_protocol_pnpm.md @@ -0,0 +1,75 @@ +# command_update_catalog_protocol_pnpm + +## `vp migrate --no-interactive --no-hooks --package-manager pnpm` + +migrate pins the toolchain through the workspace catalog + +``` +VITE+ - The Unified Toolchain for the Web + +Formatting code... + +Code formatted +◇ Migrated . to Vite+ +• Node pnpm +✓ Dependencies installed in +• 1 config update applied +``` + +## `vpt print-file package.json` + +the migrated project references the catalog + +``` +{ + "name": "command-update-catalog-protocol-pnpm", + "devDependencies": { + "vite": "catalog:", + "vite-plus": "catalog:" + }, + "packageManager": "pnpm@11.20.0" +} +``` + +## `vp up` + +#2309: update must not resolve the catalog reference away + +``` +✓ Lockfile passes supply-chain policies (verified ago) +Already up to date + +Done in using pnpm +``` + +## `vpt print-file package.json` + +`vite` stays `catalog:` instead of the concrete core alias + +``` +{ + "name": "command-update-catalog-protocol-pnpm", + "devDependencies": { + "vite": "catalog:", + "vite-plus": "catalog:" + }, + "packageManager": "pnpm@11.20.0" +} +``` + +## `vpt print-file pnpm-workspace.yaml` + +the catalog keeps owning the resolved toolchain version + +``` +catalog: + vite: npm:@voidzero-dev/vite-plus-core@ + vite-plus: +overrides: + vite@*: "catalog:" +peerDependencyRules: + allowAny: + - vite + allowedVersions: + vite: "*" +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_migrate_pnpm11/snapshots/create_approve_builds_migrate_pnpm11.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_migrate_pnpm11/snapshots/create_approve_builds_migrate_pnpm11.md index c74d30872e..51d6f4d597 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_migrate_pnpm11/snapshots/create_approve_builds_migrate_pnpm11.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_migrate_pnpm11/snapshots/create_approve_builds_migrate_pnpm11.md @@ -24,7 +24,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: "catalog:" + vite@*: "catalog:" peerDependencyRules: allowAny: - vite @@ -60,7 +60,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: "catalog:" + vite@*: "catalog:" peerDependencyRules: allowAny: - vite @@ -87,7 +87,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: "catalog:" + vite@*: "catalog:" peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_pnpm11/snapshots/create_approve_builds_pnpm11.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_pnpm11/snapshots/create_approve_builds_pnpm11.md index 6f06005932..02d8568dde 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_pnpm11/snapshots/create_approve_builds_pnpm11.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_pnpm11/snapshots/create_approve_builds_pnpm11.md @@ -22,7 +22,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: "catalog:" + vite@*: "catalog:" peerDependencyRules: allowAny: - vite @@ -56,7 +56,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: "catalog:" + vite@*: "catalog:" peerDependencyRules: allowAny: - vite @@ -83,7 +83,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: "catalog:" + vite@*: "catalog:" peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_org_bundled_monorepo/snapshots/create_org_bundled_monorepo.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_org_bundled_monorepo/snapshots/create_org_bundled_monorepo.md index 393c40aaee..a5f8cc7d31 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_org_bundled_monorepo/snapshots/create_org_bundled_monorepo.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_org_bundled_monorepo/snapshots/create_org_bundled_monorepo.md @@ -44,7 +44,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: "catalog:" + vite@*: "catalog:" peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_add_git_hooks/snapshots/migration_add_git_hooks.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_add_git_hooks/snapshots/migration_add_git_hooks.md index bdb8767398..76358ae348 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_add_git_hooks/snapshots/migration_add_git_hooks.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_add_git_hooks/snapshots/migration_add_git_hooks.md @@ -49,7 +49,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_chained_lint_staged_pre_commit/snapshots/migration_chained_lint_staged_pre_commit.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_chained_lint_staged_pre_commit/snapshots/migration_chained_lint_staged_pre_commit.md index 9864837543..c24e1c4e1d 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_chained_lint_staged_pre_commit/snapshots/migration_chained_lint_staged_pre_commit.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_chained_lint_staged_pre_commit/snapshots/migration_chained_lint_staged_pre_commit.md @@ -54,7 +54,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_custom_dir/snapshots/migration_composed_husky_custom_dir.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_custom_dir/snapshots/migration_composed_husky_custom_dir.md index 766c8d3f85..417130c867 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_custom_dir/snapshots/migration_composed_husky_custom_dir.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_custom_dir/snapshots/migration_composed_husky_custom_dir.md @@ -63,7 +63,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_prepare/snapshots/migration_composed_husky_prepare.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_prepare/snapshots/migration_composed_husky_prepare.md index dd48923291..86cd306460 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_prepare/snapshots/migration_composed_husky_prepare.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_prepare/snapshots/migration_composed_husky_prepare.md @@ -50,7 +50,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_env_prefix_lint_staged/snapshots/migration_env_prefix_lint_staged.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_env_prefix_lint_staged/snapshots/migration_env_prefix_lint_staged.md index ba9803d963..419baaafe5 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_env_prefix_lint_staged/snapshots/migration_env_prefix_lint_staged.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_env_prefix_lint_staged/snapshots/migration_env_prefix_lint_staged.md @@ -54,7 +54,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint/snapshots/migration_eslint.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint/snapshots/migration_eslint.md index 7e013cd63f..ed31473498 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint/snapshots/migration_eslint.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint/snapshots/migration_eslint.md @@ -50,7 +50,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lint_staged/snapshots/migration_eslint_lint_staged.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lint_staged/snapshots/migration_eslint_lint_staged.md index 6344911e27..62e2d0a518 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lint_staged/snapshots/migration_eslint_lint_staged.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lint_staged/snapshots/migration_eslint_lint_staged.md @@ -47,7 +47,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lintstagedrc/snapshots/migration_eslint_lintstagedrc.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lintstagedrc/snapshots/migration_eslint_lintstagedrc.md index a03ff2ddd2..19ef6077a2 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lintstagedrc/snapshots/migration_eslint_lintstagedrc.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lintstagedrc/snapshots/migration_eslint_lintstagedrc.md @@ -47,7 +47,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_npx_wrapper/snapshots/migration_eslint_npx_wrapper.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_npx_wrapper/snapshots/migration_eslint_npx_wrapper.md index f0842bcb80..d297f5e5f6 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_npx_wrapper/snapshots/migration_eslint_npx_wrapper.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_npx_wrapper/snapshots/migration_eslint_npx_wrapper.md @@ -52,7 +52,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky/snapshots/migration_existing_husky.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky/snapshots/migration_existing_husky.md index c8c87deda3..546c6effc0 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky/snapshots/migration_existing_husky.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky/snapshots/migration_existing_husky.md @@ -50,7 +50,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_lint_staged/snapshots/migration_existing_husky_lint_staged.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_lint_staged/snapshots/migration_existing_husky_lint_staged.md index 56110fd5f7..db483d0aa6 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_lint_staged/snapshots/migration_existing_husky_lint_staged.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_lint_staged/snapshots/migration_existing_husky_lint_staged.md @@ -54,7 +54,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_hooks/snapshots/migration_existing_husky_v8_hooks.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_hooks/snapshots/migration_existing_husky_v8_hooks.md index 501857fcae..f0c5b7b915 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_hooks/snapshots/migration_existing_husky_v8_hooks.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_hooks/snapshots/migration_existing_husky_v8_hooks.md @@ -51,7 +51,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_multi_hooks/snapshots/migration_existing_husky_v8_multi_hooks.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_multi_hooks/snapshots/migration_existing_husky_v8_multi_hooks.md index 2e246709a6..1b60fa7afa 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_multi_hooks/snapshots/migration_existing_husky_v8_multi_hooks.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_multi_hooks/snapshots/migration_existing_husky_v8_multi_hooks.md @@ -51,7 +51,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_lint_staged_config/snapshots/migration_existing_lint_staged_config.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_lint_staged_config/snapshots/migration_existing_lint_staged_config.md index b68a73c622..27645d247f 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_lint_staged_config/snapshots/migration_existing_lint_staged_config.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_lint_staged_config/snapshots/migration_existing_lint_staged_config.md @@ -49,7 +49,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_prepare_script/snapshots/migration_existing_prepare_script.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_prepare_script/snapshots/migration_existing_prepare_script.md index 9cdd2c583c..e96ca2e661 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_prepare_script/snapshots/migration_existing_prepare_script.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_prepare_script/snapshots/migration_existing_prepare_script.md @@ -50,7 +50,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown/snapshots/migration_from_tsdown.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown/snapshots/migration_from_tsdown.md index 37ae463f51..20c439d0cb 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown/snapshots/migration_from_tsdown.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown/snapshots/migration_from_tsdown.md @@ -84,7 +84,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown_json_config/snapshots/migration_from_tsdown_json_config.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown_json_config/snapshots/migration_from_tsdown_json_config.md index 946d79562d..89494ff3d6 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown_json_config/snapshots/migration_from_tsdown_json_config.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown_json_config/snapshots/migration_from_tsdown_json_config.md @@ -84,7 +84,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_config/snapshots/migration_from_vitest_config.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_config/snapshots/migration_from_vitest_config.md index a1eb859148..ca978ebabc 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_config/snapshots/migration_from_vitest_config.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_config/snapshots/migration_from_vitest_config.md @@ -93,8 +93,8 @@ allowBuilds: edgedriver: true geckodriver: true overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_files/snapshots/migration_from_vitest_files.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_files/snapshots/migration_from_vitest_files.md index f856e5e8ef..839948754a 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_files/snapshots/migration_from_vitest_files.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_files/snapshots/migration_from_vitest_files.md @@ -55,8 +55,8 @@ catalog: vite-plus: '@vitest/browser-playwright': overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag/snapshots/migration_husky_latest_dist_tag.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag/snapshots/migration_husky_latest_dist_tag.md index de8dadcc68..3053b40e6d 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag/snapshots/migration_husky_latest_dist_tag.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag/snapshots/migration_husky_latest_dist_tag.md @@ -50,7 +50,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag_v9_installed/snapshots/migration_husky_latest_dist_tag_v9_installed.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag_v9_installed/snapshots/migration_husky_latest_dist_tag_v9_installed.md index 04ae9c13e3..cead48df58 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag_v9_installed/snapshots/migration_husky_latest_dist_tag_v9_installed.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag_v9_installed/snapshots/migration_husky_latest_dist_tag_v9_installed.md @@ -54,7 +54,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_semicolon_prepare/snapshots/migration_husky_semicolon_prepare.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_semicolon_prepare/snapshots/migration_husky_semicolon_prepare.md index 15d70e45a2..c897585700 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_semicolon_prepare/snapshots/migration_husky_semicolon_prepare.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_semicolon_prepare/snapshots/migration_husky_semicolon_prepare.md @@ -54,7 +54,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_v8_preserves_lint_staged/snapshots/migration_husky_v8_preserves_lint_staged.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_v8_preserves_lint_staged/snapshots/migration_husky_v8_preserves_lint_staged.md index 7da1b85977..a74eb320af 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_v8_preserves_lint_staged/snapshots/migration_husky_v8_preserves_lint_staged.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_v8_preserves_lint_staged/snapshots/migration_husky_v8_preserves_lint_staged.md @@ -54,7 +54,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lazy_plugins_await/snapshots/migration_lazy_plugins_await.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lazy_plugins_await/snapshots/migration_lazy_plugins_await.md index 98b62a45f3..0f2a1951b1 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lazy_plugins_await/snapshots/migration_lazy_plugins_await.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lazy_plugins_await/snapshots/migration_lazy_plugins_await.md @@ -61,7 +61,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_in_scripts/snapshots/migration_lint_staged_in_scripts.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_in_scripts/snapshots/migration_lint_staged_in_scripts.md index f86d4c01f7..2e74b17b0c 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_in_scripts/snapshots/migration_lint_staged_in_scripts.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_in_scripts/snapshots/migration_lint_staged_in_scripts.md @@ -55,7 +55,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_ts_config/snapshots/migration_lint_staged_ts_config.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_ts_config/snapshots/migration_lint_staged_ts_config.md index 3362afdc15..6fc439341a 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_ts_config/snapshots/migration_lint_staged_ts_config.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_ts_config/snapshots/migration_lint_staged_ts_config.md @@ -52,7 +52,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_json/snapshots/migration_lintstagedrc_json.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_json/snapshots/migration_lintstagedrc_json.md index 500a2461a1..607a08ba5c 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_json/snapshots/migration_lintstagedrc_json.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_json/snapshots/migration_lintstagedrc_json.md @@ -133,7 +133,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_merge_fail/snapshots/migration_lintstagedrc_merge_fail.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_merge_fail/snapshots/migration_lintstagedrc_merge_fail.md index de72892b3d..77190c2d7e 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_merge_fail/snapshots/migration_lintstagedrc_merge_fail.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_merge_fail/snapshots/migration_lintstagedrc_merge_fail.md @@ -53,7 +53,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_not_support/snapshots/migration_lintstagedrc_not_support.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_not_support/snapshots/migration_lintstagedrc_not_support.md index 0ba55e21ea..bc6e8fa22d 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_not_support/snapshots/migration_lintstagedrc_not_support.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_not_support/snapshots/migration_lintstagedrc_not_support.md @@ -81,7 +81,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_staged_exists/snapshots/migration_lintstagedrc_staged_exists.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_staged_exists/snapshots/migration_lintstagedrc_staged_exists.md index e80aa524a1..b6af13b6ac 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_staged_exists/snapshots/migration_lintstagedrc_staged_exists.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_staged_exists/snapshots/migration_lintstagedrc_staged_exists.md @@ -50,7 +50,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_js/snapshots/migration_merge_vite_config_js.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_js/snapshots/migration_merge_vite_config_js.md index ddeea15715..b66d23c454 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_js/snapshots/migration_merge_vite_config_js.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_js/snapshots/migration_merge_vite_config_js.md @@ -90,7 +90,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_ts/snapshots/migration_merge_vite_config_ts.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_ts/snapshots/migration_merge_vite_config_ts.md index 4dcd8e5341..93c54c83f6 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_ts/snapshots/migration_merge_vite_config_ts.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_ts/snapshots/migration_merge_vite_config_ts.md @@ -133,8 +133,8 @@ catalog: vite-plus: '@vitest/browser-playwright': overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm/snapshots/migration_monorepo_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm/snapshots/migration_monorepo_pnpm.md index ae96608a83..ffbf239a39 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm/snapshots/migration_monorepo_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm/snapshots/migration_monorepo_pnpm.md @@ -124,8 +124,8 @@ catalog: minimumReleaseAge: 1440 overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm_overrides_dependency_selector/snapshots/migration_monorepo_pnpm_overrides_dependency_selector.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm_overrides_dependency_selector/snapshots/migration_monorepo_pnpm_overrides_dependency_selector.md index 9881b4231a..ab8dc31e0a 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm_overrides_dependency_selector/snapshots/migration_monorepo_pnpm_overrides_dependency_selector.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm_overrides_dependency_selector/snapshots/migration_monorepo_pnpm_overrides_dependency_selector.md @@ -67,7 +67,7 @@ catalog: overrides: supertest>superagent: 9.0.2 react-click-away-listener>react: 0.0.0-experimental-7dc903cd-20251203 - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_git_repo/snapshots/migration_no_git_repo.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_git_repo/snapshots/migration_no_git_repo.md index 1504ecbde7..686d421bb2 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_git_repo/snapshots/migration_no_git_repo.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_git_repo/snapshots/migration_no_git_repo.md @@ -45,7 +45,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks/snapshots/migration_no_hooks.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks/snapshots/migration_no_hooks.md index 2ee45f2f74..2d05f13483 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks/snapshots/migration_no_hooks.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks/snapshots/migration_no_hooks.md @@ -45,7 +45,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks_with_husky/snapshots/migration_no_hooks_with_husky.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks_with_husky/snapshots/migration_no_hooks_with_husky.md index ee446b617d..7ca7e56314 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks_with_husky/snapshots/migration_no_hooks_with_husky.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks_with_husky/snapshots/migration_no_hooks_with_husky.md @@ -54,7 +54,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_npmx_dev/snapshots/migration_npmx_dev.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_npmx_dev/snapshots/migration_npmx_dev.md index 80d95f82a7..e24d23ee28 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_npmx_dev/snapshots/migration_npmx_dev.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_npmx_dev/snapshots/migration_npmx_dev.md @@ -55,8 +55,8 @@ catalog: '@vitest/browser-playwright': '@vitest/coverage-v8': overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_other_hook_tool/snapshots/migration_other_hook_tool.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_other_hook_tool/snapshots/migration_other_hook_tool.md index 46237ea22a..c089fafd3a 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_other_hook_tool/snapshots/migration_other_hook_tool.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_other_hook_tool/snapshots/migration_other_hook_tool.md @@ -54,7 +54,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_json_with_comments/snapshots/migration_oxlintrc_json_with_comments.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_json_with_comments/snapshots/migration_oxlintrc_json_with_comments.md index 5f58fd5401..73c8257696 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_json_with_comments/snapshots/migration_oxlintrc_json_with_comments.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_json_with_comments/snapshots/migration_oxlintrc_json_with_comments.md @@ -88,7 +88,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_jsonc/snapshots/migration_oxlintrc_jsonc.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_jsonc/snapshots/migration_oxlintrc_jsonc.md index d980be1839..7e6db8097e 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_jsonc/snapshots/migration_oxlintrc_jsonc.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_jsonc/snapshots/migration_oxlintrc_jsonc.md @@ -97,7 +97,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_installed_vite_plus/snapshots/migration_partially_installed_vite_plus.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_installed_vite_plus/snapshots/migration_partially_installed_vite_plus.md index b093d4756d..3d2c84c650 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_installed_vite_plus/snapshots/migration_partially_installed_vite_plus.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_installed_vite_plus/snapshots/migration_partially_installed_vite_plus.md @@ -65,7 +65,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_migrated_pre_commit/snapshots/migration_partially_migrated_pre_commit.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_migrated_pre_commit/snapshots/migration_partially_migrated_pre_commit.md index 1e03f0bc8a..3986400a7a 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_migrated_pre_commit/snapshots/migration_partially_migrated_pre_commit.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_migrated_pre_commit/snapshots/migration_partially_migrated_pre_commit.md @@ -51,7 +51,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier/snapshots/migration_prettier.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier/snapshots/migration_prettier.md index 8992e97272..5e97a3f852 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier/snapshots/migration_prettier.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier/snapshots/migration_prettier.md @@ -51,7 +51,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_eslint_combo/snapshots/migration_prettier_eslint_combo.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_eslint_combo/snapshots/migration_prettier_eslint_combo.md index b3208de05f..83d5ce59e7 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_eslint_combo/snapshots/migration_prettier_eslint_combo.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_eslint_combo/snapshots/migration_prettier_eslint_combo.md @@ -53,7 +53,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_ignore_unknown/snapshots/migration_prettier_ignore_unknown.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_ignore_unknown/snapshots/migration_prettier_ignore_unknown.md index 83562aebb3..e7f56e96a1 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_ignore_unknown/snapshots/migration_prettier_ignore_unknown.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_ignore_unknown/snapshots/migration_prettier_ignore_unknown.md @@ -51,7 +51,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_lint_staged/snapshots/migration_prettier_lint_staged.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_lint_staged/snapshots/migration_prettier_lint_staged.md index 766b342436..ace247fbc3 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_lint_staged/snapshots/migration_prettier_lint_staged.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_lint_staged/snapshots/migration_prettier_lint_staged.md @@ -48,7 +48,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_pkg_json/snapshots/migration_prettier_pkg_json.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_pkg_json/snapshots/migration_prettier_pkg_json.md index 9d9e663707..21cd8a02bf 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_pkg_json/snapshots/migration_prettier_pkg_json.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_pkg_json/snapshots/migration_prettier_pkg_json.md @@ -49,7 +49,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_rewrite_declare_module/snapshots/migration_rewrite_declare_module.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_rewrite_declare_module/snapshots/migration_rewrite_declare_module.md index f85f03d49a..f3c4113b66 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_rewrite_declare_module/snapshots/migration_rewrite_declare_module.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_rewrite_declare_module/snapshots/migration_rewrite_declare_module.md @@ -83,8 +83,8 @@ catalog: vitest: vite-plus: overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_dependency/snapshots/migration_skip_vite_dependency.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_dependency/snapshots/migration_skip_vite_dependency.md index ea5d51825f..9663a94770 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_dependency/snapshots/migration_skip_vite_dependency.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_dependency/snapshots/migration_skip_vite_dependency.md @@ -75,7 +75,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_peer_dependency/snapshots/migration_skip_vite_peer_dependency.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_peer_dependency/snapshots/migration_skip_vite_peer_dependency.md index a9256678a8..8ace240699 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_peer_dependency/snapshots/migration_skip_vite_peer_dependency.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_peer_dependency/snapshots/migration_skip_vite_peer_dependency.md @@ -75,7 +75,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_subpath/snapshots/migration_subpath.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_subpath/snapshots/migration_subpath.md index cfb0475ac2..b3a66d2bcc 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_subpath/snapshots/migration_subpath.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_subpath/snapshots/migration_subpath.md @@ -76,7 +76,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_tsconfig_esmoduleinterop/snapshots/migration_tsconfig_esmoduleinterop.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_tsconfig_esmoduleinterop/snapshots/migration_tsconfig_esmoduleinterop.md index 2b16ee3adc..75200493a9 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_tsconfig_esmoduleinterop/snapshots/migration_tsconfig_esmoduleinterop.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_tsconfig_esmoduleinterop/snapshots/migration_tsconfig_esmoduleinterop.md @@ -77,7 +77,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_peer_only_pnpm/snapshots/migration_upgrade_browser_peer_only_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_peer_only_pnpm/snapshots/migration_upgrade_browser_peer_only_pnpm.md index efd79b8d33..caddc39162 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_peer_only_pnpm/snapshots/migration_upgrade_browser_peer_only_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_peer_only_pnpm/snapshots/migration_upgrade_browser_peer_only_pnpm.md @@ -53,8 +53,8 @@ catalog: vitest: '@vitest/browser-playwright': overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_source_only_pnpm/snapshots/migration_upgrade_browser_source_only_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_source_only_pnpm/snapshots/migration_upgrade_browser_source_only_pnpm.md index 32bae9fd21..9f857f2cc1 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_source_only_pnpm/snapshots/migration_upgrade_browser_source_only_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_source_only_pnpm/snapshots/migration_upgrade_browser_source_only_pnpm.md @@ -51,8 +51,8 @@ catalog: vitest: '@vitest/browser-playwright': overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/migration_upgrade_browser_webdriverio_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/migration_upgrade_browser_webdriverio_pnpm.md index dc177aa545..fdf43408bc 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/migration_upgrade_browser_webdriverio_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/migration_upgrade_browser_webdriverio_pnpm.md @@ -50,8 +50,8 @@ catalog: vitest: '@vitest/browser-webdriverio': overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_monorepo_vitest_localized_pnpm/snapshots/migration_upgrade_monorepo_vitest_localized_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_monorepo_vitest_localized_pnpm/snapshots/migration_upgrade_monorepo_vitest_localized_pnpm.md index 6011cd4142..c5969a996a 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_monorepo_vitest_localized_pnpm/snapshots/migration_upgrade_monorepo_vitest_localized_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_monorepo_vitest_localized_pnpm/snapshots/migration_upgrade_monorepo_vitest_localized_pnpm.md @@ -66,8 +66,8 @@ catalog: vitest: '@vitest/ui': overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_nuxt_test_utils_monorepo/snapshots/migration_upgrade_nuxt_test_utils_monorepo.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_nuxt_test_utils_monorepo/snapshots/migration_upgrade_nuxt_test_utils_monorepo.md index 70d345c6fb..465554a573 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_nuxt_test_utils_monorepo/snapshots/migration_upgrade_nuxt_test_utils_monorepo.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_nuxt_test_utils_monorepo/snapshots/migration_upgrade_nuxt_test_utils_monorepo.md @@ -58,8 +58,8 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_peer_vitest_catalog_pnpm/snapshots/migration_upgrade_peer_vitest_catalog_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_peer_vitest_catalog_pnpm/snapshots/migration_upgrade_peer_vitest_catalog_pnpm.md index bb93cfacb9..9c3d0f07fa 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_peer_vitest_catalog_pnpm/snapshots/migration_upgrade_peer_vitest_catalog_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_peer_vitest_catalog_pnpm/snapshots/migration_upgrade_peer_vitest_catalog_pnpm.md @@ -50,7 +50,7 @@ catalog: catalogs: test: {} overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pkg_pr_new_pnpm/snapshots/migration_upgrade_pkg_pr_new_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pkg_pr_new_pnpm/snapshots/migration_upgrade_pkg_pr_new_pnpm.md index 73f1e0697a..59094af3ff 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pkg_pr_new_pnpm/snapshots/migration_upgrade_pkg_pr_new_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pkg_pr_new_pnpm/snapshots/migration_upgrade_pkg_pr_new_pnpm.md @@ -51,8 +51,8 @@ catalog: '@vitest/coverage-v8': overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: @@ -107,8 +107,8 @@ catalog: '@vitest/coverage-v8': overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm9_overrides/snapshots/migration_upgrade_pnpm9_overrides.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm9_overrides/snapshots/migration_upgrade_pnpm9_overrides.md index 75326c8e91..79bec01712 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm9_overrides/snapshots/migration_upgrade_pnpm9_overrides.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm9_overrides/snapshots/migration_upgrade_pnpm9_overrides.md @@ -33,8 +33,8 @@ pnpm.overrides stay catalog: (not inlined to a version) "packageManager": "pnpm@9.15.9", "pnpm": { "overrides": { - "vite": "catalog:", - "vitest": "catalog:" + "vite@*": "catalog:", + "vitest@*": "catalog:" }, "peerDependencyRules": { "allowAny": [ diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_bundled_catalog_dep/snapshots/migration_upgrade_pnpm_bundled_catalog_dep.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_bundled_catalog_dep/snapshots/migration_upgrade_pnpm_bundled_catalog_dep.md index a3374883fc..9e63d36f5e 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_bundled_catalog_dep/snapshots/migration_upgrade_pnpm_bundled_catalog_dep.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_bundled_catalog_dep/snapshots/migration_upgrade_pnpm_bundled_catalog_dep.md @@ -48,7 +48,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_catalogs_default/snapshots/migration_upgrade_pnpm_catalogs_default.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_catalogs_default/snapshots/migration_upgrade_pnpm_catalogs_default.md index ccc31e394e..1cb71f44bd 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_catalogs_default/snapshots/migration_upgrade_pnpm_catalogs_default.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_catalogs_default/snapshots/migration_upgrade_pnpm_catalogs_default.md @@ -51,7 +51,7 @@ catalogs: default: rari: ^0.14.12 overrides: - vite: catalog:build + vite@*: catalog:build peerDependencyRules: allowAny: - vite @@ -105,7 +105,7 @@ catalogs: default: rari: ^0.14.12 overrides: - vite: catalog:build + vite@*: catalog:build peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_named_catalog/snapshots/migration_upgrade_pnpm_named_catalog.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_named_catalog/snapshots/migration_upgrade_pnpm_named_catalog.md index 40b0585e24..13dae38604 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_named_catalog/snapshots/migration_upgrade_pnpm_named_catalog.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_named_catalog/snapshots/migration_upgrade_pnpm_named_catalog.md @@ -52,7 +52,7 @@ catalogs: vitest: vite-plus: overrides: - vite: catalog:vite-stack + vite@*: catalog:vite-stack peerDependencyRules: allowAny: - vite @@ -107,7 +107,7 @@ catalogs: vitest: vite-plus: overrides: - vite: catalog:vite-stack + vite@*: catalog:vite-stack peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_setup_skipped_default_pnpm/snapshots/migration_upgrade_setup_skipped_default_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_setup_skipped_default_pnpm/snapshots/migration_upgrade_setup_skipped_default_pnpm.md index ff51ead3c4..dced98c173 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_setup_skipped_default_pnpm/snapshots/migration_upgrade_setup_skipped_default_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_setup_skipped_default_pnpm/snapshots/migration_upgrade_setup_skipped_default_pnpm.md @@ -43,7 +43,7 @@ pnpm settings consolidated by the version upgrade ``` overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_stale_local_pnpm/snapshots/migration_upgrade_stale_local_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_stale_local_pnpm/snapshots/migration_upgrade_stale_local_pnpm.md index e0f3dbf1ae..e02b10c9fb 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_stale_local_pnpm/snapshots/migration_upgrade_stale_local_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_stale_local_pnpm/snapshots/migration_upgrade_stale_local_pnpm.md @@ -45,7 +45,7 @@ pnpm settings should be consolidated here ``` overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_vitest_reference_whitespace_pnpm/snapshots/migration_upgrade_vitest_reference_whitespace_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_vitest_reference_whitespace_pnpm/snapshots/migration_upgrade_vitest_reference_whitespace_pnpm.md index b0ffe8fbf3..3ace8f239c 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_vitest_reference_whitespace_pnpm/snapshots/migration_upgrade_vitest_reference_whitespace_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_vitest_reference_whitespace_pnpm/snapshots/migration_upgrade_vitest_reference_whitespace_pnpm.md @@ -53,7 +53,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_plus_in_dependencies_pnpm/snapshots/migration_vite_plus_in_dependencies_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_plus_in_dependencies_pnpm/snapshots/migration_vite_plus_in_dependencies_pnpm.md index 519bdb33cf..2f08121e54 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_plus_in_dependencies_pnpm/snapshots/migration_vite_plus_in_dependencies_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_plus_in_dependencies_pnpm/snapshots/migration_vite_plus_in_dependencies_pnpm.md @@ -47,7 +47,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_peer_dep/snapshots/migration_vitest_peer_dep.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_peer_dep/snapshots/migration_vitest_peer_dep.md index 69bfb7af17..17f735d8f0 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_peer_dep/snapshots/migration_vitest_peer_dep.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_peer_dep/snapshots/migration_vitest_peer_dep.md @@ -49,8 +49,8 @@ catalog: vitest: vite-plus: overrides: - vite: 'catalog:' - vitest: 'catalog:' + vite@*: 'catalog:' + vitest@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_unmanaged_override/snapshots/migration_vitest_unmanaged_override.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_unmanaged_override/snapshots/migration_vitest_unmanaged_override.md index 1d232688d4..8278e5fb88 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_unmanaged_override/snapshots/migration_vitest_unmanaged_override.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_unmanaged_override/snapshots/migration_vitest_unmanaged_override.md @@ -48,7 +48,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@latest vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/snapshots/new_vite_monorepo.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/snapshots/new_vite_monorepo.md index 6041f8f930..6667489dc5 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/snapshots/new_vite_monorepo.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/snapshots/new_vite_monorepo.md @@ -93,7 +93,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: "catalog:" + vite@*: "catalog:" peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/redact.rs b/crates/vp_cli_snapshots/tests/cli_snapshots/redact.rs index f8ddee50c9..100737e2f1 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/redact.rs +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/redact.rs @@ -56,10 +56,13 @@ static TOOL_VERSION_RE: LazyLock = LazyLock::new(|| { // context while leaving other dep versions (core-js, typescript, ...) // assertable. The `vite-plus` key form requires a line-leading key so package // NAME values like `"vite-plus-application"` are untouched, and it needs a -// digit after the separator so `vite-plus: catalog:` stays verbatim. +// digit after the separator so `vite-plus: catalog:` stays verbatim. The core +// alias also accepts a leading `^`/`~`: a package manager that resolves the +// alias itself writes back a RANGE (`npm:@voidzero-dev/vite-plus-core@^0.2.8`), +// which churns per release exactly like the exact form. static VP_VERSION_RE: LazyLock = LazyLock::new(|| { regex::Regex::new( - r#"(?m)(^\s*"?vite-plus"?\s*:\s*"?|@voidzero-dev/vite-plus-core@)\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?"#, + r#"(?m)(^\s*"?vite-plus"?\s*:\s*"?|@voidzero-dev/vite-plus-core@[\^~]?)\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?"#, ) .unwrap() }); diff --git a/docs/guide/migrate-rules.md b/docs/guide/migrate-rules.md index 561cbacf73..7e24571381 100644 --- a/docs/guide/migrate-rules.md +++ b/docs/guide/migrate-rules.md @@ -82,6 +82,14 @@ Related rules: - A direct `vite` declaration is never removed merely because a root override exists. - Plain or stale aliases are normalized; named catalog references are kept. +- Under pnpm the managed override keys carry an explicit `@*` range (`vite@*`, + `vitest@*`). pnpm applies overrides by replacing the declared spec on every + manifest, importers included, and a bare key matches any spec — including + `catalog:`, which would make `vp up` rewrite the reference to a concrete + version. The range keeps the override on the transitive and peer declarations + it exists for and leaves `catalog:` references to the catalog, which already + resolves them to Vite+ core. Migration re-keys a project still carrying the + bare key and preserves its named-catalog choice. - The direct-entry rule above is pnpm-specific. Bun mirrors its core alias as a direct dependency for its peer resolver, and npm browser-provider layouts may need a top-level `vite` edge so nested Vitest packages can resolve diff --git a/docs/guide/upgrade.md b/docs/guide/upgrade.md index 83bdb64ae2..7fb21b84f6 100644 --- a/docs/guide/upgrade.md +++ b/docs/guide/upgrade.md @@ -69,7 +69,9 @@ If you migrated with `vp migrate`, your project pins `vitest` to an exact versio - **npm / Bun:** a `vitest` entry under `overrides` in `package.json` - **Yarn:** a `vitest` entry under `resolutions` in `package.json` -- **pnpm:** a `vitest` entry under `overrides` in `pnpm-workspace.yaml` — unless your `package.json` already had a `pnpm` field, in which case it lives under `pnpm.overrides` in `package.json` instead (pnpm ignores `pnpm-workspace.yaml` overrides when `package.json` defines `pnpm.overrides`) +- **pnpm:** a `vitest@*` entry under `overrides` in `pnpm-workspace.yaml` — unless your `package.json` already had a `pnpm` field, in which case it lives under `pnpm.overrides` in `package.json` instead (pnpm ignores `pnpm-workspace.yaml` overrides when `package.json` defines `pnpm.overrides`) + +Under pnpm the managed keys carry an explicit `@*` range (`vite@*`, `vitest@*`). pnpm applies overrides by replacing the declared spec on every manifest, importers included, and a bare key matches any spec — including `catalog:`. The range keeps the override on the transitive and peer declarations it exists for while leaving `catalog:` references intact, so `vp up` no longer rewrites them to a concrete version. A Vite+ release can bump the bundled Vitest. Because that pin also applies to `vite-plus`'s own `vitest` dependency, an out-of-date pin keeps installing the previous runner even after you upgrade `vite-plus` — splitting Vitest's internals (mocks, `expect`, runner state) between the pinned copy and the one `vp test` loads. diff --git a/packages/cli/src/create/templates/monorepo.ts b/packages/cli/src/create/templates/monorepo.ts index 27e4a09baa..159a3086b9 100644 --- a/packages/cli/src/create/templates/monorepo.ts +++ b/packages/cli/src/create/templates/monorepo.ts @@ -231,20 +231,21 @@ export function alignMonorepoTypeScriptVersion( * scaffolded sub-package. After migration its scripts already use `vp ...` and * nothing imports `'vite'` directly, so `vite-plus` provides them transitively. * - * pnpm is the exception and keeps them: pnpm only surfaces the - * pnpm-workspace.yaml `overrides.vite: catalog:` entry through a package that - * directly depends on `vite`, so keeping the aliased devDep lets `vp why vite` - * reflect the override (resolving to @voidzero-dev/vite-plus-core). npm, yarn, - * and bun redirect the transitive/peer vite via their root - * overrides/resolutions regardless of a direct dep, so the aliased keys are - * dead weight and are dropped. + * pnpm is the exception and keeps them: a package needs a DIRECT `vite` edge for + * `vite` to resolve to @voidzero-dev/vite-plus-core there (and for `vp why vite` + * to show it) rather than pnpm auto-installing an upstream Vite to satisfy + * Vitest's peer. Migration points that edge at the workspace catalog, which owns + * the alias; the `vite@*` workspace override covers the transitive and peer + * declarations instead (see `pnpmOverrideKey`). npm, yarn, and bun redirect the + * transitive/peer vite via their root overrides/resolutions regardless of a + * direct dep, so the aliased keys are dead weight and are dropped. */ export function dropAliasedRuntimeDevDeps( appProjectPath: string, packageManager: PackageManager, ): void { - // pnpm keeps the aliased vite/vitest so the pnpm-workspace.yaml override has - // a direct consumer to redirect; see the doc comment above. + // pnpm keeps the aliased vite/vitest so the package has a direct `vite` edge + // to point at the workspace catalog; see the doc comment above. if (packageManager === PackageManager.pnpm) { return; } diff --git a/packages/cli/src/migration/__tests__/migrator.spec.ts b/packages/cli/src/migration/__tests__/migrator.spec.ts index f853aaa24c..3b6fb5b78e 100644 --- a/packages/cli/src/migration/__tests__/migrator.spec.ts +++ b/packages/cli/src/migration/__tests__/migrator.spec.ts @@ -60,9 +60,16 @@ const { detectYarnPnpMode, configureYarnNodeModulesMode, pnpmSupportsWorkspaceSettings, + pnpmOverrideKey, setPackageManager, } = await import('../migrator.js'); +// pnpm's managed override keys are range-qualified so they never rewrite an +// importer's `catalog:` spec (issue #2309). npm/bun `overrides` and yarn +// `resolutions` keep bare package-name keys. +const PNPM_VITE_OVERRIDE_KEY = pnpmOverrideKey('vite'); +const PNPM_VITEST_OVERRIDE_KEY = pnpmOverrideKey('vitest'); + const { collectMigrationSetupPlan } = await import('../setup-plan.js'); describe('pnpm workspace settings support', () => { @@ -2870,7 +2877,7 @@ describe('ensureVitePlusBootstrap', () => { catalog?: Record; }; // The vite override stays `catalog:` (settings remain in package.json below 10.6.2). - expect(rootPkg.pnpm?.overrides?.vite).toBe('catalog:'); + expect(rootPkg.pnpm?.overrides?.[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:'); // The catalog entries are rewritten off the stale 0.1.18 wrappers. expect(workspace.catalog?.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); expect(workspace.catalog?.['vite-plus']).toBe('latest'); @@ -3453,7 +3460,7 @@ describe('ensureVitePlusBootstrap', () => { }; expect(workspace.catalog['@vitest/browser-playwright']).toBe(VITEST_VERSION); expect(workspace.catalog.vitest).toBe(VITEST_VERSION); - expect(workspace.overrides.vitest).toBe('catalog:'); + expect(workspace.overrides[PNPM_VITEST_OVERRIDE_KEY]).toBe('catalog:'); expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); }); @@ -3640,8 +3647,9 @@ describe('ensureVitePlusBootstrap', () => { // Managed `vitest` is gone from every sink; `vite` stays managed. expect(workspace.catalog.vitest).toBeUndefined(); expect(workspace.catalog.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); + expect(workspace.overrides[PNPM_VITEST_OVERRIDE_KEY]).toBeUndefined(); expect(workspace.overrides.vitest).toBeUndefined(); - expect(workspace.overrides.vite).toBe('catalog:'); + expect(workspace.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:'); expect(workspace.peerDependencyRules.allowAny).toEqual(['vite']); expect(workspace.peerDependencyRules.allowedVersions).toEqual({ vite: '*' }); expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); @@ -3716,7 +3724,7 @@ describe('ensureVitePlusBootstrap', () => { overrides: Record; }; expect(workspace.catalog['vite-plus']).toBe('latest'); - expect(workspace.overrides.vite).toBe('catalog:'); + expect(workspace.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:'); }); it('moves existing pnpm settings to pnpm-workspace.yaml', () => { @@ -3839,7 +3847,9 @@ describe('ensureVitePlusBootstrap', () => { }; }; expect(pkg.pnpm.overrides.react).toBe('18.3.1'); - expect(pkg.pnpm.overrides.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); + expect(pkg.pnpm.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe( + 'npm:@voidzero-dev/vite-plus-core@latest', + ); expect(pkg.pnpm.peerDependencyRules.allowAny).toEqual(['react', 'vite']); }); @@ -4697,9 +4707,10 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { }; const overrides = workspace.overrides; expect(overrides['some-pkg']).toBe('1.0.0'); - expect(overrides.vite).toBeDefined(); + expect(overrides[PNPM_VITE_OVERRIDE_KEY]).toBeDefined(); // Common case (no @vitest/* dep, no vitest source): `vitest` is not managed, // so no override is written — it arrives transitively through vite-plus. + expect(overrides[PNPM_VITEST_OVERRIDE_KEY]).toBeUndefined(); expect(overrides.vitest).toBeUndefined(); // peerDependencyRules should be present @@ -4745,13 +4756,73 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.pnpm), true, true); const yaml = readYaml(path.join(tmpDir, 'pnpm-workspace.yaml')); - expect(yaml).toContain("vite: 'catalog:'"); + expect(yaml).toContain(`${PNPM_VITE_OVERRIDE_KEY}: 'catalog:'`); // Common case (no @vitest/* dep, no vitest source): `vitest` is not managed, // so no `vitest` override is written — it arrives transitively through // vite-plus. expect(yaml).not.toContain('vitest'); }); + it('range-qualifies managed pnpm override keys so `vp up` keeps `catalog:` (#2309)', () => { + // pnpm applies overrides by REPLACING the declared spec on every manifest, + // importers included. A bare `vite` key has no range and so matches even a + // `catalog:` spec, which strips the catalog provenance and makes + // `pnpm update` write the resolved core alias into package.json. `vite@*` + // matches every real semver range (what transitive/peer `vite` uses) and + // never `catalog:`, which is not a valid range. + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ name: 'test', devDependencies: { vite: '^7.0.0' } }), + ); + rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.pnpm), true, true); + + const workspace = readYamlObject(path.join(tmpDir, 'pnpm-workspace.yaml')) as { + overrides: Record; + }; + const pkg = readJson(path.join(tmpDir, 'package.json')) as { + devDependencies: Record; + }; + expect(PNPM_VITE_OVERRIDE_KEY).toBe('vite@*'); + expect(Object.keys(workspace.overrides)).toEqual([PNPM_VITE_OVERRIDE_KEY]); + expect(workspace.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:'); + // The importer keeps referencing the catalog: that is what the override key + // must no longer be able to rewrite. + expect(pkg.devDependencies.vite).toBe('catalog:'); + }); + + it('drops a pre-#2309 bare managed pnpm override key when adding the ranged one', () => { + // Leaving both keys in place would restore the clobbering match, so the bare + // key hands its `catalog:` choice over and is removed. + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ name: 'test', devDependencies: { vite: 'catalog:' } }), + ); + fs.writeFileSync( + path.join(tmpDir, 'pnpm-workspace.yaml'), + [ + 'overrides:', + " vite: 'catalog:'", + ' react: 18.3.1', + 'catalog:', + ' vite: npm:@voidzero-dev/vite-plus-core@latest', + '', + ].join('\n'), + ); + rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.pnpm), true, true); + + const workspace = readYamlObject(path.join(tmpDir, 'pnpm-workspace.yaml')) as { + overrides: Record; + }; + expect(workspace.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:'); + expect(workspace.overrides).not.toHaveProperty('vite'); + // Unrelated user overrides are untouched — the rewrite only re-keys managed + // entries. + expect(workspace.overrides.react).toBe('18.3.1'); + // A project still on the bare key must read as pending so one `vp migrate` + // repairs it; once re-keyed it converges. + expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); + }); + it('rewrites named catalogs in pnpm-workspace.yaml without adding new entries', () => { fs.writeFileSync( path.join(tmpDir, 'package.json'), @@ -4791,11 +4862,15 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { overrides: Record; catalogs: Record>; }; - expect(yaml.overrides.vite).toBe('catalog:vite7'); + // A pre-#2309 bare key hands its named-catalog choice to the range-qualified + // key and is dropped, so only one managed `vite` override remains. + expect(yaml.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:vite7'); + expect(yaml.overrides.vite).toBeUndefined(); // Common case (no @vitest/* dep, no vitest source): `vitest` is not managed, // so no override is added and the pre-existing managed `vitest` catalog // entries (default + named) are REMOVED — it arrives transitively through // vite-plus. + expect(yaml.overrides[PNPM_VITEST_OVERRIDE_KEY]).toBeUndefined(); expect(yaml.overrides.vitest).toBeUndefined(); expect(yaml.catalog?.vitest).toBeUndefined(); expect(yaml.catalogs.vite7.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); @@ -4868,7 +4943,7 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { expect(workspace.catalogs.default).toEqual({ rari: '^0.14.12' }); expect(workspace.catalogs.build.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); expect(workspace.catalogs.build['vite-plus']).toBe('latest'); - expect(workspace.overrides.vite).toBe('catalog:build'); + expect(workspace.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:build'); expect(pkg.devDependencies.vite).toBe('catalog:build'); expect(pkg.devDependencies['vite-plus']).toBe('catalog:build'); expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); @@ -4919,7 +4994,7 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { expect(workspace.catalogs.default.react).toBe('^19.0.0'); expect(workspace.catalogs.default.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); expect(workspace.catalogs.default['vite-plus']).toBe('latest'); - expect(workspace.overrides.vite).toBe('catalog:'); + expect(workspace.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:'); expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); }); @@ -4973,7 +5048,7 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { expect(workspace.catalogs['repo-tooling']).toEqual({ prettier: '3.8.3' }); expect(workspace.catalogs['vite-stack'].vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); expect(workspace.catalogs['vite-stack']['vite-plus']).toBe('latest'); - expect(workspace.overrides.vite).toBe('catalog:vite-stack'); + expect(workspace.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:vite-stack'); expect(pkg.devDependencies.vite).toBe('catalog:vite-stack'); expect(pkg.devDependencies['vite-plus']).toBe('catalog:vite-stack'); expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); @@ -5537,7 +5612,7 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { expect(yaml.overrides).not.toHaveProperty('@vitejs/plugin-react>vite'); expect(yaml.overrides).not.toHaveProperty('vite-plugin-svgr>vite'); // The managed `vite` override stays and unrelated selectors survive. - expect(yaml.overrides).toHaveProperty('vite'); + expect(yaml.overrides).toHaveProperty(PNPM_VITE_OVERRIDE_KEY); expect(yaml.overrides['some-other-pkg']).toBe('1.0.0'); }); @@ -6277,9 +6352,11 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { overrides: Record; catalogs: Record>; }; - expect(yaml.overrides.vite).toBe('catalog:vite7'); + expect(yaml.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:vite7'); + expect(yaml.overrides.vite).toBeUndefined(); // Common case (no @vitest/* dep, no vitest source): `vitest` is not managed, // so no `vitest` override is injected. + expect(yaml.overrides[PNPM_VITEST_OVERRIDE_KEY]).toBeUndefined(); expect(yaml.overrides.vitest).toBeUndefined(); expect(yaml.overrides.react).toBe('^18.0.0'); expect(yaml.catalogs.vite7.vite).toBe('npm:@voidzero-dev/vite-plus-core@latest'); @@ -6323,9 +6400,11 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { const yaml = readYamlObject(path.join(tmpDir, 'pnpm-workspace.yaml')) as { overrides: Record; }; - expect(yaml.overrides.vite).toBe('catalog:'); + expect(yaml.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:'); + expect(yaml.overrides.vite).toBeUndefined(); // Common case (no @vitest/* dep, no vitest source): `vitest` is not managed, // so no `vitest` override is added. + expect(yaml.overrides[PNPM_VITEST_OVERRIDE_KEY]).toBeUndefined(); expect(yaml.overrides.vitest).toBeUndefined(); }); diff --git a/packages/cli/src/migration/migrator/catalog.ts b/packages/cli/src/migration/migrator/catalog.ts index 341b85847c..7f86ea8dc8 100644 --- a/packages/cli/src/migration/migrator/catalog.ts +++ b/packages/cli/src/migration/migrator/catalog.ts @@ -36,6 +36,7 @@ import { REMOVE_PACKAGES, VITEST_IS_MANAGED_OVERRIDE, isPlainRecord, + pnpmOverrideKey, type CatalogDependencyResolver, type PackageJsonDependencyField, type PnpmPackageJsonSettings, @@ -313,11 +314,20 @@ export function rewritePnpmWorkspaceYaml( removeYamlMapVitestEntry(doc.getIn(['overrides'])); } for (const key of Object.keys(managed)) { - const currentVersion = getYamlMapScalarStringValue(overrides, key); + // Managed keys are range-qualified (`vite@*`) so the override never + // rewrites an importer's `catalog:` spec — see `pnpmOverrideKey`. Carry a + // pre-#2309 bare key's value over to the new key so a user's own + // `catalog:` choice survives, then drop the bare key: leaving both + // in place would restore the clobbering match. + const overrideKey = pnpmOverrideKey(key); + const currentVersion = + getYamlMapScalarStringValue(overrides, overrideKey) ?? + getYamlMapScalarStringValue(overrides, key); const version = getCatalogDependencySpec(currentVersion, managed[key], true, { preferredCatalogSpec, }); - doc.setIn(['overrides', scalarString(key)], scalarString(version)); + deleteYamlMapKey(overrides, key); + doc.setIn(['overrides', scalarString(overrideKey)], scalarString(version)); } // remove dependency selector from vite, e.g. "vite-plugin-svgr>vite": "npm:vite@7.0.12" // Snapshot the keys before deleting (mirrors the `keysSnapshot` loop above): @@ -575,14 +585,17 @@ export function getCatalogDependencySpec( /** * #1932: under pnpm, an importer that depends on `vite-plus` (which bundles - * `vitest`) needs a DIRECT `vite` devDep so the `vite` override binds vitest's - * required `vite` peer to @voidzero-dev/vite-plus-core. Without a direct edge, - * pnpm's `autoInstallPeers` fabricates a separate upstream `vite` to satisfy the + * `vitest`) needs a DIRECT `vite` devDep pointing at @voidzero-dev/vite-plus-core + * so vitest's required `vite` peer binds to it. Without a direct edge, pnpm's + * `autoInstallPeers` fabricates a separate upstream `vite` to satisfy the * peer, splitting vite-plus / vite / vitest into duplicate instances (the extra * vite also lacks vite's `@voidzero-dev/vite-task-client` integration, breaking - * the `vp test` cache). npm/yarn/bun redirect transitive/peer vite via root - * overrides/resolutions (and drop the aliased vite), so this is pnpm-only, - * mirroring the bun root-package branch in `rewriteRootWorkspacePackageJson`. + * the `vp test` cache). Under a catalog the edge is a `catalog:` reference and + * the catalog entry carries the alias; the `vite@*` workspace override covers + * transitive and peer declarations instead of this one (see `pnpmOverrideKey`). + * npm/yarn/bun redirect transitive/peer vite via root overrides/resolutions (and + * drop the aliased vite), so this is pnpm-only, mirroring the bun root-package + * branch in `rewriteRootWorkspacePackageJson`. * * A package that already declares `vite` in ANY dependency field, including * `peerDependencies` (e.g. a vite plugin pinning `vite ^6`), is left untouched @@ -823,6 +836,21 @@ function getYamlMapScalarStringValue(map: unknown, key: string): string | undefi return undefined; } +// Delete a key by its literal name. `YAMLMap.delete` compares the key NODE, so +// the node has to be looked up in `.items` first — passing a fresh scalar would +// silently no-op. +function deleteYamlMapKey(map: unknown, key: string): void { + if (!(map instanceof YAMLMap)) { + return; + } + const target = map.items.find( + (item) => item.key instanceof Scalar && item.key.value === key, + )?.key; + if (target) { + map.delete(target); + } +} + function pruneYamlMapLegacyWrapperAliases(map: unknown): void { if (!(map instanceof YAMLMap)) { return; diff --git a/packages/cli/src/migration/migrator/orchestrators.ts b/packages/cli/src/migration/migrator/orchestrators.ts index af187c1d12..0ff4862a31 100644 --- a/packages/cli/src/migration/migrator/orchestrators.ts +++ b/packages/cli/src/migration/migrator/orchestrators.ts @@ -56,6 +56,7 @@ import { type MigrationReport } from '../report.ts'; import { PROVIDER_OVERRIDE_DROP_NAMES, pnpmMajor, + pnpmOverrideKey, type CatalogDependencyResolver, type PnpmPackageJsonSettings, } from './shared.ts'; @@ -190,12 +191,27 @@ export function rewriteStandaloneProject( removeVitestPeerDependencyRule(pkg.pnpm.peerDependencyRules); } } + // Managed pnpm override keys are range-qualified (`vite@*`) so they never + // rewrite an importer's `catalog:` spec — see `pnpmOverrideKey`. Drop the + // pre-#2309 bare keys the user's config may still carry; keeping both + // would restore the clobbering match. `peerDependencyRules` below keys on + // plain package names and stays bare. + for (const key of overrideKeys) { + delete pkg.pnpm?.overrides?.[key]; + } // Project already has pnpm config in package.json -- keep using it. pkg.pnpm = { ...pkg.pnpm, overrides: { ...pkg.pnpm?.overrides, - ...managed, + ...Object.fromEntries( + Object.entries(managed).map(([key, spec]) => [pnpmOverrideKey(key), spec]), + ), + // The force-override `vite-plus` pin keeps a BARE key: it only exists + // in `file:` tgz mode, where migration writes the tgz spec straight + // into every manifest instead of a `catalog:` reference, so there is + // no catalog provenance for a bare key to strip. This matches the + // workspace-yaml force-override path in `rewriteStandaloneProject`. ...(isForceOverrideMode() ? { [VITE_PLUS_NAME]: VITE_PLUS_VERSION } : {}), }, peerDependencyRules: { diff --git a/packages/cli/src/migration/migrator/shared.ts b/packages/cli/src/migration/migrator/shared.ts index 1ab9aa861e..91691a5051 100644 --- a/packages/cli/src/migration/migrator/shared.ts +++ b/packages/cli/src/migration/migrator/shared.ts @@ -161,6 +161,47 @@ export const LEGACY_WRAPPER_FALLBACK_VERSIONS: Record = { vitest: VITEST_VERSION, }; +/** + * Managed pnpm override keys carry an explicit `@*` range instead of being bare + * package names (`vite@*`, not `vite`). + * + * pnpm applies overrides through a read-package hook that REPLACES the declared + * spec on every manifest, importers included, before resolution runs. A BARE + * override key has no range, and pnpm treats "no range" as "matches every + * declared spec" — `catalog:` included. An importer that declares + * `vite: "catalog:"` therefore loses its catalog provenance during resolution, + * and `pnpm update` writes the resolved core alias back into its package.json + * (issue #2309). Qualifying the key with `@*` keeps the override on every real + * semver range — which is what the transitive and peer `vite` declarations this + * override exists for always use — while leaving `catalog:` specs alone: `*` is + * a valid range and `catalog:` is not, so pnpm's `isIntersectingRange` never + * matches the two. Nothing changes about what gets installed, because an + * importer that references the catalog already resolves to the aliased core + * through its catalog entry. + * + * This is pnpm-only. npm/bun `overrides` and yarn `resolutions` keep bare keys: + * those managers have no `catalog:` importer specs to lose (bun catalogs live in + * package.json and are resolved before overrides apply). + */ +export function pnpmOverrideKey(dependencyName: string): string { + return `${dependencyName}@*`; +} + +/** + * How a sink spells its managed override keys: pnpm's `overrides` use the + * range-qualified form ({@link pnpmOverrideKey}), every other sink uses the bare + * package name. A pnpm sink still carrying a bare managed key predates the + * #2309 fix, so it deliberately reads as UNSATISFIED and gets rewritten. + */ +export type ManagedOverrideKeyStyle = 'bare' | 'pnpm-ranged'; + +export function managedOverrideKey( + dependencyName: string, + keyStyle: ManagedOverrideKeyStyle, +): string { + return keyStyle === 'pnpm-ranged' ? pnpmOverrideKey(dependencyName) : dependencyName; +} + export type PackageJsonDependencyField = | 'devDependencies' | 'dependencies' diff --git a/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts b/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts index ffdf0d776e..8a0ee731e5 100644 --- a/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts +++ b/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts @@ -59,8 +59,10 @@ import { OPT_IN_BROWSER_PROVIDERS, REMOVE_PACKAGES, VITEST_IS_MANAGED_OVERRIDE, + managedOverrideKey, pnpmMajor, type CatalogDependencyResolver, + type ManagedOverrideKeyStyle, type PnpmPackageJsonSettings, } from './shared.ts'; @@ -143,16 +145,24 @@ export function overridesSatisfyVitePlus( overrides: Record | undefined, usesVitest: boolean, catalogDependencyResolver?: CatalogDependencyResolver, + keyStyle: ManagedOverrideKeyStyle = 'bare', ): boolean { // Common case: a lingering managed `vitest` override is NOT satisfied — it - // must be removed, so the bootstrap stays pending until it is. - if (!usesVitest && VITEST_IS_MANAGED_OVERRIDE && typeof overrides?.vitest === 'string') { + // must be removed, so the bootstrap stays pending until it is. Both key + // spellings count: a pnpm sink migrated before #2309 still carries the bare + // one (see `managedOverrideKey`). + if ( + !usesVitest && + VITEST_IS_MANAGED_OVERRIDE && + (typeof overrides?.[managedOverrideKey('vitest', keyStyle)] === 'string' || + typeof overrides?.vitest === 'string') + ) { return false; } return Object.keys(managedOverridePackages(usesVitest)).every((dependencyName) => overrideSpecSatisfiesVitePlus( dependencyName, - overrides?.[dependencyName], + overrides?.[managedOverrideKey(dependencyName, keyStyle)], catalogDependencyResolver, ), ); @@ -743,20 +753,30 @@ export function detectVitePlusBootstrapPending( if (supportCatalog) { return ( catalogVitePlusDependencyPending(pkg, catalogDependencyResolver) || - !overridesSatisfyVitePlus(pkg.pnpm?.overrides, usesVitest, catalogDependencyResolver) || + !overridesSatisfyVitePlus( + pkg.pnpm?.overrides, + usesVitest, + catalogDependencyResolver, + 'pnpm-ranged', + ) || !pnpmPeerDependencyRulesSatisfyVitePlus(pkg.pnpm?.peerDependencyRules, usesVitest) ); } return ( vitePlusDependencyNeedsConcreteVersion(pkg) || - !overridesSatisfyVitePlus(pkg.pnpm?.overrides, usesVitest) || + !overridesSatisfyVitePlus(pkg.pnpm?.overrides, usesVitest, undefined, 'pnpm-ranged') || !pnpmPeerDependencyRulesSatisfyVitePlus(pkg.pnpm?.peerDependencyRules, usesVitest) ); } const resolver = readPnpmWorkspaceCatalogDependencyResolver(projectPath); return ( workspaceCatalogVitePlusDependencyPending(projectPath, packages, resolver) || - !overridesSatisfyVitePlus(readPnpmWorkspaceOverrides(projectPath), usesVitest, resolver) || + !overridesSatisfyVitePlus( + readPnpmWorkspaceOverrides(projectPath), + usesVitest, + resolver, + 'pnpm-ranged', + ) || !pnpmPeerDependencyRulesSatisfyVitePlus( readPnpmWorkspacePeerDependencyRules(projectPath), usesVitest, @@ -850,6 +870,7 @@ function ensureOverrideEntries( overrides: Record | undefined, usesVitest: boolean, catalogDependencyResolver?: CatalogDependencyResolver, + keyStyle: ManagedOverrideKeyStyle = 'bare', ): { overrides: Record; changed: boolean } { const next = { ...overrides }; let changed = false; @@ -860,15 +881,20 @@ function ensureOverrideEntries( for (const [dependencyName, overrideSpec] of Object.entries( managedOverridePackages(usesVitest), )) { - if ( - !overrideSpecSatisfiesVitePlus( - dependencyName, - next[dependencyName], - catalogDependencyResolver, - ) - ) { - next[dependencyName] = overrideSpec; + const overrideKey = managedOverrideKey(dependencyName, keyStyle); + // Carry a pre-#2309 bare key's value over to the range-qualified key so the + // user's own `catalog:` choice survives, then drop the bare key — + // keeping both would restore the match that clobbers `catalog:` importers. + const currentSpec = next[overrideKey] ?? next[dependencyName]; + if (overrideKey !== dependencyName && next[dependencyName] !== undefined) { + delete next[dependencyName]; + changed = true; + } + if (!overrideSpecSatisfiesVitePlus(dependencyName, currentSpec, catalogDependencyResolver)) { + next[overrideKey] = overrideSpec; changed = true; + } else if (next[overrideKey] !== currentSpec) { + next[overrideKey] = currentSpec; } } return { overrides: next, changed }; @@ -1052,6 +1078,7 @@ export function ensureVitePlusBootstrap( pkg.pnpm.overrides, usesVitest, supportCatalog ? readPnpmWorkspaceCatalogDependencyResolver(projectPath) : undefined, + 'pnpm-ranged', ); if (ensured.changed) { pkg.pnpm.overrides = ensured.overrides; @@ -1151,6 +1178,7 @@ export function ensureVitePlusBootstrap( readPnpmWorkspaceOverrides(projectPath), usesVitest, catalogDependencyResolver, + 'pnpm-ranged', ) || !pnpmPeerDependencyRulesSatisfyVitePlus( readPnpmWorkspacePeerDependencyRules(projectPath), diff --git a/packages/cli/src/migration/migrator/vitest-ecosystem.ts b/packages/cli/src/migration/migrator/vitest-ecosystem.ts index 8cf68984f6..f161c891c7 100644 --- a/packages/cli/src/migration/migrator/vitest-ecosystem.ts +++ b/packages/cli/src/migration/migrator/vitest-ecosystem.ts @@ -25,6 +25,7 @@ import { REMOVE_PACKAGES, VITEST_BROWSER_DEP_NAMES, VITEST_IS_MANAGED_OVERRIDE, + pnpmOverrideKey, type CatalogDependencyResolver, type PackageJsonDependencyField, } from './shared.ts'; @@ -546,12 +547,22 @@ export function projectUsesVitestDirectly( // alias is always a string, whereas a nested object value (npm/bun `overrides`) // is a user override scoped under `vitest` and must be left intact. Returns true // iff an entry was removed. +// +// pnpm override sinks spell the managed key `vitest@*` (see `pnpmOverrideKey`), +// so both spellings are swept: which one a project carries depends on whether it +// was last migrated before or after the #2309 fix. export function removeManagedVitestEntry(record: Record | undefined): boolean { - if (VITEST_IS_MANAGED_OVERRIDE && typeof record?.vitest === 'string') { - delete record.vitest; - return true; + if (!VITEST_IS_MANAGED_OVERRIDE || !record) { + return false; } - return false; + let removed = false; + for (const key of Object.keys(record)) { + if (isManagedVitestOverrideKey(key) && typeof record[key] === 'string') { + delete record[key]; + removed = true; + } + } + return removed; } // Remove a managed `vitest` scalar key from a YAMLMap (pnpm-workspace.yaml @@ -560,14 +571,26 @@ export function removeYamlMapVitestEntry(map: unknown): void { if (!VITEST_IS_MANAGED_OVERRIDE || !(map instanceof YAMLMap)) { return; } - const target = map.items.find( - (item) => item.key instanceof Scalar && item.key.value === 'vitest', - )?.key; - if (target) { + const targets = map.items + .filter( + (item) => + item.key instanceof Scalar && + typeof item.key.value === 'string' && + isManagedVitestOverrideKey(item.key.value), + ) + .map((item) => item.key); + for (const target of targets) { map.delete(target); } } +// `vitest` itself, or the range-qualified pnpm override spelling of it. A +// selector-scoped key (`some-app>vitest`) constrains that parent's subtree only +// and is never a managed key, so the `>`-bearing forms stay out. +function isManagedVitestOverrideKey(key: string): boolean { + return key === 'vitest' || key === pnpmOverrideKey('vitest'); +} + // Remove the managed `vitest` entry from pnpm peerDependencyRules (its // `allowAny` array entry and `allowedVersions.vitest`), in place. Works on both // the package.json `pnpm.peerDependencyRules` JSON shape and the same shape read From fb2c466b33ea8902bd522c62a89ab8437456178b Mon Sep 17 00:00:00 2001 From: MK Date: Wed, 12 Aug 2026 09:24:11 +0800 Subject: [PATCH 2/9] test(snapshots): pin the #2309 repair fixture to an exact catalog version The fixture hand-wrote `vite: npm:@voidzero-dev/vite-plus-core@latest` in the catalog, so `vp up` had a real version bump to perform and the clobber read as a side effect of that resolution. The reported case pins an exact version, where the update is a NO-OP and the catalog reference is still destroyed, which is both the reporter's shape and the sharper repro. Let `vp migrate` write the pinned version instead of hard-coding one that would churn each release, then rewind the override key to the pre-fix bare spelling with `vpt replace-file-content` (which also fails loudly if migrate ever stops writing the ranged key). `vp up` now reports "Already up to date" and still rewrites `vite: "catalog:"` to the pinned alias. Reverts the redaction widening from the previous commit: with an exact pin no snapshot produces the `@^0.2.8` range form any more. --- .../package.json | 3 +- .../pnpm-workspace.yaml | 10 ---- .../snapshots.toml | 28 ++++++++-- ...mand_update_catalog_protocol_legacy_key.md | 54 +++++++++++++++++-- .../tests/cli_snapshots/redact.rs | 7 +-- 5 files changed, 76 insertions(+), 26 deletions(-) delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/pnpm-workspace.yaml diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/package.json index 7287fafd0b..62c7db9fa4 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/package.json +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/package.json @@ -2,8 +2,7 @@ "name": "command-update-catalog-protocol-legacy-key", "private": true, "devDependencies": { - "vite": "catalog:", - "vite-plus": "catalog:" + "vite": "^7.0.0" }, "packageManager": "pnpm@11.20.0" } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/pnpm-workspace.yaml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/pnpm-workspace.yaml deleted file mode 100644 index d9df99abda..0000000000 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/pnpm-workspace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -catalog: - vite: npm:@voidzero-dev/vite-plus-core@latest - vite-plus: latest -overrides: - vite: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots.toml index dbfeb886e5..4750d215e9 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots.toml @@ -4,23 +4,43 @@ vp = "global" skip-platforms = ["windows"] unset-env = ["CI", "VP_SKIP_INSTALL"] local-registry = true -comment = "#2309 repair path: a project migrated before the fix carries the bare `vite` override key, which `vp up` uses to clobber `catalog:`. One `vp migrate` re-keys it." +comment = "#2309 repair path. Migrate first so the catalog holds a real PINNED toolchain version (the reporter's shape), then downgrade the override key to the pre-fix bare spelling a project migrated by an older Vite+ still carries." steps = [ + { argv = [ + "vp", + "migrate", + "--no-interactive", + "--no-hooks", + "--package-manager", + "pnpm", + ], comment = "migrate pins the toolchain through the workspace catalog", continue-on-failure = true }, + { argv = [ + "vpt", + "replace-file-content", + "pnpm-workspace.yaml", + "vite@*:", + "vite:", + ], comment = "rewind the override key to the pre-#2309 bare spelling (fails if migrate stopped writing the ranged key)", snapshot = false, continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "pnpm-workspace.yaml", + ], comment = "the pre-fix shape: bare override key over an exactly pinned catalog alias", continue-on-failure = true }, { argv = [ "vp", "up", - ], comment = "the bare override key resolves the catalog reference away", snapshot = false, continue-on-failure = true }, + ], comment = "nothing to update, yet the bare key still resolves the catalog reference away", continue-on-failure = true }, { argv = [ "vpt", "print-file", "package.json", - ], comment = "`vite` lost `catalog:`; `vite-plus` (no override) kept it", continue-on-failure = true }, + ], comment = "`vite` lost `catalog:` for the pinned alias; `vite-plus` (no override) kept it", continue-on-failure = true }, { argv = [ "vp", "migrate", "--no-interactive", "--no-hooks", - ], comment = "migrate repairs both the override key and the clobbered spec", continue-on-failure = true }, + ], comment = "the bare key reads as pending, so one migrate repairs it", continue-on-failure = true }, { argv = [ "vpt", "print-file", diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots/command_update_catalog_protocol_legacy_key.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots/command_update_catalog_protocol_legacy_key.md index 69c2d2ee08..58722b5824 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots/command_update_catalog_protocol_legacy_key.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots/command_update_catalog_protocol_legacy_key.md @@ -1,22 +1,66 @@ # command_update_catalog_protocol_legacy_key -#2309 repair path: a project migrated before the fix carries the bare `vite` override key, which `vp up` uses to clobber `catalog:`. One `vp migrate` re-keys it. +#2309 repair path. Migrate first so the catalog holds a real PINNED toolchain version (the reporter's shape), then downgrade the override key to the pre-fix bare spelling a project migrated by an older Vite+ still carries. + +## `vp migrate --no-interactive --no-hooks --package-manager pnpm` + +migrate pins the toolchain through the workspace catalog + +``` +VITE+ - The Unified Toolchain for the Web + +Formatting code... + +Code formatted +◇ Migrated . to Vite+ +• Node pnpm +✓ Dependencies installed in +• 1 config update applied +``` + +## `vpt replace-file-content pnpm-workspace.yaml vite@*: vite:` + +rewind the override key to the pre-#2309 bare spelling (fails if migrate stopped writing the ranged key) + + +## `vpt print-file pnpm-workspace.yaml` + +the pre-fix shape: bare override key over an exactly pinned catalog alias + +``` +catalog: + vite: npm:@voidzero-dev/vite-plus-core@ + vite-plus: +overrides: + vite: "catalog:" +peerDependencyRules: + allowAny: + - vite + allowedVersions: + vite: "*" +``` ## `vp up` -the bare override key resolves the catalog reference away +nothing to update, yet the bare key still resolves the catalog reference away +``` +✓ Lockfile passes supply-chain policies (verified ago) +Already up to date + +Done in using pnpm +``` ## `vpt print-file package.json` -`vite` lost `catalog:`; `vite-plus` (no override) kept it +`vite` lost `catalog:` for the pinned alias; `vite-plus` (no override) kept it ``` { "name": "command-update-catalog-protocol-legacy-key", "private": true, "devDependencies": { - "vite": "npm:@voidzero-dev/vite-plus-core@^", + "vite": "npm:@voidzero-dev/vite-plus-core@", "vite-plus": "catalog:" }, "packageManager": "pnpm@11.20.0" @@ -25,7 +69,7 @@ the bare override key resolves the catalog reference away ## `vp migrate --no-interactive --no-hooks` -migrate repairs both the override key and the clobbered spec +the bare key reads as pending, so one migrate repairs it ``` VITE+ - The Unified Toolchain for the Web diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/redact.rs b/crates/vp_cli_snapshots/tests/cli_snapshots/redact.rs index 100737e2f1..f8ddee50c9 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/redact.rs +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/redact.rs @@ -56,13 +56,10 @@ static TOOL_VERSION_RE: LazyLock = LazyLock::new(|| { // context while leaving other dep versions (core-js, typescript, ...) // assertable. The `vite-plus` key form requires a line-leading key so package // NAME values like `"vite-plus-application"` are untouched, and it needs a -// digit after the separator so `vite-plus: catalog:` stays verbatim. The core -// alias also accepts a leading `^`/`~`: a package manager that resolves the -// alias itself writes back a RANGE (`npm:@voidzero-dev/vite-plus-core@^0.2.8`), -// which churns per release exactly like the exact form. +// digit after the separator so `vite-plus: catalog:` stays verbatim. static VP_VERSION_RE: LazyLock = LazyLock::new(|| { regex::Regex::new( - r#"(?m)(^\s*"?vite-plus"?\s*:\s*"?|@voidzero-dev/vite-plus-core@[\^~]?)\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?"#, + r#"(?m)(^\s*"?vite-plus"?\s*:\s*"?|@voidzero-dev/vite-plus-core@)\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?"#, ) .unwrap() }); From 6f6e875a1354388977c3300d84f6d1ab0de9536b Mon Sep 17 00:00:00 2001 From: MK Date: Wed, 12 Aug 2026 11:20:33 +0800 Subject: [PATCH 3/9] test(snapshots): re-record the remaining pnpm override-key fixtures These 11 fixtures timed out on the local recording pass (slow managed Node/package-manager downloads), so they kept the pre-#2309 bare `vite` override key and failed CI on all three platforms. Every diff is the key rename; no behavior changed. --- .../snapshots/migration_auto_create_vite_config.md | 2 +- .../snapshots/migration_baseurl_tsconfig.md | 2 +- .../snapshots/migration_existing_pnpm_exec_lint_staged.md | 2 +- .../snapshots/migration_hooks_skip_on_existing_hookspath.md | 2 +- .../snapshots/migration_husky_catalog_version.md | 2 +- .../snapshots/migration_husky_or_prepare.md | 2 +- .../snapshots/migration_lint_staged_merge_fail.md | 2 +- .../snapshots/migration_preserve_below_policy_node_pins.md | 2 +- .../snapshots/migration_standalone_pnpm.md | 2 +- .../migration_vite_version/snapshots/migration_vite_version.md | 2 +- .../snapshots/migration_vitest_import_only.md | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_auto_create_vite_config/snapshots/migration_auto_create_vite_config.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_auto_create_vite_config/snapshots/migration_auto_create_vite_config.md index f366cd9a42..f2565fb662 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_auto_create_vite_config/snapshots/migration_auto_create_vite_config.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_auto_create_vite_config/snapshots/migration_auto_create_vite_config.md @@ -97,7 +97,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_baseurl_tsconfig/snapshots/migration_baseurl_tsconfig.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_baseurl_tsconfig/snapshots/migration_baseurl_tsconfig.md index f6fb39fb4f..934567475c 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_baseurl_tsconfig/snapshots/migration_baseurl_tsconfig.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_baseurl_tsconfig/snapshots/migration_baseurl_tsconfig.md @@ -104,7 +104,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_pnpm_exec_lint_staged/snapshots/migration_existing_pnpm_exec_lint_staged.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_pnpm_exec_lint_staged/snapshots/migration_existing_pnpm_exec_lint_staged.md index 79064c34c7..70c49619b3 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_pnpm_exec_lint_staged/snapshots/migration_existing_pnpm_exec_lint_staged.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_pnpm_exec_lint_staged/snapshots/migration_existing_pnpm_exec_lint_staged.md @@ -54,7 +54,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_hooks_skip_on_existing_hookspath/snapshots/migration_hooks_skip_on_existing_hookspath.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_hooks_skip_on_existing_hookspath/snapshots/migration_hooks_skip_on_existing_hookspath.md index 3f2891395b..28e6cd687f 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_hooks_skip_on_existing_hookspath/snapshots/migration_hooks_skip_on_existing_hookspath.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_hooks_skip_on_existing_hookspath/snapshots/migration_hooks_skip_on_existing_hookspath.md @@ -49,7 +49,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_catalog_version/snapshots/migration_husky_catalog_version.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_catalog_version/snapshots/migration_husky_catalog_version.md index f06baa58b3..465016b0fd 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_catalog_version/snapshots/migration_husky_catalog_version.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_catalog_version/snapshots/migration_husky_catalog_version.md @@ -59,7 +59,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_or_prepare/snapshots/migration_husky_or_prepare.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_or_prepare/snapshots/migration_husky_or_prepare.md index 9932c6f3ca..2989ce7ff3 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_or_prepare/snapshots/migration_husky_or_prepare.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_or_prepare/snapshots/migration_husky_or_prepare.md @@ -54,7 +54,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_merge_fail/snapshots/migration_lint_staged_merge_fail.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_merge_fail/snapshots/migration_lint_staged_merge_fail.md index 285639787c..9f030d3201 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_merge_fail/snapshots/migration_lint_staged_merge_fail.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_merge_fail/snapshots/migration_lint_staged_merge_fail.md @@ -56,7 +56,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserve_below_policy_node_pins/snapshots/migration_preserve_below_policy_node_pins.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserve_below_policy_node_pins/snapshots/migration_preserve_below_policy_node_pins.md index 8a75400205..12d3b03dcb 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserve_below_policy_node_pins/snapshots/migration_preserve_below_policy_node_pins.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserve_below_policy_node_pins/snapshots/migration_preserve_below_policy_node_pins.md @@ -66,7 +66,7 @@ catalogs: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: catalog:vite-stack + vite@*: catalog:vite-stack peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_standalone_pnpm/snapshots/migration_standalone_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_standalone_pnpm/snapshots/migration_standalone_pnpm.md index 84ca94b8bd..65da6a3bce 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_standalone_pnpm/snapshots/migration_standalone_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_standalone_pnpm/snapshots/migration_standalone_pnpm.md @@ -40,7 +40,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: "catalog:" + vite@*: "catalog:" peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_version/snapshots/migration_vite_version.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_version/snapshots/migration_vite_version.md index 85454a545f..213755184f 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_version/snapshots/migration_vite_version.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_version/snapshots/migration_vite_version.md @@ -47,7 +47,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_import_only/snapshots/migration_vitest_import_only.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_import_only/snapshots/migration_vitest_import_only.md index ecb7a5e217..c31bf9f0dc 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_import_only/snapshots/migration_vitest_import_only.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_import_only/snapshots/migration_vitest_import_only.md @@ -56,7 +56,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: overrides: - vite: 'catalog:' + vite@*: 'catalog:' peerDependencyRules: allowAny: - vite From a8d66cc930c6d21836a35b6df7a435a048fc857b Mon Sep 17 00:00:00 2001 From: MK Date: Wed, 12 Aug 2026 13:28:46 +0800 Subject: [PATCH 4/9] test(snapshots): cover the #2309 fix on pnpm 12 pnpm 12 fixes the clobber upstream: on 12.0.0-rc.3 a bare override key no longer strips a catalog: importer spec, verified by A/B on identical config (pnpm 11.20.0 rewrites it, 12.0.0-rc.3 does not). The range-qualified key vite-plus writes stays correct there, and still redirects an incompatible transitive edge, so it is not merely a pnpm 9-11 workaround. The vp up screen is omitted: pnpm 12's update summary reports a package-count delta that churns with the bundled dependency graph. --- .../.gitignore | 1 + .../package.json | 7 +++ .../snapshots.toml | 31 ++++++++++ .../command_update_catalog_protocol_pnpm12.md | 56 +++++++++++++++++++ 4 files changed, 95 insertions(+) create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/.gitignore create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/package.json create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/snapshots.toml create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/snapshots/command_update_catalog_protocol_pnpm12.md diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/.gitignore b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/.gitignore new file mode 100644 index 0000000000..c2658d7d1b --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/package.json new file mode 100644 index 0000000000..68b48816d0 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/package.json @@ -0,0 +1,7 @@ +{ + "name": "command-update-catalog-protocol-pnpm12", + "devDependencies": { + "vite": "^7.0.0" + }, + "packageManager": "pnpm@12.0.0-rc.3" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/snapshots.toml new file mode 100644 index 0000000000..8e260713c0 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/snapshots.toml @@ -0,0 +1,31 @@ +[[case]] +name = "command_update_catalog_protocol_pnpm12" +vp = "global" +skip-platforms = ["windows"] +unset-env = ["CI", "VP_SKIP_INSTALL"] +local-registry = true +comment = "#2309 on pnpm 12. pnpm 12 fixes the clobber upstream (a bare override key no longer strips a `catalog:` importer spec), so this pins that the range-qualified key vite-plus writes is also correct there rather than only being a pnpm 9-11 workaround." +steps = [ + { argv = [ + "vp", + "migrate", + "--no-interactive", + "--no-hooks", + "--package-manager", + "pnpm", + ], comment = "migrate pins the toolchain through the workspace catalog", continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "pnpm-workspace.yaml", + ], comment = "the range-qualified override key is written on pnpm 12 too", continue-on-failure = true }, + { argv = [ + "vp", + "up", + ], comment = "update must not resolve the catalog reference away (screen omitted: pnpm 12's update summary reports a package-count delta that churns with the bundled dependency graph)", snapshot = false, continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "package.json", + ], comment = "`vite` stays `catalog:`", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/snapshots/command_update_catalog_protocol_pnpm12.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/snapshots/command_update_catalog_protocol_pnpm12.md new file mode 100644 index 0000000000..faaf331eff --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/snapshots/command_update_catalog_protocol_pnpm12.md @@ -0,0 +1,56 @@ +# command_update_catalog_protocol_pnpm12 + +#2309 on pnpm 12. pnpm 12 fixes the clobber upstream (a bare override key no longer strips a `catalog:` importer spec), so this pins that the range-qualified key vite-plus writes is also correct there rather than only being a pnpm 9-11 workaround. + +## `vp migrate --no-interactive --no-hooks --package-manager pnpm` + +migrate pins the toolchain through the workspace catalog + +``` +VITE+ - The Unified Toolchain for the Web + +Formatting code... + +Code formatted +◇ Migrated . to Vite+ +• Node pnpm +✓ Dependencies installed in +• 1 config update applied +``` + +## `vpt print-file pnpm-workspace.yaml` + +the range-qualified override key is written on pnpm 12 too + +``` +catalog: + vite: npm:@voidzero-dev/vite-plus-core@ + vite-plus: +overrides: + vite@*: "catalog:" +peerDependencyRules: + allowAny: + - vite + allowedVersions: + vite: "*" +``` + +## `vp up` + +update must not resolve the catalog reference away (screen omitted: pnpm 12's update summary reports a package-count delta that churns with the bundled dependency graph) + + +## `vpt print-file package.json` + +`vite` stays `catalog:` + +``` +{ + "name": "command-update-catalog-protocol-pnpm12", + "devDependencies": { + "vite": "catalog:", + "vite-plus": "catalog:" + }, + "packageManager": "pnpm@12.0.0-rc.3" +} +``` From d012f2f6348acd77991e10ce2ba3b5c365f1ecad Mon Sep 17 00:00:00 2001 From: MK Date: Wed, 12 Aug 2026 14:09:14 +0800 Subject: [PATCH 5/9] docs: simplify the #2309 override-key prose Apply ASD-STE100 style to the comments and guide text added by this branch: one instruction per sentence, active voice, no ellipsis, and sentences under 25 words. The longest sentence was 52 words. Also removes the em dashes these additions introduced. Comments and documentation only. No code changed. --- docs/guide/migrate-rules.md | 16 +++--- docs/guide/upgrade.md | 2 +- .../cli/src/migration/migrator/catalog.ts | 10 ++-- .../src/migration/migrator/orchestrators.ts | 11 +++-- packages/cli/src/migration/migrator/shared.ts | 49 ++++++++++--------- .../migration/migrator/vite-plus-bootstrap.ts | 15 +++--- .../migration/migrator/vitest-ecosystem.ts | 12 ++--- 7 files changed, 61 insertions(+), 54 deletions(-) diff --git a/docs/guide/migrate-rules.md b/docs/guide/migrate-rules.md index 7e24571381..41fb55da46 100644 --- a/docs/guide/migrate-rules.md +++ b/docs/guide/migrate-rules.md @@ -82,14 +82,14 @@ Related rules: - A direct `vite` declaration is never removed merely because a root override exists. - Plain or stale aliases are normalized; named catalog references are kept. -- Under pnpm the managed override keys carry an explicit `@*` range (`vite@*`, - `vitest@*`). pnpm applies overrides by replacing the declared spec on every - manifest, importers included, and a bare key matches any spec — including - `catalog:`, which would make `vp up` rewrite the reference to a concrete - version. The range keeps the override on the transitive and peer declarations - it exists for and leaves `catalog:` references to the catalog, which already - resolves them to Vite+ core. Migration re-keys a project still carrying the - bare key and preserves its named-catalog choice. +- Under pnpm the managed override keys use an explicit `@*` range (`vite@*`, + `vitest@*`). pnpm applies an override by replacing the declared spec on every + manifest, importer manifests included. A bare key matches any spec, including + `catalog:`, and `vp up` then rewrites that reference to a concrete version. + The `@*` range keeps the override on the transitive and peer declarations it + exists for. It leaves `catalog:` references to the catalog, which already + resolves them to Vite+ core. Migration re-keys a project that still holds the + bare key, and keeps its named-catalog choice. - The direct-entry rule above is pnpm-specific. Bun mirrors its core alias as a direct dependency for its peer resolver, and npm browser-provider layouts may need a top-level `vite` edge so nested Vitest packages can resolve diff --git a/docs/guide/upgrade.md b/docs/guide/upgrade.md index 7fb21b84f6..50b34c472e 100644 --- a/docs/guide/upgrade.md +++ b/docs/guide/upgrade.md @@ -71,7 +71,7 @@ If you migrated with `vp migrate`, your project pins `vitest` to an exact versio - **Yarn:** a `vitest` entry under `resolutions` in `package.json` - **pnpm:** a `vitest@*` entry under `overrides` in `pnpm-workspace.yaml` — unless your `package.json` already had a `pnpm` field, in which case it lives under `pnpm.overrides` in `package.json` instead (pnpm ignores `pnpm-workspace.yaml` overrides when `package.json` defines `pnpm.overrides`) -Under pnpm the managed keys carry an explicit `@*` range (`vite@*`, `vitest@*`). pnpm applies overrides by replacing the declared spec on every manifest, importers included, and a bare key matches any spec — including `catalog:`. The range keeps the override on the transitive and peer declarations it exists for while leaving `catalog:` references intact, so `vp up` no longer rewrites them to a concrete version. +Under pnpm the managed keys use an explicit `@*` range (`vite@*`, `vitest@*`). pnpm applies an override by replacing the declared spec on every manifest, importer manifests included. A bare key matches any spec, including `catalog:`. The `@*` range keeps the override on the transitive and peer declarations it exists for, and leaves `catalog:` references intact. `vp up` therefore no longer rewrites them to a concrete version. A Vite+ release can bump the bundled Vitest. Because that pin also applies to `vite-plus`'s own `vitest` dependency, an out-of-date pin keeps installing the previous runner even after you upgrade `vite-plus` — splitting Vitest's internals (mocks, `expect`, runner state) between the pinned copy and the one `vp test` loads. diff --git a/packages/cli/src/migration/migrator/catalog.ts b/packages/cli/src/migration/migrator/catalog.ts index 7f86ea8dc8..05bd727954 100644 --- a/packages/cli/src/migration/migrator/catalog.ts +++ b/packages/cli/src/migration/migrator/catalog.ts @@ -314,11 +314,11 @@ export function rewritePnpmWorkspaceYaml( removeYamlMapVitestEntry(doc.getIn(['overrides'])); } for (const key of Object.keys(managed)) { - // Managed keys are range-qualified (`vite@*`) so the override never - // rewrites an importer's `catalog:` spec — see `pnpmOverrideKey`. Carry a - // pre-#2309 bare key's value over to the new key so a user's own - // `catalog:` choice survives, then drop the bare key: leaving both - // in place would restore the clobbering match. + // Managed keys are range-qualified (`vite@*`), so the override never + // rewrites an importer's `catalog:` spec. See `pnpmOverrideKey`. + // Move a pre-#2309 bare key's value to the new key, so a user's own + // `catalog:` choice survives. Then delete the bare key. Two keys + // for one package would restore the match that clobbers `catalog:`. const overrideKey = pnpmOverrideKey(key); const currentVersion = getYamlMapScalarStringValue(overrides, overrideKey) ?? diff --git a/packages/cli/src/migration/migrator/orchestrators.ts b/packages/cli/src/migration/migrator/orchestrators.ts index 0ff4862a31..394d7d7293 100644 --- a/packages/cli/src/migration/migrator/orchestrators.ts +++ b/packages/cli/src/migration/migrator/orchestrators.ts @@ -191,11 +191,12 @@ export function rewriteStandaloneProject( removeVitestPeerDependencyRule(pkg.pnpm.peerDependencyRules); } } - // Managed pnpm override keys are range-qualified (`vite@*`) so they never - // rewrite an importer's `catalog:` spec — see `pnpmOverrideKey`. Drop the - // pre-#2309 bare keys the user's config may still carry; keeping both - // would restore the clobbering match. `peerDependencyRules` below keys on - // plain package names and stays bare. + // Managed pnpm override keys are range-qualified (`vite@*`), so they + // never rewrite an importer's `catalog:` spec. See `pnpmOverrideKey`. + // Delete the pre-#2309 bare keys that the user's config can still hold. + // Two keys for one package would restore the match that clobbers + // `catalog:`. `peerDependencyRules` below keys on plain package names, + // so it stays bare. for (const key of overrideKeys) { delete pkg.pnpm?.overrides?.[key]; } diff --git a/packages/cli/src/migration/migrator/shared.ts b/packages/cli/src/migration/migrator/shared.ts index 91691a5051..cfe61e9712 100644 --- a/packages/cli/src/migration/migrator/shared.ts +++ b/packages/cli/src/migration/migrator/shared.ts @@ -162,36 +162,41 @@ export const LEGACY_WRAPPER_FALLBACK_VERSIONS: Record = { }; /** - * Managed pnpm override keys carry an explicit `@*` range instead of being bare - * package names (`vite@*`, not `vite`). + * Managed pnpm override keys use an explicit `@*` range, not a bare package + * name: `vite@*`, not `vite`. * - * pnpm applies overrides through a read-package hook that REPLACES the declared - * spec on every manifest, importers included, before resolution runs. A BARE - * override key has no range, and pnpm treats "no range" as "matches every - * declared spec" — `catalog:` included. An importer that declares - * `vite: "catalog:"` therefore loses its catalog provenance during resolution, - * and `pnpm update` writes the resolved core alias back into its package.json - * (issue #2309). Qualifying the key with `@*` keeps the override on every real - * semver range — which is what the transitive and peer `vite` declarations this - * override exists for always use — while leaving `catalog:` specs alone: `*` is - * a valid range and `catalog:` is not, so pnpm's `isIntersectingRange` never - * matches the two. Nothing changes about what gets installed, because an - * importer that references the catalog already resolves to the aliased core - * through its catalog entry. + * pnpm applies overrides through a read-package hook. The hook replaces the + * declared spec on every manifest, importer manifests included, before + * resolution runs. A bare override key has no range, and pnpm treats a key with + * no range as a match for every declared spec. That includes `catalog:`. An + * importer that declares `vite: "catalog:"` therefore loses its link to the + * catalog during resolution, and `pnpm update` then writes the resolved core + * alias into that importer's package.json (issue #2309). * - * This is pnpm-only. npm/bun `overrides` and yarn `resolutions` keep bare keys: - * those managers have no `catalog:` importer specs to lose (bun catalogs live in - * package.json and are resolved before overrides apply). + * The `@*` range keeps the override on every valid semver range. Transitive and + * peer `vite` declarations always use such a range, and they are the reason this + * override exists. The range also leaves `catalog:` specs alone, because `*` is + * a valid semver range and `catalog:` is not, so pnpm's `isIntersectingRange` + * never matches the two. The installed result does not change: an importer that + * references the catalog already resolves to the aliased core through its + * catalog entry. + * + * This applies to pnpm only. npm and bun `overrides`, and yarn `resolutions`, + * keep bare keys. Those package managers have no `catalog:` importer specs to + * lose. Bun catalogs live in package.json, and bun resolves them before it + * applies overrides. */ export function pnpmOverrideKey(dependencyName: string): string { return `${dependencyName}@*`; } /** - * How a sink spells its managed override keys: pnpm's `overrides` use the - * range-qualified form ({@link pnpmOverrideKey}), every other sink uses the bare - * package name. A pnpm sink still carrying a bare managed key predates the - * #2309 fix, so it deliberately reads as UNSATISFIED and gets rewritten. + * How a sink spells its managed override keys. pnpm's `overrides` use the + * range-qualified form ({@link pnpmOverrideKey}). Every other sink uses the bare + * package name. + * + * A pnpm sink that still holds a bare managed key predates the #2309 fix. Such a + * key reads as unsatisfied on purpose, so the next migration rewrites it. */ export type ManagedOverrideKeyStyle = 'bare' | 'pnpm-ranged'; diff --git a/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts b/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts index 8a0ee731e5..f6d828bd0e 100644 --- a/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts +++ b/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts @@ -147,10 +147,10 @@ export function overridesSatisfyVitePlus( catalogDependencyResolver?: CatalogDependencyResolver, keyStyle: ManagedOverrideKeyStyle = 'bare', ): boolean { - // Common case: a lingering managed `vitest` override is NOT satisfied — it - // must be removed, so the bootstrap stays pending until it is. Both key - // spellings count: a pnpm sink migrated before #2309 still carries the bare - // one (see `managedOverrideKey`). + // Common case: a lingering managed `vitest` override is not satisfied. It + // must be removed, so the bootstrap stays pending until then. Both key + // spellings count. A pnpm sink migrated before #2309 still holds the bare + // one. See `managedOverrideKey`. if ( !usesVitest && VITEST_IS_MANAGED_OVERRIDE && @@ -882,9 +882,10 @@ function ensureOverrideEntries( managedOverridePackages(usesVitest), )) { const overrideKey = managedOverrideKey(dependencyName, keyStyle); - // Carry a pre-#2309 bare key's value over to the range-qualified key so the - // user's own `catalog:` choice survives, then drop the bare key — - // keeping both would restore the match that clobbers `catalog:` importers. + // Move a pre-#2309 bare key's value to the range-qualified key, so the + // user's own `catalog:` choice survives. Then delete the bare key. + // Two keys for one package would restore the match that clobbers + // `catalog:` importers. const currentSpec = next[overrideKey] ?? next[dependencyName]; if (overrideKey !== dependencyName && next[dependencyName] !== undefined) { delete next[dependencyName]; diff --git a/packages/cli/src/migration/migrator/vitest-ecosystem.ts b/packages/cli/src/migration/migrator/vitest-ecosystem.ts index f161c891c7..132c01395c 100644 --- a/packages/cli/src/migration/migrator/vitest-ecosystem.ts +++ b/packages/cli/src/migration/migrator/vitest-ecosystem.ts @@ -548,9 +548,9 @@ export function projectUsesVitestDirectly( // is a user override scoped under `vitest` and must be left intact. Returns true // iff an entry was removed. // -// pnpm override sinks spell the managed key `vitest@*` (see `pnpmOverrideKey`), -// so both spellings are swept: which one a project carries depends on whether it -// was last migrated before or after the #2309 fix. +// pnpm override sinks spell the managed key `vitest@*`. See `pnpmOverrideKey`. +// This function removes both spellings. A project holds the bare key if it was +// last migrated before the #2309 fix, and the ranged key if after. export function removeManagedVitestEntry(record: Record | undefined): boolean { if (!VITEST_IS_MANAGED_OVERRIDE || !record) { return false; @@ -584,9 +584,9 @@ export function removeYamlMapVitestEntry(map: unknown): void { } } -// `vitest` itself, or the range-qualified pnpm override spelling of it. A -// selector-scoped key (`some-app>vitest`) constrains that parent's subtree only -// and is never a managed key, so the `>`-bearing forms stay out. +// True for `vitest` itself, and for the range-qualified pnpm override spelling. +// A selector-scoped key (`some-app>vitest`) constrains only that parent's +// subtree. Such a key is never a managed key, so forms with `>` stay out. function isManagedVitestOverrideKey(key: string): boolean { return key === 'vitest' || key === pnpmOverrideKey('vitest'); } From 0b565cd4dab210804f07640053e5cada390f60b5 Mon Sep 17 00:00:00 2001 From: MK Date: Wed, 12 Aug 2026 15:40:05 +0800 Subject: [PATCH 6/9] fix(migrate): address review findings on the #2309 override re-keying Four gaps in the range-qualified override key change. The monorepo root writer was missed. `rewriteMonorepo` routes root pnpm settings through `rewriteRootWorkspacePackageJson`, not the standalone writer, and its pre-10.6.2 branch still spread bare `...managed` keys into `pkg.pnpm.overrides`. Those workspace-wide bare keys kept matching child `catalog:` declarations, so `vp up` could still replace them. Both writers now share one `mergeManagedPnpmOverrides` helper, which is what let the paths drift apart in the first place. That helper also carries a legacy bare key's `catalog:` value onto the ranged key. The package.json paths previously replaced it with the concrete managed alias, which disconnected the override from the user's named catalog and contradicted the documented preservation behaviour. A `file:` managed spec still wins, since force-override mode has no catalog. `overridesSatisfyVitePlus` read only the ranged key in `pnpm-ranged` mode, so a map holding BOTH `vite@*` and a legacy bare `vite` reported satisfied. The fast path then skipped the rewrite and left the clobbering key active. Any remaining bare managed key now reports unsatisfied. The managed-vitest sweep was over-broad. `removeManagedVitestEntry` and `removeYamlMapVitestEntry` deleted `vitest@*` from every sink, but only pnpm overrides use that spelling. npm also accepts a range in an override key, so a user-authored `"vitest@*"` in npm `overrides` was silently deleted. Both now take a key style and sweep the ranged spelling for pnpm sinks only. Each fix has a unit test that fails without it. --- .../src/migration/__tests__/migrator.spec.ts | 109 ++++++++++++++++++ .../cli/src/migration/migrator/catalog.ts | 46 +++++++- .../src/migration/migrator/orchestrators.ts | 21 +--- .../migration/migrator/vite-plus-bootstrap.ts | 15 ++- .../migration/migrator/vitest-ecosystem.ts | 39 ++++--- 5 files changed, 194 insertions(+), 36 deletions(-) diff --git a/packages/cli/src/migration/__tests__/migrator.spec.ts b/packages/cli/src/migration/__tests__/migrator.spec.ts index 3b6fb5b78e..d6543c404d 100644 --- a/packages/cli/src/migration/__tests__/migrator.spec.ts +++ b/packages/cli/src/migration/__tests__/migrator.spec.ts @@ -4823,6 +4823,115 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); }); + it('re-keys pnpm.overrides in a monorepo root below pnpm 10.6.2 (#2309 review P1)', () => { + // `rewriteMonorepo` routes root settings through `rewriteRootWorkspacePackageJson`, + // a different writer from the standalone path. A bare key left there keeps + // matching child `catalog:` declarations workspace-wide. + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ + name: 'pnpm9-monorepo', + workspaces: ['packages/*'], + devDependencies: { vite: 'catalog:' }, + pnpm: { overrides: { vite: 'catalog:', react: '^18.0.0' } }, + }), + ); + fs.writeFileSync( + path.join(tmpDir, 'pnpm-workspace.yaml'), + ['packages:', ' - packages/*', 'catalog:', ' vite: ^7.0.0', ''].join('\n'), + ); + + rewriteMonorepo(makeWorkspaceInfo(tmpDir, PackageManager.pnpm, '9.15.9'), true); + + const pkg = readJson(path.join(tmpDir, 'package.json')) as { + pnpm: { overrides: Record }; + }; + expect(pkg.pnpm.overrides[PNPM_VITE_OVERRIDE_KEY]).toBeDefined(); + expect(pkg.pnpm.overrides).not.toHaveProperty('vite'); + expect(pkg.pnpm.overrides.react).toBe('^18.0.0'); + }); + + it('carries a legacy named-catalog override value onto the ranged key (#2309 review P2)', () => { + // The re-keying must not silently disconnect the override from the user's + // named catalog by replacing it with the concrete managed alias. + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ + name: 'pnpm9-standalone', + devDependencies: { vite: 'catalog:toolchain' }, + pnpm: { overrides: { vite: 'catalog:toolchain' } }, + }), + ); + fs.writeFileSync( + path.join(tmpDir, 'pnpm-workspace.yaml'), + ['catalogs:', ' toolchain:', ' vite: ^7.0.0', ''].join('\n'), + ); + + rewriteStandaloneProject( + tmpDir, + makeWorkspaceInfo(tmpDir, PackageManager.pnpm, '9.15.9'), + true, + true, + ); + + const pkg = readJson(path.join(tmpDir, 'package.json')) as { + pnpm: { overrides: Record }; + }; + expect(pkg.pnpm.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:toolchain'); + expect(pkg.pnpm.overrides).not.toHaveProperty('vite'); + }); + + it('treats a leftover bare key as pending beside a valid ranged key (#2309 review P2)', () => { + // A hand-edited or partially repaired project can hold both spellings. The + // bare one still matches `catalog:` importer specs, so the already-migrated + // fast path must not skip the rewrite that deletes it. + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ name: 'test', devDependencies: { vite: '^7.0.0' } }), + ); + rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.pnpm), true, true); + expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); + + // Re-introduce the pre-#2309 key next to the correct one. + const workspacePath = path.join(tmpDir, 'pnpm-workspace.yaml'); + fs.writeFileSync( + workspacePath, + fs + .readFileSync(workspacePath, 'utf8') + .replace('overrides:\n', "overrides:\n vite: 'catalog:'\n"), + ); + + expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(true); + + // One more migrate converges again by dropping the bare key. + rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.pnpm), true, true); + const workspace = readYamlObject(path.join(tmpDir, 'pnpm-workspace.yaml')) as { + overrides: Record; + }; + expect(workspace.overrides).not.toHaveProperty('vite'); + expect(workspace.overrides[PNPM_VITE_OVERRIDE_KEY]).toBe('catalog:'); + }); + + it('leaves a user-authored ranged npm override alone (#2309 review P2)', () => { + // npm accepts a range in an override key too, but vite-plus only ever + // manages the BARE key there. A `vitest@*` entry in npm `overrides` is the + // user's own and must survive the managed-vitest sweep. + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ + name: 'npm-project', + devDependencies: { vite: '^7.0.0' }, + overrides: { 'vitest@*': '3.2.4' }, + }), + ); + rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.npm), true, true); + + const pkg = readJson(path.join(tmpDir, 'package.json')) as { + overrides: Record; + }; + expect(pkg.overrides['vitest@*']).toBe('3.2.4'); + }); + it('rewrites named catalogs in pnpm-workspace.yaml without adding new entries', () => { fs.writeFileSync( path.join(tmpDir, 'package.json'), diff --git a/packages/cli/src/migration/migrator/catalog.ts b/packages/cli/src/migration/migrator/catalog.ts index 05bd727954..4dd66519bd 100644 --- a/packages/cli/src/migration/migrator/catalog.ts +++ b/packages/cli/src/migration/migrator/catalog.ts @@ -311,7 +311,7 @@ export function rewritePnpmWorkspaceYaml( // Common case (no direct vitest): actively strip any lingering managed // `vitest` override so it arrives transitively through vite-plus. if (!usesVitest) { - removeYamlMapVitestEntry(doc.getIn(['overrides'])); + removeYamlMapVitestEntry(doc.getIn(['overrides']), 'pnpm-ranged'); } for (const key of Object.keys(managed)) { // Managed keys are range-qualified (`vite@*`), so the override never @@ -837,8 +837,8 @@ function getYamlMapScalarStringValue(map: unknown, key: string): string | undefi } // Delete a key by its literal name. `YAMLMap.delete` compares the key NODE, so -// the node has to be looked up in `.items` first — passing a fresh scalar would -// silently no-op. +// the node has to be looked up in `.items` first. A fresh scalar would silently +// no-op. function deleteYamlMapKey(map: unknown, key: string): void { if (!(map instanceof YAMLMap)) { return; @@ -851,6 +851,37 @@ function deleteYamlMapKey(map: unknown, key: string): void { } } +/** + * Merge the managed override entries into a pnpm `overrides` record, under the + * range-qualified keys (see `pnpmOverrideKey`). + * + * Every pnpm sink goes through this helper: the package.json `pnpm.overrides` + * written for pnpm 9.5 to 10.6.1, from both the standalone and the monorepo-root + * writer. A bare managed key left by a pre-#2309 migration is deleted, because + * two keys for one package would restore the match that clobbers `catalog:` + * importer specs. + * + * A bare key's `catalog:` value moves to the ranged key, so a user's own + * `catalog:` choice survives the re-keying. This mirrors + * `getCatalogDependencySpec`, which keeps a `catalog:` reference in the + * pnpm-workspace.yaml sink. A `file:` managed spec (force-override mode) always + * wins, because there is no catalog to resolve against in that mode. + */ +export function mergeManagedPnpmOverrides( + overrides: Record | undefined, + managed: Record, +): Record { + const next = { ...overrides }; + for (const [dependencyName, managedSpec] of Object.entries(managed)) { + const overrideKey = pnpmOverrideKey(dependencyName); + const existing = next[overrideKey] ?? next[dependencyName]; + delete next[dependencyName]; + next[overrideKey] = + existing?.startsWith('catalog:') && !managedSpec.startsWith('file:') ? existing : managedSpec; + } + return next; +} + function pruneYamlMapLegacyWrapperAliases(map: unknown): void { if (!(map instanceof YAMLMap)) { return; @@ -1236,7 +1267,7 @@ export function rewriteRootWorkspacePackageJson( dropRemovePackageOverrideKeys(pkg.pnpm?.overrides); // Common case: drop a lingering managed `vitest` override before merging. if (!workspaceUsesVitest) { - removeManagedVitestEntry(pkg.pnpm?.overrides); + removeManagedVitestEntry(pkg.pnpm?.overrides, 'pnpm-ranged'); } if (!workspaceUsesVitest && pkg.pnpm?.peerDependencyRules) { removeVitestPeerDependencyRule(pkg.pnpm.peerDependencyRules); @@ -1244,8 +1275,11 @@ export function rewriteRootWorkspacePackageJson( pkg.pnpm = { ...pkg.pnpm, overrides: { - ...pkg.pnpm?.overrides, - ...managed, + ...mergeManagedPnpmOverrides(pkg.pnpm?.overrides, managed), + // The force-override `vite-plus` pin keeps a BARE key: it only exists + // in `file:` tgz mode, where migration writes the tgz spec straight + // into every manifest instead of a `catalog:` reference, so there is + // no catalog provenance for a bare key to strip. ...(isForceOverrideMode() ? { [VITE_PLUS_NAME]: VITE_PLUS_VERSION } : {}), }, peerDependencyRules: { diff --git a/packages/cli/src/migration/migrator/orchestrators.ts b/packages/cli/src/migration/migrator/orchestrators.ts index 394d7d7293..92731f8693 100644 --- a/packages/cli/src/migration/migrator/orchestrators.ts +++ b/packages/cli/src/migration/migrator/orchestrators.ts @@ -21,6 +21,7 @@ import { injectFmtDefaults, injectLintTypeCheckDefaults, managedOverridePackages, + mergeManagedPnpmOverrides, mergeStagedConfigToViteConfig, mergeTsdownConfigFile, mergeViteConfigFiles, @@ -56,7 +57,6 @@ import { type MigrationReport } from '../report.ts'; import { PROVIDER_OVERRIDE_DROP_NAMES, pnpmMajor, - pnpmOverrideKey, type CatalogDependencyResolver, type PnpmPackageJsonSettings, } from './shared.ts'; @@ -186,28 +186,19 @@ export function rewriteStandaloneProject( // Common case: drop a lingering managed `vitest` override + its peer // rules before re-merging. if (!usesVitest) { - removeManagedVitestEntry(pkg.pnpm?.overrides); + removeManagedVitestEntry(pkg.pnpm?.overrides, 'pnpm-ranged'); if (pkg.pnpm?.peerDependencyRules) { removeVitestPeerDependencyRule(pkg.pnpm.peerDependencyRules); } } - // Managed pnpm override keys are range-qualified (`vite@*`), so they - // never rewrite an importer's `catalog:` spec. See `pnpmOverrideKey`. - // Delete the pre-#2309 bare keys that the user's config can still hold. - // Two keys for one package would restore the match that clobbers - // `catalog:`. `peerDependencyRules` below keys on plain package names, - // so it stays bare. - for (const key of overrideKeys) { - delete pkg.pnpm?.overrides?.[key]; - } // Project already has pnpm config in package.json -- keep using it. + // `mergeManagedPnpmOverrides` writes the range-qualified keys and drops + // any pre-#2309 bare key. `peerDependencyRules` below keys on plain + // package names, so it stays bare. pkg.pnpm = { ...pkg.pnpm, overrides: { - ...pkg.pnpm?.overrides, - ...Object.fromEntries( - Object.entries(managed).map(([key, spec]) => [pnpmOverrideKey(key), spec]), - ), + ...mergeManagedPnpmOverrides(pkg.pnpm?.overrides, managed), // The force-override `vite-plus` pin keeps a BARE key: it only exists // in `file:` tgz mode, where migration writes the tgz spec straight // into every manifest instead of a `catalog:` reference, so there is diff --git a/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts b/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts index f6d828bd0e..c780724215 100644 --- a/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts +++ b/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts @@ -147,6 +147,7 @@ export function overridesSatisfyVitePlus( catalogDependencyResolver?: CatalogDependencyResolver, keyStyle: ManagedOverrideKeyStyle = 'bare', ): boolean { + const managed = managedOverridePackages(usesVitest); // Common case: a lingering managed `vitest` override is not satisfied. It // must be removed, so the bootstrap stays pending until then. Both key // spellings count. A pnpm sink migrated before #2309 still holds the bare @@ -159,7 +160,17 @@ export function overridesSatisfyVitePlus( ) { return false; } - return Object.keys(managedOverridePackages(usesVitest)).every((dependencyName) => + // A pnpm sink can hold BOTH spellings, for example after a hand edit or a + // partial repair. The leftover bare key still matches `catalog:` importer + // specs, so it must be re-keyed even when the ranged key is already correct. + // Report unsatisfied so the rewrite runs and deletes it. + if ( + keyStyle === 'pnpm-ranged' && + Object.keys(managed).some((dependencyName) => typeof overrides?.[dependencyName] === 'string') + ) { + return false; + } + return Object.keys(managed).every((dependencyName) => overrideSpecSatisfiesVitePlus( dependencyName, overrides?.[managedOverrideKey(dependencyName, keyStyle)], @@ -875,7 +886,7 @@ function ensureOverrideEntries( const next = { ...overrides }; let changed = false; // Common case: drop a lingering managed `vitest` override. - if (!usesVitest && removeManagedVitestEntry(next)) { + if (!usesVitest && removeManagedVitestEntry(next, keyStyle)) { changed = true; } for (const [dependencyName, overrideSpec] of Object.entries( diff --git a/packages/cli/src/migration/migrator/vitest-ecosystem.ts b/packages/cli/src/migration/migrator/vitest-ecosystem.ts index 132c01395c..ff76db6829 100644 --- a/packages/cli/src/migration/migrator/vitest-ecosystem.ts +++ b/packages/cli/src/migration/migrator/vitest-ecosystem.ts @@ -27,6 +27,7 @@ import { VITEST_IS_MANAGED_OVERRIDE, pnpmOverrideKey, type CatalogDependencyResolver, + type ManagedOverrideKeyStyle, type PackageJsonDependencyField, } from './shared.ts'; @@ -548,16 +549,22 @@ export function projectUsesVitestDirectly( // is a user override scoped under `vitest` and must be left intact. Returns true // iff an entry was removed. // -// pnpm override sinks spell the managed key `vitest@*`. See `pnpmOverrideKey`. -// This function removes both spellings. A project holds the bare key if it was -// last migrated before the #2309 fix, and the ranged key if after. -export function removeManagedVitestEntry(record: Record | undefined): boolean { +// `keyStyle` selects which spellings count as managed. Only a pnpm override sink +// spells the managed key `vitest@*` (see `pnpmOverrideKey`), and such a sink can +// hold either spelling: the bare one if the project was last migrated before the +// #2309 fix, the ranged one if after. Every other sink stays `bare`. npm also +// accepts a range in an override key, so a user-authored `"vitest@*"` there is +// the user's own entry and must not be deleted. +export function removeManagedVitestEntry( + record: Record | undefined, + keyStyle: ManagedOverrideKeyStyle = 'bare', +): boolean { if (!VITEST_IS_MANAGED_OVERRIDE || !record) { return false; } let removed = false; for (const key of Object.keys(record)) { - if (isManagedVitestOverrideKey(key) && typeof record[key] === 'string') { + if (isManagedVitestOverrideKey(key, keyStyle) && typeof record[key] === 'string') { delete record[key]; removed = true; } @@ -566,8 +573,13 @@ export function removeManagedVitestEntry(record: Record | undefi } // Remove a managed `vitest` scalar key from a YAMLMap (pnpm-workspace.yaml -// `overrides`, `catalog`, and each named `catalogs` entry). -export function removeYamlMapVitestEntry(map: unknown): void { +// `overrides`, `catalog`, and each named `catalogs` entry). Only the `overrides` +// map uses the range-qualified spelling; `catalog`/`catalogs` and +// `allowedVersions` key on plain package names, so they stay `bare`. +export function removeYamlMapVitestEntry( + map: unknown, + keyStyle: ManagedOverrideKeyStyle = 'bare', +): void { if (!VITEST_IS_MANAGED_OVERRIDE || !(map instanceof YAMLMap)) { return; } @@ -576,7 +588,7 @@ export function removeYamlMapVitestEntry(map: unknown): void { (item) => item.key instanceof Scalar && typeof item.key.value === 'string' && - isManagedVitestOverrideKey(item.key.value), + isManagedVitestOverrideKey(item.key.value, keyStyle), ) .map((item) => item.key); for (const target of targets) { @@ -584,11 +596,12 @@ export function removeYamlMapVitestEntry(map: unknown): void { } } -// True for `vitest` itself, and for the range-qualified pnpm override spelling. -// A selector-scoped key (`some-app>vitest`) constrains only that parent's -// subtree. Such a key is never a managed key, so forms with `>` stay out. -function isManagedVitestOverrideKey(key: string): boolean { - return key === 'vitest' || key === pnpmOverrideKey('vitest'); +// True for `vitest` itself, and, in a pnpm override sink, for the +// range-qualified spelling. A selector-scoped key (`some-app>vitest`) constrains +// only that parent's subtree. Such a key is never a managed key, so forms with +// `>` stay out. +function isManagedVitestOverrideKey(key: string, keyStyle: ManagedOverrideKeyStyle): boolean { + return key === 'vitest' || (keyStyle === 'pnpm-ranged' && key === pnpmOverrideKey('vitest')); } // Remove the managed `vitest` entry from pnpm peerDependencyRules (its From 1e073e60f6ae6b8d1bea3f7d7e90f0a084b3084a Mon Sep 17 00:00:00 2001 From: MK Date: Wed, 12 Aug 2026 16:41:28 +0800 Subject: [PATCH 7/9] docs: record the exact-prerelease gap in the pnpm override key Codex review on 4321a19e: `vite@*` does not match a declaration pinning an exact prerelease. pnpm compares with semver.intersects(declaredSpec, keyRange), which is asymmetric for prereleases: intersects('8.0.0-beta.18', '*') is false while the reverse is true. My earlier justification checked the wrong argument order. Verified on pnpm 11.20.0: a bare key redirects an exact-prerelease declaration, the ranged key does not. No range string avoids it, because node-semver only admits a prerelease when a comparator carries the same version tuple. A prerelease RANGE (^8.0.0-beta.1) still matches, and pnpm 12.0.0-rc.3 matches the exact form too, so the gap is pnpm 9-11 only. A bare key would close it but is what clobbers catalog:, so below pnpm 12 the two cannot both hold. Corrects the comments and guide text that claimed the range keeps the override on every valid semver range. --- docs/guide/migrate-rules.md | 12 ++++++--- docs/guide/upgrade.md | 2 +- packages/cli/src/migration/migrator/shared.ts | 25 +++++++++++++------ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/docs/guide/migrate-rules.md b/docs/guide/migrate-rules.md index 41fb55da46..a700dc89a2 100644 --- a/docs/guide/migrate-rules.md +++ b/docs/guide/migrate-rules.md @@ -86,10 +86,14 @@ Related rules: `vitest@*`). pnpm applies an override by replacing the declared spec on every manifest, importer manifests included. A bare key matches any spec, including `catalog:`, and `vp up` then rewrites that reference to a concrete version. - The `@*` range keeps the override on the transitive and peer declarations it - exists for. It leaves `catalog:` references to the catalog, which already - resolves them to Vite+ core. Migration re-keys a project that still holds the - bare key, and keeps its named-catalog choice. + The `@*` range keeps the override on the semver ranges that transitive and + peer declarations use. It leaves `catalog:` references to the catalog, which + already resolves them to Vite+ core. Migration re-keys a project that still + holds the bare key, and keeps its named-catalog choice. +- On pnpm 9 to 11 that range does not match a declaration that pins an exact + prerelease, such as `vite: "8.0.0-beta.18"`, so the override skips it and pnpm + can install a separate upstream Vite. A prerelease range such as + `^8.0.0-beta.1` still matches, and pnpm 12 matches the exact form as well. - The direct-entry rule above is pnpm-specific. Bun mirrors its core alias as a direct dependency for its peer resolver, and npm browser-provider layouts may need a top-level `vite` edge so nested Vitest packages can resolve diff --git a/docs/guide/upgrade.md b/docs/guide/upgrade.md index 50b34c472e..6352d02cc2 100644 --- a/docs/guide/upgrade.md +++ b/docs/guide/upgrade.md @@ -71,7 +71,7 @@ If you migrated with `vp migrate`, your project pins `vitest` to an exact versio - **Yarn:** a `vitest` entry under `resolutions` in `package.json` - **pnpm:** a `vitest@*` entry under `overrides` in `pnpm-workspace.yaml` — unless your `package.json` already had a `pnpm` field, in which case it lives under `pnpm.overrides` in `package.json` instead (pnpm ignores `pnpm-workspace.yaml` overrides when `package.json` defines `pnpm.overrides`) -Under pnpm the managed keys use an explicit `@*` range (`vite@*`, `vitest@*`). pnpm applies an override by replacing the declared spec on every manifest, importer manifests included. A bare key matches any spec, including `catalog:`. The `@*` range keeps the override on the transitive and peer declarations it exists for, and leaves `catalog:` references intact. `vp up` therefore no longer rewrites them to a concrete version. +Under pnpm the managed keys use an explicit `@*` range (`vite@*`, `vitest@*`). pnpm applies an override by replacing the declared spec on every manifest, importer manifests included. A bare key matches any spec, including `catalog:`. The `@*` range keeps the override on the semver ranges that transitive and peer declarations use, and leaves `catalog:` references intact. `vp up` therefore no longer rewrites them to a concrete version. On pnpm 9 to 11 the range does not match a declaration that pins an exact prerelease (`vite: "8.0.0-beta.18"`); a prerelease range such as `^8.0.0-beta.1` still matches, and pnpm 12 matches both. A Vite+ release can bump the bundled Vitest. Because that pin also applies to `vite-plus`'s own `vitest` dependency, an out-of-date pin keeps installing the previous runner even after you upgrade `vite-plus` — splitting Vitest's internals (mocks, `expect`, runner state) between the pinned copy and the one `vp test` loads. diff --git a/packages/cli/src/migration/migrator/shared.ts b/packages/cli/src/migration/migrator/shared.ts index cfe61e9712..9707f0ebec 100644 --- a/packages/cli/src/migration/migrator/shared.ts +++ b/packages/cli/src/migration/migrator/shared.ts @@ -173,13 +173,24 @@ export const LEGACY_WRAPPER_FALLBACK_VERSIONS: Record = { * catalog during resolution, and `pnpm update` then writes the resolved core * alias into that importer's package.json (issue #2309). * - * The `@*` range keeps the override on every valid semver range. Transitive and - * peer `vite` declarations always use such a range, and they are the reason this - * override exists. The range also leaves `catalog:` specs alone, because `*` is - * a valid semver range and `catalog:` is not, so pnpm's `isIntersectingRange` - * never matches the two. The installed result does not change: an importer that - * references the catalog already resolves to the aliased core through its - * catalog entry. + * The `@*` range keeps the override on the declared semver ranges that + * transitive and peer `vite` declarations use, and those declarations are the + * reason this override exists. The range leaves `catalog:` specs alone, because + * `catalog:` is not a valid semver range, so pnpm's `isIntersectingRange` + * rejects it before it compares anything. The installed result does not change: + * an importer that references the catalog already resolves to the aliased core + * through its catalog entry. + * + * KNOWN GAP on pnpm 9 to 11. A declaration that pins an EXACT prerelease, such + * as `vite: "8.0.0-beta.18"`, escapes the override. pnpm compares with + * `semver.intersects(declaredSpec, keyRange)`, and that call is asymmetric for + * prereleases: it returns false for an exact prerelease against a wildcard + * range, even though the arguments in the other order return true. No range + * string avoids this, because node-semver only admits a prerelease when a + * comparator carries the same version tuple. A prerelease RANGE such as + * `^8.0.0-beta.1` still matches, and pnpm 12 matches the exact form too. A bare + * key would cover this case, but a bare key is what clobbers `catalog:`, so + * below pnpm 12 the two cannot both hold. * * This applies to pnpm only. npm and bun `overrides`, and yarn `resolutions`, * keep bare keys. Those package managers have no `catalog:` importer specs to From 2aa48817bed7e81546de7088fbcfaefbee3416e8 Mon Sep 17 00:00:00 2001 From: MK Date: Fri, 14 Aug 2026 23:09:28 +0800 Subject: [PATCH 8/9] docs: drop the guide prerelease notes and simplify review-round prose The pnpm 9 to 11 exact-prerelease gap stays in the `pnpmOverrideKey` comment. The migrate-rules and upgrade guides drop it per review. Apply STE style to the prose added after 98a2fd30d: split sentences over the length limits, keep one statement per sentence, use active voice, and remove the em dash from the pnpm override bullet. --- docs/guide/migrate-rules.md | 4 ---- docs/guide/upgrade.md | 4 ++-- .../src/migration/__tests__/migrator.spec.ts | 20 +++++++++---------- .../cli/src/migration/migrator/catalog.ts | 13 ++++++------ .../src/migration/migrator/orchestrators.ts | 11 +++++----- packages/cli/src/migration/migrator/shared.ts | 18 ++++++++--------- .../migration/migrator/vite-plus-bootstrap.ts | 4 ++-- .../migration/migrator/vitest-ecosystem.ts | 10 +++++----- 8 files changed, 40 insertions(+), 44 deletions(-) diff --git a/docs/guide/migrate-rules.md b/docs/guide/migrate-rules.md index a700dc89a2..8c8fb95cf6 100644 --- a/docs/guide/migrate-rules.md +++ b/docs/guide/migrate-rules.md @@ -90,10 +90,6 @@ Related rules: peer declarations use. It leaves `catalog:` references to the catalog, which already resolves them to Vite+ core. Migration re-keys a project that still holds the bare key, and keeps its named-catalog choice. -- On pnpm 9 to 11 that range does not match a declaration that pins an exact - prerelease, such as `vite: "8.0.0-beta.18"`, so the override skips it and pnpm - can install a separate upstream Vite. A prerelease range such as - `^8.0.0-beta.1` still matches, and pnpm 12 matches the exact form as well. - The direct-entry rule above is pnpm-specific. Bun mirrors its core alias as a direct dependency for its peer resolver, and npm browser-provider layouts may need a top-level `vite` edge so nested Vitest packages can resolve diff --git a/docs/guide/upgrade.md b/docs/guide/upgrade.md index 6352d02cc2..d3ff934d4b 100644 --- a/docs/guide/upgrade.md +++ b/docs/guide/upgrade.md @@ -69,9 +69,9 @@ If you migrated with `vp migrate`, your project pins `vitest` to an exact versio - **npm / Bun:** a `vitest` entry under `overrides` in `package.json` - **Yarn:** a `vitest` entry under `resolutions` in `package.json` -- **pnpm:** a `vitest@*` entry under `overrides` in `pnpm-workspace.yaml` — unless your `package.json` already had a `pnpm` field, in which case it lives under `pnpm.overrides` in `package.json` instead (pnpm ignores `pnpm-workspace.yaml` overrides when `package.json` defines `pnpm.overrides`) +- **pnpm:** a `vitest@*` entry under `overrides` in `pnpm-workspace.yaml`. If your `package.json` already has a `pnpm` field, the entry lives under `pnpm.overrides` in `package.json` instead. pnpm ignores `pnpm-workspace.yaml` overrides when `package.json` defines `pnpm.overrides`. -Under pnpm the managed keys use an explicit `@*` range (`vite@*`, `vitest@*`). pnpm applies an override by replacing the declared spec on every manifest, importer manifests included. A bare key matches any spec, including `catalog:`. The `@*` range keeps the override on the semver ranges that transitive and peer declarations use, and leaves `catalog:` references intact. `vp up` therefore no longer rewrites them to a concrete version. On pnpm 9 to 11 the range does not match a declaration that pins an exact prerelease (`vite: "8.0.0-beta.18"`); a prerelease range such as `^8.0.0-beta.1` still matches, and pnpm 12 matches both. +Under pnpm the managed keys use an explicit `@*` range (`vite@*`, `vitest@*`). pnpm applies an override by replacing the declared spec on every manifest, importer manifests included. A bare key matches any spec, including `catalog:`. The `@*` range keeps the override on the semver ranges that transitive and peer declarations use, and leaves `catalog:` references intact. `vp up` therefore no longer rewrites them to a concrete version. A Vite+ release can bump the bundled Vitest. Because that pin also applies to `vite-plus`'s own `vitest` dependency, an out-of-date pin keeps installing the previous runner even after you upgrade `vite-plus` — splitting Vitest's internals (mocks, `expect`, runner state) between the pinned copy and the one `vp test` loads. diff --git a/packages/cli/src/migration/__tests__/migrator.spec.ts b/packages/cli/src/migration/__tests__/migrator.spec.ts index d6543c404d..34c9bd43b5 100644 --- a/packages/cli/src/migration/__tests__/migrator.spec.ts +++ b/packages/cli/src/migration/__tests__/migrator.spec.ts @@ -4825,8 +4825,8 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { it('re-keys pnpm.overrides in a monorepo root below pnpm 10.6.2 (#2309 review P1)', () => { // `rewriteMonorepo` routes root settings through `rewriteRootWorkspacePackageJson`, - // a different writer from the standalone path. A bare key left there keeps - // matching child `catalog:` declarations workspace-wide. + // a different writer from the standalone path. A bare key left there still + // matches child `catalog:` declarations workspace-wide. fs.writeFileSync( path.join(tmpDir, 'package.json'), JSON.stringify({ @@ -4852,8 +4852,8 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { }); it('carries a legacy named-catalog override value onto the ranged key (#2309 review P2)', () => { - // The re-keying must not silently disconnect the override from the user's - // named catalog by replacing it with the concrete managed alias. + // The re-key step must keep the override on the user's named catalog. It + // must not write the concrete managed alias instead. fs.writeFileSync( path.join(tmpDir, 'package.json'), JSON.stringify({ @@ -4883,7 +4883,7 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { it('treats a leftover bare key as pending beside a valid ranged key (#2309 review P2)', () => { // A hand-edited or partially repaired project can hold both spellings. The - // bare one still matches `catalog:` importer specs, so the already-migrated + // bare key still matches `catalog:` importer specs, so the already-migrated // fast path must not skip the rewrite that deletes it. fs.writeFileSync( path.join(tmpDir, 'package.json'), @@ -4892,7 +4892,7 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.pnpm), true, true); expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); - // Re-introduce the pre-#2309 key next to the correct one. + // Re-introduce the pre-#2309 bare key next to the ranged key. const workspacePath = path.join(tmpDir, 'pnpm-workspace.yaml'); fs.writeFileSync( workspacePath, @@ -4903,7 +4903,7 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(true); - // One more migrate converges again by dropping the bare key. + // One more migrate run drops the bare key and converges again. rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.pnpm), true, true); const workspace = readYamlObject(path.join(tmpDir, 'pnpm-workspace.yaml')) as { overrides: Record; @@ -4913,9 +4913,9 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => { }); it('leaves a user-authored ranged npm override alone (#2309 review P2)', () => { - // npm accepts a range in an override key too, but vite-plus only ever - // manages the BARE key there. A `vitest@*` entry in npm `overrides` is the - // user's own and must survive the managed-vitest sweep. + // npm accepts a range in an override key too, but vite-plus manages only + // the BARE key there. A `vitest@*` entry in npm `overrides` is the user's + // own and must survive the managed-vitest sweep. fs.writeFileSync( path.join(tmpDir, 'package.json'), JSON.stringify({ diff --git a/packages/cli/src/migration/migrator/catalog.ts b/packages/cli/src/migration/migrator/catalog.ts index 4dd66519bd..f31e645877 100644 --- a/packages/cli/src/migration/migrator/catalog.ts +++ b/packages/cli/src/migration/migrator/catalog.ts @@ -837,8 +837,7 @@ function getYamlMapScalarStringValue(map: unknown, key: string): string | undefi } // Delete a key by its literal name. `YAMLMap.delete` compares the key NODE, so -// the node has to be looked up in `.items` first. A fresh scalar would silently -// no-op. +// find the node in `.items` first. A fresh scalar would silently no-op. function deleteYamlMapKey(map: unknown, key: string): void { if (!(map instanceof YAMLMap)) { return; @@ -855,11 +854,11 @@ function deleteYamlMapKey(map: unknown, key: string): void { * Merge the managed override entries into a pnpm `overrides` record, under the * range-qualified keys (see `pnpmOverrideKey`). * - * Every pnpm sink goes through this helper: the package.json `pnpm.overrides` - * written for pnpm 9.5 to 10.6.1, from both the standalone and the monorepo-root - * writer. A bare managed key left by a pre-#2309 migration is deleted, because - * two keys for one package would restore the match that clobbers `catalog:` - * importer specs. + * Both writers of the package.json `pnpm.overrides` sink go through this + * helper: the standalone writer and the monorepo-root writer. That sink serves + * pnpm 9.5 to 10.6.1. The helper deletes a bare managed key that a pre-#2309 + * migration left. Two keys for one package would restore the match that + * clobbers `catalog:` importer specs. * * A bare key's `catalog:` value moves to the ranged key, so a user's own * `catalog:` choice survives the re-keying. This mirrors diff --git a/packages/cli/src/migration/migrator/orchestrators.ts b/packages/cli/src/migration/migrator/orchestrators.ts index 92731f8693..36400ec2f3 100644 --- a/packages/cli/src/migration/migrator/orchestrators.ts +++ b/packages/cli/src/migration/migrator/orchestrators.ts @@ -199,11 +199,12 @@ export function rewriteStandaloneProject( ...pkg.pnpm, overrides: { ...mergeManagedPnpmOverrides(pkg.pnpm?.overrides, managed), - // The force-override `vite-plus` pin keeps a BARE key: it only exists - // in `file:` tgz mode, where migration writes the tgz spec straight - // into every manifest instead of a `catalog:` reference, so there is - // no catalog provenance for a bare key to strip. This matches the - // workspace-yaml force-override path in `rewriteStandaloneProject`. + // The force-override `vite-plus` pin keeps a BARE key. The pin only + // exists in `file:` tgz mode, where migration writes the tgz spec + // straight into every manifest instead of a `catalog:` reference. + // In that mode there is no catalog provenance for a bare key to + // strip. This matches the workspace-yaml force-override path in + // `rewriteStandaloneProject`. ...(isForceOverrideMode() ? { [VITE_PLUS_NAME]: VITE_PLUS_VERSION } : {}), }, peerDependencyRules: { diff --git a/packages/cli/src/migration/migrator/shared.ts b/packages/cli/src/migration/migrator/shared.ts index 9707f0ebec..89b85ac8d9 100644 --- a/packages/cli/src/migration/migrator/shared.ts +++ b/packages/cli/src/migration/migrator/shared.ts @@ -174,23 +174,23 @@ export const LEGACY_WRAPPER_FALLBACK_VERSIONS: Record = { * alias into that importer's package.json (issue #2309). * * The `@*` range keeps the override on the declared semver ranges that - * transitive and peer `vite` declarations use, and those declarations are the + * transitive and peer `vite` declarations use. Those declarations are the * reason this override exists. The range leaves `catalog:` specs alone, because * `catalog:` is not a valid semver range, so pnpm's `isIntersectingRange` * rejects it before it compares anything. The installed result does not change: * an importer that references the catalog already resolves to the aliased core * through its catalog entry. * - * KNOWN GAP on pnpm 9 to 11. A declaration that pins an EXACT prerelease, such + * Known gap on pnpm 9 to 11: a declaration that pins an EXACT prerelease, such * as `vite: "8.0.0-beta.18"`, escapes the override. pnpm compares with - * `semver.intersects(declaredSpec, keyRange)`, and that call is asymmetric for + * `semver.intersects(declaredSpec, keyRange)`. That call is asymmetric for * prereleases: it returns false for an exact prerelease against a wildcard - * range, even though the arguments in the other order return true. No range - * string avoids this, because node-semver only admits a prerelease when a - * comparator carries the same version tuple. A prerelease RANGE such as - * `^8.0.0-beta.1` still matches, and pnpm 12 matches the exact form too. A bare - * key would cover this case, but a bare key is what clobbers `catalog:`, so - * below pnpm 12 the two cannot both hold. + * range. The reversed argument order returns true. No range string avoids + * this, because node-semver only admits a prerelease when a comparator carries + * the same version tuple. A prerelease RANGE such as `^8.0.0-beta.1` still + * matches. pnpm 12 matches the exact form too. A bare key would cover this + * case, but a bare key is what clobbers `catalog:` specs. Below pnpm 12, + * prerelease coverage and `catalog:` safety cannot both hold. * * This applies to pnpm only. npm and bun `overrides`, and yarn `resolutions`, * keep bare keys. Those package managers have no `catalog:` importer specs to diff --git a/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts b/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts index c780724215..2ecfb93c83 100644 --- a/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts +++ b/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts @@ -162,8 +162,8 @@ export function overridesSatisfyVitePlus( } // A pnpm sink can hold BOTH spellings, for example after a hand edit or a // partial repair. The leftover bare key still matches `catalog:` importer - // specs, so it must be re-keyed even when the ranged key is already correct. - // Report unsatisfied so the rewrite runs and deletes it. + // specs. Report unsatisfied, so the rewrite runs and deletes the bare key + // even when the ranged key is already correct. if ( keyStyle === 'pnpm-ranged' && Object.keys(managed).some((dependencyName) => typeof overrides?.[dependencyName] === 'string') diff --git a/packages/cli/src/migration/migrator/vitest-ecosystem.ts b/packages/cli/src/migration/migrator/vitest-ecosystem.ts index ff76db6829..70822ae896 100644 --- a/packages/cli/src/migration/migrator/vitest-ecosystem.ts +++ b/packages/cli/src/migration/migrator/vitest-ecosystem.ts @@ -551,10 +551,10 @@ export function projectUsesVitestDirectly( // // `keyStyle` selects which spellings count as managed. Only a pnpm override sink // spells the managed key `vitest@*` (see `pnpmOverrideKey`), and such a sink can -// hold either spelling: the bare one if the project was last migrated before the -// #2309 fix, the ranged one if after. Every other sink stays `bare`. npm also -// accepts a range in an override key, so a user-authored `"vitest@*"` there is -// the user's own entry and must not be deleted. +// hold either spelling. A project migrated before the #2309 fix holds the bare +// key. A project migrated after it holds the ranged key. Every other sink stays +// `bare`. npm also accepts a range in an override key, so a user-authored +// `"vitest@*"` in npm `overrides` belongs to the user. Do not delete it. export function removeManagedVitestEntry( record: Record | undefined, keyStyle: ManagedOverrideKeyStyle = 'bare', @@ -574,7 +574,7 @@ export function removeManagedVitestEntry( // Remove a managed `vitest` scalar key from a YAMLMap (pnpm-workspace.yaml // `overrides`, `catalog`, and each named `catalogs` entry). Only the `overrides` -// map uses the range-qualified spelling; `catalog`/`catalogs` and +// map uses the range-qualified spelling. `catalog`, `catalogs`, and // `allowedVersions` key on plain package names, so they stay `bare`. export function removeYamlMapVitestEntry( map: unknown, From c7480fc3c94c9cfbeacc33155108f165fd6f0a61 Mon Sep 17 00:00:00 2001 From: MK Date: Fri, 14 Aug 2026 23:48:09 +0800 Subject: [PATCH 9/9] refactor(migrate): simplify the #2309 override re-keying helpers Apply the /simplify review findings on this branch's code: - Drop the `deleteYamlMapKey` helper. Its premise was wrong: yaml 2.9.0's `YAMLMap.delete` resolves a plain string key through `findPair`, verified against the installed package. The YAML sink now deletes the bare key directly, with the same missing-map guard. - Probe the two managed `vitest` key spellings directly instead of scanning every sink entry through a predicate; `managedVitestOverrideKeys` now owns the spelling list and `isManagedVitestOverrideKey` is gone. - Fold the force-override `vite-plus` pin into `mergeManagedPnpmOverrides`, so both package.json `pnpm.overrides` writers really do go through the one helper and the twin call-site blocks collapse to one line each. - Restructure `ensureOverrideEntries` to move-then-check: the bare key moves onto the ranged key first, which removes the trailing re-materialize branch and its cross-branch `changed` invariant. - Write the lingering-vitest check so the ranged spelling only appears under `keyStyle === 'pnpm-ranged'`; the old disjunction read the same key twice for bare sinks. --- .../cli/src/migration/migrator/catalog.ts | 36 +++++++------------ .../src/migration/migrator/orchestrators.ts | 11 +----- .../migration/migrator/vite-plus-bootstrap.ts | 13 +++---- .../migration/migrator/vitest-ecosystem.ts | 30 ++++++---------- 4 files changed, 32 insertions(+), 58 deletions(-) diff --git a/packages/cli/src/migration/migrator/catalog.ts b/packages/cli/src/migration/migrator/catalog.ts index f31e645877..067b99a8da 100644 --- a/packages/cli/src/migration/migrator/catalog.ts +++ b/packages/cli/src/migration/migrator/catalog.ts @@ -326,7 +326,9 @@ export function rewritePnpmWorkspaceYaml( const version = getCatalogDependencySpec(currentVersion, managed[key], true, { preferredCatalogSpec, }); - deleteYamlMapKey(overrides, key); + if (overrides instanceof YAMLMap) { + overrides.delete(key); + } doc.setIn(['overrides', scalarString(overrideKey)], scalarString(version)); } // remove dependency selector from vite, e.g. "vite-plugin-svgr>vite": "npm:vite@7.0.12" @@ -836,20 +838,6 @@ function getYamlMapScalarStringValue(map: unknown, key: string): string | undefi return undefined; } -// Delete a key by its literal name. `YAMLMap.delete` compares the key NODE, so -// find the node in `.items` first. A fresh scalar would silently no-op. -function deleteYamlMapKey(map: unknown, key: string): void { - if (!(map instanceof YAMLMap)) { - return; - } - const target = map.items.find( - (item) => item.key instanceof Scalar && item.key.value === key, - )?.key; - if (target) { - map.delete(target); - } -} - /** * Merge the managed override entries into a pnpm `overrides` record, under the * range-qualified keys (see `pnpmOverrideKey`). @@ -865,6 +853,12 @@ function deleteYamlMapKey(map: unknown, key: string): void { * `getCatalogDependencySpec`, which keeps a `catalog:` reference in the * pnpm-workspace.yaml sink. A `file:` managed spec (force-override mode) always * wins, because there is no catalog to resolve against in that mode. + * + * Force-override mode also appends the `vite-plus` pin, under a BARE key. The + * pin only exists in `file:` tgz mode, where migration writes the tgz spec + * straight into every manifest instead of a `catalog:` reference. In that mode + * there is no catalog provenance for a bare key to strip. This matches the + * workspace-yaml force-override path in `rewriteStandaloneProject`. */ export function mergeManagedPnpmOverrides( overrides: Record | undefined, @@ -878,6 +872,9 @@ export function mergeManagedPnpmOverrides( next[overrideKey] = existing?.startsWith('catalog:') && !managedSpec.startsWith('file:') ? existing : managedSpec; } + if (isForceOverrideMode()) { + next[VITE_PLUS_NAME] = VITE_PLUS_VERSION; + } return next; } @@ -1273,14 +1270,7 @@ export function rewriteRootWorkspacePackageJson( } pkg.pnpm = { ...pkg.pnpm, - overrides: { - ...mergeManagedPnpmOverrides(pkg.pnpm?.overrides, managed), - // The force-override `vite-plus` pin keeps a BARE key: it only exists - // in `file:` tgz mode, where migration writes the tgz spec straight - // into every manifest instead of a `catalog:` reference, so there is - // no catalog provenance for a bare key to strip. - ...(isForceOverrideMode() ? { [VITE_PLUS_NAME]: VITE_PLUS_VERSION } : {}), - }, + overrides: mergeManagedPnpmOverrides(pkg.pnpm?.overrides, managed), peerDependencyRules: { ...pkg.pnpm?.peerDependencyRules, allowAny: [ diff --git a/packages/cli/src/migration/migrator/orchestrators.ts b/packages/cli/src/migration/migrator/orchestrators.ts index 36400ec2f3..86a6f02225 100644 --- a/packages/cli/src/migration/migrator/orchestrators.ts +++ b/packages/cli/src/migration/migrator/orchestrators.ts @@ -197,16 +197,7 @@ export function rewriteStandaloneProject( // package names, so it stays bare. pkg.pnpm = { ...pkg.pnpm, - overrides: { - ...mergeManagedPnpmOverrides(pkg.pnpm?.overrides, managed), - // The force-override `vite-plus` pin keeps a BARE key. The pin only - // exists in `file:` tgz mode, where migration writes the tgz spec - // straight into every manifest instead of a `catalog:` reference. - // In that mode there is no catalog provenance for a bare key to - // strip. This matches the workspace-yaml force-override path in - // `rewriteStandaloneProject`. - ...(isForceOverrideMode() ? { [VITE_PLUS_NAME]: VITE_PLUS_VERSION } : {}), - }, + overrides: mergeManagedPnpmOverrides(pkg.pnpm?.overrides, managed), peerDependencyRules: { ...pkg.pnpm?.peerDependencyRules, allowAny: [ diff --git a/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts b/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts index 2ecfb93c83..4a327f91e9 100644 --- a/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts +++ b/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts @@ -61,6 +61,7 @@ import { VITEST_IS_MANAGED_OVERRIDE, managedOverrideKey, pnpmMajor, + pnpmOverrideKey, type CatalogDependencyResolver, type ManagedOverrideKeyStyle, type PnpmPackageJsonSettings, @@ -155,8 +156,8 @@ export function overridesSatisfyVitePlus( if ( !usesVitest && VITEST_IS_MANAGED_OVERRIDE && - (typeof overrides?.[managedOverrideKey('vitest', keyStyle)] === 'string' || - typeof overrides?.vitest === 'string') + (typeof overrides?.vitest === 'string' || + (keyStyle === 'pnpm-ranged' && typeof overrides?.[pnpmOverrideKey('vitest')] === 'string')) ) { return false; } @@ -897,16 +898,16 @@ function ensureOverrideEntries( // user's own `catalog:` choice survives. Then delete the bare key. // Two keys for one package would restore the match that clobbers // `catalog:` importers. - const currentSpec = next[overrideKey] ?? next[dependencyName]; if (overrideKey !== dependencyName && next[dependencyName] !== undefined) { + next[overrideKey] ??= next[dependencyName]; delete next[dependencyName]; changed = true; } - if (!overrideSpecSatisfiesVitePlus(dependencyName, currentSpec, catalogDependencyResolver)) { + if ( + !overrideSpecSatisfiesVitePlus(dependencyName, next[overrideKey], catalogDependencyResolver) + ) { next[overrideKey] = overrideSpec; changed = true; - } else if (next[overrideKey] !== currentSpec) { - next[overrideKey] = currentSpec; } } return { overrides: next, changed }; diff --git a/packages/cli/src/migration/migrator/vitest-ecosystem.ts b/packages/cli/src/migration/migrator/vitest-ecosystem.ts index 70822ae896..233a130f19 100644 --- a/packages/cli/src/migration/migrator/vitest-ecosystem.ts +++ b/packages/cli/src/migration/migrator/vitest-ecosystem.ts @@ -1,7 +1,7 @@ import fs from 'node:fs'; import path from 'node:path'; -import { Scalar, YAMLMap } from 'yaml'; +import { YAMLMap } from 'yaml'; import { PackageManager, type WorkspacePackage } from '../../types/index.ts'; import { @@ -563,8 +563,8 @@ export function removeManagedVitestEntry( return false; } let removed = false; - for (const key of Object.keys(record)) { - if (isManagedVitestOverrideKey(key, keyStyle) && typeof record[key] === 'string') { + for (const key of managedVitestOverrideKeys(keyStyle)) { + if (typeof record[key] === 'string') { delete record[key]; removed = true; } @@ -583,25 +583,17 @@ export function removeYamlMapVitestEntry( if (!VITEST_IS_MANAGED_OVERRIDE || !(map instanceof YAMLMap)) { return; } - const targets = map.items - .filter( - (item) => - item.key instanceof Scalar && - typeof item.key.value === 'string' && - isManagedVitestOverrideKey(item.key.value, keyStyle), - ) - .map((item) => item.key); - for (const target of targets) { - map.delete(target); + for (const key of managedVitestOverrideKeys(keyStyle)) { + map.delete(key); } } -// True for `vitest` itself, and, in a pnpm override sink, for the -// range-qualified spelling. A selector-scoped key (`some-app>vitest`) constrains -// only that parent's subtree. Such a key is never a managed key, so forms with -// `>` stay out. -function isManagedVitestOverrideKey(key: string, keyStyle: ManagedOverrideKeyStyle): boolean { - return key === 'vitest' || (keyStyle === 'pnpm-ranged' && key === pnpmOverrideKey('vitest')); +// The managed spellings of the `vitest` override key: `vitest` everywhere, plus +// `vitest@*` in a pnpm override sink (see `pnpmOverrideKey`). Exact key +// equality keeps selector-scoped keys such as `some-app>vitest` out, and, in +// bare sinks, a user-authored ranged key too. +function managedVitestOverrideKeys(keyStyle: ManagedOverrideKeyStyle): string[] { + return keyStyle === 'pnpm-ranged' ? ['vitest', pnpmOverrideKey('vitest')] : ['vitest']; } // Remove the managed `vitest` entry from pnpm peerDependencyRules (its