@@ -169,7 +169,6 @@ const updateManifestByAgent: Record<Agent, AgentModifyManifestFn> = (() => {
169
169
170
170
type AgentListDepsOptions = {
171
171
npmExecPath ?: string
172
- rootPath ?: string
173
172
}
174
173
type AgentListDepsFn = (
175
174
agentExecPath : string ,
@@ -178,32 +177,39 @@ type AgentListDepsFn = (
178
177
) => Promise < string >
179
178
180
179
const lsByAgent = ( ( ) => {
181
- function cleanupParseable (
182
- stdout : string ,
183
- cwd : string ,
184
- rootPath ?: string
185
- ) : string {
186
- stdout = stdout . trim ( )
187
- stdout = stdout . replaceAll ( cwd , '' )
188
- if ( rootPath && rootPath !== cwd ) {
189
- stdout = stdout . replaceAll ( rootPath , '' )
180
+ function cleanupQueryStdout ( stdout : string ) : string {
181
+ if ( stdout === '' ) {
182
+ return ''
183
+ }
184
+ let pkgs
185
+ try {
186
+ pkgs = JSON . stringify ( stdout )
187
+ } catch { }
188
+ if ( ! Array . isArray ( pkgs ) ) {
189
+ return ''
190
+ }
191
+ const names = new Set < string > ( )
192
+ for ( const { name, pkgid = '' } of pkgs ) {
193
+ // `npm query` results may not have a "name" property, in which case we
194
+ // fallback to "pkgid".
195
+ // `vlt ls --view json` results always have a "name" property.
196
+ const resolvedName = name ?? pkgid . slice ( 0 , pkgid . indexOf ( '@' , 1 ) )
197
+ if ( resolvedName ) {
198
+ names . add ( resolvedName )
199
+ }
190
200
}
191
- return stdout . replaceAll ( '\\' , '/' )
201
+ return JSON . stringify ( [ ... names ] , null , 2 )
192
202
}
193
203
194
- async function npmLs ( npmExecPath : string , cwd : string , rootPath ?: string ) {
195
- return cleanupParseable (
196
- (
197
- await spawn (
198
- npmExecPath ,
199
- [ 'ls' , '--parseable' , '--omit' , 'dev' , '--all' ] ,
200
- { cwd }
201
- )
202
- ) . stdout ,
203
- cwd ,
204
- rootPath
205
- )
204
+ async function npmQuery ( npmExecPath : string , cwd : string ) : Promise < string > {
205
+ let stdout = ''
206
+ try {
207
+ stdout = ( await spawn ( npmExecPath , [ 'query' , ':not(.dev)' ] , { cwd } ) )
208
+ . stdout
209
+ } catch { }
210
+ return cleanupQueryStdout ( stdout )
206
211
}
212
+
207
213
return < Record < Agent , AgentListDepsFn > > {
208
214
async bun ( agentExecPath : string , cwd : string ) {
209
215
try {
@@ -214,61 +220,48 @@ const lsByAgent = (() => {
214
220
} catch { }
215
221
return ''
216
222
} ,
217
- async npm (
218
- agentExecPath : string ,
219
- cwd : string ,
220
- options : AgentListDepsOptions
221
- ) {
222
- const { rootPath } = < AgentListDepsOptions > { __proto__ : null , ...options }
223
- try {
224
- return await npmLs ( agentExecPath , cwd , rootPath )
225
- } catch { }
226
- return ''
223
+ async npm ( agentExecPath : string , cwd : string ) {
224
+ return await npmQuery ( agentExecPath , cwd )
227
225
} ,
228
226
async pnpm (
229
227
agentExecPath : string ,
230
228
cwd : string ,
231
229
options : AgentListDepsOptions
232
230
) {
233
- const { npmExecPath, rootPath } = < AgentListDepsOptions > {
231
+ const { npmExecPath } = < AgentListDepsOptions > {
234
232
__proto__ : null ,
235
233
...options
236
234
}
237
- let stdout = ''
238
235
if ( npmExecPath && npmExecPath !== 'npm' ) {
239
- try {
240
- stdout = await npmLs ( npmExecPath , cwd , rootPath )
241
- } catch ( e : any ) {
242
- if ( e ?. stderr ?. includes ( 'code ELSPROBLEMS' ) ) {
243
- stdout = e ?. stdout
244
- }
236
+ const result = await npmQuery ( npmExecPath , cwd )
237
+ if ( result ) {
238
+ return result
245
239
}
246
- } else {
247
- try {
248
- stdout = cleanupParseable (
249
- (
250
- await spawn (
251
- agentExecPath ,
252
- [ 'ls' , '--parseable' , '--prod' , '--depth' , 'Infinity' ] ,
253
- { cwd }
254
- )
255
- ) . stdout ,
256
- cwd ,
257
- rootPath
258
- )
259
- } catch { }
260
240
}
261
- return stdout
241
+ try {
242
+ const { stdout } = await spawn (
243
+ agentExecPath ,
244
+ [ 'ls' , '--parseable' , '--prod' , '--depth' , 'Infinity' ] ,
245
+ { cwd }
246
+ )
247
+ // Convert the parseable stdout into a json array of unique names.
248
+ // The matchAll regexp looks for forward or backward slash followed by
249
+ // one or more non-slashes until the newline.
250
+ const names = new Set ( stdout . matchAll ( / (?< = [ / \\ ] ) [ ^ / \\ ] + (? = \n ) / g) )
251
+ return JSON . stringify ( [ ...names ] , null , 2 )
252
+ } catch { }
253
+ return ''
262
254
} ,
263
255
async vlt ( agentExecPath : string , cwd : string ) {
256
+ let stdout = ''
264
257
try {
265
- return (
266
- await spawn ( agentExecPath ! , [ 'ls' , '--view' , 'human' , ':not(.dev)' ] , {
258
+ stdout = (
259
+ await spawn ( agentExecPath , [ 'ls' , '--view' , 'human' , ':not(.dev)' ] , {
267
260
cwd
268
261
} )
269
262
) . stdout
270
263
} catch { }
271
- return ''
264
+ return cleanupQueryStdout ( stdout )
272
265
} ,
273
266
async 'yarn/berry' ( agentExecPath : string , cwd : string ) {
274
267
try {
@@ -303,8 +296,8 @@ type AgentDepsIncludesFn = (stdout: string, name: string) => boolean
303
296
304
297
const depsIncludesByAgent : Record < Agent , AgentDepsIncludesFn > = {
305
298
bun : ( stdout : string , name : string ) => stdout . includes ( ` ${ name } @` ) ,
306
- npm : ( stdout : string , name : string ) => stdout . includes ( `/ ${ name } \n ` ) ,
307
- pnpm : ( stdout : string , name : string ) => stdout . includes ( `/ ${ name } \n ` ) ,
299
+ npm : ( stdout : string , name : string ) => stdout . includes ( `" ${ name } " ` ) ,
300
+ pnpm : ( stdout : string , name : string ) => stdout . includes ( `" ${ name } " ` ) ,
308
301
vlt : ( stdout : string , name : string ) => stdout . includes ( ` ${ name } @` ) ,
309
302
'yarn/berry' : ( stdout : string , name : string ) => stdout . includes ( ` ${ name } @` ) ,
310
303
'yarn/classic' : ( stdout : string , name : string ) => stdout . includes ( ` ${ name } @` )
@@ -453,7 +446,7 @@ async function addOverrides(
453
446
}
454
447
const thingToScan = isLockScanned
455
448
? lockSrc
456
- : await lsByAgent [ agent ] ( agentExecPath , pkgPath , { npmExecPath, rootPath } )
449
+ : await lsByAgent [ agent ] ( agentExecPath , pkgPath , { npmExecPath } )
457
450
const thingScanner = isLockScanned
458
451
? lockIncludesByAgent [ agent ]
459
452
: depsIncludesByAgent [ agent ]
0 commit comments