metro 0.71.0 → 0.71.3

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 (57) hide show
  1. package/package.json +23 -22
  2. package/src/Bundler.js +0 -2
  3. package/src/Bundler.js.flow +1 -1
  4. package/src/DeltaBundler/DeltaCalculator.js +2 -0
  5. package/src/DeltaBundler/DeltaCalculator.js.flow +2 -0
  6. package/src/DeltaBundler/Worker.flow.js +78 -0
  7. package/src/DeltaBundler/Worker.flow.js.flow +121 -0
  8. package/src/DeltaBundler/Worker.js +8 -66
  9. package/src/DeltaBundler/Worker.js.flow +8 -107
  10. package/src/DeltaBundler/WorkerFarm.js.flow +2 -2
  11. package/src/DeltaBundler/__fixtures__/hasteImpl.js +4 -0
  12. package/src/DeltaBundler/graphOperations.js +382 -222
  13. package/src/DeltaBundler/graphOperations.js.flow +404 -232
  14. package/src/DeltaBundler/types.flow.js +6 -0
  15. package/src/DeltaBundler/types.flow.js.flow +7 -1
  16. package/src/DeltaBundler.js +0 -2
  17. package/src/DeltaBundler.js.flow +1 -1
  18. package/src/HmrServer.js +0 -2
  19. package/src/HmrServer.js.flow +1 -2
  20. package/src/ModuleGraph/node-haste/node-haste.flow.js +0 -1
  21. package/src/ModuleGraph/node-haste/node-haste.flow.js.flow +1 -2
  22. package/src/ModuleGraph/node-haste/node-haste.js.flow +7 -2
  23. package/src/ModuleGraph/output/util.js.flow +2 -2
  24. package/src/ModuleGraph/silent-console.js +5 -4
  25. package/src/ModuleGraph/silent-console.js.flow +8 -4
  26. package/src/ModuleGraph/worker/collectDependencies.js +215 -8
  27. package/src/ModuleGraph/worker/collectDependencies.js.flow +233 -13
  28. package/src/Server.js +2 -0
  29. package/src/Server.js.flow +9 -2
  30. package/src/cli.js +5 -0
  31. package/src/cli.js.flow +5 -0
  32. package/src/commands/build.js +4 -3
  33. package/src/commands/build.js.flow +3 -1
  34. package/src/commands/serve.js +3 -3
  35. package/src/commands/serve.js.flow +3 -1
  36. package/src/index.flow.js +392 -0
  37. package/src/index.flow.js.flow +480 -0
  38. package/src/index.js +8 -380
  39. package/src/index.js.flow +8 -466
  40. package/src/lib/CountingSet.js +116 -0
  41. package/src/lib/CountingSet.js.flow +126 -0
  42. package/src/lib/JsonReporter.js +0 -2
  43. package/src/lib/JsonReporter.js.flow +1 -1
  44. package/src/lib/getAppendScripts.js +10 -4
  45. package/src/lib/getAppendScripts.js.flow +6 -4
  46. package/src/lib/getPreludeCode.js +19 -1
  47. package/src/lib/getPreludeCode.js.flow +15 -0
  48. package/src/lib/getPrependedScripts.js +10 -2
  49. package/src/lib/getPrependedScripts.js.flow +11 -2
  50. package/src/lib/reporting.js +0 -2
  51. package/src/lib/reporting.js.flow +2 -1
  52. package/src/node-haste/DependencyGraph/ModuleResolution.js +15 -3
  53. package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +15 -0
  54. package/src/node-haste/DependencyGraph/createHasteMap.js +78 -19
  55. package/src/node-haste/DependencyGraph/createHasteMap.js.flow +14 -9
  56. package/src/node-haste/DependencyGraph.js +2 -2
  57. package/src/node-haste/DependencyGraph.js.flow +4 -2
