@@ -247,6 +247,35 @@ describe('detectNodeVersionManagerFile', () => {
247247 fs . writeFileSync ( path . join ( tmpDir , '.nvmrc' ) , 'v20.5.0\n' ) ;
248248 expect ( detectNodeVersionManagerFile ( tmpDir ) ) . toEqual ( { file : '.nvmrc' } ) ;
249249 } ) ;
250+
251+ it ( 'detects volta node in package.json' , ( ) => {
252+ fs . writeFileSync (
253+ path . join ( tmpDir , 'package.json' ) ,
254+ JSON . stringify ( { volta : { node : '20.5.0' } } ) ,
255+ ) ;
256+ expect ( detectNodeVersionManagerFile ( tmpDir ) ) . toEqual ( {
257+ file : 'package.json' ,
258+ voltaNodeVersion : '20.5.0' ,
259+ } ) ;
260+ } ) ;
261+
262+ it ( 'prefers .nvmrc over volta when both are present and sets voltaPresent' , ( ) => {
263+ fs . writeFileSync ( path . join ( tmpDir , '.nvmrc' ) , 'v20.5.0\n' ) ;
264+ fs . writeFileSync (
265+ path . join ( tmpDir , 'package.json' ) ,
266+ JSON . stringify ( { volta : { node : '18.0.0' } } ) ,
267+ ) ;
268+ expect ( detectNodeVersionManagerFile ( tmpDir ) ) . toEqual ( { file : '.nvmrc' , voltaPresent : true } ) ;
269+ } ) ;
270+
271+ it ( 'returns undefined when .node-version already exists even with volta' , ( ) => {
272+ fs . writeFileSync ( path . join ( tmpDir , '.node-version' ) , '20.5.0\n' ) ;
273+ fs . writeFileSync (
274+ path . join ( tmpDir , 'package.json' ) ,
275+ JSON . stringify ( { volta : { node : '20.5.0' } } ) ,
276+ ) ;
277+ expect ( detectNodeVersionManagerFile ( tmpDir ) ) . toBeUndefined ( ) ;
278+ } ) ;
250279} ) ;
251280
252281describe ( 'migrateNodeVersionManagerFile' , ( ) => {
@@ -260,6 +289,28 @@ describe('migrateNodeVersionManagerFile', () => {
260289 fs . rmSync ( tmpDir , { recursive : true , force : true } ) ;
261290 } ) ;
262291
292+ it ( 'adds volta manual step when voltaPresent is set' , ( ) => {
293+ fs . writeFileSync ( path . join ( tmpDir , '.nvmrc' ) , 'v20.5.0\n' ) ;
294+ const report = {
295+ createdViteConfigCount : 0 ,
296+ mergedConfigCount : 0 ,
297+ mergedStagedConfigCount : 0 ,
298+ inlinedLintStagedConfigCount : 0 ,
299+ removedConfigCount : 0 ,
300+ tsdownImportCount : 0 ,
301+ rewrittenImportFileCount : 0 ,
302+ rewrittenImportErrors : [ ] ,
303+ eslintMigrated : false ,
304+ prettierMigrated : false ,
305+ nodeVersionFileMigrated : false ,
306+ gitHooksConfigured : false ,
307+ warnings : [ ] ,
308+ manualSteps : [ ] ,
309+ } ;
310+ migrateNodeVersionManagerFile ( tmpDir , { file : '.nvmrc' , voltaPresent : true } , report ) ;
311+ expect ( report . manualSteps ) . toContain ( 'Remove the "volta" field from package.json' ) ;
312+ } ) ;
313+
263314 it ( 'migrates .nvmrc to .node-version and removes .nvmrc' , ( ) => {
264315 fs . writeFileSync ( path . join ( tmpDir , '.nvmrc' ) , 'v20.5.0\n' ) ;
265316 const ok = migrateNodeVersionManagerFile ( tmpDir , { file : '.nvmrc' } ) ;
@@ -291,6 +342,77 @@ describe('migrateNodeVersionManagerFile', () => {
291342 expect ( report . warnings . length ) . toBe ( 1 ) ;
292343 expect ( fs . existsSync ( path . join ( tmpDir , '.node-version' ) ) ) . toBe ( false ) ;
293344 } ) ;
345+
346+ it ( 'migrates volta node version to .node-version' , ( ) => {
347+ const ok = migrateNodeVersionManagerFile ( tmpDir , {
348+ file : 'package.json' ,
349+ voltaNodeVersion : '20.5.0' ,
350+ } ) ;
351+ expect ( ok ) . toBe ( true ) ;
352+ expect ( fs . readFileSync ( path . join ( tmpDir , '.node-version' ) , 'utf8' ) ) . toBe ( '20.5.0\n' ) ;
353+ } ) ;
354+
355+ it ( 'sets nodeVersionFileMigrated and manualSteps in report for volta migration' , ( ) => {
356+ const report = {
357+ createdViteConfigCount : 0 ,
358+ mergedConfigCount : 0 ,
359+ mergedStagedConfigCount : 0 ,
360+ inlinedLintStagedConfigCount : 0 ,
361+ removedConfigCount : 0 ,
362+ tsdownImportCount : 0 ,
363+ rewrittenImportFileCount : 0 ,
364+ rewrittenImportErrors : [ ] ,
365+ eslintMigrated : false ,
366+ prettierMigrated : false ,
367+ nodeVersionFileMigrated : false ,
368+ gitHooksConfigured : false ,
369+ warnings : [ ] ,
370+ manualSteps : [ ] ,
371+ } ;
372+ migrateNodeVersionManagerFile (
373+ tmpDir ,
374+ { file : 'package.json' , voltaNodeVersion : '20.5.0' } ,
375+ report ,
376+ ) ;
377+ expect ( report . nodeVersionFileMigrated ) . toBe ( true ) ;
378+ expect ( report . manualSteps ) . toContain ( 'Remove the "volta" field from package.json' ) ;
379+ } ) ;
380+
381+ it ( 'normalizes volta.node "lts" to "lts/*"' , ( ) => {
382+ const ok = migrateNodeVersionManagerFile ( tmpDir , {
383+ file : 'package.json' ,
384+ voltaNodeVersion : 'lts' ,
385+ } ) ;
386+ expect ( ok ) . toBe ( true ) ;
387+ expect ( fs . readFileSync ( path . join ( tmpDir , '.node-version' ) , 'utf8' ) ) . toBe ( 'lts/*\n' ) ;
388+ } ) ;
389+
390+ it ( 'returns false and warns when volta.node is a partial version' , ( ) => {
391+ const report = {
392+ createdViteConfigCount : 0 ,
393+ mergedConfigCount : 0 ,
394+ mergedStagedConfigCount : 0 ,
395+ inlinedLintStagedConfigCount : 0 ,
396+ removedConfigCount : 0 ,
397+ tsdownImportCount : 0 ,
398+ rewrittenImportFileCount : 0 ,
399+ rewrittenImportErrors : [ ] ,
400+ eslintMigrated : false ,
401+ prettierMigrated : false ,
402+ nodeVersionFileMigrated : false ,
403+ gitHooksConfigured : false ,
404+ warnings : [ ] ,
405+ manualSteps : [ ] ,
406+ } ;
407+ const ok = migrateNodeVersionManagerFile (
408+ tmpDir ,
409+ { file : 'package.json' , voltaNodeVersion : '20' } ,
410+ report ,
411+ ) ;
412+ expect ( ok ) . toBe ( false ) ;
413+ expect ( report . warnings . length ) . toBe ( 1 ) ;
414+ expect ( fs . existsSync ( path . join ( tmpDir , '.node-version' ) ) ) . toBe ( false ) ;
415+ } ) ;
294416} ) ;
295417
296418function makeWorkspaceInfo (
0 commit comments