@@ -7,11 +7,15 @@ const {
77 ObjectCreate,
88 ObjectEntries,
99 ObjectFreeze,
10+ ObjectKeys,
1011 ObjectSetPrototypeOf,
1112 RegExpPrototypeTest,
1213 SafeMap,
1314 uncurryThis,
1415} = primordials ;
16+ const {
17+ compositeKey
18+ } = require ( 'internal/util/compositekey' ) ;
1519const {
1620 canBeRequiredByUsers
1721} = require ( 'internal/bootstrap/loaders' ) . NativeModule ;
@@ -70,13 +74,21 @@ class Manifest {
7074 */
7175 #integrities = new SafeMap ( ) ;
7276 /**
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+ }
7483 *
7584 * Used to find where a dependency is located.
7685 *
7786 * This stores functions to lazily calculate locations as needed.
7887 * `true` is used to signify that the location is not specified
7988 * by the manifest and default resolution should be allowed.
89+ *
90+ * The functions return `null` to signify that a dependency is
91+ * not found
8092 */
8193 #dependencies = new SafeMap ( ) ;
8294 /**
@@ -158,36 +170,83 @@ class Manifest {
158170 dependencyMap = ObjectCreate ( null ) ;
159171 }
160172 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 ( ) ;
161203 /**
162- * @returns {true | URL }
204+ * @returns {true | null | URL }
163205 */
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 ) ;
166213 return null ;
167214 }
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 ) ;
170220 return true ;
171221 }
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 } ` ;
176232 const resolvedURL = new URL ( href ) ;
177- parsedURLs . set ( to , resolvedURL ) ;
233+ parsedURLs . set ( target , resolvedURL ) ;
178234 parsedURLs . set ( href , resolvedURL ) ;
235+ localMappings . set ( key , resolvedURL ) ;
179236 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 ) ;
182239 const href = resourceURL . href ;
183- parsedURLs . set ( to , resolvedURL ) ;
240+ parsedURLs . set ( target , resolvedURL ) ;
184241 parsedURLs . set ( href , resolvedURL ) ;
242+ localMappings . set ( key , resolvedURL ) ;
185243 return resolvedURL ;
186244 }
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 ) ;
190248 parsedURLs . set ( href , resolvedURL ) ;
249+ localMappings . set ( key , resolvedURL ) ;
191250 return resolvedURL ;
192251 } ;
193252 dependencies . set ( resourceHREF , dependencyRedirectList ) ;
@@ -208,7 +267,10 @@ class Manifest {
208267 const dependencies = this . #dependencies;
209268 if ( dependencies . has ( requester ) ) {
210269 return {
211- resolve : ( to ) => dependencies . get ( requester ) ( `${ to } ` ) ,
270+ resolve : ( specifier , conditions ) => dependencies . get ( requester ) (
271+ `${ specifier } ` ,
272+ conditions
273+ ) ,
212274 reaction : this . #reaction
213275 } ;
214276 }
0 commit comments