metro 0.80.2 → 0.80.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.
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true,
5
+ });
6
+ exports.buildSubgraph = buildSubgraph;
7
+ var _contextModule = require("../lib/contextModule");
8
+ var _path = _interopRequireDefault(require("path"));
9
+ function _interopRequireDefault(obj) {
10
+ return obj && obj.__esModule ? obj : { default: obj };
11
+ }
12
+ /**
13
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
14
+ *
15
+ * This source code is licensed under the MIT license found in the
16
+ * LICENSE file in the root directory of this source tree.
17
+ *
18
+ *
19
+ * @format
20
+ */
21
+
22
+ function resolveDependencies(parentPath, dependencies, resolve) {
23
+ const maybeResolvedDeps = new Map();
24
+ const resolvedContexts = new Map();
25
+ for (const dep of dependencies) {
26
+ let resolvedDep;
27
+ const key = dep.data.key;
28
+
29
+ // `require.context`
30
+ const { contextParams } = dep.data;
31
+ if (contextParams) {
32
+ // Ensure the filepath has uniqueness applied to ensure multiple `require.context`
33
+ // statements can be used to target the same file with different properties.
34
+ const from = _path.default.join(parentPath, "..", dep.name);
35
+ const absolutePath = (0, _contextModule.deriveAbsolutePathFromContext)(
36
+ from,
37
+ contextParams
38
+ );
39
+ const resolvedContext = {
40
+ from,
41
+ mode: contextParams.mode,
42
+ recursive: contextParams.recursive,
43
+ filter: new RegExp(
44
+ contextParams.filter.pattern,
45
+ contextParams.filter.flags
46
+ ),
47
+ };
48
+ resolvedContexts.set(key, resolvedContext);
49
+ resolvedDep = {
50
+ absolutePath,
51
+ data: dep,
52
+ };
53
+ } else {
54
+ try {
55
+ resolvedDep = {
56
+ absolutePath: resolve(parentPath, dep).filePath,
57
+ data: dep,
58
+ };
59
+ } catch (error) {
60
+ // Ignore unavailable optional dependencies. They are guarded
61
+ // with a try-catch block and will be handled during runtime.
62
+ if (dep.data.isOptional !== true) {
63
+ throw error;
64
+ }
65
+ }
66
+ }
67
+ if (maybeResolvedDeps.has(key)) {
68
+ throw new Error(
69
+ `resolveDependencies: Found duplicate dependency key '${key}' in ${parentPath}`
70
+ );
71
+ }
72
+ maybeResolvedDeps.set(key, resolvedDep);
73
+ }
74
+ const resolvedDeps = new Map();
75
+ // Return just the dependencies we successfully resolved.
76
+ // FIXME: This has a bad bug affecting all dependencies *after* an unresolved
77
+ // optional dependency. We'll need to propagate the nulls all the way to the
78
+ // serializer and the require() runtime to keep the dependency map from being
79
+ // desynced from the contents of the module.
80
+ for (const [key, resolvedDep] of maybeResolvedDeps) {
81
+ if (resolvedDep) {
82
+ resolvedDeps.set(key, resolvedDep);
83
+ }
84
+ }
85
+ return {
86
+ dependencies: resolvedDeps,
87
+ resolvedContexts,
88
+ };
89
+ }
90
+ async function buildSubgraph(
91
+ entryPaths,
92
+ resolvedContexts,
93
+ { resolve, transform, shouldTraverse }
94
+ ) {
95
+ const moduleData = new Map();
96
+ const errors = new Map();
97
+ const visitedPaths = new Set();
98
+ async function visit(absolutePath, requireContext) {
99
+ if (visitedPaths.has(absolutePath)) {
100
+ return;
101
+ }
102
+ visitedPaths.add(absolutePath);
103
+ const transformResult = await transform(absolutePath, requireContext);
104
+
105
+ // Get the absolute path of all sub-dependencies (some of them could have been
106
+ // moved but maintain the same relative path).
107
+ const resolutionResult = resolveDependencies(
108
+ absolutePath,
109
+ transformResult.dependencies,
110
+ resolve
111
+ );
112
+ moduleData.set(absolutePath, {
113
+ ...transformResult,
114
+ ...resolutionResult,
115
+ });
116
+ await Promise.all(
117
+ [...resolutionResult.dependencies]
118
+ .filter(([key, dependency]) => shouldTraverse(dependency))
119
+ .map(([key, dependency]) =>
120
+ visit(
121
+ dependency.absolutePath,
122
+ resolutionResult.resolvedContexts.get(dependency.data.data.key)
123
+ ).catch((error) => errors.set(dependency.absolutePath, error))
124
+ )
125
+ );
126
+ }
127
+ await Promise.all(
128
+ [...entryPaths].map((absolutePath) =>
129
+ visit(absolutePath, resolvedContexts.get(absolutePath)).catch((error) =>
130
+ errors.set(absolutePath, error)
131
+ )
132
+ )
133
+ );
134
+ return {
135
+ moduleData,
136
+ errors,
137
+ };
138
+ }
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict-local
8
+ * @format
9
+ */
10
+
11
+ import type {RequireContext} from '../lib/contextModule';
12
+ import type {
13
+ Dependency,
14
+ ModuleData,
15
+ ResolveFn,
16
+ TransformFn,
17
+ TransformResultDependency,
18
+ } from './types.flow';
19
+
20
+ import {deriveAbsolutePathFromContext} from '../lib/contextModule';
21
+ import path from 'path';
22
+
23
+ type Parameters<T> = $ReadOnly<{
24
+ resolve: ResolveFn,
25
+ transform: TransformFn<T>,
26
+ shouldTraverse: Dependency => boolean,
27
+ }>;
28
+
29
+ function resolveDependencies(
30
+ parentPath: string,
31
+ dependencies: $ReadOnlyArray<TransformResultDependency>,
32
+ resolve: ResolveFn,
33
+ ): {
34
+ dependencies: Map<string, Dependency>,
35
+ resolvedContexts: Map<string, RequireContext>,
36
+ } {
37
+ const maybeResolvedDeps = new Map<string, void | Dependency>();
38
+ const resolvedContexts = new Map<string, RequireContext>();
39
+
40
+ for (const dep of dependencies) {
41
+ let resolvedDep;
42
+ const key = dep.data.key;
43
+
44
+ // `require.context`
45
+ const {contextParams} = dep.data;
46
+ if (contextParams) {
47
+ // Ensure the filepath has uniqueness applied to ensure multiple `require.context`
48
+ // statements can be used to target the same file with different properties.
49
+ const from = path.join(parentPath, '..', dep.name);
50
+ const absolutePath = deriveAbsolutePathFromContext(from, contextParams);
51
+
52
+ const resolvedContext: RequireContext = {
53
+ from,
54
+ mode: contextParams.mode,
55
+ recursive: contextParams.recursive,
56
+ filter: new RegExp(
57
+ contextParams.filter.pattern,
58
+ contextParams.filter.flags,
59
+ ),
60
+ };
61
+
62
+ resolvedContexts.set(key, resolvedContext);
63
+
64
+ resolvedDep = {
65
+ absolutePath,
66
+ data: dep,
67
+ };
68
+ } else {
69
+ try {
70
+ resolvedDep = {
71
+ absolutePath: resolve(parentPath, dep).filePath,
72
+ data: dep,
73
+ };
74
+ } catch (error) {
75
+ // Ignore unavailable optional dependencies. They are guarded
76
+ // with a try-catch block and will be handled during runtime.
77
+ if (dep.data.isOptional !== true) {
78
+ throw error;
79
+ }
80
+ }
81
+ }
82
+
83
+ if (maybeResolvedDeps.has(key)) {
84
+ throw new Error(
85
+ `resolveDependencies: Found duplicate dependency key '${key}' in ${parentPath}`,
86
+ );
87
+ }
88
+ maybeResolvedDeps.set(key, resolvedDep);
89
+ }
90
+
91
+ const resolvedDeps = new Map<string, Dependency>();
92
+ // Return just the dependencies we successfully resolved.
93
+ // FIXME: This has a bad bug affecting all dependencies *after* an unresolved
94
+ // optional dependency. We'll need to propagate the nulls all the way to the
95
+ // serializer and the require() runtime to keep the dependency map from being
96
+ // desynced from the contents of the module.
97
+ for (const [key, resolvedDep] of maybeResolvedDeps) {
98
+ if (resolvedDep) {
99
+ resolvedDeps.set(key, resolvedDep);
100
+ }
101
+ }
102
+ return {dependencies: resolvedDeps, resolvedContexts};
103
+ }
104
+
105
+ export async function buildSubgraph<T>(
106
+ entryPaths: $ReadOnlySet<string>,
107
+ resolvedContexts: $ReadOnlyMap<string, ?RequireContext>,
108
+ {resolve, transform, shouldTraverse}: Parameters<T>,
109
+ ): Promise<{
110
+ moduleData: Map<string, ModuleData<T>>,
111
+ errors: Map<string, Error>,
112
+ }> {
113
+ const moduleData: Map<string, ModuleData<T>> = new Map();
114
+ const errors: Map<string, Error> = new Map();
115
+ const visitedPaths: Set<string> = new Set();
116
+
117
+ async function visit(
118
+ absolutePath: string,
119
+ requireContext: ?RequireContext,
120
+ ): Promise<void> {
121
+ if (visitedPaths.has(absolutePath)) {
122
+ return;
123
+ }
124
+ visitedPaths.add(absolutePath);
125
+ const transformResult = await transform(absolutePath, requireContext);
126
+
127
+ // Get the absolute path of all sub-dependencies (some of them could have been
128
+ // moved but maintain the same relative path).
129
+ const resolutionResult = resolveDependencies(
130
+ absolutePath,
131
+ transformResult.dependencies,
132
+ resolve,
133
+ );
134
+
135
+ moduleData.set(absolutePath, {
136
+ ...transformResult,
137
+ ...resolutionResult,
138
+ });
139
+
140
+ await Promise.all(
141
+ [...resolutionResult.dependencies]
142
+ .filter(([key, dependency]) => shouldTraverse(dependency))
143
+ .map(([key, dependency]) =>
144
+ visit(
145
+ dependency.absolutePath,
146
+ resolutionResult.resolvedContexts.get(dependency.data.data.key),
147
+ ).catch(error => errors.set(dependency.absolutePath, error)),
148
+ ),
149
+ );
150
+ }
151
+
152
+ await Promise.all(
153
+ [...entryPaths].map(absolutePath =>
154
+ visit(absolutePath, resolvedContexts.get(absolutePath)).catch(error =>
155
+ errors.set(absolutePath, error),
156
+ ),
157
+ ),
158
+ );
159
+
160
+ return {moduleData, errors};
161
+ }
@@ -25,41 +25,41 @@ export type MixedOutput = {
25
25
 
26
26
  export type AsyncDependencyType = 'async' | 'prefetch' | 'weak';
27
27
 
28
- export type TransformResultDependency = {
28
+ export type TransformResultDependency = $ReadOnly<{
29
29
  /**
30
30
  * The literal name provided to a require or import call. For example 'foo' in
31
31
  * case of `require('foo')`.
32
32
  */
33
- +name: string,
33
+ name: string,
34
34
 
35
35
  /**
36
36
  * Extra data returned by the dependency extractor.
37
37
  */
38
- +data: {
38
+ data: $ReadOnly<{
39
39
  /**
40
40
  * A locally unique key for this dependency within the current module.
41
41
  */
42
- +key: string,
42
+ key: string,
43
43
  /**
44
44
  * If not null, this dependency is due to a dynamic `import()` or `__prefetchImport()` call.
45
45
  */
46
- +asyncType: AsyncDependencyType | null,
46
+ asyncType: AsyncDependencyType | null,
47
47
  /**
48
48
  * The dependency is enclosed in a try/catch block.
49
49
  */
50
- +isOptional?: boolean,
50
+ isOptional?: boolean,
51
51
 
52
- +locs: $ReadOnlyArray<BabelSourceLocation>,
52
+ locs: $ReadOnlyArray<BabelSourceLocation>,
53
53
 
54
54
  /** Context for requiring a collection of modules. */
55
- +contextParams?: RequireContextParams,
56
- },
57
- };
55
+ contextParams?: RequireContextParams,
56
+ }>,
57
+ }>;
58
58
 
59
- export type Dependency = {
60
- +absolutePath: string,
61
- +data: TransformResultDependency,
62
- };
59
+ export type Dependency = $ReadOnly<{
60
+ absolutePath: string,
61
+ data: TransformResultDependency,
62
+ }>;
63
63
 
64
64
  export type Module<T = MixedOutput> = $ReadOnly<{
65
65
  dependencies: Map<string, Dependency>,
@@ -70,6 +70,14 @@ export type Module<T = MixedOutput> = $ReadOnly<{
70
70
  unstable_transformResultKey?: ?string,
71
71
  }>;
72
72
 
73
+ export type ModuleData<T = MixedOutput> = $ReadOnly<{
74
+ dependencies: $ReadOnlyMap<string, Dependency>,
75
+ resolvedContexts: $ReadOnlyMap<string, RequireContext>,
76
+ output: $ReadOnlyArray<T>,
77
+ getSource: () => Buffer,
78
+ unstable_transformResultKey?: ?string,
79
+ }>;
80
+
73
81
  export type Dependencies<T = MixedOutput> = Map<string, Module<T>>;
74
82
  export type ReadOnlyDependencies<T = MixedOutput> = $ReadOnlyMap<
75
83
  string,
@@ -115,6 +123,12 @@ export type TransformFn<T = MixedOutput> = (
115
123
  string,
116
124
  ?RequireContext,
117
125
  ) => Promise<TransformResultWithSource<T>>;
126
+
127
+ export type ResolveFn = (
128
+ from: string,
129
+ dependency: TransformResultDependency,
130
+ ) => BundlerResolution;
131
+
118
132
  export type AllowOptionalDependenciesWithOptions = {
119
133
  +exclude: Array<string>,
120
134
  };
@@ -128,10 +142,7 @@ export type BundlerResolution = $ReadOnly<{
128
142
  }>;
129
143
 
130
144
  export type Options<T = MixedOutput> = {
131
- +resolve: (
132
- from: string,
133
- dependency: TransformResultDependency,
134
- ) => BundlerResolution,
145
+ +resolve: ResolveFn,
135
146
  +transform: TransformFn<T>,
136
147
  +transformOptions: TransformInputOptions,
137
148
  +onProgress: ?(numProcessed: number, total: number) => mixed,
@@ -38,7 +38,7 @@ export type Dependency = $ReadOnly<{
38
38
  // TODO: Convert to a Flow enum
39
39
  export type ContextMode = 'sync' | 'eager' | 'lazy' | 'lazy-once';
40
40
 
41
- type ContextFilter = {pattern: string, flags: string};
41
+ type ContextFilter = $ReadOnly<{pattern: string, flags: string}>;
42
42
 
43
43
  export type RequireContextParams = $ReadOnly<{
44
44
  /* Should search for files recursively. Optional, default `true` when `require.context` is used */
package/src/index.flow.js CHANGED
@@ -321,6 +321,7 @@ exports.buildGraph = async function (
321
321
  },
322
322
  {
323
323
  customResolverOptions,
324
+ dev,
324
325
  }
325
326
  );
326
327
  } finally {
@@ -458,7 +458,7 @@ exports.buildGraph = async function (
458
458
  platform,
459
459
  type,
460
460
  },
461
- {customResolverOptions},
461
+ {customResolverOptions, dev},
462
462
  );
463
463
  } finally {
464
464
  bundler.end();
@@ -19,6 +19,7 @@ function splitBundleOptions(options) {
19
19
  entryFile: options.entryFile,
20
20
  resolverOptions: {
21
21
  customResolverOptions: options.customResolverOptions,
22
+ dev: options.dev,
22
23
  },
23
24
  transformOptions: {
24
25
  customTransformOptions: options.customTransformOptions,
@@ -21,6 +21,7 @@ function splitBundleOptions(options: BundleOptions): SplitBundleOptions {
21
21
  entryFile: options.entryFile,
22
22
  resolverOptions: {
23
23
  customResolverOptions: options.customResolverOptions,
24
+ dev: options.dev,
24
25
  },
25
26
  transformOptions: {
26
27
  customTransformOptions: options.customTransformOptions,
@@ -53,7 +53,9 @@ class ModuleResolver {
53
53
  },
54
54
  false,
55
55
  null,
56
- /* resolverOptions */ {}
56
+ /* resolverOptions */ {
57
+ dev: false,
58
+ }
57
59
  );
58
60
  this._cachedEmptyModule = emptyModule;
59
61
  }
@@ -88,6 +90,7 @@ class ModuleResolver {
88
90
  {
89
91
  allowHaste,
90
92
  assetExts,
93
+ dev: resolverOptions.dev,
91
94
  disableHierarchicalLookup,
92
95
  doesFileExist,
93
96
  extraNodeModules,
@@ -120,7 +120,7 @@ class ModuleResolver<TPackage: Packageish> {
120
120
  },
121
121
  false,
122
122
  null,
123
- /* resolverOptions */ {},
123
+ /* resolverOptions */ {dev: false},
124
124
  );
125
125
  this._cachedEmptyModule = emptyModule;
126
126
  }
@@ -157,6 +157,7 @@ class ModuleResolver<TPackage: Packageish> {
157
157
  {
158
158
  allowHaste,
159
159
  assetExts,
160
+ dev: resolverOptions.dev,
160
161
  disableHierarchicalLookup,
161
162
  doesFileExist,
162
163
  extraNodeModules,
@@ -260,10 +260,7 @@ class DependencyGraph extends EventEmitter {
260
260
 
261
261
  // Compound key for the resolver cache
262
262
  const resolverOptionsKey =
263
- JSON.stringify(
264
- resolverOptions.customResolverOptions ?? {},
265
- canonicalize
266
- ) ?? "";
263
+ JSON.stringify(resolverOptions ?? {}, canonicalize) ?? "";
267
264
  const originKey = isSensitiveToOriginFolder ? path.dirname(from) : "";
268
265
  const targetKey = to;
269
266
  const platformKey = platform ?? NULL_PLATFORM;
@@ -335,10 +335,7 @@ class DependencyGraph extends EventEmitter {
335
335
 
336
336
  // Compound key for the resolver cache
337
337
  const resolverOptionsKey =
338
- JSON.stringify(
339
- resolverOptions.customResolverOptions ?? {},
340
- canonicalize,
341
- ) ?? '';
338
+ JSON.stringify(resolverOptions ?? {}, canonicalize) ?? '';
342
339
  const originKey = isSensitiveToOriginFolder ? path.dirname(from) : '';
343
340
  const targetKey = to;
344
341
  const platformKey = platform ?? NULL_PLATFORM;
@@ -65,6 +65,7 @@ export type BundleOptions = {
65
65
 
66
66
  export type ResolverInputOptions = $ReadOnly<{
67
67
  customResolverOptions?: CustomResolverOptions,
68
+ dev: boolean,
68
69
  }>;
69
70
 
70
71
  export type SerializerOptions = {