Skip to content

Commit

Permalink
chore: improve package json typings (#955)
Browse files Browse the repository at this point in the history
also fixed few error, finding by type-checking

improve addonInstance typings

fix more typing errors

fix more typings

suspend overload error here
  • Loading branch information
lifeart committed Sep 1, 2021
1 parent 9447c60 commit 25a883a
Show file tree
Hide file tree
Showing 12 changed files with 192 additions and 80 deletions.
7 changes: 4 additions & 3 deletions packages/addon-shim/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
AddonMeta,
AddonInstance,
isDeepAddonInstance,
PackageInfo,
} from '@embroider/shared-internals';
import buildFunnel from 'broccoli-funnel';
import type { Node } from 'broccoli-node-api';
Expand All @@ -13,7 +14,7 @@ export interface ShimOptions {
disabled?: (options: any) => boolean;
}

function addonMeta(pkgJSON: any): AddonMeta {
function addonMeta(pkgJSON: PackageInfo): AddonMeta {
let meta = pkgJSON['ember-addon'];
if (meta?.version !== 2 || meta?.type !== 'addon') {
throw new Error(`did not find valid v2 addon metadata in ${pkgJSON.name}`);
Expand All @@ -22,7 +23,7 @@ function addonMeta(pkgJSON: any): AddonMeta {
}

export function addonV1Shim(directory: string, options: ShimOptions = {}) {
let pkg = JSON.parse(
let pkg: PackageInfo = JSON.parse(
readFileSync(resolve(directory, './package.json'), 'utf8')
);

Expand All @@ -42,7 +43,7 @@ export function addonV1Shim(directory: string, options: ShimOptions = {}) {
return {
name: pkg.name,
included(this: AddonInstance, ...args: unknown[]) {
if (((this.parent.pkg as any)['ember-addon']?.version ?? 1) < 2) {
if ((this.parent.pkg['ember-addon']?.version ?? 1) < 2) {
let autoImportVersion = this.parent.addons.find(
(a) => a.name === 'ember-auto-import'
)?.pkg.version;
Expand Down
4 changes: 2 additions & 2 deletions packages/compat/src/compat-utils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import cloneDeep from 'lodash/cloneDeep';
import { AddonMeta } from '@embroider/core';
import { AddonMeta, PackageInfo } from '@embroider/core';
import resolve from 'resolve';
import { resolve as pathResolve } from 'path';
import { PluginItem } from '@babel/core';

export function addPeerDependency(packageJSON: any, packageName: string, version = '*') {
export function addPeerDependency(packageJSON: PackageInfo, packageName: string, version = '*') {
let pkg = cloneDeep(packageJSON);
if (!pkg.peerDependencies) {
pkg.peerDependencies = {};
Expand Down
10 changes: 5 additions & 5 deletions packages/compat/src/default-pipeline.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { App, Addons as CompatAddons, Options, PrebuiltAddons } from '.';
import { toBroccoliPlugin, PackagerConstructor, Variant } from '@embroider/core';
import { toBroccoliPlugin, PackagerConstructor, Variant, EmberAppInstance } from '@embroider/core';
import { Node } from 'broccoli-node-api';
import writeFile from 'broccoli-file-creator';
import mergeTrees from 'broccoli-merge-trees';
Expand All @@ -11,7 +11,7 @@ export interface PipelineOptions<PackagerOptions> extends Options {
}

export default function defaultPipeline<PackagerOptions>(
emberApp: object,
emberApp: EmberAppInstance,
packager?: PackagerConstructor<PackagerOptions>,
options?: PipelineOptions<PackagerOptions>
): Node {
Expand Down Expand Up @@ -52,11 +52,11 @@ export default function defaultPipeline<PackagerOptions>(
return new BroccoliPackager(embroiderApp, variants, options && options.packagerOptions);
}

function hasFastboot(emberApp: any) {
return emberApp.project.addons.find((a: any) => a.name === 'ember-cli-fastboot');
function hasFastboot(emberApp: EmberAppInstance | EmberAppInstance) {
return emberApp.project.addons.find(a => a.name === 'ember-cli-fastboot');
}

function defaultVariants(emberApp: any): Variant[] {
function defaultVariants(emberApp: EmberAppInstance): Variant[] {
let variants: Variant[] = [];
if (emberApp.env === 'production') {
variants.push({
Expand Down
40 changes: 25 additions & 15 deletions packages/compat/src/v1-addon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ import mergeTrees from 'broccoli-merge-trees';
import semver from 'semver';
import rewriteAddonTree from './rewrite-addon-tree';
import { mergeWithAppend } from './merges';
import { AddonMeta, NodeTemplateCompiler, debug, PackageCache, Resolver, extensionsPattern } from '@embroider/core';
import {
AddonMeta,
NodeTemplateCompiler,
debug,
PackageCache,
Resolver,
extensionsPattern,
AddonInstance,
AddonTreePath,
} from '@embroider/core';
import Options from './options';
import walkSync from 'walk-sync';
import ObserveTree from './observe-tree';
Expand All @@ -30,7 +39,7 @@ import { getEmberExports } from '@embroider/core/src/load-ember-template-compile
import prepHtmlbarsAstPluginsForUnwrap from './prepare-htmlbars-ast-plugins';
import getRealAddon from './get-real-addon';

const stockTreeNames = Object.freeze([
const stockTreeNames: AddonTreePath[] = Object.freeze([
'addon',
'addon-styles',
'styles',
Expand All @@ -41,7 +50,7 @@ const stockTreeNames = Object.freeze([
'vendor',
// 'addon-templates' and 'templates are trees too, but they live inside
// 'addon' and 'app' and we handle them there.
]);
]) as AddonTreePath[];

const dynamicTreeHooks = Object.freeze([
'treeFor',
Expand Down Expand Up @@ -114,7 +123,7 @@ class V1AddonCompatResolver implements Resolver {
// v1 addon instance.
export default class V1Addon {
constructor(
protected addonInstance: any,
protected addonInstance: AddonInstance,
protected addonOptions: Required<Options>,
protected app: V1App,
private packageCache: PackageCache,
Expand All @@ -128,10 +137,10 @@ export default class V1Addon {
// this is only defined when there are custom AST transforms that need it
@Memoize()
private get templateCompiler(): NodeTemplateCompiler | undefined {
let htmlbars = this.addonInstance.addons.find((a: any) => a.name === 'ember-cli-htmlbars');
let htmlbars = this.addonInstance.addons.find(a => a.name === 'ember-cli-htmlbars');
if (htmlbars) {
let options = htmlbars.htmlbarsOptions() as HTMLBarsOptions;
if (options.plugins && options.plugins.ast) {
let options = (htmlbars as any).htmlbarsOptions() as HTMLBarsOptions;
if (options?.plugins?.ast) {
// our macros don't run here in stage1
options.plugins.ast = options.plugins.ast.filter((p: any) => !isEmbroiderMacrosPlugin(p));
prepHtmlbarsAstPluginsForUnwrap(this.addonInstance.registry);
Expand Down Expand Up @@ -288,7 +297,7 @@ export default class V1Addon {
// shallow copy only! This is OK as long as we're only changing top-level
// keys in this method
let pkg = Object.assign({}, this.packageJSON);
let meta: AddonMeta = Object.assign({}, pkg.meta, this.packageMeta);
let meta: AddonMeta = Object.assign({}, this.packageCache.get(this.root).meta, this.packageMeta);
pkg['ember-addon'] = meta;

// classic addons don't get to customize their entrypoints like this. We
Expand All @@ -311,7 +320,7 @@ export default class V1Addon {
@Memoize()
private get mainModule() {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const mod = require(this.addonInstance.constructor._meta_.modulePath);
const mod = require((this.addonInstance as unknown as any).constructor._meta_.modulePath);

if (typeof mod === 'function') {
return mod.prototype;
Expand Down Expand Up @@ -373,7 +382,7 @@ export default class V1Addon {
}

@Memoize()
private hasStockTree(treeName: string): boolean {
private hasStockTree(treeName: AddonTreePath): boolean {
if (this.suppressesTree(treeName)) {
return false;
}
Expand Down Expand Up @@ -424,7 +433,7 @@ export default class V1Addon {
}
}

protected stockTree(treeName: string): Node {
protected stockTree(treeName: AddonTreePath): Node {
return this.throughTreeCache(treeName, 'stock', () => {
// adjust from the legacy "root" to our real root, because our rootTree
// uses our real root but the stock trees are defined in terms of the
Expand Down Expand Up @@ -457,7 +466,7 @@ export default class V1Addon {
tree = this.addonInstance.preprocessJs(tree, '/', this.moduleName, {
registry: this.addonInstance.registry,
});
if (this.addonInstance.shouldCompileTemplates() && this.addonInstance.registry.load('template').length > 0) {
if (this.addonInstance.shouldCompileTemplates() && this.addonInstance.registry.load('template')?.length > 0) {
tree = this.app.preprocessRegistry.preprocessTemplates(tree, {
registry: this.addonInstance.registry,
});
Expand Down Expand Up @@ -574,7 +583,7 @@ export default class V1Addon {
// a previous name was uncacheable, so we're entirely uncacheable
return undefined;
}
let key = this.addonInstance.cacheKeyForTree(name);
let key = this.addonInstance.cacheKeyForTree?.(name);
if (key) {
return accum + key;
} else {
Expand Down Expand Up @@ -638,6 +647,7 @@ export default class V1Addon {
name: string,
{ neuterPreprocessors } = { neuterPreprocessors: false }
): Node | undefined {
// @ts-expect-error have no idea why throughTreeCache overload is not working here..
return this.throughTreeCache(name, 'original', () => {
// get the real addon as we're going to patch and restore `preprocessJs`
const realAddon = getRealAddon(this.addonInstance);
Expand Down Expand Up @@ -977,15 +987,15 @@ export default class V1Addon {
// getEngineConfigContents is an arbitrary customizable module, so we can't
// easily rewrite it to live inside our conditional, so it's safer in a
// separate module.
built.trees.push(writeFile('config/_environment_browser_.js', this.addonInstance.getEngineConfigContents()));
built.trees.push(writeFile('config/_environment_browser_.js', this.addonInstance.getEngineConfigContents?.()));
built.trees.push(
writeFile(
'config/environment.js',
`
import { macroCondition, getGlobalConfig, importSync } from '@embroider/macros';
let config;
if (macroCondition(getGlobalConfig().fastboot?.isRunning)){
config = ${JSON.stringify(this.addonInstance.engineConfig(this.app.env, {}), null, 2)};
config = ${JSON.stringify(this.addonInstance.engineConfig?.(this.app.env, {}), null, 2)};
} else {
config = importSync('./_environment_browser_.js').default;
}
Expand Down
61 changes: 28 additions & 33 deletions packages/compat/src/v1-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@ import resolve from 'resolve';
import { Node } from 'broccoli-node-api';
import { V1Config, WriteV1Config } from './v1-config';
import { WriteV1AppBoot, ReadV1AppBoot } from './v1-appboot';
import { PackageCache, TemplateCompiler, TemplateCompilerPlugins, AddonMeta, Package } from '@embroider/core';
import {
PackageCache,
TemplateCompiler,
TemplateCompilerPlugins,
AddonMeta,
Package,
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';
Expand All @@ -21,32 +31,15 @@ import SynthesizeTemplateOnlyComponents from './synthesize-template-only-compone
import { isEmberAutoImportDynamic } from './detect-babel-plugins';
import prepHtmlbarsAstPluginsForUnwrap from './prepare-htmlbars-ast-plugins';
import { readFileSync } from 'fs';
import type { Options as HTMLBarsOptions } from 'ember-cli-htmlbars';
import semver from 'semver';

// This controls and types the interface between our new world and the classic
// v1 app instance.

type FilePath = string;
type OutputFileToInputFileMap = { [filePath: string]: FilePath[] };

interface EmberApp {
env: string;
name: string;
_scriptOutputFiles: OutputFileToInputFileMap;
_styleOutputFiles: OutputFileToInputFileMap;
legacyTestFilesToAppend: FilePath[];
vendorTestStaticStyles: FilePath[];
_customTransformsMap: Map<string, any>;
_nodeModules: Map<string, { name: string; path: FilePath }>;
options: any;
tests: boolean;
trees: any;
project: any;
registry: any;
testIndex(): Node;
getLintTests(): Node;
otherAssetPaths: any[];
}
type EmberCliHTMLBarsAddon = AddonInstance & {
htmlbarsOptions(): HTMLBarsOptions;
};

interface Group {
outputFiles: OutputFileToInputFileMap;
Expand All @@ -58,8 +51,8 @@ export default class V1App {
// used to signal that this is a dummy app owned by a particular addon
owningAddon: Package | undefined;

static create(app: EmberApp, packageCache: PackageCache): V1App {
if (app.project.pkg.keywords && app.project.pkg.keywords.includes('ember-addon')) {
static create(app: EmberAppInstance, packageCache: PackageCache): V1App {
if (app.project.pkg.keywords?.includes('ember-addon')) {
// we are a dummy app, which is unfortunately weird and special
return new V1DummyApp(app, packageCache);
} else {
Expand All @@ -71,7 +64,7 @@ export default class V1App {
private _implicitScripts: string[] = [];
private _implicitStyles: string[] = [];

protected constructor(protected app: EmberApp, protected packageCache: PackageCache) {}
protected constructor(protected app: EmberAppInstance, protected packageCache: PackageCache) {}

// always the name from package.json. Not the one that apps may have weirdly
// customized.
Expand Down Expand Up @@ -436,10 +429,10 @@ export default class V1App {
'implicit-test-styles': this.app.vendorTestStaticStyles.map(remapAsset),
'public-assets': mapKeys(this._publicAssets, (_, key) => remapAsset(key)),
};
let meta = {
let meta: PackageInfo = {
name: '@embroider/synthesized-vendor',
version: '0.0.0',
keywords: 'ember-addon',
keywords: ['ember-addon'],
'ember-addon': addonMeta,
};
writeJSONSync(join(outputPath, 'package.json'), meta, { spaces: 2 });
Expand Down Expand Up @@ -499,10 +492,10 @@ export default class V1App {
addonMeta['public-assets']![`./assets/${file}`] = `/assets/${file}`;
}
}
let meta = {
let meta: PackageInfo = {
name: '@embroider/synthesized-styles',
version: '0.0.0',
keywords: 'ember-addon',
keywords: ['ember-addon'],
'ember-addon': addonMeta,
};
writeJSONSync(join(outputPath, 'package.json'), meta, { spaces: 2 });
Expand Down Expand Up @@ -562,15 +555,17 @@ export default class V1App {
}

get htmlbarsPlugins(): TemplateCompilerPlugins {
let addon = this.app.project.addons.find((a: any) => a.name === 'ember-cli-htmlbars');
let addon = this.app.project.addons.find(
(a: AddonInstance) => a.name === 'ember-cli-htmlbars'
) as unknown as EmberCliHTMLBarsAddon;
let options = addon.htmlbarsOptions();
if (options.plugins.ast) {
if (options?.plugins?.ast) {
// even if the app was using @embroider/macros, we drop it from the config
// here in favor of our globally-configured one.
options.plugins.ast = options.plugins.ast.filter((p: any) => !isEmbroiderMacrosPlugin(p));
prepHtmlbarsAstPluginsForUnwrap(this.app.registry);
}
return options.plugins;
return options.plugins ?? {};
}

// our own appTree. Not to be confused with the one that combines the app js
Expand Down Expand Up @@ -747,7 +742,7 @@ function throwIfMissing<T>(
}

class V1DummyApp extends V1App {
constructor(app: EmberApp, packageCache: PackageCache) {
constructor(app: EmberAppInstance, packageCache: PackageCache) {
super(app, packageCache);
this.owningAddon = new OwningAddon(this.app.project.root, packageCache);
this.packageCache.seed(this.owningAddon);
Expand Down
10 changes: 5 additions & 5 deletions packages/compat/src/v1-instance-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import V1App from './v1-app';
import V1Addon, { V1AddonConstructor } from './v1-addon';
import { pathExistsSync } from 'fs-extra';
import { getOrCreate } from '@embroider/core';
import { AddonInstance, getOrCreate } from '@embroider/core';
import { MovablePackageCache } from './moved-package-cache';
import Options from './options';
import isEqual from 'lodash/isEqual';
Expand Down Expand Up @@ -38,12 +38,12 @@ export default class V1InstanceCache {

// no reason to do this on demand because oldApp already eagerly loaded
// all descendants
(oldApp.project.addons as any[]).forEach(addon => {
(oldApp.project.addons as AddonInstance[]).forEach(addon => {
this.addAddon(addon);
});
}

private adapterClass(addonInstance: any): V1AddonConstructor {
private adapterClass(addonInstance: AddonInstance): V1AddonConstructor {
let packageName = addonInstance.pkg.name;
// if the user registered something (including "null", which allows
// disabling the built-in adapters), that takes precedence.
Expand Down Expand Up @@ -72,13 +72,13 @@ export default class V1InstanceCache {
return AdapterClass;
}

private addAddon(addonInstance: any) {
private addAddon(addonInstance: AddonInstance) {
this.orderIdx += 1;
let Klass = this.adapterClass(addonInstance);
let v1Addon = new Klass(addonInstance, this.options, this.app, this.packageCache, this.orderIdx);
let pkgs = getOrCreate(this.addons, v1Addon.root, () => []);
pkgs.push(v1Addon);
(addonInstance.addons as any[]).forEach(a => this.addAddon(a));
addonInstance.addons.forEach(a => this.addAddon(a));
}

getAddons(root: string): V1Addon[] {
Expand Down
Loading

0 comments on commit 25a883a

Please sign in to comment.