metro 0.71.2 → 0.72.1

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 (91) hide show
  1. package/package.json +21 -21
  2. package/src/Assets.js +3 -2
  3. package/src/Assets.js.flow +3 -2
  4. package/src/Bundler.js +11 -2
  5. package/src/Bundler.js.flow +7 -1
  6. package/src/DeltaBundler/DeltaCalculator.js +85 -21
  7. package/src/DeltaBundler/DeltaCalculator.js.flow +63 -8
  8. package/src/DeltaBundler/Serializers/hmrJSBundle.js.flow +1 -3
  9. package/src/DeltaBundler/Transformer.js +27 -4
  10. package/src/DeltaBundler/Transformer.js.flow +18 -2
  11. package/src/DeltaBundler/Worker.flow.js +45 -1
  12. package/src/DeltaBundler/Worker.flow.js.flow +42 -1
  13. package/src/DeltaBundler/WorkerFarm.js +3 -2
  14. package/src/DeltaBundler/WorkerFarm.js.flow +5 -3
  15. package/src/DeltaBundler/graphOperations.js +170 -63
  16. package/src/DeltaBundler/graphOperations.js.flow +144 -64
  17. package/src/DeltaBundler/types.flow.js.flow +11 -5
  18. package/src/HmrServer.js +2 -0
  19. package/src/HmrServer.js.flow +2 -0
  20. package/src/IncrementalBundler.js +6 -0
  21. package/src/IncrementalBundler.js.flow +6 -0
  22. package/src/ModuleGraph/node-haste/HasteFS.js.flow +1 -1
  23. package/src/ModuleGraph/node-haste/node-haste.js +14 -7
  24. package/src/ModuleGraph/node-haste/node-haste.js.flow +35 -10
  25. package/src/ModuleGraph/output/indexed-ram-bundle.js.flow +5 -13
  26. package/src/ModuleGraph/output/multiple-files-ram-bundle.js.flow +4 -14
  27. package/src/ModuleGraph/output/util.js +1 -0
  28. package/src/ModuleGraph/output/util.js.flow +4 -3
  29. package/src/ModuleGraph/silent-console.js +5 -4
  30. package/src/ModuleGraph/silent-console.js.flow +8 -4
  31. package/src/ModuleGraph/worker/collectDependencies.js +19 -30
  32. package/src/ModuleGraph/worker/collectDependencies.js.flow +28 -43
  33. package/src/Server.js +8 -0
  34. package/src/Server.js.flow +48 -12
  35. package/src/cli-utils.js.flow +1 -1
  36. package/src/commands/build.js +1 -2
  37. package/src/commands/build.js.flow +6 -9
  38. package/src/commands/dependencies.js +1 -1
  39. package/src/commands/serve.js +2 -1
  40. package/src/commands/serve.js.flow +7 -8
  41. package/src/index.flow.js +11 -8
  42. package/src/index.flow.js.flow +10 -7
  43. package/src/integration_tests/basic_bundle/require-context/conflict.js +25 -0
  44. package/src/integration_tests/basic_bundle/require-context/conflict.js.flow +27 -0
  45. package/src/integration_tests/basic_bundle/require-context/empty.js +29 -0
  46. package/src/integration_tests/basic_bundle/require-context/empty.js.flow +26 -0
  47. package/src/integration_tests/basic_bundle/require-context/matching.js +26 -0
  48. package/src/integration_tests/basic_bundle/require-context/matching.js.flow +27 -0
  49. package/src/integration_tests/basic_bundle/require-context/mode-eager.js +22 -0
  50. package/src/integration_tests/basic_bundle/require-context/mode-eager.js.flow +24 -0
  51. package/src/integration_tests/basic_bundle/require-context/mode-lazy-once.js +22 -0
  52. package/src/integration_tests/basic_bundle/require-context/mode-lazy-once.js.flow +24 -0
  53. package/src/integration_tests/basic_bundle/require-context/mode-lazy.js +22 -0
  54. package/src/integration_tests/basic_bundle/require-context/mode-lazy.js.flow +24 -0
  55. package/src/integration_tests/basic_bundle/require-context/mode-sync.js +20 -0
  56. package/src/integration_tests/basic_bundle/require-context/mode-sync.js.flow +22 -0
  57. package/src/integration_tests/basic_bundle/require-context/subdir/a.js +12 -0
  58. package/src/integration_tests/basic_bundle/require-context/subdir/a.js.flow +11 -0
  59. package/src/integration_tests/basic_bundle/require-context/subdir/b.js +18 -0
  60. package/src/integration_tests/basic_bundle/require-context/subdir/b.js.flow +11 -0
  61. package/src/integration_tests/basic_bundle/require-context/subdir/c.js +12 -0
  62. package/src/integration_tests/basic_bundle/require-context/subdir/c.js.flow +11 -0
  63. package/src/integration_tests/basic_bundle/require-context/subdir/nested/d.js +12 -0
  64. package/src/integration_tests/basic_bundle/require-context/subdir/nested/d.js.flow +11 -0
  65. package/src/integration_tests/basic_bundle/require-context/subdir-conflict/index.js +12 -0
  66. package/src/integration_tests/basic_bundle/require-context/subdir-conflict/index.js.flow +11 -0
  67. package/src/integration_tests/basic_bundle/require-context/utils.js +29 -0
  68. package/src/integration_tests/basic_bundle/require-context/utils.js.flow +44 -0
  69. package/src/lib/CountingSet.js +1 -0
  70. package/src/lib/CountingSet.js.flow +1 -0
  71. package/src/lib/contextModule.js +80 -0
  72. package/src/lib/contextModule.js.flow +86 -0
  73. package/src/lib/contextModuleTemplates.js +186 -0
  74. package/src/lib/contextModuleTemplates.js.flow +148 -0
  75. package/src/lib/getGraphId.js +2 -1
  76. package/src/lib/getGraphId.js.flow +3 -0
  77. package/src/lib/getPrependedScripts.js +2 -0
  78. package/src/lib/getPrependedScripts.js.flow +2 -0
  79. package/src/lib/parseOptionsFromUrl.js.flow +7 -18
  80. package/src/lib/transformHelpers.js +41 -9
  81. package/src/lib/transformHelpers.js.flow +46 -9
  82. package/src/node-haste/DependencyGraph/ModuleResolution.js +1 -0
  83. package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +3 -2
  84. package/src/node-haste/DependencyGraph/createHasteMap.js +7 -1
  85. package/src/node-haste/DependencyGraph/createHasteMap.js.flow +8 -2
  86. package/src/node-haste/DependencyGraph.js +7 -0
  87. package/src/node-haste/DependencyGraph.js.flow +17 -2
  88. package/src/shared/output/bundle.flow.js +67 -0
  89. package/src/shared/output/bundle.flow.js.flow +89 -0
  90. package/src/shared/output/bundle.js +8 -55
  91. package/src/shared/output/bundle.js.flow +8 -75
