@@ -422,63 +422,77 @@ export class Buddy {
422
422
423
423
// Handle package.json updates - only for actual package.json files, not dependency or GitHub Actions files
424
424
const packageJsonUpdates = updates . filter ( update =>
425
- update . file === 'package.json'
425
+ update . file . endsWith ( 'package.json' )
426
426
&& ! update . file . includes ( '.yaml' )
427
427
&& ! update . file . includes ( '.yml' )
428
428
&& ! update . file . includes ( '.github/workflows/' ) ,
429
429
)
430
- if ( packageJsonUpdates . length > 0 ) {
431
- const packageJsonPath = 'package.json'
432
430
433
- // Read current package.json content as string to preserve formatting
434
- let packageJsonContent = fs . readFileSync ( packageJsonPath , 'utf-8' )
435
-
436
- // Parse to understand structure
437
- const packageJson = JSON . parse ( packageJsonContent )
438
-
439
- // Apply updates using string replacement to preserve formatting
440
- for ( const update of packageJsonUpdates ) {
441
- let packageFound = false
442
-
443
- // Clean package name (remove dependency type info like "(dev)")
444
- const cleanPackageName = update . name . replace ( / \s * \( d e v \) $ / , '' ) . replace ( / \s * \( p e e r \) $ / , '' ) . replace ( / \s * \( o p t i o n a l \) $ / , '' )
445
-
446
- // Try to find and update the package in each dependency section
447
- const dependencySections = [ 'dependencies' , 'devDependencies' , 'peerDependencies' , 'optionalDependencies' ]
448
-
449
- for ( const section of dependencySections ) {
450
- if ( packageJson [ section ] && packageJson [ section ] [ cleanPackageName ] ) {
451
- const currentVersionInFile = packageJson [ section ] [ cleanPackageName ]
452
-
453
- // Extract the original version prefix (^, ~, >=, etc.) or lack thereof
454
- const versionPrefixMatch = currentVersionInFile . match ( / ^ ( \D * ) / )
455
- const originalPrefix = versionPrefixMatch ? versionPrefixMatch [ 1 ] : ''
431
+ // Group package.json updates by file
432
+ const updatesByPackageFile = new Map < string , PackageUpdate [ ] > ( )
433
+ for ( const update of packageJsonUpdates ) {
434
+ if ( ! updatesByPackageFile . has ( update . file ) ) {
435
+ updatesByPackageFile . set ( update . file , [ ] )
436
+ }
437
+ updatesByPackageFile . get ( update . file ) ! . push ( update )
438
+ }
456
439
457
- // Create regex to find the exact line with this package and version
458
- // This handles various formatting styles like: "package": "version", "package":"version", etc.
459
- const packageRegex = new RegExp (
460
- `("${ cleanPackageName . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) } "\\s*:\\s*")([^"]+)(")` ,
461
- 'g' ,
462
- )
440
+ // Process each package.json file
441
+ for ( const [ packageJsonPath , packageUpdates ] of updatesByPackageFile ) {
442
+ try {
443
+ // Read current package.json content as string to preserve formatting
444
+ let packageJsonContent = fs . readFileSync ( packageJsonPath , 'utf-8' )
445
+
446
+ // Parse to understand structure
447
+ const packageJson = JSON . parse ( packageJsonContent )
448
+
449
+ // Apply updates using string replacement to preserve formatting
450
+ for ( const update of packageUpdates ) {
451
+ let packageFound = false
452
+
453
+ // Clean package name (remove dependency type info like "(dev)")
454
+ const cleanPackageName = update . name . replace ( / \s * \( d e v \) $ / , '' ) . replace ( / \s * \( p e e r \) $ / , '' ) . replace ( / \s * \( o p t i o n a l \) $ / , '' )
455
+
456
+ // Try to find and update the package in each dependency section
457
+ const dependencySections = [ 'dependencies' , 'devDependencies' , 'peerDependencies' , 'optionalDependencies' ]
458
+
459
+ for ( const section of dependencySections ) {
460
+ if ( packageJson [ section ] && packageJson [ section ] [ cleanPackageName ] ) {
461
+ const currentVersionInFile = packageJson [ section ] [ cleanPackageName ]
462
+
463
+ // Extract the original version prefix (^, ~, >=, etc.) or lack thereof
464
+ const versionPrefixMatch = currentVersionInFile . match ( / ^ ( \D * ) / )
465
+ const originalPrefix = versionPrefixMatch ? versionPrefixMatch [ 1 ] : ''
466
+
467
+ // Create regex to find the exact line with this package and version
468
+ // This handles various formatting styles like: "package": "version", "package":"version", etc.
469
+ const packageRegex = new RegExp (
470
+ `("${ cleanPackageName . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) } "\\s*:\\s*")([^"]+)(")` ,
471
+ 'g' ,
472
+ )
473
+
474
+ // Preserve the original prefix when updating to new version
475
+ const newVersion = `${ originalPrefix } ${ update . newVersion } `
476
+ packageJsonContent = packageJsonContent . replace ( packageRegex , `$1${ newVersion } $3` )
477
+ packageFound = true
478
+ break
479
+ }
480
+ }
463
481
464
- // Preserve the original prefix when updating to new version
465
- const newVersion = `${ originalPrefix } ${ update . newVersion } `
466
- packageJsonContent = packageJsonContent . replace ( packageRegex , `$1${ newVersion } $3` )
467
- packageFound = true
468
- break
482
+ if ( ! packageFound ) {
483
+ console . warn ( `Package ${ cleanPackageName } not found in ${ packageJsonPath } ` )
469
484
}
470
485
}
471
486
472
- if ( ! packageFound ) {
473
- console . warn ( `Package ${ cleanPackageName } not found in package.json` )
474
- }
487
+ fileUpdates . push ( {
488
+ path : packageJsonPath ,
489
+ content : packageJsonContent ,
490
+ type : 'update' as const ,
491
+ } )
492
+ }
493
+ catch ( error ) {
494
+ console . warn ( `Failed to update ${ packageJsonPath } :` , error )
475
495
}
476
-
477
- fileUpdates . push ( {
478
- path : packageJsonPath ,
479
- content : packageJsonContent ,
480
- type : 'update' as const ,
481
- } )
482
496
}
483
497
484
498
// Handle dependency file updates (deps.yaml, dependencies.yaml, etc.)
0 commit comments