Skip to content

Commit

Permalink
setComponentTemplate
Browse files Browse the repository at this point in the history
Co-authored-by: Robert Jackson <[email protected]>
  • Loading branch information
chancancode and rwjblue committed Jun 27, 2019
1 parent 1cb5f67 commit dad92ae
Show file tree
Hide file tree
Showing 17 changed files with 409 additions and 127 deletions.
1 change: 1 addition & 0 deletions packages/@ember/-internals/glimmer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,3 +388,4 @@ export { setComponentManager, getComponentManager } from './lib/utils/custom-com
export { setModifierManager, getModifierManager } from './lib/utils/custom-modifier-manager';
export { capabilities as modifierCapabilties } from './lib/modifiers/custom';
export { isSerializationFirstNode } from './lib/utils/serialization-first-node-helpers';
export { setComponentTemplate, getComponentTemplate } from './lib/utils/component-template';
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ const EMPTY_POSITIONAL_ARGS: VersionedPathReference[] = [];

debugFreeze(EMPTY_POSITIONAL_ARGS);

export default class InputComponentManager extends InternalComponentManager<InputComponentState> {
export default class InputComponentManager extends InternalComponentManager<InputComponentState, Destroyable> {
getCapabilities(): ComponentCapabilities {
return CAPABILITIES;
}

prepareArgs(_state: InternalDefinitionState, args: Arguments): PreparedArguments {
prepareArgs(_state: InternalDefinitionState<Destroyable>, args: Arguments): PreparedArguments {
assert(
'The `<Input />` component does not take any positional arguments',
args.positional.length === 0
Expand All @@ -54,7 +54,7 @@ export default class InputComponentManager extends InternalComponentManager<Inpu

create(
_env: Environment,
{ ComponentClass }: InternalDefinitionState,
{ ComponentClass }: InternalDefinitionState<Destroyable>,
args: Arguments,
_dynamicScope: DynamicScope,
caller: VersionedPathReference
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,41 @@
import { Factory, Owner } from '@ember/-internals/owner';
import { Owner } from '@ember/-internals/owner';
import { OwnedTemplateMeta } from '@ember/-internals/views';
import { ComponentDefinition, Invocation, WithStaticLayout } from '@glimmer/runtime';
import { Dict } from '@glimmer/util';
import RuntimeResolver from '../resolver';
import { OwnedTemplate } from '../template';
import AbstractComponentManager from './abstract';

export interface InternalDefinitionState {
ComponentClass: Factory<any, any>;
export interface InternalComponentClass<T> {
create(props?: Dict<any>): T;
}

export interface InternalDefinitionState<T> {
ComponentClass: InternalComponentClass<T>;
layout: OwnedTemplate;
}

export class InternalComponentDefinition<T>
implements ComponentDefinition<InternalDefinitionState, InternalManager<T>> {
public state: InternalDefinitionState;
export class InternalComponentDefinition<T, U>
implements ComponentDefinition<InternalDefinitionState<U>, InternalManager<T, U>> {
public state: InternalDefinitionState<U>;

constructor(
public manager: InternalManager<T>,
ComponentClass: Factory<any, any>,
public manager: InternalManager<T, U>,
ComponentClass: InternalComponentClass<U>,
layout: OwnedTemplate
) {
this.state = { ComponentClass, layout };
}
}

export default abstract class InternalManager<T>
extends AbstractComponentManager<T, InternalDefinitionState>
implements WithStaticLayout<T, InternalDefinitionState, OwnedTemplateMeta, RuntimeResolver> {
export default abstract class InternalManager<T, U>
extends AbstractComponentManager<T, InternalDefinitionState<U>>
implements WithStaticLayout<T, InternalDefinitionState<U>, OwnedTemplateMeta, RuntimeResolver> {
constructor(protected owner: Owner) {
super();
}

getLayout({ layout: _layout }: InternalDefinitionState): Invocation {
getLayout({ layout: _layout }: InternalDefinitionState<U>): Invocation {
let layout = _layout.asLayout();

return {
Expand Down
6 changes: 1 addition & 5 deletions packages/@ember/-internals/glimmer/lib/environment.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { OWNER, Owner } from '@ember/-internals/owner';
import { constructStyleDeprecationMessage, lookupComponent } from '@ember/-internals/views';
import { constructStyleDeprecationMessage } from '@ember/-internals/views';
import { warn } from '@ember/debug';
import { DEBUG } from '@glimmer/env';
import { Option, Simple } from '@glimmer/interfaces';
Expand Down Expand Up @@ -57,10 +57,6 @@ export default class Environment extends GlimmerEnvironment {
return s;
}

lookupComponent(name: string, meta: any) {
return lookupComponent(meta.owner, name, meta);
}

toConditionalReference(reference: UpdatableReference): VersionedReference<boolean> {
return ConditionalReference.create(reference);
}
Expand Down
163 changes: 134 additions & 29 deletions packages/@ember/-internals/glimmer/lib/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { privatize as P } from '@ember/-internals/container';
import { ENV } from '@ember/-internals/environment';
import { LookupOptions, Owner, setOwner } from '@ember/-internals/owner';
import { lookupComponent, lookupPartial, OwnedTemplateMeta } from '@ember/-internals/views';
import { Factory, LookupOptions, Owner, setOwner } from '@ember/-internals/owner';
import { lookupPartial, OwnedTemplateMeta } from '@ember/-internals/views';
import {
EMBER_GLIMMER_ANGLE_BRACKET_BUILT_INS,
EMBER_GLIMMER_FN_HELPER,
EMBER_GLIMMER_ON_MODIFIER,
EMBER_GLIMMER_SET_COMPONENT_TEMPLATE,
EMBER_MODULE_UNIFICATION,
} from '@ember/canary-features';
import { assert } from '@ember/debug';
Expand All @@ -22,6 +23,7 @@ import CompileTimeLookup from './compile-time-lookup';
import { CurlyComponentDefinition } from './component-managers/curly';
import { CustomManagerDefinition, ManagerDelegate } from './component-managers/custom';
import InternalComponentManager, {
InternalComponentClass,
InternalComponentDefinition,
} from './component-managers/internal';
import { TemplateOnlyComponentDefinition } from './component-managers/template-only';
Expand Down Expand Up @@ -50,6 +52,7 @@ import { populateMacros } from './syntax';
import { mountHelper } from './syntax/mount';
import { outletHelper } from './syntax/outlet';
import { Factory as TemplateFactory, Injections, OwnedTemplate } from './template';
import { getComponentTemplate } from './utils/component-template';
import { getModifierManager } from './utils/custom-modifier-manager';
import { getManager } from './utils/managers';
import { ClassBasedHelperReference, SimpleHelperReference } from './utils/references';
Expand All @@ -65,6 +68,117 @@ function makeOptions(moduleName: string, namespace?: string): LookupOptions {
};
}

function componentFor(
name: string,
owner: Owner,
options?: LookupOptions
): Option<Factory<{}, {}>> {
let fullName = `component:${name}`;
return owner.factoryFor(fullName, options) || null;
}

function layoutFor(name: string, owner: Owner, options?: LookupOptions): Option<OwnedTemplate> {
let templateFullName = `template:components/${name}`;

return owner.lookup(templateFullName, options) || null;
}

function lookupModuleUnificationComponentPair(
owner: Owner,
name: string,
options?: LookupOptions
): Option<LookupResult> {
let localComponent = componentFor(name, owner, options);
let localLayout = layoutFor(name, owner, options);

let globalComponent = componentFor(name, owner);
let globalLayout = layoutFor(name, owner);

// TODO: we shouldn't have to recheck fallback, we should have a lookup that doesn't fallback
if (
localComponent !== null &&
globalComponent !== null &&
globalComponent.class === localComponent.class
) {
localComponent = null;
}
if (
localLayout !== null &&
globalLayout !== null &&
localLayout.referrer.moduleName === globalLayout.referrer.moduleName
) {
localLayout = null;
}

if (localComponent !== null || localLayout !== null) {
return { component: localComponent, layout: localLayout } as LookupResult;
} else if (globalComponent !== null || globalLayout !== null) {
return { component: globalComponent, layout: globalLayout } as LookupResult;
} else {
return null;
}
}

type LookupResult =
| {
component: Factory<{}, {}>;
layout: OwnedTemplate;
}
| {
component: Factory<{}, {}>;
layout: null;
}
| {
component: null;
layout: OwnedTemplate;
};

function lookupComponentPair(
owner: Owner,
name: string,
options?: LookupOptions
): Option<LookupResult> {
let component = componentFor(name, owner, options);

if (EMBER_GLIMMER_SET_COMPONENT_TEMPLATE) {
if (component !== null && component.class !== undefined) {
let factory = getComponentTemplate(component.class);

if (factory !== null) {
return { component, layout: factory(owner) };
}
}
}

let layout = layoutFor(name, owner, options);

if (component === null && layout === null) {
return null;
} else {
return { component, layout } as LookupResult;
}
}

function lookupComponent(owner: Owner, name: string, options: LookupOptions): Option<LookupResult> {
if (options.source || options.namespace) {
if (EMBER_MODULE_UNIFICATION) {
return lookupModuleUnificationComponentPair(owner, name, options);
}

let pair = lookupComponentPair(owner, name, options);

if (pair !== null) {
return pair;
}
}

if (EMBER_MODULE_UNIFICATION) {
return lookupModuleUnificationComponentPair(owner, name);
}

return lookupComponentPair(owner, name);
}

interface IBuiltInHelpers {
[name: string]: Helper | undefined;
}
Expand Down Expand Up @@ -123,7 +237,6 @@ export default class RuntimeResolver implements IRuntimeResolver<OwnedTemplateMe
// supports directly imported late bound layouts on component.prototype.layout
private templateCache: Map<Owner, Map<TemplateFactory, OwnedTemplate>> = new Map();
private componentDefinitionCache: Map<object, ComponentDefinition | null> = new Map();
private customManagerCache: Map<string, ManagerDelegate<Opaque>> = new Map();

public templateCacheHits = 0;
public templateCacheMisses = 0;
Expand Down Expand Up @@ -346,14 +459,14 @@ export default class RuntimeResolver implements IRuntimeResolver<OwnedTemplateMe
name = parsed.name;
namespace = parsed.namespace;
}
let { layout, component } = lookupComponent(owner, name, makeOptions(moduleName, namespace));

let key = component === undefined ? layout : component;
let pair = lookupComponent(owner, name, makeOptions(moduleName, namespace));

if (key === undefined) {
if (pair === null) {
return null;
}

let key = pair.component === null ? pair.layout : pair.component;
let cachedComponentDefinition = this.componentDefinitionCache.get(key);
if (cachedComponentDefinition !== undefined) {
return cachedComponentDefinition;
Expand All @@ -363,30 +476,33 @@ export default class RuntimeResolver implements IRuntimeResolver<OwnedTemplateMe

let definition: Option<ComponentDefinition> = null;

if (layout !== undefined && component === undefined && ENV._TEMPLATE_ONLY_GLIMMER_COMPONENTS) {
definition = new TemplateOnlyComponentDefinition(layout);
if (pair.component === null && ENV._TEMPLATE_ONLY_GLIMMER_COMPONENTS) {
definition = new TemplateOnlyComponentDefinition(pair.layout);
}

if (component !== undefined && component.class !== undefined) {
let wrapper = getManager(component.class);
if (pair.component !== null) {
assert(`missing component class ${name}`, pair.component.class !== undefined);

let ComponentClass = pair.component.class!;
let wrapper = getManager(ComponentClass);

if (wrapper && wrapper.type === 'component') {
let { factory } = wrapper;

if (wrapper.internal) {
assert(`missing layout for internal component ${name}`, layout !== undefined);
assert(`missing layout for internal component ${name}`, pair.layout !== null);

definition = new InternalComponentDefinition(
factory(owner) as InternalComponentManager<Opaque>,
component.class,
layout!
factory(owner) as InternalComponentManager<unknown, unknown>,
ComponentClass as InternalComponentClass<unknown>,
pair.layout!
);
} else {
definition = new CustomManagerDefinition(
name,
component,
pair.component,
factory(owner) as ManagerDelegate<Opaque>,
layout || owner.lookup<OwnedTemplate>(P`template:components/-default`)
pair.layout || owner.lookup<OwnedTemplate>(P`template:components/-default`)!
);
}
}
Expand All @@ -395,25 +511,14 @@ export default class RuntimeResolver implements IRuntimeResolver<OwnedTemplateMe
if (definition === null) {
definition = new CurlyComponentDefinition(
name,
component || owner.factoryFor(P`component:-default`),
pair.component || owner.factoryFor(P`component:-default`),
null,
layout! // TODO fix type
pair.layout! // TODO fix type
);
}

finalizer();
this.componentDefinitionCache.set(key, definition);
return definition;
}

_lookupComponentManager(owner: Owner, managerId: string): ManagerDelegate<Opaque> {
if (this.customManagerCache.has(managerId)) {
return this.customManagerCache.get(managerId)!;
}
let delegate = owner.lookup<ManagerDelegate<Opaque>>(`component-manager:${managerId}`);

this.customManagerCache.set(managerId, delegate);

return delegate;
}
}
20 changes: 19 additions & 1 deletion packages/@ember/-internals/glimmer/lib/template.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { getOwner } from '@ember/-internals/owner';
import { privatize as P } from '@ember/-internals/container';
import { getOwner, Owner, setOwner } from '@ember/-internals/owner';
import { OwnedTemplateMeta, StaticTemplateMeta } from '@ember/-internals/views';
import { Template } from '@glimmer/interfaces';
import { LazyCompiler, templateFactory, TemplateFactory } from '@glimmer/opcode-compiler';
import { SerializedTemplateWithLazyBlock } from '@glimmer/wire-format';

export interface NewTemplateFactory {
(owner: Owner): OwnedTemplate;
}

export type StaticTemplate = SerializedTemplateWithLazyBlock<StaticTemplateMeta>;
export type OwnedTemplate = Template<OwnedTemplateMeta>;

Expand All @@ -20,6 +25,7 @@ export interface Factory {
id: string;
meta: StaticTemplateMeta;
create(injections: Injections): OwnedTemplate;
toNewTemplateFactory(): NewTemplateFactory;
}

class FactoryWrapper implements Factory {
Expand All @@ -35,4 +41,16 @@ class FactoryWrapper implements Factory {
const owner = getOwner(injections);
return this.factory.create(injections.compiler, { owner });
}

toNewTemplateFactory(): NewTemplateFactory {
return (owner: Owner) => {
let options = {
compiler: owner.lookup(P`template-compiler:main`) as any,
};

setOwner(options, owner);

return this.create(options);
};
}
}
Loading

0 comments on commit dad92ae

Please sign in to comment.