Skip to content

Commit

Permalink
feat(template-compiler): a proper abstraction for resources
Browse files Browse the repository at this point in the history
  • Loading branch information
EisenbergEffect committed Jul 2, 2018
1 parent 7d7cbeb commit 3d62b7a
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 51 deletions.
4 changes: 2 additions & 2 deletions src/jit/templating/template-compiler.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ITemplateCompiler, Resources } from "../../runtime/templating/template-compiler";
import { ITemplateCompiler, ICompilationResources } from "../../runtime/templating/template-compiler";
import { TemplateDefinition } from "../../runtime/templating/instructions";

export class TemplateCompiler implements ITemplateCompiler {
get name() {
return 'default';
}

compile(definition: TemplateDefinition, resources: Resources): TemplateDefinition {
compile(definition: TemplateDefinition, resources: ICompilationResources): TemplateDefinition {
throw new Error('Template Compiler Not Yet Implemented');
}
}
17 changes: 9 additions & 8 deletions src/kernel/di.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface IRegistration<T = any> {
}

export interface IFactory<T = any> {
readonly type: Function;
registerTransformer(transformer: (instance: T) => T): boolean;
construct(container: IContainer, dynamicDependencies?: any[]): T;
}
Expand Down Expand Up @@ -261,7 +262,7 @@ class Resolver implements IResolver, IRegistration {
}
}

