@embroider/core 2.1.1-unstable.73213f2a → 2.1.1-unstable.936fd63

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.
@@ -1,4 +1,10 @@
1
1
  "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
2
8
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
9
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
10
  };
@@ -11,6 +17,9 @@ const debug_1 = __importDefault(require("debug"));
11
17
  const assert_never_1 = __importDefault(require("assert-never"));
12
18
  const resolve_1 = __importDefault(require("resolve"));
13
19
  const virtual_content_1 = require("./virtual-content");
20
+ const typescript_memoize_1 = require("typescript-memoize");
21
+ const describe_exports_1 = require("./describe-exports");
22
+ const fs_1 = require("fs");
14
23
  const debug = (0, debug_1.default)('embroider:resolver');
15
24
  function logTransition(reason, before, after = before) {
16
25
  if (after.isVirtual) {
@@ -61,6 +70,7 @@ class Resolver {
61
70
  // why we need to know about it.
62
71
  return logTransition('early exit', request);
63
72
  }
73
+ request = this.handleFastbootCompat(request);
64
74
  request = this.handleGlobalsCompat(request);
65
75
  request = this.handleRenaming(request);
66
76
  return this.preHandleExternal(request);
@@ -161,15 +171,42 @@ class Resolver {
161
171
  owningPackage(fromFile) {
162
172
  return shared_internals_2.PackageCache.shared('embroider-stage3', this.options.appRoot).ownerOfFile(fromFile);
163
173
  }
164
- originalPackage(fromFile) {
165
- let originalFile = this.options.relocatedFiles[fromFile];
166
- if (originalFile) {
167
- let owning = shared_internals_2.PackageCache.shared('embroider-stage3', this.options.appRoot).ownerOfFile(originalFile);
168
- if (owning && !owning.isV2Ember()) {
169
- throw new Error(`bug: it should only be possible for a v2 ember package to own relocated files`);
174
+ logicalPackage(owningPackage, file) {
175
+ let logicalLocation = this.reverseSearchAppTree(owningPackage, file);
176
+ if (logicalLocation) {
177
+ let pkg = shared_internals_2.PackageCache.shared('embroider-stage3', this.options.appRoot).get(logicalLocation.owningEngine.root);
178
+ if (!pkg.isV2Ember()) {
179
+ throw new Error(`bug: all engines should be v2 addons by the time we see them here`);
180
+ }
181
+ return pkg;
182
+ }
183
+ return owningPackage;
184
+ }
185
+ handleFastbootCompat(request) {
186
+ var _a;
187
+ let match = (0, virtual_content_1.decodeFastbootSwitch)(request.fromFile);
188
+ if (!match) {
189
+ return request;
190
+ }
191
+ let section;
192
+ if (request.specifier === './browser') {
193
+ section = 'app-js';
194
+ }
195
+ else if (request.specifier === './fastboot') {
196
+ section = 'fastboot-js';
197
+ }
198
+ if (!section) {
199
+ return request;
200
+ }
201
+ let pkg = this.owningPackage(match.filename);
202
+ if (pkg) {
203
+ let rel = withoutJSExt((0, shared_internals_2.explicitRelative)(pkg.root, match.filename));
204
+ let entry = (_a = this.mergeMap.get(pkg.root)) === null || _a === void 0 ? void 0 : _a.get(rel);
205
+ if ((entry === null || entry === void 0 ? void 0 : entry.type) === 'both') {
206
+ return request.alias(entry[section].localPath).rehome((0, path_1.resolve)(entry[section].packageRoot, 'package.json'));
170
207
  }
171
- return owning;
172
208
  }
209
+ return request;
173
210
  }
174
211
  handleGlobalsCompat(request) {
175
212
  let match = compatPattern.exec(request.specifier);
@@ -197,9 +234,7 @@ class Resolver {
197
234
  }
198
235
  resolveHelper(path, inEngine, request) {
199
236
  let target = this.parseGlobalPath(path, inEngine);
200
- return request
201
- .alias(`${target.packageName}/helpers/${target.memberName}`)
202
- .rehome((0, path_1.resolve)(inEngine.root, 'package.json'));
237
+ return logTransition('resolveHelper', request, request.alias(`${target.packageName}/helpers/${target.memberName}`).rehome((0, path_1.resolve)(inEngine.root, 'package.json')));
203
238
  }
204
239
  resolveComponent(path, inEngine, request) {
205
240
  let target = this.parseGlobalPath(path, inEngine);
@@ -241,25 +276,25 @@ class Resolver {
241
276
  let helperCandidate = this.resolveHelper(path, inEngine, request);
242
277
  let helperMatch = this.nodeResolve(helperCandidate.specifier, helperCandidate.fromFile);
243
278
  if (helperMatch.type === 'real') {
244
- return helperCandidate;
279
+ return logTransition('ambiguous case matched a helper', request, helperCandidate);
245
280
  }
246
281
  // unlike resolveHelper, resolveComponent already does pre-resolution in
247
282
  // order to deal with its own internal ambiguity around JS vs HBS vs
248
283
  // colocation.≥
249
284
  let componentMatch = this.resolveComponent(path, inEngine, request);
250
285
  if (componentMatch !== request) {
251
- return componentMatch;
286
+ return logTransition('ambiguous case matched a cmoponent', request, componentMatch);
252
287
  }
253
288
  // this is the hard failure case -- we were supposed to find something and
254
289
  // didn't. Let the normal resolution process progress so the user gets a
255
290
  // normal build error.
256
- return request;
291
+ return logTransition('ambiguous case failing', request);
257
292
  }
258
293
  resolveModifier(path, inEngine, request) {
259
294
  let target = this.parseGlobalPath(path, inEngine);
260
- return request
295
+ return logTransition('resolveModifier', request, request
261
296
  .alias(`${target.packageName}/modifiers/${target.memberName}`)
262
- .rehome((0, path_1.resolve)(inEngine.root, 'package.json'));
297
+ .rehome((0, path_1.resolve)(inEngine.root, 'package.json')));
263
298
  }
264
299
  *componentTemplateCandidates(inPackageName) {
265
300
  yield { prefix: '/templates/components/', suffix: '' };
@@ -295,6 +330,106 @@ class Resolver {
295
330
  return { packageName: inEngine.packageName, memberName: path, from: (0, path_1.resolve)(inEngine.root, 'pacakge.json') };
296
331
  }
297
332
  }
333
+ engineConfig(packageName) {
334
+ return this.options.engines.find(e => e.packageName === packageName);
335
+ }
336
+ // This is where we figure out how all the classic treeForApp merging bottoms
337
+ // out.
338
+ get mergeMap() {
339
+ let packageCache = shared_internals_2.PackageCache.shared('embroider-stage3', this.options.appRoot);
340
+ let result = new Map();
341
+ for (let engine of this.options.engines) {
342
+ let engineModules = new Map();
343
+ for (let addonConfig of engine.activeAddons) {
344
+ let addon = packageCache.get(addonConfig.root);
345
+ if (!addon.isV2Addon()) {
346
+ continue;
347
+ }
348
+ let appJS = addon.meta['app-js'];
349
+ if (appJS) {
350
+ for (let [inEngineName, inAddonName] of Object.entries(appJS)) {
351
+ if (!inEngineName.startsWith('./')) {
352
+ throw new Error(`addon ${addon.name} declares app-js in its package.json with the illegal name "${inEngineName}". It must start with "./" to make it clear that it's relative to the app`);
353
+ }
354
+ if (!inAddonName.startsWith('./')) {
355
+ throw new Error(`addon ${addon.name} declares app-js in its package.json with the illegal name "${inAddonName}". It must start with "./" to make it clear that it's relative to the addon`);
356
+ }
357
+ inEngineName = withoutJSExt(inEngineName);
358
+ let prevEntry = engineModules.get(inEngineName);
359
+ switch (prevEntry === null || prevEntry === void 0 ? void 0 : prevEntry.type) {
360
+ case undefined:
361
+ engineModules.set(inEngineName, {
362
+ type: 'app-only',
363
+ 'app-js': {
364
+ localPath: inAddonName,
365
+ packageRoot: addon.root,
366
+ fromPackageName: addon.name,
367
+ },
368
+ });
369
+ break;
370
+ case 'app-only':
371
+ case 'both':
372
+ // first match wins, so this one is shadowed
373
+ break;
374
+ case 'fastboot-only':
375
+ engineModules.set(inEngineName, {
376
+ type: 'both',
377
+ 'app-js': {
378
+ localPath: inAddonName,
379
+ packageRoot: addon.root,
380
+ fromPackageName: addon.name,
381
+ },
382
+ 'fastboot-js': prevEntry['fastboot-js'],
383
+ });
384
+ break;
385
+ }
386
+ }
387
+ }
388
+ let fastbootJS = addon.meta['fastboot-js'];
389
+ if (fastbootJS) {
390
+ for (let [inEngineName, inAddonName] of Object.entries(fastbootJS)) {
391
+ if (!inEngineName.startsWith('./')) {
392
+ throw new Error(`addon ${addon.name} declares fastboot-js in its package.json with the illegal name "${inEngineName}". It must start with "./" to make it clear that it's relative to the app`);
393
+ }
394
+ if (!inAddonName.startsWith('./')) {
395
+ throw new Error(`addon ${addon.name} declares fastboot-js in its package.json with the illegal name "${inAddonName}". It must start with "./" to make it clear that it's relative to the addon`);
396
+ }
397
+ inEngineName = withoutJSExt(inEngineName);
398
+ let prevEntry = engineModules.get(inEngineName);
399
+ switch (prevEntry === null || prevEntry === void 0 ? void 0 : prevEntry.type) {
400
+ case undefined:
401
+ engineModules.set(inEngineName, {
402
+ type: 'fastboot-only',
403
+ 'fastboot-js': {
404
+ localPath: inAddonName,
405
+ packageRoot: addon.root,
406
+ fromPackageName: addon.name,
407
+ },
408
+ });
409
+ break;
410
+ case 'fastboot-only':
411
+ case 'both':
412
+ // first match wins, so this one is shadowed
413
+ break;
414
+ case 'app-only':
415
+ engineModules.set(inEngineName, {
416
+ type: 'both',
417
+ 'fastboot-js': {
418
+ localPath: inAddonName,
419
+ packageRoot: addon.root,
420
+ fromPackageName: addon.name,
421
+ },
422
+ 'app-js': prevEntry['app-js'],
423
+ });
424
+ break;
425
+ }
426
+ }
427
+ }
428
+ }
429
+ result.set(engine.root, engineModules);
430
+ }
431
+ return result;
432
+ }
298
433
  owningEngine(pkg) {
299
434
  if (pkg.root === this.options.appRoot) {
300
435
  // the app is always the first engine
@@ -341,12 +476,6 @@ class Resolver {
341
476
  // correctly.
342
477
  return logTransition(`v1 self-import`, request, this.resolveWithinPackage(request, pkg));
343
478
  }
344
- let originalPkg = this.originalPackage(request.fromFile);
345
- if (originalPkg && pkg.meta['auto-upgraded'] && originalPkg.name === packageName) {
346
- // A file that was relocated out of a package is importing that package's
347
- // name, it should find its own original copy.
348
- return logTransition(`self-import in app-js`, request, this.resolveWithinPackage(request, originalPkg));
349
- }
350
479
  return request;
351
480
  }
352
481
  resolveWithinPackage(request, pkg) {
@@ -383,9 +512,14 @@ class Resolver {
383
512
  let publicSpecifier = absoluteSpecifier.replace(pkg.root, pkg.name);
384
513
  return external('beforeResolve', request, publicSpecifier);
385
514
  }
386
- else {
387
- return request;
515
+ // if the requesting file is in an addon's app-js, the relative request
516
+ // should really be understood as a request for a module in the containing
517
+ // engine
518
+ let logicalLocation = this.reverseSearchAppTree(pkg, request.fromFile);
519
+ if (logicalLocation) {
520
+ return logTransition('beforeResolve: relative import in app-js', request, request.rehome((0, path_1.resolve)(logicalLocation.owningEngine.root, logicalLocation.inAppName)));
388
521
  }
522
+ return request;
389
523
  }
390
524
  // absolute package imports can also be explicitly external based on their
391
525
  // full specifier name
@@ -411,9 +545,13 @@ class Resolver {
411
545
  let newHome = (0, path_1.resolve)(this.options.appRoot, 'package.json');
412
546
  return logTransition(`emberVirtualPeerDeps in v2 addon`, request, request.rehome(newHome));
413
547
  }
414
- if (pkg.meta['auto-upgraded'] && !pkg.hasDependency('ember-auto-import')) {
548
+ // if this file is part of an addon's app-js, it's really the logical
549
+ // package to which it belongs (normally the app) that affects some policy
550
+ // choices about what it can import
551
+ let logicalPackage = this.logicalPackage(pkg, fromFile);
552
+ if (logicalPackage.meta['auto-upgraded'] && !logicalPackage.hasDependency('ember-auto-import')) {
415
553
  try {
416
- let dep = shared_internals_2.PackageCache.shared('embroider-stage3', this.options.appRoot).resolve(packageName, pkg);
554
+ let dep = shared_internals_2.PackageCache.shared('embroider-stage3', this.options.appRoot).resolve(packageName, logicalPackage);
417
555
  if (!dep.isEmberPackage()) {
418
556
  // classic ember addons can only import non-ember dependencies if they
419
557
  // have ember-auto-import.
@@ -428,20 +566,10 @@ class Resolver {
428
566
  }
429
567
  // assertions on what native v2 addons can import
430
568
  if (!pkg.meta['auto-upgraded']) {
431
- let originalPkg = this.originalPackage(fromFile);
432
- if (originalPkg) {
433
- // this file has been moved into another package (presumably the app).
434
- if (packageName !== pkg.name) {
435
- // the only thing that native v2 addons are allowed to import from
436
- // within the app tree is their own name.
437
- throw new Error(`${pkg.name} is trying to import ${packageName} from within its app tree. This is unsafe, because ${pkg.name} can't control which dependencies are resolvable from the app`);
438
- }
439
- }
440
- else {
441
- // this file has not been moved. The normal case.
442
- if (!pkg.meta['auto-upgraded'] && !reliablyResolvable(pkg, packageName)) {
443
- throw new Error(`${pkg.name} is trying to import from ${packageName} but that is not one of its explicit dependencies`);
444
- }
569
+ if (!pkg.meta['auto-upgraded'] &&
570
+ !appImportInAppTree(pkg, logicalPackage, packageName) &&
571
+ !reliablyResolvable(pkg, packageName)) {
572
+ throw new Error(`${pkg.name} is trying to import from ${packageName} but that is not one of its explicit dependencies`);
445
573
  }
446
574
  }
447
575
  return request;
@@ -466,18 +594,27 @@ class Resolver {
466
594
  }
467
595
  let pkg = this.owningPackage(fromFile);
468
596
  if (!pkg || !pkg.isV2Ember()) {
469
- return request;
597
+ return logTransition('fallbackResolve: not in an ember package', request);
470
598
  }
471
599
  let packageName = (0, shared_internals_1.packageName)(specifier);
472
600
  if (!packageName) {
473
- // this is a relative import, we have nothing more to for it.
474
- return request;
475
- }
476
- let originalPkg = this.originalPackage(fromFile);
477
- if (originalPkg) {
478
- // we didn't find it from the original package, so try from the relocated
479
- // package
480
- return logTransition(`relocation fallback`, request, request.rehome((0, path_1.resolve)(originalPkg.root, 'package.json')));
601
+ // this is a relative import
602
+ let withinEngine = this.engineConfig(pkg.name);
603
+ if (withinEngine) {
604
+ // it's a relative import inside an engine (which also means app), which
605
+ // means we may need to satisfy the request via app tree merging.
606
+ let appJSMatch = this.searchAppTree(request, withinEngine, (0, shared_internals_2.explicitRelative)(pkg.root, (0, path_1.resolve)((0, path_1.dirname)(fromFile), specifier)));
607
+ if (appJSMatch) {
608
+ return logTransition('fallbackResolve: relative appJsMatch', request, appJSMatch);
609
+ }
610
+ else {
611
+ return logTransition('fallbackResolve: relative appJs search failure', request);
612
+ }
613
+ }
614
+ else {
615
+ // nothing else to do for relative imports
616
+ return logTransition('fallbackResolve: relative failure', request);
617
+ }
481
618
  }
482
619
  // auto-upgraded packages can fall back to the set of known active addons
483
620
  //
@@ -486,6 +623,21 @@ class Resolver {
486
623
  if ((pkg.meta['auto-upgraded'] || packageName === pkg.name) && this.options.activeAddons[packageName]) {
487
624
  return logTransition(`activeAddons`, request, this.resolveWithinPackage(request, shared_internals_2.PackageCache.shared('embroider-stage3', this.options.appRoot).get(this.options.activeAddons[packageName])));
488
625
  }
626
+ let targetingEngine = this.engineConfig(packageName);
627
+ if (targetingEngine) {
628
+ let appJSMatch = this.searchAppTree(request, targetingEngine, specifier.replace(packageName, '.'));
629
+ if (appJSMatch) {
630
+ return logTransition('fallbackResolve: non-relative appJsMatch', request, appJSMatch);
631
+ }
632
+ }
633
+ let logicalLocation = this.reverseSearchAppTree(pkg, request.fromFile);
634
+ if (logicalLocation) {
635
+ // the requesting file is in an addon's appTree. We didn't succeed in
636
+ // resolving this (non-relative) request from inside the actual addon, so
637
+ // next try to resolve it from the corresponding logical location in the
638
+ // app.
639
+ return logTransition('fallbackResolve: retry from logical home of app-js file', request, request.rehome((0, path_1.resolve)(logicalLocation.owningEngine.root, logicalLocation.inAppName)));
640
+ }
489
641
  if (pkg.meta['auto-upgraded']) {
490
642
  // auto-upgraded packages can fall back to attempting to find dependencies at
491
643
  // runtime. Native v2 packages can only get this behavior in the
@@ -503,7 +655,29 @@ class Resolver {
503
655
  }
504
656
  // this is falling through with the original specifier which was
505
657
  // non-resolvable, which will presumably cause a static build error in stage3.
506
- return request;
658
+ return logTransition('fallbackResolve final exit', request);
659
+ }
660
+ searchAppTree(request, engine, inEngineSpecifier) {
661
+ var _a;
662
+ inEngineSpecifier = withoutJSExt(inEngineSpecifier);
663
+ let entry = (_a = this.mergeMap.get(engine.root)) === null || _a === void 0 ? void 0 : _a.get(inEngineSpecifier);
664
+ switch (entry === null || entry === void 0 ? void 0 : entry.type) {
665
+ case undefined:
666
+ return undefined;
667
+ case 'app-only':
668
+ return request.alias(entry['app-js'].localPath).rehome((0, path_1.resolve)(entry['app-js'].packageRoot, 'package.json'));
669
+ case 'fastboot-only':
670
+ return request
671
+ .alias(entry['fastboot-js'].localPath)
672
+ .rehome((0, path_1.resolve)(entry['fastboot-js'].packageRoot, 'package.json'));
673
+ case 'both':
674
+ let foundAppJS = this.nodeResolve(entry['app-js'].localPath, (0, path_1.resolve)(entry['app-js'].packageRoot, 'package.json'));
675
+ if (foundAppJS.type !== 'real') {
676
+ throw new Error(`${entry['app-js'].fromPackageName} declared ${inEngineSpecifier} in packageJSON.ember-addon.app-js, but that module does not exist`);
677
+ }
678
+ let { names } = (0, describe_exports_1.describeExports)((0, fs_1.readFileSync)(foundAppJS.filename, 'utf8'), {});
679
+ return request.virtualize((0, virtual_content_1.fastbootSwitch)(request.specifier, request.fromFile, names));
680
+ }
507
681
  }
508
682
  // check whether the given file with the given owningPackage is an addon's
509
683
  // appTree, and if so return the notional location within the app (or owning
@@ -512,12 +686,14 @@ class Resolver {
512
686
  // if the requesting file is in an addon's app-js, the request should
513
687
  // really be understood as a request for a module in the containing engine
514
688
  if (owningPackage.isV2Addon()) {
515
- let appJS = owningPackage.meta['app-js'];
516
- if (appJS) {
517
- let fromPackageRelativePath = (0, shared_internals_2.explicitRelative)(owningPackage.root, fromFile);
518
- for (let [inAppName, inAddonName] of Object.entries(appJS)) {
519
- if (inAddonName === fromPackageRelativePath) {
520
- return { owningEngine: this.owningEngine(owningPackage), inAppName };
689
+ let sections = [owningPackage.meta['app-js'], owningPackage.meta['fastboot-js']];
690
+ for (let section of sections) {
691
+ if (section) {
692
+ let fromPackageRelativePath = (0, shared_internals_2.explicitRelative)(owningPackage.root, fromFile);
693
+ for (let [inAppName, inAddonName] of Object.entries(section)) {
694
+ if (inAddonName === fromPackageRelativePath) {
695
+ return { owningEngine: this.owningEngine(owningPackage), inAppName };
696
+ }
521
697
  }
522
698
  }
523
699
  }
@@ -561,6 +737,9 @@ class Resolver {
561
737
  return undefined;
562
738
  }
563
739
  }
740
+ __decorate([
741
+ (0, typescript_memoize_1.Memoize)()
742
+ ], Resolver.prototype, "mergeMap", null);
564
743
  exports.Resolver = Resolver;
565
744
  function isExplicitlyExternal(specifier, fromPkg) {
566
745
  return Boolean(fromPkg.isV2Addon() && fromPkg.meta['externals'] && fromPkg.meta['externals'].includes(specifier));
@@ -582,8 +761,19 @@ function reliablyResolvable(pkg, packageName) {
582
761
  }
583
762
  return false;
584
763
  }
764
+ //
765
+ function appImportInAppTree(inPackage, inLogicalPackage, importedPackageName) {
766
+ return inPackage !== inLogicalPackage && importedPackageName === inLogicalPackage.name;
767
+ }
585
768
  function external(label, request, specifier) {
586
769
  let filename = (0, virtual_content_1.virtualExternalModule)(specifier);
587
770
  return logTransition(label, request, request.virtualize(filename));
588
771
  }
772
+ // this is specifically for app-js handling, where only .js and .hbs are legal
773
+ // extensiosn, and only .js is allowed to be an *implied* extension (.hbs must
774
+ // be explicit). So when normalizing such paths, it's only a .js suffix that we
775
+ // must remove.
776
+ function withoutJSExt(filename) {
777
+ return filename.replace(/\.js$/, '');
778
+ }
589
779
  //# sourceMappingURL=module-resolver.js.map