metro 0.70.3 → 0.71.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/package.json +23 -22
  2. package/src/Assets.js.flow +4 -4
  3. package/src/Bundler/util.js +1 -1
  4. package/src/Bundler/util.js.flow +2 -2
  5. package/src/Bundler.js +15 -10
  6. package/src/Bundler.js.flow +19 -14
  7. package/src/DeltaBundler/DeltaCalculator.js +13 -17
  8. package/src/DeltaBundler/DeltaCalculator.js.flow +15 -20
  9. package/src/DeltaBundler/Serializers/getAllFiles.js.flow +2 -2
  10. package/src/DeltaBundler/Serializers/getAssets.js.flow +2 -2
  11. package/src/DeltaBundler/Serializers/getExplodedSourceMap.js.flow +4 -4
  12. package/src/DeltaBundler/Serializers/getRamBundleInfo.js.flow +6 -6
  13. package/src/DeltaBundler/Serializers/helpers/getSourceMapInfo.js.flow +4 -4
  14. package/src/DeltaBundler/Serializers/helpers/processBytecodeModules.js.flow +2 -2
  15. package/src/DeltaBundler/Serializers/helpers/processModules.js.flow +2 -2
  16. package/src/DeltaBundler/Serializers/hmrJSBundle.js.flow +2 -2
  17. package/src/DeltaBundler/Serializers/sourceMapGenerator.js.flow +6 -6
  18. package/src/DeltaBundler/Serializers/sourceMapObject.js.flow +4 -4
  19. package/src/DeltaBundler/Serializers/sourceMapString.js.flow +2 -2
  20. package/src/DeltaBundler/Worker.flow.js +78 -0
  21. package/src/DeltaBundler/Worker.flow.js.flow +121 -0
  22. package/src/DeltaBundler/Worker.js +8 -66
  23. package/src/DeltaBundler/Worker.js.flow +8 -107
  24. package/src/DeltaBundler/WorkerFarm.js.flow +4 -4
  25. package/src/DeltaBundler/__fixtures__/hasteImpl.js +4 -0
  26. package/src/DeltaBundler/getTransformCacheKey.js.flow +2 -2
  27. package/src/DeltaBundler/graphOperations.js +641 -0
  28. package/src/DeltaBundler/graphOperations.js.flow +752 -0
  29. package/src/DeltaBundler/types.flow.js +6 -0
  30. package/src/DeltaBundler/types.flow.js.flow +43 -31
  31. package/src/DeltaBundler.js +12 -6
  32. package/src/DeltaBundler.js.flow +14 -10
  33. package/src/HmrServer.js +0 -2
  34. package/src/HmrServer.js.flow +7 -8
  35. package/src/IncrementalBundler.js +1 -1
  36. package/src/IncrementalBundler.js.flow +8 -8
  37. package/src/ModuleGraph/node-haste/ModuleCache.js +1 -1
  38. package/src/ModuleGraph/node-haste/ModuleCache.js.flow +1 -1
  39. package/src/ModuleGraph/node-haste/node-haste.flow.js +0 -1
  40. package/src/ModuleGraph/node-haste/node-haste.flow.js.flow +3 -4
  41. package/src/ModuleGraph/node-haste/node-haste.js +4 -4
  42. package/src/ModuleGraph/node-haste/node-haste.js.flow +13 -7
  43. package/src/ModuleGraph/output/indexed-ram-bundle.js.flow +2 -2
  44. package/src/ModuleGraph/output/plain-bundle.js.flow +2 -2
  45. package/src/ModuleGraph/output/reverse-dependency-map-references.js.flow +8 -8
  46. package/src/ModuleGraph/output/util.js.flow +2 -2
  47. package/src/ModuleGraph/types.flow.js.flow +37 -37
  48. package/src/ModuleGraph/worker/collectDependencies.js +215 -8
  49. package/src/ModuleGraph/worker/collectDependencies.js.flow +230 -13
  50. package/src/Server/symbolicate.js.flow +1 -1
  51. package/src/Server.js.flow +18 -18
  52. package/src/cli.js +5 -0
  53. package/src/cli.js.flow +5 -0
  54. package/src/commands/build.js +4 -3
  55. package/src/commands/build.js.flow +5 -3
  56. package/src/commands/serve.js +3 -3
  57. package/src/commands/serve.js.flow +5 -3
  58. package/src/index.flow.js +392 -0
  59. package/src/index.flow.js.flow +480 -0
  60. package/src/index.js +8 -366
  61. package/src/index.js.flow +8 -456
  62. package/src/lib/CountingSet.js +116 -0
  63. package/src/lib/CountingSet.js.flow +126 -0
  64. package/src/lib/JsonReporter.js +0 -2
  65. package/src/lib/JsonReporter.js.flow +1 -1
  66. package/src/lib/bundleToBytecode.js.flow +2 -2
  67. package/src/lib/bundleToString.js.flow +2 -2
  68. package/src/lib/getAppendScripts.js +10 -4
  69. package/src/lib/getAppendScripts.js.flow +6 -4
  70. package/src/lib/getPreludeCode.js +19 -1
  71. package/src/lib/getPreludeCode.js.flow +17 -2
  72. package/src/lib/getPrependedScripts.js +10 -2
  73. package/src/lib/getPrependedScripts.js.flow +11 -2
  74. package/src/lib/reporting.js +0 -2
  75. package/src/lib/reporting.js.flow +2 -1
  76. package/src/lib/transformHelpers.js.flow +2 -2
  77. package/src/node-haste/DependencyGraph/ModuleResolution.js +17 -4
  78. package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +20 -12
  79. package/src/node-haste/DependencyGraph/createHasteMap.js +80 -19
  80. package/src/node-haste/DependencyGraph/createHasteMap.js.flow +16 -14
  81. package/src/node-haste/DependencyGraph.js +31 -29
  82. package/src/node-haste/DependencyGraph.js.flow +44 -38
  83. package/src/node-haste/ModuleCache.js.flow +1 -1
  84. package/src/node-haste/lib/AssetPaths.js.flow +2 -2
  85. package/src/node-haste/lib/parsePlatformFilePath.js.flow +2 -2
  86. package/src/shared/output/RamBundle/as-indexed-file.js.flow +1 -1
  87. package/src/shared/output/RamBundle/buildSourcemapWithMetadata.js.flow +2 -2
  88. package/src/shared/types.flow.js.flow +14 -14
  89. package/src/DeltaBundler/computeDelta.js +0 -42
  90. package/src/DeltaBundler/computeDelta.js.flow +0 -47
  91. package/src/DeltaBundler/traverseDependencies.js +0 -470
  92. package/src/DeltaBundler/traverseDependencies.js.flow +0 -565
  93. package/src/node-haste/DependencyGraph/types.js +0 -10
  94. package/src/node-haste/DependencyGraph/types.js.flow +0 -88
