@@ -63,7 +63,7 @@ export class ChangeDetectionCompiler {
|
||||
var index = 0;
|
||||
var sourceParts = changeDetectorDefinitions.map(definition => {
|
||||
var codegen: any;
|
||||
var sourcePart;
|
||||
var sourcePart: string;
|
||||
// TODO(tbosch): move the 2 code generators to the same place, one with .dart and one with .ts
|
||||
// suffix
|
||||
// and have the same API for calling them!
|
||||
@@ -74,7 +74,7 @@ export class ChangeDetectionCompiler {
|
||||
'dynamic' :
|
||||
`${moduleRef(componentType.moduleUrl)}${componentType.name}`;
|
||||
codegen.generate(typeRef, className, definition);
|
||||
factories.push(`(dispatcher) => new ${className}(dispatcher)`);
|
||||
factories.push(`${className}.newChangeDetector`);
|
||||
sourcePart = codegen.toString();
|
||||
} else {
|
||||
codegen = new ChangeDetectorJITGenerator(
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import {isPresent, isBlank, Type, isString, StringWrapper} from 'angular2/src/facade/lang';
|
||||
import {isPresent, isBlank, Type, isString, StringWrapper, IS_DART} from 'angular2/src/facade/lang';
|
||||
import {SetWrapper, StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {
|
||||
TemplateCmd,
|
||||
text,
|
||||
ngContent,
|
||||
beginElement,
|
||||
endElement,
|
||||
beginComponent,
|
||||
endComponent,
|
||||
embeddedTemplate,
|
||||
CompiledTemplate
|
||||
TextCmd,
|
||||
NgContentCmd,
|
||||
BeginElementCmd,
|
||||
EndElementCmd,
|
||||
BeginComponentCmd,
|
||||
EndComponentCmd,
|
||||
EmbeddedTemplateCmd,
|
||||
CompiledComponentTemplate
|
||||
} from 'angular2/src/core/linker/template_commands';
|
||||
import {
|
||||
TemplateAst,
|
||||
@@ -32,12 +32,11 @@ import {SourceExpressions, SourceExpression, moduleRef} from './source_module';
|
||||
|
||||
import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
|
||||
import {
|
||||
shimHostAttribute,
|
||||
shimContentAttribute,
|
||||
shimContentAttributeExpr,
|
||||
shimHostAttributeExpr
|
||||
} from './style_compiler';
|
||||
import {escapeSingleQuoteString, MODULE_SUFFIX} from './util';
|
||||
escapeSingleQuoteString,
|
||||
codeGenConstConstructorCall,
|
||||
codeGenValueFn,
|
||||
MODULE_SUFFIX
|
||||
} from './util';
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
|
||||
export var TEMPLATE_COMMANDS_MODULE_REF =
|
||||
@@ -49,28 +48,24 @@ const STYLE_ATTR = 'style';
|
||||
|
||||
@Injectable()
|
||||
export class CommandCompiler {
|
||||
compileComponentRuntime(component: CompileDirectiveMetadata, appId: string, templateId: number,
|
||||
template: TemplateAst[], changeDetectorFactories: Function[],
|
||||
compileComponentRuntime(component: CompileDirectiveMetadata, template: TemplateAst[],
|
||||
changeDetectorFactories: Function[],
|
||||
componentTemplateFactory: Function): TemplateCmd[] {
|
||||
var visitor = new CommandBuilderVisitor(
|
||||
new RuntimeCommandFactory(component, appId, templateId, componentTemplateFactory,
|
||||
changeDetectorFactories),
|
||||
0);
|
||||
new RuntimeCommandFactory(component, componentTemplateFactory, changeDetectorFactories), 0);
|
||||
templateVisitAll(visitor, template);
|
||||
return visitor.result;
|
||||
}
|
||||
|
||||
compileComponentCodeGen(component: CompileDirectiveMetadata, appIdExpr: string,
|
||||
templateIdExpr: string, template: TemplateAst[],
|
||||
compileComponentCodeGen(component: CompileDirectiveMetadata, template: TemplateAst[],
|
||||
changeDetectorFactoryExpressions: string[],
|
||||
componentTemplateFactory: Function): SourceExpression {
|
||||
var visitor = new CommandBuilderVisitor(
|
||||
new CodegenCommandFactory(component, appIdExpr, templateIdExpr, componentTemplateFactory,
|
||||
changeDetectorFactoryExpressions),
|
||||
0);
|
||||
var visitor =
|
||||
new CommandBuilderVisitor(new CodegenCommandFactory(component, componentTemplateFactory,
|
||||
changeDetectorFactoryExpressions),
|
||||
0);
|
||||
templateVisitAll(visitor, template);
|
||||
var source = `[${visitor.result.join(',')}]`;
|
||||
return new SourceExpression([], source);
|
||||
return new SourceExpression([], codeGenArray(visitor.result));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +78,7 @@ interface CommandFactory<R> {
|
||||
createEndElement(): R;
|
||||
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
nativeShadow: boolean, ngContentIndex: number): R;
|
||||
encapsulation: ViewEncapsulation, ngContentIndex: number): R;
|
||||
createEndComponent(): R;
|
||||
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
@@ -91,112 +86,89 @@ interface CommandFactory<R> {
|
||||
}
|
||||
|
||||
class RuntimeCommandFactory implements CommandFactory<TemplateCmd> {
|
||||
constructor(private component: CompileDirectiveMetadata, private appId: string,
|
||||
private templateId: number, private componentTemplateFactory: Function,
|
||||
constructor(private component: CompileDirectiveMetadata,
|
||||
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);
|
||||
return new TextCmd(value, isBound, ngContentIndex);
|
||||
}
|
||||
createNgContent(index: number, ngContentIndex: number): TemplateCmd {
|
||||
return ngContent(index, ngContentIndex);
|
||||
return new NgContentCmd(index, ngContentIndex);
|
||||
}
|
||||
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
isBound: boolean, ngContentIndex: number): TemplateCmd {
|
||||
return beginElement(name, this._addStyleShimAttributes(attrNameAndValues, null, null),
|
||||
eventTargetAndNames, variableNameAndValues, this._mapDirectives(directives),
|
||||
isBound, ngContentIndex);
|
||||
return new BeginElementCmd(name, attrNameAndValues, eventTargetAndNames, variableNameAndValues,
|
||||
this._mapDirectives(directives), isBound, ngContentIndex);
|
||||
}
|
||||
createEndElement(): TemplateCmd { return endElement(); }
|
||||
createEndElement(): TemplateCmd { return new EndElementCmd(); }
|
||||
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
nativeShadow: boolean, ngContentIndex: number): TemplateCmd {
|
||||
var nestedTemplate = this.componentTemplateFactory(directives[0]);
|
||||
return beginComponent(
|
||||
name, this._addStyleShimAttributes(attrNameAndValues, directives[0], nestedTemplate.id),
|
||||
eventTargetAndNames, variableNameAndValues, this._mapDirectives(directives), nativeShadow,
|
||||
ngContentIndex, nestedTemplate);
|
||||
encapsulation: ViewEncapsulation, ngContentIndex: number): TemplateCmd {
|
||||
var nestedTemplateAccessor = this.componentTemplateFactory(directives[0]);
|
||||
return new BeginComponentCmd(name, attrNameAndValues, eventTargetAndNames,
|
||||
variableNameAndValues, this._mapDirectives(directives),
|
||||
encapsulation, ngContentIndex, nestedTemplateAccessor);
|
||||
}
|
||||
createEndComponent(): TemplateCmd { return endComponent(); }
|
||||
createEndComponent(): TemplateCmd { return new EndComponentCmd(); }
|
||||
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
isMerged: boolean, ngContentIndex: number,
|
||||
children: TemplateCmd[]): TemplateCmd {
|
||||
return embeddedTemplate(attrNameAndValues, variableNameAndValues,
|
||||
this._mapDirectives(directives), isMerged, ngContentIndex,
|
||||
this.changeDetectorFactories[embeddedTemplateIndex], children);
|
||||
return new EmbeddedTemplateCmd(attrNameAndValues, variableNameAndValues,
|
||||
this._mapDirectives(directives), isMerged, ngContentIndex,
|
||||
this.changeDetectorFactories[embeddedTemplateIndex], children);
|
||||
}
|
||||
}
|
||||
|
||||
class CodegenCommandFactory implements CommandFactory<string> {
|
||||
constructor(private component: CompileDirectiveMetadata, private appIdExpr: string,
|
||||
private templateIdExpr: string, private componentTemplateFactory: Function,
|
||||
class CodegenCommandFactory implements CommandFactory<Expression> {
|
||||
constructor(private component: CompileDirectiveMetadata,
|
||||
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): Expression {
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'TextCmd')}(${escapeSingleQuoteString(value)}, ${isBound}, ${ngContentIndex})`);
|
||||
}
|
||||
|
||||
createText(value: string, isBound: boolean, ngContentIndex: number): string {
|
||||
return `${TEMPLATE_COMMANDS_MODULE_REF}text(${escapeSingleQuoteString(value)}, ${isBound}, ${ngContentIndex})`;
|
||||
}
|
||||
createNgContent(index: number, ngContentIndex: number): string {
|
||||
return `${TEMPLATE_COMMANDS_MODULE_REF}ngContent(${index}, ${ngContentIndex})`;
|
||||
createNgContent(index: number, ngContentIndex: number): Expression {
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'NgContentCmd')}(${index}, ${ngContentIndex})`);
|
||||
}
|
||||
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
isBound: boolean, ngContentIndex: number): string {
|
||||
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})`;
|
||||
isBound: boolean, ngContentIndex: number): Expression {
|
||||
var attrsExpression = codeGenArray(attrNameAndValues);
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'BeginElementCmd')}(${escapeSingleQuoteString(name)}, ${attrsExpression}, ` +
|
||||
`${codeGenArray(eventTargetAndNames)}, ${codeGenArray(variableNameAndValues)}, ${codeGenDirectivesArray(directives)}, ${isBound}, ${ngContentIndex})`);
|
||||
}
|
||||
createEndElement(): Expression {
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'EndElementCmd')}()`);
|
||||
}
|
||||
createEndElement(): string { return `${TEMPLATE_COMMANDS_MODULE_REF}endElement()`; }
|
||||
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
nativeShadow: boolean, ngContentIndex: number): string {
|
||||
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})`;
|
||||
encapsulation: ViewEncapsulation, ngContentIndex: number): Expression {
|
||||
var attrsExpression = codeGenArray(attrNameAndValues);
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'BeginComponentCmd')}(${escapeSingleQuoteString(name)}, ${attrsExpression}, ` +
|
||||
`${codeGenArray(eventTargetAndNames)}, ${codeGenArray(variableNameAndValues)}, ${codeGenDirectivesArray(directives)}, ${codeGenViewEncapsulation(encapsulation)}, ${ngContentIndex}, ${this.componentTemplateFactory(directives[0])})`);
|
||||
}
|
||||
createEndComponent(): Expression {
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'EndComponentCmd')}()`);
|
||||
}
|
||||
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(${codeGenArray(attrNameAndValues)}, ${codeGenArray(variableNameAndValues)}, ` +
|
||||
`${codeGenDirectivesArray(directives)}, ${isMerged}, ${ngContentIndex}, ${this.changeDetectorFactoryExpressions[embeddedTemplateIndex]}, [${children.join(',')}])`;
|
||||
isMerged: boolean, ngContentIndex: number,
|
||||
children: Expression[]): Expression {
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'EmbeddedTemplateCmd')}(${codeGenArray(attrNameAndValues)}, ${codeGenArray(variableNameAndValues)}, ` +
|
||||
`${codeGenDirectivesArray(directives)}, ${isMerged}, ${ngContentIndex}, ${this.changeDetectorFactoryExpressions[embeddedTemplateIndex]}, ${codeGenArray(children)})`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +242,7 @@ class CommandBuilderVisitor<R> implements TemplateAstVisitor {
|
||||
if (isPresent(component)) {
|
||||
this.result.push(this.commandFactory.createBeginComponent(
|
||||
ast.name, attrNameAndValues, eventTargetAndNames, variableNameAndValues, directives,
|
||||
component.template.encapsulation === ViewEncapsulation.Native, ast.ngContentIndex));
|
||||
component.template.encapsulation, ast.ngContentIndex));
|
||||
templateVisitAll(this, ast.children);
|
||||
this.result.push(this.commandFactory.createEndComponent());
|
||||
} else {
|
||||
@@ -383,11 +355,21 @@ function escapeValue(value: any): string {
|
||||
}
|
||||
|
||||
function codeGenArray(data: any[]): string {
|
||||
return `[${data.map(escapeValue).join(',')}]`;
|
||||
var base = `[${data.map(escapeValue).join(',')}]`;
|
||||
return IS_DART ? `const ${base}` : base;
|
||||
}
|
||||
|
||||
function codeGenDirectivesArray(directives: CompileDirectiveMetadata[]): string {
|
||||
var expressions = directives.map(
|
||||
directiveType => `${moduleRef(directiveType.type.moduleUrl)}${directiveType.type.name}`);
|
||||
return `[${expressions.join(',')}]`;
|
||||
var base = `[${expressions.join(',')}]`;
|
||||
return IS_DART ? `const ${base}` : base;
|
||||
}
|
||||
|
||||
function codeGenViewEncapsulation(value: ViewEncapsulation): string {
|
||||
if (IS_DART) {
|
||||
return `${TEMPLATE_COMMANDS_MODULE_REF}${value}`;
|
||||
} else {
|
||||
return `${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,21 +9,12 @@ import {UrlResolver} from 'angular2/src/compiler/url_resolver';
|
||||
import {extractStyleUrls} from './style_url_resolver';
|
||||
import {
|
||||
escapeSingleQuoteString,
|
||||
codeGenConcatArray,
|
||||
codeGenMapArray,
|
||||
codeGenReplaceAll,
|
||||
codeGenExportVariable,
|
||||
codeGenToString,
|
||||
MODULE_SUFFIX
|
||||
} 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}`;
|
||||
import {COMPONENT_VARIABLE, HOST_ATTR, CONTENT_ATTR} from 'angular2/src/core/render/view_factory';
|
||||
|
||||
@Injectable()
|
||||
export class StyleCompiler {
|
||||
@@ -32,28 +23,16 @@ export class StyleCompiler {
|
||||
|
||||
constructor(private _xhr: XHR, private _urlResolver: UrlResolver) {}
|
||||
|
||||
compileComponentRuntime(appId: string, templateId: number,
|
||||
template: CompileTemplateMetadata): Promise<string[]> {
|
||||
compileComponentRuntime(template: CompileTemplateMetadata): Promise<Array<string | any[]>> {
|
||||
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, componentId(appId, templateId))));
|
||||
template.encapsulation === ViewEncapsulation.Emulated);
|
||||
}
|
||||
|
||||
compileComponentCodeGen(appIdExpression: string, templateIdExpression: string,
|
||||
template: CompileTemplateMetadata): SourceExpression {
|
||||
compileComponentCodeGen(template: CompileTemplateMetadata): SourceExpression {
|
||||
var shim = template.encapsulation === ViewEncapsulation.Emulated;
|
||||
var suffix;
|
||||
if (shim) {
|
||||
suffix = codeGenMapArray(
|
||||
['style'],
|
||||
`style${codeGenReplaceAll(COMPONENT_VARIABLE, componentIdExpression(appIdExpression, templateIdExpression))}`);
|
||||
} else {
|
||||
suffix = '';
|
||||
}
|
||||
return this._styleCodeGen(template.styles, template.styleUrls, shim, suffix);
|
||||
return this._styleCodeGen(template.styles, template.styleUrls, shim);
|
||||
}
|
||||
|
||||
compileStylesheetCodeGen(stylesheetUrl: string, cssText: string): SourceModule[] {
|
||||
@@ -61,17 +40,16 @@ export class StyleCompiler {
|
||||
return [
|
||||
this._styleModule(
|
||||
stylesheetUrl, false,
|
||||
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, false, '')),
|
||||
this._styleModule(
|
||||
stylesheetUrl, true,
|
||||
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, true, ''))
|
||||
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, false)),
|
||||
this._styleModule(stylesheetUrl, true, this._styleCodeGen([styleWithImports.style],
|
||||
styleWithImports.styleUrls, true))
|
||||
];
|
||||
}
|
||||
|
||||
clearCache() { this._styleCache.clear(); }
|
||||
|
||||
private _loadStyles(plainStyles: string[], absUrls: string[],
|
||||
encapsulate: boolean): Promise<string[]> {
|
||||
encapsulate: boolean): Promise<Array<string | any[]>> {
|
||||
var promises = absUrls.map((absUrl) => {
|
||||
var cacheKey = `${absUrl}${encapsulate ? '.shim' : ''}`;
|
||||
var result = this._styleCache.get(cacheKey);
|
||||
@@ -86,22 +64,23 @@ export class StyleCompiler {
|
||||
return result;
|
||||
});
|
||||
return PromiseWrapper.all(promises).then((nestedStyles: string[][]) => {
|
||||
var result = plainStyles.map(plainStyle => this._shimIfNeeded(plainStyle, encapsulate));
|
||||
nestedStyles.forEach(styles => styles.forEach(style => result.push(style)));
|
||||
var result: Array<string | any[]> =
|
||||
plainStyles.map(plainStyle => this._shimIfNeeded(plainStyle, encapsulate));
|
||||
nestedStyles.forEach(styles => result.push(styles));
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
private _styleCodeGen(plainStyles: string[], absUrls: string[], shim: boolean,
|
||||
suffix: string): SourceExpression {
|
||||
var expressionSource = `(`;
|
||||
expressionSource +=
|
||||
`[${plainStyles.map( plainStyle => escapeSingleQuoteString(this._shimIfNeeded(plainStyle, shim)) ).join(',')}]`;
|
||||
private _styleCodeGen(plainStyles: string[], absUrls: string[], shim: boolean): SourceExpression {
|
||||
var arrayPrefix = IS_DART ? `const` : '';
|
||||
var styleExpressions = plainStyles.map(
|
||||
plainStyle => escapeSingleQuoteString(this._shimIfNeeded(plainStyle, shim)));
|
||||
|
||||
for (var i = 0; i < absUrls.length; i++) {
|
||||
var moduleUrl = this._createModuleUrl(absUrls[i], shim);
|
||||
expressionSource += codeGenConcatArray(`${moduleRef(moduleUrl)}STYLES`);
|
||||
styleExpressions.push(`${moduleRef(moduleUrl)}STYLES`);
|
||||
}
|
||||
expressionSource += `)${suffix}`;
|
||||
var expressionSource = `${arrayPrefix} [${styleExpressions.join(',')}]`;
|
||||
return new SourceExpression([], expressionSource);
|
||||
}
|
||||
|
||||
@@ -122,29 +101,3 @@ export class StyleCompiler {
|
||||
return shim ? `${stylesheetUrl}.shim${MODULE_SUFFIX}` : `${stylesheetUrl}${MODULE_SUFFIX}`;
|
||||
}
|
||||
}
|
||||
|
||||
export function shimContentAttribute(appId: string, templateId: number): string {
|
||||
return StringWrapper.replaceAll(CONTENT_ATTR, COMPONENT_REGEX, componentId(appId, templateId));
|
||||
}
|
||||
|
||||
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)}`;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {ListWrapper, SetWrapper} from 'angular2/src/facade/collection';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
import {
|
||||
CompiledTemplate,
|
||||
CompiledComponentTemplate,
|
||||
TemplateCmd,
|
||||
nextTemplateId,
|
||||
CompiledHostTemplate
|
||||
CompiledHostTemplate,
|
||||
BeginComponentCmd
|
||||
} from 'angular2/src/core/linker/template_commands';
|
||||
import {
|
||||
createHostComponentMeta,
|
||||
@@ -23,7 +23,6 @@ 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/application_tokens';
|
||||
|
||||
import {TEMPLATE_COMMANDS_MODULE_REF} from './command_compiler';
|
||||
import {
|
||||
@@ -32,22 +31,19 @@ import {
|
||||
codeGenValueFn,
|
||||
MODULE_SUFFIX
|
||||
} from './util';
|
||||
import {Inject} from 'angular2/src/core/di';
|
||||
|
||||
@Injectable()
|
||||
export class TemplateCompiler {
|
||||
private _hostCacheKeys = new Map<Type, any>();
|
||||
private _compiledTemplateCache = new Map<any, CompiledTemplate>();
|
||||
private _compiledTemplateDone = new Map<any, Promise<CompiledTemplate>>();
|
||||
private _appId: string;
|
||||
private _compiledTemplateCache = new Map<any, CompiledComponentTemplate>();
|
||||
private _compiledTemplateDone = new Map<any, Promise<CompiledComponentTemplate>>();
|
||||
private _nextTemplateId: number = 0;
|
||||
|
||||
constructor(private _runtimeMetadataResolver: RuntimeMetadataResolver,
|
||||
private _templateNormalizer: TemplateNormalizer,
|
||||
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
|
||||
private _commandCompiler: CommandCompiler,
|
||||
private _cdCompiler: ChangeDetectionCompiler, @Inject(APP_ID) appId: string) {
|
||||
this._appId = appId;
|
||||
}
|
||||
private _cdCompiler: ChangeDetectionCompiler) {}
|
||||
|
||||
normalizeDirectiveMetadata(directive: CompileDirectiveMetadata):
|
||||
Promise<CompileDirectiveMetadata> {
|
||||
@@ -87,7 +83,7 @@ export class TemplateCompiler {
|
||||
this._compileComponentRuntime(hostCacheKey, hostMeta, [compMeta], new Set());
|
||||
}
|
||||
return this._compiledTemplateDone.get(hostCacheKey)
|
||||
.then(compiledTemplate => new CompiledHostTemplate(() => compiledTemplate));
|
||||
.then(compiledTemplate => new CompiledHostTemplate(compiledTemplate));
|
||||
}
|
||||
|
||||
clearCache() {
|
||||
@@ -97,57 +93,55 @@ export class TemplateCompiler {
|
||||
this._compiledTemplateDone.clear();
|
||||
}
|
||||
|
||||
private _compileComponentRuntime(cacheKey: any, compMeta: CompileDirectiveMetadata,
|
||||
viewDirectives: CompileDirectiveMetadata[],
|
||||
compilingComponentCacheKeys: Set<any>): CompiledTemplate {
|
||||
private _compileComponentRuntime(
|
||||
cacheKey: any, compMeta: CompileDirectiveMetadata, viewDirectives: CompileDirectiveMetadata[],
|
||||
compilingComponentCacheKeys: Set<any>): CompiledComponentTemplate {
|
||||
var compiledTemplate = this._compiledTemplateCache.get(cacheKey);
|
||||
var done = this._compiledTemplateDone.get(cacheKey);
|
||||
if (isBlank(compiledTemplate)) {
|
||||
var styles;
|
||||
var styles = [];
|
||||
var changeDetectorFactory;
|
||||
var commands;
|
||||
var templateId = nextTemplateId();
|
||||
compiledTemplate =
|
||||
new CompiledTemplate(templateId, (_a, _b) => [changeDetectorFactory, commands, styles]);
|
||||
var commands = [];
|
||||
var templateId = `${stringify(compMeta.type.runtime)}Template${this._nextTemplateId++}`;
|
||||
compiledTemplate = new CompiledComponentTemplate(
|
||||
templateId, (dispatcher) => changeDetectorFactory(dispatcher), commands, styles);
|
||||
this._compiledTemplateCache.set(cacheKey, compiledTemplate);
|
||||
compilingComponentCacheKeys.add(cacheKey);
|
||||
done =
|
||||
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);
|
||||
var parsedTemplate = this._templateParser.parse(
|
||||
compMeta.template.template, normalizedViewDirMetas, compMeta.type.name);
|
||||
done = PromiseWrapper
|
||||
.all([<any>this._styleCompiler.compileComponentRuntime(compMeta.template)].concat(
|
||||
viewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
|
||||
.then((stylesAndNormalizedViewDirMetas: any[]) => {
|
||||
var childPromises = [];
|
||||
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
|
||||
var parsedTemplate = this._templateParser.parse(
|
||||
compMeta.template.template, normalizedViewDirMetas, compMeta.type.name);
|
||||
|
||||
var changeDetectorFactories = this._cdCompiler.compileComponentRuntime(
|
||||
compMeta.type, compMeta.changeDetection, parsedTemplate);
|
||||
changeDetectorFactory = changeDetectorFactories[0];
|
||||
styles = stylesAndNormalizedViewDirMetas[0];
|
||||
commands = this._compileCommandsRuntime(compMeta, templateId, parsedTemplate,
|
||||
changeDetectorFactories,
|
||||
compilingComponentCacheKeys, childPromises);
|
||||
return PromiseWrapper.all(childPromises);
|
||||
})
|
||||
.then((_) => {
|
||||
SetWrapper.delete(compilingComponentCacheKeys, cacheKey);
|
||||
return compiledTemplate;
|
||||
});
|
||||
var changeDetectorFactories = this._cdCompiler.compileComponentRuntime(
|
||||
compMeta.type, compMeta.changeDetection, parsedTemplate);
|
||||
changeDetectorFactory = changeDetectorFactories[0];
|
||||
var tmpStyles: string[] = stylesAndNormalizedViewDirMetas[0];
|
||||
tmpStyles.forEach(style => styles.push(style));
|
||||
var tmpCommands: TemplateCmd[] = this._compileCommandsRuntime(
|
||||
compMeta, parsedTemplate, changeDetectorFactories,
|
||||
compilingComponentCacheKeys, childPromises);
|
||||
tmpCommands.forEach(cmd => commands.push(cmd));
|
||||
return PromiseWrapper.all(childPromises);
|
||||
})
|
||||
.then((_) => {
|
||||
SetWrapper.delete(compilingComponentCacheKeys, cacheKey);
|
||||
return compiledTemplate;
|
||||
});
|
||||
this._compiledTemplateDone.set(cacheKey, done);
|
||||
}
|
||||
return compiledTemplate;
|
||||
}
|
||||
|
||||
private _compileCommandsRuntime(compMeta: CompileDirectiveMetadata, templateId: number,
|
||||
parsedTemplate: TemplateAst[],
|
||||
private _compileCommandsRuntime(compMeta: CompileDirectiveMetadata, parsedTemplate: TemplateAst[],
|
||||
changeDetectorFactories: Function[],
|
||||
compilingComponentCacheKeys: Set<Type>,
|
||||
childPromises: Promise<any>[]): TemplateCmd[] {
|
||||
return this._commandCompiler.compileComponentRuntime(
|
||||
compMeta, this._appId, templateId, parsedTemplate, changeDetectorFactories,
|
||||
var cmds: TemplateCmd[] = this._commandCompiler.compileComponentRuntime(
|
||||
compMeta, parsedTemplate, changeDetectorFactories,
|
||||
(childComponentDir: CompileDirectiveMetadata) => {
|
||||
var childCacheKey = childComponentDir.type.runtime;
|
||||
var childViewDirectives: CompileDirectiveMetadata[] =
|
||||
@@ -160,8 +154,14 @@ export class TemplateCompiler {
|
||||
// Only wait for a child if it is not a cycle
|
||||
childPromises.push(this._compiledTemplateDone.get(childCacheKey));
|
||||
}
|
||||
return childTemplate;
|
||||
return () => childTemplate;
|
||||
});
|
||||
cmds.forEach(cmd => {
|
||||
if (cmd instanceof BeginComponentCmd) {
|
||||
cmd.templateGetter();
|
||||
}
|
||||
});
|
||||
return cmds;
|
||||
}
|
||||
|
||||
compileTemplatesCodeGen(components: NormalizedComponentWithViewDirectives[]): SourceModule {
|
||||
@@ -171,40 +171,35 @@ export class TemplateCompiler {
|
||||
var declarations = [];
|
||||
var templateArguments = [];
|
||||
var componentMetas: CompileDirectiveMetadata[] = [];
|
||||
var templateIdVariable = 'templateId';
|
||||
var appIdVariable = 'appId';
|
||||
components.forEach(componentWithDirs => {
|
||||
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
|
||||
assertComponent(compMeta);
|
||||
componentMetas.push(compMeta);
|
||||
this._processTemplateCodeGen(compMeta, appIdVariable, templateIdVariable,
|
||||
this._processTemplateCodeGen(compMeta,
|
||||
<CompileDirectiveMetadata[]>componentWithDirs.directives,
|
||||
declarations, templateArguments);
|
||||
if (compMeta.dynamicLoadable) {
|
||||
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
|
||||
componentMetas.push(hostMeta);
|
||||
this._processTemplateCodeGen(hostMeta, appIdVariable, templateIdVariable, [compMeta],
|
||||
declarations, templateArguments);
|
||||
this._processTemplateCodeGen(hostMeta, [compMeta], declarations, templateArguments);
|
||||
}
|
||||
});
|
||||
ListWrapper.forEachWithIndex(componentMetas, (compMeta: CompileDirectiveMetadata,
|
||||
index: number) => {
|
||||
var templateDataFn = codeGenValueFn([appIdVariable, templateIdVariable],
|
||||
`[${(<any[]>templateArguments[index]).join(',')}]`);
|
||||
var templateId = `${compMeta.type.moduleUrl}|${compMeta.type.name}`;
|
||||
var constructionKeyword = IS_DART ? 'const' : 'new';
|
||||
var compiledTemplateExpr =
|
||||
`new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledTemplate(${TEMPLATE_COMMANDS_MODULE_REF}nextTemplateId(),${templateDataFn})`;
|
||||
`${constructionKeyword} ${TEMPLATE_COMMANDS_MODULE_REF}CompiledComponentTemplate('${templateId}',${(<any[]>templateArguments[index]).join(',')})`;
|
||||
var variableValueExpr;
|
||||
if (compMeta.type.isHost) {
|
||||
var factoryName = `_hostTemplateFactory${index}`;
|
||||
declarations.push(`${codeGenValueFn([], compiledTemplateExpr, factoryName)};`);
|
||||
var constructionKeyword = IS_DART ? 'const' : 'new';
|
||||
variableValueExpr =
|
||||
`${constructionKeyword} ${TEMPLATE_COMMANDS_MODULE_REF}CompiledHostTemplate(${factoryName})`;
|
||||
`${constructionKeyword} ${TEMPLATE_COMMANDS_MODULE_REF}CompiledHostTemplate(${compiledTemplateExpr})`;
|
||||
} else {
|
||||
variableValueExpr = compiledTemplateExpr;
|
||||
}
|
||||
declarations.push(
|
||||
`${codeGenExportVariable(templateVariableName(compMeta.type), compMeta.type.isHost)}${variableValueExpr};`);
|
||||
var varName = templateVariableName(compMeta.type);
|
||||
declarations.push(`${codeGenExportVariable(varName)}${variableValueExpr};`);
|
||||
declarations.push(`${codeGenValueFn([], varName, templateGetterName(compMeta.type))};`);
|
||||
});
|
||||
var moduleUrl = components[0].component.type.moduleUrl;
|
||||
return new SourceModule(`${templateModuleUrl(moduleUrl)}`, declarations.join('\n'));
|
||||
@@ -214,17 +209,16 @@ export class TemplateCompiler {
|
||||
return this._styleCompiler.compileStylesheetCodeGen(stylesheetUrl, cssText);
|
||||
}
|
||||
|
||||
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata, appIdExpr: string,
|
||||
templateIdExpr: string, directives: CompileDirectiveMetadata[],
|
||||
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata,
|
||||
directives: CompileDirectiveMetadata[],
|
||||
targetDeclarations: string[], targetTemplateArguments: any[][]) {
|
||||
var styleExpr =
|
||||
this._styleCompiler.compileComponentCodeGen(appIdExpr, templateIdExpr, compMeta.template);
|
||||
var styleExpr = this._styleCompiler.compileComponentCodeGen(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, appIdExpr, templateIdExpr, parsedTemplate, changeDetectorsExprs.expressions,
|
||||
compMeta, parsedTemplate, changeDetectorsExprs.expressions,
|
||||
codeGenComponentTemplateFactory);
|
||||
|
||||
addAll(styleExpr.declarations, targetDeclarations);
|
||||
@@ -251,6 +245,10 @@ function templateVariableName(type: CompileTypeMetadata): string {
|
||||
return `${type.name}Template`;
|
||||
}
|
||||
|
||||
function templateGetterName(type: CompileTypeMetadata): string {
|
||||
return `${templateVariableName(type)}Getter`;
|
||||
}
|
||||
|
||||
function templateModuleUrl(moduleUrl: string): string {
|
||||
var urlWithoutSuffix = moduleUrl.substring(0, moduleUrl.length - MODULE_SUFFIX.length);
|
||||
return `${urlWithoutSuffix}.template${MODULE_SUFFIX}`;
|
||||
@@ -263,5 +261,5 @@ function addAll(source: any[], target: any[]) {
|
||||
}
|
||||
|
||||
function codeGenComponentTemplateFactory(nestedCompType: CompileDirectiveMetadata): string {
|
||||
return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}${templateVariableName(nestedCompType.type)}`;
|
||||
return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}${templateGetterName(nestedCompType.type)}`;
|
||||
}
|
||||
|
||||
@@ -43,31 +43,19 @@ function escapeString(input: string, re: RegExp): string {
|
||||
});
|
||||
}
|
||||
|
||||
export function codeGenExportVariable(name: string, isConst: boolean = false): string {
|
||||
export function codeGenExportVariable(name: string): string {
|
||||
if (IS_DART) {
|
||||
return isConst ? `const ${name} = ` : `final ${name} = `;
|
||||
return `const ${name} = `;
|
||||
} else {
|
||||
return `var ${name} = exports['${name}'] = `;
|
||||
}
|
||||
}
|
||||
|
||||
export function codeGenConcatArray(expression: string): string {
|
||||
return `${IS_DART ? '..addAll' : '.concat'}(${expression})`;
|
||||
}
|
||||
|
||||
export function codeGenMapArray(argNames: string[], callback: string): string {
|
||||
export function codeGenConstConstructorCall(name: string): string {
|
||||
if (IS_DART) {
|
||||
return `.map( (${argNames.join(',')}) => ${callback} ).toList()`;
|
||||
return `const ${name}`;
|
||||
} else {
|
||||
return `.map(function(${argNames.join(',')}) { return ${callback}; })`;
|
||||
}
|
||||
}
|
||||
|
||||
export function codeGenReplaceAll(pattern: string, expression: string): string {
|
||||
if (IS_DART) {
|
||||
return `.replaceAll('${pattern}', ${expression})`;
|
||||
} else {
|
||||
return `.replace(/${pattern}/g, ${expression})`;
|
||||
return `new ${name}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user