Skip to content

Commit

Permalink
[wip] need to contain the weirdness of the app package
Browse files Browse the repository at this point in the history
  • Loading branch information
ef4 committed May 22, 2023
1 parent bff8ccb commit bc32c93
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 107 deletions.
130 changes: 105 additions & 25 deletions packages/compat/src/compat-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ function setup(legacyEmberAppInstance: object, options: Required<Options>) {

let instantiate = async (root: string, appSrcDir: string) => {
let packageCache = RewrittenPackageCache.shared('embroider', appSrcDir);
let appPackage = packageCache.get(appSrcDir);
let appPackage = AppPackage.create(packageCache.get(appSrcDir), oldPackage);
let adapter = new CompatAppAdapter(
root,
appPackage,
Expand Down Expand Up @@ -173,16 +173,13 @@ class CompatAppAdapter implements AppAdapter<TreeNames, CompatResolverOptions> {
}

developingAddons(): string[] {
if (this.oldPackage.owningAddon) {
return [this.oldPackage.owningAddon.root];
}
// TODO: dummy app puts addon under development
return [];
}

@Memoize()
activeAddonChildren(pkg: Package = this.appPackage): AddonPackage[] {
let deps = this.appSpecialDependencies(pkg);
let result = (deps.filter(this.isActiveAddon) as AddonPackage[]).filter(
let result = (pkg.dependencies.filter(this.isActiveAddon) as AddonPackage[]).filter(
// When looking for child addons, we want to ignore 'peerDependencies' of
// a given package, to align with how ember-cli resolves addons. So here
// we only include dependencies that definitely appear in one of the other
Expand All @@ -198,27 +195,9 @@ class CompatAppAdapter implements AppAdapter<TreeNames, CompatResolverOptions> {
return result.sort(this.orderAddons);
}

private appSpecialDependencies(pkg: Package): Package[] {
if (pkg !== this.appPackage) {
return pkg.dependencies;
}
// the app package is special because at this stage we're still looking at
// the original app package, but its deps have been rewritten.
return pkg.dependencies.map(dep => RewrittenPackageCache.shared('embroider', this.appPackage.root).maybeMoved(dep));
}

private appSpecialDescendants(pkg: Package, filter?: (p: Package) => boolean) {
if (pkg !== this.appPackage) {
return pkg.findDescendants(filter);
}
// the app package is special because at this stage we're still looking at
// the original app package, but its deps have been rewritten.
return Package.prototype.findDescendants.call({ dependencies: this.appSpecialDependencies(pkg) }, filter);
}

@Memoize()
get allActiveAddons(): AddonPackage[] {
let result = this.appSpecialDescendants(this.appPackage, this.isActiveAddon) as AddonPackage[];
let result = this.appPackage.findDescendants(this.isActiveAddon) as AddonPackage[];
let extras = [this.synthVendor, this.synthStyles].filter(this.isActiveAddon) as AddonPackage[];
let extraDescendants = flatMap(extras, dep => dep.findDescendants(this.isActiveAddon)) as AddonPackage[];
result = [...result, ...extras, ...extraDescendants];
Expand Down Expand Up @@ -456,3 +435,104 @@ function defaultAddonPackageRules(): PackageRules[] {
.filter(Boolean)
.reduce((a, b) => a.concat(b), []);
}

// without this, using a class as an interface forces you to have the same
// private and protected methods too (since people trying to extend from you
// could see all of those)
type PublicAPI<T> = { [K in keyof T]: T[K] };

// The app package is special and weird for two main reasons:
//
// 1. At the point where we're interrogating it, the addons have been rewritten
// to v2 but the app has not. So the app package's dependencies are no longer
// correct.
// 2. Dummy apps are weird need special rules.
//
class AppPackage implements PublicAPI<Package> {
static create(realPkg: Package, instance: V1App) {
// cast is because we only implement the public API of Package, not the full
// protected API.
return new AppPackage(realPkg, instance) as unknown as Package;
}

constructor(private realPkg: Package, private instance: V1App) {}

get dependencies(): Package[] {
// the app package is special because at this stage we're still looking at
// the original app package, but its deps have been rewritten.
return this.realPkg.dependencies.map(dep => RewrittenPackageCache.shared('embroider', this.root).maybeMoved(dep));
}

findDescendants(filter?: (p: Package) => boolean) {
// the app package is special because at this stage we're still looking at
// the original app package, but its deps have been rewritten.
return Package.prototype.findDescendants.call({ dependencies: this.dependencies }, filter);
}

get name(): string {
if (this.instance.isDummyApp) {
// here we accept the ember-cli behavior
return this.instance.name;
} else {
// always the name from package.json. Not the one that apps may have weirdly
// customized.
return this.realPkg.name;
}
}

get root(): string {
return this.instance.root;
}

get version() {
return this.realPkg.version;
}

get packageJSON() {
return this.realPkg.packageJSON;
}

get meta() {
return this.realPkg.meta;
}

get isEmberPackage() {
return this.realPkg.isEmberPackage;
}

isEngine() {
return this.realPkg.isEngine();
}

isLazyEngine() {
return this.realPkg.isLazyEngine();
}

isV2Ember() {
return this.realPkg.isV2Ember;
}

isV2App() {
return this.realPkg.isV2App;
}

isV2Addon() {
return this.realPkg.isV2Addon;
}

get mayRebuild() {
return this.realPkg.mayRebuild;
}

get nonResolvableDeps() {
return this.realPkg.nonResolvableDeps;
}

get dependencyNames() {
return this.realPkg.dependencyNames;
}

hasDependency(name: string): boolean {
return this.realPkg.hasDependency(name);
}
}
40 changes: 0 additions & 40 deletions packages/compat/src/dummy-package.ts

This file was deleted.

61 changes: 20 additions & 41 deletions packages/compat/src/v1-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,9 @@ import resolve from 'resolve';
import { Node } from 'broccoli-node-api';
import { V1Config, WriteV1Config } from './v1-config';
import { WriteV1AppBoot, ReadV1AppBoot } from './v1-appboot';
import {
AddonMeta,
Package,
EmberAppInstance,
OutputFileToInputFileMap,
PackageInfo,
AddonInstance,
} from '@embroider/core';
import { AddonMeta, EmberAppInstance, OutputFileToInputFileMap, PackageInfo, AddonInstance } from '@embroider/core';
import { writeJSONSync, ensureDirSync, copySync, readdirSync, pathExistsSync, existsSync } from 'fs-extra';
import AddToTree from './add-to-tree';
import DummyPackage, { OwningAddon } from './dummy-package';
import { TransformOptions } from '@babel/core';
import { isEmbroiderMacrosPlugin, MacrosConfig } from '@embroider/macros/src/node';
import resolvePackagePath from 'resolve-package-path';
Expand Down Expand Up @@ -48,16 +40,8 @@ interface Group {
}

export default class V1App {
// used to signal that this is a dummy app owned by a particular addon
owningAddon: Package | undefined;

static create(app: EmberAppInstance): V1App {
if (app.project.pkg.keywords?.includes('ember-addon')) {
// we are a dummy app, which is unfortunately weird and special
return new V1DummyApp(app);
} else {
return new V1App(app);
}
return new V1App(app);
}

private _publicAssets: { [filePath: string]: string } = Object.create(null);
Expand All @@ -70,19 +54,33 @@ export default class V1App {
this.packageCache = new MovablePackageCache(MacrosConfig.for(app, this.root), this.root);
}

// always the name from package.json. Not the one that apps may have weirdly
// customized.
get name(): string {
return this.app.project.pkg.name;
if (this.isDummyApp) {
// here we accept the ember-cli behavior
return this.app.name;
} else {
// always the name from package.json. Not the one that apps may have weirdly
// customized.
return this.app.project.pkg.name;
}
}

get env(): string {
return this.app.env;
}

get isDummyApp(): boolean {
return Boolean(this.app.project.pkg.keywords?.includes('ember-addon'));
}

@Memoize()
get root(): string {
return dirname(pkgUpSync({ cwd: this.app.project.root })!);
if (this.isDummyApp) {
// this is the Known Hack for finding the true root of the dummy app.
return join(this.app.project.configPath(), '..', '..');
} else {
return dirname(pkgUpSync({ cwd: this.app.project.root })!);
}
}

@Memoize()
Expand Down Expand Up @@ -774,25 +772,6 @@ function throwIfMissing<T>(
return asset;
}

class V1DummyApp extends V1App {
constructor(app: EmberAppInstance) {
super(app);
this.owningAddon = new OwningAddon(this.app.project.root, this.packageCache);
this.packageCache.seed(this.owningAddon);
this.packageCache.seed(new DummyPackage(this.root, this.owningAddon, this.packageCache));
}

get name(): string {
// here we accept the ember-cli behavior
return this.app.name;
}

get root(): string {
// this is the Known Hack for finding the true root of the dummy app.
return join(this.app.project.configPath(), '..', '..');
}
}

interface Preprocessors {
preprocessJs(tree: Node, a: string, b: string, options: object): Node;
preprocessCss(tree: Node, a: string, b: string, options: object): Node;
Expand Down
3 changes: 3 additions & 0 deletions packages/shared-internals/src/package-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export default class PackageCache {
}

get(packageRoot: string) {
if (/dummy/.test(packageRoot)) {
debugger;
}
let root = realpathSync(packageRoot);
let p = getOrCreate(this.rootCache, root, () => {
return new Package(root, this, root === this.appRoot);
Expand Down
7 changes: 6 additions & 1 deletion packages/shared-internals/src/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ export default class Package {

@Memoize()
protected get internalPackageJSON() {
return JSON.parse(readFileSync(join(this.root, 'package.json'), 'utf8'));
try {
return JSON.parse(readFileSync(join(this.root, 'package.json'), 'utf8'));
} catch (err) {
debugger;
throw err;
}
}

@Memoize()
Expand Down

0 comments on commit bc32c93

Please sign in to comment.