Skip to content

Commit

Permalink
implement instructionCompiler / renderStrategy (formerly bindingComma…
Browse files Browse the repository at this point in the history
…nd) (#133)

* feat(jit): implement instruction-compiler decorator

feat(runtime): implement render-strategy decorator
refactor(template-compiler): various fixes and cleanups

* refactor(template-compiler): move binding commands to decorators

* fix(template-compiler): workaround for DI issue

* fix(binding-command): rename file

* fix(binding-command): pass correct bindingType to parser

* chore(renderer): fix linting errors

* chore(template-compiler): fix linting errors

* refactor(binding-command): add handles method
  • Loading branch information
fkleuver authored and EisenbergEffect committed Sep 3, 2018
1 parent d17dbd9 commit 1067e03
Show file tree
Hide file tree
Showing 12 changed files with 595 additions and 340 deletions.
58 changes: 52 additions & 6 deletions packages/jit/src/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,37 @@
import { IContainer, Registration } from '@aurelia/kernel';
import { AttrBindingBehavior, Compose, DebounceBindingBehavior, Else, If, ITemplateCompiler, OneTimeBindingBehavior, Repeat, Replaceable, SanitizeValueConverter, SelfBindingBehavior, SignalBindingBehavior, ThrottleBindingBehavior, ToViewBindingBehavior, TwoWayBindingBehavior, UpdateTriggerBindingBehavior, With } from '@aurelia/runtime';
import * as ExpressionParser from './binding/expression-parser';
import {
AttrBindingBehavior,
Compose,
DebounceBindingBehavior,
Else,
FromViewBindingBehavior,
If,
ITemplateCompiler,
OneTimeBindingBehavior,
Repeat,
Replaceable,
SanitizeValueConverter,
SelfBindingBehavior,
SignalBindingBehavior,
ThrottleBindingBehavior,
ToViewBindingBehavior,
TwoWayBindingBehavior,
UpdateTriggerBindingBehavior,
With
} from '@aurelia/runtime';
import { register } from './binding/expression-parser';
import {
CallBindingCommand,
CaptureBindingCommand,
DefaultBindingCommand,
DelegateBindingCommand,
ForBindingCommand,
FromViewBindingCommand,
OneTimeBindingCommand,
ToViewBindingCommand,
TriggerBindingCommand,
TwoWayBindingCommand
} from './templating/binding-command';
import { TemplateCompiler } from './templating/template-compiler';

const globalResources: any[] = [
Expand All @@ -15,19 +46,34 @@ const globalResources: any[] = [
DebounceBindingBehavior,
OneTimeBindingBehavior,
ToViewBindingBehavior,
FromViewBindingBehavior,
SelfBindingBehavior,
SignalBindingBehavior,
ThrottleBindingBehavior,
TwoWayBindingBehavior,
UpdateTriggerBindingBehavior
];

const defaultBindingLanguage: any[] = [
DefaultBindingCommand,
OneTimeBindingCommand,
ToViewBindingCommand,
FromViewBindingCommand,
TwoWayBindingCommand,
TriggerBindingCommand,
DelegateBindingCommand,
CaptureBindingCommand,
CallBindingCommand,
ForBindingCommand
];

export const BasicConfiguration = {
register(container: IContainer) {
register(container: IContainer) {
register(container);
container.register(
ExpressionParser,
Registration.singleton(ITemplateCompiler, TemplateCompiler),
...globalResources
...globalResources,
...defaultBindingLanguage
);
}
}
};
176 changes: 170 additions & 6 deletions packages/jit/src/templating/binding-command.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
import { Constructable, IContainer, Registration, Writable } from '@aurelia/kernel';
import { IResourceKind, IResourceType } from '@aurelia/runtime';
import { Constructable, IContainer, Immutable, Registration, Writable } from '@aurelia/kernel';
import { BindingMode, BindingType, ICustomAttributeSource, IExpressionParser, INode, IResourceDescriptions, IResourceKind, IResourceType, ITemplateSource, TargetedInstruction } from '@aurelia/runtime';
import { CallBindingInstruction, CaptureBindingInstruction, DelegateBindingInstruction, FromViewBindingInstruction, HydrateElementInstruction, HydrateTemplateController, OneTimeBindingInstruction, SetPropertyInstruction, ToViewBindingInstruction, TriggerBindingInstruction, TwoWayBindingInstruction } from './template-compiler';

export interface IBindingCommandSource {
name: string;
}

export type IBindingCommandType = IResourceType<IBindingCommandSource>;
export interface IBindingCommand {
compile(
attr: { name: string; value: string },
node: INode,
targetName: string,
resources: IResourceDescriptions,
attributeDefinition: Immutable<Required<ICustomAttributeSource>> | null,
elementDefinition: Immutable<Required<ITemplateSource>> | null,
elementInstruction?: HydrateElementInstruction
): TargetedInstruction;
handles(attributeDefinition: Immutable<Required<ICustomAttributeSource>> | null): boolean;
}

export type IBindingCommandType = IResourceType<IBindingCommandSource, IBindingCommand>;

export function bindingCommand(nameOrSource: string | IBindingCommandSource) {
return function<T extends Constructable>(target: T) {
return BindingCommandResource.define(nameOrSource, target);
}
};
}

// TODO: implement this
export const BindingCommandResource: IResourceKind<IBindingCommandSource, IBindingCommandType> = {
name: 'binding-command',

Expand All @@ -26,7 +39,7 @@ export const BindingCommandResource: IResourceKind<IBindingCommandSource, IBindi
},

define<T extends Constructable>(nameOrSource: string | IBindingCommandSource, ctor: T): T & IBindingCommandType {
const description = typeof nameOrSource === 'string' ? { name: nameOrSource } : nameOrSource;
const description = typeof nameOrSource === 'string' ? { name: nameOrSource, targetName: null } : nameOrSource;
const Type: T & IBindingCommandType = ctor as any;

(Type as Writable<IBindingCommandType>).kind = BindingCommandResource;
Expand All @@ -35,6 +48,157 @@ export const BindingCommandResource: IResourceKind<IBindingCommandSource, IBindi
container.register(Registration.singleton(Type.kind.keyFrom(description.name), Type));
};

const proto = Type.prototype;

proto.handles = proto.handles || defaultHandles;

return Type;
}
};

