@@ -4,6 +4,7 @@ import path from 'node:path'
4
4
import spawn from '@npmcli/promise-spawn'
5
5
import EditablePackageJson from '@npmcli/package-json'
6
6
import { getManifestData } from '@socketsecurity/registry'
7
+ //import cacache from 'cacache'
7
8
import meow from 'meow'
8
9
import npa from 'npm-package-arg'
9
10
import ora from 'ora'
@@ -12,6 +13,8 @@ import semver from 'semver'
12
13
import { glob as tinyGlob } from 'tinyglobby'
13
14
import { parse as yamlParse } from 'yaml'
14
15
16
+ //import { packumentCache, pacoteCachePath } from '../constants'
17
+ import { packumentCache } from '../constants'
15
18
import { commonFlags } from '../flags'
16
19
import { printFlagList } from '../utils/formatting'
17
20
import { existsSync } from '../utils/fs'
@@ -24,11 +27,11 @@ import { isNonEmptyString } from '../utils/strings'
24
27
25
28
import type { Content as PackageJsonContent } from '@npmcli/package-json'
26
29
import type { ManifestEntry } from '@socketsecurity/registry'
30
+ import type { Ora } from 'ora'
27
31
import type { PacoteOptions } from 'pacote'
28
32
import type { CliSubcommand } from '../utils/meow-with-subcommands'
29
33
import type {
30
34
Agent ,
31
- AgentPlusBun ,
32
35
StringKeyValueObject
33
36
} from '../utils/package-manager-detector'
34
37
@@ -39,7 +42,6 @@ const RESOLUTIONS_FIELD_NAME = 'resolutions'
39
42
40
43
const distPath = __dirname
41
44
const manifestNpmOverrides = getManifestData ( 'npm' ) !
42
- const packumentCache = new Map ( )
43
45
44
46
type NpmOverrides = { [ key : string ] : string | StringKeyValueObject }
45
47
type PnpmOrYarnOverrides = { [ key : string ] : string }
@@ -50,10 +52,10 @@ type GetOverridesResult = {
50
52
overrides : Overrides
51
53
}
52
54
53
- const getOverridesDataByAgent : Record < AgentPlusBun , GetOverrides > = {
55
+ const getOverridesDataByAgent : Record < Agent , GetOverrides > = {
54
56
bun ( pkgJson : PackageJsonContent ) {
55
57
const overrides = ( pkgJson as any ) ?. resolutions ?? { }
56
- return { type : 'yarn' , overrides }
58
+ return { type : 'yarn/berry ' , overrides }
57
59
} ,
58
60
// npm overrides documentation:
59
61
// https://docs.npmjs.com/cli/v10/configuring-npm/package-json#overrides
@@ -69,15 +71,21 @@ const getOverridesDataByAgent: Record<AgentPlusBun, GetOverrides> = {
69
71
} ,
70
72
// Yarn resolutions documentation:
71
73
// https://yarnpkg.com/configuration/manifest#resolutions
72
- yarn ( pkgJson : PackageJsonContent ) {
74
+ ' yarn/berry' ( pkgJson : PackageJsonContent ) {
73
75
const overrides = ( pkgJson as any ) ?. resolutions ?? { }
74
- return { type : 'yarn' , overrides }
76
+ return { type : 'yarn/berry' , overrides }
77
+ } ,
78
+ // Yarn resolutions documentation:
79
+ // https://classic.yarnpkg.com/en/docs/selective-version-resolutions
80
+ 'yarn/classic' ( pkgJson : PackageJsonContent ) {
81
+ const overrides = ( pkgJson as any ) ?. resolutions ?? { }
82
+ return { type : 'yarn/classic' , overrides }
75
83
}
76
84
}
77
85
78
86
type AgentLockIncludesFn = ( lockSrc : string , name : string ) => boolean
79
87
80
- const lockIncludesByAgent : Record < AgentPlusBun , AgentLockIncludesFn > = ( ( ) => {
88
+ const lockIncludesByAgent : Record < Agent , AgentLockIncludesFn > = ( ( ) => {
81
89
const yarn = ( lockSrc : string , name : string ) => {
82
90
const escapedName = escapeRegExp ( name )
83
91
return new RegExp (
@@ -109,7 +117,8 @@ const lockIncludesByAgent: Record<AgentPlusBun, AgentLockIncludesFn> = (() => {
109
117
'm'
110
118
) . test ( lockSrc )
111
119
} ,
112
- yarn
120
+ 'yarn/berry' : yarn ,
121
+ 'yarn/classic' : yarn
113
122
}
114
123
} ) ( )
115
124
@@ -118,7 +127,7 @@ type AgentModifyManifestFn = (
118
127
overrides : Overrides
119
128
) => void
120
129
121
- const updateManifestByAgent : Record < AgentPlusBun , AgentModifyManifestFn > = {
130
+ const updateManifestByAgent : Record < Agent , AgentModifyManifestFn > = {
122
131
bun ( pkgJson : EditablePackageJson , overrides : Overrides ) {
123
132
pkgJson . update ( {
124
133
[ RESOLUTIONS_FIELD_NAME ] : < PnpmOrYarnOverrides > overrides
@@ -137,7 +146,12 @@ const updateManifestByAgent: Record<AgentPlusBun, AgentModifyManifestFn> = {
137
146
}
138
147
} )
139
148
} ,
140
- yarn ( pkgJson : EditablePackageJson , overrides : Overrides ) {
149
+ 'yarn/berry' ( pkgJson : EditablePackageJson , overrides : Overrides ) {
150
+ pkgJson . update ( {
151
+ [ RESOLUTIONS_FIELD_NAME ] : < PnpmOrYarnOverrides > overrides
152
+ } )
153
+ } ,
154
+ 'yarn/classic' ( pkgJson : EditablePackageJson , overrides : Overrides ) {
141
155
pkgJson . update ( {
142
156
[ RESOLUTIONS_FIELD_NAME ] : < PnpmOrYarnOverrides > overrides
143
157
} )
@@ -150,7 +164,7 @@ type AgentListDepsFn = (
150
164
rootPath : string
151
165
) => Promise < string >
152
166
153
- const lsByAgent : Record < AgentPlusBun , AgentListDepsFn > = {
167
+ const lsByAgent : Record < Agent , AgentListDepsFn > = {
154
168
async bun ( agentExecPath : string , cwd : string , _rootPath : string ) {
155
169
try {
156
170
// Bun does not support filtering by production packages yet.
@@ -166,8 +180,10 @@ const lsByAgent: Record<AgentPlusBun, AgentListDepsFn> = {
166
180
[ 'ls' , '--parseable' , '--omit' , 'dev' , '--all' ] ,
167
181
{ cwd }
168
182
)
183
+ stdout = stdout . trim ( )
169
184
stdout = stdout . replaceAll ( cwd , '' )
170
- return rootPath === cwd ? stdout : stdout . replaceAll ( rootPath , '' )
185
+ stdout = rootPath === cwd ? stdout : stdout . replaceAll ( rootPath , '' )
186
+ return stdout . replaceAll ( '\\' , '/' )
171
187
} catch { }
172
188
return ''
173
189
} ,
@@ -178,12 +194,14 @@ const lsByAgent: Record<AgentPlusBun, AgentListDepsFn> = {
178
194
[ 'ls' , '--parseable' , '--prod' , '--depth' , 'Infinity' ] ,
179
195
{ cwd }
180
196
)
197
+ stdout = stdout . trim ( )
181
198
stdout = stdout . replaceAll ( cwd , '' )
182
- return rootPath === cwd ? stdout : stdout . replaceAll ( rootPath , '' )
199
+ stdout = rootPath === cwd ? stdout : stdout . replaceAll ( rootPath , '' )
200
+ return stdout . replaceAll ( '\\' , '/' )
183
201
} catch { }
184
202
return ''
185
203
} ,
186
- async yarn ( agentExecPath : string , cwd : string , _rootPath : string ) {
204
+ async ' yarn/berry' ( agentExecPath : string , cwd : string , _rootPath : string ) {
187
205
try {
188
206
return (
189
207
// Yarn Berry does not support filtering by production packages yet.
@@ -192,24 +210,33 @@ const lsByAgent: Record<AgentPlusBun, AgentListDepsFn> = {
192
210
await spawn ( agentExecPath , [ 'info' , '--recursive' , '--name-only' ] , {
193
211
cwd
194
212
} )
195
- ) . stdout
213
+ ) . stdout . trim ( )
196
214
)
197
215
} catch { }
216
+ return ''
217
+ } ,
218
+ async 'yarn/classic' ( agentExecPath : string , cwd : string , _rootPath : string ) {
198
219
try {
199
220
// However, Yarn Classic does support it.
200
- return ( await spawn ( agentExecPath , [ 'list' , '--prod' ] , { cwd } ) ) . stdout
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 ( )
201
227
} catch { }
202
228
return ''
203
229
}
204
230
}
205
231
206
232
type AgentDepsIncludesFn = ( stdout : string , name : string ) => boolean
207
233
208
- const depsIncludesByAgent : Record < AgentPlusBun , AgentDepsIncludesFn > = {
209
- bun : ( stdout : string , name : string ) => stdout . includes ( name ) ,
210
- npm : ( stdout : string , name : string ) => stdout . includes ( name ) ,
211
- pnpm : ( stdout : string , name : string ) => stdout . includes ( name ) ,
212
- yarn : ( stdout : string , name : string ) => stdout . includes ( name )
234
+ const depsIncludesByAgent : Record < Agent , AgentDepsIncludesFn > = {
235
+ bun : ( stdout : string , name : string ) => stdout . includes ( ` ${ name } @` ) ,
236
+ npm : ( stdout : string , name : string ) => stdout . includes ( `/${ name } \n` ) ,
237
+ pnpm : ( stdout : string , name : string ) => stdout . includes ( `/${ name } \n` ) ,
238
+ 'yarn/berry' : ( stdout : string , name : string ) => stdout . includes ( ` ${ name } @` ) ,
239
+ 'yarn/classic' : ( stdout : string , name : string ) => stdout . includes ( ` ${ name } @` )
213
240
}
214
241
215
242
function getDependencyEntries ( pkgJson : PackageJsonContent ) {
@@ -242,7 +269,7 @@ function getDependencyEntries(pkgJson: PackageJsonContent) {
242
269
}
243
270
244
271
async function getWorkspaces (
245
- agent : AgentPlusBun ,
272
+ agent : Agent ,
246
273
pkgPath : string ,
247
274
pkgJson : PackageJsonContent
248
275
) : Promise < string [ ] | undefined > {
@@ -288,7 +315,7 @@ function workspaceToGlobPattern(workspace: string): string {
288
315
}
289
316
290
317
type AddOverridesConfig = {
291
- agent : AgentPlusBun
318
+ agent : Agent
292
319
agentExecPath : string
293
320
lockSrc : string
294
321
manifestEntries : ManifestEntry [ ]
@@ -301,6 +328,7 @@ type AddOverridesConfig = {
301
328
302
329
type AddOverridesState = {
303
330
added : Set < string >
331
+ spinner ?: Ora | undefined
304
332
updated : Set < string >
305
333
}
306
334
@@ -318,12 +346,14 @@ async function addOverrides(
318
346
} : AddOverridesConfig ,
319
347
state : AddOverridesState = {
320
348
added : new Set ( ) ,
349
+ spinner : undefined ,
321
350
updated : new Set ( )
322
351
}
323
352
) : Promise < AddOverridesState > {
324
353
if ( editablePkgJson === undefined ) {
325
354
editablePkgJson = await EditablePackageJson . load ( pkgPath )
326
355
}
356
+ const { spinner } = state
327
357
const pkgJson : Readonly < PackageJsonContent > = editablePkgJson . content
328
358
const isRoot = pkgPath === rootPath
329
359
const isLockScanned = isRoot && ! prod
@@ -342,12 +372,12 @@ async function addOverrides(
342
372
} else {
343
373
overridesDataObjects . push (
344
374
getOverridesDataByAgent [ 'npm' ] ( pkgJson ) ,
345
- getOverridesDataByAgent [ 'yarn' ] ( pkgJson )
375
+ getOverridesDataByAgent [ 'yarn/classic ' ] ( pkgJson )
346
376
)
347
377
}
348
- const spinner = isRoot
349
- ? ora ( 'Fetching override manifests...' ) . start ( )
350
- : undefined
378
+ if ( spinner ) {
379
+ spinner . text = `Adding overrides ${ isRoot ? '' : ` to ${ path . relative ( rootPath , pkgPath ) } ` } ...`
380
+ }
351
381
const depAliasMap = new Map < string , { id : string ; version : string } > ( )
352
382
// Chunk package names to process them in parallel 3 at a time.
353
383
await pEach ( manifestEntries , 3 , async ( { 1 : data } ) => {
@@ -428,21 +458,29 @@ async function addOverrides(
428
458
workspaces . map ( workspaceToGlobPattern ) ,
429
459
{
430
460
absolute : true ,
431
- cwd : pkgPath !
461
+ cwd : pkgPath ! ,
462
+ ignore : [ '**/node_modules/**' , '**/bower_components/**' ]
432
463
}
433
464
)
434
465
// Chunk package names to process them in parallel 3 at a time.
435
466
await pEach ( wsPkgJsonPaths , 3 , async wsPkgJsonPath => {
436
- const { added, updated } = await addOverrides ( {
437
- agent,
438
- agentExecPath,
439
- lockSrc,
440
- manifestEntries,
441
- pin,
442
- pkgPath : path . dirname ( wsPkgJsonPath ) ,
443
- prod,
444
- rootPath
445
- } )
467
+ const { added, updated } = await addOverrides (
468
+ {
469
+ agent,
470
+ agentExecPath,
471
+ lockSrc,
472
+ manifestEntries,
473
+ pin,
474
+ pkgPath : path . dirname ( wsPkgJsonPath ) ,
475
+ prod,
476
+ rootPath
477
+ } ,
478
+ {
479
+ added : new Set ( ) ,
480
+ spinner,
481
+ updated : new Set ( )
482
+ }
483
+ )
446
484
for ( const regPkgName of added ) {
447
485
state . added . add ( regPkgName )
448
486
}
@@ -451,8 +489,7 @@ async function addOverrides(
451
489
}
452
490
} )
453
491
}
454
- spinner ?. stop ( )
455
- if ( state . added . size || state . updated . size ) {
492
+ if ( state . added . size > 0 || state . updated . size > 0 ) {
456
493
editablePkgJson . update ( < PackageJsonContent > Object . fromEntries ( depEntries ) )
457
494
for ( const { overrides, type } of overridesDataObjects ) {
458
495
updateManifestByAgent [ type ] ( editablePkgJson , toSortedObject ( overrides ) )
@@ -462,6 +499,34 @@ async function addOverrides(
462
499
return state
463
500
}
464
501
502
+ // type ExtractOptions = pacote.Options & {
503
+ // tmpPrefix?: string
504
+ // [key: string]: any
505
+ // }
506
+
507
+ // async function extractPackage(pkgNameOrId: string, options: ExtractOptions | undefined, callback: (tmpDirPath: string) => any) {
508
+ // if (arguments.length === 2 && typeof options === 'function') {
509
+ // callback = options
510
+ // options = undefined
511
+ // }
512
+ // const { tmpPrefix, ...extractOptions } = { __proto__: null, ...options }
513
+ // // cacache.tmp.withTmp DOES return a promise.
514
+ // await cacache.tmp.withTmp(
515
+ // pacoteCachePath,
516
+ // { tmpPrefix },
517
+ // // eslint-disable-next-line @typescript-eslint/no-misused-promises
518
+ // async tmpDirPath => {
519
+ // await pacote.extract(pkgNameOrId, tmpDirPath, {
520
+ // __proto__: null,
521
+ // packumentCache,
522
+ // preferOffline: true,
523
+ // ...<Omit<typeof extractOptions, '__proto__'>>extractOptions
524
+ // })
525
+ // await callback(tmpDirPath)
526
+ // }
527
+ // )
528
+ // }
529
+
465
530
type FetchPackageManifestOptions = {
466
531
signal ?: AbortSignal
467
532
}
@@ -506,6 +571,7 @@ export const optimize: CliSubcommand = {
506
571
const {
507
572
agent,
508
573
agentExecPath,
574
+ agentVersion,
509
575
lockSrc,
510
576
lockPath,
511
577
minimumNodeVersion,
@@ -535,15 +601,24 @@ export const optimize: CliSubcommand = {
535
601
console . log ( `✘ ${ COMMAND_TITLE } : No package.json found` )
536
602
return
537
603
}
604
+ if ( prod && ( agent === 'bun' || agent === 'yarn/berry' ) ) {
605
+ console . log (
606
+ `✘ ${ COMMAND_TITLE } : --prod not supported for ${ agent } ${ agentVersion ? `@${ agentVersion . toString ( ) } ` : '' } `
607
+ )
608
+ return
609
+ }
538
610
if ( lockPath && path . relative ( cwd , lockPath ) . startsWith ( '.' ) ) {
539
611
console . log (
540
612
`⚠️ ${ COMMAND_TITLE } : Package ${ lockName } found at ${ lockPath } `
541
613
)
542
614
}
615
+ const spinner = ora ( 'Socket optimizing...' )
543
616
const state : AddOverridesState = {
544
617
added : new Set ( ) ,
618
+ spinner,
545
619
updated : new Set ( )
546
620
}
621
+ spinner . start ( )
547
622
if ( lockSrc ) {
548
623
const nodeRange = `>=${ minimumNodeVersion } `
549
624
const manifestEntries = manifestNpmOverrides . filter ( ( { 1 : data } ) =>
@@ -580,18 +655,23 @@ export const optimize: CliSubcommand = {
580
655
if ( isNpm || pkgJsonChanged ) {
581
656
// Always update package-lock.json until the npm overrides PR lands:
582
657
// https://github.com/npm/cli/pull/7025
583
- const spinner = ora ( `Updating ${ lockName } ...` ) . start ( )
658
+ spinner . text = `Updating ${ lockName } ...`
584
659
try {
585
660
if ( isNpm ) {
586
661
const wrapperPath = path . join ( distPath , 'npm-cli.js' )
587
- await spawn ( process . execPath , [ wrapperPath , 'install' ] , {
588
- stdio : 'pipe' ,
589
- env : {
590
- ...process . env ,
591
- UPDATE_SOCKET_OVERRIDES_IN_PACKAGE_LOCK_FILE : '1'
662
+ await spawn (
663
+ process . execPath ,
664
+ [ wrapperPath , 'install' , '--no-audit' , '--no-fund' ] ,
665
+ {
666
+ stdio : 'pipe' ,
667
+ env : {
668
+ ...process . env ,
669
+ UPDATE_SOCKET_OVERRIDES_IN_PACKAGE_LOCK_FILE : '1'
670
+ }
592
671
}
593
- } )
672
+ )
594
673
} else {
674
+ // All package managers support the "install" command.
595
675
await spawn ( agentExecPath , [ 'install' ] , { stdio : 'pipe' } )
596
676
}
597
677
spinner . stop ( )
0 commit comments