@@ -22,19 +22,19 @@ export type BuildResult = GraphResult;
22
22
  export type Callback<A = void, B = void> = (Error => void) &
23
23
  ((null | void, A, B) => void);
24
24
 
25
- export type Dependency = {|
25
+ export type Dependency = {
26
26
  // The module name or path used to require the dependency
27
27
  id: string,
28
28
  +isAsync: boolean,
29
29
  +isPrefetchOnly: boolean,
30
- +splitCondition: ?{|
30
+ +splitCondition: ?{
31
31
  +mobileConfigName: string,
32
- |},
32
+ },
33
33
  path: string,
34
34
  +locs: $ReadOnlyArray<BabelSourceLocation>,
35
- |};
35
+ };
36
36
 
37
- export type File = {|
37
+ export type File = {
38
38
  code: string,
39
39
  map: ?BasicSourceMap,
40
40
  functionMap: ?FBSourceFunctionMap,
@@ -42,7 +42,7 @@ export type File = {|
42
42
  type: CodeFileTypes,
43
43
  libraryIdx: ?number,
44
44
  soundResources?: ?Array<string>,
45
- |};
45
+ };
46
46
 
47
47
  type CodeFileTypes = 'module' | 'script';
48
48
 
@@ -51,11 +51,11 @@ export type GraphFn = (
51
51
  // platform: string,
52
52
  ) => GraphResult;
53
53
 
54
- export type GraphResult = {|
54
+ export type GraphResult = {
55
55
  modules: Array<Module>,
56
- |};
56
+ };
57
57
 
58
- export type ModuleIds = {|
58
+ export type ModuleIds = {
59
59
  /**
60
60
  * The module ID is global across all segments and identifies the module
61
61
  * uniquely. This is useful to cache modules that has been loaded already at
@@ -71,7 +71,7 @@ export type ModuleIds = {|
71
71
  * case this property does not apply and will be omitted.
72
72
  */
73
73
  +localId?: number,
74
- |};
74
+ };
75
75
 
76
76
  /**
77
77
  * Indempotent function that gets us the IDs corresponding to a particular
@@ -87,17 +87,17 @@ export type LoadResult = {
87
87
 
88
88
  export type LoadFn = (file: string) => LoadResult;
89
89
 
90
- export type Module = {|
90
+ export type Module = {
91
91
  dependencies: Array<Dependency>,
92
92
  file: File,
93
- |};
93
+ };
94
94
 
95
95
  export type PostProcessModules = (
96
96
  modules: $ReadOnlyArray<Module>,
97
97
  entryPoints: Array<string>,
98
98
  ) => $ReadOnlyArray<Module>;
99
99
 
100
- export type OutputFnArg = {|
100
+ export type OutputFnArg = {
101
101
  dependencyMapReservedName?: ?string,
102
102
  filename: string,
103
103
  globalPrefix: string,
@@ -107,22 +107,22 @@ export type OutputFnArg = {|
107
107
  sourceMapPath?: ?string,
108
108
  enableIDInlining: boolean,
109
109
  segmentID: number,
110
- |};
110
+ };
111
111
  export type OutputFn<M: MixedSourceMap = MixedSourceMap> =
112
112
  OutputFnArg => OutputResult<M>;
113
113
 
114
- export type OutputResult<M: MixedSourceMap> = {|
114
+ export type OutputResult<M: MixedSourceMap> = {
115
115
  code: string | Buffer,
116
116
  extraFiles?: Iterable<[string, string | Buffer]>,
117
117
  map: M,
118
- |};
118
+ };
119
119
 
120
- export type PackageData = {|
120
+ export type PackageData = {
121
121
  browser?: Object | string,
122
122
  main?: string,
123
123
  name?: string,
124
124
  'react-native'?: Object | string,
125
- |};
125
+ };
126
126
 
127
127
  export type ResolveFn = (id: string, source: ?string) => string;
128
128
 
@@ -159,16 +159,16 @@ export type TransformResults = {
159
159
 
160
160
  export type TransformVariants = {+[name: string]: {...}};
161
161
 
162
- export type TransformedCodeFile = {|
162
+ export type TransformedCodeFile = {
163
163
  +file: string,
164
164
  +functionMap: ?FBSourceFunctionMap,
165
165
  +hasteID: ?string,
166
166
  +package?: PackageData,
167
167
  +transformed: TransformResults,
168
168
  +type: CodeFileTypes,
169
- |};
169
+ };
170
170
 
171
- export type ImageSize = {|+width: number, +height: number|};
171
+ export type ImageSize = {+width: number, +height: number};
172
172
 
173
173
  export type AssetFileVariant = $ReadOnly<{
174
174
  /**
@@ -228,24 +228,24 @@ export type AssetFile = $ReadOnly<{
228
228
  }>;
229
229
 
230
230
  export type TransformedSourceFile =
231
- | {|
231
+ | {
232
232
  +type: 'code',
233
233
  +details: TransformedCodeFile,
234
- |}
235
- | {|
234
+ }
235
+ | {
236
236
  +type: 'asset',
237
237
  +details: AssetFile,
238
- |}
239
- | {|
238
+ }
239
+ | {
240
240
  +type: 'unknown',
241
- |};
241
+ };
242
242
 
243
- export type LibraryOptions = {|
243
+ export type LibraryOptions = {
244
244
  dependencies?: Array<string>,
245
245
  optimize: boolean,
246
246
  platform?: string,
247
247
  rebasePath: string => string,
248
- |};
248
+ };
249
249
 
250
250
  export type Base64Content = string;
251
251
  export type AssetContents = {
@@ -258,7 +258,7 @@ export type AssetContentsByPath = {
258
258
  ...
259
259
  };
260
260
 
261
- export type ResolvedCodeFile = {|
261
+ export type ResolvedCodeFile = {
262
262
  +codeFile: TransformedCodeFile,
263
263
  /**
264
264
  * Imagine we have a source file that contains a `require('foo')`. The library
@@ -267,35 +267,35 @@ export type ResolvedCodeFile = {|
267
267
  * `{'foo': 'bar/foo.js', 'bar': 'node_modules/bar/index.js'}`.
268
268
  */
269
269
  +filePathsByDependencyName: {[dependencyName: string]: string, ...},
270
- |};
270
+ };
271
271
 
