@@ -7,11 +7,15 @@ const {
7
7
ObjectCreate,
8
8
ObjectEntries,
9
9
ObjectFreeze,
10
+ ObjectKeys,
10
11
ObjectSetPrototypeOf,
11
12
RegExpPrototypeTest,
12
13
SafeMap,
13
14
uncurryThis,
14
15
} = primordials ;
16
+ const {
17
+ compositeKey
18
+ } = require ( 'internal/util/compositekey' ) ;
15
19
const {
16
20
canBeRequiredByUsers
17
21
} = require ( 'internal/bootstrap/loaders' ) . NativeModule ;
@@ -70,13 +74,21 @@ class Manifest {
70
74
*/
71
75
#integrities = new SafeMap ( ) ;
72
76
/**
73
- * @type {Map<string, (specifier: string) => true | URL> }
77
+ * @type {
78
+ Map<
79
+ string,
80
+ (specifier: string, conditions: Set<string>) => true | null | URL
81
+ >
82
+ }
74
83
*
75
84
* Used to find where a dependency is located.
76
85
*
77
86
* This stores functions to lazily calculate locations as needed.
78
87
* `true` is used to signify that the location is not specified
79
88
* by the manifest and default resolution should be allowed.
89
+ *
90
+ * The functions return `null` to signify that a dependency is
91
+ * not found
80
92
*/
81
93
#dependencies = new SafeMap ( ) ;
82
94
/**
@@ -158,36 +170,83 @@ class Manifest {
158
170
dependencyMap = ObjectCreate ( null ) ;
159
171
}
160
172
if ( typeof dependencyMap === 'object' && ! ArrayIsArray ( dependencyMap ) ) {
173
+ function searchDependencies ( target , conditions ) {
174
+ if (
175
+ target &&
176
+ typeof target === 'object' &&
177
+ ! ArrayIsArray ( target )
178
+ ) {
179
+ const keys = ObjectKeys ( target ) ;
180
+ for ( let i = 0 ; i < keys . length ; i ++ ) {
181
+ const key = keys [ i ] ;
182
+ if ( conditions . has ( key ) ) {
183
+ const ret = searchDependencies ( target [ key ] , conditions ) ;
184
+ if ( ret != null ) {
185
+ return ret ;
186
+ }
187
+ }
188
+ }
189
+ } else if ( typeof target === 'string' ) {
190
+ return target ;
191
+ } else if ( target === true ) {
192
+ return target ;
193
+ } else {
194
+ throw new ERR_MANIFEST_INVALID_RESOURCE_FIELD (
195
+ resourceHREF ,
196
+ 'dependencies' ) ;
197
+ }
198
+ return null ;
199
+ }
200
+ // This is used so we don't traverse this every time
201
+ // in theory we can delete parts of the dep map once this is populated
202
+ const localMappings = new SafeMap ( ) ;
161
203
/**
162
- * @returns {true | URL }
204
+ * @returns {true | null | URL }
163
205
*/
164
- const dependencyRedirectList = ( toSpecifier ) => {
165
- if ( toSpecifier in dependencyMap !== true ) {
206
+ const dependencyRedirectList = ( specifier , conditions ) => {
207
+ const key = compositeKey ( [ localMappings , specifier , ...conditions ] ) ;
208
+ if ( localMappings . has ( key ) ) {
209
+ return localMappings . get ( key ) ;
210
+ }
211
+ if ( specifier in dependencyMap !== true ) {
212
+ localMappings . set ( key , null ) ;
166
213
return null ;
167
214
}
168
- const to = dependencyMap [ toSpecifier ] ;
169
- if ( to === true ) {
215
+ const target = searchDependencies (
216
+ dependencyMap [ specifier ] ,
217
+ conditions ) ;
218
+ if ( target === true ) {
219
+ localMappings . set ( key , true ) ;
170
220
return true ;
171
221
}
172
- if ( parsedURLs . has ( to ) ) {
173
- return parsedURLs . get ( to ) ;
174
- } else if ( canBeRequiredByUsers ( to ) ) {
175
- const href = `node:${ to } ` ;
222
+ if ( typeof target !== 'string' ) {
223
+ localMappings . set ( key , null ) ;
224
+ return null ;
225
+ }
226
+ if ( parsedURLs . has ( target ) ) {
227
+ const parsed = parsedURLs . get ( target ) ;
228
+ localMappings . set ( key , parsed ) ;
229
+ return parsed ;
230
+ } else if ( canBeRequiredByUsers ( target ) ) {
231
+ const href = `node:${ target } ` ;
176
232
const resolvedURL = new URL ( href ) ;
177
- parsedURLs . set ( to , resolvedURL ) ;
233
+ parsedURLs . set ( target , resolvedURL ) ;
178
234
parsedURLs . set ( href , resolvedURL ) ;
235
+ localMappings . set ( key , resolvedURL ) ;
179
236
return resolvedURL ;
180
- } else if ( RegExpPrototypeTest ( kRelativeURLStringPattern , to ) ) {
181
- const resolvedURL = new URL ( to , manifestURL ) ;
237
+ } else if ( RegExpPrototypeTest ( kRelativeURLStringPattern , target ) ) {
238
+ const resolvedURL = new URL ( target , manifestURL ) ;
182
239
const href = resourceURL . href ;
183
- parsedURLs . set ( to , resolvedURL ) ;
240
+ parsedURLs . set ( target , resolvedURL ) ;
184
241
parsedURLs . set ( href , resolvedURL ) ;
242
+ localMappings . set ( key , resolvedURL ) ;
185
243
return resolvedURL ;
186
244
}
187
- const resolvedURL = new URL ( to ) ;
188
- const href = resourceURL . href ;
189
- parsedURLs . set ( to , resolvedURL ) ;
245
+ const resolvedURL = new URL ( target ) ;
246
+ const href = resolvedURL . href ;
247
+ parsedURLs . set ( target , resolvedURL ) ;
190
248
parsedURLs . set ( href , resolvedURL ) ;
249
+ localMappings . set ( key , resolvedURL ) ;
191
250
return resolvedURL ;
192
251
} ;
193
252
dependencies . set ( resourceHREF , dependencyRedirectList ) ;
@@ -208,7 +267,10 @@ class Manifest {
208
267
const dependencies = this . #dependencies;
209
268
if ( dependencies . has ( requester ) ) {
210
269
return {
211
- resolve : ( to ) => dependencies . get ( requester ) ( `${ to } ` ) ,
270
+ resolve : ( specifier , conditions ) => dependencies . get ( requester ) (
271
+ `${ specifier } ` ,
272
+ conditions
273
+ ) ,
212
274
reaction : this . #reaction
213
275
} ;
214
276
}
0 commit comments