@@ -37,6 +37,20 @@ export type Dependency<TSplitCondition> = $ReadOnly<{
37
37
  name: string,
38
38
  }>;
39
39
 
40
+ // TODO: Convert to a Flow enum
41
+ type ContextMode = 'sync' | 'eager' | 'lazy' | 'lazy-once';
42
+
43
+ type ContextFilter = {pattern: string, flags: string};
44
+
45
+ export type RequireContextParams = $ReadOnly<{
46
+ /* Should search for files recursively. Optional, default `true` when `require.context` is used */
47
+ recursive: boolean,
48
+ /* Filename filter pattern for use in `require.context`. Optional, default `.*` (any file) when `require.context` is used */
49
+ filter: $ReadOnly<ContextFilter>,
50
+ /** Mode for resolving dynamic dependencies. Defaults to `sync` */
51
+ mode: ContextMode,
52
+ }>;
53
+
40
54
  type DependencyData<TSplitCondition> = $ReadOnly<{
41
55
  // If null, then the dependency is synchronous.
42
56
  // (ex. `require('foo')`)
@@ -45,6 +59,8 @@ type DependencyData<TSplitCondition> = $ReadOnly<{
45
59
  // If left unspecified, then the dependency is unconditionally split.
46
60
  splitCondition?: TSplitCondition,
47
61
  locs: Array<BabelSourceLocation>,
62
+ /** Context for requiring a collection of modules. */
63
+ contextParams?: RequireContextParams,
48
64
  }>;
49
65
 
50
66
  export type MutableInternalDependency<TSplitCondition> = {
@@ -66,6 +82,8 @@ export type State<TSplitCondition> = {
66
82
  dependencyMapIdentifier: ?Identifier,
67
83
  keepRequireNames: boolean,
68
84
  allowOptionalDependencies: AllowOptionalDependencies,
85
+ /** Enable `require.context` statements which can be used to import multiple files in a directory. */
86
+ unstable_allowRequireContext: boolean,
69
87
  };
70
88
 
71
89
  export type Options<TSplitCondition = void> = $ReadOnly<{
@@ -77,6 +95,8 @@ export type Options<TSplitCondition = void> = $ReadOnly<{
77
95
  allowOptionalDependencies: AllowOptionalDependencies,
78
96
  dependencyRegistry?: ModuleDependencyRegistry<TSplitCondition>,
79
97
  dependencyTransformer?: DependencyTransformer<TSplitCondition>,
98
+ /** Enable `require.context` statements which can be used to import multiple files in a directory. */
99
+ unstable_allowRequireContext: boolean,
80
100
  }>;
81
101
 
82
102
  export type CollectedDependencies<+TSplitCondition> = $ReadOnly<{
@@ -87,8 +107,8 @@ export type CollectedDependencies<+TSplitCondition> = $ReadOnly<{
87
107
 
88
108
  // Registry for the dependency of a module.
89
109
  // Defines when dependencies should be collapsed.
90
- // E.g. should a module that's once required optinally and once not
91
- // be tretaed as the smae or different dependencies.
110
+ // E.g. should a module that's once required optionally and once not
111
+ // be treated as the same or different dependencies.
92
112
  export interface ModuleDependencyRegistry<+TSplitCondition> {
93
113
  registerDependency(
94
114
  qualifier: ImportQualifier,
@@ -151,10 +171,14 @@ function collectDependencies<TSplitCondition = void>(
151
171
  dynamicRequires: options.dynamicRequires,
152
172
  keepRequireNames: options.keepRequireNames,
153
173
  allowOptionalDependencies: options.allowOptionalDependencies,
174
+ unstable_allowRequireContext: options.unstable_allowRequireContext,
154
175
  };
155
176
 
156
177
  const visitor = {
157
- CallExpression(path, state): void {
178
+ CallExpression(
179
+ path: NodePath<BabelNodeCallExpression>,
180
+ state: State<TSplitCondition>,
181
+ ): void {
158
182
  if (visited.has(path.node)) {
159
183
  return;
160
184
  }
@@ -199,6 +223,26 @@ function collectDependencies<TSplitCondition = void>(
199
223
  return;
200
224
  }
201
225
 
226
+ // Match `require.context`
227
+ if (
228
+ // Feature gate, defaults to `false`.
229
+ state.unstable_allowRequireContext &&
230
+ callee.type === 'MemberExpression' &&
231
+ // `require`
232
+ callee.object.type === 'Identifier' &&
233
+ callee.object.name === 'require' &&
234
+ // `context`
235
+ callee.property.type === 'Identifier' &&
236
+ callee.property.name === 'context' &&
237
+ !callee.computed &&
238
+ // Ensure `require` refers to the global and not something else.
239
+ !path.scope.getBinding('require')
240
+ ) {
241
+ processRequireContextCall(path, state);
242
+ visited.add(path.node);
243
+ return;
244
+ }
245
+
202
246
  if (
203
247
  name != null &&
204
248
  state.dependencyCalls.has(name) &&
@@ -213,7 +257,7 @@ function collectDependencies<TSplitCondition = void>(
213
257
  ExportNamedDeclaration: collectImports,
214
258
  ExportAllDeclaration: collectImports,
215
259
 
216
- Program(path, state) {
260
+ Program(path: NodePath<BabelNodeProgram>, state: State<TSplitCondition>) {
217
261
  state.asyncRequireModulePathStringLiteral = types.stringLiteral(
218
262
  options.asyncRequireModulePath,
219
263
  );
@@ -251,6 +295,132 @@ function collectDependencies<TSplitCondition = void>(
251
295
  };
252
296
  }
253
297
 
298
+ /** Extract args passed to the `require.context` method. */
299
+ function getRequireContextArgs(
300
+ path: NodePath<CallExpression>,
301
+ ): [string, RequireContextParams] {
302
+ const args = path.get('arguments');
303
+
304
+ let directory: string;
305
+ if (!Array.isArray(args) || args.length < 1) {
306
+ throw new InvalidRequireCallError(path);
307
+ } else {
308
+ const result = args[0].evaluate();
309
+ if (result.confident && typeof result.value === 'string') {
310
+ directory = result.value;
311
+ } else {
312
+ throw new InvalidRequireCallError(
313
+ result.deopt ?? args[0],
314
+ 'First argument of `require.context` should be a string denoting the directory to require.',
315
+ );
316
+ }
317
+ }
318
+
319
+ // Default to requiring through all directories.
320
+ let recursive: boolean = true;
321
+ if (args.length > 1) {
322
+ const result = args[1].evaluate();
323
+ if (result.confident && typeof result.value === 'boolean') {
324
+ recursive = result.value;
325
+ } else if (!(result.confident && typeof result.value === 'undefined')) {
326
+ throw new InvalidRequireCallError(
327
+ result.deopt ?? args[1],
328
+ 'Second argument of `require.context` should be an optional boolean indicating if files should be imported recursively or not.',
329
+ );
330
+ }
331
+ }
332
+
333
+ // Default to all files.
334
+ let filter: ContextFilter = {pattern: '.*', flags: ''};
335
+ if (args.length > 2) {
336
+ // evaluate() to check for undefined (because it's technically a scope lookup)
337
+ // but check the AST for the regex literal, since evaluate() doesn't do regex.
338
+ const result = args[2].evaluate();
339
+ const argNode = args[2].node;
340
+ if (argNode.type === 'RegExpLiteral') {
341
+ // TODO: Handle `new RegExp(...)` -- `argNode.type === 'NewExpression'`
342
+ filter = {
343
+ pattern: argNode.pattern,
344
+ flags: argNode.flags || '',
345
+ };
346
+ } else if (!(result.confident && typeof result.value === 'undefined')) {
347
+ throw new InvalidRequireCallError(
348
+ args[2],
349
+ `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}.`,
350
+ );
351
+ }
352
+ }
353
+
354
+ // Default to `sync`.
355
+ let mode: ContextMode = 'sync';
356
+ if (args.length > 3) {
357
+ const result = args[3].evaluate();
358
+ if (result.confident && typeof result.value === 'string') {
359
+ mode = getContextMode(args[3], result.value);
360
+ } else if (!(result.confident && typeof result.value === 'undefined')) {
361
+ throw new InvalidRequireCallError(
362
+ result.deopt ?? args[3],
363
+ 'Fourth argument of `require.context` should be an optional string "mode" denoting how the modules will be resolved.',
364
+ );
365
+ }
366
+ }
367
+
368
+ if (args.length > 4) {
369
+ throw new InvalidRequireCallError(
370
+ path,
371
+ `Too many arguments provided to \`require.context\` call. Expected 4, got: ${args.length}`,
372
+ );
373
+ }
374
+
375
+ return [
376
+ directory,
377
+ {
378
+ recursive,
379
+ filter,
380
+ mode,
381
+ },
382
+ ];
383
+ }
384
+
385
+ function getContextMode(path: NodePath<>, mode: string): ContextMode {
386
+ if (
387
+ mode === 'sync' ||
388
+ mode === 'eager' ||
389
+ mode === 'lazy' ||
390
+ mode === 'lazy-once'
391
+ ) {
392
+ return mode;
393
+ }
394
+ throw new InvalidRequireCallError(
395
+ path,
396
+ `require.context "${mode}" mode is not supported. Expected one of: sync, eager, lazy, lazy-once`,
397
+ );
398
+ }
399
+
400
+ function processRequireContextCall<TSplitCondition>(
401
+ path: NodePath<CallExpression>,
402
+ state: State<TSplitCondition>,
403
+ ): void {
404
+ const [directory, contextParams] = getRequireContextArgs(path);
405
+ const transformer = state.dependencyTransformer;
406
+ const dep = registerDependency(
407
+ state,
408
+ {
409
+ // We basically want to "import" every file in a folder and then filter them out with the given `filter` RegExp.
410
+ name: directory,
411
+ // Capture the matching context
412
+ contextParams,
413
+ asyncType: null,
414
+ optional: isOptionalDependency(directory, path, state),
415
+ },
416
+ path,
417
+ );
418
+
419
+ // require() the generated module representing this context
420
+ path.get('callee').replaceWith(types.identifier('require'));
421
+ transformer.transformSyncRequire(path, dep, state);
422
+ }
423
+
254
424
  function collectImports<TSplitCondition>(
255
425
  path: NodePath<>,
256
426
  state: State<TSplitCondition>,
@@ -344,6 +514,7 @@ export type ImportQualifier = $ReadOnly<{
344
514
  asyncType: AsyncDependencyType | null,
345
515
  splitCondition?: NodePath<>,
346
516
  optional: boolean,
517
+ contextParams?: RequireContextParams,
347
518
  }>;
348
519
 
349
520
  function registerDependency<TSplitCondition>(
@@ -352,7 +523,6 @@ function registerDependency<TSplitCondition>(
352
523
  path: NodePath<>,
353
524
  ): InternalDependency<TSplitCondition> {
354
525
  const dependency = state.dependencyRegistry.registerDependency(qualifier);
355
-
356
526
  const loc = getNearestLocFromPath(path);
357
527
  if (loc != null) {
358
528
  dependency.locs.push(loc);
@@ -419,14 +589,20 @@ function getModuleNameFromCallArgs(path: NodePath<CallExpression>): ?string {
419
589
 
420
590
  return null;
421
591
  }
592
+
422
593
  collectDependencies.getModuleNameFromCallArgs = getModuleNameFromCallArgs;
423
594
 
424
595
  class InvalidRequireCallError extends Error {
425
- constructor({node}: any) {
596
+ constructor({node}: NodePath<>, message?: string) {
426
597
  const line = node.loc && node.loc.start && node.loc.start.line;
427
598
 
428
599
  super(
429
- `Invalid call at line ${line || '<unknown>'}: ${generate(node).code}`,
600
+ [
601
+ `Invalid call at line ${line || '<unknown>'}: ${generate(node).code}`,
602
+ message,
603
+ ]
604
+ .filter(Boolean)
605
+ .join('\n'),
430
606
  );
431
607
  }
432
608
  }
@@ -469,9 +645,11 @@ const DefaultDependencyTransformer: DependencyTransformer<mixed> = {
469
645
  state: State<mixed>,
470
646
  ): void {
471
647
  const moduleIDExpression = createModuleIDExpression(dependency, state);
472
- path.node.arguments = state.keepRequireNames
473
- ? [moduleIDExpression, types.stringLiteral(dependency.name)]
474
- : [moduleIDExpression];
648
+ path.node.arguments = [moduleIDExpression];
649
+ // Always add the debug name argument last
650
+ if (state.keepRequireNames) {
651
+ path.node.arguments.push(types.stringLiteral(dependency.name));
652
+ }
475
653
  },
476
654
 
477
655
  transformImportCall(
@@ -546,6 +724,44 @@ function createModuleNameLiteral(dependency: InternalDependency<mixed>) {
546
724
  return types.stringLiteral(dependency.name);
547
725
  }
548
726
 
727
+ /**
728
+ * Given an import qualifier, return a key used to register the dependency.
729
+ * Generally this return the `ImportQualifier.name` property, but in the case
730
+ * of `require.context` more attributes can be appended to distinguish various combinations that would otherwise conflict.
731
+ *
732
+ * For example, the following case would have collision issues if they all utilized the `name` property:
733
+ * ```
734
+ * require('./foo');
735
+ * require.context('./foo');
736
+ * require.context('./foo', true, /something/);
737
+ * require.context('./foo', false, /something/);
738
+ * require.context('./foo', false, /something/, 'lazy');
739
+ * ```
740
+ *
741
+ * This method should be utilized by `registerDependency`.
742
+ */
743
+ function getKeyForDependency(qualifier: ImportQualifier): string {
744
+ let key = qualifier.name;
745
+
746
+ const {contextParams} = qualifier;
747
+ // Add extra qualifiers when using `require.context` to prevent collisions.
748
+ if (contextParams) {
749
+ // NOTE(EvanBacon): Keep this synchronized with `RequireContextParams`, if any other properties are added
750
+ // then this key algorithm should be updated to account for those properties.
751
+ // Example: `./directory__true__/foobar/m__lazy`
752
+ key += [
753
+ '',
754
+ 'context',
755
+ String(contextParams.recursive),
756
+ String(contextParams.filter.pattern),
757
+ String(contextParams.filter.flags),
758
+ contextParams.mode,
759
+ // Join together and append to the name:
760
+ ].join('__');
761
+ }
762
+ return key;
763
+ }
764
+
549
765
  class DefaultModuleDependencyRegistry<TSplitCondition = void>
550
766
  implements ModuleDependencyRegistry<TSplitCondition>
551
767
  {
@@ -554,8 +770,9 @@ class DefaultModuleDependencyRegistry<TSplitCondition = void>
554
770
  registerDependency(
555
771
  qualifier: ImportQualifier,
556
772
  ): InternalDependency<TSplitCondition> {
773
+ const key = getKeyForDependency(qualifier);
557
774
  let dependency: ?InternalDependency<TSplitCondition> =
558
- this._dependencies.get(qualifier.name);
775
+ this._dependencies.get(key);
559
776
 
560
777
  if (dependency == null) {
561
778
  const newDependency: MutableInternalDependency<TSplitCondition> = {
@@ -568,14 +785,17 @@ class DefaultModuleDependencyRegistry<TSplitCondition = void>
568
785
  if (qualifier.optional) {
569
786
  newDependency.isOptional = true;
570
787
  }
788
+ if (qualifier.contextParams) {
789
+ newDependency.contextParams = qualifier.contextParams;
790
+ }
571
791
 
572
792
  dependency = newDependency;
573
- this._dependencies.set(qualifier.name, dependency);
793
+ this._dependencies.set(key, dependency);
574
794
  } else {
575
795
  const original = dependency;
576
796
  dependency = collapseDependencies(original, qualifier);
577
797
  if (original !== dependency) {
578
- this._dependencies.set(qualifier.name, dependency);
798
+ this._dependencies.set(key, dependency);
579
799
  }
580
800
  }
581
801
 
package/src/Server.js CHANGED
@@ -660,6 +660,8 @@ class Server {
660
660
 
661
661
  const serializer =
662
662
  this._config.serializer.customSerializer ||
663
+ /* $FlowFixMe[missing-local-annot] The type annotation(s) required by
664
+ * Flow's LTI update could not be added via codemod */
663
665
  ((...args) => bundleToString(baseJSBundle(...args)).code);
664
666
 
665
667
  const bundle = await serializer(
@@ -9,6 +9,8 @@
9
9
  */
10
10
 
11
11
  'use strict';
12
+
13
+ import type {StackFrameOutput} from './Server/symbolicate';
12
14
  import type {AssetData} from './Assets';
13
15
  import type {ExplodedSourceMap} from './DeltaBundler/Serializers/getExplodedSourceMap';
14
16
  import type {RamBundleInfo} from './DeltaBundler/Serializers/getRamBundleInfo';
@@ -733,6 +735,8 @@ class Server {
733
735
 
734
736
  const serializer =
735
737
  this._config.serializer.customSerializer ||
738
+ /* $FlowFixMe[missing-local-annot] The type annotation(s) required by
739
+ * Flow's LTI update could not be added via codemod */
736
740
  ((...args) => bundleToString(baseJSBundle(...args)).code);
737
741
 
738
742
  const bundle = await serializer(
@@ -1011,7 +1015,10 @@ class Server {
1011
1015
  });
1012
1016
 
1013
1017
  async _symbolicate(req: IncomingMessage, res: ServerResponse) {
1014
- const getCodeFrame = (urls, symbolicatedStack) => {
1018
+ const getCodeFrame = (
1019
+ urls: Set<string>,
1020
+ symbolicatedStack: $ReadOnlyArray<StackFrameOutput>,
1021
+ ) => {
1015
1022
  for (let i = 0; i < symbolicatedStack.length; i++) {
1016
1023
  const {collapse, column, file, lineNumber} = symbolicatedStack[i];
1017
1024
  const fileAbsolute = path.resolve(this._config.projectRoot, file ?? '');
@@ -1161,7 +1168,7 @@ class Server {
1161
1168
  }
1162
1169
 
1163
1170
  async _resolveRelativePath(
1164
- filePath,
1171
+ filePath: string,
1165
1172
  {
1166
1173
  transformOptions,
1167
1174
  relativeTo,
package/src/cli.js CHANGED
@@ -11,6 +11,11 @@
11
11
  */
12
12
  "use strict";
13
13
 
14
+ try {
15
+ // $FlowFixMe[untyped-import]
16
+ require("metro-babel-register").unstable_registerForMetroMonorepo();
17
+ } catch {}
18
+
14
19
  const { attachMetroCli } = require("./index");
15
20
 
16
21
  const yargs = require("yargs");
package/src/cli.js.flow CHANGED
@@ -11,6 +11,11 @@
11
11
 
12
12
  'use strict';
13
13
 
14
+ try {
15
+ // $FlowFixMe[untyped-import]
16
+ require('metro-babel-register').unstable_registerForMetroMonorepo();
17
+ } catch {}
18
+
14
19
  const {attachMetroCli} = require('./index');
15
20
  const yargs = require('yargs');
16
21
 
@@ -11,8 +11,6 @@
11
11
 
12
12
  const { makeAsyncCommand } = require("../cli-utils");
13
13
 
14
- const MetroApi = require("../index");
15
-
16
14
  const TerminalReporter = require("../lib/TerminalReporter");
17
15
 
18
16
  const { loadConfig } = require("metro-config");
@@ -78,7 +76,10 @@ module.exports = () => ({
78
76
  handler: makeAsyncCommand(async (argv) => {
79
77
  const config = await loadConfig(argv); // $FlowExpectedError YargArguments and RunBuildOptions are used interchangeable but their types are not yet compatible
80
78
 
81
- const options = argv;
79
+ const options = argv; // Inline require() to avoid circular dependency with ../index
80
+
81
+ const MetroApi = require("../index");
82
+
82
83
  await MetroApi.runBuild(config, {
83
84
  ...options,
84
85
  onBegin: () => {
@@ -15,7 +15,6 @@ import type {YargArguments} from 'metro-config/src/configTypes.flow';
15
15
  import typeof Yargs from 'yargs';
16
16
 
17
17
  const {makeAsyncCommand} = require('../cli-utils');
18
- const MetroApi = require('../index');
19
18
  const TerminalReporter = require('../lib/TerminalReporter');
20
19
  const {loadConfig} = require('metro-config');
21
20
  const {Terminal} = require('metro-core');
@@ -66,6 +65,9 @@ module.exports = (): ({
66
65
  // $FlowExpectedError YargArguments and RunBuildOptions are used interchangeable but their types are not yet compatible
67
66
  const options = (argv: RunBuildOptions);
68
67
 
68
+ // Inline require() to avoid circular dependency with ../index
69
+ const MetroApi = require('../index');
70
+
69
71
  await MetroApi.runBuild(config, {
70
72
  ...options,
71
73
  onBegin: (): void => {
@@ -11,8 +11,6 @@
11
11
 
12
12
  const { makeAsyncCommand, watchFile } = require("../cli-utils");
13
13
 
14
- const MetroApi = require("../index");
15
-
16
14
  const { loadConfig, resolveConfig } = require("metro-config");
17
15
 
18
16
  const { promisify } = require("util");
@@ -93,7 +91,9 @@ module.exports = () => ({
93
91
  await promisify(server.close).call(server);
94
92
  }
95
93
 
96
- const config = await loadConfig(argv); // $FlowExpectedError YargArguments and RunBuildOptions are used interchangeable but their types are not yet compatible
94
+ const config = await loadConfig(argv); // Inline require() to avoid circular dependency with ../index
95
+
96
+ const MetroApi = require("../index"); // $FlowExpectedError YargArguments and RunBuildOptions are used interchangeable but their types are not yet compatible
97
97
 
98
98
  server = await MetroApi.runServer(config, argv);
99
99
  restarting = false;
@@ -15,7 +15,6 @@ import type {YargArguments} from 'metro-config/src/configTypes.flow';
15
15
  import typeof Yargs from 'yargs';
16
16
 
17
17
  const {makeAsyncCommand, watchFile} = require('../cli-utils');
18
- const MetroApi = require('../index');
19
18
  const {loadConfig, resolveConfig} = require('metro-config');
20
19
  const {promisify} = require('util');
21
20
 
@@ -84,6 +83,9 @@ module.exports = (): ({
84
83
 
85
84
  const config = await loadConfig(argv);
86
85
 
86
+ // Inline require() to avoid circular dependency with ../index
87
+ const MetroApi = require('../index');
88
+
87
89
  // $FlowExpectedError YargArguments and RunBuildOptions are used interchangeable but their types are not yet compatible
88
90
  server = await MetroApi.runServer(config, (argv: RunServerOptions));
89
91