272
- export type LibraryBoundCodeFile = {|
272
+ export type LibraryBoundCodeFile = {
273
273
  ...ResolvedCodeFile,
274
274
  /**
275
275
  * Index of the library that this code file has been exported from.
276
276
  */
277
277
  +libraryIdx: number,
278
- |};
278
+ };
279
279
 
280
280
  /**
281
281
  * Describe a set of JavaScript files and the associated assets. It could be
282
282
  * depending on modules from other libraries. To be able to resolve these
283
283
  * dependencies, these libraries need to be provided by callsites (ex. Buck).
284
284
  */
285
- export type Library = {|
285
+ export type Library = {
286
286
  +files: Array<TransformedCodeFile>,
287
287
  /* cannot be a Map because it's JSONified later on */
288
288
  +assets: AssetContentsByPath,
289
- |};
289
+ };
290
290
 
291
291
  /**
292
292
  * Just like a `Library`, but it also contains module resolutions. For example
293
293
  * if there is a `require('foo')` in some JavaScript file, we keep track of the
294
294
  * path it resolves to, ex. `beep/glo/foo.js`.
295
295
  */
296
- export type ResolvedLibrary = {|
296
+ export type ResolvedLibrary = {
297
297
  +files: $ReadOnlyArray<ResolvedCodeFile>,
298
298
  /* cannot be a Map because it's JSONified later on */
299
299
  +assets: AssetContentsByPath,
300
300
  +isPartiallyResolved?: boolean,
301
- |};
301
+ };
@@ -53,6 +53,7 @@ function collectDependencies(ast, options) {
53
53
  dynamicRequires: options.dynamicRequires,
54
54
  keepRequireNames: options.keepRequireNames,
55
55
  allowOptionalDependencies: options.allowOptionalDependencies,
56
+ unstable_allowRequireContext: options.unstable_allowRequireContext,
56
57
  };