getFactory(container: IContainer): IFactory {
getFactory(container: IContainer): IFactory | null {
switch (this.strategy) {
case ResolverStrategy.singleton:
case ResolverStrategy.transient:
Expand All @@ -280,13 +281,13 @@ interface IInvoker {
class Factory implements IFactory {
private transformers: ((instance: any) => any)[] = null;

constructor(private fn: Function, private invoker: IInvoker, private dependencies: any[]) { }
constructor(public type: Function, private invoker: IInvoker, private dependencies: any[]) { }

construct(container: IContainer, dynamicDependencies?: any[]): any {
let transformers = this.transformers;
let instance = dynamicDependencies !== undefined
? this.invoker.invokeWithDynamicDependencies(container, this.fn, this.dependencies, dynamicDependencies)
: this.invoker.invoke(container, this.fn, this.dependencies);
? this.invoker.invokeWithDynamicDependencies(container, this.type, this.dependencies, dynamicDependencies)
: this.invoker.invoke(container, this.type, this.dependencies);

if (transformers === null) {
return instance;
Expand All @@ -308,10 +309,10 @@ class Factory implements IFactory {
return true;
}

static create(fn: Function & { inject?: any }): IFactory {
const dependencies = DI.getDependencies(fn);
static create(type: Function): IFactory {
const dependencies = DI.getDependencies(type);
const invoker = classInvokers[dependencies.length] || classInvokers.fallback;
return new Factory(fn, invoker, dependencies);
return new Factory(type, invoker, dependencies);
}
}

Expand All @@ -332,7 +333,7 @@ function isRegistry(obj: any): obj is IRegistry {
class Container implements IContainer {
private parent: Container = null;
private resolvers = new Map<any, IResolver>();
private factories: Map<Function, any>;
private factories: Map<Function, IFactory>;
private configuration: IContainerConfiguration;

constructor(configuration: IContainerConfiguration = {}) {
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export function bindable(configOrTarget?: IBindableInstruction | Object, key?, d
let deco = function(target, key2, descriptor2) {
target = target.constructor;

let observables: Record<string, IBindableInstruction> = target.observables || (target.observables = {});
let bindables: Record<string, IBindableInstruction> = target.bindables || (target.bindables = {});
let config: IBindableInstruction = configOrTarget || {};

if (!config.attribute) {
Expand All @@ -121,7 +121,7 @@ export function bindable(configOrTarget?: IBindableInstruction | Object, key?, d
config.mode = BindingMode.oneWay;
}

observables[key2] = config;
bindables[key2] = config;
};

if (key) { //placed on a property without parens
Expand Down
26 changes: 10 additions & 16 deletions src/runtime/templating/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,9 @@ export const Component = {
return Type;
},
attribute<T extends Constructable>(nameOrSource: string | IAttributeSource, ctor: T): T & IAttributeType {
const definition = createAttributeDefinition(nameOrSource);
const Type: T & IAttributeType = ctor as any;
const definition = createAttributeDefinition(typeof nameOrSource === 'string' ? { name: nameOrSource } : nameOrSource, Type);
const proto: IAttributeComponent = Type.prototype;
const observables = (Type as any).observables || {};

(Type as Writable<IAttributeType>).type = 'attribute';
(Type as Writable<IAttributeType>).definition = definition;
Expand All @@ -114,7 +113,7 @@ export const Component = {
this.$isBound = false;
this.$scope = null;
this.$slot = null;
this.$behavior = renderingEngine.applyRuntimeBehavior(Type, this, observables);
this.$behavior = renderingEngine.applyRuntimeBehavior(Type, this, definition.bindables);

if (this.$behavior.hasCreated) {
(this as any).created();
Expand Down Expand Up @@ -222,7 +221,7 @@ export const Component = {
};

this.$context = template.renderContext;
this.$behavior = renderingEngine.applyRuntimeBehavior(Type, this, definition.observables);
this.$behavior = renderingEngine.applyRuntimeBehavior(Type, this, definition.bindables);
this.$host = definition.containerless ? DOM.convertToAnchor(host, true) : host;
this.$shadowRoot = DOM.createElementViewHost(this.$host, definition.shadowOptions);
this.$usingSlotEmulation = DOM.isUsingSlotEmulation(this.$host);
Expand Down Expand Up @@ -366,18 +365,13 @@ function createDefinition<T>(nameOrSource: string | T): Immutable<T> {
}
}

function createAttributeDefinition(nameOrSource: string | IAttributeSource): Immutable<Required<IAttributeSource>> {
if (typeof nameOrSource === 'string') {
nameOrSource = {
name: nameOrSource
};
}

function createAttributeDefinition(attributeSource:IAttributeSource, Type: IAttributeType): Immutable<Required<IAttributeSource>> {
return {
name: nameOrSource.name,
aliases: nameOrSource.aliases || PLATFORM.emptyArray,
defaultBindingMode: nameOrSource.defaultBindingMode || BindingMode.oneWay,
isTemplateController: nameOrSource.isTemplateController || false
name: attributeSource.name,
aliases: attributeSource.aliases || PLATFORM.emptyArray,
defaultBindingMode: attributeSource.defaultBindingMode || BindingMode.oneWay,
isTemplateController: attributeSource.isTemplateController || false,
bindables: Object.assign({}, (Type as any).bindables, attributeSource.bindables)
};
}

Expand All @@ -389,7 +383,7 @@ function createTemplateDefinition(templateSource: ITemplateSource, Type: IElemen
required: false,
compiler: 'default'
},
observables: Object.assign({}, (Type as any).observables, templateSource.observables),
bindables: Object.assign({}, (Type as any).bindables, templateSource.bindables),
instructions: templateSource.instructions ? Array.from(templateSource.instructions) : PLATFORM.emptyArray,
dependencies: templateSource.dependencies ? Array.from(templateSource.dependencies) : PLATFORM.emptyArray,
surrogates: templateSource.surrogates ? Array.from(templateSource.surrogates) : PLATFORM.emptyArray,
Expand Down
13 changes: 11 additions & 2 deletions src/runtime/templating/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,26 @@ export interface ITemplateSource {
dependencies?: any[];
build?: IBuildInstruction;
surrogates?: TargetedInstruction[];
observables?: Record<string, IBindableInstruction>;
bindables?: Record<string, IBindableInstruction>;
containerless?: boolean;
shadowOptions?: ShadowRootInit;
hasSlots?: boolean;
}

export interface IElementDescription extends Pick<TemplateDefinition, 'name' | 'bindables'> {
bindables: Record<string, Required<IBindableInstruction>>;
}

export interface IAttributeSource {
name: string;
defaultBindingMode?: BindingMode;
aliases?: string[];
isTemplateController?: boolean;
bindables?: Record<string, IBindableInstruction>;
}

export interface IAttributeDescription extends AttributeDefinition {
bindables: Record<string, Required<IBindableInstruction>>;
}

export interface IValueConverterSource {
Expand All @@ -62,7 +71,7 @@ export interface IBindableInstruction {

export type TemplateDefinition = Immutable<Required<ITemplateSource>>;
export type TemplatePartDefinitions = Record<string, Immutable<ITemplateSource>>;
export type ObservableDefinitions = Record<string, Immutable<IBindableInstruction>>;
export type BindableDefinitions = Record<string, Immutable<IBindableInstruction>>;
export type AttributeDefinition = Immutable<Required<IAttributeSource>>;
export type ValueConverterDefinition = Immutable<Required<IValueConverterSource>>;
export type BindingBehaviorDefinition = Immutable<Required<IBindingBehaviorSource>>;
Expand Down
42 changes: 34 additions & 8 deletions src/runtime/templating/rendering-engine.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { RuntimeBehavior, IRuntimeBehavior } from "./runtime-behavior";
import { IAttributeType, IElementType, IAttributeComponent, IElementComponent } from "./component";
import { DI, IContainer, inject, all } from "../../kernel/di";
import { ITemplateSource, IHydrateElementInstruction, TemplateDefinition, TemplatePartDefinitions, ObservableDefinitions } from "./instructions";
import { ITemplateSource, IHydrateElementInstruction, TemplateDefinition, TemplatePartDefinitions, BindableDefinitions, IElementDescription, IAttributeDescription } from "./instructions";
import { ITaskQueue } from "../task-queue";
import { IViewOwner, View } from "./view";
import { INode, IView, DOM } from "../dom";
Expand All @@ -21,14 +21,14 @@ import { ITemplate } from "./template";
import { IObserverLocator } from "../binding/observer-locator";
import { IEventManager } from "../binding/event-manager";
import { IExpressionParser } from "../binding/expression-parser";
import { ITemplateCompiler } from "./template-compiler";
import { ITemplateCompiler, ICompilationResources } from "./template-compiler";

export interface IRenderingEngine {
getElementTemplate(definition: TemplateDefinition, componentType: IElementType): ITemplate;
getVisualFactory(context: IRenderContext, source: Immutable<ITemplateSource>): IVisualFactory;

applyRuntimeBehavior(type: IAttributeType, instance: IAttributeComponent, observables: ObservableDefinitions): IRuntimeBehavior;
applyRuntimeBehavior(type: IElementType, instance: IElementComponent, observables: ObservableDefinitions): IRuntimeBehavior
applyRuntimeBehavior(type: IAttributeType, instance: IAttributeComponent, bindables: BindableDefinitions): IRuntimeBehavior;
applyRuntimeBehavior(type: IElementType, instance: IElementComponent, bindables: BindableDefinitions): IRuntimeBehavior

createVisualFromComponent(context: IRenderContext, componentOrType: any, instruction: Immutable<IHydrateElementInstruction>): VisualWithCentralComponent;
createRenderer(context: IRenderContext): IRenderer;
Expand Down Expand Up @@ -98,7 +98,7 @@ class RenderingEngine implements IRenderingEngine {
throw Reporter.error(20, `Requested Compiler: ${compiler.name}`);
}

definition = compiler.compile(definition, context);
definition = compiler.compile(definition, new RuntimeCompilationResources(<ExposedContext>context));
}

return new CompiledTemplate(this, context, definition);
Expand Down Expand Up @@ -138,11 +138,11 @@ class RenderingEngine implements IRenderingEngine {
return new VisualFactory(definition.name, CompiledVisual);
}

applyRuntimeBehavior(type: IAttributeType | IElementType, instance: IAttributeComponent | IElementComponent, observables: ObservableDefinitions): IRuntimeBehavior {
applyRuntimeBehavior(type: IAttributeType | IElementType, instance: IAttributeComponent | IElementComponent, bindables: BindableDefinitions): IRuntimeBehavior {
let found = this.behaviorLookup.get(type);

if (!found) {
found = RuntimeBehavior.create(instance, observables, type);
found = RuntimeBehavior.create(instance, bindables, type);
this.behaviorLookup.set(type, found);
}

Expand Down Expand Up @@ -210,7 +210,7 @@ function createDefinition(definition: Immutable<ITemplateSource>): TemplateDefin
required: false,
compiler: 'default'
},
observables: definition.observables || PLATFORM.emptyObject,
bindables: definition.bindables || PLATFORM.emptyObject,
instructions: definition.instructions ? Array.from(definition.instructions) : PLATFORM.emptyArray,
dependencies: definition.dependencies ? Array.from(definition.dependencies) : PLATFORM.emptyArray,
surrogates: definition.surrogates ? Array.from(definition.surrogates) : PLATFORM.emptyArray,
Expand All @@ -236,6 +236,32 @@ class CompiledTemplate implements ITemplate {
}
}

class RuntimeCompilationResources implements ICompilationResources {
constructor(private context: ExposedContext) {}

tryGetElement(name: string): IElementDescription | null {
return this.getDescription<IElementDescription>(name);
}

tryGetAttribute(name: string): IAttributeDescription | null {
return this.getDescription<IAttributeDescription>(name);
}

private getDescription<T extends (IElementDescription | IAttributeDescription)>(name: string) {
const resolver = this.context.getResolver(name);

if (resolver !== null && resolver.getFactory) {
let factory = resolver.getFactory(this.context);

if (factory !== null) {
return (factory.type as IElementType | IAttributeType).definition as T;
}
}

return null;
}
}

abstract class Visual implements IVisual {
$bindable: IBindScope[] = [];
$attachable: IAttach[] = [];
Expand Down
18 changes: 9 additions & 9 deletions src/runtime/templating/runtime-behavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ITaskQueue } from "../task-queue";
import { SubscriberCollection } from "../binding/subscriber-collection";
import { IAccessor, ISubscribable } from "../binding/observation";
import { Observer } from "../binding/property-observation";
import { ObservableDefinitions } from "./instructions";
import { BindableDefinitions } from "./instructions";

export interface IRuntimeBehavior {
hasCreated: boolean;
Expand All @@ -22,7 +22,7 @@ export interface IRuntimeBehavior {
export class RuntimeBehavior implements IRuntimeBehavior {
private constructor() {}

observables: ObservableDefinitions;
bindables: BindableDefinitions;
hasCreated = false;
hasBound = false;
hasAttaching = false;
Expand All @@ -32,22 +32,22 @@ export class RuntimeBehavior implements IRuntimeBehavior {
hasUnbound = false;
hasCreateView = false;

static create(instance, observables: ObservableDefinitions, Component: IElementType | IAttributeType) {
static create(instance, bindables: BindableDefinitions, Component: IElementType | IAttributeType) {
const behavior = new RuntimeBehavior();

for (let name in instance) {
if (name in observables) {
if (name in bindables) {
continue;
}

const callback = `${name}Changed`;

if (callback in instance) {
observables[name] = { callback };
bindables[name] = { callback };
}
}

behavior.observables = observables;
behavior.bindables = bindables;
behavior.hasCreated = 'created' in instance;
behavior.hasBound = 'bound' in instance;
behavior.hasAttaching = 'attaching' in instance;
Expand Down Expand Up @@ -82,12 +82,12 @@ export class RuntimeBehavior implements IRuntimeBehavior {

private applyTo(taskQueue: ITaskQueue, instance: any) {
const observers = {};
const finalObservables = this.observables;
const observableNames = Object.getOwnPropertyNames(finalObservables);
const finalBindables = this.bindables;
const observableNames = Object.getOwnPropertyNames(finalBindables);

for (let i = 0, ii = observableNames.length; i < ii; ++i) {
const name = observableNames[i];
const observable = finalObservables[name];
const observable = finalBindables[name];
const changeHandler = observable.callback;

if (changeHandler in instance) {
Expand Down
11 changes: 7 additions & 4 deletions src/runtime/templating/template-compiler.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { TemplateDefinition } from "./instructions";
import { IServiceLocator, DI } from "../../kernel/di";
import { TemplateDefinition, IElementDescription, IAttributeDescription } from "./instructions";
import { DI } from "../../kernel/di";

export type Resources = Pick<IServiceLocator, 'has'>;
export interface ICompilationResources {
tryGetElement(name: string): IElementDescription | null;
tryGetAttribute(name: string): IAttributeDescription | null;
}

export interface ITemplateCompiler {
readonly name: string;
compile(definition: TemplateDefinition, resources: Resources): TemplateDefinition;
compile(definition: TemplateDefinition, resources: ICompilationResources): TemplateDefinition;
}

export const ITemplateCompiler = DI.createInterface<ITemplateCompiler>().noDefault();

0 comments on commit 3d62b7a

Please sign in to comment.