feat(compiler): add TemplateCompiler

TemplateCompiler is the entry point to the new compiler

Related to #3605
Closes #4220
This commit is contained in:
Tobias Bosch
2015-09-14 15:59:09 -07:00
parent eaa20f661a
commit 457b689bf0
47 changed files with 2064 additions and 725 deletions

View File

@ -93,8 +93,11 @@ export class DirectiveResolver {
properties: mergedProperties,
events: mergedEvents,
host: mergedHost,
dynamicLoadable: dm.dynamicLoadable,
compiledHostTemplate: dm.compiledHostTemplate,
bindings: dm.bindings,
exportAs: dm.exportAs,
moduleId: dm.moduleId,
compileChildren: dm.compileChildren,
changeDetection: dm.changeDetection,
viewBindings: dm.viewBindings
@ -108,6 +111,7 @@ export class DirectiveResolver {
host: mergedHost,
bindings: dm.bindings,
exportAs: dm.exportAs,
moduleId: dm.moduleId,
compileChildren: dm.compileChildren
});
}

View File

@ -1,4 +1,4 @@
import {Type, CONST_EXPR, isPresent} from 'angular2/src/core/facade/lang';
import {Type, CONST_EXPR, isPresent, isBlank} from 'angular2/src/core/facade/lang';
import {
RenderTemplateCmd,
RenderCommandVisitor,
@ -10,7 +10,35 @@ import {
} from 'angular2/src/core/render/render';
export class CompiledTemplate {
constructor(public id: string, public commands: TemplateCmd[]) {}
private _changeDetectorFactories: Function[] = null;
private _styles: string[] = null;
private _commands: TemplateCmd[] = null;
// Note: paramGetter is a function so that we can have cycles between templates!
constructor(public id: number, private _paramGetter: Function) {}
private _init() {
if (isBlank(this._commands)) {
var params = this._paramGetter();
this._changeDetectorFactories = params[0];
this._commands = params[1];
this._styles = params[2];
}
}
get changeDetectorFactories(): Function[] {
this._init();
return this._changeDetectorFactories;
}
get styles(): string[] {
this._init();
return this._styles;
}
get commands(): TemplateCmd[] {
this._init();
return this._commands;
}
}
const EMPTY_ARR = CONST_EXPR([]);
@ -73,14 +101,14 @@ export function endElement(): TemplateCmd {
export class BeginComponentCmd implements TemplateCmd, IBeginElementCmd, RenderBeginComponentCmd {
isBound: boolean = true;
templateId: string;
templateId: number;
component: Type;
constructor(public name: string, public attrNameAndValues: string[], public eventNames: string[],
public variableNameAndValues: string[], public directives: Type[],
public nativeShadow: boolean, public ngContentIndex: number,
public template: CompiledTemplate) {
this.component = directives[0];
this.templateId = isPresent(template) ? template.id : null;
this.templateId = template.id;
}
visit(visitor: CommandVisitor, context: any): any {
return visitor.visitBeginComponent(this, context);

View File

@ -10,7 +10,7 @@ import {reflector} from 'angular2/src/core/reflection/reflection';
@Injectable()
export class ViewResolver {
_cache: Map<Type, /*node*/ any> = new Map();
_cache: Map<Type, ViewMetadata> = new Map();
resolve(component: Type): ViewMetadata {
var view = this._cache.get(component);

View File

@ -1,14 +1,14 @@
library angular2.src.core.metadata;
import "package:angular2/src/core/facade/collection.dart" show List;
import 'package:angular2/src/core/facade/collection.dart' show List;
import 'package:angular2/src/core/change_detection/change_detection.dart';
import "./metadata/di.dart";
import "./metadata/directives.dart";
import "./metadata/view.dart";
import './metadata/di.dart';
import './metadata/directives.dart';
import './metadata/view.dart';
export "./metadata/di.dart";
export "./metadata/directives.dart";
export "./metadata/view.dart";
export './metadata/di.dart';
export './metadata/directives.dart';
export './metadata/view.dart';
/**
* See: [DirectiveMetadata] for docs.
@ -16,7 +16,7 @@ export "./metadata/view.dart";
class Directive extends DirectiveMetadata {
const Directive({String selector, List<String> properties,
List<String> events, Map<String, String> host,
List bindings, String exportAs,
List bindings, String exportAs, String moduleId,
bool compileChildren: true})
: super(
selector: selector,
@ -25,6 +25,7 @@ class Directive extends DirectiveMetadata {
host: host,
bindings: bindings,
exportAs: exportAs,
moduleId: moduleId,
compileChildren: compileChildren);
}
@ -33,16 +34,18 @@ class Directive extends DirectiveMetadata {
*/
class Component extends ComponentMetadata {
const Component({String selector, List<String> properties,
List<String> events, Map<String, String> host,
List bindings, String exportAs,
List<String> events, Map<String, String> host, bool dynamicLoadable,
List bindings, String exportAs, String moduleId,
bool compileChildren, List viewBindings, ChangeDetectionStrategy changeDetection})
: super(
selector: selector,
properties: properties,
events: events,
host: host,
dynamicLoadable: dynamicLoadable,
bindings: bindings,
exportAs: exportAs,
moduleId: moduleId,
compileChildren: compileChildren,
viewBindings: viewBindings,
changeDetection: changeDetection);

View File

@ -139,11 +139,11 @@ export interface ViewDecorator extends TypeDecorator {
export interface DirectiveFactory {
(obj: {
selector?: string, properties?: string[], events?: string[], host?: StringMap<string, string>,
bindings?: any[], exportAs?: string, compileChildren?: boolean;
bindings?: any[], exportAs?: string, moduleId?: string, compileChildren?: boolean;
}): DirectiveDecorator;
new (obj: {
selector?: string, properties?: string[], events?: string[], host?: StringMap<string, string>,
bindings?: any[], exportAs?: string, compileChildren?: boolean;
bindings?: any[], exportAs?: string, moduleId?: string, compileChildren?: boolean;
}): DirectiveMetadata;
}
@ -196,8 +196,10 @@ export interface ComponentFactory {
properties?: string[],
events?: string[],
host?: StringMap<string, string>,
dynamicLoadable?: boolean,
bindings?: any[],
exportAs?: string,
moduleId?: string,
compileChildren?: boolean,
viewBindings?: any[],
changeDetection?: ChangeDetectionStrategy,
@ -207,8 +209,10 @@ export interface ComponentFactory {
properties?: string[],
events?: string[],
host?: StringMap<string, string>,
dynamicLoadable?: boolean,
bindings?: any[],
exportAs?: string,
moduleId?: string,
compileChildren?: boolean,
viewBindings?: any[],
changeDetection?: ChangeDetectionStrategy,

View File

@ -1,4 +1,4 @@
import {isPresent, CONST, CONST_EXPR} from 'angular2/src/core/facade/lang';
import {isPresent, CONST, CONST_EXPR, Type} from 'angular2/src/core/facade/lang';
import {InjectableMetadata} from 'angular2/src/core/di/metadata';
import {ChangeDetectionStrategy} from 'angular2/src/core/change_detection';
@ -699,8 +699,29 @@ export class DirectiveMetadata extends InjectableMetadata {
*/
exportAs: string;
/**
* The module id of the module that contains the directive.
* Needed to be able to resolve relative urls for templates and styles.
* In Dart, this can be determined automatically and does not need to be set.
* In CommonJS, this can always be set to `module.id`.
*
* ## Simple Example
*
* ```
* @Directive({
* selector: 'someDir',
* moduleId: module.id
* })
* class SomeDir {
* }
*
* ```
*/
moduleId: string;
constructor({
selector, properties, events, host, bindings, exportAs, compileChildren = true,
selector, properties, events, host, bindings, exportAs, moduleId,
compileChildren = true,
}: {
selector?: string,
properties?: string[],
@ -708,6 +729,7 @@ export class DirectiveMetadata extends InjectableMetadata {
host?: StringMap<string, string>,
bindings?: any[],
exportAs?: string,
moduleId?: string,
compileChildren?: boolean,
} = {}) {
super();
@ -716,6 +738,7 @@ export class DirectiveMetadata extends InjectableMetadata {
this.events = events;
this.host = host;
this.exportAs = exportAs;
this.moduleId = moduleId;
this.compileChildren = compileChildren;
this.bindings = bindings;
}
@ -764,6 +787,34 @@ 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;
/**
* Used by build tools to store the compiled template.
* Not intended to be used by a user.
*/
compiledHostTemplate: /* CompiledTemplate */ any;
/**
* Defines the used change detection strategy.
*
@ -817,14 +868,18 @@ export class ComponentMetadata extends DirectiveMetadata {
*/
viewBindings: any[];
constructor({selector, properties, events, host, exportAs, bindings, viewBindings,
changeDetection = ChangeDetectionStrategy.Default, compileChildren = true}: {
constructor({selector, properties, events, host, dynamicLoadable, compiledHostTemplate, exportAs,
moduleId, bindings, viewBindings, changeDetection = ChangeDetectionStrategy.Default,
compileChildren = true}: {
selector?: string,
properties?: string[],
events?: string[],
host?: StringMap<string, string>,
dynamicLoadable?: boolean,
compiledHostTemplate?: any,
bindings?: any[],
exportAs?: string,
moduleId?: string,
compileChildren?: boolean,
viewBindings?: any[],
changeDetection?: ChangeDetectionStrategy,
@ -835,12 +890,15 @@ export class ComponentMetadata extends DirectiveMetadata {
events: events,
host: host,
exportAs: exportAs,
moduleId: moduleId,
bindings: bindings,
compileChildren: compileChildren
});
this.changeDetection = changeDetection;
this.viewBindings = viewBindings;
this.dynamicLoadable = dynamicLoadable;
this.compiledHostTemplate = compiledHostTemplate;
}
}

View File

@ -11,5 +11,8 @@ export interface PlatformReflectionCapabilities {
getter(name: string): GetterFn;
setter(name: string): SetterFn;
method(name: string): MethodFn;
// TODO(tbosch): remove this method after the new compiler is done
// (and ComponentUrlMapper as well).
importUri(type: Type): string;
moduleId(type: Type): string;
}

View File

@ -44,6 +44,8 @@ class NoReflectionCapabilities implements PlatformReflectionCapabilities {
}
String importUri(Type type) => './';
String moduleId(Type type) => null;
}
final Reflector reflector = new Reflector(new NoReflectionCapabilities());

View File

@ -5,6 +5,8 @@ import 'types.dart';
import 'dart:mirrors';
import 'platform_reflection_capabilities.dart';
var DOT_REGEX = new RegExp('\\.');
class ReflectionCapabilities implements PlatformReflectionCapabilities {
ReflectionCapabilities([metadataReader]) {}
@ -315,4 +317,8 @@ class ReflectionCapabilities implements PlatformReflectionCapabilities {
String importUri(Type type) {
return '${(reflectClass(type).owner as LibraryMirror).uri}';
}
String moduleId(Type type) {
return '${MirrorSystem.getName((reflectClass(type).owner as LibraryMirror).qualifiedName).replaceAll(DOT_REGEX, "/")}';
}
}

View File

@ -168,4 +168,6 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
// There is not a concept of import uri in Js, but this is useful in developing Dart applications.
importUri(type: Type): string { return './'; }
moduleId(type: Type): string { return null; }
}

View File

@ -156,6 +156,8 @@ export class Reflector {
_containsReflectionInfo(typeOrFunc) { return this._injectableInfo.has(typeOrFunc); }
importUri(type: Type): string { return this.reflectionCapabilities.importUri(type); }
moduleId(type: Type): string { return this.reflectionCapabilities.moduleId(type); }
}
function _mergeMaps(target: Map<any, any>, config: StringMap<string, Function>): void {

View File

@ -409,7 +409,7 @@ export interface RenderBeginElementCmd extends RenderBeginCmd {
export interface RenderBeginComponentCmd extends RenderBeginElementCmd {
nativeShadow: boolean;
templateId: string;
templateId: number;
}
export interface RenderEmbeddedTemplateCmd extends RenderBeginElementCmd {