refactor(compiler): don’t require `id` in metadata and use `appId`

The output of the compiler has to be the same
given the same input. Requiring a unique id for
every type already during compilation makes it
hard to parallelize compilation.

Part of #3605
Closes #4397
This commit is contained in:
Tobias Bosch 2015-09-28 10:30:33 -07:00
parent cd0e9c9cd4
commit 8ff65a30c7
13 changed files with 327 additions and 186 deletions

View File

@ -8,7 +8,8 @@ import {
endElement,
beginComponent,
endComponent,
embeddedTemplate
embeddedTemplate,
CompiledTemplate
} from 'angular2/src/core/compiler/template_commands';
import {
TemplateAst,
@ -30,7 +31,12 @@ import {CompileTypeMetadata, CompileDirectiveMetadata} from './directive_metadat
import {SourceExpressions, SourceExpression, moduleRef} from './source_module';
import {ViewEncapsulation} from 'angular2/src/core/render/api';
import {shimHostAttribute, shimContentAttribute} from './style_compiler';
import {
shimHostAttribute,
shimContentAttribute,
shimContentAttributeExpr,
shimHostAttributeExpr
} from './style_compiler';
import {escapeSingleQuoteString} from './util';
import {Injectable} from 'angular2/src/core/di';
@ -40,21 +46,25 @@ const IMPLICIT_TEMPLATE_VAR = '\$implicit';
@Injectable()
export class CommandCompiler {
compileComponentRuntime(component: CompileDirectiveMetadata, template: TemplateAst[],
changeDetectorFactories: Function[],
compileComponentRuntime(component: CompileDirectiveMetadata, appId: string, templateId: number,
template: TemplateAst[], changeDetectorFactories: Function[],
componentTemplateFactory: Function): TemplateCmd[] {
var visitor = new CommandBuilderVisitor(
new RuntimeCommandFactory(componentTemplateFactory, changeDetectorFactories), component, 0);
new RuntimeCommandFactory(component, appId, templateId, componentTemplateFactory,
changeDetectorFactories),
0);
templateVisitAll(visitor, template);
return visitor.result;
}
compileComponentCodeGen(component: CompileDirectiveMetadata, template: TemplateAst[],
compileComponentCodeGen(component: CompileDirectiveMetadata, appIdExpr: string,
templateIdExpr: string, template: TemplateAst[],
changeDetectorFactoryExpressions: string[],
componentTemplateFactory: Function): SourceExpression {
var visitor = new CommandBuilderVisitor(
new CodegenCommandFactory(componentTemplateFactory, changeDetectorFactoryExpressions),
component, 0);
new CodegenCommandFactory(component, appIdExpr, templateIdExpr, componentTemplateFactory,
changeDetectorFactoryExpressions),
0);
templateVisitAll(visitor, template);
var source = `[${visitor.result.join(',')}]`;
return new SourceExpression([], source);
@ -78,11 +88,27 @@ interface CommandFactory<R> {
}
class RuntimeCommandFactory implements CommandFactory<TemplateCmd> {
constructor(public componentTemplateFactory: Function,
public changeDetectorFactories: Function[]) {}
constructor(private component: CompileDirectiveMetadata, private appId: string,
private templateId: number, private componentTemplateFactory: Function,
private changeDetectorFactories: Function[]) {}
private _mapDirectives(directives: CompileDirectiveMetadata[]): Type[] {
return directives.map(directive => directive.type.runtime);
}
private _addStyleShimAttributes(attrNameAndValues: string[],
localComponent: CompileDirectiveMetadata,
localTemplateId: number): string[] {
var additionalStyles = [];
if (isPresent(localComponent) &&
localComponent.template.encapsulation === ViewEncapsulation.Emulated) {
additionalStyles.push(shimHostAttribute(this.appId, localTemplateId));
additionalStyles.push('');
}
if (this.component.template.encapsulation === ViewEncapsulation.Emulated) {
additionalStyles.push(shimContentAttribute(this.appId, this.templateId));
additionalStyles.push('');
}
return additionalStyles.concat(attrNameAndValues);
}
createText(value: string, isBound: boolean, ngContentIndex: number): TemplateCmd {
return text(value, isBound, ngContentIndex);
@ -91,16 +117,19 @@ class RuntimeCommandFactory implements CommandFactory<TemplateCmd> {
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
isBound: boolean, ngContentIndex: number): TemplateCmd {
return beginElement(name, attrNameAndValues, eventTargetAndNames, variableNameAndValues,
this._mapDirectives(directives), isBound, ngContentIndex);
return beginElement(name, this._addStyleShimAttributes(attrNameAndValues, null, null),
eventTargetAndNames, variableNameAndValues, this._mapDirectives(directives),
isBound, ngContentIndex);
}
createEndElement(): TemplateCmd { return endElement(); }
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
nativeShadow: boolean, ngContentIndex: number): TemplateCmd {
return beginComponent(name, attrNameAndValues, eventTargetAndNames, variableNameAndValues,
this._mapDirectives(directives), nativeShadow, ngContentIndex,
this.componentTemplateFactory(directives[0]));
var nestedTemplate = this.componentTemplateFactory(directives[0]);
return beginComponent(
name, this._addStyleShimAttributes(attrNameAndValues, directives[0], nestedTemplate.id),
eventTargetAndNames, variableNameAndValues, this._mapDirectives(directives), nativeShadow,
ngContentIndex, nestedTemplate);
}
createEndComponent(): TemplateCmd { return endComponent(); }
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
@ -113,21 +142,28 @@ class RuntimeCommandFactory implements CommandFactory<TemplateCmd> {
}
}
function escapePrimitiveArray(data: any[]): string {
return `[${data.map( (value) => {
if (isString(value)) {
return escapeSingleQuoteString(value);
} else if (isBlank(value)) {
return 'null';
} else {
return value;
}
}).join(',')}]`;
}
class CodegenCommandFactory implements CommandFactory<string> {
constructor(public componentTemplateFactory: Function,
public changeDetectorFactoryExpressions: string[]) {}
constructor(private component: CompileDirectiveMetadata, private appIdExpr: string,
private templateIdExpr: string, private componentTemplateFactory: Function,
private changeDetectorFactoryExpressions: string[]) {}
private _addStyleShimAttributes(attrNameAndValues: string[],
localComponent: CompileDirectiveMetadata,
localTemplateIdExpr: string): any[] {
var additionalStlyes = [];
if (isPresent(localComponent) &&
localComponent.template.encapsulation === ViewEncapsulation.Emulated) {
additionalStlyes.push(
new Expression(shimHostAttributeExpr(this.appIdExpr, localTemplateIdExpr)));
additionalStlyes.push('');
}
if (this.component.template.encapsulation === ViewEncapsulation.Emulated) {
additionalStlyes.push(
new Expression(shimContentAttributeExpr(this.appIdExpr, this.templateIdExpr)));
additionalStlyes.push('');
}
return additionalStlyes.concat(attrNameAndValues);
}
createText(value: string, isBound: boolean, ngContentIndex: number): string {
return `${TEMPLATE_COMMANDS_MODULE_REF}text(${escapeSingleQuoteString(value)}, ${isBound}, ${ngContentIndex})`;
@ -138,28 +174,27 @@ class CodegenCommandFactory implements CommandFactory<string> {
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
isBound: boolean, ngContentIndex: number): string {
return `${TEMPLATE_COMMANDS_MODULE_REF}beginElement(${escapeSingleQuoteString(name)}, ${escapePrimitiveArray(attrNameAndValues)}, ${escapePrimitiveArray(eventTargetAndNames)}, ${escapePrimitiveArray(variableNameAndValues)}, [${_escapeDirectives(directives).join(',')}], ${isBound}, ${ngContentIndex})`;
var attrsExpression = codeGenArray(this._addStyleShimAttributes(attrNameAndValues, null, null));
return `${TEMPLATE_COMMANDS_MODULE_REF}beginElement(${escapeSingleQuoteString(name)}, ${attrsExpression}, ${codeGenArray(eventTargetAndNames)}, ${codeGenArray(variableNameAndValues)}, ${codeGenDirectivesArray(directives)}, ${isBound}, ${ngContentIndex})`;
}
createEndElement(): string { return `${TEMPLATE_COMMANDS_MODULE_REF}endElement()`; }
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
nativeShadow: boolean, ngContentIndex: number): string {
return `${TEMPLATE_COMMANDS_MODULE_REF}beginComponent(${escapeSingleQuoteString(name)}, ${escapePrimitiveArray(attrNameAndValues)}, ${escapePrimitiveArray(eventTargetAndNames)}, ${escapePrimitiveArray(variableNameAndValues)}, [${_escapeDirectives(directives).join(',')}], ${nativeShadow}, ${ngContentIndex}, ${this.componentTemplateFactory(directives[0])})`;
var nestedCompExpr = this.componentTemplateFactory(directives[0]);
var attrsExpression = codeGenArray(
this._addStyleShimAttributes(attrNameAndValues, directives[0], `${nestedCompExpr}.id`));
return `${TEMPLATE_COMMANDS_MODULE_REF}beginComponent(${escapeSingleQuoteString(name)}, ${attrsExpression}, ${codeGenArray(eventTargetAndNames)}, ${codeGenArray(variableNameAndValues)}, ${codeGenDirectivesArray(directives)}, ${nativeShadow}, ${ngContentIndex}, ${nestedCompExpr})`;
}
createEndComponent(): string { return `${TEMPLATE_COMMANDS_MODULE_REF}endComponent()`; }
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
isMerged: boolean, ngContentIndex: number, children: string[]): string {
return `${TEMPLATE_COMMANDS_MODULE_REF}embeddedTemplate(${escapePrimitiveArray(attrNameAndValues)}, ${escapePrimitiveArray(variableNameAndValues)}, ` +
`[${_escapeDirectives(directives).join(',')}], ${isMerged}, ${ngContentIndex}, ${this.changeDetectorFactoryExpressions[embeddedTemplateIndex]}, [${children.join(',')}])`;
return `${TEMPLATE_COMMANDS_MODULE_REF}embeddedTemplate(${codeGenArray(attrNameAndValues)}, ${codeGenArray(variableNameAndValues)}, ` +
`${codeGenDirectivesArray(directives)}, ${isMerged}, ${ngContentIndex}, ${this.changeDetectorFactoryExpressions[embeddedTemplateIndex]}, [${children.join(',')}])`;
}
}
function _escapeDirectives(directives: CompileDirectiveMetadata[]): string[] {
return directives.map(directiveType =>
`${moduleRef(directiveType.type.moduleId)}${directiveType.type.name}`);
}
function visitAndReturnContext(visitor: TemplateAstVisitor, asts: TemplateAst[], context: any):
any {
templateVisitAll(visitor, asts, context);
@ -169,22 +204,11 @@ function visitAndReturnContext(visitor: TemplateAstVisitor, asts: TemplateAst[],
class CommandBuilderVisitor<R> implements TemplateAstVisitor {
result: R[] = [];
transitiveNgContentCount: number = 0;
constructor(public commandFactory: CommandFactory<R>, public component: CompileDirectiveMetadata,
public embeddedTemplateIndex: number) {}
constructor(public commandFactory: CommandFactory<R>, public embeddedTemplateIndex: number) {}
private _readAttrNameAndValues(localComponent: CompileDirectiveMetadata,
directives: CompileDirectiveMetadata[],
private _readAttrNameAndValues(directives: CompileDirectiveMetadata[],
attrAsts: TemplateAst[]): string[] {
var attrNameAndValues: string[] = visitAndReturnContext(this, attrAsts, []);
if (isPresent(localComponent) &&
localComponent.template.encapsulation === ViewEncapsulation.Emulated) {
attrNameAndValues.push(shimHostAttribute(localComponent.type.id));
attrNameAndValues.push('');
}
if (this.component.template.encapsulation === ViewEncapsulation.Emulated) {
attrNameAndValues.push(shimContentAttribute(this.component.type.id));
attrNameAndValues.push('');
}
directives.forEach(directiveMeta => {
StringMapWrapper.forEach(directiveMeta.hostAttributes, (value, name) => {
attrNameAndValues.push(name);
@ -201,8 +225,7 @@ class CommandBuilderVisitor<R> implements TemplateAstVisitor {
}
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any {
this.embeddedTemplateIndex++;
var childVisitor =
new CommandBuilderVisitor(this.commandFactory, this.component, this.embeddedTemplateIndex);
var childVisitor = new CommandBuilderVisitor(this.commandFactory, this.embeddedTemplateIndex);
templateVisitAll(childVisitor, ast.children);
var isMerged = childVisitor.transitiveNgContentCount > 0;
var variableNameAndValues = [];
@ -215,7 +238,7 @@ class CommandBuilderVisitor<R> implements TemplateAstVisitor {
directiveAst.visit(this, new DirectiveContext(index, [], [], directives));
});
this.result.push(this.commandFactory.createEmbeddedTemplate(
this.embeddedTemplateIndex, this._readAttrNameAndValues(null, directives, ast.attrs),
this.embeddedTemplateIndex, this._readAttrNameAndValues(directives, ast.attrs),
variableNameAndValues, directives, isMerged, ast.ngContentIndex, childVisitor.result));
this.transitiveNgContentCount += childVisitor.transitiveNgContentCount;
this.embeddedTemplateIndex = childVisitor.embeddedTemplateIndex;
@ -238,7 +261,7 @@ class CommandBuilderVisitor<R> implements TemplateAstVisitor {
});
eventTargetAndNames = removeKeyValueArrayDuplicates(eventTargetAndNames);
var attrNameAndValues = this._readAttrNameAndValues(component, directives, ast.attrs);
var attrNameAndValues = this._readAttrNameAndValues(directives, ast.attrs);
if (isPresent(component)) {
this.result.push(this.commandFactory.createBeginComponent(
ast.name, attrNameAndValues, eventTargetAndNames, variableNameAndValues, directives,
@ -306,4 +329,30 @@ class DirectiveContext {
constructor(public index: number, public eventTargetAndNames: string[],
public targetVariableNameAndValues: any[],
public targetDirectives: CompileDirectiveMetadata[]) {}
}
}
class Expression {
constructor(public value: string) {}
}
function escapeValue(value: any): string {
if (value instanceof Expression) {
return value.value;
} else if (isString(value)) {
return escapeSingleQuoteString(value);
} else if (isBlank(value)) {
return 'null';
} else {
return `${value}`;
}
}
function codeGenArray(data: any[]): string {
return `[${data.map(escapeValue).join(',')}]`;
}
function codeGenDirectivesArray(directives: CompileDirectiveMetadata[]): string {
var expressions = directives.map(
directiveType => `${moduleRef(directiveType.type.moduleId)}${directiveType.type.name}`);
return `[${expressions.join(',')}]`;
}

View File

@ -22,27 +22,22 @@ import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/compiler
var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g;
export class CompileTypeMetadata {
id: number;
runtime: Type;
name: string;
moduleId: string;
constructor({id, runtime, name, moduleId}:
{id?: number, runtime?: Type, name?: string, moduleId?: string} = {}) {
this.id = id;
constructor({runtime, name, moduleId}: {runtime?: Type, name?: string, moduleId?: string} = {}) {
this.runtime = runtime;
this.name = name;
this.moduleId = moduleId;
}
static fromJson(data: StringMap<string, any>): CompileTypeMetadata {
return new CompileTypeMetadata(
{id: data['id'], name: data['name'], moduleId: data['moduleId']});
return new CompileTypeMetadata({name: data['name'], moduleId: data['moduleId']});
}
toJson(): StringMap<string, any> {
return {
// Note: Runtime type can't be serialized...
'id': this.id,
'name': this.name,
'moduleId': this.moduleId
};
@ -253,12 +248,8 @@ export function createHostComponentMeta(componentType: CompileTypeMetadata,
componentSelector: string): CompileDirectiveMetadata {
var template = CssSelector.parse(componentSelector)[0].getMatchingElementTemplate();
return CompileDirectiveMetadata.create({
type: new CompileTypeMetadata({
runtime: Object,
id: (componentType.id * -1) - 1,
name: `Host${componentType.name}`,
moduleId: componentType.moduleId
}),
type: new CompileTypeMetadata(
{runtime: Object, name: `Host${componentType.name}`, moduleId: componentType.moduleId}),
template: new CompileTemplateMetadata(
{template: template, templateUrl: '', styles: [], styleUrls: [], ngContentSelectors: []}),
changeDetection: ChangeDetectionStrategy.Default,

View File

@ -25,7 +25,6 @@ var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g;
@Injectable()
export class RuntimeMetadataResolver {
private _directiveCounter = 0;
private _cache: Map<Type, cpl.CompileDirectiveMetadata> = new Map();
constructor(private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver) {}
@ -55,12 +54,8 @@ export class RuntimeMetadataResolver {
exportAs: directiveAnnotation.exportAs,
isComponent: isPresent(templateMeta),
dynamicLoadable: true,
type: new cpl.CompileTypeMetadata({
id: this._directiveCounter++,
name: stringify(directiveType),
moduleId: moduleId,
runtime: directiveType
}),
type: new cpl.CompileTypeMetadata(
{name: stringify(directiveType), moduleId: moduleId, runtime: directiveType}),
template: templateMeta,
changeDetection: changeDetectionStrategy,
properties: directiveAnnotation.properties,
@ -89,8 +84,8 @@ export class RuntimeMetadataResolver {
function removeDuplicatedDirectives(directives: cpl.CompileDirectiveMetadata[]):
cpl.CompileDirectiveMetadata[] {
var directivesMap: Map<number, cpl.CompileDirectiveMetadata> = new Map();
directives.forEach((dirMeta) => { directivesMap.set(dirMeta.type.id, dirMeta); });
var directivesMap: Map<Type, cpl.CompileDirectiveMetadata> = new Map();
directives.forEach((dirMeta) => { directivesMap.set(dirMeta.type.runtime, dirMeta); });
return MapWrapper.values(directivesMap);
}

View File

@ -13,14 +13,17 @@ import {
codeGenConcatArray,
codeGenMapArray,
codeGenReplaceAll,
codeGenExportVariable
codeGenExportVariable,
codeGenToString
} from './util';
import {Injectable} from 'angular2/src/core/di';
const COMPONENT_VARIABLE = '%COMP%';
var COMPONENT_REGEX = /%COMP%/g;
const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
const HOST_ATTR_EXPR = `'_nghost-'+${COMPONENT_VARIABLE}`;
const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
const CONTENT_ATTR_EXPR = `'_ngcontent-'+${COMPONENT_VARIABLE}`;
@Injectable()
export class StyleCompiler {
@ -29,24 +32,24 @@ export class StyleCompiler {
constructor(private _xhr: XHR, private _urlResolver: UrlResolver) {}
compileComponentRuntime(type: CompileTypeMetadata,
compileComponentRuntime(appId: string, templateId: number,
template: CompileTemplateMetadata): Promise<string[]> {
var styles = template.styles;
var styleAbsUrls = template.styleUrls;
return this._loadStyles(styles, styleAbsUrls,
template.encapsulation === ViewEncapsulation.Emulated)
.then(styles => styles.map(
style => StringWrapper.replaceAll(style, COMPONENT_REGEX, `${type.id}`)));
.then(styles => styles.map(style => StringWrapper.replaceAll(
style, COMPONENT_REGEX, componentId(appId, templateId))));
}
compileComponentCodeGen(type: CompileTypeMetadata,
compileComponentCodeGen(appIdExpression: string, templateIdExpression: string,
template: CompileTemplateMetadata): SourceExpression {
var shim = template.encapsulation === ViewEncapsulation.Emulated;
var suffix;
if (shim) {
var componentId = `${ type.id}`;
suffix =
codeGenMapArray(['style'], `style${codeGenReplaceAll(COMPONENT_VARIABLE, componentId)}`);
suffix = codeGenMapArray(
['style'],
`style${codeGenReplaceAll(COMPONENT_VARIABLE, componentIdExpression(appIdExpression, templateIdExpression))}`);
} else {
suffix = '';
}
@ -118,10 +121,28 @@ export class StyleCompiler {
}
}
export function shimContentAttribute(componentId: number): string {
return StringWrapper.replaceAll(CONTENT_ATTR, COMPONENT_REGEX, `${componentId}`);
export function shimContentAttribute(appId: string, templateId: number): string {
return StringWrapper.replaceAll(CONTENT_ATTR, COMPONENT_REGEX, componentId(appId, templateId));
}
export function shimHostAttribute(componentId: number): string {
return StringWrapper.replaceAll(HOST_ATTR, COMPONENT_REGEX, `${componentId}`);
export function shimContentAttributeExpr(appIdExpr: string, templateIdExpr: string): string {
return StringWrapper.replaceAll(CONTENT_ATTR_EXPR, COMPONENT_REGEX,
componentIdExpression(appIdExpr, templateIdExpr));
}
export function shimHostAttribute(appId: string, templateId: number): string {
return StringWrapper.replaceAll(HOST_ATTR, COMPONENT_REGEX, componentId(appId, templateId));
}
export function shimHostAttributeExpr(appIdExpr: string, templateIdExpr: string): string {
return StringWrapper.replaceAll(HOST_ATTR_EXPR, COMPONENT_REGEX,
componentIdExpression(appIdExpr, templateIdExpr));
}
function componentId(appId: string, templateId: number): string {
return `${appId}-${templateId}`;
}
function componentIdExpression(appIdExpression: string, templateIdExpression: string): string {
return `${appIdExpression}+'-'+${codeGenToString(templateIdExpression)}`;
}

View File

@ -2,7 +2,12 @@ import {Type, Json, isBlank, stringify} from 'angular2/src/core/facade/lang';
import {BaseException} from 'angular2/src/core/facade/exceptions';
import {ListWrapper, SetWrapper} from 'angular2/src/core/facade/collection';
import {PromiseWrapper, Promise} from 'angular2/src/core/facade/async';
import {CompiledTemplate, TemplateCmd} from 'angular2/src/core/compiler/template_commands';
import {
CompiledTemplate,
TemplateCmd,
nextTemplateId,
CompiledHostTemplate
} from 'angular2/src/core/compiler/template_commands';
import {
createHostComponentMeta,
CompileDirectiveMetadata,
@ -18,20 +23,26 @@ import {CommandCompiler} from './command_compiler';
import {TemplateParser} from './template_parser';
import {TemplateNormalizer} from './template_normalizer';
import {RuntimeMetadataResolver} from './runtime_metadata';
import {APP_ID} from 'angular2/src/core/render/dom/dom_tokens';
import {TEMPLATE_COMMANDS_MODULE_REF} from './command_compiler';
import {IS_DART, codeGenExportVariable, escapeSingleQuoteString, codeGenValueFn} from './util';
import {Inject} from 'angular2/src/core/di';
@Injectable()
export class TemplateCompiler {
private _compiledTemplateCache: Map<number, CompiledTemplate> = new Map();
private _compiledTemplateDone: Map<number, Promise<CompiledTemplate>> = new Map();
private _hostCacheKeys: Map<Type, any> = new Map();
private _compiledTemplateCache: Map<Type, CompiledTemplate> = new Map();
private _compiledTemplateDone: Map<Type, Promise<CompiledTemplate>> = new Map();
private _appId: string;
constructor(private _runtimeMetadataResolver: RuntimeMetadataResolver,
private _templateNormalizer: TemplateNormalizer,
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
private _commandCompiler: CommandCompiler,
private _cdCompiler: ChangeDetectionCompiler) {}
private _cdCompiler: ChangeDetectionCompiler, @Inject(APP_ID) appId: string) {
this._appId = appId;
}
normalizeDirectiveMetadata(directive:
CompileDirectiveMetadata): Promise<CompileDirectiveMetadata> {
@ -63,40 +74,49 @@ export class TemplateCompiler {
}));
}
compileHostComponentRuntime(type: Type): Promise<CompiledTemplate> {
var compMeta: CompileDirectiveMetadata = this._runtimeMetadataResolver.getMetadata(type);
assertComponent(compMeta);
var hostMeta: CompileDirectiveMetadata =
createHostComponentMeta(compMeta.type, compMeta.selector);
compileHostComponentRuntime(type: Type): Promise<CompiledHostTemplate> {
var hostCacheKey = this._hostCacheKeys.get(type);
if (isBlank(hostCacheKey)) {
hostCacheKey = new Object();
this._hostCacheKeys.set(type, hostCacheKey);
var compMeta: CompileDirectiveMetadata = this._runtimeMetadataResolver.getMetadata(type);
assertComponent(compMeta);
var hostMeta: CompileDirectiveMetadata =
createHostComponentMeta(compMeta.type, compMeta.selector);
this._compileComponentRuntime(hostMeta, [compMeta], new Set());
return this._compiledTemplateDone.get(hostMeta.type.id);
this._compileComponentRuntime(hostCacheKey, hostMeta, [compMeta], new Set());
}
return this._compiledTemplateDone.get(hostCacheKey)
.then(compiledTemplate => new CompiledHostTemplate(() => compiledTemplate));
}
clearCache() {
this._hostCacheKeys.clear();
this._styleCompiler.clearCache();
this._compiledTemplateCache.clear();
this._compiledTemplateDone.clear();
}
private _compileComponentRuntime(compMeta: CompileDirectiveMetadata,
private _compileComponentRuntime(cacheKey: any, compMeta: CompileDirectiveMetadata,
viewDirectives: CompileDirectiveMetadata[],
compilingComponentIds: Set<number>): CompiledTemplate {
var compiledTemplate = this._compiledTemplateCache.get(compMeta.type.id);
var done = this._compiledTemplateDone.get(compMeta.type.id);
compilingComponentCacheKeys: Set<any>): CompiledTemplate {
var compiledTemplate = this._compiledTemplateCache.get(cacheKey);
var done = this._compiledTemplateDone.get(cacheKey);
if (isBlank(compiledTemplate)) {
var styles;
var changeDetectorFactory;
var commands;
var templateId = nextTemplateId();
compiledTemplate =
new CompiledTemplate(compMeta.type.id, () => [changeDetectorFactory, commands, styles]);
this._compiledTemplateCache.set(compMeta.type.id, compiledTemplate);
compilingComponentIds.add(compMeta.type.id);
new CompiledTemplate(templateId, (_a, _b) => [changeDetectorFactory, commands, styles]);
this._compiledTemplateCache.set(cacheKey, compiledTemplate);
compilingComponentCacheKeys.add(cacheKey);
done =
PromiseWrapper
.all([
<any>this._styleCompiler.compileComponentRuntime(compMeta.type, compMeta.template)
].concat(viewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
PromiseWrapper.all([
<any>this._styleCompiler.compileComponentRuntime(this._appId, templateId,
compMeta.template)
].concat(viewDirectives.map(dirMeta =>
this.normalizeDirectiveMetadata(dirMeta))))
.then((stylesAndNormalizedViewDirMetas: any[]) => {
var childPromises = [];
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
@ -107,36 +127,38 @@ export class TemplateCompiler {
compMeta.type, compMeta.changeDetection, parsedTemplate);
changeDetectorFactory = changeDetectorFactories[0];
styles = stylesAndNormalizedViewDirMetas[0];
commands =
this._compileCommandsRuntime(compMeta, parsedTemplate, changeDetectorFactories,
compilingComponentIds, childPromises);
commands = this._compileCommandsRuntime(compMeta, templateId, parsedTemplate,
changeDetectorFactories,
compilingComponentCacheKeys, childPromises);
return PromiseWrapper.all(childPromises);
})
.then((_) => {
SetWrapper.delete(compilingComponentIds, compMeta.type.id);
SetWrapper.delete(compilingComponentCacheKeys, cacheKey);
return compiledTemplate;
});
this._compiledTemplateDone.set(compMeta.type.id, done);
this._compiledTemplateDone.set(cacheKey, done);
}
return compiledTemplate;
}
private _compileCommandsRuntime(compMeta: CompileDirectiveMetadata, parsedTemplate: TemplateAst[],
private _compileCommandsRuntime(compMeta: CompileDirectiveMetadata, templateId: number,
parsedTemplate: TemplateAst[],
changeDetectorFactories: Function[],
compilingComponentIds: Set<number>,
compilingComponentCacheKeys: Set<Type>,
childPromises: Promise<any>[]): TemplateCmd[] {
return this._commandCompiler.compileComponentRuntime(
compMeta, parsedTemplate, changeDetectorFactories,
compMeta, this._appId, templateId, parsedTemplate, changeDetectorFactories,
(childComponentDir: CompileDirectiveMetadata) => {
var childCacheKey = childComponentDir.type.runtime;
var childViewDirectives: CompileDirectiveMetadata[] =
this._runtimeMetadataResolver.getViewDirectivesMetadata(
childComponentDir.type.runtime);
var childIsRecursive = SetWrapper.has(compilingComponentIds, childComponentDir.type.id);
var childTemplate = this._compileComponentRuntime(childComponentDir, childViewDirectives,
compilingComponentIds);
var childIsRecursive = SetWrapper.has(compilingComponentCacheKeys, childCacheKey);
var childTemplate = this._compileComponentRuntime(
childCacheKey, childComponentDir, childViewDirectives, compilingComponentCacheKeys);
if (!childIsRecursive) {
// Only wait for a child if it is not a cycle
childPromises.push(this._compiledTemplateDone.get(childComponentDir.type.id));
childPromises.push(this._compiledTemplateDone.get(childCacheKey));
}
return childTemplate;
});
@ -147,24 +169,40 @@ export class TemplateCompiler {
var declarations = [];
var templateArguments = [];
var componentMetas: CompileDirectiveMetadata[] = [];
var isHost: boolean[] = [];
var templateIdVariable = 'templateId';
var appIdVariable = 'appId';
components.forEach(componentWithDirs => {
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
assertComponent(compMeta);
componentMetas.push(compMeta);
this._processTemplateCodeGen(compMeta,
isHost.push(false);
this._processTemplateCodeGen(compMeta, appIdVariable, templateIdVariable,
<CompileDirectiveMetadata[]>componentWithDirs.directives,
declarations, templateArguments);
if (compMeta.dynamicLoadable) {
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
componentMetas.push(hostMeta);
this._processTemplateCodeGen(hostMeta, [compMeta], declarations, templateArguments);
isHost.push(true);
this._processTemplateCodeGen(hostMeta, appIdVariable, templateIdVariable, [compMeta],
declarations, templateArguments);
}
});
ListWrapper.forEachWithIndex(componentMetas, (compMeta: CompileDirectiveMetadata,
index: number) => {
var templateDataFn = codeGenValueFn([], `[${(<any[]>templateArguments[index]).join(',')}]`);
var templateDataFn = codeGenValueFn([templateIdVariable, appIdVariable],
`[${(<any[]>templateArguments[index]).join(',')}]`);
var compiledTemplateExpr =
`new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledTemplate(${TEMPLATE_COMMANDS_MODULE_REF}nextTemplateId(),${templateDataFn})`;
var variableValueExpr;
if (isHost[index]) {
variableValueExpr =
`new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledHostTemplate(${codeGenValueFn([], compiledTemplateExpr)})`;
} else {
variableValueExpr = compiledTemplateExpr;
}
declarations.push(
`${codeGenExportVariable(templateVariableName(compMeta.type))}new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledTemplate(${compMeta.type.id},${templateDataFn});`);
`${codeGenExportVariable(templateVariableName(compMeta.type))}${variableValueExpr};`);
});
return new SourceModule(`${templateModuleName(moduleId)}`, declarations.join('\n'));
}
@ -173,16 +211,17 @@ export class TemplateCompiler {
return this._styleCompiler.compileStylesheetCodeGen(moduleId, cssText);
}
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata,
directives: CompileDirectiveMetadata[],
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata, appIdExpr: string,
templateIdExpr: string, directives: CompileDirectiveMetadata[],
targetDeclarations: string[], targetTemplateArguments: any[][]) {
var styleExpr = this._styleCompiler.compileComponentCodeGen(compMeta.type, compMeta.template);
var styleExpr =
this._styleCompiler.compileComponentCodeGen(appIdExpr, templateIdExpr, compMeta.template);
var parsedTemplate =
this._templateParser.parse(compMeta.template.template, directives, compMeta.type.name);
var changeDetectorsExprs = this._cdCompiler.compileComponentCodeGen(
compMeta.type, compMeta.changeDetection, parsedTemplate);
var commandsExpr = this._commandCompiler.compileComponentCodeGen(
compMeta, parsedTemplate, changeDetectorsExprs.expressions,
compMeta, appIdExpr, templateIdExpr, parsedTemplate, changeDetectorsExprs.expressions,
codeGenComponentTemplateFactory);
addAll(styleExpr.declarations, targetDeclarations);

View File

@ -95,7 +95,7 @@ export class TemplateParser {
class TemplateParseVisitor implements HtmlAstVisitor {
selectorMatcher: SelectorMatcher;
errors: string[] = [];
directivesIndexByTypeId: Map<number, number> = new Map();
directivesIndex: Map<CompileDirectiveMetadata, number> = new Map();
constructor(directives: CompileDirectiveMetadata[], private _exprParser: Parser,
private _schemaRegistry: ElementSchemaRegistry) {
this.selectorMatcher = new SelectorMatcher();
@ -103,7 +103,7 @@ class TemplateParseVisitor implements HtmlAstVisitor {
(directive: CompileDirectiveMetadata, index: number) => {
var selector = CssSelector.parse(directive.selector);
this.selectorMatcher.addSelectables(selector, directive);
this.directivesIndexByTypeId.set(directive.type.id, index);
this.directivesIndex.set(directive, index);
});
}
@ -397,8 +397,7 @@ class TemplateParseVisitor implements HtmlAstVisitor {
} else if (!dir1Comp && dir2Comp) {
return 1;
} else {
return this.directivesIndexByTypeId.get(dir1.type.id) -
this.directivesIndexByTypeId.get(dir2.type.id);
return this.directivesIndex.get(dir1) - this.directivesIndex.get(dir2);
}
});
return directives;

View File

@ -59,11 +59,11 @@ export function codeGenMapArray(argNames: string[], callback: string): string {
}
}
export function codeGenReplaceAll(pattern: string, value: string): string {
export function codeGenReplaceAll(pattern: string, expression: string): string {
if (IS_DART) {
return `.replaceAll('${pattern}', '${value}')`;
return `.replaceAll('${pattern}', ${expression})`;
} else {
return `.replace(/${pattern}/g, '${value}')`;
return `.replace(/${pattern}/g, ${expression})`;
}
}
@ -75,6 +75,14 @@ export function codeGenValueFn(params: string[], value: string): string {
}
}
export function codeGenToString(expr: string): string {
if (IS_DART) {
return `'\${${expr}}'`;
} else {
// JS automatically convets to string...
return expr;
}
}
export function splitAtColon(input: string, defaultValues: string[]): string[] {
var parts = StringWrapper.split(input.trim(), /\s*:\s*/g);

View File

@ -9,23 +9,48 @@ import {
RenderEmbeddedTemplateCmd
} from 'angular2/src/core/render/render';
var _nextTemplateId: number = 0;
export function nextTemplateId(): number {
return _nextTemplateId++;
}
/**
* A compiled template. This is const as we are storing it as annotation
* A compiled host template.
*
* This is const as we are storing it as annotation
* for the compiled component type.
*/
@CONST()
export class CompiledTemplate {
static getChangeDetectorFromData(data: any[]): Function { return data[0]; }
static getCommandsFromData(data: any[]): TemplateCmd[] { return data[1]; }
static getSylesFromData(data: any[]): string[] { return data[2]; }
export class CompiledHostTemplate {
// Note: _templateGetter is a function so that CompiledHostTemplate can be
// a const!
constructor(private _templateGetter: Function) {}
getTemplate(): CompiledTemplate { return this._templateGetter(); }
}
/**
* A compiled template.
*/
export class CompiledTemplate {
// Note: paramGetter is a function so that we can have cycles between templates!
// paramGetter returns a tuple with:
// - ChangeDetector factory function
// - TemplateCmd[]
// - styles
constructor(public id: number,
public dataGetter: /*()=>[Function, TemplateCmd[], string[]]*/ Function) {}
private _dataGetter: /*()=>Array<Function, TemplateCmd[], string[]>*/ Function) {}
getData(appId: string): CompiledTemplateData {
var data = this._dataGetter(appId, this.id);
return new CompiledTemplateData(data[0], data[1], data[2]);
}
}
export class CompiledTemplateData {
constructor(public changeDetectorFactory: Function, public commands: TemplateCmd[],
public styles: string[]) {}
}
const EMPTY_ARR = CONST_EXPR([]);

View File

@ -14,6 +14,7 @@ import {
} from 'angular2/test_lib';
import {CONST_EXPR, stringify, isType, Type, isBlank} from 'angular2/src/core/facade/lang';
import {MapWrapper} from 'angular2/src/core/facade/collection';
import {PromiseWrapper, Promise} from 'angular2/src/core/facade/async';
import {TemplateParser} from 'angular2/src/compiler/template_parser';
import {
@ -61,12 +62,15 @@ export class RootComp {}
export class SomeDir {}
export class AComp {}
var RootCompTypeMeta = new CompileTypeMetadata(
{id: 1, name: 'RootComp', runtime: RootComp, moduleId: THIS_MODULE_NAME});
var RootCompTypeMeta =
new CompileTypeMetadata({name: 'RootComp', runtime: RootComp, moduleId: THIS_MODULE_NAME});
var SomeDirTypeMeta =
new CompileTypeMetadata({id: 2, name: 'SomeDir', runtime: SomeDir, moduleId: THIS_MODULE_NAME});
new CompileTypeMetadata({name: 'SomeDir', runtime: SomeDir, moduleId: THIS_MODULE_NAME});
var ACompTypeMeta =
new CompileTypeMetadata({id: 3, name: 'AComp', runtime: AComp, moduleId: THIS_MODULE_NAME});
new CompileTypeMetadata({name: 'AComp', runtime: AComp, moduleId: THIS_MODULE_NAME});
var compTypeTemplateId: Map<CompileTypeMetadata, number> =
MapWrapper.createFromPairs([[RootCompTypeMeta, 1], [SomeDirTypeMeta, 2], [ACompTypeMeta, 3]]);
const APP_ID = 'app1';
var NESTED_COMPONENT = new CompiledTemplate(45, () => []);
@ -221,7 +225,7 @@ export function main() {
run(rootComp, [])
.then((data) => {
expect(data).toEqual([
[BEGIN_ELEMENT, 'div', ['_ngcontent-1', ''], [], [], [], false, null],
[BEGIN_ELEMENT, 'div', ['_ngcontent-app1-1', ''], [], [], [], false, null],
[END_ELEMENT]
]);
async.done();
@ -283,7 +287,7 @@ export function main() {
[
BEGIN_COMPONENT,
'a',
['_nghost-3', '', '_ngcontent-1', ''],
['_nghost-app1-3', '', '_ngcontent-app1-1', ''],
[],
[],
['ACompType'],
@ -424,7 +428,7 @@ export function main() {
describe('compileComponentRuntime', () => {
beforeEach(() => {
componentTemplateFactory = (directive: CompileDirectiveMetadata) => {
return new CompiledTemplate(directive.type.id, () => []);
return new CompiledTemplate(compTypeTemplateId.get(directive.type), () => []);
};
});
@ -437,7 +441,8 @@ export function main() {
var parsedTemplate =
parser.parse(component.template.template, directives, component.type.name);
var commands = commandCompiler.compileComponentRuntime(
component, parsedTemplate, changeDetectorFactories, componentTemplateFactory);
component, APP_ID, compTypeTemplateId.get(component.type), parsedTemplate,
changeDetectorFactories, componentTemplateFactory);
return PromiseWrapper.resolve(humanize(commands));
}
@ -448,7 +453,7 @@ export function main() {
describe('compileComponentCodeGen', () => {
beforeEach(() => {
componentTemplateFactory = (directive: CompileDirectiveMetadata) => {
return `new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledTemplate(${directive.type.id}, ${codeGenValueFn([], '{}')})`;
return `new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledTemplate(${compTypeTemplateId.get(directive.type)}, ${codeGenValueFn([], '{}')})`;
};
});
@ -461,7 +466,8 @@ export function main() {
var parsedTemplate =
parser.parse(component.template.template, directives, component.type.name);
var sourceModule = commandCompiler.compileComponentCodeGen(
component, parsedTemplate, changeDetectorFactoryExpressions, componentTemplateFactory);
component, `'${APP_ID}'`, `${compTypeTemplateId.get(component.type)}`, parsedTemplate,
changeDetectorFactoryExpressions, componentTemplateFactory);
var testableModule = createTestableModule(sourceModule).getSourceWithImports();
return evalModule(testableModule.source, testableModule.imports, null);
}

View File

@ -28,7 +28,7 @@ export function main() {
var fullDirectiveMeta: CompileDirectiveMetadata;
beforeEach(() => {
fullTypeMeta = new CompileTypeMetadata({id: 23, name: 'SomeType', moduleId: 'someUrl'});
fullTypeMeta = new CompileTypeMetadata({name: 'SomeType', moduleId: 'someUrl'});
fullTemplateMeta = new CompileTemplateMetadata({
encapsulation: ViewEncapsulation.Emulated,
template: '<a></a>',

View File

@ -42,7 +42,8 @@ const IMPORT_ABS_MODULE_NAME_WITH_IMPORT =
export function main() {
describe('StyleCompiler', () => {
var xhr: SpyXHR;
var typeMeta;
var templateId;
var appId;
beforeEachBindings(() => {
xhr = <any>new SpyXHR();
@ -52,7 +53,8 @@ export function main() {
var compiler: StyleCompiler;
beforeEach(inject([StyleCompiler], (_compiler) => {
typeMeta = new CompileTypeMetadata({id: 23, moduleId: 'someUrl'});
templateId = 23;
appId = 'app1';
compiler = _compiler;
}));
@ -81,8 +83,9 @@ export function main() {
return PromiseWrapper.resolve(response);
});
return compiler.compileComponentRuntime(
typeMeta, new CompileTemplateMetadata(
{styles: styles, styleUrls: styleAbsUrls, encapsulation: encapsulation}));
appId, templateId,
new CompileTemplateMetadata(
{styles: styles, styleUrls: styleAbsUrls, encapsulation: encapsulation}));
}
describe('no shim', () => {
@ -121,8 +124,8 @@ export function main() {
compile(['div {\ncolor: red;\n}', 'span {\ncolor: blue;\n}'], [], encapsulation)
.then(styles => {
compareStyles(styles, [
'div[_ngcontent-23] {\ncolor: red;\n}',
'span[_ngcontent-23] {\ncolor: blue;\n}'
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
'span[_ngcontent-app1-23] {\ncolor: blue;\n}'
]);
async.done();
});
@ -132,8 +135,8 @@ export function main() {
compile(['div {\ncolor: red;\n}'], [IMPORT_ABS_MODULE_NAME], encapsulation)
.then(styles => {
compareStyles(styles, [
'div[_ngcontent-23] {\ncolor: red;\n}',
'span[_ngcontent-23] {\ncolor: blue;\n}'
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
'span[_ngcontent-app1-23] {\ncolor: blue;\n}'
]);
async.done();
});
@ -143,9 +146,9 @@ export function main() {
compile(['div {\ncolor: red;\n}'], [IMPORT_ABS_MODULE_NAME_WITH_IMPORT], encapsulation)
.then(styles => {
compareStyles(styles, [
'div[_ngcontent-23] {\ncolor: red;\n}',
'a[_ngcontent-23] {\ncolor: green;\n}',
'span[_ngcontent-23] {\ncolor: blue;\n}'
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
'a[_ngcontent-app1-23] {\ncolor: green;\n}',
'span[_ngcontent-app1-23] {\ncolor: blue;\n}'
]);
async.done();
});
@ -198,8 +201,9 @@ export function main() {
function compile(styles: string[], styleAbsUrls: string[], encapsulation: ViewEncapsulation):
Promise<string[]> {
var sourceExpression = compiler.compileComponentCodeGen(
typeMeta, new CompileTemplateMetadata(
{styles: styles, styleUrls: styleAbsUrls, encapsulation: encapsulation}));
`'${appId}'`, `${templateId}`,
new CompileTemplateMetadata(
{styles: styles, styleUrls: styleAbsUrls, encapsulation: encapsulation}));
var sourceWithImports = testableExpression(sourceExpression).getSourceWithImports();
return evalModule(sourceWithImports.source, sourceWithImports.imports, null);
};
@ -207,7 +211,7 @@ export function main() {
describe('no shim', () => {
var encapsulation = ViewEncapsulation.None;
it('should compile plain css ruless', inject([AsyncTestCompleter], (async) => {
it('should compile plain css rules', inject([AsyncTestCompleter], (async) => {
compile(['div {color: red}', 'span {color: blue}'], [], encapsulation)
.then(styles => {
expect(styles).toEqual(['div {color: red}', 'span {color: blue}']);
@ -240,8 +244,8 @@ export function main() {
compile(['div {\ncolor: red;\n}', 'span {\ncolor: blue;\n}'], [], encapsulation)
.then(styles => {
compareStyles(styles, [
'div[_ngcontent-23] {\ncolor: red;\n}',
'span[_ngcontent-23] {\ncolor: blue;\n}'
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
'span[_ngcontent-app1-23] {\ncolor: blue;\n}'
]);
async.done();
});
@ -251,8 +255,8 @@ export function main() {
compile(['div {color: red}'], [IMPORT_ABS_MODULE_NAME], encapsulation)
.then(styles => {
compareStyles(styles, [
'div[_ngcontent-23] {\ncolor: red;\n}',
'span[_ngcontent-23] {\ncolor: blue;\n}'
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
'span[_ngcontent-app1-23] {\ncolor: blue;\n}'
]);
async.done();
});

View File

@ -41,22 +41,25 @@ import {
CompiledTemplate
} from 'angular2/src/core/compiler/template_commands';
import {Component, View, Directive} from 'angular2/core';
import {Component, View, Directive, bind} from 'angular2/core';
import {TEST_BINDINGS} from './test_bindings';
import {TestContext, TestDispatcher, TestPipes} from './change_detector_mocks';
import {codeGenValueFn, codeGenExportVariable} from 'angular2/src/compiler/util';
import {APP_ID} from 'angular2/src/core/render/dom/dom_tokens';
// Attention: This path has to point to this test file!
const THIS_MODULE = 'angular2/test/compiler/template_compiler_spec';
var THIS_MODULE_REF = moduleRef(THIS_MODULE);
const APP_ID_VALUE = 'app1';
export function main() {
describe('TemplateCompiler', () => {
var compiler: TemplateCompiler;
var runtimeMetadataResolver: RuntimeMetadataResolver;
beforeEachBindings(() => TEST_BINDINGS);
beforeEachBindings(() => [bind(APP_ID).toValue(APP_ID_VALUE), TEST_BINDINGS]);
beforeEach(inject([TemplateCompiler, RuntimeMetadataResolver],
(_compiler, _runtimeMetadataResolver) => {
compiler = _compiler;
@ -125,7 +128,8 @@ export function main() {
describe('compileHostComponentRuntime', () => {
function compile(components: Type[]): Promise<any[]> {
return compiler.compileHostComponentRuntime(components[0]).then(humanizeTemplate);
return compiler.compileHostComponentRuntime(components[0])
.then((compiledHostTemplate) => humanizeTemplate(compiledHostTemplate.getTemplate()));
}
runTests(compile);
@ -307,7 +311,8 @@ class CompWithoutHost {
function testableTemplateModule(sourceModule: SourceModule, normComp: CompileDirectiveMetadata):
SourceModule {
var resultExpression = `${THIS_MODULE_REF}humanizeTemplate(Host${normComp.type.name}Template)`;
var resultExpression =
`${THIS_MODULE_REF}humanizeTemplate(Host${normComp.type.name}Template.getTemplate())`;
var testableSource = `${sourceModule.sourceWithModuleRefs}
${codeGenExportVariable('run')}${codeGenValueFn(['_'], resultExpression)};`;
return new SourceModule(sourceModule.moduleId, testableSource);
@ -330,16 +335,15 @@ export function humanizeTemplate(template: CompiledTemplate,
if (isPresent(result)) {
return result;
}
var templateData = template.getData(APP_ID_VALUE);
var commands = [];
var templateData = template.dataGetter();
result = {
'styles': CompiledTemplate.getSylesFromData(templateData),
'styles': templateData.styles,
'commands': commands,
'cd': testChangeDetector(CompiledTemplate.getChangeDetectorFromData(templateData))
'cd': testChangeDetector(templateData.changeDetectorFactory)
};
humanizedTemplates.set(template.id, result);
visitAllCommands(new CommandHumanizer(commands, humanizedTemplates),
CompiledTemplate.getCommandsFromData(templateData));
visitAllCommands(new CommandHumanizer(commands, humanizedTemplates), templateData.commands);
return result;
}

View File

@ -322,11 +322,11 @@ export function main() {
it('should locate directives components first and ordered by the directives array in the View',
() => {
var dirA = CompileDirectiveMetadata.create(
{selector: '[a]', type: new CompileTypeMetadata({name: 'DirA', id: 3})});
{selector: '[a]', type: new CompileTypeMetadata({name: 'DirA'})});
var dirB = CompileDirectiveMetadata.create(
{selector: '[b]', type: new CompileTypeMetadata({name: 'DirB', id: 2})});
{selector: '[b]', type: new CompileTypeMetadata({name: 'DirB'})});
var dirC = CompileDirectiveMetadata.create(
{selector: '[c]', type: new CompileTypeMetadata({name: 'DirC', id: 1})});
{selector: '[c]', type: new CompileTypeMetadata({name: 'DirC'})});
var comp = CompileDirectiveMetadata.create({
selector: 'div',
isComponent: true,