metro 0.77.0 → 0.78.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 +20 -20
- package/src/DeltaBundler/Graph.js +1 -1
- package/src/DeltaBundler/Graph.js.flow +1 -1
- package/src/DeltaBundler/types.d.ts +2 -9
- package/src/DeltaBundler/types.flow.js.flow +4 -1
- package/src/HmrServer.js +9 -2
- package/src/HmrServer.js.flow +10 -3
- package/src/ModuleGraph/worker/collectDependencies.js +10 -2
- package/src/ModuleGraph/worker/collectDependencies.js.flow +12 -3
- package/src/Server/MultipartResponse.js +4 -0
- package/src/Server/MultipartResponse.js.flow +5 -0
- package/src/Server.js +43 -4
- package/src/Server.js.flow +42 -5
- package/src/commands/serve.js +1 -1
- package/src/commands/serve.js.flow +1 -1
- package/src/index.d.ts +0 -1
- package/src/index.flow.js +1 -18
- package/src/index.flow.js.flow +3 -32
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-import.js +21 -0
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-import.js.flow +17 -0
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-multi-line-import-with-escapes.js +18 -0
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-multi-line-import-with-escapes.js.flow +29 -0
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-multi-line-import.js +18 -0
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-multi-line-import.js.flow +29 -0
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-require-with-embedded-comment.js +18 -0
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-require-with-embedded-comment.js.flow +17 -0
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-require.js +17 -0
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-require.js.flow +17 -0
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-specifier-with-escapes.js +20 -0
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-specifier-with-escapes.js.flow +19 -0
- package/src/integration_tests/basic_bundle/build-errors/inline-requires-cannot-resolve-import.js +21 -0
- package/src/integration_tests/basic_bundle/build-errors/inline-requires-cannot-resolve-import.js.flow +17 -0
- package/src/integration_tests/basic_bundle/build-errors/inline-requires-cannot-resolve-require.js +17 -0
- package/src/integration_tests/basic_bundle/build-errors/inline-requires-cannot-resolve-require.js.flow +17 -0
- package/src/integration_tests/metro.config.js +5 -3
- package/src/lib/createWebsocketServer.js +2 -0
- package/src/lib/createWebsocketServer.js.flow +5 -2
- package/src/lib/transformHelpers.js +2 -2
- package/src/lib/transformHelpers.js.flow +6 -3
- package/src/node-haste/DependencyGraph/ModuleResolution.js +139 -52
- package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +152 -51
- package/src/node-haste/DependencyGraph.d.ts +5 -2
- package/src/node-haste/DependencyGraph.js +3 -2
- package/src/node-haste/DependencyGraph.js.flow +7 -3
- package/src/node-haste/Package.js.flow +1 -1
|
@@ -43,7 +43,14 @@ class ModuleResolver {
|
|
|
43
43
|
if (!emptyModule) {
|
|
44
44
|
emptyModule = this.resolveDependency(
|
|
45
45
|
this._projectRootFakeModule,
|
|
46
|
-
|
|
46
|
+
{
|
|
47
|
+
name: this._options.emptyModulePath,
|
|
48
|
+
data: {
|
|
49
|
+
key: this._options.emptyModulePath,
|
|
50
|
+
asyncType: null,
|
|
51
|
+
locs: [],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
47
54
|
false,
|
|
48
55
|
null,
|
|
49
56
|
/* resolverOptions */ {}
|
|
@@ -54,7 +61,7 @@ class ModuleResolver {
|
|
|
54
61
|
}
|
|
55
62
|
resolveDependency(
|
|
56
63
|
fromModule,
|
|
57
|
-
|
|
64
|
+
dependency,
|
|
58
65
|
allowHaste,
|
|
59
66
|
platform,
|
|
60
67
|
resolverOptions
|
|
@@ -77,34 +84,37 @@ class ModuleResolver {
|
|
|
77
84
|
} = this._options;
|
|
78
85
|
try {
|
|
79
86
|
const result = Resolver.resolve(
|
|
80
|
-
createDefaultContext(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
87
|
+
createDefaultContext(
|
|
88
|
+
{
|
|
89
|
+
allowHaste,
|
|
90
|
+
assetExts,
|
|
91
|
+
disableHierarchicalLookup,
|
|
92
|
+
doesFileExist,
|
|
93
|
+
extraNodeModules,
|
|
94
|
+
mainFields,
|
|
95
|
+
nodeModulesPaths,
|
|
96
|
+
preferNativePlatform,
|
|
97
|
+
resolveAsset,
|
|
98
|
+
resolveRequest,
|
|
99
|
+
sourceExts,
|
|
100
|
+
unstable_conditionNames,
|
|
101
|
+
unstable_conditionsByPlatform,
|
|
102
|
+
unstable_enablePackageExports,
|
|
103
|
+
unstable_getRealPath,
|
|
104
|
+
unstable_logWarning: this._logWarning,
|
|
105
|
+
customResolverOptions: resolverOptions.customResolverOptions ?? {},
|
|
106
|
+
originModulePath: fromModule.path,
|
|
107
|
+
resolveHasteModule: (name) =>
|
|
108
|
+
this._options.getHasteModulePath(name, platform),
|
|
109
|
+
resolveHastePackage: (name) =>
|
|
110
|
+
this._options.getHastePackagePath(name, platform),
|
|
111
|
+
getPackage: this._getPackage,
|
|
112
|
+
getPackageForModule: (modulePath) =>
|
|
113
|
+
this._getPackageForModule(fromModule, modulePath),
|
|
114
|
+
},
|
|
115
|
+
dependency
|
|
116
|
+
),
|
|
117
|
+
dependency.name,
|
|
108
118
|
platform
|
|
109
119
|
);
|
|
110
120
|
return this._getFileResolvedModule(result);
|
|
@@ -113,7 +123,7 @@ class ModuleResolver {
|
|
|
113
123
|
const { candidates } = error;
|
|
114
124
|
throw new UnableToResolveError(
|
|
115
125
|
fromModule.path,
|
|
116
|
-
|
|
126
|
+
dependency.name,
|
|
117
127
|
[
|
|
118
128
|
"\n\nNone of these files exist:",
|
|
119
129
|
` * ${Resolver.formatFileCandidates(
|
|
@@ -125,6 +135,7 @@ class ModuleResolver {
|
|
|
125
135
|
].join("\n"),
|
|
126
136
|
{
|
|
127
137
|
cause: error,
|
|
138
|
+
dependency,
|
|
128
139
|
}
|
|
129
140
|
);
|
|
130
141
|
}
|
|
@@ -138,13 +149,16 @@ class ModuleResolver {
|
|
|
138
149
|
const hint = displayDirPaths.length ? " or in these directories:" : "";
|
|
139
150
|
throw new UnableToResolveError(
|
|
140
151
|
fromModule.path,
|
|
141
|
-
|
|
152
|
+
dependency.name,
|
|
142
153
|
[
|
|
143
|
-
`${
|
|
154
|
+
`${dependency.name} could not be found within the project${
|
|
155
|
+
hint || "."
|
|
156
|
+
}`,
|
|
144
157
|
...displayDirPaths.map((dirPath) => ` ${dirPath}`),
|
|
145
158
|
].join("\n"),
|
|
146
159
|
{
|
|
147
160
|
cause: error,
|
|
161
|
+
dependency,
|
|
148
162
|
}
|
|
149
163
|
);
|
|
150
164
|
}
|
|
@@ -245,7 +259,7 @@ class UnableToResolveError extends Error {
|
|
|
245
259
|
super();
|
|
246
260
|
this.originModulePath = originModulePath;
|
|
247
261
|
this.targetModuleName = targetModuleName;
|
|
248
|
-
const codeFrameMessage = this.buildCodeFrameMessage();
|
|
262
|
+
const codeFrameMessage = this.buildCodeFrameMessage(options?.dependency);
|
|
249
263
|
this.message =
|
|
250
264
|
util.format(
|
|
251
265
|
"Unable to resolve module %s from %s: %s",
|
|
@@ -255,7 +269,7 @@ class UnableToResolveError extends Error {
|
|
|
255
269
|
) + (codeFrameMessage ? "\n" + codeFrameMessage : "");
|
|
256
270
|
this.cause = options?.cause;
|
|
257
271
|
}
|
|
258
|
-
buildCodeFrameMessage() {
|
|
272
|
+
buildCodeFrameMessage(dependency) {
|
|
259
273
|
let file;
|
|
260
274
|
try {
|
|
261
275
|
file = fs.readFileSync(this.originModulePath, "utf8");
|
|
@@ -269,31 +283,104 @@ class UnableToResolveError extends Error {
|
|
|
269
283
|
}
|
|
270
284
|
throw error;
|
|
271
285
|
}
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
break;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
286
|
+
const location = dependency?.data.locs.length
|
|
287
|
+
? refineDependencyLocation(
|
|
288
|
+
dependency.data.locs[0],
|
|
289
|
+
file,
|
|
290
|
+
this.targetModuleName
|
|
291
|
+
)
|
|
292
|
+
: // TODO: Ultimately we shouldn't ever have to guess the location.
|
|
293
|
+
guessDependencyLocation(file, this.targetModuleName);
|
|
283
294
|
return codeFrameColumns(
|
|
284
295
|
fs.readFileSync(this.originModulePath, "utf8"),
|
|
285
|
-
|
|
286
|
-
start: {
|
|
287
|
-
column: column + 1,
|
|
288
|
-
line: lineNumber + 1,
|
|
289
|
-
},
|
|
290
|
-
},
|
|
296
|
+
location,
|
|
291
297
|
{
|
|
292
298
|
forceColor: process.env.NODE_ENV !== "test",
|
|
293
299
|
}
|
|
294
300
|
);
|
|
295
301
|
}
|
|
296
302
|
}
|
|
303
|
+
|
|
304
|
+
// Given a source location for an import declaration or `require()` call (etc),
|
|
305
|
+
// return a location for use with @babel/code-frame in the resolution error.
|
|
306
|
+
function refineDependencyLocation(loc, fileContents, targetSpecifier) {
|
|
307
|
+
const lines = fileContents.split("\n");
|
|
308
|
+
// If we can find the module name in range of the given loc, surrounded by
|
|
309
|
+
// matching quotes, that's likely our specifier. Point to the first column of
|
|
310
|
+
// the *last* valid occurrence.
|
|
311
|
+
// Note that module names may not always be found in the source code verbatim,
|
|
312
|
+
// whether because of escaping or because of exotic dependency APIs.
|
|
313
|
+
for (let line = loc.end.line - 1; line >= loc.start.line - 1; line--) {
|
|
314
|
+
const maxColumn =
|
|
315
|
+
line === loc.end.line ? loc.end.column + 2 : lines[line].length;
|
|
316
|
+
const minColumn = line === loc.start.line ? loc.start.column - 1 : 0;
|
|
317
|
+
const lineStr = lines[line];
|
|
318
|
+
const lineSlice = lineStr.slice(minColumn, maxColumn);
|
|
319
|
+
for (
|
|
320
|
+
let offset = lineSlice.lastIndexOf(targetSpecifier);
|
|
321
|
+
offset !== -1 &&
|
|
322
|
+
// leave room for quotes
|
|
323
|
+
offset > 0 &&
|
|
324
|
+
offset < lineSlice.length - 1;
|
|
325
|
+
offset = lineSlice.lastIndexOf(targetSpecifier, offset - 1)
|
|
326
|
+
) {
|
|
327
|
+
const maybeQuoteBefore = lineSlice[minColumn + offset - 1];
|
|
328
|
+
const maybeQuoteAfter =
|
|
329
|
+
lineStr[minColumn + offset + targetSpecifier.length];
|
|
330
|
+
if (isQuote(maybeQuoteBefore) && maybeQuoteBefore === maybeQuoteAfter) {
|
|
331
|
+
return {
|
|
332
|
+
start: {
|
|
333
|
+
line: line + 1,
|
|
334
|
+
column: minColumn + offset + 1,
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// Otherwise, if this is a single-line loc, return it exactly, as a range.
|
|
341
|
+
if (loc.start.line === loc.end.line) {
|
|
342
|
+
return {
|
|
343
|
+
start: {
|
|
344
|
+
line: loc.start.line,
|
|
345
|
+
column: loc.start.column + 1,
|
|
346
|
+
},
|
|
347
|
+
end: {
|
|
348
|
+
line: loc.end.line,
|
|
349
|
+
column: loc.end.column + 1,
|
|
350
|
+
},
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
// Otherwise, point to the first column of the loc, to avoid including too
|
|
354
|
+
// much unnecessary context.
|
|
355
|
+
return {
|
|
356
|
+
start: {
|
|
357
|
+
line: loc.start.line,
|
|
358
|
+
column: loc.start.column + 1,
|
|
359
|
+
},
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function guessDependencyLocation(fileContents, targetSpecifier) {
|
|
363
|
+
const lines = fileContents.split("\n");
|
|
364
|
+
let lineNumber = 0;
|
|
365
|
+
let column = -1;
|
|
366
|
+
for (let line = 0; line < lines.length; line++) {
|
|
367
|
+
const columnLocation = lines[line].lastIndexOf(targetSpecifier);
|
|
368
|
+
if (columnLocation >= 0) {
|
|
369
|
+
lineNumber = line;
|
|
370
|
+
column = columnLocation;
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return {
|
|
375
|
+
start: {
|
|
376
|
+
column: column + 1,
|
|
377
|
+
line: lineNumber + 1,
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
function isQuote(str) {
|
|
382
|
+
return str === '"' || str === "'" || str === "`";
|
|
383
|
+
}
|
|
297
384
|
module.exports = {
|
|
298
385
|
ModuleResolver,
|
|
299
386
|
UnableToResolveError,
|
|
@@ -29,7 +29,10 @@ const Resolver = require('metro-resolver');
|
|
|
29
29
|
const createDefaultContext = require('metro-resolver/src/createDefaultContext');
|
|
30
30
|
const path = require('path');
|
|
31
31
|
const util = require('util');
|
|
32
|
-
import type {
|
|
32
|
+
import type {
|
|
33
|
+
BundlerResolution,
|
|
34
|
+
TransformResultDependency,
|
|
35
|
+
} from '../../DeltaBundler/types.flow';
|
|
33
36
|
import type {Reporter} from '../../lib/reporting';
|
|
34
37
|
|
|
35
38
|
export type DirExistsFn = (filePath: string) => boolean;
|
|
@@ -107,7 +110,14 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
107
110
|
if (!emptyModule) {
|
|
108
111
|
emptyModule = this.resolveDependency(
|
|
109
112
|
this._projectRootFakeModule,
|
|
110
|
-
|
|
113
|
+
{
|
|
114
|
+
name: this._options.emptyModulePath,
|
|
115
|
+
data: {
|
|
116
|
+
key: this._options.emptyModulePath,
|
|
117
|
+
asyncType: null,
|
|
118
|
+
locs: [],
|
|
119
|
+
},
|
|
120
|
+
},
|
|
111
121
|
false,
|
|
112
122
|
null,
|
|
113
123
|
/* resolverOptions */ {},
|
|
@@ -119,7 +129,7 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
119
129
|
|
|
120
130
|
resolveDependency(
|
|
121
131
|
fromModule: Moduleish,
|
|
122
|
-
|
|
132
|
+
dependency: TransformResultDependency,
|
|
123
133
|
allowHaste: boolean,
|
|
124
134
|
platform: string | null,
|
|
125
135
|
resolverOptions: ResolverInputOptions,
|
|
@@ -143,34 +153,37 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
143
153
|
|
|
144
154
|
try {
|
|
145
155
|
const result = Resolver.resolve(
|
|
146
|
-
createDefaultContext(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
156
|
+
createDefaultContext(
|
|
157
|
+
{
|
|
158
|
+
allowHaste,
|
|
159
|
+
assetExts,
|
|
160
|
+
disableHierarchicalLookup,
|
|
161
|
+
doesFileExist,
|
|
162
|
+
extraNodeModules,
|
|
163
|
+
mainFields,
|
|
164
|
+
nodeModulesPaths,
|
|
165
|
+
preferNativePlatform,
|
|
166
|
+
resolveAsset,
|
|
167
|
+
resolveRequest,
|
|
168
|
+
sourceExts,
|
|
169
|
+
unstable_conditionNames,
|
|
170
|
+
unstable_conditionsByPlatform,
|
|
171
|
+
unstable_enablePackageExports,
|
|
172
|
+
unstable_getRealPath,
|
|
173
|
+
unstable_logWarning: this._logWarning,
|
|
174
|
+
customResolverOptions: resolverOptions.customResolverOptions ?? {},
|
|
175
|
+
originModulePath: fromModule.path,
|
|
176
|
+
resolveHasteModule: (name: string) =>
|
|
177
|
+
this._options.getHasteModulePath(name, platform),
|
|
178
|
+
resolveHastePackage: (name: string) =>
|
|
179
|
+
this._options.getHastePackagePath(name, platform),
|
|
180
|
+
getPackage: this._getPackage,
|
|
181
|
+
getPackageForModule: (modulePath: string) =>
|
|
182
|
+
this._getPackageForModule(fromModule, modulePath),
|
|
183
|
+
},
|
|
184
|
+
dependency,
|
|
185
|
+
),
|
|
186
|
+
dependency.name,
|
|
174
187
|
platform,
|
|
175
188
|
);
|
|
176
189
|
return this._getFileResolvedModule(result);
|
|
@@ -179,7 +192,7 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
179
192
|
const {candidates} = error;
|
|
180
193
|
throw new UnableToResolveError(
|
|
181
194
|
fromModule.path,
|
|
182
|
-
|
|
195
|
+
dependency.name,
|
|
183
196
|
[
|
|
184
197
|
'\n\nNone of these files exist:',
|
|
185
198
|
` * ${Resolver.formatFileCandidates(
|
|
@@ -191,6 +204,7 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
191
204
|
].join('\n'),
|
|
192
205
|
{
|
|
193
206
|
cause: error,
|
|
207
|
+
dependency,
|
|
194
208
|
},
|
|
195
209
|
);
|
|
196
210
|
}
|
|
@@ -206,13 +220,16 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
206
220
|
|
|
207
221
|
throw new UnableToResolveError(
|
|
208
222
|
fromModule.path,
|
|
209
|
-
|
|
223
|
+
dependency.name,
|
|
210
224
|
[
|
|
211
|
-
`${
|
|
225
|
+
`${dependency.name} could not be found within the project${
|
|
226
|
+
hint || '.'
|
|
227
|
+
}`,
|
|
212
228
|
...displayDirPaths.map((dirPath: string) => ` ${dirPath}`),
|
|
213
229
|
].join('\n'),
|
|
214
230
|
{
|
|
215
231
|
cause: error,
|
|
232
|
+
dependency,
|
|
216
233
|
},
|
|
217
234
|
);
|
|
218
235
|
}
|
|
@@ -324,13 +341,14 @@ class UnableToResolveError extends Error {
|
|
|
324
341
|
targetModuleName: string,
|
|
325
342
|
message: string,
|
|
326
343
|
options?: $ReadOnly<{
|
|
344
|
+
dependency?: ?TransformResultDependency,
|
|
327
345
|
cause?: Error,
|
|
328
346
|
}>,
|
|
329
347
|
) {
|
|
330
348
|
super();
|
|
331
349
|
this.originModulePath = originModulePath;
|
|
332
350
|
this.targetModuleName = targetModuleName;
|
|
333
|
-
const codeFrameMessage = this.buildCodeFrameMessage();
|
|
351
|
+
const codeFrameMessage = this.buildCodeFrameMessage(options?.dependency);
|
|
334
352
|
this.message =
|
|
335
353
|
util.format(
|
|
336
354
|
'Unable to resolve module %s from %s: %s',
|
|
@@ -342,7 +360,7 @@ class UnableToResolveError extends Error {
|
|
|
342
360
|
this.cause = options?.cause;
|
|
343
361
|
}
|
|
344
362
|
|
|
345
|
-
buildCodeFrameMessage(): ?string {
|
|
363
|
+
buildCodeFrameMessage(dependency: ?TransformResultDependency): ?string {
|
|
346
364
|
let file;
|
|
347
365
|
try {
|
|
348
366
|
file = fs.readFileSync(this.originModulePath, 'utf8');
|
|
@@ -357,28 +375,111 @@ class UnableToResolveError extends Error {
|
|
|
357
375
|
throw error;
|
|
358
376
|
}
|
|
359
377
|
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
break;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
378
|
+
const location = dependency?.data.locs.length
|
|
379
|
+
? refineDependencyLocation(
|
|
380
|
+
dependency.data.locs[0],
|
|
381
|
+
file,
|
|
382
|
+
this.targetModuleName,
|
|
383
|
+
)
|
|
384
|
+
: // TODO: Ultimately we shouldn't ever have to guess the location.
|
|
385
|
+
guessDependencyLocation(file, this.targetModuleName);
|
|
372
386
|
return codeFrameColumns(
|
|
373
387
|
fs.readFileSync(this.originModulePath, 'utf8'),
|
|
374
|
-
|
|
375
|
-
start: {column: column + 1, line: lineNumber + 1},
|
|
376
|
-
},
|
|
388
|
+
location,
|
|
377
389
|
{forceColor: process.env.NODE_ENV !== 'test'},
|
|
378
390
|
);
|
|
379
391
|
}
|
|
380
392
|
}
|
|
381
393
|
|
|
394
|
+
// Given a source location for an import declaration or `require()` call (etc),
|
|
395
|
+
// return a location for use with @babel/code-frame in the resolution error.
|
|
396
|
+
function refineDependencyLocation(
|
|
397
|
+
loc: BabelSourceLocation,
|
|
398
|
+
fileContents: string,
|
|
399
|
+
targetSpecifier: string,
|
|
400
|
+
): {
|
|
401
|
+
start: {column: number, line: number},
|
|
402
|
+
end?: {column: number, line: number},
|
|
403
|
+
} {
|
|
404
|
+
const lines = fileContents.split('\n');
|
|
405
|
+
// If we can find the module name in range of the given loc, surrounded by
|
|
406
|
+
// matching quotes, that's likely our specifier. Point to the first column of
|
|
407
|
+
// the *last* valid occurrence.
|
|
408
|
+
// Note that module names may not always be found in the source code verbatim,
|
|
409
|
+
// whether because of escaping or because of exotic dependency APIs.
|
|
410
|
+
for (let line = loc.end.line - 1; line >= loc.start.line - 1; line--) {
|
|
411
|
+
const maxColumn =
|
|
412
|
+
line === loc.end.line ? loc.end.column + 2 : lines[line].length;
|
|
413
|
+
const minColumn = line === loc.start.line ? loc.start.column - 1 : 0;
|
|
414
|
+
const lineStr = lines[line];
|
|
415
|
+
const lineSlice = lineStr.slice(minColumn, maxColumn);
|
|
416
|
+
for (
|
|
417
|
+
let offset = lineSlice.lastIndexOf(targetSpecifier);
|
|
418
|
+
offset !== -1 && // leave room for quotes
|
|
419
|
+
offset > 0 &&
|
|
420
|
+
offset < lineSlice.length - 1;
|
|
421
|
+
offset = lineSlice.lastIndexOf(targetSpecifier, offset - 1)
|
|
422
|
+
) {
|
|
423
|
+
const maybeQuoteBefore = lineSlice[minColumn + offset - 1];
|
|
424
|
+
const maybeQuoteAfter =
|
|
425
|
+
lineStr[minColumn + offset + targetSpecifier.length];
|
|
426
|
+
if (isQuote(maybeQuoteBefore) && maybeQuoteBefore === maybeQuoteAfter) {
|
|
427
|
+
return {
|
|
428
|
+
start: {
|
|
429
|
+
line: line + 1,
|
|
430
|
+
column: minColumn + offset + 1,
|
|
431
|
+
},
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// Otherwise, if this is a single-line loc, return it exactly, as a range.
|
|
437
|
+
if (loc.start.line === loc.end.line) {
|
|
438
|
+
return {
|
|
439
|
+
start: {
|
|
440
|
+
line: loc.start.line,
|
|
441
|
+
column: loc.start.column + 1,
|
|
442
|
+
},
|
|
443
|
+
end: {
|
|
444
|
+
line: loc.end.line,
|
|
445
|
+
column: loc.end.column + 1,
|
|
446
|
+
},
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
// Otherwise, point to the first column of the loc, to avoid including too
|
|
450
|
+
// much unnecessary context.
|
|
451
|
+
return {
|
|
452
|
+
start: {
|
|
453
|
+
line: loc.start.line,
|
|
454
|
+
column: loc.start.column + 1,
|
|
455
|
+
},
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function guessDependencyLocation(
|
|
460
|
+
fileContents: string,
|
|
461
|
+
targetSpecifier: string,
|
|
462
|
+
) {
|
|
463
|
+
const lines = fileContents.split('\n');
|
|
464
|
+
let lineNumber = 0;
|
|
465
|
+
let column = -1;
|
|
466
|
+
for (let line = 0; line < lines.length; line++) {
|
|
467
|
+
const columnLocation = lines[line].lastIndexOf(targetSpecifier);
|
|
468
|
+
if (columnLocation >= 0) {
|
|
469
|
+
lineNumber = line;
|
|
470
|
+
column = columnLocation;
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return {
|
|
475
|
+
start: {column: column + 1, line: lineNumber + 1},
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function isQuote(str: ?string): boolean {
|
|
480
|
+
return str === '"' || str === "'" || str === '`';
|
|
481
|
+
}
|
|
482
|
+
|
|
382
483
|
module.exports = {
|
|
383
484
|
ModuleResolver,
|
|
384
485
|
UnableToResolveError,
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
import {EventEmitter} from 'events';
|
|
12
12
|
import {ConfigT} from 'metro-config';
|
|
13
13
|
import {ResolverInputOptions} from '../shared/types';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
BundlerResolution,
|
|
16
|
+
TransformResultDependency,
|
|
17
|
+
} from '../DeltaBundler/types';
|
|
15
18
|
|
|
16
19
|
export default class DependencyGraph extends EventEmitter {
|
|
17
20
|
constructor(
|
|
@@ -48,7 +51,7 @@ export default class DependencyGraph extends EventEmitter {
|
|
|
48
51
|
|
|
49
52
|
resolveDependency(
|
|
50
53
|
from: string,
|
|
51
|
-
to:
|
|
54
|
+
to: TransformResultDependency,
|
|
52
55
|
platform: string | null,
|
|
53
56
|
resolverOptions: ResolverInputOptions,
|
|
54
57
|
options: {assumeFlatNodeModules: boolean},
|
|
@@ -239,7 +239,7 @@ class DependencyGraph extends EventEmitter {
|
|
|
239
239
|
}
|
|
240
240
|
resolveDependency(
|
|
241
241
|
from,
|
|
242
|
-
|
|
242
|
+
dependency,
|
|
243
243
|
platform,
|
|
244
244
|
resolverOptions,
|
|
245
245
|
// TODO: Fold assumeFlatNodeModules into resolverOptions and add to graphId
|
|
@@ -247,6 +247,7 @@ class DependencyGraph extends EventEmitter {
|
|
|
247
247
|
assumeFlatNodeModules: false,
|
|
248
248
|
}
|
|
249
249
|
) {
|
|
250
|
+
const to = dependency.name;
|
|
250
251
|
const isSensitiveToOriginFolder =
|
|
251
252
|
// Resolution is always relative to the origin folder unless we assume a flat node_modules
|
|
252
253
|
!assumeFlatNodeModules ||
|
|
@@ -280,7 +281,7 @@ class DependencyGraph extends EventEmitter {
|
|
|
280
281
|
try {
|
|
281
282
|
resolution = this._moduleResolver.resolveDependency(
|
|
282
283
|
this._moduleCache.getModule(from),
|
|
283
|
-
|
|
284
|
+
dependency,
|
|
284
285
|
true,
|
|
285
286
|
platform,
|
|
286
287
|
resolverOptions
|
|
@@ -36,7 +36,10 @@ const {InvalidPackageError} = require('metro-resolver');
|
|
|
36
36
|
const nullthrows = require('nullthrows');
|
|
37
37
|
const path = require('path');
|
|
38
38
|
import type {ResolverInputOptions} from '../shared/types.flow';
|
|
39
|
-
import type {
|
|
39
|
+
import type {
|
|
40
|
+
BundlerResolution,
|
|
41
|
+
TransformResultDependency,
|
|
42
|
+
} from '../DeltaBundler/types.flow';
|
|
40
43
|
|
|
41
44
|
const NULL_PLATFORM = Symbol();
|
|
42
45
|
|
|
@@ -310,7 +313,7 @@ class DependencyGraph extends EventEmitter {
|
|
|
310
313
|
|
|
311
314
|
resolveDependency(
|
|
312
315
|
from: string,
|
|
313
|
-
|
|
316
|
+
dependency: TransformResultDependency,
|
|
314
317
|
platform: string | null,
|
|
315
318
|
resolverOptions: ResolverInputOptions,
|
|
316
319
|
|
|
@@ -319,6 +322,7 @@ class DependencyGraph extends EventEmitter {
|
|
|
319
322
|
assumeFlatNodeModules: false,
|
|
320
323
|
},
|
|
321
324
|
): BundlerResolution {
|
|
325
|
+
const to = dependency.name;
|
|
322
326
|
const isSensitiveToOriginFolder =
|
|
323
327
|
// Resolution is always relative to the origin folder unless we assume a flat node_modules
|
|
324
328
|
!assumeFlatNodeModules ||
|
|
@@ -353,7 +357,7 @@ class DependencyGraph extends EventEmitter {
|
|
|
353
357
|
try {
|
|
354
358
|
resolution = this._moduleResolver.resolveDependency(
|
|
355
359
|
this._moduleCache.getModule(from),
|
|
356
|
-
|
|
360
|
+
dependency,
|
|
357
361
|
true,
|
|
358
362
|
platform,
|
|
359
363
|
resolverOptions,
|