@@ -30,6 +30,8 @@
30
30
 
31
31
  'use strict';
32
32
 
33
+ import type {RequireContextParams} from '../ModuleGraph/worker/collectDependencies';
34
+ import type {RequireContext} from '../lib/contextModule';
33
35
  import type {
34
36
  Dependency,
35
37
  Graph,
@@ -40,7 +42,12 @@ import type {
40
42
  } from './types.flow';
41
43
 
42
44
  import CountingSet from '../lib/CountingSet';
45
+ import {
46
+ deriveAbsolutePathFromContext,
47
+ fileMatchesContext,
48
+ } from '../lib/contextModule';
43
49
 
50
+ import * as path from 'path';
44
51
  const invariant = require('invariant');
45
52
  const nullthrows = require('nullthrows');
46
53
 
@@ -63,6 +70,8 @@ type NodeColor =
63
70
 
64
71
  // Private state for the graph that persists between operations.
65
72
  export opaque type PrivateState = {
73
+ /** Resolved context parameters from `require.context`. */
74
+ +resolvedContexts: Map<string, RequireContext>,
66
75
  +gc: {
67
76
  // GC state for nodes in the graph (graph.dependencies)
68
77
  +color: Map<string, NodeColor>,
@@ -79,6 +88,7 @@ function createGraph<T>(options: GraphInputOptions): Graph<T> {
79
88
  dependencies: new Map(),
80
89
  importBundleNames: new Set(),
81
90
  privateState: {
91
+ resolvedContexts: new Map(),
82
92
  gc: {
83
93
  color: new Map(),
84
94
  possibleCycleRoots: new Set(),
@@ -144,7 +154,7 @@ function getInternalOptions<T>({
144
154
  * dependency graph.
145
155
  * Instead of traversing the whole graph each time, it just calculates the
146
156
  * difference between runs by only traversing the added/removed dependencies.
147
- * To do so, it uses the passed passed graph dependencies and it mutates it.
157
+ * To do so, it uses the passed graph dependencies and it mutates it.
148
158
  * The paths parameter contains the absolute paths of the root files that the
149
159
  * method should traverse. Normally, these paths should be the modified files
150
160
  * since the last traversal.
@@ -266,13 +276,15 @@ async function processModule<T>(
266
276
  delta: Delta,
267
277
  options: InternalOptions<T>,
268
278
  ): Promise<Module<T>> {
279
+ const resolvedContext = graph.privateState.resolvedContexts.get(path);
269
280
  // Transform the file via the given option.
270
281
  // TODO: Unbind the transform method from options
271
- const result = await options.transform(path);
282
+ const result = await options.transform(path, resolvedContext);
272
283
 
273
284
  // Get the absolute path of all sub-dependencies (some of them could have been
274
285
  // moved but maintain the same relative path).
275
286
  const currentDependencies = resolveDependencies(
287
+ graph,
276
288
  path,
277
289
  result.dependencies,
278
290
  options,
@@ -295,46 +307,26 @@ async function processModule<T>(
295
307
  graph.dependencies.set(module.path, module);
296
308
 
297
309
  // Diff dependencies (1/2): remove dependencies that have changed or been removed.
298
- for (const [relativePath, prevDependency] of previousDependencies) {
299
- const curDependency = currentDependencies.get(relativePath);
310
+ for (const [key, prevDependency] of previousDependencies) {
311
+ const curDependency = currentDependencies.get(key);
300
312
  if (
301
313
  !curDependency ||
302
- curDependency.absolutePath !== prevDependency.absolutePath ||
303
- (options.experimentalImportBundleSupport &&
304
- curDependency.data.data.asyncType !==
305
- prevDependency.data.data.asyncType)
314
+ !dependenciesEqual(prevDependency, curDependency, options)
306
315
  ) {
307
- removeDependency(
308
- module,
309
- relativePath,
310
- prevDependency,
311
- graph,
312
- delta,
313
- options,
314
- );
316
+ removeDependency(module, key, prevDependency, graph, delta, options);
315
317
  }
316
318
  }
317
319
 
318
320
  // Diff dependencies (2/2): add dependencies that have changed or been added.
319
321
  const promises = [];
320
- for (const [relativePath, curDependency] of currentDependencies) {
321
- const prevDependency = previousDependencies.get(relativePath);
322
+ for (const [key, curDependency] of currentDependencies) {
323
+ const prevDependency = previousDependencies.get(key);
322
324
  if (
323
325
  !prevDependency ||
324
- prevDependency.absolutePath !== curDependency.absolutePath ||
325
- (options.experimentalImportBundleSupport &&
326
- prevDependency.data.data.asyncType !==
327
- curDependency.data.data.asyncType)
326
+ !dependenciesEqual(prevDependency, curDependency, options)
328
327
  ) {
329
328
  promises.push(
330
- addDependency(
331
- module,
332
- relativePath,
333
- curDependency,
334
- graph,
335
- delta,
336
- options,
337
- ),
329
+ addDependency(module, key, curDependency, graph, delta, options),
338
330
  );
339
331
  }
340
332
  }
@@ -359,9 +351,39 @@ async function processModule<T>(
359
351
  return module;
360
352
  }
361
353
 
354
+ function dependenciesEqual(
355
+ a: Dependency,
356
+ b: Dependency,
357
+ options: $ReadOnly<{experimentalImportBundleSupport: boolean, ...}>,
358
+ ): boolean {
359
+ return (
360
+ a === b ||
361
+ (a.absolutePath === b.absolutePath &&
362
+ (!options.experimentalImportBundleSupport ||
363
+ a.data.data.asyncType === b.data.data.asyncType) &&
364
+ contextParamsEqual(a.data.data.contextParams, b.data.data.contextParams))
365
+ );
366
+ }
367
+
368
+ function contextParamsEqual(
369
+ a: ?RequireContextParams,
370
+ b: ?RequireContextParams,
371
+ ): boolean {
372
+ return (
373
+ a === b ||
374
+ (a == null && b == null) ||
375
+ (a != null &&
376
+ b != null &&
377
+ a.recursive === b.recursive &&
378
+ a.filter.pattern === b.filter.pattern &&
379
+ a.filter.flags === b.filter.flags &&
380
+ a.mode === b.mode)
381
+ );
382
+ }
383
+
362
384
  async function addDependency<T>(
363
385
  parentModule: Module<T>,
364
- relativePath: string,
386
+ key: string,
365
387
  dependency: Dependency,
366
388
  graph: Graph<T>,
367
389
  delta: Delta,
@@ -420,18 +442,18 @@ async function addDependency<T>(
420
442
  // This means the parent's dependencies can get desynced from
421
443
  // inverseDependencies and the other fields in the case of lazy edges.
422
444
  // Not an optimal representation :(
423
- parentModule.dependencies.set(relativePath, dependency);
445
+ parentModule.dependencies.set(key, dependency);
424
446
  }
425
447
 
426
448
  function removeDependency<T>(
427
449
  parentModule: Module<T>,
428
- relativePath: string,
450
+ key: string,
429
451
  dependency: Dependency,
430
452
  graph: Graph<T>,
431
453
  delta: Delta,
432
454
  options: InternalOptions<T>,
433
455
  ): void {
434
- parentModule.dependencies.delete(relativePath);
456
+ parentModule.dependencies.delete(key);
435
457
 
436
458
  const {absolutePath} = dependency;
437
459
 
@@ -461,42 +483,98 @@ function removeDependency<T>(
461
483
  }
462
484
  }
463
485
 
486
+ /**
487
+ * Collect a list of context modules which include a given file.
488
+ */
489
+ function markModifiedContextModules<T>(
490
+ graph: Graph<T>,
491
+ filePath: string,
492
+ modifiedPaths: Set<string>,
493
+ ) {
494
+ for (const [absolutePath, context] of graph.privateState.resolvedContexts) {
495
+ if (
496
+ !modifiedPaths.has(absolutePath) &&
497
+ fileMatchesContext(filePath, context)
498
+ ) {
499
+ modifiedPaths.add(absolutePath);
500
+ }
501
+ }
502
+ }
503
+
464
504
  function resolveDependencies<T>(
505
+ graph: Graph<T>,
465
506
  parentPath: string,
466
507
  dependencies: $ReadOnlyArray<TransformResultDependency>,
467
508
  options: InternalOptions<T>,
468
509
  ): Map<string, Dependency> {
469
- const resolve = (parentPath: string, result: TransformResultDependency) => {
470
- const relativePath = result.name;
471
- try {
472
- return [
473
- relativePath,
474
- {
475
- absolutePath: options.resolve(parentPath, relativePath),
476
- data: result,
477
- },
478
- ];
479
- } catch (error) {
480
- // Ignore unavailable optional dependencies. They are guarded
481
- // with a try-catch block and will be handled during runtime.
482
- if (result.data.isOptional !== true) {
483
- throw error;
510
+ const maybeResolvedDeps = new Map();
511
+ for (const dep of dependencies) {
512
+ let resolvedDep;
513
+
514
+ // `require.context`
515
+ const {contextParams} = dep.data;
516
+ if (contextParams) {
517
+ // Ensure the filepath has uniqueness applied to ensure multiple `require.context`
518
+ // statements can be used to target the same file with different properties.
519
+ const from = path.join(parentPath, '..', dep.name);
520
+ const absolutePath = deriveAbsolutePathFromContext(from, contextParams);
521
+
522
+ const resolvedContext: RequireContext = {
523
+ from,
524
+ mode: contextParams.mode,
525
+ recursive: contextParams.recursive,
526
+ filter: new RegExp(
527
+ contextParams.filter.pattern,
528
+ contextParams.filter.flags,
529
+ ),
530
+ };
531
+
532
+ graph.privateState.resolvedContexts.set(absolutePath, resolvedContext);
533
+
534
+ resolvedDep = {
535
+ absolutePath,
536
+ data: dep,
537
+ };
538
+ } else {
539
+ try {
540
+ resolvedDep = {
541
+ absolutePath: options.resolve(parentPath, dep.name),
542
+ data: dep,
543
+ };
544
+
545
+ // This dependency may have existed previously as a require.context -
546
+ // clean it up.
547
+ graph.privateState.resolvedContexts.delete(resolvedDep.absolutePath);
548
+ } catch (error) {
549
+ // Ignore unavailable optional dependencies. They are guarded
550
+ // with a try-catch block and will be handled during runtime.
551
+ if (dep.data.isOptional !== true) {
552
+ throw error;
553
+ }
484
554
  }
485
555
  }
486
- return undefined;
487
- };
488
556
 
489
- const resolved = dependencies.reduce(
490
- (list: Array<[string, Dependency]>, result: TransformResultDependency) => {
491
- const resolvedPath = resolve(parentPath, result);
492
- if (resolvedPath) {
493
- list.push(resolvedPath);
494
- }
495
- return list;
496
- },
497
- [],
498
- );
499
- return new Map(resolved);
557
+ const key = dep.data.key;
558
+ if (maybeResolvedDeps.has(key)) {
559
+ throw new Error(
560
+ `resolveDependencies: Found duplicate dependency key '${key}' in ${parentPath}`,
561
+ );
562
+ }
563
+ maybeResolvedDeps.set(key, resolvedDep);
564
+ }
565
+
566
+ const resolvedDeps = new Map();
567
+ // Return just the dependencies we successfully resolved.
568
+ // FIXME: This has a bad bug affecting all dependencies *after* an unresolved
569
+ // optional dependency. We'll need to propagate the nulls all the way to the
570
+ // serializer and the require() runtime to keep the dependency map from being
571
+ // desynced from the contents of the module.
572
+ for (const [key, resolvedDep] of maybeResolvedDeps) {
573
+ if (resolvedDep) {
574
+ resolvedDeps.set(key, resolvedDep);
575
+ }
576
+ }
577
+ return resolvedDeps;
500
578
  }
501
579
 
502
580
  /**
@@ -604,8 +682,8 @@ function releaseModule<T>(
604
682
  delta: Delta,
605
683
  options: InternalOptions<T>,
606
684
  ) {
607
- for (const [relativePath, dependency] of module.dependencies) {
608
- removeDependency(module, relativePath, dependency, graph, delta, options);
685
+ for (const [key, dependency] of module.dependencies) {
686
+ removeDependency(module, key, dependency, graph, delta, options);
609
687
  }
610
688
  graph.privateState.gc.color.set(module.path, 'black');
611
689
  if (!graph.privateState.gc.possibleCycleRoots.has(module.path)) {
@@ -631,6 +709,7 @@ function freeModule<T>(module: Module<T>, graph: Graph<T>, delta: Delta) {
631
709
  delta.earlyInverseDependencies.delete(module.path);
632
710
  graph.privateState.gc.possibleCycleRoots.delete(module.path);
633
711
  graph.privateState.gc.color.delete(module.path);
712
+ graph.privateState.resolvedContexts.delete(module.path);
634
713
  }
635
714
 
636
715
  // Mark a module as a possible cycle root
@@ -749,4 +828,5 @@ module.exports = {
749
828
  initialTraverseDependencies,
750
829
  traverseDependencies,
751
830
  reorderGraph,
831
+ markModifiedContextModules,
752
832
  };
@@ -11,6 +11,7 @@
11
11
  'use strict';
12
12
 
13
13
  import type {RequireContextParams} from '../ModuleGraph/worker/collectDependencies';
14
+ import type {RequireContext} from '../lib/contextModule';
14
15
  import type {PrivateState} from './graphOperations';
15
16
  import type {JsTransformOptions} from 'metro-transform-worker';
16
17
 
@@ -31,10 +32,13 @@ export type TransformResultDependency = {
31
32
  +name: string,
32
33
 
33
34
  /**
34
- * Extra data returned by the dependency extractor. Whatever is added here is
35
- * blindly piped by Metro to the serializers.
35
+ * Extra data returned by the dependency extractor.
36
36
  */
37
37
  +data: {
38
+ /**
39
+ * A locally unique key for this dependency within the current module.
40
+ */
41
+ +key: string,
38
42
  /**
39
43
  * If not null, this dependency is due to a dynamic `import()` or `__prefetchImport()` call.
40
44
  */
@@ -104,9 +108,10 @@ export type TransformResultWithSource<T = MixedOutput> = $ReadOnly<{
104
108
  getSource: () => Buffer,
105
109
  }>;
106
110
 
107
- export type TransformFn<T = MixedOutput> = string => Promise<
108
- TransformResultWithSource<T>,
109
- >;
111
+ export type TransformFn<T = MixedOutput> = (
112
+ string,
113
+ ?RequireContext,
114
+ ) => Promise<TransformResultWithSource<T>>;
110
115
  export type AllowOptionalDependenciesWithOptions = {
111
116
  +exclude: Array<string>,
112
117
  };
@@ -120,6 +125,7 @@ export type Options<T = MixedOutput> = {
120
125
  +transformOptions: TransformInputOptions,
121
126
  +onProgress: ?(numProcessed: number, total: number) => mixed,
122
127
  +experimentalImportBundleSupport: boolean,
128
+ +unstable_allowRequireContext: boolean,
123
129
  +shallow: boolean,
124
130
  };
125
131
 
package/src/HmrServer.js CHANGED
@@ -99,6 +99,8 @@ class HmrServer {
99
99
  shallow: graphOptions.shallow,
100
100
  experimentalImportBundleSupport:
101
101
  this._config.transformer.experimentalImportBundleSupport,
102
+ unstable_allowRequireContext:
103
+ this._config.transformer.unstable_allowRequireContext,
102
104
  });
103
105
 
104
106
  const revPromise = this._bundler.getRevisionByGraphId(graphId);
@@ -125,6 +125,8 @@ class HmrServer<TClient: Client> {
125
125
  shallow: graphOptions.shallow,
126
126
  experimentalImportBundleSupport:
127
127
  this._config.transformer.experimentalImportBundleSupport,
128
+ unstable_allowRequireContext:
129
+ this._config.transformer.unstable_allowRequireContext,
128
130
  });
129
131
  const revPromise = this._bundler.getRevisionByGraphId(graphId);
130
132
  if (!revPromise) {
@@ -93,6 +93,8 @@ class IncrementalBundler {
93
93
  onProgress: otherOptions.onProgress,
94
94
  experimentalImportBundleSupport:
95
95
  this._config.transformer.experimentalImportBundleSupport,
96
+ unstable_allowRequireContext:
97
+ this._config.transformer.unstable_allowRequireContext,
96
98
  shallow: otherOptions.shallow,
97
99
  });
98
100
 
@@ -133,6 +135,8 @@ class IncrementalBundler {
133
135
  onProgress: otherOptions.onProgress,
134
136
  experimentalImportBundleSupport:
135
137
  this._config.transformer.experimentalImportBundleSupport,
138
+ unstable_allowRequireContext:
139
+ this._config.transformer.unstable_allowRequireContext,
136
140
  shallow: otherOptions.shallow,
137
141
  }
138
142
  );
@@ -178,6 +182,8 @@ class IncrementalBundler {
178
182
  shallow: otherOptions.shallow,
179
183
  experimentalImportBundleSupport:
180
184
  this._config.transformer.experimentalImportBundleSupport,
185
+ unstable_allowRequireContext:
186
+ this._config.transformer.unstable_allowRequireContext,
181
187
  });
182
188
  const revisionId = createRevisionId();
183
189
 
@@ -123,6 +123,8 @@ class IncrementalBundler {
123
123
  onProgress: otherOptions.onProgress,
124
124
  experimentalImportBundleSupport:
125
125
  this._config.transformer.experimentalImportBundleSupport,
126
+ unstable_allowRequireContext:
127
+ this._config.transformer.unstable_allowRequireContext,
126
128
  shallow: otherOptions.shallow,
127
129
  });
128
130
 
@@ -164,6 +166,8 @@ class IncrementalBundler {
164
166
  onProgress: otherOptions.onProgress,
165
167
  experimentalImportBundleSupport:
166
168
  this._config.transformer.experimentalImportBundleSupport,
169
+ unstable_allowRequireContext:
170
+ this._config.transformer.unstable_allowRequireContext,
167
171
  shallow: otherOptions.shallow,
168
172
  },
169
173
  );
@@ -218,6 +222,8 @@ class IncrementalBundler {
218
222
  shallow: otherOptions.shallow,
219
223
  experimentalImportBundleSupport:
220
224
  this._config.transformer.experimentalImportBundleSupport,
225
+ unstable_allowRequireContext:
226
+ this._config.transformer.unstable_allowRequireContext,
221
227
  });
222
228
  const revisionId = createRevisionId();
223
229
  const revisionPromise = (async () => {
@@ -58,7 +58,7 @@ module.exports = class HasteFS {
58
58
  return Array.from<string>(this.files.keys());
59
59
  }
60
60
 
61
- matchFiles() {
61
+ matchFiles(): $FlowFixMeEmpty {
62
62
  throw new Error('HasteFS.matchFiles is not implemented yet.');
63
63
  }
64
64
 
@@ -47,7 +47,13 @@ const NODE_MODULES = path.sep + "node_modules" + path.sep;
47
47
 
48
48
  const isNodeModules = (file) => file.includes(NODE_MODULES); // This function maps the ModuleGraph data structure to metro-file-map's ModuleMap
49
49
 
50
- const createModuleMap = ({ files, moduleCache, sourceExts, platforms }) => {
50
+ const createModuleMap = ({
51
+ files,
52
+ moduleCache,
53
+ sourceExts,
54
+ additionalExts,
55
+ platforms,
56
+ }) => {
51
57
  const platformSet = new Set(
52
58
  (platforms !== null && platforms !== void 0
53
59
  ? platforms
@@ -62,11 +68,12 @@ const createModuleMap = ({ files, moduleCache, sourceExts, platforms }) => {
62
68
 
63
69
  let id;
64
70
  let module;
71
+ const fileExt = path.extname(filePath).substr(1);
65
72
 
66
73
  if (filePath.endsWith(PACKAGE_JSON)) {
67
74
  module = moduleCache.getPackage(filePath);
68
75
  id = module.data.name;
69
- } else if (sourceExts.indexOf(path.extname(filePath).substr(1)) !== -1) {
76
+ } else if (sourceExts.has(fileExt) || additionalExts.has(fileExt)) {
70
77
  module = moduleCache.getModule(filePath);
71
78
  id = module.name;
72
79
  }
@@ -107,6 +114,7 @@ exports.createResolveFn = function (options) {
107
114
  extraNodeModules,
108
115
  transformedFiles,
109
116
  sourceExts,
117
+ additionalExts,
110
118
  platform,
111
119
  platforms,
112
120
  } = options;
@@ -146,7 +154,8 @@ exports.createResolveFn = function (options) {
146
154
  map: createModuleMap({
147
155
  files,
148
156
  moduleCache,
149
- sourceExts,
157
+ sourceExts: new Set(sourceExts),
158
+ additionalExts: new Set(additionalExts),
150
159
  platforms,
151
160
  }),
152
161
  mocks: new Map(),
@@ -172,10 +181,8 @@ exports.createResolveFn = function (options) {
172
181
  const from =
173
182
  sourcePath != null
174
183
  ? new Module(sourcePath, moduleCache, getTransformedFile(sourcePath))
175
- : NULL_MODULE;
176
- const allowHaste = !isNodeModules(from.path); // $FlowFixMe -- error revealed by types-first codemod
184
+ : NULL_MODULE; // $FlowFixMe -- error revealed by types-first codemod
177
185
 
178
- return moduleResolver.resolveDependency(from, id, allowHaste, platform)
179
- .path;
186
+ return moduleResolver.resolveDependency(from, id, true, platform).path;
180
187
  };
181
188
  };
@@ -10,7 +10,7 @@
10
10
 
11
11
  import type {Moduleish} from '../../node-haste/DependencyGraph/ModuleResolution';
12
12
  import type {ResolveFn, TransformedCodeFile} from '../types.flow';
13
- import type {Extensions, Path} from './node-haste.flow';
13
+ import type {Path} from './node-haste.flow';
14
14
  import type {ModuleMapData, ModuleMapItem} from 'metro-file-map';
15
15
  import type {CustomResolver} from 'metro-resolver';
16
16
 
@@ -27,7 +27,19 @@ const defaults = require('metro-config/src/defaults/defaults');
27
27
  const path = require('path');
28
28
 
29
29
  type ResolveOptions = {
30
- assetExts: Extensions,
30
+ /**
31
+ * (Used by the resolver) The extensions tried (in order) to implicitly
32
+ * locate a source file.
33
+ */
34
+ sourceExts: $ReadOnlyArray<string>,
35
+
36
+ /**
37
+ * The additional extensions to include in the file map as source files that
38
+ * can be explicitly imported.
39
+ */
40
+ additionalExts: $ReadOnlyArray<string>,
41
+
42
+ assetExts: $ReadOnlyArray<string>,
31
43
  assetResolutions: $ReadOnlyArray<string>,
32
44
  +disableHierarchicalLookup: boolean,
33
45
  +emptyModulePath: string,
@@ -37,7 +49,6 @@ type ResolveOptions = {
37
49
  +platform: string,
38
50
  platforms?: $ReadOnlyArray<string>,
39
51
  resolveRequest?: ?CustomResolver,
40
- +sourceExts: Extensions,
41
52
  transformedFiles: {[path: Path]: TransformedCodeFile, ...},
42
53
  };
43
54
 
@@ -56,14 +67,21 @@ const NULL_MODULE: Moduleish = {
56
67
  };
57
68
 
58
69
  const NODE_MODULES = path.sep + 'node_modules' + path.sep;
59
- const isNodeModules = file => file.includes(NODE_MODULES);
70
+ const isNodeModules = (file: string) => file.includes(NODE_MODULES);
60
71
 
61
72
  // This function maps the ModuleGraph data structure to metro-file-map's ModuleMap
62
73
  const createModuleMap = ({
63
74
  files,
64
75
  moduleCache,
65
76
  sourceExts,
77
+ additionalExts,
66
78
  platforms,
79
+ }: {
80
+ files: Array<string>,
81
+ moduleCache: ModuleCache,
82
+ sourceExts: $ReadOnlySet<string>,
83
+ additionalExts: $ReadOnlySet<string>,
84
+ platforms: void | $ReadOnlyArray<string>,
67
85
  }): ModuleMapData => {
68
86
  const platformSet = new Set(
69
87
  (platforms ?? defaults.platforms).concat([NATIVE_PLATFORM]),
@@ -77,10 +95,12 @@ const createModuleMap = ({
77
95
  }
78
96
  let id;
79
97
  let module;
98
+ const fileExt = path.extname(filePath).substr(1);
99
+
80
100
  if (filePath.endsWith(PACKAGE_JSON)) {
81
101
  module = moduleCache.getPackage(filePath);
82
102
  id = module.data.name;
83
- } else if (sourceExts.indexOf(path.extname(filePath).substr(1)) !== -1) {
103
+ } else if (sourceExts.has(fileExt) || additionalExts.has(fileExt)) {
84
104
  module = moduleCache.getModule(filePath);
85
105
  id = module.name;
86
106
  }
@@ -123,6 +143,7 @@ exports.createResolveFn = function (options: ResolveOptions): ResolveFn {
123
143
  extraNodeModules,
124
144
  transformedFiles,
125
145
  sourceExts,
146
+ additionalExts,
126
147
  platform,
127
148
  platforms,
128
149
  } = options;
@@ -142,7 +163,7 @@ exports.createResolveFn = function (options: ResolveOptions): ResolveFn {
142
163
  );
143
164
 
144
165
  const assetExtensions = new Set(assetExts.map(asset => '.' + asset));
145
- const isAssetFile = file => assetExtensions.has(path.extname(file));
166
+ const isAssetFile = (file: string) => assetExtensions.has(path.extname(file));
146
167
 
147
168
  const moduleResolver = new ModuleResolver({
148
169
  dirExists: (filePath: string): boolean => hasteFS.dirExists(filePath),
@@ -156,7 +177,13 @@ exports.createResolveFn = function (options: ResolveOptions): ResolveFn {
156
177
  moduleCache,
157
178
  moduleMap: new ModuleMap({
158
179
  duplicates: new Map(),
159
- map: createModuleMap({files, moduleCache, sourceExts, platforms}),
180
+ map: createModuleMap({
181
+ files,
182
+ moduleCache,
183
+ sourceExts: new Set(sourceExts),
184
+ additionalExts: new Set(additionalExts),
185
+ platforms,
186
+ }),
160
187
  mocks: new Map(),
161
188
  rootDir: '',
162
189
  }),
@@ -186,9 +213,7 @@ exports.createResolveFn = function (options: ResolveOptions): ResolveFn {
186
213
  sourcePath != null
187
214
  ? new Module(sourcePath, moduleCache, getTransformedFile(sourcePath))
188
215
  : NULL_MODULE;
189
- const allowHaste = !isNodeModules(from.path);
190
216
  // $FlowFixMe -- error revealed by types-first codemod
191
- return moduleResolver.resolveDependency(from, id, allowHaste, platform)
192
- .path;
217
+ return moduleResolver.resolveDependency(from, id, true, platform).path;
193
218
  };
194
219
  };
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  'use strict';
12
- import type {IdsForPathFn, Dependency} from '../types.flow';
12
+ import type {Dependency} from '../types.flow';
13
13
  import type {BasicSourceMap} from '../../../../metro-source-map/src/source-map';
14
14
 
15
15
  import type {Module, OutputFn, OutputFnArg} from '../types.flow';
@@ -33,18 +33,10 @@ function asIndexedRamBundle({
33
33
  preloadedModules,
34
34
  ramGroupHeads,
35
35
  requireCalls,
36
- }: $TEMPORARY$object<{
37
- dependencyMapReservedName?: ?string,
38
- enableIDInlining: boolean,
39
- filename: string,
40
- globalPrefix: string,
41
- idsForPath: IdsForPathFn,
42
- modules: Iterable<Module>,
43
- preloadedModules: Set<string>,
36
+ }: $ReadOnly<{
37
+ ...OutputFnArg,
38
+ preloadedModules: $ReadOnlySet<string>,
44
39
  ramGroupHeads: ?$ReadOnlyArray<string>,
45
- requireCalls: Iterable<Module>,
46
- segmentID: number,
47
- sourceMapPath?: ?string,
48
40
  }>): {
49
41
  code: string | Buffer,
50
42
  extraFiles?: Iterable<[string, string | Buffer]>,
@@ -137,7 +129,7 @@ function* subtree(
137
129
  }
138
130
 
139
131
  function createBuilder(
140
- preloadedModules: Set<string>,
132
+ preloadedModules: $ReadOnlySet<string>,
141
133
  ramGroupHeads: ?$ReadOnlyArray<string>,
142
134
  ): OutputFn<IndexMap> {
143
135
  return (x: OutputFnArg) =>