@embroider/core 3.4.5 → 3.4.6-unstable.4c0881e
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 +13 -11
- package/src/app-files.d.ts +1 -1
- package/src/app-files.js +1 -1
- package/src/app-files.js.map +1 -1
- package/src/index.d.ts +1 -1
- package/src/index.js.map +1 -1
- package/src/module-resolver.d.ts +19 -13
- package/src/module-resolver.js +217 -189
- package/src/module-resolver.js.map +1 -1
- package/src/node-resolve.d.ts +33 -0
- package/src/node-resolve.js +131 -0
- package/src/node-resolve.js.map +1 -0
- package/src/virtual-content.d.ts +6 -2
- package/src/virtual-content.js +80 -38
- package/src/virtual-content.js.map +1 -1
- package/LICENSE +0 -21
package/src/module-resolver.js
CHANGED
@@ -15,63 +15,59 @@ const path_1 = require("path");
|
|
15
15
|
const shared_internals_2 = require("@embroider/shared-internals");
|
16
16
|
const debug_1 = __importDefault(require("debug"));
|
17
17
|
const assert_never_1 = __importDefault(require("assert-never"));
|
18
|
-
const
|
18
|
+
const reverse_exports_1 = __importDefault(require("@embroider/reverse-exports"));
|
19
|
+
const resolve_exports_1 = require("resolve.exports");
|
19
20
|
const virtual_content_1 = require("./virtual-content");
|
20
21
|
const typescript_memoize_1 = require("typescript-memoize");
|
21
22
|
const describe_exports_1 = require("./describe-exports");
|
22
23
|
const fs_1 = require("fs");
|
24
|
+
const node_resolve_1 = require("./node-resolve");
|
23
25
|
const debug = (0, debug_1.default)('embroider:resolver');
|
26
|
+
// Using a formatter makes this work lazy so nothing happens when we aren't
|
27
|
+
// logging. It is unfortunate that formatters are a globally mutable config and
|
28
|
+
// you can only use single character names, but oh well.
|
29
|
+
debug_1.default.formatters.p = (s) => {
|
30
|
+
let cwd = process.cwd();
|
31
|
+
if (s.startsWith(cwd)) {
|
32
|
+
return s.slice(cwd.length + 1);
|
33
|
+
}
|
34
|
+
return s;
|
35
|
+
};
|
24
36
|
function logTransition(reason, before, after = before) {
|
25
37
|
if (after.isVirtual) {
|
26
|
-
debug(`
|
38
|
+
debug(`[%s:virtualized] %s because %s\n in %p`, before.debugType, before.specifier, reason, before.fromFile);
|
39
|
+
}
|
40
|
+
else if (after.resolvedTo) {
|
41
|
+
debug(`[%s:resolvedTo] %s because %s\n in %p`, before.debugType, before.specifier, reason, before.fromFile);
|
27
42
|
}
|
28
43
|
else if (before.specifier !== after.specifier) {
|
29
44
|
if (before.fromFile !== after.fromFile) {
|
30
|
-
debug(`aliased and rehomed
|
45
|
+
debug(`[%s:aliased and rehomed] %s to %s\n because %s\n from %p\n to %p`, before.debugType, before.specifier, after.specifier, reason, before.fromFile, after.fromFile);
|
31
46
|
}
|
32
47
|
else {
|
33
|
-
debug(`aliased
|
48
|
+
debug(`[%s:aliased] %s to %s\n because %s`, before.debugType, before.specifier, after.specifier, reason);
|
34
49
|
}
|
35
50
|
}
|
36
51
|
else if (before.fromFile !== after.fromFile) {
|
37
|
-
debug(`rehomed
|
52
|
+
debug(`[%s:rehomed] %s, because %s\n from %p\n to %p`, before.debugType, before.specifier, reason, before.fromFile, after.fromFile);
|
53
|
+
}
|
54
|
+
else if (after.isNotFound) {
|
55
|
+
debug(`[%s:not-found] %s because %s\n in %p`, before.debugType, before.specifier, reason, before.fromFile);
|
38
56
|
}
|
39
57
|
else {
|
40
|
-
debug(`
|
58
|
+
debug(`[%s:unchanged] %s because %s\n in %p`, before.debugType, before.specifier, reason, before.fromFile);
|
41
59
|
}
|
42
60
|
return after;
|
43
61
|
}
|
44
|
-
|
45
|
-
|
46
|
-
constructor(specifier, fromFile, isVirtual, meta) {
|
47
|
-
this.specifier = specifier;
|
48
|
-
this.fromFile = fromFile;
|
49
|
-
this.isVirtual = isVirtual;
|
50
|
-
this.meta = meta;
|
51
|
-
}
|
52
|
-
alias(specifier) {
|
53
|
-
return new NodeModuleRequest(specifier, this.fromFile, false, this.meta);
|
54
|
-
}
|
55
|
-
rehome(fromFile) {
|
56
|
-
if (this.fromFile === fromFile) {
|
57
|
-
return this;
|
58
|
-
}
|
59
|
-
else {
|
60
|
-
return new NodeModuleRequest(this.specifier, fromFile, false, this.meta);
|
61
|
-
}
|
62
|
-
}
|
63
|
-
virtualize(filename) {
|
64
|
-
return new NodeModuleRequest(filename, this.fromFile, true, this.meta);
|
65
|
-
}
|
66
|
-
withMeta(meta) {
|
67
|
-
return new NodeModuleRequest(this.specifier, this.fromFile, this.isVirtual, meta);
|
68
|
-
}
|
62
|
+
function isTerminal(request) {
|
63
|
+
return request.isVirtual || request.isNotFound || Boolean(request.resolvedTo);
|
69
64
|
}
|
65
|
+
const compatPattern = /#embroider_compat\/(?<type>[^\/]+)\/(?<rest>.*)/;
|
70
66
|
class Resolver {
|
71
67
|
constructor(options) {
|
72
68
|
this.options = options;
|
73
69
|
}
|
74
|
-
beforeResolve(request) {
|
70
|
+
async beforeResolve(request) {
|
75
71
|
if (request.specifier === '@embroider/macros') {
|
76
72
|
// the macros package is always handled directly within babel (not
|
77
73
|
// necessarily as a real resolvable package), so we should not mess with it.
|
@@ -79,8 +75,11 @@ class Resolver {
|
|
79
75
|
// why we need to know about it.
|
80
76
|
return logTransition('early exit', request);
|
81
77
|
}
|
78
|
+
if (request.specifier === 'require') {
|
79
|
+
return this.external('early require', request, request.specifier);
|
80
|
+
}
|
82
81
|
request = this.handleFastbootSwitch(request);
|
83
|
-
request = this.handleGlobalsCompat(request);
|
82
|
+
request = await this.handleGlobalsCompat(request);
|
84
83
|
request = this.handleImplicitModules(request);
|
85
84
|
request = this.handleRenaming(request);
|
86
85
|
// we expect the specifier to be app relative at this point - must be after handleRenaming
|
@@ -96,95 +95,45 @@ class Resolver {
|
|
96
95
|
// that calls your build system's normal module resolver, this does both pre-
|
97
96
|
// and post-resolution adjustments as needed to implement our compatibility
|
98
97
|
// rules.
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
let
|
105
|
-
let out = gen.next();
|
106
|
-
while (!out.done) {
|
107
|
-
out = gen.next(await out.value);
|
108
|
-
}
|
109
|
-
return out.value;
|
110
|
-
}
|
111
|
-
// synchronous alternative to resolve() above. Because our own internals are
|
112
|
-
// all synchronous, you can use this if your defaultResolve function is
|
113
|
-
// synchronous.
|
114
|
-
resolveSync(request, defaultResolve) {
|
115
|
-
let gen = this.internalResolve(request, defaultResolve);
|
116
|
-
let out = gen.next();
|
117
|
-
while (!out.done) {
|
118
|
-
out = gen.next(out.value);
|
119
|
-
}
|
120
|
-
return out.value;
|
121
|
-
}
|
122
|
-
// Our core implementation is a generator so it can power both resolve() and
|
123
|
-
// resolveSync()
|
124
|
-
*internalResolve(request, defaultResolve) {
|
125
|
-
request = this.beforeResolve(request);
|
126
|
-
let resolution = yield defaultResolve(request);
|
98
|
+
async resolve(request) {
|
99
|
+
request = await this.beforeResolve(request);
|
100
|
+
if (request.resolvedTo) {
|
101
|
+
return request.resolvedTo;
|
102
|
+
}
|
103
|
+
let resolution = await request.defaultResolve();
|
127
104
|
switch (resolution.type) {
|
128
105
|
case 'found':
|
106
|
+
case 'ignored':
|
129
107
|
return resolution;
|
130
108
|
case 'not_found':
|
131
109
|
break;
|
132
110
|
default:
|
133
111
|
throw (0, assert_never_1.default)(resolution);
|
134
112
|
}
|
135
|
-
let nextRequest = this.fallbackResolve(request);
|
113
|
+
let nextRequest = await this.fallbackResolve(request);
|
136
114
|
if (nextRequest === request) {
|
137
115
|
// no additional fallback is available.
|
138
116
|
return resolution;
|
139
117
|
}
|
118
|
+
if (nextRequest.resolvedTo) {
|
119
|
+
return nextRequest.resolvedTo;
|
120
|
+
}
|
140
121
|
if (nextRequest.fromFile === request.fromFile && nextRequest.specifier === request.specifier) {
|
141
122
|
throw new Error('Bug Discovered! New request is not === original request but has the same fromFile and specifier. This will likely create a loop.');
|
142
123
|
}
|
143
|
-
if (nextRequest.isVirtual) {
|
144
|
-
// virtual requests are terminal, there is no more
|
145
|
-
// fallbackResolve around them. The defaultResolve is
|
146
|
-
// to implement them.
|
147
|
-
return
|
124
|
+
if (nextRequest.isVirtual || nextRequest.isNotFound) {
|
125
|
+
// virtual and NotFound requests are terminal, there is no more
|
126
|
+
// beforeResolve or fallbackResolve around them. The defaultResolve is
|
127
|
+
// expected to know how to implement them.
|
128
|
+
return nextRequest.defaultResolve();
|
148
129
|
}
|
149
|
-
return
|
130
|
+
return this.resolve(nextRequest);
|
150
131
|
}
|
151
132
|
// Use standard NodeJS resolving, with our required compatibility rules on
|
152
133
|
// top. This is a convenience method for calling resolveSync with the
|
153
134
|
// defaultResolve already configured to be "do the normal node thing".
|
154
|
-
nodeResolve(specifier, fromFile) {
|
155
|
-
|
156
|
-
if (request.isVirtual) {
|
157
|
-
return {
|
158
|
-
type: 'found',
|
159
|
-
result: {
|
160
|
-
type: 'virtual',
|
161
|
-
content: (0, virtual_content_1.virtualContent)(request.specifier, this),
|
162
|
-
filename: request.specifier,
|
163
|
-
},
|
164
|
-
};
|
165
|
-
}
|
166
|
-
try {
|
167
|
-
let filename = resolve_1.default.sync(request.specifier, {
|
168
|
-
basedir: (0, path_1.dirname)(request.fromFile),
|
169
|
-
extensions: this.options.resolvableExtensions,
|
170
|
-
});
|
171
|
-
return { type: 'found', result: { type: 'real', filename } };
|
172
|
-
}
|
173
|
-
catch (err) {
|
174
|
-
if (err.code !== 'MODULE_NOT_FOUND') {
|
175
|
-
throw err;
|
176
|
-
}
|
177
|
-
return { type: 'not_found', err };
|
178
|
-
}
|
179
|
-
});
|
180
|
-
switch (resolution.type) {
|
181
|
-
case 'not_found':
|
182
|
-
return resolution;
|
183
|
-
case 'found':
|
184
|
-
return resolution.result;
|
185
|
-
default:
|
186
|
-
throw (0, assert_never_1.default)(resolution);
|
187
|
-
}
|
135
|
+
async nodeResolve(specifier, fromFile) {
|
136
|
+
return (0, node_resolve_1.nodeResolve)(this, specifier, fromFile);
|
188
137
|
}
|
189
138
|
get packageCache() {
|
190
139
|
return shared_internals_2.RewrittenPackageCache.shared('embroider', this.options.appRoot);
|
@@ -201,6 +150,9 @@ class Resolver {
|
|
201
150
|
return owningPackage;
|
202
151
|
}
|
203
152
|
generateFastbootSwitch(request) {
|
153
|
+
if (isTerminal(request)) {
|
154
|
+
return request;
|
155
|
+
}
|
204
156
|
let pkg = this.packageCache.ownerOfFile(request.fromFile);
|
205
157
|
if (!pkg) {
|
206
158
|
return request;
|
@@ -237,6 +189,9 @@ class Resolver {
|
|
237
189
|
}
|
238
190
|
handleFastbootSwitch(request) {
|
239
191
|
var _a;
|
192
|
+
if (isTerminal(request)) {
|
193
|
+
return request;
|
194
|
+
}
|
240
195
|
let match = (0, virtual_content_1.decodeFastbootSwitch)(request.fromFile);
|
241
196
|
if (!match) {
|
242
197
|
return request;
|
@@ -275,12 +230,15 @@ class Resolver {
|
|
275
230
|
}
|
276
231
|
let entry = (_a = this.getEntryFromMergeMap(rel, pkg.root)) === null || _a === void 0 ? void 0 : _a.entry;
|
277
232
|
if ((entry === null || entry === void 0 ? void 0 : entry.type) === 'both') {
|
278
|
-
return logTransition('matched addon entry', request, request.alias(entry[section].
|
233
|
+
return logTransition('matched addon entry', request, request.alias(entry[section].specifier).rehome(entry[section].fromFile));
|
279
234
|
}
|
280
235
|
}
|
281
236
|
return logTransition('failed to match in fastboot switch', request);
|
282
237
|
}
|
283
238
|
handleImplicitModules(request) {
|
239
|
+
if (isTerminal(request)) {
|
240
|
+
return request;
|
241
|
+
}
|
284
242
|
let im = (0, virtual_content_1.decodeImplicitModules)(request.specifier);
|
285
243
|
if (!im) {
|
286
244
|
return request;
|
@@ -298,7 +256,10 @@ class Resolver {
|
|
298
256
|
return logTransition(`own implicit modules`, request, request.virtualize((0, path_1.resolve)(pkg.root, `-embroider-${im.type}.js`)));
|
299
257
|
}
|
300
258
|
}
|
301
|
-
handleGlobalsCompat(request) {
|
259
|
+
async handleGlobalsCompat(request) {
|
260
|
+
if (isTerminal(request)) {
|
261
|
+
return request;
|
262
|
+
}
|
302
263
|
let match = compatPattern.exec(request.specifier);
|
303
264
|
if (!match) {
|
304
265
|
return request;
|
@@ -326,52 +287,60 @@ class Resolver {
|
|
326
287
|
let target = this.parseGlobalPath(path, inEngine);
|
327
288
|
return logTransition('resolveHelper', request, request.alias(`${target.packageName}/helpers/${target.memberName}`).rehome((0, path_1.resolve)(inEngine.root, 'package.json')));
|
328
289
|
}
|
329
|
-
resolveComponent(path, inEngine, request) {
|
290
|
+
async resolveComponent(path, inEngine, request) {
|
330
291
|
let target = this.parseGlobalPath(path, inEngine);
|
331
292
|
let hbsModule = null;
|
332
293
|
let jsModule = null;
|
333
294
|
// first, the various places our template might be.
|
334
295
|
for (let candidate of this.componentTemplateCandidates(target.packageName)) {
|
335
|
-
let
|
336
|
-
|
337
|
-
|
296
|
+
let candidateSpecifier = `${target.packageName}${candidate.prefix}${target.memberName}${candidate.suffix}`;
|
297
|
+
let resolution = await this.resolve(request.alias(candidateSpecifier).rehome(target.from).withMeta({
|
298
|
+
runtimeFallback: false,
|
299
|
+
}));
|
300
|
+
if (resolution.type === 'found') {
|
301
|
+
hbsModule = resolution;
|
338
302
|
break;
|
339
303
|
}
|
340
304
|
}
|
341
305
|
// then the various places our javascript might be.
|
342
306
|
for (let candidate of this.componentJSCandidates(target.packageName)) {
|
343
|
-
let
|
307
|
+
let candidateSpecifier = `${target.packageName}${candidate.prefix}${target.memberName}${candidate.suffix}`;
|
308
|
+
let resolution = await this.resolve(request.alias(candidateSpecifier).rehome(target.from).withMeta({
|
309
|
+
runtimeFallback: false,
|
310
|
+
}));
|
344
311
|
// .hbs is a resolvable extension for us, so we need to exclude it here.
|
345
312
|
// It matches as a priority lower than .js, so finding an .hbs means
|
346
313
|
// there's definitely not a .js.
|
347
|
-
if (resolution.type === '
|
348
|
-
jsModule = resolution
|
314
|
+
if (resolution.type === 'found' && !resolution.filename.endsWith('.hbs')) {
|
315
|
+
jsModule = resolution;
|
349
316
|
break;
|
350
317
|
}
|
351
318
|
}
|
352
319
|
if (hbsModule) {
|
353
|
-
return logTransition(`resolveComponent found legacy HBS`, request, request.virtualize((0, virtual_content_1.virtualPairComponent)(hbsModule, jsModule)));
|
320
|
+
return logTransition(`resolveComponent found legacy HBS`, request, request.virtualize((0, virtual_content_1.virtualPairComponent)(hbsModule.filename, jsModule === null || jsModule === void 0 ? void 0 : jsModule.filename)));
|
354
321
|
}
|
355
322
|
else if (jsModule) {
|
356
|
-
return logTransition(`resolveComponent found only JS`, request, request.
|
323
|
+
return logTransition(`resolving to resolveComponent found only JS`, request, request.resolveTo(jsModule));
|
357
324
|
}
|
358
325
|
else {
|
359
326
|
return logTransition(`resolveComponent failed`, request);
|
360
327
|
}
|
361
328
|
}
|
362
|
-
resolveHelperOrComponent(path, inEngine, request) {
|
329
|
+
async resolveHelperOrComponent(path, inEngine, request) {
|
363
330
|
// resolveHelper just rewrites our request to one that should target the
|
364
331
|
// component, so here to resolve the ambiguity we need to actually resolve
|
365
332
|
// that candidate to see if it works.
|
366
333
|
let helperCandidate = this.resolveHelper(path, inEngine, request);
|
367
|
-
let helperMatch = this.
|
368
|
-
|
369
|
-
|
334
|
+
let helperMatch = await this.resolve(request.alias(helperCandidate.specifier).rehome(helperCandidate.fromFile).withMeta({
|
335
|
+
runtimeFallback: false,
|
336
|
+
}));
|
337
|
+
if (helperMatch.type === 'found') {
|
338
|
+
return logTransition('resolve to ambiguous case matched a helper', request, request.resolveTo(helperMatch));
|
370
339
|
}
|
371
340
|
// unlike resolveHelper, resolveComponent already does pre-resolution in
|
372
341
|
// order to deal with its own internal ambiguity around JS vs HBS vs
|
373
342
|
// colocation.≥
|
374
|
-
let componentMatch = this.resolveComponent(path, inEngine, request);
|
343
|
+
let componentMatch = await this.resolveComponent(path, inEngine, request);
|
375
344
|
if (componentMatch !== request) {
|
376
345
|
return logTransition('ambiguous case matched a cmoponent', request, componentMatch);
|
377
346
|
}
|
@@ -396,6 +365,7 @@ class Resolver {
|
|
396
365
|
}
|
397
366
|
*componentJSCandidates(inPackageName) {
|
398
367
|
yield { prefix: '/components/', suffix: '' };
|
368
|
+
yield { prefix: '/components/', suffix: '/index' };
|
399
369
|
yield { prefix: '/components/', suffix: '/component' };
|
400
370
|
let pods = this.podPrefix(inPackageName);
|
401
371
|
if (pods) {
|
@@ -414,10 +384,10 @@ class Resolver {
|
|
414
384
|
parseGlobalPath(path, inEngine) {
|
415
385
|
let parts = path.split('@');
|
416
386
|
if (parts.length > 1 && parts[0].length > 0) {
|
417
|
-
return { packageName: parts[0], memberName: parts[1], from: (0, path_1.resolve)(inEngine.root, '
|
387
|
+
return { packageName: parts[0], memberName: parts[1], from: (0, path_1.resolve)(inEngine.root, 'package.json') };
|
418
388
|
}
|
419
389
|
else {
|
420
|
-
return { packageName: inEngine.packageName, memberName: path, from: (0, path_1.resolve)(inEngine.root, '
|
390
|
+
return { packageName: inEngine.packageName, memberName: path, from: (0, path_1.resolve)(inEngine.root, 'package.json') };
|
421
391
|
}
|
422
392
|
}
|
423
393
|
engineConfig(packageName) {
|
@@ -449,8 +419,8 @@ class Resolver {
|
|
449
419
|
engineModules.set(inEngineName, {
|
450
420
|
type: 'app-only',
|
451
421
|
'app-js': {
|
452
|
-
|
453
|
-
|
422
|
+
specifier: (0, reverse_exports_1.default)(addon.packageJSON, inAddonName),
|
423
|
+
fromFile: addonConfig.canResolveFromFile,
|
454
424
|
fromPackageName: addon.name,
|
455
425
|
},
|
456
426
|
});
|
@@ -463,8 +433,8 @@ class Resolver {
|
|
463
433
|
engineModules.set(inEngineName, {
|
464
434
|
type: 'both',
|
465
435
|
'app-js': {
|
466
|
-
|
467
|
-
|
436
|
+
specifier: (0, reverse_exports_1.default)(addon.packageJSON, inAddonName),
|
437
|
+
fromFile: addonConfig.canResolveFromFile,
|
468
438
|
fromPackageName: addon.name,
|
469
439
|
},
|
470
440
|
'fastboot-js': prevEntry['fastboot-js'],
|
@@ -488,8 +458,8 @@ class Resolver {
|
|
488
458
|
engineModules.set(inEngineName, {
|
489
459
|
type: 'fastboot-only',
|
490
460
|
'fastboot-js': {
|
491
|
-
|
492
|
-
|
461
|
+
specifier: (0, reverse_exports_1.default)(addon.packageJSON, inAddonName),
|
462
|
+
fromFile: addonConfig.canResolveFromFile,
|
493
463
|
fromPackageName: addon.name,
|
494
464
|
},
|
495
465
|
});
|
@@ -502,8 +472,8 @@ class Resolver {
|
|
502
472
|
engineModules.set(inEngineName, {
|
503
473
|
type: 'both',
|
504
474
|
'fastboot-js': {
|
505
|
-
|
506
|
-
|
475
|
+
specifier: (0, reverse_exports_1.default)(addon.packageJSON, inAddonName),
|
476
|
+
fromFile: addonConfig.canResolveFromFile,
|
507
477
|
fromPackageName: addon.name,
|
508
478
|
},
|
509
479
|
'app-js': prevEntry['app-js'],
|
@@ -525,7 +495,7 @@ class Resolver {
|
|
525
495
|
return owningEngine;
|
526
496
|
}
|
527
497
|
handleRewrittenPackages(request) {
|
528
|
-
if (request
|
498
|
+
if (isTerminal(request)) {
|
529
499
|
return request;
|
530
500
|
}
|
531
501
|
let requestingPkg = this.packageCache.ownerOfFile(request.fromFile);
|
@@ -544,10 +514,6 @@ class Resolver {
|
|
544
514
|
targetPkg = this.packageCache.resolve(packageName, requestingPkg);
|
545
515
|
}
|
546
516
|
catch (err) {
|
547
|
-
// this is not the place to report resolution failures. If the thing
|
548
|
-
// doesn't resolve, we're just not interested in redirecting it for
|
549
|
-
// backward-compat, that's all. The rest of the system will take care of
|
550
|
-
// reporting a failure to resolve (or handling it a different way)
|
551
517
|
if (err.code !== 'MODULE_NOT_FOUND') {
|
552
518
|
throw err;
|
553
519
|
}
|
@@ -563,14 +529,26 @@ class Resolver {
|
|
563
529
|
return logTransition('request targets a moved package', request, this.resolveWithinMovedPackage(request, targetPkg));
|
564
530
|
}
|
565
531
|
else if (originalRequestingPkg !== requestingPkg) {
|
566
|
-
|
567
|
-
|
568
|
-
|
532
|
+
if (targetPkg) {
|
533
|
+
// in this case, the requesting package is moved but its destination is
|
534
|
+
// not, so we need to rehome the request back to the original location.
|
535
|
+
return logTransition('outbound request from moved package', request, request
|
536
|
+
// setting meta here because if this fails, we want the fallback
|
537
|
+
// logic to revert our rehome and continue from the *moved* package.
|
538
|
+
.withMeta({ originalFromFile: request.fromFile })
|
539
|
+
.rehome((0, path_1.resolve)(originalRequestingPkg.root, 'package.json')));
|
540
|
+
}
|
541
|
+
else {
|
542
|
+
// requesting package was moved and we failed to find its target. We
|
543
|
+
// can't let that accidentally succeed in the defaultResolve because we
|
544
|
+
// could escape the moved package system.
|
545
|
+
return logTransition('missing outbound request from moved package', request, request.notFound());
|
546
|
+
}
|
569
547
|
}
|
570
548
|
return request;
|
571
549
|
}
|
572
550
|
handleRenaming(request) {
|
573
|
-
if (request
|
551
|
+
if (isTerminal(request)) {
|
574
552
|
return request;
|
575
553
|
}
|
576
554
|
let packageName = (0, shared_internals_1.packageName)(request.specifier);
|
@@ -603,12 +581,34 @@ class Resolver {
|
|
603
581
|
return logTransition(`renamePackages`, request, request.alias(request.specifier.replace(packageName, this.options.renamePackages[packageName])));
|
604
582
|
}
|
605
583
|
}
|
606
|
-
if (pkg.
|
607
|
-
// we found a self-import
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
584
|
+
if (pkg.name === packageName) {
|
585
|
+
// we found a self-import
|
586
|
+
if (pkg.meta['auto-upgraded']) {
|
587
|
+
// auto-upgraded packages always get automatically adjusted. They never
|
588
|
+
// supported fancy package.json exports features so this direct mapping
|
589
|
+
// to the root is always right.
|
590
|
+
// "my-package/foo" -> "./foo"
|
591
|
+
// "my-package" -> "./" (this can't be just "." because node's require.resolve doesn't reliable support that)
|
592
|
+
let selfImportPath = request.specifier === pkg.name ? './' : request.specifier.replace(pkg.name, '.');
|
593
|
+
return logTransition(`v1 self-import`, request, request.alias(selfImportPath).rehome((0, path_1.resolve)(pkg.root, 'package.json')));
|
594
|
+
}
|
595
|
+
else {
|
596
|
+
// v2 packages are supposed to use package.json `exports` to enable
|
597
|
+
// self-imports, but not all build tools actually follow the spec. This
|
598
|
+
// is a workaround for badly behaved packagers.
|
599
|
+
//
|
600
|
+
// Known upstream bugs this works around:
|
601
|
+
// - https://github.com/vitejs/vite/issues/9731
|
602
|
+
if (pkg.packageJSON.exports) {
|
603
|
+
let found = (0, resolve_exports_1.exports)(pkg.packageJSON, request.specifier, {
|
604
|
+
browser: true,
|
605
|
+
conditions: ['default', 'imports'],
|
606
|
+
});
|
607
|
+
if (found === null || found === void 0 ? void 0 : found[0]) {
|
608
|
+
return logTransition(`v2 self-import with package.json exports`, request, request.alias(found === null || found === void 0 ? void 0 : found[0]).rehome((0, path_1.resolve)(pkg.root, 'package.json')));
|
609
|
+
}
|
610
|
+
}
|
611
|
+
}
|
612
612
|
}
|
613
613
|
return request;
|
614
614
|
}
|
@@ -617,16 +617,17 @@ class Resolver {
|
|
617
617
|
if (pkg.name.startsWith('@')) {
|
618
618
|
levels.push('..');
|
619
619
|
}
|
620
|
+
let originalFromFile = request.fromFile;
|
620
621
|
let newRequest = request.rehome((0, path_1.resolve)(pkg.root, ...levels, 'moved-package-target.js'));
|
621
622
|
if (newRequest === request) {
|
622
623
|
return request;
|
623
624
|
}
|
624
|
-
|
625
|
-
|
626
|
-
});
|
625
|
+
// setting meta because if this fails, we want the fallback to pick up back
|
626
|
+
// in the original requesting package.
|
627
|
+
return newRequest.withMeta({ originalFromFile });
|
627
628
|
}
|
628
629
|
preHandleExternal(request) {
|
629
|
-
if (request
|
630
|
+
if (isTerminal(request)) {
|
630
631
|
return request;
|
631
632
|
}
|
632
633
|
let { specifier, fromFile } = request;
|
@@ -659,7 +660,15 @@ class Resolver {
|
|
659
660
|
// engine
|
660
661
|
let logicalLocation = this.reverseSearchAppTree(pkg, request.fromFile);
|
661
662
|
if (logicalLocation) {
|
662
|
-
return logTransition('beforeResolve: relative import in app-js', request, request
|
663
|
+
return logTransition('beforeResolve: relative import in app-js', request, request
|
664
|
+
.alias('./' + path_1.posix.join((0, path_1.dirname)(logicalLocation.inAppName), request.specifier))
|
665
|
+
// it's important that we're rehoming this to the root of the engine
|
666
|
+
// (which we know really exists), and not to a subdir like
|
667
|
+
// logicalLocation.inAppName (which might not physically exist),
|
668
|
+
// because some environments (including node's require.resolve) will
|
669
|
+
// refuse to do resolution from a notional path that doesn't
|
670
|
+
// physically exist.
|
671
|
+
.rehome((0, path_1.resolve)(logicalLocation.owningEngine.root, 'package.json')));
|
663
672
|
}
|
664
673
|
return request;
|
665
674
|
}
|
@@ -674,11 +683,11 @@ class Resolver {
|
|
674
683
|
if (shared_internals_1.emberVirtualPeerDeps.has(packageName) && !pkg.hasDependency(packageName)) {
|
675
684
|
// addons (whether auto-upgraded or not) may use the app's
|
676
685
|
// emberVirtualPeerDeps, like "@glimmer/component" etc.
|
677
|
-
|
678
|
-
|
686
|
+
let addon = this.locateActiveAddon(packageName);
|
687
|
+
if (!addon) {
|
688
|
+
throw new Error(`${pkg.name} is trying to import the emberVirtualPeerDep "${packageName}", but it seems to be missing`);
|
679
689
|
}
|
680
|
-
|
681
|
-
return logTransition(`emberVirtualPeerDeps in v2 addon`, request, request.rehome(newHome));
|
690
|
+
return logTransition(`emberVirtualPeerDeps`, request, request.rehome(addon.canResolveFromFile));
|
682
691
|
}
|
683
692
|
// if this file is part of an addon's app-js, it's really the logical
|
684
693
|
// package to which it belongs (normally the app) that affects some policy
|
@@ -709,6 +718,22 @@ class Resolver {
|
|
709
718
|
}
|
710
719
|
return request;
|
711
720
|
}
|
721
|
+
locateActiveAddon(packageName) {
|
722
|
+
if (packageName === this.options.modulePrefix) {
|
723
|
+
// the app itself is something that addon's can classically resolve if they know it's name.
|
724
|
+
return {
|
725
|
+
root: this.options.appRoot,
|
726
|
+
canResolveFromFile: (0, path_1.resolve)(this.packageCache.maybeMoved(this.packageCache.get(this.options.appRoot)).root, 'package.json'),
|
727
|
+
};
|
728
|
+
}
|
729
|
+
for (let engine of this.options.engines) {
|
730
|
+
for (let addon of engine.activeAddons) {
|
731
|
+
if (addon.name === packageName) {
|
732
|
+
return addon;
|
733
|
+
}
|
734
|
+
}
|
735
|
+
}
|
736
|
+
}
|
712
737
|
external(label, request, specifier) {
|
713
738
|
if (this.options.amdCompatibility === 'cjs') {
|
714
739
|
let filename = (0, virtual_content_1.virtualExternalCJSModule)(specifier);
|
@@ -741,8 +766,11 @@ class Resolver {
|
|
741
766
|
throw new Error(`Embroider's amdCompatibility option is disabled, but something tried to use it to access "${request.specifier}"`);
|
742
767
|
}
|
743
768
|
}
|
744
|
-
fallbackResolve(request) {
|
769
|
+
async fallbackResolve(request) {
|
745
770
|
var _a, _b, _c;
|
771
|
+
if (request.isVirtual) {
|
772
|
+
throw new Error('Build tool bug detected! Fallback resolve should never see a virtual request. It is expected that the defaultResolve for your bundler has already resolved this request');
|
773
|
+
}
|
746
774
|
if (request.specifier === '@embroider/macros') {
|
747
775
|
// the macros package is always handled directly within babel (not
|
748
776
|
// necessarily as a real resolvable package), so we should not mess with it.
|
@@ -750,8 +778,7 @@ class Resolver {
|
|
750
778
|
// why we need to know about it.
|
751
779
|
return logTransition('fallback early exit', request);
|
752
780
|
}
|
753
|
-
|
754
|
-
if (compatPattern.test(specifier)) {
|
781
|
+
if (compatPattern.test(request.specifier)) {
|
755
782
|
// Some kinds of compat requests get rewritten into other things
|
756
783
|
// deterministically. For example, "#embroider_compat/helpers/whatever"
|
757
784
|
// means only "the-current-engine/helpers/whatever", and if that doesn't
|
@@ -767,39 +794,33 @@ class Resolver {
|
|
767
794
|
// here.
|
768
795
|
return request;
|
769
796
|
}
|
770
|
-
|
771
|
-
if (!((_a = request.meta) === null || _a === void 0 ? void 0 : _a.resolvedWithinPackage)) {
|
772
|
-
throw new Error(`bug: embroider resolver's meta is not propagating`);
|
773
|
-
}
|
774
|
-
fromFile = (0, path_1.resolve)((_b = request.meta) === null || _b === void 0 ? void 0 : _b.resolvedWithinPackage, 'package.json');
|
775
|
-
}
|
776
|
-
let pkg = this.packageCache.ownerOfFile(fromFile);
|
797
|
+
let pkg = this.packageCache.ownerOfFile(request.fromFile);
|
777
798
|
if (!pkg) {
|
778
799
|
return logTransition('no identifiable owningPackage', request);
|
779
800
|
}
|
780
|
-
//
|
781
|
-
// to
|
782
|
-
//
|
783
|
-
// isV2Ember()
|
801
|
+
// meta.originalFromFile gets set when we want to try to rehome a request
|
802
|
+
// but then come back to the original location here in the fallback when the
|
803
|
+
// rehomed request fails
|
784
804
|
let movedPkg = this.packageCache.maybeMoved(pkg);
|
785
805
|
if (movedPkg !== pkg) {
|
786
|
-
|
806
|
+
let originalFromFile = (_a = request.meta) === null || _a === void 0 ? void 0 : _a.originalFromFile;
|
807
|
+
if (typeof originalFromFile !== 'string') {
|
787
808
|
throw new Error(`bug: embroider resolver's meta is not propagating`);
|
788
809
|
}
|
789
|
-
|
810
|
+
request = request.rehome(originalFromFile);
|
790
811
|
pkg = movedPkg;
|
791
812
|
}
|
792
813
|
if (!pkg.isV2Ember()) {
|
793
814
|
return logTransition('fallbackResolve: not in an ember package', request);
|
794
815
|
}
|
795
|
-
let packageName = (0, shared_internals_1.packageName)(specifier);
|
816
|
+
let packageName = (0, shared_internals_1.packageName)(request.specifier);
|
796
817
|
if (!packageName) {
|
797
818
|
// this is a relative import
|
798
819
|
let withinEngine = this.engineConfig(pkg.name);
|
799
820
|
if (withinEngine) {
|
800
821
|
// it's a relative import inside an engine (which also means app), which
|
801
822
|
// means we may need to satisfy the request via app tree merging.
|
802
|
-
let appJSMatch = this.searchAppTree(request, withinEngine, (0, shared_internals_2.explicitRelative)(pkg.root, (0, path_1.resolve)((0, path_1.dirname)(fromFile), specifier)));
|
823
|
+
let appJSMatch = await this.searchAppTree(request, withinEngine, (0, shared_internals_2.explicitRelative)(pkg.root, (0, path_1.resolve)((0, path_1.dirname)(request.fromFile), request.specifier)));
|
803
824
|
if (appJSMatch) {
|
804
825
|
return logTransition('fallbackResolve: relative appJsMatch', request, appJSMatch);
|
805
826
|
}
|
@@ -813,40 +834,49 @@ class Resolver {
|
|
813
834
|
}
|
814
835
|
}
|
815
836
|
// auto-upgraded packages can fall back to the set of known active addons
|
816
|
-
if (pkg.meta['auto-upgraded']
|
817
|
-
|
818
|
-
if (
|
819
|
-
|
837
|
+
if (pkg.meta['auto-upgraded']) {
|
838
|
+
let addon = this.locateActiveAddon(packageName);
|
839
|
+
if (addon) {
|
840
|
+
const rehomed = request.rehome(addon.canResolveFromFile);
|
841
|
+
if (rehomed !== request) {
|
842
|
+
return logTransition(`activeAddons`, request, rehomed);
|
843
|
+
}
|
820
844
|
}
|
821
845
|
}
|
822
|
-
let logicalLocation = this.reverseSearchAppTree(pkg, fromFile);
|
846
|
+
let logicalLocation = this.reverseSearchAppTree(pkg, request.fromFile);
|
823
847
|
if (logicalLocation) {
|
824
848
|
// the requesting file is in an addon's appTree. We didn't succeed in
|
825
849
|
// resolving this (non-relative) request from inside the actual addon, so
|
826
850
|
// next try to resolve it from the corresponding logical location in the
|
827
851
|
// app.
|
828
|
-
return logTransition('fallbackResolve: retry from logical home of app-js file', request,
|
852
|
+
return logTransition('fallbackResolve: retry from logical home of app-js file', request,
|
853
|
+
// it might look more precise to rehome into logicalLocation.inAppName
|
854
|
+
// rather than package.json. But that logical location may not actually
|
855
|
+
// exist, and some systems (including node's require.resolve) will be
|
856
|
+
// mad about trying to resolve from notional paths that don't really
|
857
|
+
// exist.
|
858
|
+
request.rehome((0, path_1.resolve)(logicalLocation.owningEngine.root, 'package.json')));
|
829
859
|
}
|
830
860
|
let targetingEngine = this.engineConfig(packageName);
|
831
861
|
if (targetingEngine) {
|
832
|
-
let appJSMatch = this.searchAppTree(request, targetingEngine, specifier.replace(packageName, '.'));
|
862
|
+
let appJSMatch = await this.searchAppTree(request, targetingEngine, request.specifier.replace(packageName, '.'));
|
833
863
|
if (appJSMatch) {
|
834
864
|
return logTransition('fallbackResolve: non-relative appJsMatch', request, appJSMatch);
|
835
865
|
}
|
836
866
|
}
|
837
|
-
if (pkg.meta['auto-upgraded']) {
|
867
|
+
if (pkg.meta['auto-upgraded'] && ((_c = (_b = request.meta) === null || _b === void 0 ? void 0 : _b.runtimeFallback) !== null && _c !== void 0 ? _c : true)) {
|
838
868
|
// auto-upgraded packages can fall back to attempting to find dependencies at
|
839
869
|
// runtime. Native v2 packages can only get this behavior in the
|
840
870
|
// isExplicitlyExternal case above because they need to explicitly ask for
|
841
871
|
// externals.
|
842
|
-
return this.external('v1 catch-all fallback', request, specifier);
|
872
|
+
return this.external('v1 catch-all fallback', request, request.specifier);
|
843
873
|
}
|
844
874
|
else {
|
845
875
|
// native v2 packages don't automatically externalize *everything* the way
|
846
876
|
// auto-upgraded packages do, but they still externalize known and approved
|
847
877
|
// ember virtual packages (like @ember/component)
|
848
878
|
if (shared_internals_1.emberVirtualPackages.has(packageName)) {
|
849
|
-
return this.external('emberVirtualPackages', request, specifier);
|
879
|
+
return this.external('emberVirtualPackages', request, request.specifier);
|
850
880
|
}
|
851
881
|
}
|
852
882
|
// this is falling through with the original specifier which was
|
@@ -873,22 +903,20 @@ class Resolver {
|
|
873
903
|
}
|
874
904
|
}
|
875
905
|
}
|
876
|
-
searchAppTree(request, engine, inEngineSpecifier) {
|
906
|
+
async searchAppTree(request, engine, inEngineSpecifier) {
|
877
907
|
let matched = this.getEntryFromMergeMap(inEngineSpecifier, engine.root);
|
878
908
|
switch (matched === null || matched === void 0 ? void 0 : matched.entry.type) {
|
879
909
|
case undefined:
|
880
910
|
return undefined;
|
881
911
|
case 'app-only':
|
882
|
-
return request
|
883
|
-
.alias(matched.entry['app-js'].localPath)
|
884
|
-
.rehome((0, path_1.resolve)(matched.entry['app-js'].packageRoot, 'package.json'));
|
912
|
+
return request.alias(matched.entry['app-js'].specifier).rehome(matched.entry['app-js'].fromFile);
|
885
913
|
case 'fastboot-only':
|
886
|
-
return request
|
887
|
-
.alias(matched.entry['fastboot-js'].localPath)
|
888
|
-
.rehome((0, path_1.resolve)(matched.entry['fastboot-js'].packageRoot, 'package.json'));
|
914
|
+
return request.alias(matched.entry['fastboot-js'].specifier).rehome(matched.entry['fastboot-js'].fromFile);
|
889
915
|
case 'both':
|
890
|
-
let foundAppJS = this.
|
891
|
-
|
916
|
+
let foundAppJS = await this.resolve(request.alias(matched.entry['app-js'].specifier).rehome(matched.entry['app-js'].fromFile).withMeta({
|
917
|
+
runtimeFallback: false,
|
918
|
+
}));
|
919
|
+
if (foundAppJS.type !== 'found') {
|
892
920
|
throw new Error(`${matched.entry['app-js'].fromPackageName} declared ${inEngineSpecifier} in packageJSON.ember-addon.app-js, but that module does not exist`);
|
893
921
|
}
|
894
922
|
let { names } = (0, describe_exports_1.describeExports)((0, fs_1.readFileSync)(foundAppJS.filename, 'utf8'), {});
|