metro 0.71.1 → 0.72.0
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.
- package/package.json +22 -22
- package/src/Assets.js +3 -2
- package/src/Assets.js.flow +3 -2
- package/src/Bundler.js +0 -2
- package/src/Bundler.js.flow +1 -1
- package/src/DeltaBundler/DeltaCalculator.js +2 -0
- package/src/DeltaBundler/DeltaCalculator.js.flow +2 -0
- package/src/DeltaBundler/WorkerFarm.js.flow +2 -2
- package/src/DeltaBundler/graphOperations.js +50 -47
- package/src/DeltaBundler/graphOperations.js.flow +46 -52
- package/src/DeltaBundler/types.flow.js +6 -0
- package/src/DeltaBundler/types.flow.js.flow +12 -3
- package/src/DeltaBundler.js +0 -2
- package/src/DeltaBundler.js.flow +1 -1
- package/src/HmrServer.js +0 -2
- package/src/HmrServer.js.flow +1 -2
- package/src/ModuleGraph/node-haste/node-haste.flow.js +0 -1
- package/src/ModuleGraph/node-haste/node-haste.flow.js.flow +1 -2
- package/src/ModuleGraph/node-haste/node-haste.js +12 -3
- package/src/ModuleGraph/node-haste/node-haste.js.flow +34 -7
- package/src/ModuleGraph/output/util.js +1 -0
- package/src/ModuleGraph/output/util.js.flow +3 -2
- package/src/ModuleGraph/silent-console.js +5 -4
- package/src/ModuleGraph/silent-console.js.flow +8 -4
- package/src/ModuleGraph/worker/collectDependencies.js +229 -33
- package/src/ModuleGraph/worker/collectDependencies.js.flow +250 -48
- package/src/Server.js +4 -0
- package/src/Server.js.flow +11 -2
- package/src/cli-utils.js.flow +1 -1
- package/src/commands/build.js +1 -2
- package/src/commands/build.js.flow +6 -9
- package/src/commands/dependencies.js +1 -1
- package/src/commands/serve.js +2 -1
- package/src/commands/serve.js.flow +7 -8
- package/src/index.flow.js +11 -8
- package/src/index.flow.js.flow +10 -7
- package/src/lib/CountingSet.js +116 -0
- package/src/lib/CountingSet.js.flow +126 -0
- package/src/lib/JsonReporter.js +0 -2
- package/src/lib/JsonReporter.js.flow +1 -1
- package/src/lib/getAppendScripts.js +10 -4
- package/src/lib/getAppendScripts.js.flow +6 -4
- package/src/lib/getPreludeCode.js +19 -1
- package/src/lib/getPreludeCode.js.flow +15 -0
- package/src/lib/getPrependedScripts.js +10 -2
- package/src/lib/getPrependedScripts.js.flow +11 -2
- package/src/lib/reporting.js +0 -2
- package/src/lib/reporting.js.flow +2 -1
- package/src/node-haste/DependencyGraph/createHasteMap.js +8 -1
- package/src/node-haste/DependencyGraph/createHasteMap.js.flow +9 -2
- package/src/node-haste/DependencyGraph.js +2 -2
- package/src/node-haste/DependencyGraph.js.flow +4 -2
- package/src/shared/output/bundle.flow.js +67 -0
- package/src/shared/output/bundle.flow.js.flow +89 -0
- package/src/shared/output/bundle.js +8 -55
- package/src/shared/output/bundle.js.flow +8 -75
|
@@ -10,8 +10,6 @@
|
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
|
-
'use strict';
|
|
14
|
-
|
|
15
13
|
type ModuleID = string;
|
|
16
14
|
export type Path = string;
|
|
17
15
|
type Platform = string;
|
|
@@ -63,6 +61,7 @@ type HasteMapOptions = {
|
|
|
63
61
|
preferNativePlatform: true,
|
|
64
62
|
};
|
|
65
63
|
|
|
64
|
+
// eslint-disable-next-line no-unused-vars
|
|
66
65
|
declare class HasteMap {
|
|
67
66
|
// node-haste/DependencyGraph/HasteMap.js
|
|
68
67
|
build(): Promise<Object>;
|
|
@@ -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 = ({
|
|
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.
|
|
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(),
|
|
@@ -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 {
|
|
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
|
-
|
|
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.
|
|
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({
|
|
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
|
}),
|
|
@@ -62,11 +62,11 @@ type InlineModuleIdsOptions = $ReadOnly<{
|
|
|
62
62
|
}>;
|
|
63
63
|
|
|
64
64
|
// TS detection conditions copied from metro-react-native-babel-preset
|
|
65
|
-
function isTypeScriptSource(fileName) {
|
|
65
|
+
function isTypeScriptSource(fileName: string) {
|
|
66
66
|
return !!fileName && fileName.endsWith('.ts');
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
function isTSXSource(fileName) {
|
|
69
|
+
function isTSXSource(fileName: string) {
|
|
70
70
|
return !!fileName && fileName.endsWith('.tsx');
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -181,6 +181,7 @@ function inlineModuleIds(
|
|
|
181
181
|
? parseSync(code, babelConfig)
|
|
182
182
|
: HermesParser.parse(code, {
|
|
183
183
|
babel: true,
|
|
184
|
+
// $FlowFixMe[prop-missing]
|
|
184
185
|
sourceType: babelConfig.sourceType,
|
|
185
186
|
});
|
|
186
187
|
|
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
const { Console } = require("console");
|
|
13
13
|
|
|
14
14
|
const { Writable } = require("stream");
|
|
15
|
-
/* $FlowFixMe(>=0.97.0 site=react_native_fb) This comment suppresses an error
|
|
16
|
-
* found when Flow v0.97 was deployed. To see the error delete this comment and
|
|
17
|
-
* run Flow. */
|
|
18
15
|
|
|
19
|
-
const write = (_, __, callback) =>
|
|
16
|
+
const write = (_, __, callback) =>
|
|
17
|
+
/* $FlowFixMe(>=0.97.0 site=react_native_fb) This comment suppresses an error
|
|
18
|
+
* found when Flow v0.97 was deployed. To see the error delete this comment and
|
|
19
|
+
* run Flow. */
|
|
20
|
+
callback();
|
|
20
21
|
|
|
21
22
|
module.exports = new Console(
|
|
22
23
|
new Writable({
|
|
@@ -13,8 +13,12 @@
|
|
|
13
13
|
const {Console} = require('console');
|
|
14
14
|
const {Writable} = require('stream');
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
const write = (
|
|
17
|
+
_: Buffer | string | Array<{chunk: Buffer | string, encoding: string, ...}>,
|
|
18
|
+
__: string | ((error?: Error) => void),
|
|
19
|
+
callback: void | ((error?: Error) => void),
|
|
20
|
+
/* $FlowFixMe(>=0.97.0 site=react_native_fb) This comment suppresses an error
|
|
21
|
+
* found when Flow v0.97 was deployed. To see the error delete this comment and
|
|
22
|
+
* run Flow. */
|
|
23
|
+
) => callback();
|
|
20
24
|
module.exports = (new Console(new Writable({write, writev: write})): Console);
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
"use strict";
|
|
11
11
|
|
|
12
|
+
const crypto = require("crypto");
|
|
13
|
+
|
|
12
14
|
const generate = require("@babel/generator").default;
|
|
13
15
|
|
|
14
16
|
const template = require("@babel/template").default;
|
|
@@ -53,6 +55,7 @@ function collectDependencies(ast, options) {
|
|
|
53
55
|
dynamicRequires: options.dynamicRequires,
|
|
54
56
|
keepRequireNames: options.keepRequireNames,
|
|
55
57
|
allowOptionalDependencies: options.allowOptionalDependencies,
|
|
58
|
+
unstable_allowRequireContext: options.unstable_allowRequireContext,
|
|
56
59
|
};
|
|
57
60
|
const visitor = {
|
|
58
61
|
CallExpression(path, state) {
|
|
@@ -97,6 +100,22 @@ function collectDependencies(ast, options) {
|
|
|
97
100
|
splitCondition: args[1],
|
|
98
101
|
});
|
|
99
102
|
return;
|
|
103
|
+
} // Match `require.context`
|
|
104
|
+
|
|
105
|
+
if (
|
|
106
|
+
// Feature gate, defaults to `false`.
|
|
107
|
+
state.unstable_allowRequireContext &&
|
|
108
|
+
callee.type === "MemberExpression" && // `require`
|
|
109
|
+
callee.object.type === "Identifier" &&
|
|
110
|
+
callee.object.name === "require" && // `context`
|
|
111
|
+
callee.property.type === "Identifier" &&
|
|
112
|
+
callee.property.name === "context" &&
|
|
113
|
+
!callee.computed && // Ensure `require` refers to the global and not something else.
|
|
114
|
+
!path.scope.getBinding("require")
|
|
115
|
+
) {
|
|
116
|
+
processRequireContextCall(path, state);
|
|
117
|
+
visited.add(path.node);
|
|
118
|
+
return;
|
|
100
119
|
}
|
|
101
120
|
|
|
102
121
|
if (
|
|
@@ -148,6 +167,146 @@ function collectDependencies(ast, options) {
|
|
|
148
167
|
dependencyMapName: nullthrows(state.dependencyMapIdentifier).name,
|
|
149
168
|
};
|
|
150
169
|
}
|
|
170
|
+
/** Extract args passed to the `require.context` method. */
|
|
171
|
+
|
|
172
|
+
function getRequireContextArgs(path) {
|
|
173
|
+
const args = path.get("arguments");
|
|
174
|
+
let directory;
|
|
175
|
+
|
|
176
|
+
if (!Array.isArray(args) || args.length < 1) {
|
|
177
|
+
throw new InvalidRequireCallError(path);
|
|
178
|
+
} else {
|
|
179
|
+
const result = args[0].evaluate();
|
|
180
|
+
|
|
181
|
+
if (result.confident && typeof result.value === "string") {
|
|
182
|
+
directory = result.value;
|
|
183
|
+
} else {
|
|
184
|
+
var _result$deopt;
|
|
185
|
+
|
|
186
|
+
throw new InvalidRequireCallError(
|
|
187
|
+
(_result$deopt = result.deopt) !== null && _result$deopt !== void 0
|
|
188
|
+
? _result$deopt
|
|
189
|
+
: args[0],
|
|
190
|
+
"First argument of `require.context` should be a string denoting the directory to require."
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
} // Default to requiring through all directories.
|
|
194
|
+
|
|
195
|
+
let recursive = true;
|
|
196
|
+
|
|
197
|
+
if (args.length > 1) {
|
|
198
|
+
const result = args[1].evaluate();
|
|
199
|
+
|
|
200
|
+
if (result.confident && typeof result.value === "boolean") {
|
|
201
|
+
recursive = result.value;
|
|
202
|
+
} else if (!(result.confident && typeof result.value === "undefined")) {
|
|
203
|
+
var _result$deopt2;
|
|
204
|
+
|
|
205
|
+
throw new InvalidRequireCallError(
|
|
206
|
+
(_result$deopt2 = result.deopt) !== null && _result$deopt2 !== void 0
|
|
207
|
+
? _result$deopt2
|
|
208
|
+
: args[1],
|
|
209
|
+
"Second argument of `require.context` should be an optional boolean indicating if files should be imported recursively or not."
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
} // Default to all files.
|
|
213
|
+
|
|
214
|
+
let filter = {
|
|
215
|
+
pattern: ".*",
|
|
216
|
+
flags: "",
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
if (args.length > 2) {
|
|
220
|
+
// evaluate() to check for undefined (because it's technically a scope lookup)
|
|
221
|
+
// but check the AST for the regex literal, since evaluate() doesn't do regex.
|
|
222
|
+
const result = args[2].evaluate();
|
|
223
|
+
const argNode = args[2].node;
|
|
224
|
+
|
|
225
|
+
if (argNode.type === "RegExpLiteral") {
|
|
226
|
+
// TODO: Handle `new RegExp(...)` -- `argNode.type === 'NewExpression'`
|
|
227
|
+
filter = {
|
|
228
|
+
pattern: argNode.pattern,
|
|
229
|
+
flags: argNode.flags || "",
|
|
230
|
+
};
|
|
231
|
+
} else if (!(result.confident && typeof result.value === "undefined")) {
|
|
232
|
+
throw new InvalidRequireCallError(
|
|
233
|
+
args[2],
|
|
234
|
+
`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}.`
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
} // Default to `sync`.
|
|
238
|
+
|
|
239
|
+
let mode = "sync";
|
|
240
|
+
|
|
241
|
+
if (args.length > 3) {
|
|
242
|
+
const result = args[3].evaluate();
|
|
243
|
+
|
|
244
|
+
if (result.confident && typeof result.value === "string") {
|
|
245
|
+
mode = getContextMode(args[3], result.value);
|
|
246
|
+
} else if (!(result.confident && typeof result.value === "undefined")) {
|
|
247
|
+
var _result$deopt3;
|
|
248
|
+
|
|
249
|
+
throw new InvalidRequireCallError(
|
|
250
|
+
(_result$deopt3 = result.deopt) !== null && _result$deopt3 !== void 0
|
|
251
|
+
? _result$deopt3
|
|
252
|
+
: args[3],
|
|
253
|
+
'Fourth argument of `require.context` should be an optional string "mode" denoting how the modules will be resolved.'
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (args.length > 4) {
|
|
259
|
+
throw new InvalidRequireCallError(
|
|
260
|
+
path,
|
|
261
|
+
`Too many arguments provided to \`require.context\` call. Expected 4, got: ${args.length}`
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return [
|
|
266
|
+
directory,
|
|
267
|
+
{
|
|
268
|
+
recursive,
|
|
269
|
+
filter,
|
|
270
|
+
mode,
|
|
271
|
+
},
|
|
272
|
+
];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function getContextMode(path, mode) {
|
|
276
|
+
if (
|
|
277
|
+
mode === "sync" ||
|
|
278
|
+
mode === "eager" ||
|
|
279
|
+
mode === "lazy" ||
|
|
280
|
+
mode === "lazy-once"
|
|
281
|
+
) {
|
|
282
|
+
return mode;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
throw new InvalidRequireCallError(
|
|
286
|
+
path,
|
|
287
|
+
`require.context "${mode}" mode is not supported. Expected one of: sync, eager, lazy, lazy-once`
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function processRequireContextCall(path, state) {
|
|
292
|
+
const [directory, contextParams] = getRequireContextArgs(path);
|
|
293
|
+
const transformer = state.dependencyTransformer;
|
|
294
|
+
const dep = registerDependency(
|
|
295
|
+
state,
|
|
296
|
+
{
|
|
297
|
+
// We basically want to "import" every file in a folder and then filter them out with the given `filter` RegExp.
|
|
298
|
+
name: directory,
|
|
299
|
+
// Capture the matching context
|
|
300
|
+
contextParams,
|
|
301
|
+
asyncType: null,
|
|
302
|
+
optional: isOptionalDependency(directory, path, state),
|
|
303
|
+
},
|
|
304
|
+
path
|
|
305
|
+
); // require() the generated module representing this context
|
|
306
|
+
|
|
307
|
+
path.get("callee").replaceWith(types.identifier("require"));
|
|
308
|
+
transformer.transformSyncRequire(path, dep, state);
|
|
309
|
+
}
|
|
151
310
|
|
|
152
311
|
function collectImports(path, state) {
|
|
153
312
|
if (path.node.source) {
|
|
@@ -309,10 +468,15 @@ function getModuleNameFromCallArgs(path) {
|
|
|
309
468
|
collectDependencies.getModuleNameFromCallArgs = getModuleNameFromCallArgs;
|
|
310
469
|
|
|
311
470
|
class InvalidRequireCallError extends Error {
|
|
312
|
-
constructor({ node }) {
|
|
471
|
+
constructor({ node }, message) {
|
|
313
472
|
const line = node.loc && node.loc.start && node.loc.start.line;
|
|
314
473
|
super(
|
|
315
|
-
|
|
474
|
+
[
|
|
475
|
+
`Invalid call at line ${line || "<unknown>"}: ${generate(node).code}`,
|
|
476
|
+
message,
|
|
477
|
+
]
|
|
478
|
+
.filter(Boolean)
|
|
479
|
+
.join("\n")
|
|
316
480
|
);
|
|
317
481
|
}
|
|
318
482
|
}
|
|
@@ -348,9 +512,11 @@ const makeJSResourceTemplate = template.statement(`
|
|
|
348
512
|
const DefaultDependencyTransformer = {
|
|
349
513
|
transformSyncRequire(path, dependency, state) {
|
|
350
514
|
const moduleIDExpression = createModuleIDExpression(dependency, state);
|
|
351
|
-
path.node.arguments =
|
|
352
|
-
|
|
353
|
-
|
|
515
|
+
path.node.arguments = [moduleIDExpression]; // Always add the debug name argument last
|
|
516
|
+
|
|
517
|
+
if (state.keepRequireNames) {
|
|
518
|
+
path.node.arguments.push(types.stringLiteral(dependency.name));
|
|
519
|
+
}
|
|
354
520
|
},
|
|
355
521
|
|
|
356
522
|
transformImportCall(path, dependency, state) {
|
|
@@ -420,12 +586,58 @@ function createModuleIDExpression(dependency, state) {
|
|
|
420
586
|
function createModuleNameLiteral(dependency) {
|
|
421
587
|
return types.stringLiteral(dependency.name);
|
|
422
588
|
}
|
|
589
|
+
/**
|
|
590
|
+
* Given an import qualifier, return a key used to register the dependency.
|
|
591
|
+
* Generally this return the `ImportQualifier.name` property, but more
|
|
592
|
+
* attributes can be appended to distinguish various combinations that would
|
|
593
|
+
* otherwise conflict.
|
|
594
|
+
*
|
|
595
|
+
* For example, the following case would have collision issues if they all utilized the `name` property:
|
|
596
|
+
* ```
|
|
597
|
+
* require('./foo');
|
|
598
|
+
* require.context('./foo');
|
|
599
|
+
* require.context('./foo', true, /something/);
|
|
600
|
+
* require.context('./foo', false, /something/);
|
|
601
|
+
* require.context('./foo', false, /something/, 'lazy');
|
|
602
|
+
* ```
|
|
603
|
+
*
|
|
604
|
+
* This method should be utilized by `registerDependency`.
|
|
605
|
+
*/
|
|
606
|
+
|
|
607
|
+
function getKeyForDependency(qualifier) {
|
|
608
|
+
let key = qualifier.name;
|
|
609
|
+
const { asyncType } = qualifier;
|
|
610
|
+
|
|
611
|
+
if (asyncType) {
|
|
612
|
+
key += ["", asyncType].join("\0");
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
const { contextParams } = qualifier; // Add extra qualifiers when using `require.context` to prevent collisions.
|
|
616
|
+
|
|
617
|
+
if (contextParams) {
|
|
618
|
+
// NOTE(EvanBacon): Keep this synchronized with `RequireContextParams`, if any other properties are added
|
|
619
|
+
// then this key algorithm should be updated to account for those properties.
|
|
620
|
+
// Example: `./directory__true__/foobar/m__lazy`
|
|
621
|
+
key += [
|
|
622
|
+
"",
|
|
623
|
+
"context",
|
|
624
|
+
String(contextParams.recursive),
|
|
625
|
+
String(contextParams.filter.pattern),
|
|
626
|
+
String(contextParams.filter.flags),
|
|
627
|
+
contextParams.mode, // Join together and append to the name:
|
|
628
|
+
].join("\0");
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
return key;
|
|
632
|
+
}
|
|
423
633
|
|
|
424
634
|
class DefaultModuleDependencyRegistry {
|
|
425
635
|
_dependencies = new Map();
|
|
426
636
|
|
|
427
637
|
registerDependency(qualifier) {
|
|
428
|
-
|
|
638
|
+
const key = getKeyForDependency(qualifier);
|
|
639
|
+
|
|
640
|
+
let dependency = this._dependencies.get(key);
|
|
429
641
|
|
|
430
642
|
if (dependency == null) {
|
|
431
643
|
const newDependency = {
|
|
@@ -433,24 +645,28 @@ class DefaultModuleDependencyRegistry {
|
|
|
433
645
|
asyncType: qualifier.asyncType,
|
|
434
646
|
locs: [],
|
|
435
647
|
index: this._dependencies.size,
|
|
648
|
+
key: crypto.createHash("sha1").update(key).digest("base64"),
|
|
436
649
|
};
|
|
437
650
|
|
|
438
651
|
if (qualifier.optional) {
|
|
439
652
|
newDependency.isOptional = true;
|
|
440
653
|
}
|
|
441
654
|
|
|
442
|
-
|
|
655
|
+
if (qualifier.contextParams) {
|
|
656
|
+
newDependency.contextParams = qualifier.contextParams;
|
|
657
|
+
}
|
|
443
658
|
|
|
444
|
-
|
|
659
|
+
dependency = newDependency;
|
|
445
660
|
} else {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
this._dependencies.set(qualifier.name, dependency);
|
|
661
|
+
if (dependency.isOptional && !qualifier.optional) {
|
|
662
|
+
// A previously optionally required dependency was required non-optionally.
|
|
663
|
+
// Mark it non optional for the whole module
|
|
664
|
+
dependency = { ...dependency, isOptional: false };
|
|
451
665
|
}
|
|
452
666
|
}
|
|
453
667
|
|
|
668
|
+
this._dependencies.set(key, dependency);
|
|
669
|
+
|
|
454
670
|
return dependency;
|
|
455
671
|
}
|
|
456
672
|
|
|
@@ -459,24 +675,4 @@ class DefaultModuleDependencyRegistry {
|
|
|
459
675
|
}
|
|
460
676
|
}
|
|
461
677
|
|
|
462
|
-
function collapseDependencies(dependency, qualifier) {
|
|
463
|
-
let collapsed = dependency; // A previously optionally required dependency was required non-optionaly.
|
|
464
|
-
// Mark it non optional for the whole module
|
|
465
|
-
|
|
466
|
-
if (collapsed.isOptional && !qualifier.optional) {
|
|
467
|
-
collapsed = { ...dependency, isOptional: false };
|
|
468
|
-
} // A previously asynchronously (or prefetch) required module was required synchronously.
|
|
469
|
-
// Make the dependency sync.
|
|
470
|
-
|
|
471
|
-
if (collapsed.asyncType != null && qualifier.asyncType == null) {
|
|
472
|
-
collapsed = { ...dependency, asyncType: null };
|
|
473
|
-
} // A prefetched dependency was required async in the module. Mark it as async.
|
|
474
|
-
|
|
475
|
-
if (collapsed.asyncType === "prefetch" && qualifier.asyncType === "async") {
|
|
476
|
-
collapsed = { ...dependency, asyncType: "async" };
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
return collapsed;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
678
|
module.exports = collectDependencies;
|