@@ -3179,7 +3179,7 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => {
31793179 peerDependencies : Record < string , string > ;
31803180 } ;
31813181 expect ( pkg . devDependencies . vite ) . toBe ( 'catalog:vite7' ) ;
3182- expect ( pkg . devDependencies [ 'vite-plus' ] ) . toBe ( 'catalog:' ) ;
3182+ expect ( pkg . devDependencies [ 'vite-plus' ] ) . toBe ( 'catalog:vite7 ' ) ;
31833183 expect ( pkg . peerDependencies . vite ) . toBe ( '^7.0.0' ) ;
31843184 // Peer declarations do not keep the managed catalog alive. Resolve the
31853185 // catalog entry to its public range before pruning it so the peer cannot
@@ -3188,6 +3188,166 @@ describe('rewriteStandaloneProject pnpm workspace yaml', () => {
31883188 expect ( pkg . peerDependencies ) . not . toHaveProperty ( 'tsdown' ) ;
31893189 } ) ;
31903190
3191+ it ( 'reuses catalogs.default without creating a duplicate top-level catalog' , ( ) => {
3192+ fs . writeFileSync (
3193+ path . join ( tmpDir , 'package.json' ) ,
3194+ JSON . stringify ( {
3195+ name : 'rari-shaped-workspace' ,
3196+ devDependencies : {
3197+ vite : 'catalog:build' ,
3198+ 'vite-plus' : 'catalog:build' ,
3199+ } ,
3200+ } ) ,
3201+ ) ;
3202+ fs . writeFileSync (
3203+ path . join ( tmpDir , 'pnpm-workspace.yaml' ) ,
3204+ [
3205+ 'catalogs:' ,
3206+ ' build:' ,
3207+ ' vite: ^8.0.0' ,
3208+ ' vite-plus: ^0.2.0' ,
3209+ ' default:' ,
3210+ ' rari: ^0.14.12' ,
3211+ '' ,
3212+ ] . join ( '\n' ) ,
3213+ ) ;
3214+
3215+ const savedForceMigrate = process . env . VP_FORCE_MIGRATE ;
3216+ process . env . VP_FORCE_MIGRATE = '1' ;
3217+ try {
3218+ rewriteStandaloneProject ( tmpDir , makeWorkspaceInfo ( tmpDir , PackageManager . pnpm ) , true , true ) ;
3219+ } finally {
3220+ if ( savedForceMigrate === undefined ) {
3221+ delete process . env . VP_FORCE_MIGRATE ;
3222+ } else {
3223+ process . env . VP_FORCE_MIGRATE = savedForceMigrate ;
3224+ }
3225+ }
3226+
3227+ const workspace = readYamlObject ( path . join ( tmpDir , 'pnpm-workspace.yaml' ) ) as {
3228+ catalog ?: Record < string , string > ;
3229+ catalogs : Record < string , Record < string , string > > ;
3230+ overrides : Record < string , string > ;
3231+ } ;
3232+ const pkg = readJson ( path . join ( tmpDir , 'package.json' ) ) as {
3233+ devDependencies : Record < string , string > ;
3234+ } ;
3235+
3236+ expect ( workspace . catalog ) . toBeUndefined ( ) ;
3237+ expect ( workspace . catalogs . default ) . toEqual ( { rari : '^0.14.12' } ) ;
3238+ expect ( workspace . catalogs . build . vite ) . toBe ( 'npm:@voidzero-dev/vite-plus-core@latest' ) ;
3239+ expect ( workspace . catalogs . build [ 'vite-plus' ] ) . toBe ( 'latest' ) ;
3240+ expect ( workspace . overrides . vite ) . toBe ( 'catalog:build' ) ;
3241+ expect ( pkg . devDependencies . vite ) . toBe ( 'catalog:build' ) ;
3242+ expect ( pkg . devDependencies [ 'vite-plus' ] ) . toBe ( 'catalog:build' ) ;
3243+ expect ( detectVitePlusBootstrapPending ( tmpDir , PackageManager . pnpm ) ) . toBe ( false ) ;
3244+ } ) ;
3245+
3246+ it ( 'writes managed dependencies into an active catalogs.default definition' , ( ) => {
3247+ fs . writeFileSync (
3248+ path . join ( tmpDir , 'package.json' ) ,
3249+ JSON . stringify ( {
3250+ name : 'default-catalog-workspace' ,
3251+ devDependencies : {
3252+ vite : 'catalog:' ,
3253+ 'vite-plus' : 'catalog:' ,
3254+ } ,
3255+ } ) ,
3256+ ) ;
3257+ fs . writeFileSync (
3258+ path . join ( tmpDir , 'pnpm-workspace.yaml' ) ,
3259+ [
3260+ 'catalogs:' ,
3261+ ' default:' ,
3262+ ' react: ^19.0.0' ,
3263+ ' vite: ^8.0.0' ,
3264+ ' vite-plus: ^0.2.0' ,
3265+ '' ,
3266+ ] . join ( '\n' ) ,
3267+ ) ;
3268+
3269+ const savedForceMigrate = process . env . VP_FORCE_MIGRATE ;
3270+ process . env . VP_FORCE_MIGRATE = '1' ;
3271+ try {
3272+ rewriteStandaloneProject ( tmpDir , makeWorkspaceInfo ( tmpDir , PackageManager . pnpm ) , true , true ) ;
3273+ } finally {
3274+ if ( savedForceMigrate === undefined ) {
3275+ delete process . env . VP_FORCE_MIGRATE ;
3276+ } else {
3277+ process . env . VP_FORCE_MIGRATE = savedForceMigrate ;
3278+ }
3279+ }
3280+
3281+ const workspace = readYamlObject ( path . join ( tmpDir , 'pnpm-workspace.yaml' ) ) as {
3282+ catalog ?: Record < string , string > ;
3283+ catalogs : Record < string , Record < string , string > > ;
3284+ overrides : Record < string , string > ;
3285+ } ;
3286+
3287+ expect ( workspace . catalog ) . toBeUndefined ( ) ;
3288+ expect ( workspace . catalogs . default . react ) . toBe ( '^19.0.0' ) ;
3289+ expect ( workspace . catalogs . default . vite ) . toBe ( 'npm:@voidzero-dev/vite-plus-core@latest' ) ;
3290+ expect ( workspace . catalogs . default [ 'vite-plus' ] ) . toBe ( 'latest' ) ;
3291+ expect ( workspace . overrides . vite ) . toBe ( 'catalog:' ) ;
3292+ expect ( detectVitePlusBootstrapPending ( tmpDir , PackageManager . pnpm ) ) . toBe ( false ) ;
3293+ } ) ;
3294+
3295+ it ( 'reuses a named-only Vite stack catalog without creating a default catalog' , ( ) => {
3296+ fs . writeFileSync (
3297+ path . join ( tmpDir , 'package.json' ) ,
3298+ JSON . stringify ( {
3299+ name : 'vize-shaped-workspace' ,
3300+ devDependencies : {
3301+ vite : 'catalog:vite-stack' ,
3302+ 'vite-plus' : 'catalog:vite-stack' ,
3303+ } ,
3304+ } ) ,
3305+ ) ;
3306+ fs . writeFileSync (
3307+ path . join ( tmpDir , 'pnpm-workspace.yaml' ) ,
3308+ [
3309+ 'catalogs:' ,
3310+ ' repo-tooling:' ,
3311+ ' prettier: 3.8.3' ,
3312+ ' vite-stack:' ,
3313+ ' vite: npm:@voidzero-dev/vite-plus-core@0.1.21' ,
3314+ ' vitest: npm:@voidzero-dev/vite-plus-test@0.1.21' ,
3315+ ' vite-plus: 0.1.21' ,
3316+ '' ,
3317+ ] . join ( '\n' ) ,
3318+ ) ;
3319+
3320+ const savedForceMigrate = process . env . VP_FORCE_MIGRATE ;
3321+ process . env . VP_FORCE_MIGRATE = '1' ;
3322+ try {
3323+ rewriteStandaloneProject ( tmpDir , makeWorkspaceInfo ( tmpDir , PackageManager . pnpm ) , true , true ) ;
3324+ } finally {
3325+ if ( savedForceMigrate === undefined ) {
3326+ delete process . env . VP_FORCE_MIGRATE ;
3327+ } else {
3328+ process . env . VP_FORCE_MIGRATE = savedForceMigrate ;
3329+ }
3330+ }
3331+
3332+ const workspace = readYamlObject ( path . join ( tmpDir , 'pnpm-workspace.yaml' ) ) as {
3333+ catalog ?: Record < string , string > ;
3334+ catalogs : Record < string , Record < string , string > > ;
3335+ overrides : Record < string , string > ;
3336+ } ;
3337+ const pkg = readJson ( path . join ( tmpDir , 'package.json' ) ) as {
3338+ devDependencies : Record < string , string > ;
3339+ } ;
3340+
3341+ expect ( workspace . catalog ) . toBeUndefined ( ) ;
3342+ expect ( workspace . catalogs [ 'repo-tooling' ] ) . toEqual ( { prettier : '3.8.3' } ) ;
3343+ expect ( workspace . catalogs [ 'vite-stack' ] . vite ) . toBe ( 'npm:@voidzero-dev/vite-plus-core@latest' ) ;
3344+ expect ( workspace . catalogs [ 'vite-stack' ] [ 'vite-plus' ] ) . toBe ( 'latest' ) ;
3345+ expect ( workspace . overrides . vite ) . toBe ( 'catalog:vite-stack' ) ;
3346+ expect ( pkg . devDependencies . vite ) . toBe ( 'catalog:vite-stack' ) ;
3347+ expect ( pkg . devDependencies [ 'vite-plus' ] ) . toBe ( 'catalog:vite-stack' ) ;
3348+ expect ( detectVitePlusBootstrapPending ( tmpDir , PackageManager . pnpm ) ) . toBe ( false ) ;
3349+ } ) ;
3350+
31913351 it ( 'drops only global/vite-plus-parent selector-shaped REMOVE_PACKAGES overrides after moving pnpm config' , ( ) => {
31923352 // Project starts with its pnpm config in package.json (`pkg.pnpm.overrides`).
31933353 // A selector-shaped provider key is stripped only when it would re-pin
0 commit comments