@@ -13,7 +13,7 @@ import { parse as yamlParse } from 'yaml'
1313import { getManifestData } from '@socketsecurity/registry'
1414import {
1515 hasOwn ,
16- objectFromEntries ,
16+ isObject ,
1717 toSortedObject
1818} from '@socketsecurity/registry/lib/objects'
1919import { fetchPackageManifest } from '@socketsecurity/registry/lib/packages'
@@ -37,6 +37,7 @@ import type { Ora } from 'ora'
3737
3838const COMMAND_TITLE = 'Socket Optimize'
3939const OVERRIDES_FIELD_NAME = 'overrides'
40+ const PNPM_FIELD_NAME = 'pnpm'
4041const PNPM_WORKSPACE = 'pnpm-workspace'
4142const RESOLUTIONS_FIELD_NAME = 'resolutions'
4243
@@ -138,31 +139,131 @@ type AgentModifyManifestFn = (
138139) => void
139140
140141const updateManifestByAgent : Record < Agent , AgentModifyManifestFn > = ( ( ) => {
141- function updateOverrides ( pkgJson : EditablePackageJson , overrides : Overrides ) {
142- pkgJson . update ( {
143- [ OVERRIDES_FIELD_NAME ] : overrides
144- } )
142+ const depFields = [
143+ 'dependencies' ,
144+ 'devDependencies' ,
145+ 'peerDependencies' ,
146+ 'peerDependenciesMeta' ,
147+ 'optionalDependencies' ,
148+ 'bundleDependencies'
149+ ]
150+
151+ function getEntryIndexes (
152+ entries : [ string | symbol , any ] [ ] ,
153+ keys : ( string | symbol ) [ ]
154+ ) : number [ ] {
155+ return keys
156+ . map ( n => entries . findIndex ( p => p [ 0 ] === n ) )
157+ . filter ( n => n !== - 1 )
158+ . sort ( ( a , b ) => a - b )
159+ }
160+
161+ function getLowestEntryIndex (
162+ entries : [ string | symbol , any ] [ ] ,
163+ keys : ( string | symbol ) [ ]
164+ ) {
165+ return getEntryIndexes ( entries , keys ) ?. [ 0 ] ?? - 1
166+ }
167+
168+ function getHighestEntryIndex (
169+ entries : [ string | symbol , any ] [ ] ,
170+ keys : ( string | symbol ) [ ]
171+ ) {
172+ return getEntryIndexes ( entries , keys ) . at ( - 1 ) ?? - 1
173+ }
174+
175+ function updatePkgJson (
176+ editablePkgJson : EditablePackageJson ,
177+ field : string ,
178+ value : any
179+ ) {
180+ const pkgJson = editablePkgJson . content
181+ const oldValue = pkgJson [ field ]
182+ if ( oldValue ) {
183+ // The field already exists so we simply update the field value.
184+ if ( field === PNPM_FIELD_NAME ) {
185+ editablePkgJson . update ( {
186+ [ field ] : {
187+ ...( isObject ( oldValue ) ? oldValue : { } ) ,
188+ overrides : value
189+ }
190+ } )
191+ } else {
192+ editablePkgJson . update ( { [ field ] : value } )
193+ }
194+ return
195+ }
196+ // Since the field doesn't exist we want to insert it into the package.json
197+ // in a place that makes sense, e.g. close to the "dependencies" field. If
198+ // we can't find a place to insert the field we'll add it to the bottom.
199+ const entries = Object . entries ( pkgJson )
200+ let insertIndex = - 1
201+ let isPlacingHigher = false
202+ if ( field === OVERRIDES_FIELD_NAME ) {
203+ insertIndex = getLowestEntryIndex ( entries , [ 'resolutions' ] )
204+ if ( insertIndex === - 1 ) {
205+ isPlacingHigher = true
206+ insertIndex = getHighestEntryIndex ( entries , [ ...depFields , 'pnpm' ] )
207+ }
208+ } else if ( field === RESOLUTIONS_FIELD_NAME ) {
209+ isPlacingHigher = true
210+ insertIndex = getHighestEntryIndex ( entries , [
211+ ...depFields ,
212+ 'overrides' ,
213+ 'pnpm'
214+ ] )
215+ } else if ( field === PNPM_FIELD_NAME ) {
216+ insertIndex = getLowestEntryIndex ( entries , [ 'overrides' , 'resolutions' ] )
217+ if ( insertIndex === - 1 ) {
218+ isPlacingHigher = true
219+ insertIndex = getHighestEntryIndex ( entries , depFields )
220+ }
221+ }
222+ if ( insertIndex === - 1 ) {
223+ insertIndex = getLowestEntryIndex ( entries , [ 'engines' , 'files' ] )
224+ }
225+ if ( insertIndex === - 1 ) {
226+ isPlacingHigher = true
227+ insertIndex = getHighestEntryIndex ( entries , [
228+ 'exports' ,
229+ 'imports' ,
230+ 'main'
231+ ] )
232+ }
233+ if ( insertIndex === - 1 ) {
234+ insertIndex = entries . length
235+ } else if ( isPlacingHigher ) {
236+ insertIndex += 1
237+ }
238+ entries . splice ( insertIndex , 0 , [ field , value ] )
239+ editablePkgJson . fromJSON (
240+ `${ JSON . stringify ( Object . fromEntries ( entries ) , null , 2 ) } \n`
241+ )
242+ }
243+
244+ function updateOverrides (
245+ editablePkgJson : EditablePackageJson ,
246+ overrides : Overrides
247+ ) {
248+ updatePkgJson ( editablePkgJson , OVERRIDES_FIELD_NAME , overrides )
145249 }
146250
147251 function updateResolutions (
148- pkgJson : EditablePackageJson ,
252+ editablePkgJson : EditablePackageJson ,
149253 overrides : Overrides
150254 ) {
151- pkgJson . update ( {
152- [ RESOLUTIONS_FIELD_NAME ] : < PnpmOrYarnOverrides > overrides
153- } )
255+ updatePkgJson (
256+ editablePkgJson ,
257+ RESOLUTIONS_FIELD_NAME ,
258+ < PnpmOrYarnOverrides > overrides
259+ )
154260 }
155261
156262 return {
157263 bun : updateResolutions ,
158264 npm : updateOverrides ,
159- pnpm ( pkgJson : EditablePackageJson , overrides : Overrides ) {
160- pkgJson . update ( {
161- pnpm : {
162- ...( < object > pkgJson . content [ 'pnpm' ] ) ,
163- [ OVERRIDES_FIELD_NAME ] : overrides
164- }
165- } )
265+ pnpm ( editablePkgJson : EditablePackageJson , overrides : Overrides ) {
266+ updatePkgJson ( editablePkgJson , PNPM_FIELD_NAME , overrides )
166267 } ,
167268 vlt : updateOverrides ,
168269 'yarn/berry' : updateResolutions ,
@@ -622,7 +723,7 @@ async function addOverrides(
622723 } )
623724 }
624725 if ( state . added . size > 0 || state . updated . size > 0 ) {
625- editablePkgJson . update ( < NPMCliPackageJson > objectFromEntries ( depEntries ) )
726+ editablePkgJson . update ( < NPMCliPackageJson > Object . fromEntries ( depEntries ) )
626727 for ( const { overrides, type } of overridesDataObjects ) {
627728 updateManifestByAgent [ type ] ( editablePkgJson , toSortedObject ( overrides ) )
628729 }
0 commit comments