refactor(compiler): cleanup and preparation for integration

- Rename `DirectiveMetadata` into `CompileDirectiveMetadata`, merge
  with `NormalizedDirectiveMetadata` and remove `ChangeDetectionMetadata`
- Store change detector factories not as array but
  directly at the `CompiledTemplate` or the embedded template
  to make instantiation easier later on
- Already analyze variable values and map them
  to `Directive.exportAs`
- Keep the directive sort order as specified in the
  `@View()` annotation
- Allow to clear the runtime cache in `StyleCompiler`
  and `TemplateCompiler`
- Ignore `script` elements to match the semantics of the
  current compiler
- Make all components dynamically loadable and remove
  the previously introduced property `@Component#dynamicLoadable`
  for now until we find a better option to configure this
- Don’t allow to specify bindings in `@View#directives` and `@View#pipes` as this was never supported by the transformer (see below for the breaking change)

BREAKING CHANGE:
- don't support DI bindings in `@View#directives` and `@View@pipes` any more in preparation of integrating the new compiler. Use `@Directive#bindings` to reexport directives under a different token instead.

Part of #3605
Closes #4314
This commit is contained in:
Tobias Bosch
2015-09-18 10:33:23 -07:00
parent eb7839e0ec
commit cc0c30484f
37 changed files with 1480 additions and 1167 deletions

View File

@ -42,7 +42,7 @@ export {
DebugContext,
ChangeDetectorGenConfig
} from './interfaces';
export {ChangeDetectionStrategy, changeDetectionStrategyFromJson} from './constants';
export {ChangeDetectionStrategy, CHANGE_DECTION_STRATEGY_VALUES} from './constants';
export {DynamicProtoChangeDetector} from './proto_change_detector';
export {BindingRecord, BindingTarget} from './binding_record';
export {DirectiveIndex, DirectiveRecord} from './directive_record';

View File

