diff --git a/modules/angular2/src/compiler/command_compiler.ts b/modules/angular2/src/compiler/command_compiler.ts index 524c63ba4b..f5256d066b 100644 --- a/modules/angular2/src/compiler/command_compiler.ts +++ b/modules/angular2/src/compiler/command_compiler.ts @@ -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 { } class RuntimeCommandFactory implements CommandFactory { - 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 { 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 { } } -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 { - 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 { 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 implements TemplateAstVisitor { result: R[] = []; transitiveNgContentCount: number = 0; - constructor(public commandFactory: CommandFactory, public component: CompileDirectiveMetadata, - public embeddedTemplateIndex: number) {} + constructor(public commandFactory: CommandFactory, 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 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 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 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[]) {} -} \ No newline at end of file +} + +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(',')}]`; +} diff --git a/modules/angular2/src/compiler/directive_metadata.ts b/modules/angular2/src/compiler/directive_metadata.ts index 82d37b3185..2ac9f88024 100644 --- a/modules/angular2/src/compiler/directive_metadata.ts +++ b/modules/angular2/src/compiler/directive_metadata.ts @@ -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): CompileTypeMetadata { - return new CompileTypeMetadata( - {id: data['id'], name: data['name'], moduleId: data['moduleId']}); + return new CompileTypeMetadata({name: data['name'], moduleId: data['moduleId']}); } toJson(): StringMap { 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, diff --git a/modules/angular2/src/compiler/runtime_metadata.ts b/modules/angular2/src/compiler/runtime_metadata.ts index 4c81a230c5..5c376b321e 100644 --- a/modules/angular2/src/compiler/runtime_metadata.ts +++ b/modules/angular2/src/compiler/runtime_metadata.ts @@ -25,7 +25,6 @@ var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g; @Injectable() export class RuntimeMetadataResolver { - private _directiveCounter = 0; private _cache: Map = 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 = new Map(); - directives.forEach((dirMeta) => { directivesMap.set(dirMeta.type.id, dirMeta); }); + var directivesMap: Map = new Map(); + directives.forEach((dirMeta) => { directivesMap.set(dirMeta.type.runtime, dirMeta); }); return MapWrapper.values(directivesMap); } diff --git a/modules/angular2/src/compiler/style_compiler.ts b/modules/angular2/src/compiler/style_compiler.ts index 64b4d40fea..bff4e6e164 100644 --- a/modules/angular2/src/compiler/style_compiler.ts +++ b/modules/angular2/src/compiler/style_compiler.ts @@ -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 { 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)}`; +} \ No newline at end of file diff --git a/modules/angular2/src/compiler/template_compiler.ts b/modules/angular2/src/compiler/template_compiler.ts index 7e774c4886..9667ab814a 100644 --- a/modules/angular2/src/compiler/template_compiler.ts +++ b/modules/angular2/src/compiler/template_compiler.ts @@ -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 = new Map(); - private _compiledTemplateDone: Map> = new Map(); + private _hostCacheKeys: Map = new Map(); + private _compiledTemplateCache: Map = new Map(); + private _compiledTemplateDone: Map> = 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 { @@ -63,40 +74,49 @@ export class TemplateCompiler { })); } - compileHostComponentRuntime(type: Type): Promise { - var compMeta: CompileDirectiveMetadata = this._runtimeMetadataResolver.getMetadata(type); - assertComponent(compMeta); - var hostMeta: CompileDirectiveMetadata = - createHostComponentMeta(compMeta.type, compMeta.selector); + compileHostComponentRuntime(type: Type): Promise { + 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): CompiledTemplate { - var compiledTemplate = this._compiledTemplateCache.get(compMeta.type.id); - var done = this._compiledTemplateDone.get(compMeta.type.id); + compilingComponentCacheKeys: Set): 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([ - this._styleCompiler.compileComponentRuntime(compMeta.type, compMeta.template) - ].concat(viewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta)))) + PromiseWrapper.all([ + 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, + compilingComponentCacheKeys: Set, childPromises: Promise[]): 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 = componentWithDirs.component; assertComponent(compMeta); componentMetas.push(compMeta); - this._processTemplateCodeGen(compMeta, + isHost.push(false); + this._processTemplateCodeGen(compMeta, appIdVariable, templateIdVariable, 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([], `[${(templateArguments[index]).join(',')}]`); + var templateDataFn = codeGenValueFn([templateIdVariable, appIdVariable], + `[${(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); diff --git a/modules/angular2/src/compiler/template_parser.ts b/modules/angular2/src/compiler/template_parser.ts index db59503991..5608e6f523 100644 --- a/modules/angular2/src/compiler/template_parser.ts +++ b/modules/angular2/src/compiler/template_parser.ts @@ -95,7 +95,7 @@ export class TemplateParser { class TemplateParseVisitor implements HtmlAstVisitor { selectorMatcher: SelectorMatcher; errors: string[] = []; - directivesIndexByTypeId: Map = new Map(); + directivesIndex: Map = 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; diff --git a/modules/angular2/src/compiler/util.ts b/modules/angular2/src/compiler/util.ts index 013cd36032..63daf7be83 100644 --- a/modules/angular2/src/compiler/util.ts +++ b/modules/angular2/src/compiler/util.ts @@ -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); diff --git a/modules/angular2/src/core/compiler/template_commands.ts b/modules/angular2/src/core/compiler/template_commands.ts index 44dfbbf690..7adea0c832 100644 --- a/modules/angular2/src/core/compiler/template_commands.ts +++ b/modules/angular2/src/core/compiler/template_commands.ts @@ -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) {} + + 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([]); diff --git a/modules/angular2/test/compiler/command_compiler_spec.ts b/modules/angular2/test/compiler/command_compiler_spec.ts index 5f006216a3..a86bf5202e 100644 --- a/modules/angular2/test/compiler/command_compiler_spec.ts +++ b/modules/angular2/test/compiler/command_compiler_spec.ts @@ -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 = + 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); } diff --git a/modules/angular2/test/compiler/directive_metadata_spec.ts b/modules/angular2/test/compiler/directive_metadata_spec.ts index b57b74a8d6..ab67e75ee3 100644 --- a/modules/angular2/test/compiler/directive_metadata_spec.ts +++ b/modules/angular2/test/compiler/directive_metadata_spec.ts @@ -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: '', diff --git a/modules/angular2/test/compiler/style_compiler_spec.ts b/modules/angular2/test/compiler/style_compiler_spec.ts index 94f16fc7b1..c7be28223e 100644 --- a/modules/angular2/test/compiler/style_compiler_spec.ts +++ b/modules/angular2/test/compiler/style_compiler_spec.ts @@ -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 = 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 { 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(); }); diff --git a/modules/angular2/test/compiler/template_compiler_spec.ts b/modules/angular2/test/compiler/template_compiler_spec.ts index b781822c89..604fede4da 100644 --- a/modules/angular2/test/compiler/template_compiler_spec.ts +++ b/modules/angular2/test/compiler/template_compiler_spec.ts @@ -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 { - 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; } diff --git a/modules/angular2/test/compiler/template_parser_spec.ts b/modules/angular2/test/compiler/template_parser_spec.ts index ec9301afa6..e1b44dcc1b 100644 --- a/modules/angular2/test/compiler/template_parser_spec.ts +++ b/modules/angular2/test/compiler/template_parser_spec.ts @@ -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,