1
1
import * as path from 'path' ;
2
2
import * as fs from 'fs' ;
3
3
import * as cp from 'child_process' ;
4
- import findWorkspaceRoot from 'find-yarn-workspace-root' ;
5
- import { Manifest } from './manifest' ;
6
- import { readNodeManifest } from './package' ;
7
- import { CancellationToken , log } from './util' ;
4
+ import parseSemver from 'parse-semver' ;
5
+ import { CancellationToken , log , nonnull } from './util' ;
8
6
9
7
const exists = ( file : string ) =>
10
8
fs . promises . stat ( file ) . then (
@@ -64,67 +62,51 @@ async function checkNPM(cancellationToken?: CancellationToken): Promise<void> {
64
62
}
65
63
}
66
64
67
- function getNpmDependencies ( cwd : string ) : Promise < SourceAndDestination [ ] > {
65
+ function getNpmDependencies ( cwd : string ) : Promise < string [ ] > {
68
66
return checkNPM ( )
69
67
. then ( ( ) =>
70
68
exec ( 'npm list --production --parseable --depth=99999 --loglevel=error' , { cwd, maxBuffer : 5000 * 1024 } )
71
69
)
72
- . then ( ( { stdout } ) => stdout . split ( / [ \r \n ] / ) . filter ( dir => path . isAbsolute ( dir ) )
73
- . map ( dir => {
74
- return {
75
- src : dir ,
76
- dest : path . relative ( cwd , dir )
77
- }
78
- } ) ) ;
70
+ . then ( ( { stdout } ) => stdout . split ( / [ \r \n ] / ) . filter ( dir => path . isAbsolute ( dir ) ) ) ;
71
+ }
72
+
73
+ interface YarnTreeNode {
74
+ name : string ;
75
+ children : YarnTreeNode [ ] ;
79
76
}
80
77
81
78
export interface YarnDependency {
82
79
name : string ;
83
- path : SourceAndDestination ;
80
+ path : string ;
84
81
children : YarnDependency [ ] ;
85
82
}
86
83
87
- export interface SourceAndDestination {
88
- src : string ;
89
- dest : string ;
90
- }
84
+ function asYarnDependency ( prefix : string , tree : YarnTreeNode , prune : boolean ) : YarnDependency | null {
85
+ if ( prune && / @ [ \^ ~ ] / . test ( tree . name ) ) {
86
+ return null ;
87
+ }
91
88
92
- async function asYarnDependencies ( root : string , rootDependencies : string [ ] ) : Promise < YarnDependency [ ] > {
93
- const resolve = async ( prefix : string , dependencies : string [ ] , collected : Map < string , YarnDependency > = new Map ( ) ) : Promise < YarnDependency [ ] > => await Promise . all ( dependencies
94
- . map ( async ( name : string ) => {
95
- let newPrefix = prefix , depPath = null , depManifest = null ;
96
- while ( ! depManifest && root . length <= newPrefix . length ) {
97
- depPath = path . join ( newPrefix , 'node_modules' , name ) ;
98
- try {
99
- depManifest = await readNodeManifest ( depPath ) ;
100
- } catch ( err ) {
101
- newPrefix = path . join ( newPrefix , '..' ) ;
102
- if ( newPrefix . length < root . length ) {
103
- throw err ;
104
- }
105
- }
106
- }
89
+ let name : string ;
107
90
108
- if ( ! depPath || ! depManifest ) {
109
- throw new Error ( `Error finding dependencies` ) ;
110
- }
91
+ try {
92
+ const parseResult = parseSemver ( tree . name ) ;
93
+ name = parseResult . name ;
94
+ } catch ( err ) {
95
+ name = tree . name . replace ( / ^ ( [ ^ @ + ] ) @ .* $ / , '$1' ) ;
96
+ }
111
97
112
- const result : YarnDependency = {
113
- name,
114
- path : {
115
- src : depPath ,
116
- dest : path . relative ( root , depPath ) ,
117
- } ,
118
- children : [ ] ,
119
- } ;
120
- const shouldResolveChildren = ! collected . has ( depPath ) ;
121
- collected . set ( depPath , result ) ;
122
- if ( shouldResolveChildren ) {
123
- result . children = await resolve ( depPath , Object . keys ( depManifest . dependencies || { } ) , collected ) ;
124
- }
125
- return result ;
126
- } ) ) ;
127
- return resolve ( root , rootDependencies ) ;
98
+ const dependencyPath = path . join ( prefix , name ) ;
99
+ const children : YarnDependency [ ] = [ ] ;
100
+
101
+ for ( const child of tree . children || [ ] ) {
102
+ const dep = asYarnDependency ( path . join ( prefix , name , 'node_modules' ) , child , prune ) ;
103
+
104
+ if ( dep ) {
105
+ children . push ( dep ) ;
106
+ }
107
+ }
108
+
109
+ return { name, path : dependencyPath , children } ;
128
110
}
129
111
130
112
function selectYarnDependencies ( deps : YarnDependency [ ] , packagedDependencies : string [ ] ) : YarnDependency [ ] {
@@ -172,10 +154,26 @@ function selectYarnDependencies(deps: YarnDependency[], packagedDependencies: st
172
154
return reached . values ;
173
155
}
174
156
175
- async function getYarnProductionDependencies ( root : string , manifest : Manifest , packagedDependencies ?: string [ ] ) : Promise < YarnDependency [ ] > {
157
+ async function getYarnProductionDependencies ( cwd : string , packagedDependencies ?: string [ ] ) : Promise < YarnDependency [ ] > {
158
+ const raw = await new Promise < string > ( ( c , e ) =>
159
+ cp . exec (
160
+ 'yarn list --prod --json' ,
161
+ { cwd, encoding : 'utf8' , env : { ...process . env } , maxBuffer : 5000 * 1024 } ,
162
+ ( err , stdout ) => ( err ? e ( err ) : c ( stdout ) )
163
+ )
164
+ ) ;
165
+ const match = / ^ { " t y p e " : " t r e e " .* $ / m. exec ( raw ) ;
166
+
167
+ if ( ! match || match . length !== 1 ) {
168
+ throw new Error ( 'Could not parse result of `yarn list --json`' ) ;
169
+ }
170
+
176
171
const usingPackagedDependencies = Array . isArray ( packagedDependencies ) ;
172
+ const trees = JSON . parse ( match [ 0 ] ) . data . trees as YarnTreeNode [ ] ;
177
173
178
- let result = await asYarnDependencies ( root , Object . keys ( manifest . dependencies || { } ) ) ;
174
+ let result = trees
175
+ . map ( tree => asYarnDependency ( path . join ( cwd , 'node_modules' ) , tree , ! usingPackagedDependencies ) )
176
+ . filter ( nonnull ) ;
179
177
180
178
if ( usingPackagedDependencies ) {
181
179
result = selectYarnDependencies ( result , packagedDependencies ! ) ;
@@ -184,35 +182,22 @@ async function getYarnProductionDependencies(root: string, manifest: Manifest, p
184
182
return result ;
185
183
}
186
184
187
- async function getYarnDependencies ( cwd : string , root : string , manifest : Manifest , packagedDependencies ?: string [ ] ) : Promise < SourceAndDestination [ ] > {
188
- const result : SourceAndDestination [ ] = [ {
189
- src : cwd ,
190
- dest : ''
191
- } ] ;
192
-
193
- if ( await exists ( path . join ( root , 'yarn.lock' ) ) ) {
194
- const deps = await getYarnProductionDependencies ( root , manifest , packagedDependencies ) ;
195
- const flatten = ( dep : YarnDependency ) => {
196
- result . push ( dep . path ) ;
197
- dep . children . forEach ( flatten ) ;
198
- } ;
199
- deps . forEach ( flatten ) ;
200
- }
201
-
202
- const dedup = new Map ( ) ;
185
+ async function getYarnDependencies ( cwd : string , packagedDependencies ?: string [ ] ) : Promise < string [ ] > {
186
+ const result = new Set ( [ cwd ] ) ;
203
187
204
- for ( const item of result ) {
205
- if ( ! dedup . has ( item . src ) ) {
206
- dedup . set ( item . src , item ) ;
207
- }
208
- }
188
+ const deps = await getYarnProductionDependencies ( cwd , packagedDependencies ) ;
189
+ const flatten = ( dep : YarnDependency ) => {
190
+ result . add ( dep . path ) ;
191
+ dep . children . forEach ( flatten ) ;
192
+ } ;
193
+ deps . forEach ( flatten ) ;
209
194
210
- return [ ...dedup . values ( ) ] ;
195
+ return [ ...result ] ;
211
196
}
212
197
213
- export async function detectYarn ( root : string ) {
198
+ export async function detectYarn ( cwd : string ) : Promise < boolean > {
214
199
for ( const name of [ 'yarn.lock' , '.yarnrc' , '.yarnrc.yaml' , '.pnp.cjs' , '.yarn' ] ) {
215
- if ( await exists ( path . join ( root , name ) ) ) {
200
+ if ( await exists ( path . join ( cwd , name ) ) ) {
216
201
if ( ! process . env [ 'VSCE_TESTS' ] ) {
217
202
log . info (
218
203
`Detected presence of ${ name } . Using 'yarn' instead of 'npm' (to override this pass '--no-yarn' on the command line).`
@@ -226,16 +211,13 @@ export async function detectYarn(root: string) {
226
211
227
212
export async function getDependencies (
228
213
cwd : string ,
229
- manifest : Manifest ,
230
214
dependencies : 'npm' | 'yarn' | 'none' | undefined ,
231
215
packagedDependencies ?: string [ ]
232
- ) : Promise < SourceAndDestination [ ] > {
233
- const root = findWorkspaceRoot ( cwd ) || cwd ;
234
-
216
+ ) : Promise < string [ ] > {
235
217
if ( dependencies === 'none' ) {
236
- return [ { src : root , dest : '' } ] ;
237
- } else if ( dependencies === 'yarn' || ( dependencies === undefined && ( await detectYarn ( root ) ) ) ) {
238
- return await getYarnDependencies ( cwd , root , manifest , packagedDependencies ) ;
218
+ return [ cwd ] ;
219
+ } else if ( dependencies === 'yarn' || ( dependencies === undefined && ( await detectYarn ( cwd ) ) ) ) {
220
+ return await getYarnDependencies ( cwd , packagedDependencies ) ;
239
221
} else {
240
222
return await getNpmDependencies ( cwd ) ;
241
223
}
0 commit comments