@ -1,11 +1,4 @@
import {
StringWrapper,
normalizeBool,
isBlank,
serializeEnum,
deserializeEnum
} from 'angular2/src/core/facade/lang';
import {MapWrapper} from 'angular2/src/core/facade/collection';
import {StringWrapper, normalizeBool, isBlank} from 'angular2/src/core/facade/lang';
export enum ChangeDetectionStrategy {
/**
@ -48,19 +41,15 @@ export enum ChangeDetectionStrategy {
OnPushObserve
}
var strategyMap: Map<number, ChangeDetectionStrategy> = MapWrapper.createFromPairs([
[0, ChangeDetectionStrategy.CheckOnce],
[1, ChangeDetectionStrategy.Checked],
[2, ChangeDetectionStrategy.CheckAlways],
[3, ChangeDetectionStrategy.Detached],
[4, ChangeDetectionStrategy.OnPush],
[5, ChangeDetectionStrategy.Default],
[6, ChangeDetectionStrategy.OnPushObserve]
]);
export function changeDetectionStrategyFromJson(value: number): ChangeDetectionStrategy {
return deserializeEnum(value, strategyMap);
}
export var CHANGE_DECTION_STRATEGY_VALUES = [
ChangeDetectionStrategy.CheckOnce,
ChangeDetectionStrategy.Checked,
ChangeDetectionStrategy.CheckAlways,
ChangeDetectionStrategy.Detached,
ChangeDetectionStrategy.OnPush,
ChangeDetectionStrategy.Default,
ChangeDetectionStrategy.OnPushObserve
];
export function isDefaultChangeDetectionStrategy(changeDetectionStrategy: ChangeDetectionStrategy):
boolean {

View File

@ -117,7 +117,6 @@ export class DirectiveResolver {
properties: mergedProperties,
events: mergedEvents,
host: mergedHost,
dynamicLoadable: dm.dynamicLoadable,
bindings: dm.bindings,
exportAs: dm.exportAs,
moduleId: dm.moduleId,

View File

@ -1,4 +1,4 @@
import {StringMap} from 'angular2/src/core/facade/collection';
import {StringMap, MapWrapper} from 'angular2/src/core/facade/collection';
export enum LifecycleHooks {
OnInit,
@ -11,6 +11,17 @@ export enum LifecycleHooks {
AfterViewChecked
}
export var LIFECYCLE_HOOKS_VALUES = [
LifecycleHooks.OnInit,
LifecycleHooks.OnDestroy,
LifecycleHooks.DoCheck,
LifecycleHooks.OnChanges,
LifecycleHooks.AfterContentInit,
LifecycleHooks.AfterContentChecked,
LifecycleHooks.AfterViewInit,
LifecycleHooks.AfterViewChecked
];
/**
* Lifecycle hooks are guaranteed to be called in the following order:
* - `OnChanges` (if any bindings have changed),

View File

@ -10,7 +10,7 @@ import {
} from 'angular2/src/core/render/render';
export class CompiledTemplate {
private _changeDetectorFactories: Function[] = null;
private _changeDetectorFactory: Function = null;
private _styles: string[] = null;
private _commands: TemplateCmd[] = null;
// Note: paramGetter is a function so that we can have cycles between templates!
@ -19,15 +19,15 @@ export class CompiledTemplate {
private _init() {
if (isBlank(this._commands)) {
var params = this._paramGetter();
this._changeDetectorFactories = params[0];
this._changeDetectorFactory = params[0];
this._commands = params[1];
this._styles = params[2];
}
}
get changeDetectorFactories(): Function[] {
get changeDetectorFactory(): Function {
this._init();
return this._changeDetectorFactories;
return this._changeDetectorFactory;
}
get styles(): string[] {
@ -69,26 +69,28 @@ export function ngContent(ngContentIndex: number): NgContentCmd {
}
export interface IBeginElementCmd extends TemplateCmd, RenderBeginElementCmd {
variableNameAndValues: string[];
eventNames: string[];
variableNameAndValues: Array<string | number>;
eventTargetAndNames: string[];
directives: Type[];
visit(visitor: CommandVisitor, context: any): any;
}
export class BeginElementCmd implements TemplateCmd, IBeginElementCmd, RenderBeginElementCmd {
constructor(public name: string, public attrNameAndValues: string[], public eventNames: string[],
public variableNameAndValues: string[], public directives: Type[],
constructor(public name: string, public attrNameAndValues: string[],
public eventTargetAndNames: string[],
public variableNameAndValues: Array<string | number>, public directives: Type[],
public isBound: boolean, public ngContentIndex: number) {}
visit(visitor: CommandVisitor, context: any): any {
return visitor.visitBeginElement(this, context);
}
}
export function beginElement(name: string, attrNameAndValues: string[], eventNames: string[],
variableNameAndValues: string[], directives: Type[], isBound: boolean,
ngContentIndex: number): BeginElementCmd {
return new BeginElementCmd(name, attrNameAndValues, eventNames, variableNameAndValues, directives,
isBound, ngContentIndex);
export function beginElement(name: string, attrNameAndValues: string[],
eventTargetAndNames: string[],
variableNameAndValues: Array<string | number>, directives: Type[],
isBound: boolean, ngContentIndex: number): BeginElementCmd {
return new BeginElementCmd(name, attrNameAndValues, eventTargetAndNames, variableNameAndValues,
directives, isBound, ngContentIndex);
}
export class EndElementCmd implements TemplateCmd {
@ -103,8 +105,9 @@ export class BeginComponentCmd implements TemplateCmd, IBeginElementCmd, RenderB
isBound: boolean = true;
templateId: number;
component: Type;
constructor(public name: string, public attrNameAndValues: string[], public eventNames: string[],
public variableNameAndValues: string[], public directives: Type[],
constructor(public name: string, public attrNameAndValues: string[],
public eventTargetAndNames: string[],
public variableNameAndValues: Array<string | number>, public directives: Type[],
public nativeShadow: boolean, public ngContentIndex: number,
public template: CompiledTemplate) {
this.component = directives[0];
@ -115,11 +118,11 @@ export class BeginComponentCmd implements TemplateCmd, IBeginElementCmd, RenderB
}
}
export function beginComponent(name: string, attrNameAnsValues: string[], eventNames: string[],
variableNameAndValues: string[], directives: Type[],
nativeShadow: boolean, ngContentIndex: number,
template: CompiledTemplate): BeginComponentCmd {
return new BeginComponentCmd(name, attrNameAnsValues, eventNames, variableNameAndValues,
export function beginComponent(
name: string, attrNameAnsValues: string[], eventTargetAndNames: string[],
variableNameAndValues: Array<string | number>, directives: Type[], nativeShadow: boolean,
ngContentIndex: number, template: CompiledTemplate): BeginComponentCmd {
return new BeginComponentCmd(name, attrNameAnsValues, eventTargetAndNames, variableNameAndValues,
directives, nativeShadow, ngContentIndex, template);
}
@ -135,10 +138,10 @@ export class EmbeddedTemplateCmd implements TemplateCmd, IBeginElementCmd,
RenderEmbeddedTemplateCmd {
isBound: boolean = true;
name: string = null;
eventNames: string[] = EMPTY_ARR;
eventTargetAndNames: string[] = EMPTY_ARR;
constructor(public attrNameAndValues: string[], public variableNameAndValues: string[],
public directives: Type[], public isMerged: boolean, public ngContentIndex: number,
public children: TemplateCmd[]) {}
public changeDetectorFactory: Function, public children: TemplateCmd[]) {}
visit(visitor: CommandVisitor, context: any): any {
return visitor.visitEmbeddedTemplate(this, context);
}
@ -146,20 +149,13 @@ export class EmbeddedTemplateCmd implements TemplateCmd, IBeginElementCmd,
export function embeddedTemplate(attrNameAndValues: string[], variableNameAndValues: string[],
directives: Type[], isMerged: boolean, ngContentIndex: number,
children: TemplateCmd[]): EmbeddedTemplateCmd {
changeDetectorFactory: Function, children: TemplateCmd[]):
EmbeddedTemplateCmd {
return new EmbeddedTemplateCmd(attrNameAndValues, variableNameAndValues, directives, isMerged,
ngContentIndex, children);
ngContentIndex, changeDetectorFactory, children);
}
export interface CommandVisitor extends RenderCommandVisitor {
visitText(cmd: TextCmd, context: any): any;
visitNgContent(cmd: NgContentCmd, context: any): any;
visitBeginElement(cmd: BeginElementCmd, context: any): any;
visitEndElement(context: any): any;
visitBeginComponent(cmd: BeginComponentCmd, context: any): any;
visitEndComponent(context: any): any;
visitEmbeddedTemplate(cmd: EmbeddedTemplateCmd, context: any): any;
}
export interface CommandVisitor extends RenderCommandVisitor {}
export function visitAllCommands(visitor: CommandVisitor, cmds: TemplateCmd[],
context: any = null) {

View File

@ -36,7 +36,7 @@ class Directive extends DirectiveMetadata {
*/
class Component extends ComponentMetadata {
const Component({String selector, List<String> properties,
List<String> events, Map<String, String> host, bool dynamicLoadable,
List<String> events, Map<String, String> host,
List bindings, String exportAs, String moduleId,
Map<String, dynamic> queries,
bool compileChildren, List viewBindings, ChangeDetectionStrategy changeDetection})
@ -45,7 +45,6 @@ class Component extends ComponentMetadata {
properties: properties,
events: events,
host: host,
dynamicLoadable: dynamicLoadable,
bindings: bindings,
exportAs: exportAs,
moduleId: moduleId,

View File

@ -76,8 +76,8 @@ export interface ComponentDecorator extends TypeDecorator {
View(obj: {
templateUrl?: string,
template?: string,
directives?: Array<Type | any | any[]>,
pipes?: Array<Type | any | any[]>,
directives?: Array<Type | any[]>,
pipes?: Array<Type | any[]>,
renderer?: string,
styles?: string[],
styleUrls?: string[],
@ -96,8 +96,8 @@ export interface ViewDecorator extends TypeDecorator {
View(obj: {
templateUrl?: string,
template?: string,
directives?: Array<Type | any | any[]>,
pipes?: Array<Type | any | any[]>,
directives?: Array<Type | any[]>,
pipes?: Array<Type | any[]>,
renderer?: string,
styles?: string[],
styleUrls?: string[],
@ -218,7 +218,6 @@ export interface ComponentFactory {
properties?: string[],
events?: string[],
host?: StringMap<string, string>,
dynamicLoadable?: boolean,
bindings?: any[],
exportAs?: string,
moduleId?: string,
@ -232,7 +231,6 @@ export interface ComponentFactory {
properties?: string[],
events?: string[],
host?: StringMap<string, string>,
dynamicLoadable?: boolean,
bindings?: any[],
exportAs?: string,
moduleId?: string,
@ -290,7 +288,8 @@ export interface ViewFactory {
(obj: {
templateUrl?: string,
template?: string,
directives?: Array<Type | any | any[]>,
directives?: Array<Type | any[]>,
pipes?: Array<Type | any[]>,
encapsulation?: ViewEncapsulation,
styles?: string[],
styleUrls?: string[],
@ -298,7 +297,8 @@ export interface ViewFactory {
new (obj: {
templateUrl?: string,
template?: string,
directives?: Array<Type | any | any[]>,
directives?: Array<Type | any[]>,
pipes?: Array<Type | any[]>,
encapsulation?: ViewEncapsulation,
styles?: string[],
styleUrls?: string[],

View File

@ -826,27 +826,6 @@ export class DirectiveMetadata extends InjectableMetadata {
*/
@CONST()
export class ComponentMetadata extends DirectiveMetadata {
/**
* Declare that this component can be programatically loaded.
* Every component that is used in bootstrap, routing, ... has to be
* annotated with this.
*
* ## Example
*
* ```
* @Component({
* selector: 'root',
* dynamicLoadable: true
* })
* @View({
* template: 'hello world!'
* })
* class RootComponent {
* }
* ```
*/
dynamicLoadable: boolean;
/**
* Defines the used change detection strategy.
*
@ -900,22 +879,21 @@ export class ComponentMetadata extends DirectiveMetadata {
*/
viewBindings: any[];
constructor({selector, properties, events, host, dynamicLoadable, exportAs, moduleId, bindings,
queries, viewBindings, changeDetection = ChangeDetectionStrategy.Default,
compileChildren = true}: {
selector?: string,
properties?: string[],
events?: string[],
host?: StringMap<string, string>,
dynamicLoadable?: boolean,
bindings?: any[],
exportAs?: string,
moduleId?: string,
compileChildren?: boolean,
viewBindings?: any[],
queries?: StringMap<string, any>,
changeDetection?: ChangeDetectionStrategy,
} = {}) {
constructor({selector, properties, events, host, exportAs, moduleId, bindings, viewBindings,
changeDetection = ChangeDetectionStrategy.Default, queries, compileChildren = true}:
{
selector?: string,
properties?: string[],
events?: string[],
host?: StringMap<string, string>,
bindings?: any[],
exportAs?: string,
moduleId?: string,
compileChildren?: boolean,
viewBindings?: any[],
queries?: StringMap<string, any>,
changeDetection?: ChangeDetectionStrategy,
} = {}) {
super({
selector: selector,
properties: properties,
@ -930,7 +908,6 @@ export class ComponentMetadata extends DirectiveMetadata {
this.changeDetection = changeDetection;
this.viewBindings = viewBindings;
this.dynamicLoadable = dynamicLoadable;
}
}

View File

@ -82,12 +82,9 @@ export class ViewMetadata {
* }
* ```
*/
// TODO(tbosch): use Type | Binding | any[] when Dart supports union types,
// as otherwise we would need to import Binding type and Dart would warn
// for an unused import.
directives: Array<Type | any | any[]>;
directives: Array<Type | any[]>;
pipes: Array<Type | any | any[]>;
pipes: Array<Type | any[]>;
/**
* Specify how the template and the styles should be encapsulated.
@ -100,8 +97,8 @@ export class ViewMetadata {
constructor({templateUrl, template, directives, pipes, encapsulation, styles, styleUrls}: {
templateUrl?: string,
template?: string,
directives?: Array<Type | any | any[]>,
pipes?: Array<Type | any | any[]>,
directives?: Array<Type | any[]>,
pipes?: Array<Type | any[]>,
encapsulation?: ViewEncapsulation,
styles?: string[],
styleUrls?: string[],

View File

@ -1,4 +1,4 @@
import {isPresent, isBlank, RegExpWrapper, deserializeEnum} from 'angular2/src/core/facade/lang';
import {isPresent, isBlank, RegExpWrapper} from 'angular2/src/core/facade/lang';
import {Promise} from 'angular2/src/core/facade/async';
import {Map, MapWrapper, StringMap, StringMapWrapper} from 'angular2/src/core/facade/collection';
import {
@ -309,11 +309,8 @@ export enum ViewEncapsulation {
None
}
var encapsulationMap: Map<number, ViewEncapsulation> = MapWrapper.createFromPairs(
[[0, ViewEncapsulation.Emulated], [1, ViewEncapsulation.Native], [2, ViewEncapsulation.None]]);
export function viewEncapsulationFromJson(value: number): ViewEncapsulation {
return deserializeEnum(value, encapsulationMap);
}
export var VIEW_ENCAPSULATION_VALUES =
[ViewEncapsulation.Emulated, ViewEncapsulation.Native, ViewEncapsulation.None];
export class ViewDefinition {
componentId: string;
@ -409,7 +406,7 @@ export interface RenderNgContentCmd extends RenderBeginCmd { ngContentIndex: num
export interface RenderBeginElementCmd extends RenderBeginCmd {
name: string;
attrNameAndValues: string[];
eventNames: string[];
eventTargetAndNames: string[];
}
export interface RenderBeginComponentCmd extends RenderBeginElementCmd {
@ -422,15 +419,14 @@ export interface RenderEmbeddedTemplateCmd extends RenderBeginElementCmd {
children: RenderTemplateCmd[];
}
// TODO(tbosch): change ts2dart to allow to use `CMD` as type in these methods!
export interface RenderCommandVisitor {
visitText /*<CMD extends RenderTextCmd>*/ (cmd: any, context: any): any;
visitNgContent /*<CMD extends RenderNgContentCmd>*/ (cmd: any, context: any): any;
visitBeginElement /*<CMD extends RenderBeginElementCmd>*/ (cmd: any, context: any): any;
visitText(cmd: any, context: any): any;
visitNgContent(cmd: any, context: any): any;
visitBeginElement(cmd: any, context: any): any;
visitEndElement(context: any): any;
visitBeginComponent /*<CMD extends RenderBeginComponentCmd>*/ (cmd: any, context: any): any;
visitBeginComponent(cmd: any, context: any): any;
visitEndComponent(context: any): any;
visitEmbeddedTemplate /*<CMD extends RenderEmbeddedTemplateCmd>*/ (cmd: any, context: any): any;
visitEmbeddedTemplate(cmd: any, context: any): any;
}