57
58
  const visitor = {
58
59
  CallExpression(path, state) {
@@ -97,6 +98,22 @@ function collectDependencies(ast, options) {
97
98
  splitCondition: args[1],
98
99
  });
99
100
  return;
101
+ } // Match `require.context`
102
+
103
+ if (
104
+ // Feature gate, defaults to `false`.
105
+ state.unstable_allowRequireContext &&
106
+ callee.type === "MemberExpression" && // `require`
107
+ callee.object.type === "Identifier" &&
108
+ callee.object.name === "require" && // `context`
109
+ callee.property.type === "Identifier" &&
110
+ callee.property.name === "context" &&
111
+ !callee.computed && // Ensure `require` refers to the global and not something else.
112
+ !path.scope.getBinding("require")
113
+ ) {
114
+ processRequireContextCall(path, state);
115
+ visited.add(path.node);
116
+ return;
100
117
  }
101
118
 
102
119
  if (
@@ -148,6 +165,146 @@ function collectDependencies(ast, options) {
148
165
  dependencyMapName: nullthrows(state.dependencyMapIdentifier).name,
149
166
  };
150
167
  }
168
+ /** Extract args passed to the `require.context` method. */
169
+
170
+ function getRequireContextArgs(path) {
171
+ const args = path.get("arguments");
172
+ let directory;
173
+
174
+ if (!Array.isArray(args) || args.length < 1) {
175
+ throw new InvalidRequireCallError(path);
176
+ } else {
177
+ const result = args[0].evaluate();
178
+
179
+ if (result.confident && typeof result.value === "string") {
180
+ directory = result.value;
181
+ } else {
182
+ var _result$deopt;
183
+
184
+ throw new InvalidRequireCallError(
185
+ (_result$deopt = result.deopt) !== null && _result$deopt !== void 0
186
+ ? _result$deopt
187
+ : args[0],
188
+ "First argument of `require.context` should be a string denoting the directory to require."
189
+ );
190
+ }
191
+ } // Default to requiring through all directories.
192
+
193
+ let recursive = true;
194
+
195
+ if (args.length > 1) {
196
+ const result = args[1].evaluate();
197
+
198
+ if (result.confident && typeof result.value === "boolean") {
199
+ recursive = result.value;
200
+ } else if (!(result.confident && typeof result.value === "undefined")) {
201
+ var _result$deopt2;
202
+
203
+ throw new InvalidRequireCallError(
204
+ (_result$deopt2 = result.deopt) !== null && _result$deopt2 !== void 0
205
+ ? _result$deopt2
206
+ : args[1],
207
+ "Second argument of `require.context` should be an optional boolean indicating if files should be imported recursively or not."
208
+ );
209
+ }
210
+ } // Default to all files.
211
+
212
+ let filter = {
213
+ pattern: ".*",
214
+ flags: "",
215
+ };
216
+
217
+ if (args.length > 2) {
218
+ // evaluate() to check for undefined (because it's technically a scope lookup)
219
+ // but check the AST for the regex literal, since evaluate() doesn't do regex.
220
+ const result = args[2].evaluate();
221
+ const argNode = args[2].node;
222
+
223
+ if (argNode.type === "RegExpLiteral") {
224
+ // TODO: Handle `new RegExp(...)` -- `argNode.type === 'NewExpression'`
225
+ filter = {
226
+ pattern: argNode.pattern,
227
+ flags: argNode.flags || "",
228
+ };
229
+ } else if (!(result.confident && typeof result.value === "undefined")) {
230
+ throw new InvalidRequireCallError(
231
+ args[2],
232
+ `Third argument of \`require.context\` should be an optional RegExp pattern matching all of the files to import, instead found node of type: ${argNode.type}.`
233
+ );
234
+ }
235
+ } // Default to `sync`.
236
+
237
+ let mode = "sync";
238
+
239
+ if (args.length > 3) {
240
+ const result = args[3].evaluate();
241
+
242
+ if (result.confident && typeof result.value === "string") {
243
+ mode = getContextMode(args[3], result.value);
244
+ } else if (!(result.confident && typeof result.value === "undefined")) {
245
+ var _result$deopt3;
246
+
247
+ throw new InvalidRequireCallError(
248
+ (_result$deopt3 = result.deopt) !== null && _result$deopt3 !== void 0
249
+ ? _result$deopt3
250
+ : args[3],
251
+ 'Fourth argument of `require.context` should be an optional string "mode" denoting how the modules will be resolved.'
252
+ );
253
+ }
254
+ }
255
+
256
+ if (args.length > 4) {
257
+ throw new InvalidRequireCallError(
258
+ path,
259
+ `Too many arguments provided to \`require.context\` call. Expected 4, got: ${args.length}`
260
+ );
261
+ }
262
+
263
+ return [
264
+ directory,
265
+ {
266
+ recursive,
267
+ filter,
268
+ mode,
269
+ },
270
+ ];
271
+ }
272
+
273
+ function getContextMode(path, mode) {
274
+ if (
275
+ mode === "sync" ||
276
+ mode === "eager" ||
277
+ mode === "lazy" ||
278
+ mode === "lazy-once"
279
+ ) {
280
+ return mode;
281
+ }
282
+
283
+ throw new InvalidRequireCallError(
284
+ path,
285
+ `require.context "${mode}" mode is not supported. Expected one of: sync, eager, lazy, lazy-once`
286
+ );
287
+ }
288
+
289
+ function processRequireContextCall(path, state) {
290
+ const [directory, contextParams] = getRequireContextArgs(path);
291
+ const transformer = state.dependencyTransformer;
292
+ const dep = registerDependency(
293
+ state,
294
+ {
295
+ // We basically want to "import" every file in a folder and then filter them out with the given `filter` RegExp.
296
+ name: directory,
297
+ // Capture the matching context
298
+ contextParams,
299
+ asyncType: null,
300
+ optional: isOptionalDependency(directory, path, state),
301
+ },
302
+ path
303
+ ); // require() the generated module representing this context
304
+
305
+ path.get("callee").replaceWith(types.identifier("require"));
306
+ transformer.transformSyncRequire(path, dep, state);
307
+ }
151
308
 