function defaultHandles(this: IBindingCommand, attributeDefinition: Immutable<Required<ICustomAttributeSource>>): boolean {
return !attributeDefinition || attributeDefinition.isTemplateController === false;
}

export interface DefaultBindingCommand extends IBindingCommand {}

@bindingCommand('bind')
export class DefaultBindingCommand implements IBindingCommand {
static inject = [IExpressionParser];
constructor(private parser: IExpressionParser) {}

public compile(
attr: { name: string; value: string },
node: INode,
targetName: string,
resources: IResourceDescriptions,
attributeDefinition: Immutable<Required<ICustomAttributeSource>> | null,
elementDefinition: Immutable<Required<ITemplateSource>> | null
): TargetedInstruction {
let mode = BindingMode.toView;
if (elementDefinition) {
const bindable = elementDefinition.bindables[targetName];
if (bindable && bindable.mode && bindable.mode !== BindingMode.default) {
mode = bindable.mode;
}
}
switch (mode) {
case BindingMode.oneTime:
return new OneTimeBindingInstruction(this.parser.parse(attr.value, BindingType.OneTimeCommand), targetName);
case BindingMode.toView:
return new ToViewBindingInstruction(this.parser.parse(attr.value, BindingType.ToViewCommand), targetName);
case BindingMode.fromView:
return new FromViewBindingInstruction(this.parser.parse(attr.value, BindingType.FromViewCommand), targetName);
case BindingMode.twoWay:
return new TwoWayBindingInstruction(this.parser.parse(attr.value, BindingType.TwoWayCommand), targetName);
}
}
}

export interface OneTimeBindingCommand extends IBindingCommand {}

@bindingCommand('one-time')
export class OneTimeBindingCommand implements IBindingCommand {
static inject = [IExpressionParser];
constructor(private parser: IExpressionParser) {}
public compile(attr: { name: string; value: string }, node: INode, targetName: string): TargetedInstruction {
return new OneTimeBindingInstruction(this.parser.parse(attr.value, BindingType.OneTimeCommand), targetName);
}
}

