@embroider/core 3.4.7 → 3.4.8-unstable.649e0eb

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,9 +75,15 @@ 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);
84
+ request = this.handleImplicitTestScripts(request);
85
+ request = this.handleVendorStyles(request);
86
+ request = this.handleTestSupportStyles(request);
85
87
  request = this.handleRenaming(request);
86
88
  // we expect the specifier to be app relative at this point - must be after handleRenaming
87
89
  request = this.generateFastbootSwitch(request);
@@ -96,95 +98,45 @@ class Resolver {
96
98
  // that calls your build system's normal module resolver, this does both pre-
97
99
  // and post-resolution adjustments as needed to implement our compatibility
98
100
  // 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);
101
+ async resolve(request) {
102
+ request = await this.beforeResolve(request);
103
+ if (request.resolvedTo) {
104
+ return request.resolvedTo;
105
+ }
106
+ let resolution = await request.defaultResolve();
127
107
  switch (resolution.type) {
128
108
  case 'found':
109
+ case 'ignored':
129
110
  return resolution;
130
111
  case 'not_found':
131
112
  break;
132
113
  default:
133
114
  throw (0, assert_never_1.default)(resolution);
134
115
  }
135
- let nextRequest = this.fallbackResolve(request);
116
+ let nextRequest = await this.fallbackResolve(request);
136
117
  if (nextRequest === request) {
137
118
  // no additional fallback is available.
138
119
  return resolution;
139
120
  }
121
+ if (nextRequest.resolvedTo) {
122
+ return nextRequest.resolvedTo;
123
+ }
140
124
  if (nextRequest.fromFile === request.fromFile && nextRequest.specifier === request.specifier) {
141
125
  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
126
  }
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);
127
+ if (nextRequest.isVirtual || nextRequest.isNotFound) {
128
+ // virtual and NotFound requests are terminal, there is no more
129
+ // beforeResolve or fallbackResolve around them. The defaultResolve is
130
+ // expected to know how to implement them.
131
+ return nextRequest.defaultResolve();
148
132
  }
149
- return yield* this.internalResolve(nextRequest, defaultResolve);
133
+ return this.resolve(nextRequest);
150
134
  }
151
135
  // Use standard NodeJS resolving, with our required compatibility rules on
152
136
  // top. This is a convenience method for calling resolveSync with the
153
137
  // 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
- }
138
+ async nodeResolve(specifier, fromFile) {
139
+ return (0, node_resolve_1.nodeResolve)(this, specifier, fromFile);
188
140
  }