152
309
  function collectImports(path, state) {
153
310
  if (path.node.source) {
@@ -309,10 +466,15 @@ function getModuleNameFromCallArgs(path) {
309
466
  collectDependencies.getModuleNameFromCallArgs = getModuleNameFromCallArgs;
310
467
 
311
468
  class InvalidRequireCallError extends Error {
312
- constructor({ node }) {
469
+ constructor({ node }, message) {
313
470
  const line = node.loc && node.loc.start && node.loc.start.line;
314
471
  super(
315
- `Invalid call at line ${line || "<unknown>"}: ${generate(node).code}`
472
+ [
473
+ `Invalid call at line ${line || "<unknown>"}: ${generate(node).code}`,
474
+ message,
475
+ ]
476
+ .filter(Boolean)
477
+ .join("\n")
316
478
  );
317
479
  }
318
480
  }
@@ -348,9 +510,11 @@ const makeJSResourceTemplate = template.statement(`
348
510
  const DefaultDependencyTransformer = {
349
511
  transformSyncRequire(path, dependency, state) {
350
512
  const moduleIDExpression = createModuleIDExpression(dependency, state);
351
- path.node.arguments = state.keepRequireNames
352
- ? [moduleIDExpression, types.stringLiteral(dependency.name)]
353
- : [moduleIDExpression];
513
+ path.node.arguments = [moduleIDExpression]; // Always add the debug name argument last
514
+
515
+ if (state.keepRequireNames) {
516
+ path.node.arguments.push(types.stringLiteral(dependency.name));
517
+ }
354
518
  },
355
519
 
356
520
  transformImportCall(path, dependency, state) {
@@ -420,12 +584,51 @@ function createModuleIDExpression(dependency, state) {
420
584
  function createModuleNameLiteral(dependency) {
421
585
  return types.stringLiteral(dependency.name);
422
586
  }
587
+ /**
588
+ * Given an import qualifier, return a key used to register the dependency.
589
+ * Generally this return the `ImportQualifier.name` property, but in the case
590
+ * of `require.context` more attributes can be appended to distinguish various combinations that would otherwise conflict.
591
+ *
592
+ * For example, the following case would have collision issues if they all utilized the `name` property:
593
+ * ```
594
+ * require('./foo');
595
+ * require.context('./foo');
596
+ * require.context('./foo', true, /something/);
597
+ * require.context('./foo', false, /something/);
598
+ * require.context('./foo', false, /something/, 'lazy');
599
+ * ```
600
+ *
601
+ * This method should be utilized by `registerDependency`.
602
+ */
603
+
604
+ function getKeyForDependency(qualifier) {
605
+ let key = qualifier.name;
606
+ const { contextParams } = qualifier; // Add extra qualifiers when using `require.context` to prevent collisions.
607
+
608
+ if (contextParams) {
609
+ // NOTE(EvanBacon): Keep this synchronized with `RequireContextParams`, if any other properties are added
610
+ // then this key algorithm should be updated to account for those properties.
611
+ // Example: `./directory__true__/foobar/m__lazy`
612
+ key += [
613
+ "",
614
+ "context",
615
+ String(contextParams.recursive),
616
+ String(contextParams.filter.pattern),
617
+ String(contextParams.filter.flags),
618
+ contextParams.mode, // Join together and append to the name:
619
+ ].join("__");
620
+ }
621
+
622
+ return key;
623
+ }
423
624
 
424
625
  class DefaultModuleDependencyRegistry {
425
626
  _dependencies = new Map();
426
627
 
427
628
  registerDependency(qualifier) {
428
- let dependency = this._dependencies.get(qualifier.name);
629
+ const key = getKeyForDependency(qualifier);
630
+
631
+ let dependency = this._dependencies.get(key);
429
632
 
430
633
  if (dependency == null) {
431
634
  const newDependency = {
@@ -439,15 +642,19 @@ class DefaultModuleDependencyRegistry {
439
642
  newDependency.isOptional = true;
440
643
  }
441
644
 
645
+ if (qualifier.contextParams) {
646
+ newDependency.contextParams = qualifier.contextParams;
647
+ }
648
+
442
649
  dependency = newDependency;
443
650
 
444
- this._dependencies.set(qualifier.name, dependency);
651
+ this._dependencies.set(key, dependency);
445
652
  } else {
446
653
  const original = dependency;
447
654
  dependency = collapseDependencies(original, qualifier);
448
655
 
449
656
  if (original !== dependency) {
450
- this._dependencies.set(qualifier.name, dependency);
657
+ this._dependencies.set(key, dependency);
451
658
  }
452
659
  }
453
660