@embroider/core 3.4.4 → 3.4.6-unstable.11f2c70

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 resolve_1 = __importDefault(require("resolve"));
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(`virtualized %s in %s because %s`, before.specifier, before.fromFile, reason);
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: %s to %s, from %s to %s because %s`, before.specifier, after.specifier, before.fromFile, after.fromFile, reason);
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: %s to %s in %s because`, before.specifier, after.specifier, before.fromFile, reason);
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: %s from %s to %s because`, before.specifier, before.fromFile, after.fromFile, reason);
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(`unchanged: %s in %s because %s`, before.specifier, before.fromFile, reason);
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
- const compatPattern = /#embroider_compat\/(?<type>[^\/]+)\/(?<rest>.*)/;
45
- class NodeModuleRequest {
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
- // Depending on the plugin architecture you're working in, it may be easier to
101
- // call beforeResolve and fallbackResolve directly, in which case matching the
102
- // details of the recursion to what this method does are your responsibility.
103
- async resolve(request, defaultResolve) {
104
- let gen = this.internalResolve(request, defaultResolve);
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 beforeResolve or
145
- // fallbackResolve around them. The defaultResolve is expected to know how
146
- // to implement them.
147
- return yield defaultResolve(nextRequest);
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 yield* this.internalResolve(nextRequest, defaultResolve);
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
- let resolution = this.resolveSync(new NodeModuleRequest(specifier, fromFile, false, undefined), request => {
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].localPath).rehome((0, path_1.resolve)(entry[section].packageRoot, 'package.json')));
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 resolution = this.nodeResolve(`${target.packageName}${candidate.prefix}${target.memberName}${candidate.suffix}`, target.from);
336
- if (resolution.type === 'real') {
337
- hbsModule = resolution.filename;
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 resolution = this.nodeResolve(`${target.packageName}${candidate.prefix}${target.memberName}${candidate.suffix}`, target.from);
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 === 'real' && !resolution.filename.endsWith('.hbs')) {
348
- jsModule = resolution.filename;
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.alias(jsModule).rehome(target.from));
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.nodeResolve(helperCandidate.specifier, helperCandidate.fromFile);
368
- if (helperMatch.type === 'real') {
369
- return logTransition('ambiguous case matched a helper', request, helperCandidate);
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, 'pacakge.json') };
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, 'pacakge.json') };
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
- localPath: inAddonName,
453
- packageRoot: addon.root,
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
- localPath: inAddonName,
467
- packageRoot: addon.root,
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
- localPath: inAddonName,
492
- packageRoot: addon.root,
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
- localPath: inAddonName,
506
- packageRoot: addon.root,
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.isVirtual) {
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
- // in this case, the requesting package is moved but its destination is
567
- // not, so we need to rehome the request back to the original location.
568
- return logTransition('outbound request from moved package', request, request.withMeta({ wasMovedTo: request.fromFile }).rehome((0, path_1.resolve)(originalRequestingPkg.root, 'package.json')));
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.isVirtual) {
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.meta['auto-upgraded'] && pkg.name === packageName) {
607
- // we found a self-import, resolve it for them. Only auto-upgraded
608
- // packages get this help, v2 packages are natively supposed to make their
609
- // own modules resolvable, and we want to push them all to do that
610
- // correctly.
611
- return logTransition(`v1 self-import`, request, request.alias(request.specifier.replace(pkg.name, '.')).rehome((0, path_1.resolve)(pkg.root, 'package.json')));
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
- return newRequest.withMeta({
625
- resolvedWithinPackage: pkg.root,
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.isVirtual) {
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.rehome((0, path_1.resolve)(logicalLocation.owningEngine.root, logicalLocation.inAppName)));
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
- if (!this.options.activeAddons[packageName]) {
678
- throw new Error(`${pkg.name} is trying to import the app's ${packageName} package, but it seems to be missing`);
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
- let newHome = (0, path_1.resolve)(this.packageCache.maybeMoved(this.packageCache.get(this.options.appRoot)).root, 'package.json');
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
- let { specifier, fromFile } = request;
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
- if (fromFile.endsWith('moved-package-target.js')) {
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
- // if we rehomed this request to its un-rewritten location in order to try
781
- // to do the defaultResolve from there, now we refer back to the rewritten
782
- // location because that's what we want to use when asking things like
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
- if (!((_c = request.meta) === null || _c === void 0 ? void 0 : _c.wasMovedTo)) {
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
- fromFile = request.meta.wasMovedTo;
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'] && this.options.activeAddons[packageName]) {
817
- const rehomed = this.resolveWithinMovedPackage(request, this.packageCache.get(this.options.activeAddons[packageName]));
818
- if (rehomed !== request) {
819
- return logTransition(`activeAddons`, request, rehomed);
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, request.rehome((0, path_1.resolve)(logicalLocation.owningEngine.root, logicalLocation.inAppName)));
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.nodeResolve(matched.entry['app-js'].localPath, (0, path_1.resolve)(matched.entry['app-js'].packageRoot, 'package.json'));
891
- if (foundAppJS.type !== 'real') {
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'), {});