export interface ToViewBindingCommand extends IBindingCommand {}

@bindingCommand('to-view')
export class ToViewBindingCommand implements IBindingCommand {
static inject = [IExpressionParser];
constructor(private parser: IExpressionParser) {}
public compile(attr: { name: string; value: string }, node: INode, targetName: string): TargetedInstruction {
return new ToViewBindingInstruction(this.parser.parse(attr.value, BindingType.ToViewCommand), targetName);
}
}

export interface FromViewBindingCommand extends IBindingCommand {}

@bindingCommand('from-view')
export class FromViewBindingCommand implements IBindingCommand {
static inject = [IExpressionParser];
constructor(private parser: IExpressionParser) {}
public compile(attr: { name: string; value: string }, node: INode, targetName: string): TargetedInstruction {
return new FromViewBindingInstruction(this.parser.parse(attr.value, BindingType.FromViewCommand), targetName);
}
}

export interface TwoWayBindingCommand extends IBindingCommand {}

@bindingCommand('two-way')
export class TwoWayBindingCommand implements IBindingCommand {
static inject = [IExpressionParser];
constructor(private parser: IExpressionParser) {}
public compile(attr: { name: string; value: string }, node: INode, targetName: string): TargetedInstruction {
return new TwoWayBindingInstruction(this.parser.parse(attr.value, BindingType.TwoWayCommand), targetName);
}
}

export interface TriggerBindingCommand extends IBindingCommand {}

@bindingCommand('trigger')
export class TriggerBindingCommand implements IBindingCommand {
static inject = [IExpressionParser];
constructor(private parser: IExpressionParser) {}
public compile(attr: { name: string; value: string }, node: INode, targetName: string): TargetedInstruction {
return new TriggerBindingInstruction(this.parser.parse(attr.value, BindingType.TriggerCommand), targetName);
}
}

export interface DelegateBindingCommand extends IBindingCommand {}

@bindingCommand('delegate')
export class DelegateBindingCommand implements IBindingCommand {
static inject = [IExpressionParser];
constructor(private parser: IExpressionParser) {}
public compile(attr: { name: string; value: string }, node: INode, targetName: string): TargetedInstruction {
return new DelegateBindingInstruction(this.parser.parse(attr.value, BindingType.DelegateCommand), targetName);
}
}

export interface CaptureBindingCommand extends IBindingCommand {}

@bindingCommand('capture')
export class CaptureBindingCommand implements IBindingCommand {
static inject = [IExpressionParser];
constructor(private parser: IExpressionParser) {}
public compile(attr: { name: string; value: string }, node: INode, targetName: string): TargetedInstruction {
return new CaptureBindingInstruction(this.parser.parse(attr.value, BindingType.CaptureCommand), targetName);
}
}

export interface CallBindingCommand extends IBindingCommand {}

@bindingCommand('call')
export class CallBindingCommand implements IBindingCommand {
static inject = [IExpressionParser];
constructor(private parser: IExpressionParser) {}
public compile(attr: { name: string; value: string }, node: INode, targetName: string): TargetedInstruction {
return new CallBindingInstruction(this.parser.parse(attr.value, BindingType.CallCommand), targetName);
}
}

@bindingCommand('for')
export class ForBindingCommand implements IBindingCommand {
static inject = [IExpressionParser];
constructor(private parser: IExpressionParser) {}
public compile(attr: { name: string; value: string }, node: INode, targetName: string): TargetedInstruction {
const src: ITemplateSource = {
templateOrNode: node,
instructions: []
};
return new HydrateTemplateController(src, targetName, [
new ToViewBindingInstruction(this.parser.parse(attr.value, BindingType.ForCommand), 'items'),
new SetPropertyInstruction('item', 'local')
]);
}

public handles(attributeDefinition: Immutable<Required<ICustomAttributeSource>>): boolean {
return !!attributeDefinition && attributeDefinition.name === 'repeat';
}
}
Loading

0 comments on commit 1067e03

Please sign in to comment.