@@ -158,76 +158,127 @@ const updateManifestByAgent: Record<Agent, AgentModifyManifestFn> = {
158
158
}
159
159
}
160
160
161
+ type AgentListDepsOptions = {
162
+ npmExecPath ?: string
163
+ rootPath ?: string
164
+ }
161
165
type AgentListDepsFn = (
162
166
agentExecPath : string ,
163
167
cwd : string ,
164
- rootPath : string
168
+ options ?: AgentListDepsOptions
165
169
) => Promise < string >
166
170
167
- const lsByAgent : Record < Agent , AgentListDepsFn > = {
168
- async bun ( agentExecPath : string , cwd : string , _rootPath : string ) {
169
- try {
170
- // Bun does not support filtering by production packages yet.
171
- // https://github.com/oven-sh/bun/issues/8283
172
- return ( await spawn ( agentExecPath , [ 'pm' , 'ls' , '--all' ] , { cwd } ) ) . stdout
173
- } catch { }
174
- return ''
175
- } ,
176
- async npm ( agentExecPath : string , cwd : string , rootPath : string ) {
177
- try {
178
- let { stdout } = await spawn (
179
- agentExecPath ,
180
- [ 'ls' , '--parseable' , '--omit' , 'dev' , '--all' ] ,
181
- { cwd }
182
- )
183
- stdout = stdout . trim ( )
184
- stdout = stdout . replaceAll ( cwd , '' )
185
- stdout = rootPath === cwd ? stdout : stdout . replaceAll ( rootPath , '' )
186
- return stdout . replaceAll ( '\\' , '/' )
187
- } catch { }
188
- return ''
189
- } ,
190
- async pnpm ( agentExecPath : string , cwd : string , rootPath : string ) {
191
- try {
192
- let { stdout } = await spawn (
193
- agentExecPath ,
194
- [ 'ls' , '--parseable' , '--prod' , '--depth' , 'Infinity' ] ,
195
- { cwd }
196
- )
197
- stdout = stdout . trim ( )
198
- stdout = stdout . replaceAll ( cwd , '' )
199
- stdout = rootPath === cwd ? stdout : stdout . replaceAll ( rootPath , '' )
200
- return stdout . replaceAll ( '\\' , '/' )
201
- } catch { }
202
- return ''
203
- } ,
204
- async 'yarn/berry' ( agentExecPath : string , cwd : string , _rootPath : string ) {
205
- try {
206
- return (
207
- // Yarn Berry does not support filtering by production packages yet.
208
- // https://github.com/yarnpkg/berry/issues/5117
209
- (
210
- await spawn ( agentExecPath , [ 'info' , '--recursive' , '--name-only' ] , {
211
- cwd
212
- } )
171
+ const lsByAgent = ( ( ) => {
172
+ function cleanupParseable (
173
+ stdout : string ,
174
+ cwd : string ,
175
+ rootPath ?: string
176
+ ) : string {
177
+ stdout = stdout . trim ( )
178
+ stdout = stdout . replaceAll ( cwd , '' )
179
+ if ( rootPath && rootPath !== cwd ) {
180
+ stdout = stdout . replaceAll ( rootPath , '' )
181
+ }
182
+ return stdout . replaceAll ( '\\' , '/' )
183
+ }
184
+
185
+ async function npmLs ( npmExecPath : string , cwd : string , rootPath ?: string ) {
186
+ return cleanupParseable (
187
+ (
188
+ await spawn (
189
+ npmExecPath ,
190
+ [ 'ls' , '--parseable' , '--omit' , 'dev' , '--all' ] ,
191
+ { cwd }
192
+ )
193
+ ) . stdout ,
194
+ cwd ,
195
+ rootPath
196
+ )
197
+ }
198
+ return < Record < Agent , AgentListDepsFn > > {
199
+ async bun ( agentExecPath : string , cwd : string ) {
200
+ try {
201
+ // Bun does not support filtering by production packages yet.
202
+ // https://github.com/oven-sh/bun/issues/8283
203
+ return ( await spawn ( agentExecPath ! , [ 'pm' , 'ls' , '--all' ] , { cwd } ) )
204
+ . stdout
205
+ } catch { }
206
+ return ''
207
+ } ,
208
+ async npm (
209
+ agentExecPath : string ,
210
+ cwd : string ,
211
+ options : AgentListDepsOptions
212
+ ) {
213
+ const { rootPath } = < AgentListDepsOptions > { __proto__ : null , ...options }
214
+ try {
215
+ return await npmLs ( agentExecPath , cwd , rootPath )
216
+ } catch { }
217
+ return ''
218
+ } ,
219
+ async pnpm (
220
+ agentExecPath : string ,
221
+ cwd : string ,
222
+ options : AgentListDepsOptions
223
+ ) {
224
+ const { npmExecPath, rootPath } = < AgentListDepsOptions > {
225
+ __proto__ : null ,
226
+ ...options
227
+ }
228
+ let stdout = ''
229
+ if ( npmExecPath && npmExecPath !== 'npm' ) {
230
+ try {
231
+ stdout = await npmLs ( npmExecPath , cwd , rootPath )
232
+ } catch ( e : any ) {
233
+ if ( e ?. stderr ?. includes ( 'code ELSPROBLEMS' ) ) {
234
+ stdout = e ?. stdout
235
+ }
236
+ }
237
+ } else {
238
+ try {
239
+ stdout = cleanupParseable (
240
+ (
241
+ await spawn (
242
+ agentExecPath ,
243
+ [ 'ls' , '--parseable' , '--prod' , '--depth' , 'Infinity' ] ,
244
+ { cwd }
245
+ )
246
+ ) . stdout ,
247
+ cwd ,
248
+ rootPath
249
+ )
250
+ } catch { }
251
+ }
252
+ return stdout
253
+ } ,
254
+ async 'yarn/berry' ( agentExecPath : string , cwd : string ) {
255
+ try {
256
+ return (
257
+ // Yarn Berry does not support filtering by production packages yet.
258
+ // https://github.com/yarnpkg/berry/issues/5117
259
+ (
260
+ await spawn ( agentExecPath , [ 'info' , '--recursive' , '--name-only' ] , {
261
+ cwd
262
+ } )
263
+ ) . stdout . trim ( )
264
+ )
265
+ } catch { }
266
+ return ''
267
+ } ,
268
+ async 'yarn/classic' ( agentExecPath : string , cwd : string ) {
269
+ try {
270
+ // However, Yarn Classic does support it.
271
+ // https://github.com/yarnpkg/yarn/releases/tag/v1.0.0
272
+ // > Fix: Excludes dev dependencies from the yarn list output when the
273
+ // environment is production
274
+ return (
275
+ await spawn ( agentExecPath , [ 'list' , '--prod' ] , { cwd } )
213
276
) . stdout . trim ( )
214
- )
215
- } catch { }
216
- return ''
217
- } ,
218
- async 'yarn/classic' ( agentExecPath : string , cwd : string , _rootPath : string ) {
219
- try {
220
- // However, Yarn Classic does support it.
221
- // https://github.com/yarnpkg/yarn/releases/tag/v1.0.0
222
- // > Fix: Excludes dev dependencies from the yarn list output when the
223
- // environment is production
224
- return (
225
- await spawn ( agentExecPath , [ 'list' , '--prod' ] , { cwd } )
226
- ) . stdout . trim ( )
227
- } catch { }
228
- return ''
277
+ } catch { }
278
+ return ''
279
+ }
229
280
}
230
- }
281
+ } ) ( )
231
282
232
283
type AgentDepsIncludesFn = ( stdout : string , name : string ) => boolean
233
284
@@ -319,6 +370,7 @@ type AddOverridesConfig = {
319
370
agentExecPath : string
320
371
lockSrc : string
321
372
manifestEntries : ManifestEntry [ ]
373
+ npmExecPath : string
322
374
pkgJson ?: EditablePackageJson | undefined
323
375
pkgPath : string
324
376
pin ?: boolean | undefined
@@ -330,6 +382,17 @@ type AddOverridesState = {
330
382
added : Set < string >
331
383
spinner ?: Ora | undefined
332
384
updated : Set < string >
385
+ warnedPnpmWorkspaceRequiresNpm : boolean
386
+ }
387
+
388
+ function createAddOverridesState ( initials ?: any ) : AddOverridesState {
389
+ return {
390
+ added : new Set ( ) ,
391
+ spinner : undefined ,
392
+ updated : new Set ( ) ,
393
+ warnedPnpmWorkspaceRequiresNpm : false ,
394
+ ...initials
395
+ }
333
396
}
334
397
335
398
async function addOverrides (
@@ -338,17 +401,14 @@ async function addOverrides(
338
401
agentExecPath,
339
402
lockSrc,
340
403
manifestEntries,
404
+ npmExecPath,
341
405
pin,
342
406
pkgJson : editablePkgJson ,
343
407
pkgPath,
344
408
prod,
345
409
rootPath
346
410
} : AddOverridesConfig ,
347
- state : AddOverridesState = {
348
- added : new Set ( ) ,
349
- spinner : undefined ,
350
- updated : new Set ( )
351
- }
411
+ state = createAddOverridesState ( )
352
412
) : Promise < AddOverridesState > {
353
413
if ( editablePkgJson === undefined ) {
354
414
editablePkgJson = await EditablePackageJson . load ( pkgPath )
@@ -357,26 +417,39 @@ async function addOverrides(
357
417
const pkgJson : Readonly < PackageJsonContent > = editablePkgJson . content
358
418
const isRoot = pkgPath === rootPath
359
419
const isLockScanned = isRoot && ! prod
420
+ const relPath = path . relative ( rootPath , pkgPath )
421
+ const workspaces = await getWorkspaces ( agent , pkgPath , pkgJson )
422
+ const isWorkspace = ! ! workspaces
423
+ if (
424
+ isWorkspace &&
425
+ agent === 'pnpm' &&
426
+ npmExecPath === 'npm' &&
427
+ ! state . warnedPnpmWorkspaceRequiresNpm
428
+ ) {
429
+ state . warnedPnpmWorkspaceRequiresNpm = true
430
+ console . log (
431
+ `⚠️ ${ COMMAND_TITLE } : pnpm workspace support requires \`npm ls\`, falling back to \`pnpm list\``
432
+ )
433
+ }
360
434
const thingToScan = isLockScanned
361
435
? lockSrc
362
- : await lsByAgent [ agent ] ( agentExecPath , pkgPath , rootPath )
436
+ : await lsByAgent [ agent ] ( agentExecPath , pkgPath , { npmExecPath , rootPath } )
363
437
const thingScanner = isLockScanned
364
438
? lockIncludesByAgent [ agent ]
365
439
: depsIncludesByAgent [ agent ]
366
440
const depEntries = getDependencyEntries ( pkgJson )
367
- const workspaces = await getWorkspaces ( agent , pkgPath , pkgJson )
368
- const isWorkspace = ! ! workspaces
441
+
369
442
const overridesDataObjects = < GetOverridesResult [ ] > [ ]
370
443
if ( pkgJson [ 'private' ] || isWorkspace ) {
371
444
overridesDataObjects . push ( getOverridesDataByAgent [ agent ] ( pkgJson ) )
372
445
} else {
373
446
overridesDataObjects . push (
374
- getOverridesDataByAgent [ ' npm' ] ( pkgJson ) ,
447
+ getOverridesDataByAgent . npm ( pkgJson ) ,
375
448
getOverridesDataByAgent [ 'yarn/classic' ] ( pkgJson )
376
449
)
377
450
}
378
451
if ( spinner ) {
379
- spinner . text = `Adding overrides${ isRoot ? '' : ` to ${ path . relative ( rootPath , pkgPath ) } ` } ...`
452
+ spinner . text = `Adding overrides${ relPath ? ` to ${ relPath } ` : '' } ...`
380
453
}
381
454
const depAliasMap = new Map < string , { id : string ; version : string } > ( )
382
455
// Chunk package names to process them in parallel 3 at a time.
@@ -470,16 +543,13 @@ async function addOverrides(
470
543
agentExecPath,
471
544
lockSrc,
472
545
manifestEntries,
546
+ npmExecPath,
473
547
pin,
474
548
pkgPath : path . dirname ( wsPkgJsonPath ) ,
475
549
prod,
476
550
rootPath
477
551
} ,
478
- {
479
- added : new Set ( ) ,
480
- spinner,
481
- updated : new Set ( )
482
- }
552
+ createAddOverridesState ( { spinner } )
483
553
)
484
554
for ( const regPkgName of added ) {
485
555
state . added . add ( regPkgName )
@@ -575,6 +645,7 @@ export const optimize: CliSubcommand = {
575
645
lockPath,
576
646
lockSrc,
577
647
minimumNodeVersion,
648
+ npmExecPath,
578
649
pkgJson,
579
650
pkgPath,
580
651
supported
@@ -617,11 +688,7 @@ export const optimize: CliSubcommand = {
617
688
)
618
689
}
619
690
const spinner = ora ( 'Socket optimizing...' )
620
- const state : AddOverridesState = {
621
- added : new Set ( ) ,
622
- spinner,
623
- updated : new Set ( )
624
- }
691
+ const state = createAddOverridesState ( { spinner } )
625
692
spinner . start ( )
626
693
const nodeRange = `>=${ minimumNodeVersion } `
627
694
const manifestEntries = manifestNpmOverrides . filter ( ( { 1 : data } ) =>
@@ -633,6 +700,7 @@ export const optimize: CliSubcommand = {
633
700
agentExecPath,
634
701
lockSrc,
635
702
manifestEntries,
703
+ npmExecPath,
636
704
pin,
637
705
pkgJson,
638
706
pkgPath,
0 commit comments