189
141
  get packageCache() {
190
142
  return shared_internals_2.RewrittenPackageCache.shared('embroider', this.options.appRoot);
@@ -201,6 +153,9 @@ class Resolver {
201
153
  return owningPackage;
202
154
  }
203
155
  generateFastbootSwitch(request) {
156
+ if (isTerminal(request)) {
157
+ return request;
158
+ }
204
159
  let pkg = this.packageCache.ownerOfFile(request.fromFile);
205
160
  if (!pkg) {
206
161
  return request;
@@ -218,7 +173,9 @@ class Resolver {
218
173
  let fastbootFile = engineConfig.fastbootFiles[candidate];
219
174
  if (fastbootFile) {
220
175
  if (fastbootFile.shadowedFilename) {
221
- let { names } = (0, describe_exports_1.describeExports)((0, fs_1.readFileSync)((0, path_1.resolve)(pkg.root, fastbootFile.shadowedFilename), 'utf8'), {});
176
+ let { names } = (0, describe_exports_1.describeExports)((0, fs_1.readFileSync)((0, path_1.resolve)(pkg.root, fastbootFile.shadowedFilename), 'utf8'), {
177
+ configFile: false,
178
+ });
222
179
  let switchFile = (0, virtual_content_1.fastbootSwitch)(candidate, (0, path_1.resolve)(pkg.root, 'package.json'), names);
223
180
  if (switchFile === request.fromFile) {
224
181
  return logTransition('internal lookup from fastbootSwitch', request);
@@ -237,6 +194,9 @@ class Resolver {
237
194
  }
238
195
  handleFastbootSwitch(request) {
239
196
  var _a;
197
+ if (isTerminal(request)) {
198
+ return request;
199
+ }
240
200
  let match = (0, virtual_content_1.decodeFastbootSwitch)(request.fromFile);
241
201
  if (!match) {
242
202
  return request;
@@ -275,12 +235,15 @@ class Resolver {
275
235
  }
276
236
  let entry = (_a = this.getEntryFromMergeMap(rel, pkg.root)) === null || _a === void 0 ? void 0 : _a.entry;
277
237
  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')));
238
+ return logTransition('matched addon entry', request, request.alias(entry[section].specifier).rehome(entry[section].fromFile));
279
239
  }
280
240
  }
281
241
  return logTransition('failed to match in fastboot switch', request);
282
242
  }
283
243
  handleImplicitModules(request) {
244
+ if (isTerminal(request)) {
245
+ return request;
246
+ }
284
247
  let im = (0, virtual_content_1.decodeImplicitModules)(request.specifier);
285
248
  if (!im) {
286
249
  return request;
@@ -298,7 +261,42 @@ class Resolver {
298
261
  return logTransition(`own implicit modules`, request, request.virtualize((0, path_1.resolve)(pkg.root, `-embroider-${im.type}.js`)));
299
262
  }
300
263
  }
301
- handleGlobalsCompat(request) {
264
+ handleImplicitTestScripts(request) {
265
+ //TODO move the extra forwardslash handling out into the vite plugin
266
+ const candidates = [
267
+ '@embroider/core/test-support.js',
268
+ '/@embroider/core/test-support.js',
269
+ './@embroider/core/test-support.js',
270
+ ];
271
+ if (!candidates.includes(request.specifier)) {
272
+ return request;
273
+ }
274
+ let pkg = this.packageCache.ownerOfFile(request.fromFile);
275
+ if ((pkg === null || pkg === void 0 ? void 0 : pkg.root) !== this.options.engines[0].root) {
276
+ throw new Error(`bug: found an import of ${request.specifier} in ${request.fromFile}, but this is not the top-level Ember app. The top-level Ember app is the only one that has support for @embroider/core/test-support.js. If you think something should be fixed in Embroider, please open an issue on https://github.com/embroider-build/embroider/issues.`);
277
+ }
278
+ return logTransition('test-support', request, request.virtualize((0, path_1.resolve)(pkg.root, '-embroider-test-support.js')));
279
+ }
280
+ handleTestSupportStyles(request) {
281
+ //TODO move the extra forwardslash handling out into the vite plugin
282
+ const candidates = [
283
+ '@embroider/core/test-support.css',
284
+ '/@embroider/core/test-support.css',
285
+ './@embroider/core/test-support.css',
286
+ ];
287
+ if (!candidates.includes(request.specifier)) {
288
+ return request;
289
+ }
290
+ let pkg = this.packageCache.ownerOfFile(request.fromFile);
291
+ if ((pkg === null || pkg === void 0 ? void 0 : pkg.root) !== this.options.engines[0].root) {
292
+ throw new Error(`bug: found an import of ${request.specifier} in ${request.fromFile}, but this is not the top-level Ember app. The top-level Ember app is the only one that has support for @embroider/core/test-support.css. If you think something should be fixed in Embroider, please open an issue on https://github.com/embroider-build/embroider/issues.`);
293
+ }
294
+ return logTransition('test-support-styles', request, request.virtualize((0, path_1.resolve)(pkg.root, '-embroider-test-support-styles.css')));
295
+ }
296
+ async handleGlobalsCompat(request) {
297
+ if (isTerminal(request)) {
298
+ return request;
299
+ }
302
300
  let match = compatPattern.exec(request.specifier);
303
301
  if (!match) {
304
302
  return request;
@@ -322,56 +320,76 @@ class Resolver {
322
320
  throw new Error(`bug: unexepected #embroider_compat specifier: ${request.specifier}`);
323
321
  }
324
322
  }
323
+ handleVendorStyles(request) {
324
+ //TODO move the extra forwardslash handling out into the vite plugin
325
+ const candidates = ['@embroider/core/vendor.css', '/@embroider/core/vendor.css', './@embroider/core/vendor.css'];
326
+ if (!candidates.includes(request.specifier)) {
327
+ return request;
328
+ }
329
+ let pkg = this.packageCache.ownerOfFile(request.fromFile);
330
+ if ((pkg === null || pkg === void 0 ? void 0 : pkg.root) !== this.options.engines[0].root) {
331
+ throw new Error(`bug: found an import of ${request.specifier} in ${request.fromFile}, but this is not the top-level Ember app. The top-level Ember app is the only one that has support for @embroider/core/vendor.css. If you think something should be fixed in Embroider, please open an issue on https://github.com/embroider-build/embroider/issues.`);
332
+ }
333
+ return logTransition('vendor-styles', request, request.virtualize((0, path_1.resolve)(pkg.root, '-embroider-vendor-styles.css')));
334
+ }
325
335
  resolveHelper(path, inEngine, request) {
326
336
  let target = this.parseGlobalPath(path, inEngine);
327
337
  return logTransition('resolveHelper', request, request.alias(`${target.packageName}/helpers/${target.memberName}`).rehome((0, path_1.resolve)(inEngine.root, 'package.json')));
328
338
  }
329
- resolveComponent(path, inEngine, request) {
339
+ async resolveComponent(path, inEngine, request) {
330
340
  let target = this.parseGlobalPath(path, inEngine);
331
341
  let hbsModule = null;
332
342
  let jsModule = null;
333
343
  // first, the various places our template might be.
334
344
  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;
345
+ let candidateSpecifier = `${target.packageName}${candidate.prefix}${target.memberName}${candidate.suffix}`;
346
+ let resolution = await this.resolve(request.alias(candidateSpecifier).rehome(target.from).withMeta({
347
+ runtimeFallback: false,
348
+ }));
349
+ if (resolution.type === 'found') {
350
+ hbsModule = resolution;
338
351
  break;
339
352
  }
340
353
  }
341
354
  // then the various places our javascript might be.
342
355
  for (let candidate of this.componentJSCandidates(target.packageName)) {
343
- let resolution = this.nodeResolve(`${target.packageName}${candidate.prefix}${target.memberName}${candidate.suffix}`, target.from);
356
+ let candidateSpecifier = `${target.packageName}${candidate.prefix}${target.memberName}${candidate.suffix}`;
357
+ let resolution = await this.resolve(request.alias(candidateSpecifier).rehome(target.from).withMeta({
358
+ runtimeFallback: false,
359
+ }));
344
360
  // .hbs is a resolvable extension for us, so we need to exclude it here.
345
361
  // It matches as a priority lower than .js, so finding an .hbs means
346
362
  // there's definitely not a .js.
347
- if (resolution.type === 'real' && !resolution.filename.endsWith('.hbs')) {
348
- jsModule = resolution.filename;
363
+ if (resolution.type === 'found' && !resolution.filename.endsWith('.hbs')) {
364
+ jsModule = resolution;
349
365
  break;
350
366
  }
351
367
  }
352
368
  if (hbsModule) {
353
- return logTransition(`resolveComponent found legacy HBS`, request, request.virtualize((0, virtual_content_1.virtualPairComponent)(hbsModule, jsModule)));
369
+ 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
370
  }
355
371
  else if (jsModule) {
356
- return logTransition(`resolveComponent found only JS`, request, request.alias(jsModule).rehome(target.from));
372
+ return logTransition(`resolving to resolveComponent found only JS`, request, request.resolveTo(jsModule));
357
373
  }
358
374
  else {
359
375
  return logTransition(`resolveComponent failed`, request);
360
376
  }
361
377
  }
362
- resolveHelperOrComponent(path, inEngine, request) {
378
+ async resolveHelperOrComponent(path, inEngine, request) {
363
379
  // resolveHelper just rewrites our request to one that should target the
364
380
  // component, so here to resolve the ambiguity we need to actually resolve
365
381
  // that candidate to see if it works.
366
382
  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);
383
+ let helperMatch = await this.resolve(request.alias(helperCandidate.specifier).rehome(helperCandidate.fromFile).withMeta({
384
+ runtimeFallback: false,
385
+ }));
386
+ if (helperMatch.type === 'found') {
387
+ return logTransition('resolve to ambiguous case matched a helper', request, request.resolveTo(helperMatch));
370
388
  }
371
389
  // unlike resolveHelper, resolveComponent already does pre-resolution in
372
390
  // order to deal with its own internal ambiguity around JS vs HBS vs
373
391
  // colocation.≥
374
- let componentMatch = this.resolveComponent(path, inEngine, request);
392
+ let componentMatch = await this.resolveComponent(path, inEngine, request);
375
393
  if (componentMatch !== request) {
376
394
  return logTransition('ambiguous case matched a cmoponent', request, componentMatch);
377
395
  }
@@ -396,6 +414,7 @@ class Resolver {
396
414
  }
397
415
  *componentJSCandidates(inPackageName) {
398
416
  yield { prefix: '/components/', suffix: '' };
417
+ yield { prefix: '/components/', suffix: '/index' };
399
418
  yield { prefix: '/components/', suffix: '/component' };
400
419
  let pods = this.podPrefix(inPackageName);
401
420
  if (pods) {
@@ -414,10 +433,10 @@ class Resolver {
414
433
  parseGlobalPath(path, inEngine) {
415
434
  let parts = path.split('@');
416
435
  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') };
436
+ return { packageName: parts[0], memberName: parts[1], from: (0, path_1.resolve)(inEngine.root, 'package.json') };
418
437
  }
419
438
  else {
420
- return { packageName: inEngine.packageName, memberName: path, from: (0, path_1.resolve)(inEngine.root, 'pacakge.json') };
439
+ return { packageName: inEngine.packageName, memberName: path, from: (0, path_1.resolve)(inEngine.root, 'package.json') };
421
440
  }
422
441
  }
423
442
  engineConfig(packageName) {
@@ -449,8 +468,8 @@ class Resolver {
449
468
  engineModules.set(inEngineName, {
450
469
  type: 'app-only',
451
470
  'app-js': {
452
- localPath: inAddonName,
453
- packageRoot: addon.root,
471
+ specifier: (0, reverse_exports_1.default)(addon.packageJSON, inAddonName),
472
+ fromFile: addonConfig.canResolveFromFile,
454
473
  fromPackageName: addon.name,
455
474
  },
456
475
  });
@@ -463,8 +482,8 @@ class Resolver {
463
482
  engineModules.set(inEngineName, {
464
483
  type: 'both',
465
484
  'app-js': {
466
- localPath: inAddonName,
467
- packageRoot: addon.root,
485
+ specifier: (0, reverse_exports_1.default)(addon.packageJSON, inAddonName),
486
+ fromFile: addonConfig.canResolveFromFile,
468
487
  fromPackageName: addon.name,
469
488
  },
470
489
  'fastboot-js': prevEntry['fastboot-js'],
@@ -488,8 +507,8 @@ class Resolver {
488
507
  engineModules.set(inEngineName, {
489
508
  type: 'fastboot-only',
490
509
  'fastboot-js': {
491
- localPath: inAddonName,
492
- packageRoot: addon.root,
510
+ specifier: (0, reverse_exports_1.default)(addon.packageJSON, inAddonName),
511
+ fromFile: addonConfig.canResolveFromFile,
493
512
  fromPackageName: addon.name,
494
513
  },
495
514
  });
@@ -502,8 +521,8 @@ class Resolver {
502
521
  engineModules.set(inEngineName, {
503
522
  type: 'both',
504
523
  'fastboot-js': {
505
- localPath: inAddonName,
506
- packageRoot: addon.root,
524
+ specifier: (0, reverse_exports_1.default)(addon.packageJSON, inAddonName),
525
+ fromFile: addonConfig.canResolveFromFile,
507
526
  fromPackageName: addon.name,
508
527
  },
509
528
  'app-js': prevEntry['app-js'],
@@ -525,7 +544,7 @@ class Resolver {
525
544
  return owningEngine;
526
545
  }
527
546
  handleRewrittenPackages(request) {
528
- if (request.isVirtual) {
547
+ if (isTerminal(request)) {
529
548
  return request;
530
549
  }
531
550
  let requestingPkg = this.packageCache.ownerOfFile(request.fromFile);
@@ -544,10 +563,6 @@ class Resolver {
544
563
  targetPkg = this.packageCache.resolve(packageName, requestingPkg);
545
564
  }
546
565
  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
566
  if (err.code !== 'MODULE_NOT_FOUND') {
552
567
  throw err;
553
568
  }
@@ -563,14 +578,26 @@ class Resolver {
563
578
  return logTransition('request targets a moved package', request, this.resolveWithinMovedPackage(request, targetPkg));
564
579
  }
565
580
  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')));
581
+ if (targetPkg) {
582
+ // in this case, the requesting package is moved but its destination is
583
+ // not, so we need to rehome the request back to the original location.
584
+ return logTransition('outbound request from moved package', request, request
585
+ // setting meta here because if this fails, we want the fallback
586
+ // logic to revert our rehome and continue from the *moved* package.
587
+ .withMeta({ originalFromFile: request.fromFile })
588
+ .rehome((0, path_1.resolve)(originalRequestingPkg.root, 'package.json')));
589
+ }
590
+ else {
591
+ // requesting package was moved and we failed to find its target. We
592
+ // can't let that accidentally succeed in the defaultResolve because we
593
+ // could escape the moved package system.
594
+ return logTransition('missing outbound request from moved package', request, request.notFound());
595
+ }
569
596
  }
570
597
  return request;
571
598
  }
572
599
  handleRenaming(request) {
573
- if (request.isVirtual) {
600
+ if (isTerminal(request)) {
574
601
  return request;
575
602
  }
576
603
  let packageName = (0, shared_internals_1.packageName)(request.specifier);
@@ -603,12 +630,34 @@ class Resolver {
603
630
  return logTransition(`renamePackages`, request, request.alias(request.specifier.replace(packageName, this.options.renamePackages[packageName])));
604
631
  }
605
632
  }
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')));
633
+ if (pkg.name === packageName) {
634
+ // we found a self-import
635
+ if (pkg.meta['auto-upgraded']) {
636
+ // auto-upgraded packages always get automatically adjusted. They never
637
+ // supported fancy package.json exports features so this direct mapping
638
+ // to the root is always right.
639
+ // "my-package/foo" -> "./foo"
640
+ // "my-package" -> "./" (this can't be just "." because node's require.resolve doesn't reliable support that)
641
+ let selfImportPath = request.specifier === pkg.name ? './' : request.specifier.replace(pkg.name, '.');
642
+ return logTransition(`v1 self-import`, request, request.alias(selfImportPath).rehome((0, path_1.resolve)(pkg.root, 'package.json')));
643
+ }
644
+ else {
645
+ // v2 packages are supposed to use package.json `exports` to enable
646
+ // self-imports, but not all build tools actually follow the spec. This
647
+ // is a workaround for badly behaved packagers.
648
+ //
649
+ // Known upstream bugs this works around:
650
+ // - https://github.com/vitejs/vite/issues/9731
651
+ if (pkg.packageJSON.exports) {
652
+ let found = (0, resolve_exports_1.exports)(pkg.packageJSON, request.specifier, {
653
+ browser: true,
654
+ conditions: ['default', 'imports'],
655
+ });
656
+ if (found === null || found === void 0 ? void 0 : found[0]) {
657
+ 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')));
658
+ }
659
+ }
660
+ }
612
661
  }
613
662
  return request;
614
663
  }
@@ -617,16 +666,17 @@ class Resolver {
617
666
  if (pkg.name.startsWith('@')) {
618
667
  levels.push('..');
619
668
  }
669
+ let originalFromFile = request.fromFile;
620
670
  let newRequest = request.rehome((0, path_1.resolve)(pkg.root, ...levels, 'moved-package-target.js'));
621
671
  if (newRequest === request) {
622
672
  return request;
623
673
  }
624
- return newRequest.withMeta({
625
- resolvedWithinPackage: pkg.root,
626
- });
674
+ // setting meta because if this fails, we want the fallback to pick up back
675
+ // in the original requesting package.
676
+ return newRequest.withMeta({ originalFromFile });
627
677
  }
628
678
  preHandleExternal(request) {
629
- if (request.isVirtual) {
679
+ if (isTerminal(request)) {
630
680
  return request;
631
681
  }
632
682
  let { specifier, fromFile } = request;
@@ -659,7 +709,15 @@ class Resolver {
659
709
  // engine
660
710
  let logicalLocation = this.reverseSearchAppTree(pkg, request.fromFile);
661
711
  if (logicalLocation) {
662
- return logTransition('beforeResolve: relative import in app-js', request, request.rehome((0, path_1.resolve)(logicalLocation.owningEngine.root, logicalLocation.inAppName)));
712
+ return logTransition('beforeResolve: relative import in app-js', request, request
713
+ .alias('./' + path_1.posix.join((0, path_1.dirname)(logicalLocation.inAppName), request.specifier))
714
+ // it's important that we're rehoming this to the root of the engine
715
+ // (which we know really exists), and not to a subdir like
716
+ // logicalLocation.inAppName (which might not physically exist),
717
+ // because some environments (including node's require.resolve) will
718
+ // refuse to do resolution from a notional path that doesn't
719
+ // physically exist.
720
+ .rehome((0, path_1.resolve)(logicalLocation.owningEngine.root, 'package.json')));
663
721
  }
664
722
  return request;
665
723
  }
@@ -674,11 +732,11 @@ class Resolver {
674
732
  if (shared_internals_1.emberVirtualPeerDeps.has(packageName) && !pkg.hasDependency(packageName)) {
675
733
  // addons (whether auto-upgraded or not) may use the app's
676
734
  // 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`);
735
+ let addon = this.locateActiveAddon(packageName);
736
+ if (!addon) {
737
+ throw new Error(`${pkg.name} is trying to import the emberVirtualPeerDep "${packageName}", but it seems to be missing`);
679
738
  }
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));
739
+ return logTransition(`emberVirtualPeerDeps`, request, request.rehome(addon.canResolveFromFile));
682
740
  }
683
741
  // if this file is part of an addon's app-js, it's really the logical
684
742
  // package to which it belongs (normally the app) that affects some policy
@@ -709,6 +767,22 @@ class Resolver {
709
767
  }
710
768
  return request;
711
769
  }
770
+ locateActiveAddon(packageName) {
771
+ if (packageName === this.options.modulePrefix) {
772
+ // the app itself is something that addon's can classically resolve if they know it's name.
773
+ return {
774
+ root: this.options.appRoot,
775
+ canResolveFromFile: (0, path_1.resolve)(this.packageCache.maybeMoved(this.packageCache.get(this.options.appRoot)).root, 'package.json'),
776
+ };
777
+ }
778
+ for (let engine of this.options.engines) {
779
+ for (let addon of engine.activeAddons) {
780
+ if (addon.name === packageName) {
781
+ return addon;
782
+ }
783
+ }
784
+ }
785
+ }
712
786
  external(label, request, specifier) {
713
787
  if (this.options.amdCompatibility === 'cjs') {
714
788
  let filename = (0, virtual_content_1.virtualExternalCJSModule)(specifier);
@@ -741,8 +815,11 @@ class Resolver {
741
815
  throw new Error(`Embroider's amdCompatibility option is disabled, but something tried to use it to access "${request.specifier}"`);
742
816
  }
743
817
  }
744
- fallbackResolve(request) {
818
+ async fallbackResolve(request) {
745
819
  var _a, _b, _c;
820
+ if (request.isVirtual) {
821
+ 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');
822
+ }
746
823
  if (request.specifier === '@embroider/macros') {
747
824
  // the macros package is always handled directly within babel (not
748
825
  // necessarily as a real resolvable package), so we should not mess with it.
@@ -750,8 +827,7 @@ class Resolver {
750
827
  // why we need to know about it.
751
828
  return logTransition('fallback early exit', request);
752
829
  }
753
- let { specifier, fromFile } = request;
754
- if (compatPattern.test(specifier)) {
830
+ if (compatPattern.test(request.specifier)) {
755
831
  // Some kinds of compat requests get rewritten into other things
756
832
  // deterministically. For example, "#embroider_compat/helpers/whatever"
757
833
  // means only "the-current-engine/helpers/whatever", and if that doesn't
@@ -767,39 +843,33 @@ class Resolver {
767
843
  // here.
768
844
  return request;
769
845
  }
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);
846
+ let pkg = this.packageCache.ownerOfFile(request.fromFile);
777
847
  if (!pkg) {
778
848
  return logTransition('no identifiable owningPackage', request);
779
849
  }
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()
850
+ // meta.originalFromFile gets set when we want to try to rehome a request
851
+ // but then come back to the original location here in the fallback when the
852
+ // rehomed request fails
784
853
  let movedPkg = this.packageCache.maybeMoved(pkg);
785
854
  if (movedPkg !== pkg) {
786
- if (!((_c = request.meta) === null || _c === void 0 ? void 0 : _c.wasMovedTo)) {
855
+ let originalFromFile = (_a = request.meta) === null || _a === void 0 ? void 0 : _a.originalFromFile;
856
+ if (typeof originalFromFile !== 'string') {
787
857
  throw new Error(`bug: embroider resolver's meta is not propagating`);
788
858
  }
789
- fromFile = request.meta.wasMovedTo;
859
+ request = request.rehome(originalFromFile);
790
860
  pkg = movedPkg;
791
861
  }
792
862
  if (!pkg.isV2Ember()) {
793
863
  return logTransition('fallbackResolve: not in an ember package', request);
794
864
  }
795
- let packageName = (0, shared_internals_1.packageName)(specifier);
865
+ let packageName = (0, shared_internals_1.packageName)(request.specifier);
796
866
  if (!packageName) {
797
867
  // this is a relative import
798
868
  let withinEngine = this.engineConfig(pkg.name);
799
869
  if (withinEngine) {
800
870
  // it's a relative import inside an engine (which also means app), which
801
871
  // 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)));
872
+ 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
873
  if (appJSMatch) {
804
874
  return logTransition('fallbackResolve: relative appJsMatch', request, appJSMatch);
805
875
  }
@@ -813,40 +883,49 @@ class Resolver {
813
883
  }
814
884
  }
815
885
  // 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);
886
+ if (pkg.meta['auto-upgraded']) {
887
+ let addon = this.locateActiveAddon(packageName);
888
+ if (addon) {
889
+ const rehomed = request.rehome(addon.canResolveFromFile);
890
+ if (rehomed !== request) {
891
+ return logTransition(`activeAddons`, request, rehomed);
892
+ }
820
893
  }
821
894
  }
822
- let logicalLocation = this.reverseSearchAppTree(pkg, fromFile);
895
+ let logicalLocation = this.reverseSearchAppTree(pkg, request.fromFile);
823
896
  if (logicalLocation) {
824
897
  // the requesting file is in an addon's appTree. We didn't succeed in
825
898
  // resolving this (non-relative) request from inside the actual addon, so
826
899
  // next try to resolve it from the corresponding logical location in the
827
900
  // 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)));
901
+ return logTransition('fallbackResolve: retry from logical home of app-js file', request,
902
+ // it might look more precise to rehome into logicalLocation.inAppName
903
+ // rather than package.json. But that logical location may not actually
904
+ // exist, and some systems (including node's require.resolve) will be
905
+ // mad about trying to resolve from notional paths that don't really
906
+ // exist.
907
+ request.rehome((0, path_1.resolve)(logicalLocation.owningEngine.root, 'package.json')));
829
908
  }
830
909
  let targetingEngine = this.engineConfig(packageName);
831
910
  if (targetingEngine) {
832
- let appJSMatch = this.searchAppTree(request, targetingEngine, specifier.replace(packageName, '.'));
911
+ let appJSMatch = await this.searchAppTree(request, targetingEngine, request.specifier.replace(packageName, '.'));
833
912
  if (appJSMatch) {
834
913
  return logTransition('fallbackResolve: non-relative appJsMatch', request, appJSMatch);
835
914
  }
836
915
  }
837
- if (pkg.meta['auto-upgraded']) {
916
+ if (pkg.meta['auto-upgraded'] && ((_c = (_b = request.meta) === null || _b === void 0 ? void 0 : _b.runtimeFallback) !== null && _c !== void 0 ? _c : true)) {
838
917
  // auto-upgraded packages can fall back to attempting to find dependencies at
839
918
  // runtime. Native v2 packages can only get this behavior in the
840
919
  // isExplicitlyExternal case above because they need to explicitly ask for
841
920
  // externals.
842
- return this.external('v1 catch-all fallback', request, specifier);
921
+ return this.external('v1 catch-all fallback', request, request.specifier);
843
922
  }
844
923
  else {
845
924
  // native v2 packages don't automatically externalize *everything* the way
846
925
  // auto-upgraded packages do, but they still externalize known and approved
847
926
  // ember virtual packages (like @ember/component)
848
927
  if (shared_internals_1.emberVirtualPackages.has(packageName)) {
849
- return this.external('emberVirtualPackages', request, specifier);
928
+ return this.external('emberVirtualPackages', request, request.specifier);
850
929
  }
851
930
  }
852
931
  // this is falling through with the original specifier which was
@@ -873,25 +952,23 @@ class Resolver {
873
952
  }
874
953
  }
875
954
  }
876
- searchAppTree(request, engine, inEngineSpecifier) {
955
+ async searchAppTree(request, engine, inEngineSpecifier) {
877
956
  let matched = this.getEntryFromMergeMap(inEngineSpecifier, engine.root);
878
957
  switch (matched === null || matched === void 0 ? void 0 : matched.entry.type) {
879
958
  case undefined:
880
959
  return undefined;
881
960
  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'));
961
+ return request.alias(matched.entry['app-js'].specifier).rehome(matched.entry['app-js'].fromFile);
885
962
  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'));
963
+ return request.alias(matched.entry['fastboot-js'].specifier).rehome(matched.entry['fastboot-js'].fromFile);
889
964
  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') {
965
+ let foundAppJS = await this.resolve(request.alias(matched.entry['app-js'].specifier).rehome(matched.entry['app-js'].fromFile).withMeta({
966
+ runtimeFallback: false,
967
+ }));
968
+ if (foundAppJS.type !== 'found') {
892
969
  throw new Error(`${matched.entry['app-js'].fromPackageName} declared ${inEngineSpecifier} in packageJSON.ember-addon.app-js, but that module does not exist`);
893
970
  }
894
- let { names } = (0, describe_exports_1.describeExports)((0, fs_1.readFileSync)(foundAppJS.filename, 'utf8'), {});
971
+ let { names } = (0, describe_exports_1.describeExports)((0, fs_1.readFileSync)(foundAppJS.filename, 'utf8'), { configFile: false });
895
972
  return request.virtualize((0, virtual_content_1.fastbootSwitch)(matched.matched, (0, path_1.resolve)(engine.root, 'package.json'), names));
896
973
  }
897
974
  }