refactor(compiler): make `OutputAst` contain the moduleName, not the filePath (#16832).

The goal of this change is to simplify the emitters,
as we will soon create a new one to emit TypeScript nodes directly.
This commit is contained in:
Tobias Bosch 2017-05-16 16:30:37 -07:00 committed by Chuck Jazdzewski
parent 3b28c75d1f
commit 6123b9c0c6
28 changed files with 589 additions and 774 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileNgModuleSummary, CompilePipeMetadata, CompileProviderMetadata, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary, componentFactoryName, createHostComponentMeta, flatten, identifierName, sourceUrl, templateSourceUrl} from '../compile_metadata'; import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileNgModuleSummary, CompilePipeMetadata, CompileProviderMetadata, CompileStylesheetMetadata, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary, componentFactoryName, createHostComponentMeta, flatten, identifierName, sourceUrl, templateSourceUrl} from '../compile_metadata';
import {CompilerConfig} from '../config'; import {CompilerConfig} from '../config';
import {Identifiers, createIdentifier, createIdentifierToken} from '../identifiers'; import {Identifiers, createIdentifier, createIdentifierToken} from '../identifiers';
import {CompileMetadataResolver} from '../metadata_resolver'; import {CompileMetadataResolver} from '../metadata_resolver';
@ -16,8 +16,8 @@ import * as o from '../output/output_ast';
import {CompiledStylesheet, StyleCompiler} from '../style_compiler'; import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
import {SummaryResolver} from '../summary_resolver'; import {SummaryResolver} from '../summary_resolver';
import {TemplateParser} from '../template_parser/template_parser'; import {TemplateParser} from '../template_parser/template_parser';
import {syntaxError} from '../util'; import {OutputContext, syntaxError} from '../util';
import {ViewCompiler} from '../view_compiler/view_compiler'; import {ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler';
import {AotCompilerHost} from './compiler_host'; import {AotCompilerHost} from './compiler_host';
import {GeneratedFile} from './generated_file'; import {GeneratedFile} from './generated_file';
@ -60,16 +60,15 @@ export class AotCompiler {
directives: StaticSymbol[], pipes: StaticSymbol[], ngModules: StaticSymbol[], directives: StaticSymbol[], pipes: StaticSymbol[], ngModules: StaticSymbol[],
injectables: StaticSymbol[]): GeneratedFile[] { injectables: StaticSymbol[]): GeneratedFile[] {
const fileSuffix = splitTypescriptSuffix(srcFileUrl, true)[1]; const fileSuffix = splitTypescriptSuffix(srcFileUrl, true)[1];
const statements: o.Statement[] = [];
const exportedVars: string[] = [];
const generatedFiles: GeneratedFile[] = []; const generatedFiles: GeneratedFile[] = [];
generatedFiles.push(...this._createSummary( const outputCtx = this._createOutputContext(ngfactoryFilePath(srcFileUrl, true));
srcFileUrl, directives, pipes, ngModules, injectables, statements, exportedVars));
generatedFiles.push(
...this._createSummary(srcFileUrl, directives, pipes, ngModules, injectables, outputCtx));
// compile all ng modules // compile all ng modules
exportedVars.push( ngModules.forEach((ngModuleType) => this._compileModule(outputCtx, ngModuleType));
...ngModules.map((ngModuleType) => this._compileModule(ngModuleType, statements)));
// compile components // compile components
directives.forEach((dirType) => { directives.forEach((dirType) => {
@ -86,22 +85,20 @@ export class AotCompiler {
_assertComponent(compMeta); _assertComponent(compMeta);
// compile styles // compile styles
const stylesCompileResults = this._styleCompiler.compileComponent(compMeta); const componentStylesheet = this._styleCompiler.compileComponent(outputCtx, compMeta);
stylesCompileResults.externalStylesheets.forEach((compiledStyleSheet) => { // Note: compMeta is a component and therefore template is non null.
generatedFiles.push(this._codgenStyles(srcFileUrl, compiledStyleSheet, fileSuffix)); compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => {
generatedFiles.push(this._codegenStyles(srcFileUrl, compMeta, stylesheetMeta, fileSuffix));
}); });
// compile components // compile components
const compViewVars = this._compileComponent( const compViewVars = this._compileComponent(
compMeta, ngModule, ngModule.transitiveModule.directives, outputCtx, compMeta, ngModule, ngModule.transitiveModule.directives, componentStylesheet,
stylesCompileResults.componentStylesheet, fileSuffix, statements); fileSuffix);
exportedVars.push( this._compileComponentFactory(outputCtx, compMeta, ngModule, fileSuffix);
this._compileComponentFactory(compMeta, ngModule, fileSuffix, statements),
compViewVars.viewClassVar, compViewVars.compRenderTypeVar);
}); });
if (statements.length > 0) { if (outputCtx.statements.length > 0) {
const srcModule = this._codegenSourceModule( const srcModule = this._codegenSourceModule(srcFileUrl, outputCtx);
srcFileUrl, ngfactoryFilePath(srcFileUrl, true), statements, exportedVars);
generatedFiles.unshift(srcModule); generatedFiles.unshift(srcModule);
} }
return generatedFiles; return generatedFiles;
@ -109,8 +106,8 @@ export class AotCompiler {
private _createSummary( private _createSummary(
srcFileUrl: string, directives: StaticSymbol[], pipes: StaticSymbol[], srcFileUrl: string, directives: StaticSymbol[], pipes: StaticSymbol[],
ngModules: StaticSymbol[], injectables: StaticSymbol[], targetStatements: o.Statement[], ngModules: StaticSymbol[], injectables: StaticSymbol[],
targetExportedVars: string[]): GeneratedFile[] { ngFactoryCtx: OutputContext): GeneratedFile[] {
const symbolSummaries = this._symbolResolver.getSymbolsOf(srcFileUrl) const symbolSummaries = this._symbolResolver.getSymbolsOf(srcFileUrl)
.map(symbol => this._symbolResolver.resolveSymbol(symbol)); .map(symbol => this._symbolResolver.resolveSymbol(symbol));
const typeData: { const typeData: {
@ -136,22 +133,23 @@ export class AotCompiler {
metadata: this._metadataResolver.getInjectableSummary(ref) !.type metadata: this._metadataResolver.getInjectableSummary(ref) !.type
})) }))
]; ];
const {json, exportAs, forJit} = const forJitOutputCtx = this._createOutputContext(summaryForJitFileName(srcFileUrl, true));
serializeSummaries(this._summaryResolver, this._symbolResolver, symbolSummaries, typeData); const forJitTargetFilePath = summaryForJitFileName(srcFileUrl, true);
const {json, exportAs} = serializeSummaries(
forJitOutputCtx, this._summaryResolver, this._symbolResolver, symbolSummaries, typeData);
exportAs.forEach((entry) => { exportAs.forEach((entry) => {
targetStatements.push( ngFactoryCtx.statements.push(
o.variable(entry.exportAs).set(o.importExpr({reference: entry.symbol})).toDeclStmt()); o.variable(entry.exportAs).set(ngFactoryCtx.importExpr(entry.symbol)).toDeclStmt(null, [
targetExportedVars.push(entry.exportAs); o.StmtModifier.Exported
]));
}); });
return [ return [
new GeneratedFile(srcFileUrl, summaryFileName(srcFileUrl), json), new GeneratedFile(srcFileUrl, summaryFileName(srcFileUrl), json),
this._codegenSourceModule( this._codegenSourceModule(srcFileUrl, forJitOutputCtx)
srcFileUrl, summaryForJitFileName(srcFileUrl, true), forJit.statements,
forJit.exportedVars)
]; ];
} }
private _compileModule(ngModuleType: StaticSymbol, targetStatements: o.Statement[]): string { private _compileModule(outputCtx: OutputContext, ngModuleType: StaticSymbol): void {
const ngModule = this._metadataResolver.getNgModuleMetadata(ngModuleType) !; const ngModule = this._metadataResolver.getNgModuleMetadata(ngModuleType) !;
const providers: CompileProviderMetadata[] = []; const providers: CompileProviderMetadata[] = [];
@ -169,20 +167,17 @@ export class AotCompiler {
}); });
} }
const appCompileResult = this._ngModuleCompiler.compile(ngModule, providers); this._ngModuleCompiler.compile(outputCtx, ngModule, providers);
targetStatements.push(...appCompileResult.statements);
return appCompileResult.ngModuleFactoryVar;
} }
private _compileComponentFactory( private _compileComponentFactory(
compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata, fileSuffix: string, outputCtx: OutputContext, compMeta: CompileDirectiveMetadata,
targetStatements: o.Statement[]): string { ngModule: CompileNgModuleMetadata, fileSuffix: string): void {
const hostType = this._metadataResolver.getHostComponentType(compMeta.type.reference); const hostType = this._metadataResolver.getHostComponentType(compMeta.type.reference);
const hostMeta = createHostComponentMeta( const hostMeta = createHostComponentMeta(
hostType, compMeta, this._metadataResolver.getHostComponentViewClass(hostType)); hostType, compMeta, this._metadataResolver.getHostComponentViewClass(hostType));
const hostViewFactoryVar = const hostViewFactoryVar =
this._compileComponent( this._compileComponent(outputCtx, hostMeta, ngModule, [compMeta.type], null, fileSuffix)
hostMeta, ngModule, [compMeta.type], null, fileSuffix, targetStatements)
.viewClassVar; .viewClassVar;
const compFactoryVar = componentFactoryName(compMeta.type.reference); const compFactoryVar = componentFactoryName(compMeta.type.reference);
const inputsExprs: o.LiteralMapEntry[] = []; const inputsExprs: o.LiteralMapEntry[] = [];
@ -198,10 +193,10 @@ export class AotCompiler {
outputsExprs.push(new o.LiteralMapEntry(propName, o.literal(templateName), false)); outputsExprs.push(new o.LiteralMapEntry(propName, o.literal(templateName), false));
} }
targetStatements.push( outputCtx.statements.push(
o.variable(compFactoryVar) o.variable(compFactoryVar)
.set(o.importExpr(createIdentifier(Identifiers.createComponentFactory)).callFn([ .set(o.importExpr(Identifiers.createComponentFactory).callFn([
o.literal(compMeta.selector), o.importExpr(compMeta.type), o.literal(compMeta.selector), outputCtx.importExpr(compMeta.type.reference),
o.variable(hostViewFactoryVar), new o.LiteralMapExpr(inputsExprs), o.variable(hostViewFactoryVar), new o.LiteralMapExpr(inputsExprs),
new o.LiteralMapExpr(outputsExprs), new o.LiteralMapExpr(outputsExprs),
o.literalArr( o.literalArr(
@ -209,17 +204,16 @@ export class AotCompiler {
])) ]))
.toDeclStmt( .toDeclStmt(
o.importType( o.importType(
createIdentifier(Identifiers.ComponentFactory), [o.importType(compMeta.type) !], Identifiers.ComponentFactory,
[o.expressionType(outputCtx.importExpr(compMeta.type.reference)) !],
[o.TypeModifier.Const]), [o.TypeModifier.Const]),
[o.StmtModifier.Final])); [o.StmtModifier.Final, o.StmtModifier.Exported]));
return compFactoryVar;
} }
private _compileComponent( private _compileComponent(
compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata, outputCtx: OutputContext, compMeta: CompileDirectiveMetadata,
directiveIdentifiers: CompileIdentifierMetadata[], componentStyles: CompiledStylesheet|null, ngModule: CompileNgModuleMetadata, directiveIdentifiers: CompileIdentifierMetadata[],
fileSuffix: string, componentStyles: CompiledStylesheet|null, fileSuffix: string): ViewCompileResult {
targetStatements: o.Statement[]): {viewClassVar: string, compRenderTypeVar: string} {
const directives = const directives =
directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference)); directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
const pipes = ngModule.transitiveModule.pipes.map( const pipes = ngModule.transitiveModule.pipes.map(
@ -229,44 +223,70 @@ export class AotCompiler {
compMeta, compMeta.template !.template !, directives, pipes, ngModule.schemas, compMeta, compMeta.template !.template !, directives, pipes, ngModule.schemas,
templateSourceUrl(ngModule.type, compMeta, compMeta.template !)); templateSourceUrl(ngModule.type, compMeta, compMeta.template !));
const stylesExpr = componentStyles ? o.variable(componentStyles.stylesVar) : o.literalArr([]); const stylesExpr = componentStyles ? o.variable(componentStyles.stylesVar) : o.literalArr([]);
const viewResult = const viewResult = this._viewCompiler.compileComponent(
this._viewCompiler.compileComponent(compMeta, parsedTemplate, stylesExpr, usedPipes); outputCtx, compMeta, parsedTemplate, stylesExpr, usedPipes);
if (componentStyles) { if (componentStyles) {
targetStatements.push( _resolveStyleStatements(
..._resolveStyleStatements(this._symbolResolver, componentStyles, fileSuffix)); this._symbolResolver, componentStyles, this._styleCompiler.needsStyleShim(compMeta),
fileSuffix);
} }
targetStatements.push(...viewResult.statements); return viewResult;
return {viewClassVar: viewResult.viewClassVar, compRenderTypeVar: viewResult.rendererTypeVar};
} }
private _codgenStyles( private _createOutputContext(genFilePath: string): OutputContext {
fileUrl: string, stylesCompileResult: CompiledStylesheet, fileSuffix: string): GeneratedFile { const importExpr = (symbol: StaticSymbol, typeParams: o.Type[] | null = null) => {
_resolveStyleStatements(this._symbolResolver, stylesCompileResult, fileSuffix); if (!(symbol instanceof StaticSymbol)) {
return this._codegenSourceModule( throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
fileUrl, }
_stylesModuleUrl( const arity = this._symbolResolver.getTypeArity(symbol) || 0;
stylesCompileResult.meta.moduleUrl !, stylesCompileResult.isShimmed, fileSuffix), const {filePath, name, members} = this._symbolResolver.getImportAs(symbol) || symbol;
stylesCompileResult.statements, [stylesCompileResult.stylesVar]); const moduleName = this._symbolResolver.fileNameToModuleName(filePath, genFilePath);
// If we are in a type expression that refers to a generic type then supply
// the required type parameters. If there were not enough type parameters
// supplied, supply any as the type. Outside a type expression the reference
// should not supply type parameters and be treated as a simple value reference
// to the constructor function itself.
const suppliedTypeParams = typeParams || [];
const missingTypeParamsCount = arity - suppliedTypeParams.length;
const allTypeParams =
suppliedTypeParams.concat(new Array(missingTypeParamsCount).fill(o.DYNAMIC_TYPE));
return members.reduce(
(expr, memberName) => expr.prop(memberName),
<o.Expression>o.importExpr(
new o.ExternalReference(moduleName, name, null), allTypeParams));
};
return {statements: [], genFilePath, importExpr};
} }
private _codegenSourceModule( private _codegenStyles(
srcFileUrl: string, genFileUrl: string, statements: o.Statement[], srcFileUrl: string, compMeta: CompileDirectiveMetadata,
exportedVars: string[]): GeneratedFile { stylesheetMetadata: CompileStylesheetMetadata, fileSuffix: string): GeneratedFile {
const outputCtx = this._createOutputContext(_stylesModuleUrl(
stylesheetMetadata.moduleUrl !, this._styleCompiler.needsStyleShim(compMeta), fileSuffix));
const compiledStylesheet =
this._styleCompiler.compileStyles(outputCtx, compMeta, stylesheetMetadata);
_resolveStyleStatements(
this._symbolResolver, compiledStylesheet, this._styleCompiler.needsStyleShim(compMeta),
fileSuffix);
return this._codegenSourceModule(srcFileUrl, outputCtx);
}
private _codegenSourceModule(srcFileUrl: string, ctx: OutputContext): GeneratedFile {
return new GeneratedFile( return new GeneratedFile(
srcFileUrl, genFileUrl, srcFileUrl, ctx.genFilePath,
this._outputEmitter.emitStatements( this._outputEmitter.emitStatements(
sourceUrl(srcFileUrl), genFileUrl, statements, exportedVars, this._genFilePreamble)); sourceUrl(srcFileUrl), ctx.genFilePath, ctx.statements, this._genFilePreamble));
} }
} }
function _resolveStyleStatements( function _resolveStyleStatements(
reflector: StaticSymbolResolver, compileResult: CompiledStylesheet, symbolResolver: StaticSymbolResolver, compileResult: CompiledStylesheet, needsShim: boolean,
fileSuffix: string): o.Statement[] { fileSuffix: string): void {
compileResult.dependencies.forEach((dep) => { compileResult.dependencies.forEach((dep) => {
dep.valuePlaceholder.reference = reflector.getStaticSymbol( dep.setValue(symbolResolver.getStaticSymbol(
_stylesModuleUrl(dep.moduleUrl, dep.isShimmed, fileSuffix), dep.name); _stylesModuleUrl(dep.moduleUrl, needsShim, fileSuffix), dep.name));
}); });
return compileResult.statements;
} }
function _stylesModuleUrl(stylesheetUrl: string, shim: boolean, suffix: string): string { function _stylesModuleUrl(stylesheetUrl: string, shim: boolean, suffix: string): string {

View File

@ -71,8 +71,7 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
const viewCompiler = new ViewCompiler(config, elementSchemaRegistry); const viewCompiler = new ViewCompiler(config, elementSchemaRegistry);
const compiler = new AotCompiler( const compiler = new AotCompiler(
config, compilerHost, resolver, tmplParser, new StyleCompiler(urlResolver), viewCompiler, config, compilerHost, resolver, tmplParser, new StyleCompiler(urlResolver), viewCompiler,
new NgModuleCompiler(), new TypeScriptEmitter(symbolResolver), summaryResolver, new NgModuleCompiler(), new TypeScriptEmitter(), summaryResolver, options.locale || null,
options.locale || null, options.i18nFormat || null, options.genFilePreamble || null, options.i18nFormat || null, options.genFilePreamble || null, symbolResolver);
symbolResolver);
return {compiler, reflector: staticReflector}; return {compiler, reflector: staticReflector};
} }

View File

@ -8,25 +8,21 @@
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileNgModuleMetadata, CompileNgModuleSummary, CompilePipeMetadata, CompileProviderMetadata, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary} from '../compile_metadata'; import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileNgModuleMetadata, CompileNgModuleSummary, CompilePipeMetadata, CompileProviderMetadata, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary} from '../compile_metadata';
import * as o from '../output/output_ast'; import * as o from '../output/output_ast';
import {Summary, SummaryResolver} from '../summary_resolver'; import {Summary, SummaryResolver} from '../summary_resolver';
import {ValueTransformer, ValueVisitor, visitValue} from '../util'; import {OutputContext, ValueTransformer, ValueVisitor, visitValue} from '../util';
import {StaticSymbol, StaticSymbolCache} from './static_symbol'; import {StaticSymbol, StaticSymbolCache} from './static_symbol';
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver'; import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
import {summaryForJitFileName, summaryForJitName} from './util'; import {summaryForJitFileName, summaryForJitName} from './util';
export function serializeSummaries( export function serializeSummaries(
summaryResolver: SummaryResolver<StaticSymbol>, symbolResolver: StaticSymbolResolver, forJitCtx: OutputContext, summaryResolver: SummaryResolver<StaticSymbol>,
symbols: ResolvedStaticSymbol[], types: { symbolResolver: StaticSymbolResolver, symbols: ResolvedStaticSymbol[], types: {
summary: CompileTypeSummary, summary: CompileTypeSummary,
metadata: CompileNgModuleMetadata | CompileDirectiveMetadata | CompilePipeMetadata | metadata: CompileNgModuleMetadata | CompileDirectiveMetadata | CompilePipeMetadata |
CompileTypeMetadata CompileTypeMetadata
}[]): { }[]): {json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} {
json: string,
exportAs: {symbol: StaticSymbol, exportAs: string}[],
forJit: {statements: o.Statement[], exportedVars: string[]}
} {
const toJsonSerializer = new ToJsonSerializer(symbolResolver, summaryResolver); const toJsonSerializer = new ToJsonSerializer(symbolResolver, summaryResolver);
const forJitSerializer = new ForJitSerializer(symbolResolver); const forJitSerializer = new ForJitSerializer(forJitCtx, symbolResolver);
// for symbols, we use everything except for the class metadata itself // for symbols, we use everything except for the class metadata itself
// (we keep the statics though), as the class metadata is contained in the // (we keep the statics though), as the class metadata is contained in the
@ -81,8 +77,8 @@ export function serializeSummaries(
} }
}); });
const {json, exportAs} = toJsonSerializer.serialize(); const {json, exportAs} = toJsonSerializer.serialize();
const {statements, exportedVars} = forJitSerializer.serialize(exportAs); forJitSerializer.serialize(exportAs);
return {json, forJit: {statements, exportedVars}, exportAs}; return {json, exportAs};
} }
export function deserializeSummaries(symbolCache: StaticSymbolCache, json: string): export function deserializeSummaries(symbolCache: StaticSymbolCache, json: string):
@ -192,7 +188,7 @@ class ForJitSerializer {
isLibrary: boolean isLibrary: boolean
}>(); }>();
constructor(private symbolResolver: StaticSymbolResolver) {} constructor(private outputCtx: OutputContext, private symbolResolver: StaticSymbolResolver) {}
addSourceType( addSourceType(
summary: CompileTypeSummary, metadata: CompileNgModuleMetadata|CompileDirectiveMetadata| summary: CompileTypeSummary, metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|
@ -204,10 +200,7 @@ class ForJitSerializer {
this.data.set(summary.type.reference, {summary, metadata: null, isLibrary: true}); this.data.set(summary.type.reference, {summary, metadata: null, isLibrary: true});
} }
serialize(exportAs: {symbol: StaticSymbol, exportAs: string}[]): serialize(exportAs: {symbol: StaticSymbol, exportAs: string}[]): void {
{statements: o.Statement[], exportedVars: string[]} {
const statements: o.Statement[] = [];
const exportedVars: string[] = [];
const ngModuleSymbols = new Set<StaticSymbol>(); const ngModuleSymbols = new Set<StaticSymbol>();
Array.from(this.data.values()).forEach(({summary, metadata, isLibrary}) => { Array.from(this.data.values()).forEach(({summary, metadata, isLibrary}) => {
@ -222,11 +215,10 @@ class ForJitSerializer {
} }
if (!isLibrary) { if (!isLibrary) {
const fnName = summaryForJitName(summary.type.reference.name); const fnName = summaryForJitName(summary.type.reference.name);
statements.push( this.outputCtx.statements.push(
o.fn([], [new o.ReturnStatement(this.serializeSummaryWithDeps(summary, metadata !))], o.fn([], [new o.ReturnStatement(this.serializeSummaryWithDeps(summary, metadata !))],
new o.ArrayType(o.DYNAMIC_TYPE)) new o.ArrayType(o.DYNAMIC_TYPE))
.toDeclStmt(fnName, [o.StmtModifier.Final])); .toDeclStmt(fnName, [o.StmtModifier.Final, o.StmtModifier.Exported]));
exportedVars.push(fnName);
} }
}); });
@ -234,13 +226,12 @@ class ForJitSerializer {
const symbol = entry.symbol; const symbol = entry.symbol;
if (ngModuleSymbols.has(symbol)) { if (ngModuleSymbols.has(symbol)) {
const jitExportAsName = summaryForJitName(entry.exportAs); const jitExportAsName = summaryForJitName(entry.exportAs);
statements.push( this.outputCtx.statements.push(
o.variable(jitExportAsName).set(this.serializeSummaryRef(symbol)).toDeclStmt()); o.variable(jitExportAsName).set(this.serializeSummaryRef(symbol)).toDeclStmt(null, [
exportedVars.push(jitExportAsName); o.StmtModifier.Exported
]));
} }
}); });
return {statements, exportedVars};
} }
private serializeSummaryWithDeps( private serializeSummaryWithDeps(
@ -283,10 +274,12 @@ class ForJitSerializer {
private serializeSummaryRef(typeSymbol: StaticSymbol): o.Expression { private serializeSummaryRef(typeSymbol: StaticSymbol): o.Expression {
const jitImportedSymbol = this.symbolResolver.getStaticSymbol( const jitImportedSymbol = this.symbolResolver.getStaticSymbol(
summaryForJitFileName(typeSymbol.filePath), summaryForJitName(typeSymbol.name)); summaryForJitFileName(typeSymbol.filePath), summaryForJitName(typeSymbol.name));
return o.importExpr({reference: jitImportedSymbol}); return this.outputCtx.importExpr(jitImportedSymbol);
} }
private serializeSummary(data: {[key: string]: any}): o.Expression { private serializeSummary(data: {[key: string]: any}): o.Expression {
const outputCtx = this.outputCtx;
class Transformer implements ValueVisitor { class Transformer implements ValueVisitor {
visitArray(arr: any[], context: any): any { visitArray(arr: any[], context: any): any {
return o.literalArr(arr.map(entry => visitValue(entry, this, context))); return o.literalArr(arr.map(entry => visitValue(entry, this, context)));
@ -298,7 +291,7 @@ class ForJitSerializer {
visitPrimitive(value: any, context: any): any { return o.literal(value); } visitPrimitive(value: any, context: any): any { return o.literal(value); }
visitOther(value: any, context: any): any { visitOther(value: any, context: any): any {
if (value instanceof StaticSymbol) { if (value instanceof StaticSymbol) {
return o.importExpr({reference: value}); return outputCtx.importExpr(value);
} else { } else {
throw new Error(`Illegal State: Encountered value ${value}`); throw new Error(`Illegal State: Encountered value ${value}`);
} }

View File

@ -59,7 +59,6 @@ export * from './ml_parser/html_tags';
export * from './ml_parser/interpolation_config'; export * from './ml_parser/interpolation_config';
export * from './ml_parser/tags'; export * from './ml_parser/tags';
export {NgModuleCompiler} from './ng_module_compiler'; export {NgModuleCompiler} from './ng_module_compiler';
export * from './output/path_util';
export * from './output/ts_emitter'; export * from './output/ts_emitter';
export * from './parse_util'; export * from './parse_util';
export * from './schema/dom_element_schema_registry'; export * from './schema/dom_element_schema_registry';

View File

@ -286,10 +286,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
args.push(o.literal(ast.strings[ast.strings.length - 1])); args.push(o.literal(ast.strings[ast.strings.length - 1]));
return ast.expressions.length <= 9 ? return ast.expressions.length <= 9 ?
o.importExpr(createIdentifier(Identifiers.inlineInterpolate)).callFn(args) : o.importExpr(Identifiers.inlineInterpolate).callFn(args) :
o.importExpr(createIdentifier(Identifiers.interpolate)).callFn([ o.importExpr(Identifiers.interpolate).callFn([args[0], o.literalArr(args.slice(1))]);
args[0], o.literalArr(args.slice(1))
]);
} }
visitKeyedRead(ast: cdAst.KeyedRead, mode: _Mode): any { visitKeyedRead(ast: cdAst.KeyedRead, mode: _Mode): any {

View File

@ -9,117 +9,129 @@
import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, LOCALE_ID, NgModuleFactory, NgModuleRef, QueryList, Renderer, SecurityContext, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation, ɵCodegenComponentFactoryResolver, ɵEMPTY_ARRAY, ɵEMPTY_MAP, ɵand, ɵccf, ɵcmf, ɵcrt, ɵdid, ɵeld, ɵinlineInterpolate, ɵinterpolate, ɵmod, ɵmpd, ɵncd, ɵnov, ɵpad, ɵpid, ɵpod, ɵppd, ɵprd, ɵqud, ɵreflector, ɵregisterModuleFactory, ɵted, ɵunv, ɵvid} from '@angular/core'; import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, LOCALE_ID, NgModuleFactory, NgModuleRef, QueryList, Renderer, SecurityContext, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation, ɵCodegenComponentFactoryResolver, ɵEMPTY_ARRAY, ɵEMPTY_MAP, ɵand, ɵccf, ɵcmf, ɵcrt, ɵdid, ɵeld, ɵinlineInterpolate, ɵinterpolate, ɵmod, ɵmpd, ɵncd, ɵnov, ɵpad, ɵpid, ɵpod, ɵppd, ɵprd, ɵqud, ɵreflector, ɵregisterModuleFactory, ɵted, ɵunv, ɵvid} from '@angular/core';
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata'; import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
import * as o from './output/output_ast';
const CORE = assetUrl('core'); const CORE = assetUrl('core');
export interface IdentifierSpec {
name: string;
moduleUrl: string;
runtime: any;
}
export class Identifiers { export class Identifiers {
static ANALYZE_FOR_ENTRY_COMPONENTS: IdentifierSpec = { static ANALYZE_FOR_ENTRY_COMPONENTS: o.ExternalReference = {
name: 'ANALYZE_FOR_ENTRY_COMPONENTS', name: 'ANALYZE_FOR_ENTRY_COMPONENTS',
moduleUrl: CORE, moduleName: CORE,
runtime: ANALYZE_FOR_ENTRY_COMPONENTS runtime: ANALYZE_FOR_ENTRY_COMPONENTS
}; };
static ElementRef: IdentifierSpec = {name: 'ElementRef', moduleUrl: CORE, runtime: ElementRef}; static ElementRef:
static NgModuleRef: IdentifierSpec = {name: 'NgModuleRef', moduleUrl: CORE, runtime: NgModuleRef}; o.ExternalReference = {name: 'ElementRef', moduleName: CORE, runtime: ElementRef};
static NgModuleRef:
o.ExternalReference = {name: 'NgModuleRef', moduleName: CORE, runtime: NgModuleRef};
static ViewContainerRef: static ViewContainerRef:
IdentifierSpec = {name: 'ViewContainerRef', moduleUrl: CORE, runtime: ViewContainerRef}; o.ExternalReference = {name: 'ViewContainerRef', moduleName: CORE, runtime: ViewContainerRef};
static ChangeDetectorRef: static ChangeDetectorRef: o.ExternalReference = {
IdentifierSpec = {name: 'ChangeDetectorRef', moduleUrl: CORE, runtime: ChangeDetectorRef}; name: 'ChangeDetectorRef',
static QueryList: IdentifierSpec = {name: 'QueryList', moduleUrl: CORE, runtime: QueryList}; moduleName: CORE,
static TemplateRef: IdentifierSpec = {name: 'TemplateRef', moduleUrl: CORE, runtime: TemplateRef}; runtime: ChangeDetectorRef
static CodegenComponentFactoryResolver: IdentifierSpec = { };
static QueryList: o.ExternalReference = {name: 'QueryList', moduleName: CORE, runtime: QueryList};
static TemplateRef:
o.ExternalReference = {name: 'TemplateRef', moduleName: CORE, runtime: TemplateRef};
static CodegenComponentFactoryResolver: o.ExternalReference = {
name: 'ɵCodegenComponentFactoryResolver', name: 'ɵCodegenComponentFactoryResolver',
moduleUrl: CORE, moduleName: CORE,
runtime: ɵCodegenComponentFactoryResolver runtime: ɵCodegenComponentFactoryResolver
}; };
static ComponentFactoryResolver: IdentifierSpec = { static ComponentFactoryResolver: o.ExternalReference = {
name: 'ComponentFactoryResolver', name: 'ComponentFactoryResolver',
moduleUrl: CORE, moduleName: CORE,
runtime: ComponentFactoryResolver runtime: ComponentFactoryResolver
}; };
static ComponentFactory: static ComponentFactory:
IdentifierSpec = {name: 'ComponentFactory', moduleUrl: CORE, runtime: ComponentFactory}; o.ExternalReference = {name: 'ComponentFactory', moduleName: CORE, runtime: ComponentFactory};
static ComponentRef: static ComponentRef:
IdentifierSpec = {name: 'ComponentRef', moduleUrl: CORE, runtime: ComponentRef}; o.ExternalReference = {name: 'ComponentRef', moduleName: CORE, runtime: ComponentRef};
static NgModuleFactory: static NgModuleFactory:
IdentifierSpec = {name: 'NgModuleFactory', moduleUrl: CORE, runtime: NgModuleFactory}; o.ExternalReference = {name: 'NgModuleFactory', moduleName: CORE, runtime: NgModuleFactory};
static createModuleFactory: IdentifierSpec = { static createModuleFactory: o.ExternalReference = {
name: 'ɵcmf', name: 'ɵcmf',
moduleUrl: CORE, moduleName: CORE,
runtime: ɵcmf, runtime: ɵcmf,
}; };
static moduleDef: IdentifierSpec = { static moduleDef: o.ExternalReference = {
name: 'ɵmod', name: 'ɵmod',
moduleUrl: CORE, moduleName: CORE,
runtime: ɵmod, runtime: ɵmod,
}; };
static moduleProviderDef: IdentifierSpec = { static moduleProviderDef: o.ExternalReference = {
name: 'ɵmpd', name: 'ɵmpd',
moduleUrl: CORE, moduleName: CORE,
runtime: ɵmpd, runtime: ɵmpd,
}; };
static RegisterModuleFactoryFn: IdentifierSpec = { static RegisterModuleFactoryFn: o.ExternalReference = {
name: 'ɵregisterModuleFactory', name: 'ɵregisterModuleFactory',
moduleUrl: CORE, moduleName: CORE,
runtime: ɵregisterModuleFactory, runtime: ɵregisterModuleFactory,
}; };
static Injector: IdentifierSpec = {name: 'Injector', moduleUrl: CORE, runtime: Injector}; static Injector: o.ExternalReference = {name: 'Injector', moduleName: CORE, runtime: Injector};
static ViewEncapsulation: static ViewEncapsulation: o.ExternalReference = {
IdentifierSpec = {name: 'ViewEncapsulation', moduleUrl: CORE, runtime: ViewEncapsulation}; name: 'ViewEncapsulation',
static ChangeDetectionStrategy: IdentifierSpec = { moduleName: CORE,
runtime: ViewEncapsulation
};
static ChangeDetectionStrategy: o.ExternalReference = {
name: 'ChangeDetectionStrategy', name: 'ChangeDetectionStrategy',
moduleUrl: CORE, moduleName: CORE,
runtime: ChangeDetectionStrategy runtime: ChangeDetectionStrategy
}; };
static SecurityContext: IdentifierSpec = { static SecurityContext: o.ExternalReference = {
name: 'SecurityContext', name: 'SecurityContext',
moduleUrl: CORE, moduleName: CORE,
runtime: SecurityContext, runtime: SecurityContext,
}; };
static LOCALE_ID: IdentifierSpec = {name: 'LOCALE_ID', moduleUrl: CORE, runtime: LOCALE_ID}; static LOCALE_ID: o.ExternalReference = {name: 'LOCALE_ID', moduleName: CORE, runtime: LOCALE_ID};
static TRANSLATIONS_FORMAT: static TRANSLATIONS_FORMAT: o.ExternalReference = {
IdentifierSpec = {name: 'TRANSLATIONS_FORMAT', moduleUrl: CORE, runtime: TRANSLATIONS_FORMAT}; name: 'TRANSLATIONS_FORMAT',
static inlineInterpolate: moduleName: CORE,
IdentifierSpec = {name: 'ɵinlineInterpolate', moduleUrl: CORE, runtime: ɵinlineInterpolate}; runtime: TRANSLATIONS_FORMAT
};
static inlineInterpolate: o.ExternalReference = {
name: 'ɵinlineInterpolate',
moduleName: CORE,
runtime: ɵinlineInterpolate
};
static interpolate: static interpolate:
IdentifierSpec = {name: 'ɵinterpolate', moduleUrl: CORE, runtime: ɵinterpolate}; o.ExternalReference = {name: 'ɵinterpolate', moduleName: CORE, runtime: ɵinterpolate};
static EMPTY_ARRAY: static EMPTY_ARRAY:
IdentifierSpec = {name: 'ɵEMPTY_ARRAY', moduleUrl: CORE, runtime: ɵEMPTY_ARRAY}; o.ExternalReference = {name: 'ɵEMPTY_ARRAY', moduleName: CORE, runtime: ɵEMPTY_ARRAY};
static EMPTY_MAP: IdentifierSpec = {name: 'ɵEMPTY_MAP', moduleUrl: CORE, runtime: ɵEMPTY_MAP}; static EMPTY_MAP:
static Renderer: IdentifierSpec = {name: 'Renderer', moduleUrl: CORE, runtime: Renderer}; o.ExternalReference = {name: 'ɵEMPTY_MAP', moduleName: CORE, runtime: ɵEMPTY_MAP};
static viewDef: IdentifierSpec = {name: 'ɵvid', moduleUrl: CORE, runtime: ɵvid}; static Renderer: o.ExternalReference = {name: 'Renderer', moduleName: CORE, runtime: Renderer};
static elementDef: IdentifierSpec = {name: 'ɵeld', moduleUrl: CORE, runtime: ɵeld}; static viewDef: o.ExternalReference = {name: 'ɵvid', moduleName: CORE, runtime: ɵvid};
static anchorDef: IdentifierSpec = {name: 'ɵand', moduleUrl: CORE, runtime: ɵand}; static elementDef: o.ExternalReference = {name: 'ɵeld', moduleName: CORE, runtime: ɵeld};
static textDef: IdentifierSpec = {name: 'ɵted', moduleUrl: CORE, runtime: ɵted}; static anchorDef: o.ExternalReference = {name: 'ɵand', moduleName: CORE, runtime: ɵand};
static directiveDef: IdentifierSpec = {name: 'ɵdid', moduleUrl: CORE, runtime: ɵdid}; static textDef: o.ExternalReference = {name: 'ɵted', moduleName: CORE, runtime: ɵted};
static providerDef: IdentifierSpec = {name: 'ɵprd', moduleUrl: CORE, runtime: ɵprd}; static directiveDef: o.ExternalReference = {name: 'ɵdid', moduleName: CORE, runtime: ɵdid};
static queryDef: IdentifierSpec = {name: 'ɵqud', moduleUrl: CORE, runtime: ɵqud}; static providerDef: o.ExternalReference = {name: 'ɵprd', moduleName: CORE, runtime: ɵprd};
static pureArrayDef: IdentifierSpec = {name: 'ɵpad', moduleUrl: CORE, runtime: ɵpad}; static queryDef: o.ExternalReference = {name: 'ɵqud', moduleName: CORE, runtime: ɵqud};
static pureObjectDef: IdentifierSpec = {name: 'ɵpod', moduleUrl: CORE, runtime: ɵpod}; static pureArrayDef: o.ExternalReference = {name: 'ɵpad', moduleName: CORE, runtime: ɵpad};
static purePipeDef: IdentifierSpec = {name: 'ɵppd', moduleUrl: CORE, runtime: ɵppd}; static pureObjectDef: o.ExternalReference = {name: 'ɵpod', moduleName: CORE, runtime: ɵpod};
static pipeDef: IdentifierSpec = {name: 'ɵpid', moduleUrl: CORE, runtime: ɵpid}; static purePipeDef: o.ExternalReference = {name: 'ɵppd', moduleName: CORE, runtime: ɵppd};
static nodeValue: IdentifierSpec = {name: 'ɵnov', moduleUrl: CORE, runtime: ɵnov}; static pipeDef: o.ExternalReference = {name: 'ɵpid', moduleName: CORE, runtime: ɵpid};
static ngContentDef: IdentifierSpec = {name: 'ɵncd', moduleUrl: CORE, runtime: ɵncd}; static nodeValue: o.ExternalReference = {name: 'ɵnov', moduleName: CORE, runtime: ɵnov};
static unwrapValue: IdentifierSpec = {name: 'ɵunv', moduleUrl: CORE, runtime: ɵunv}; static ngContentDef: o.ExternalReference = {name: 'ɵncd', moduleName: CORE, runtime: ɵncd};
static createRendererType2: IdentifierSpec = {name: 'ɵcrt', moduleUrl: CORE, runtime: ɵcrt}; static unwrapValue: o.ExternalReference = {name: 'ɵunv', moduleName: CORE, runtime: ɵunv};
static RendererType2: IdentifierSpec = { static createRendererType2: o.ExternalReference = {name: 'ɵcrt', moduleName: CORE, runtime: ɵcrt};
static RendererType2: o.ExternalReference = {
name: 'RendererType2', name: 'RendererType2',
moduleUrl: CORE, moduleName: CORE,
// type only // type only
runtime: null runtime: null
}; };
static ViewDefinition: IdentifierSpec = { static ViewDefinition: o.ExternalReference = {
name: 'ɵViewDefinition', name: 'ɵViewDefinition',
moduleUrl: CORE, moduleName: CORE,
// type only // type only
runtime: null runtime: null
}; };
static createComponentFactory: IdentifierSpec = {name: 'ɵccf', moduleUrl: CORE, runtime: ɵccf}; static createComponentFactory:
o.ExternalReference = {name: 'ɵccf', moduleName: CORE, runtime: ɵccf};
} }
export function assetUrl(pkg: string, path: string | null = null, type: string = 'src'): string { export function assetUrl(pkg: string, path: string | null = null, type: string = 'src'): string {
@ -130,12 +142,12 @@ export function assetUrl(pkg: string, path: string | null = null, type: string =
} }
} }
export function resolveIdentifier(identifier: IdentifierSpec) { export function resolveIdentifier(identifier: o.ExternalReference) {
let name = identifier.name; let name = identifier.name;
return ɵreflector.resolveIdentifier(name, identifier.moduleUrl, null, identifier.runtime); return ɵreflector.resolveIdentifier(name !, identifier.moduleName !, null, identifier.runtime);
} }
export function createIdentifier(identifier: IdentifierSpec): CompileIdentifierMetadata { export function createIdentifier(identifier: o.ExternalReference): CompileIdentifierMetadata {
return {reference: resolveIdentifier(identifier)}; return {reference: resolveIdentifier(identifier)};
} }
@ -143,12 +155,12 @@ export function identifierToken(identifier: CompileIdentifierMetadata): CompileT
return {identifier: identifier}; return {identifier: identifier};
} }
export function createIdentifierToken(identifier: IdentifierSpec): CompileTokenMetadata { export function createIdentifierToken(identifier: o.ExternalReference): CompileTokenMetadata {
return identifierToken(createIdentifier(identifier)); return identifierToken(createIdentifier(identifier));
} }
export function createEnumIdentifier( export function createEnumIdentifier(
enumType: IdentifierSpec, name: string): CompileIdentifierMetadata { enumType: o.ExternalReference, name: string): CompileIdentifierMetadata {
const resolvedEnum = ɵreflector.resolveEnum(resolveIdentifier(enumType), name); const resolvedEnum = ɵreflector.resolveEnum(resolveIdentifier(enumType), name);
return {reference: resolvedEnum}; return {reference: resolvedEnum};
} }

View File

@ -19,7 +19,7 @@ import {jitStatements} from '../output/output_jit';
import {CompiledStylesheet, StyleCompiler} from '../style_compiler'; import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
import {SummaryResolver} from '../summary_resolver'; import {SummaryResolver} from '../summary_resolver';
import {TemplateParser} from '../template_parser/template_parser'; import {TemplateParser} from '../template_parser/template_parser';
import {SyncAsyncResult} from '../util'; import {OutputContext, SyncAsyncResult} from '../util';
import {ViewCompiler} from '../view_compiler/view_compiler'; import {ViewCompiler} from '../view_compiler/view_compiler';
@ -153,14 +153,14 @@ export class JitCompiler implements Compiler {
// Always provide a bound Compiler // Always provide a bound Compiler
const extraProviders = [this._metadataResolver.getProviderMetadata(new ProviderMeta( const extraProviders = [this._metadataResolver.getProviderMetadata(new ProviderMeta(
Compiler, {useFactory: () => new ModuleBoundCompiler(this, moduleMeta.type.reference)}))]; Compiler, {useFactory: () => new ModuleBoundCompiler(this, moduleMeta.type.reference)}))];
const compileResult = this._ngModuleCompiler.compile(moduleMeta, extraProviders); const outputCtx = createOutputContext();
const compileResult = this._ngModuleCompiler.compile(outputCtx, moduleMeta, extraProviders);
if (!this._compilerConfig.useJit) { if (!this._compilerConfig.useJit) {
ngModuleFactory = ngModuleFactory =
interpretStatements(compileResult.statements, [compileResult.ngModuleFactoryVar])[0]; interpretStatements(outputCtx.statements)[compileResult.ngModuleFactoryVar];
} else { } else {
ngModuleFactory = jitStatements( ngModuleFactory = jitStatements(
ngModuleJitUrl(moduleMeta), compileResult.statements, ngModuleJitUrl(moduleMeta), outputCtx.statements, )[compileResult.ngModuleFactoryVar];
[compileResult.ngModuleFactoryVar])[0];
} }
this._compiledNgModuleCache.set(moduleMeta.type.reference, ngModuleFactory); this._compiledNgModuleCache.set(moduleMeta.type.reference, ngModuleFactory);
} }
@ -272,11 +272,14 @@ export class JitCompiler implements Compiler {
} }
const compMeta = template.compMeta; const compMeta = template.compMeta;
const externalStylesheetsByModuleUrl = new Map<string, CompiledStylesheet>(); const externalStylesheetsByModuleUrl = new Map<string, CompiledStylesheet>();
const stylesCompileResult = this._styleCompiler.compileComponent(compMeta); const outputContext = createOutputContext();
stylesCompileResult.externalStylesheets.forEach( const componentStylesheet = this._styleCompiler.compileComponent(outputContext, compMeta);
(r) => { externalStylesheetsByModuleUrl.set(r.meta.moduleUrl !, r); }); compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => {
this._resolveStylesCompileResult( const compiledStylesheet =
stylesCompileResult.componentStylesheet, externalStylesheetsByModuleUrl); this._styleCompiler.compileStyles(createOutputContext(), compMeta, stylesheetMeta);
externalStylesheetsByModuleUrl.set(stylesheetMeta.moduleUrl !, compiledStylesheet);
});
this._resolveStylesCompileResult(componentStylesheet, externalStylesheetsByModuleUrl);
const directives = const directives =
template.directives.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference)); template.directives.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
const pipes = template.ngModule.transitiveModule.pipes.map( const pipes = template.ngModule.transitiveModule.pipes.map(
@ -285,22 +288,17 @@ export class JitCompiler implements Compiler {
compMeta, compMeta.template !.template !, directives, pipes, template.ngModule.schemas, compMeta, compMeta.template !.template !, directives, pipes, template.ngModule.schemas,
templateSourceUrl(template.ngModule.type, template.compMeta, template.compMeta.template !)); templateSourceUrl(template.ngModule.type, template.compMeta, template.compMeta.template !));
const compileResult = this._viewCompiler.compileComponent( const compileResult = this._viewCompiler.compileComponent(
compMeta, parsedTemplate, ir.variable(stylesCompileResult.componentStylesheet.stylesVar), outputContext, compMeta, parsedTemplate, ir.variable(componentStylesheet.stylesVar),
usedPipes); usedPipes);
const statements = let evalResult: any;
stylesCompileResult.componentStylesheet.statements.concat(compileResult.statements);
let viewClassAndRendererTypeVars = compMeta.isHost ?
[compileResult.viewClassVar] :
[compileResult.viewClassVar, compileResult.rendererTypeVar];
let viewClass: any;
let rendererType: any;
if (!this._compilerConfig.useJit) { if (!this._compilerConfig.useJit) {
[viewClass, rendererType] = interpretStatements(statements, viewClassAndRendererTypeVars); evalResult = interpretStatements(outputContext.statements);
} else { } else {
[viewClass, rendererType] = jitStatements( evalResult = jitStatements(
templateJitUrl(template.ngModule.type, template.compMeta), statements, templateJitUrl(template.ngModule.type, template.compMeta), outputContext.statements);
viewClassAndRendererTypeVars);
} }
const viewClass = evalResult[compileResult.viewClassVar];
const rendererType = evalResult[compileResult.rendererTypeVar];
template.compiled(viewClass, rendererType); template.compiled(viewClass, rendererType);
} }
@ -310,7 +308,7 @@ export class JitCompiler implements Compiler {
const nestedCompileResult = externalStylesheetsByModuleUrl.get(dep.moduleUrl) !; const nestedCompileResult = externalStylesheetsByModuleUrl.get(dep.moduleUrl) !;
const nestedStylesArr = this._resolveAndEvalStylesCompileResult( const nestedStylesArr = this._resolveAndEvalStylesCompileResult(
nestedCompileResult, externalStylesheetsByModuleUrl); nestedCompileResult, externalStylesheetsByModuleUrl);
dep.valuePlaceholder.reference = nestedStylesArr; dep.setValue(nestedStylesArr);
}); });
} }
@ -319,11 +317,11 @@ export class JitCompiler implements Compiler {
externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>): string[] { externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>): string[] {
this._resolveStylesCompileResult(result, externalStylesheetsByModuleUrl); this._resolveStylesCompileResult(result, externalStylesheetsByModuleUrl);
if (!this._compilerConfig.useJit) { if (!this._compilerConfig.useJit) {
return interpretStatements(result.statements, [result.stylesVar])[0]; return interpretStatements(result.outputCtx.statements)[result.stylesVar];
} else { } else {
return jitStatements( return jitStatements(
sharedStylesheetJitUrl(result.meta, this._sharedStylesheetCount++), result.statements, sharedStylesheetJitUrl(result.meta, this._sharedStylesheetCount++),
[result.stylesVar])[0]; result.outputCtx.statements)[result.stylesVar];
} }
} }
} }
@ -404,3 +402,9 @@ function flattenSummaries(fn: () => any[], out: CompileTypeSummary[] = []): Comp
}); });
return out; return out;
} }
function createOutputContext(): OutputContext {
const importExpr = (symbol: any) =>
ir.importExpr({name: identifierName(symbol), moduleName: null, runtime: symbol});
return {statements: [], genFilePath: '', importExpr};
}

View File

@ -14,58 +14,61 @@ import {CompilerInjectable} from './injectable';
import * as o from './output/output_ast'; import * as o from './output/output_ast';
import {typeSourceSpan} from './parse_util'; import {typeSourceSpan} from './parse_util';
import {NgModuleProviderAnalyzer} from './provider_analyzer'; import {NgModuleProviderAnalyzer} from './provider_analyzer';
import {OutputContext} from './util';
import {componentFactoryResolverProviderDef, depDef, providerDef} from './view_compiler/provider_compiler'; import {componentFactoryResolverProviderDef, depDef, providerDef} from './view_compiler/provider_compiler';
export class NgModuleCompileResult { export class NgModuleCompileResult {
constructor(public statements: o.Statement[], public ngModuleFactoryVar: string) {} constructor(public ngModuleFactoryVar: string) {}
} }
const LOG_VAR = o.variable('_l'); const LOG_VAR = o.variable('_l');
@CompilerInjectable() @CompilerInjectable()
export class NgModuleCompiler { export class NgModuleCompiler {
compile(ngModuleMeta: CompileNgModuleMetadata, extraProviders: CompileProviderMetadata[]): compile(
NgModuleCompileResult { ctx: OutputContext, ngModuleMeta: CompileNgModuleMetadata,
extraProviders: CompileProviderMetadata[]): NgModuleCompileResult {
const sourceSpan = typeSourceSpan('NgModule', ngModuleMeta.type); const sourceSpan = typeSourceSpan('NgModule', ngModuleMeta.type);
const entryComponentFactories = ngModuleMeta.transitiveModule.entryComponents; const entryComponentFactories = ngModuleMeta.transitiveModule.entryComponents;
const bootstrapComponents = ngModuleMeta.bootstrapComponents; const bootstrapComponents = ngModuleMeta.bootstrapComponents;
const providerParser = new NgModuleProviderAnalyzer(ngModuleMeta, extraProviders, sourceSpan); const providerParser = new NgModuleProviderAnalyzer(ngModuleMeta, extraProviders, sourceSpan);
const providerDefs = const providerDefs =
[componentFactoryResolverProviderDef(NodeFlags.None, entryComponentFactories)] [componentFactoryResolverProviderDef(ctx, NodeFlags.None, entryComponentFactories)]
.concat(providerParser.parse().map((provider) => providerDef(provider))) .concat(providerParser.parse().map((provider) => providerDef(ctx, provider)))
.map(({providerExpr, depsExpr, flags, tokenExpr}) => { .map(({providerExpr, depsExpr, flags, tokenExpr}) => {
return o.importExpr(createIdentifier(Identifiers.moduleProviderDef)).callFn([ return o.importExpr(Identifiers.moduleProviderDef).callFn([
o.literal(flags), tokenExpr, providerExpr, depsExpr o.literal(flags), tokenExpr, providerExpr, depsExpr
]); ]);
}); });
const ngModuleDef = const ngModuleDef = o.importExpr(Identifiers.moduleDef).callFn([o.literalArr(providerDefs)]);
o.importExpr(createIdentifier(Identifiers.moduleDef)).callFn([o.literalArr(providerDefs)]);
const ngModuleDefFactory = o.fn( const ngModuleDefFactory = o.fn(
[new o.FnParam(LOG_VAR.name !)], [new o.ReturnStatement(ngModuleDef)], o.INFERRED_TYPE); [new o.FnParam(LOG_VAR.name !)], [new o.ReturnStatement(ngModuleDef)], o.INFERRED_TYPE);
const ngModuleFactoryVar = `${identifierName(ngModuleMeta.type)}NgFactory`; const ngModuleFactoryVar = `${identifierName(ngModuleMeta.type)}NgFactory`;
const ngModuleFactoryStmt = const ngModuleFactoryStmt =
o.variable(ngModuleFactoryVar) o.variable(ngModuleFactoryVar)
.set(o.importExpr(createIdentifier(Identifiers.createModuleFactory)).callFn([ .set(o.importExpr(Identifiers.createModuleFactory).callFn([
o.importExpr(ngModuleMeta.type), ctx.importExpr(ngModuleMeta.type.reference),
o.literalArr(bootstrapComponents.map(id => o.importExpr(id))), ngModuleDefFactory o.literalArr(bootstrapComponents.map(id => ctx.importExpr(id.reference))),
ngModuleDefFactory
])) ]))
.toDeclStmt( .toDeclStmt(
o.importType( o.importType(
createIdentifier(Identifiers.NgModuleFactory), Identifiers.NgModuleFactory,
[o.importType(ngModuleMeta.type) !], [o.TypeModifier.Const]), [o.expressionType(ctx.importExpr(ngModuleMeta.type.reference)) !],
[o.StmtModifier.Final]); [o.TypeModifier.Const]),
[o.StmtModifier.Final, o.StmtModifier.Exported]);
const stmts: o.Statement[] = [ngModuleFactoryStmt]; ctx.statements.push(ngModuleFactoryStmt);
if (ngModuleMeta.id) { if (ngModuleMeta.id) {
const registerFactoryStmt = const registerFactoryStmt =
o.importExpr(createIdentifier(Identifiers.RegisterModuleFactoryFn)) o.importExpr(Identifiers.RegisterModuleFactoryFn)
.callFn([o.literal(ngModuleMeta.id), o.variable(ngModuleFactoryVar)]) .callFn([o.literal(ngModuleMeta.id), o.variable(ngModuleFactoryVar)])
.toStmt(); .toStmt();
stmts.push(registerFactoryStmt); ctx.statements.push(registerFactoryStmt);
} }
return new NgModuleCompileResult(stmts, ngModuleFactoryVar); return new NgModuleCompileResult(ngModuleFactoryVar);
} }
} }

View File

@ -19,7 +19,7 @@ export const CATCH_STACK_VAR = o.variable('stack', null, null);
export abstract class OutputEmitter { export abstract class OutputEmitter {
abstract emitStatements( abstract emitStatements(
srcFilePath: string, genFilePath: string, stmts: o.Statement[], exportedVars: string[], srcFilePath: string, genFilePath: string, stmts: o.Statement[],
preamble?: string|null): string; preamble?: string|null): string;
} }
@ -31,21 +31,15 @@ class _EmittedLine {
} }
export class EmitterVisitorContext { export class EmitterVisitorContext {
static createRoot(exportedVars: string[]): EmitterVisitorContext { static createRoot(): EmitterVisitorContext { return new EmitterVisitorContext(0); }
return new EmitterVisitorContext(exportedVars, 0);
}
private _lines: _EmittedLine[]; private _lines: _EmittedLine[];
private _classes: o.ClassStmt[] = []; private _classes: o.ClassStmt[] = [];
constructor(private _exportedVars: string[], private _indent: number) { constructor(private _indent: number) { this._lines = [new _EmittedLine(_indent)]; }
this._lines = [new _EmittedLine(_indent)];
}
private get _currentLine(): _EmittedLine { return this._lines[this._lines.length - 1]; } private get _currentLine(): _EmittedLine { return this._lines[this._lines.length - 1]; }
isExportedVar(varName: string): boolean { return this._exportedVars.indexOf(varName) !== -1; }
println(from?: {sourceSpan: ParseSourceSpan | null}|null, lastPart: string = ''): void { println(from?: {sourceSpan: ParseSourceSpan | null}|null, lastPart: string = ''): void {
this.print(from || null, lastPart, true); this.print(from || null, lastPart, true);
} }

View File

@ -1,65 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ParseSourceSpan} from '../parse_util';
import * as o from './output_ast';
/**
* Create a new class stmts based on the given data.
*/
export function createClassStmt(config: {
name: string,
parent?: o.Expression,
parentArgs?: o.Expression[],
ctorParams?: o.FnParam[],
builders: ClassBuilderPart | ClassBuilderPart[],
modifiers?: o.StmtModifier[],
sourceSpan?: ParseSourceSpan
}): o.ClassStmt {
const parentArgs = config.parentArgs || [];
const superCtorStmts = config.parent ? [o.SUPER_EXPR.callFn(parentArgs).toStmt()] : [];
const builder =
concatClassBuilderParts(Array.isArray(config.builders) ? config.builders : [config.builders]);
const ctor =
new o.ClassMethod(null, config.ctorParams || [], superCtorStmts.concat(builder.ctorStmts));
return new o.ClassStmt(
config.name, config.parent || null, builder.fields, builder.getters, ctor, builder.methods,
config.modifiers || [], config.sourceSpan);
}
function concatClassBuilderParts(builders: ClassBuilderPart[]) {
return {
fields: [].concat(...(builders.map((builder => builder.fields || [])) as any)),
methods: [].concat(...(builders.map(builder => builder.methods || []) as any)),
getters: [].concat(...(builders.map(builder => builder.getters || []) as any)),
ctorStmts: [].concat(...(builders.map(builder => builder.ctorStmts || []) as any)),
};
}
/**
* Collects data for a generated class.
*/
export interface ClassBuilderPart {
fields?: o.ClassField[];
methods?: o.ClassMethod[];
getters?: o.ClassGetter[];
ctorStmts?: o.Statement[];
}
/**
* Collects data for a generated class.
*/
export interface ClassBuilder {
fields: o.ClassField[];
methods: o.ClassMethod[];
getters: o.ClassGetter[];
ctorStmts: o.Statement[];
}

View File

@ -13,24 +13,21 @@ import {CompileIdentifierMetadata} from '../compile_metadata';
import {EmitterVisitorContext, OutputEmitter} from './abstract_emitter'; import {EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
import {AbstractJsEmitterVisitor} from './abstract_js_emitter'; import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
import * as o from './output_ast'; import * as o from './output_ast';
import {ImportResolver} from './path_util';
export class JavaScriptEmitter implements OutputEmitter { export class JavaScriptEmitter implements OutputEmitter {
constructor(private _importResolver: ImportResolver) {}
emitStatements( emitStatements(
srcFilePath: string, genFilePath: string, stmts: o.Statement[], exportedVars: string[], srcFilePath: string, genFilePath: string, stmts: o.Statement[],
preamble: string = ''): string { preamble: string = ''): string {
const converter = new JsEmitterVisitor(genFilePath, this._importResolver); const converter = new JsEmitterVisitor();
const ctx = EmitterVisitorContext.createRoot(exportedVars); const ctx = EmitterVisitorContext.createRoot();
converter.visitAllStatements(stmts, ctx); converter.visitAllStatements(stmts, ctx);
const preambleLines = preamble ? preamble.split('\n') : []; const preambleLines = preamble ? preamble.split('\n') : [];
converter.importsWithPrefixes.forEach((prefix, importedFilePath) => { converter.importsWithPrefixes.forEach((prefix, importedModuleName) => {
// Note: can't write the real word for import as it screws up system.js auto detection... // Note: can't write the real word for import as it screws up system.js auto detection...
preambleLines.push( preambleLines.push(
`var ${prefix} = req` + `var ${prefix} = req` +
`uire('${this._importResolver.fileNameToModuleName(importedFilePath, genFilePath)}');`); `uire('${importedModuleName}');`);
}); });
const sm = const sm =
@ -47,46 +44,36 @@ export class JavaScriptEmitter implements OutputEmitter {
class JsEmitterVisitor extends AbstractJsEmitterVisitor { class JsEmitterVisitor extends AbstractJsEmitterVisitor {
importsWithPrefixes = new Map<string, string>(); importsWithPrefixes = new Map<string, string>();
constructor(private _genFilePath: string, private _importResolver: ImportResolver) { super(); }
private _resolveStaticSymbol(value: CompileIdentifierMetadata): StaticSymbol {
const reference = value.reference;
if (!(reference instanceof StaticSymbol)) {
throw new Error(`Internal error: unknown identifier ${JSON.stringify(value)}`);
}
return this._importResolver.getImportAs(reference) || reference;
}
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any { visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
const {name, filePath} = this._resolveStaticSymbol(ast.value); const {name, moduleName} = ast.value;
if (filePath != this._genFilePath) { if (moduleName) {
let prefix = this.importsWithPrefixes.get(filePath); let prefix = this.importsWithPrefixes.get(moduleName);
if (prefix == null) { if (prefix == null) {
prefix = `i${this.importsWithPrefixes.size}`; prefix = `i${this.importsWithPrefixes.size}`;
this.importsWithPrefixes.set(filePath, prefix); this.importsWithPrefixes.set(moduleName, prefix);
} }
ctx.print(ast, `${prefix}.`); ctx.print(ast, `${prefix}.`);
} }
ctx.print(ast, name); ctx.print(ast, name !);
return null; return null;
} }
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any { visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
super.visitDeclareVarStmt(stmt, ctx); super.visitDeclareVarStmt(stmt, ctx);
if (ctx.isExportedVar(stmt.name)) { if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.println(stmt, exportVar(stmt.name)); ctx.println(stmt, exportVar(stmt.name));
} }
return null; return null;
} }
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any { visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any {
super.visitDeclareFunctionStmt(stmt, ctx); super.visitDeclareFunctionStmt(stmt, ctx);
if (ctx.isExportedVar(stmt.name)) { if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.println(stmt, exportVar(stmt.name)); ctx.println(stmt, exportVar(stmt.name));
} }
return null; return null;
} }
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any { visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
super.visitDeclareClassStmt(stmt, ctx); super.visitDeclareClassStmt(stmt, ctx);
if (ctx.isExportedVar(stmt.name)) { if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.println(stmt, exportVar(stmt.name)); ctx.println(stmt, exportVar(stmt.name));
} }
return null; return null;

View File

@ -7,7 +7,6 @@
*/ */
import {CompileIdentifierMetadata} from '../compile_metadata';
import {ParseSourceSpan} from '../parse_util'; import {ParseSourceSpan} from '../parse_util';
//// Types //// Types
@ -344,8 +343,8 @@ export class LiteralExpr extends Expression {
export class ExternalExpr extends Expression { export class ExternalExpr extends Expression {
constructor( constructor(
public value: CompileIdentifierMetadata, type?: Type|null, public value: ExternalReference, type?: Type|null, public typeParams: Type[]|null = null,
public typeParams: Type[]|null = null, sourceSpan?: ParseSourceSpan|null) { sourceSpan?: ParseSourceSpan|null) {
super(type, sourceSpan); super(type, sourceSpan);
} }
visitExpression(visitor: ExpressionVisitor, context: any): any { visitExpression(visitor: ExpressionVisitor, context: any): any {
@ -353,6 +352,9 @@ export class ExternalExpr extends Expression {
} }
} }
export class ExternalReference {
constructor(public moduleName: string|null, public name: string|null, public runtime: any|null) {}
}
export class ConditionalExpr extends Expression { export class ConditionalExpr extends Expression {
public trueCase: Expression; public trueCase: Expression;
@ -533,7 +535,8 @@ export const TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null);
//// Statements //// Statements
export enum StmtModifier { export enum StmtModifier {
Final, Final,
Private Private,
Exported
} }
export abstract class Statement { export abstract class Statement {
@ -1125,13 +1128,13 @@ export function variable(
} }
export function importExpr( export function importExpr(
id: CompileIdentifierMetadata, typeParams: Type[] | null = null, id: ExternalReference, typeParams: Type[] | null = null,
sourceSpan?: ParseSourceSpan | null): ExternalExpr { sourceSpan?: ParseSourceSpan | null): ExternalExpr {
return new ExternalExpr(id, null, typeParams, sourceSpan); return new ExternalExpr(id, null, typeParams, sourceSpan);
} }
export function importType( export function importType(
id: CompileIdentifierMetadata, typeParams: Type[] | null = null, id: ExternalReference, typeParams: Type[] | null = null,
typeModifiers: TypeModifier[] | null = null): ExpressionType|null { typeModifiers: TypeModifier[] | null = null): ExpressionType|null {
return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null; return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null;
} }

View File

@ -11,13 +11,13 @@
import * as o from './output_ast'; import * as o from './output_ast';
import {debugOutputAstAsTypeScript} from './ts_emitter'; import {debugOutputAstAsTypeScript} from './ts_emitter';
export function interpretStatements(statements: o.Statement[], resultVars: string[]): any[] { export function interpretStatements(statements: o.Statement[]): {[key: string]: any} {
const stmtsWithReturn = statements.concat(
[new o.ReturnStatement(o.literalArr(resultVars.map(resultVar => o.variable(resultVar))))]);
const ctx = new _ExecutionContext(null, null, null, new Map<string, any>()); const ctx = new _ExecutionContext(null, null, null, new Map<string, any>());
const visitor = new StatementInterpreter(); const visitor = new StatementInterpreter();
const result = visitor.visitAllStatements(stmtsWithReturn, ctx); visitor.visitAllStatements(statements, ctx);
return result != null ? result.value : null; const result: {[key: string]: any} = {};
ctx.exports.forEach((exportName) => { result[exportName] = ctx.vars.get(exportName); });
return result;
} }
function _executeFunctionStatements( function _executeFunctionStatements(
@ -32,6 +32,8 @@ function _executeFunctionStatements(
} }
class _ExecutionContext { class _ExecutionContext {
exports: string[] = [];
constructor( constructor(
public parent: _ExecutionContext|null, public instance: any, public className: string|null, public parent: _ExecutionContext|null, public instance: any, public className: string|null,
public vars: Map<string, any>) {} public vars: Map<string, any>) {}
@ -90,6 +92,9 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: _ExecutionContext): any { visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: _ExecutionContext): any {
ctx.vars.set(stmt.name, stmt.value.visitExpression(this, ctx)); ctx.vars.set(stmt.name, stmt.value.visitExpression(this, ctx));
if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.exports.push(stmt.name);
}
return null; return null;
} }
visitWriteVarExpr(expr: o.WriteVarExpr, ctx: _ExecutionContext): any { visitWriteVarExpr(expr: o.WriteVarExpr, ctx: _ExecutionContext): any {
@ -185,6 +190,9 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: _ExecutionContext): any { visitDeclareClassStmt(stmt: o.ClassStmt, ctx: _ExecutionContext): any {
const clazz = createDynamicClass(stmt, ctx, this); const clazz = createDynamicClass(stmt, ctx, this);
ctx.vars.set(stmt.name, clazz); ctx.vars.set(stmt.name, clazz);
if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.exports.push(stmt.name);
}
return null; return null;
} }
visitExpressionStmt(stmt: o.ExpressionStatement, ctx: _ExecutionContext): any { visitExpressionStmt(stmt: o.ExpressionStatement, ctx: _ExecutionContext): any {
@ -219,9 +227,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
return new clazz(...args); return new clazz(...args);
} }
visitLiteralExpr(ast: o.LiteralExpr, ctx: _ExecutionContext): any { return ast.value; } visitLiteralExpr(ast: o.LiteralExpr, ctx: _ExecutionContext): any { return ast.value; }
visitExternalExpr(ast: o.ExternalExpr, ctx: _ExecutionContext): any { visitExternalExpr(ast: o.ExternalExpr, ctx: _ExecutionContext): any { return ast.value.runtime; }
return ast.value.reference;
}
visitConditionalExpr(ast: o.ConditionalExpr, ctx: _ExecutionContext): any { visitConditionalExpr(ast: o.ConditionalExpr, ctx: _ExecutionContext): any {
if (ast.condition.visitExpression(this, ctx)) { if (ast.condition.visitExpression(this, ctx)) {
return ast.trueCase.visitExpression(this, ctx); return ast.trueCase.visitExpression(this, ctx);
@ -246,6 +252,9 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: _ExecutionContext): any { visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: _ExecutionContext): any {
const paramNames = stmt.params.map((param) => param.name); const paramNames = stmt.params.map((param) => param.name);
ctx.vars.set(stmt.name, _declareFn(paramNames, stmt.statements, ctx, this)); ctx.vars.set(stmt.name, _declareFn(paramNames, stmt.statements, ctx, this));
if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.exports.push(stmt.name);
}
return null; return null;
} }
visitBinaryOperatorExpr(ast: o.BinaryOperatorExpr, ctx: _ExecutionContext): any { visitBinaryOperatorExpr(ast: o.BinaryOperatorExpr, ctx: _ExecutionContext): any {

View File

@ -35,19 +35,24 @@ function evalExpression(
return new Function(...fnArgNames.concat(fnBody))(...fnArgValues); return new Function(...fnArgNames.concat(fnBody))(...fnArgValues);
} }
export function jitStatements( export function jitStatements(sourceUrl: string, statements: o.Statement[]): {[key: string]: any} {
sourceUrl: string, statements: o.Statement[], resultVars: string[]): any[] {
const converter = new JitEmitterVisitor(); const converter = new JitEmitterVisitor();
const ctx = EmitterVisitorContext.createRoot(resultVars); const ctx = EmitterVisitorContext.createRoot();
const returnStmt = converter.visitAllStatements(statements, ctx);
new o.ReturnStatement(o.literalArr(resultVars.map(resultVar => o.variable(resultVar)))); converter.createReturnStmt(ctx);
converter.visitAllStatements(statements.concat([returnStmt]), ctx);
return evalExpression(sourceUrl, ctx, converter.getArgs()); return evalExpression(sourceUrl, ctx, converter.getArgs());
} }
class JitEmitterVisitor extends AbstractJsEmitterVisitor { class JitEmitterVisitor extends AbstractJsEmitterVisitor {
private _evalArgNames: string[] = []; private _evalArgNames: string[] = [];
private _evalArgValues: any[] = []; private _evalArgValues: any[] = [];
private _evalExportedVars: string[] = [];
createReturnStmt(ctx: EmitterVisitorContext) {
const stmt = new o.ReturnStatement(new o.LiteralMapExpr(this._evalExportedVars.map(
resultVar => new o.LiteralMapEntry(resultVar, o.variable(resultVar)))));
stmt.visitStatement(this, ctx);
}
getArgs(): {[key: string]: any} { getArgs(): {[key: string]: any} {
const result: {[key: string]: any} = {}; const result: {[key: string]: any} = {};
@ -58,15 +63,36 @@ class JitEmitterVisitor extends AbstractJsEmitterVisitor {
} }
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any { visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
const value = ast.value.reference; const value = ast.value.runtime;
let id = this._evalArgValues.indexOf(value); let id = this._evalArgValues.indexOf(value);
if (id === -1) { if (id === -1) {
id = this._evalArgValues.length; id = this._evalArgValues.length;
this._evalArgValues.push(value); this._evalArgValues.push(value);
const name = identifierName(ast.value) || 'val'; const name = identifierName({reference: ast.value.runtime}) || 'val';
this._evalArgNames.push(`jit_${name}${id}`); this._evalArgNames.push(`jit_${name}${id}`);
} }
ctx.print(ast, this._evalArgNames[id]); ctx.print(ast, this._evalArgNames[id]);
return null; return null;
} }
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
if (stmt.hasModifier(o.StmtModifier.Exported)) {
this._evalExportedVars.push(stmt.name);
}
return super.visitDeclareVarStmt(stmt, ctx);
}
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any {
if (stmt.hasModifier(o.StmtModifier.Exported)) {
this._evalExportedVars.push(stmt.name);
}
return super.visitDeclareFunctionStmt(stmt, ctx);
}
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
if (stmt.hasModifier(o.StmtModifier.Exported)) {
this._evalExportedVars.push(stmt.name);
}
return super.visitDeclareClassStmt(stmt, ctx);
}
} }

View File

@ -1,31 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {StaticSymbol} from '../aot/static_symbol';
/**
* Interface that defines how import statements should be generated.
*/
export abstract class ImportResolver {
/**
* Converts a file path to a module name that can be used as an `import.
* I.e. `path/to/importedFile.ts` should be imported by `path/to/containingFile.ts`.
*/
abstract fileNameToModuleName(importedFilePath: string, containingFilePath: string): string|null;
/**
* Converts the given StaticSymbol into another StaticSymbol that should be used
* to generate the import from.
*/
abstract getImportAs(symbol: StaticSymbol): StaticSymbol|null;
/**
* Determine the arity of a type.
*/
abstract getTypeArity(symbol: StaticSymbol): number|null;
}

View File

@ -12,18 +12,13 @@ import {CompileIdentifierMetadata} from '../compile_metadata';
import {AbstractEmitterVisitor, CATCH_ERROR_VAR, CATCH_STACK_VAR, EmitterVisitorContext, OutputEmitter} from './abstract_emitter'; import {AbstractEmitterVisitor, CATCH_ERROR_VAR, CATCH_STACK_VAR, EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
import * as o from './output_ast'; import * as o from './output_ast';
import {ImportResolver} from './path_util';
const _debugFilePath = '/debug/lib'; const _debugFilePath = '/debug/lib';
export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type | any[]): export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type | any[]):
string { string {
const converter = new _TsEmitterVisitor(_debugFilePath, { const converter = new _TsEmitterVisitor();
fileNameToModuleName(filePath: string, containingFilePath: string) { return filePath; }, const ctx = EmitterVisitorContext.createRoot();
getImportAs(symbol: StaticSymbol | null) { return null; },
getTypeArity: symbol => null
});
const ctx = EmitterVisitorContext.createRoot([]);
const asts: any[] = Array.isArray(ast) ? ast : [ast]; const asts: any[] = Array.isArray(ast) ? ast : [ast];
asts.forEach((ast) => { asts.forEach((ast) => {
@ -42,30 +37,27 @@ export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.T
export class TypeScriptEmitter implements OutputEmitter { export class TypeScriptEmitter implements OutputEmitter {
constructor(private _importResolver: ImportResolver) {}
emitStatements( emitStatements(
srcFilePath: string, genFilePath: string, stmts: o.Statement[], exportedVars: string[], srcFilePath: string, genFilePath: string, stmts: o.Statement[],
preamble: string = ''): string { preamble: string = ''): string {
const converter = new _TsEmitterVisitor(genFilePath, this._importResolver); const converter = new _TsEmitterVisitor();
const ctx = EmitterVisitorContext.createRoot(exportedVars); const ctx = EmitterVisitorContext.createRoot();
converter.visitAllStatements(stmts, ctx); converter.visitAllStatements(stmts, ctx);
const preambleLines = preamble ? preamble.split('\n') : []; const preambleLines = preamble ? preamble.split('\n') : [];
converter.reexports.forEach((reexports, exportedFilePath) => { converter.reexports.forEach((reexports, exportedModuleName) => {
const reexportsCode = const reexportsCode =
reexports.map(reexport => `${reexport.name} as ${reexport.as}`).join(','); reexports.map(reexport => `${reexport.name} as ${reexport.as}`).join(',');
preambleLines.push( preambleLines.push(`export {${reexportsCode}} from '${exportedModuleName}';`);
`export {${reexportsCode}} from '${this._importResolver.fileNameToModuleName(exportedFilePath, genFilePath)}';`);
}); });
converter.importsWithPrefixes.forEach((prefix, importedFilePath) => { converter.importsWithPrefixes.forEach((prefix, importedModuleName) => {
// Note: can't write the real word for import as it screws up system.js auto detection... // Note: can't write the real word for import as it screws up system.js auto detection...
preambleLines.push( preambleLines.push(
`imp` + `imp` +
`ort * as ${prefix} from '${this._importResolver.fileNameToModuleName(importedFilePath, genFilePath)}';`); `ort * as ${prefix} from '${importedModuleName}';`);
}); });
const sm = const sm =
@ -82,9 +74,7 @@ export class TypeScriptEmitter implements OutputEmitter {
class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor { class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor {
private typeExpression = 0; private typeExpression = 0;
constructor(private _genFilePath: string, private _importResolver: ImportResolver) { constructor() { super(false); }
super(false);
}
importsWithPrefixes = new Map<string, string>(); importsWithPrefixes = new Map<string, string>();
reexports = new Map<string, {name: string, as: string}[]>(); reexports = new Map<string, {name: string, as: string}[]>();
@ -136,20 +126,21 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
} }
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any { visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
if (ctx.isExportedVar(stmt.name) && stmt.value instanceof o.ExternalExpr && !stmt.type) { if (stmt.hasModifier(o.StmtModifier.Exported) && stmt.value instanceof o.ExternalExpr &&
!stmt.type) {
// check for a reexport // check for a reexport
const {name, filePath, members} = this._resolveStaticSymbol(stmt.value.value); const {name, moduleName} = stmt.value.value;
if (members !.length === 0 && filePath !== this._genFilePath) { if (moduleName) {
let reexports = this.reexports.get(filePath); let reexports = this.reexports.get(moduleName);
if (!reexports) { if (!reexports) {
reexports = []; reexports = [];
this.reexports.set(filePath, reexports); this.reexports.set(moduleName, reexports);
} }
reexports.push({name, as: stmt.name}); reexports.push({name: name !, as: stmt.name});
return null; return null;
} }
} }
if (ctx.isExportedVar(stmt.name)) { if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.print(stmt, `export `); ctx.print(stmt, `export `);
} }
if (stmt.hasModifier(o.StmtModifier.Final)) { if (stmt.hasModifier(o.StmtModifier.Final)) {
@ -187,7 +178,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any { visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
ctx.pushClass(stmt); ctx.pushClass(stmt);
if (ctx.isExportedVar(stmt.name)) { if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.print(stmt, `export `); ctx.print(stmt, `export `);
} }
ctx.print(stmt, `class ${stmt.name}`); ctx.print(stmt, `class ${stmt.name}`);
@ -273,7 +264,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
} }
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any { visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any {
if (ctx.isExportedVar(stmt.name)) { if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.print(stmt, `export `); ctx.print(stmt, `export `);
} }
ctx.print(stmt, `function ${stmt.name}(`); ctx.print(stmt, `function ${stmt.name}(`);
@ -376,40 +367,18 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
}, params, ctx, ','); }, params, ctx, ',');
} }
private _resolveStaticSymbol(value: CompileIdentifierMetadata):
{name: string, filePath: string, members?: string[], arity?: number} {
const reference = value.reference;
if (!(reference instanceof StaticSymbol)) {
throw new Error(`Internal error: unknown identifier ${JSON.stringify(value)}`);
}
const arity = this._importResolver.getTypeArity(reference) || undefined;
const importReference = this._importResolver.getImportAs(reference) || reference;
return {
name: importReference.name,
filePath: importReference.filePath,
members: importReference.members, arity
};
}
private _visitIdentifier( private _visitIdentifier(
value: CompileIdentifierMetadata, typeParams: o.Type[]|null, value: o.ExternalReference, typeParams: o.Type[]|null, ctx: EmitterVisitorContext): void {
ctx: EmitterVisitorContext): void { const {name, moduleName} = value;
const {name, filePath, members, arity} = this._resolveStaticSymbol(value); if (moduleName) {
if (filePath != this._genFilePath) { let prefix = this.importsWithPrefixes.get(moduleName);
let prefix = this.importsWithPrefixes.get(filePath);
if (prefix == null) { if (prefix == null) {
prefix = `i${this.importsWithPrefixes.size}`; prefix = `i${this.importsWithPrefixes.size}`;
this.importsWithPrefixes.set(filePath, prefix); this.importsWithPrefixes.set(moduleName, prefix);
} }
ctx.print(null, `${prefix}.`); ctx.print(null, `${prefix}.`);
} }
if (members !.length) { ctx.print(null, name !);
ctx.print(null, name);
ctx.print(null, '.');
ctx.print(null, members !.join('.'));
} else {
ctx.print(null, name);
}
if (this.typeExpression > 0) { if (this.typeExpression > 0) {
// If we are in a type expression that refers to a generic type then supply // If we are in a type expression that refers to a generic type then supply
@ -417,19 +386,10 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
// supplied, supply any as the type. Outside a type expression the reference // supplied, supply any as the type. Outside a type expression the reference
// should not supply type parameters and be treated as a simple value reference // should not supply type parameters and be treated as a simple value reference
// to the constructor function itself. // to the constructor function itself.
const suppliedParameters = (typeParams && typeParams.length) || 0; const suppliedParameters = typeParams || [];
const additionalParameters = (arity || 0) - suppliedParameters; if (suppliedParameters.length > 0) {
if (suppliedParameters > 0 || additionalParameters > 0) {
ctx.print(null, `<`); ctx.print(null, `<`);
if (suppliedParameters > 0) { this.visitAllObjects(type => type.visitType(this, ctx), typeParams !, ctx, ',');
this.visitAllObjects(type => type.visitType(this, ctx), typeParams !, ctx, ',');
}
if (additionalParameters > 0) {
for (let i = 0; i < additionalParameters; i++) {
if (i > 0 || suppliedParameters > 0) ctx.print(null, ',');
ctx.print(null, 'any');
}
}
ctx.print(null, `>`); ctx.print(null, `>`);
} }
} }

View File

@ -7,17 +7,19 @@
*/ */
import {ValueTransformer, visitValue} from '../util'; import {OutputContext, ValueTransformer, visitValue} from '../util';
import * as o from './output_ast'; import * as o from './output_ast';
export const QUOTED_KEYS = '$quoted$'; export const QUOTED_KEYS = '$quoted$';
export function convertValueToOutputAst(value: any, type: o.Type | null = null): o.Expression { export function convertValueToOutputAst(
return visitValue(value, new _ValueOutputAstTransformer(), type); ctx: OutputContext, value: any, type: o.Type | null = null): o.Expression {
return visitValue(value, new _ValueOutputAstTransformer(ctx), type);
} }
class _ValueOutputAstTransformer implements ValueTransformer { class _ValueOutputAstTransformer implements ValueTransformer {
constructor(private ctx: OutputContext) {}
visitArray(arr: any[], type: o.Type): o.Expression { visitArray(arr: any[], type: o.Type): o.Expression {
return o.literalArr(arr.map(value => visitValue(value, this, null)), type); return o.literalArr(arr.map(value => visitValue(value, this, null)), type);
} }
@ -38,7 +40,7 @@ class _ValueOutputAstTransformer implements ValueTransformer {
if (value instanceof o.Expression) { if (value instanceof o.Expression) {
return value; return value;
} else { } else {
return o.importExpr({reference: value}); return this.ctx.importExpr(value);
} }
} }
} }

View File

@ -13,6 +13,7 @@ import {CompilerInjectable} from './injectable';
import * as o from './output/output_ast'; import * as o from './output/output_ast';
import {ShadowCss} from './shadow_css'; import {ShadowCss} from './shadow_css';
import {UrlResolver} from './url_resolver'; import {UrlResolver} from './url_resolver';
import {OutputContext} from './util';
const COMPONENT_VARIABLE = '%COMP%'; const COMPONENT_VARIABLE = '%COMP%';
const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`; const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
@ -20,19 +21,12 @@ const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
export class StylesCompileDependency { export class StylesCompileDependency {
constructor( constructor(
public name: string, public moduleUrl: string, public isShimmed: boolean, public name: string, public moduleUrl: string, public setValue: (value: any) => void) {}
public valuePlaceholder: CompileIdentifierMetadata) {}
}
export class StylesCompileResult {
constructor(
public componentStylesheet: CompiledStylesheet,
public externalStylesheets: CompiledStylesheet[]) {}
} }
export class CompiledStylesheet { export class CompiledStylesheet {
constructor( constructor(
public statements: o.Statement[], public stylesVar: string, public outputCtx: OutputContext, public stylesVar: string,
public dependencies: StylesCompileDependency[], public isShimmed: boolean, public dependencies: StylesCompileDependency[], public isShimmed: boolean,
public meta: CompileStylesheetMetadata) {} public meta: CompileStylesheetMetadata) {}
} }
@ -43,44 +37,53 @@ export class StyleCompiler {
constructor(private _urlResolver: UrlResolver) {} constructor(private _urlResolver: UrlResolver) {}
compileComponent(comp: CompileDirectiveMetadata): StylesCompileResult { compileComponent(outputCtx: OutputContext, comp: CompileDirectiveMetadata): CompiledStylesheet {
const template = comp.template !; const template = comp.template !;
const externalStylesheets: CompiledStylesheet[] = []; return this._compileStyles(
const componentStylesheet: CompiledStylesheet = this._compileStyles( outputCtx, comp, new CompileStylesheetMetadata({
comp, new CompileStylesheetMetadata({
styles: template.styles, styles: template.styles,
styleUrls: template.styleUrls, styleUrls: template.styleUrls,
moduleUrl: identifierModuleUrl(comp.type) moduleUrl: identifierModuleUrl(comp.type)
}), }),
true); true);
template.externalStylesheets.forEach((stylesheetMeta) => { }
const compiledStylesheet = this._compileStyles(comp, stylesheetMeta, false);
externalStylesheets.push(compiledStylesheet); compileStyles(
}); outputCtx: OutputContext, comp: CompileDirectiveMetadata,
return new StylesCompileResult(componentStylesheet, externalStylesheets); stylesheet: CompileStylesheetMetadata): CompiledStylesheet {
return this._compileStyles(outputCtx, comp, stylesheet, false);
}
needsStyleShim(comp: CompileDirectiveMetadata): boolean {
return comp.template !.encapsulation === ViewEncapsulation.Emulated;
} }
private _compileStyles( private _compileStyles(
comp: CompileDirectiveMetadata, stylesheet: CompileStylesheetMetadata, outputCtx: OutputContext, comp: CompileDirectiveMetadata,
isComponentStylesheet: boolean): CompiledStylesheet { stylesheet: CompileStylesheetMetadata, isComponentStylesheet: boolean): CompiledStylesheet {
const shim = comp.template !.encapsulation === ViewEncapsulation.Emulated; const shim = this.needsStyleShim(comp);
const styleExpressions = const styleExpressions: o.Expression[] =
stylesheet.styles.map(plainStyle => o.literal(this._shimIfNeeded(plainStyle, shim))); stylesheet.styles.map(plainStyle => o.literal(this._shimIfNeeded(plainStyle, shim)));
const dependencies: StylesCompileDependency[] = []; const dependencies: StylesCompileDependency[] = [];
for (let i = 0; i < stylesheet.styleUrls.length; i++) { stylesheet.styleUrls.forEach((styleUrl) => {
const identifier: CompileIdentifierMetadata = {reference: null}; const exprIndex = styleExpressions.length;
// Note: This placeholder will be filled later.
styleExpressions.push(null !);
dependencies.push(new StylesCompileDependency( dependencies.push(new StylesCompileDependency(
getStylesVarName(null), stylesheet.styleUrls[i], shim, identifier)); getStylesVarName(null), styleUrl,
styleExpressions.push(new o.ExternalExpr(identifier)); (value) => styleExpressions[exprIndex] = outputCtx.importExpr(value)));
} });
// styles variable contains plain strings and arrays of other styles arrays (recursive), // styles variable contains plain strings and arrays of other styles arrays (recursive),
// so we set its type to dynamic. // so we set its type to dynamic.
const stylesVar = getStylesVarName(isComponentStylesheet ? comp : null); const stylesVar = getStylesVarName(isComponentStylesheet ? comp : null);
const stmt = o.variable(stylesVar) const stmt = o.variable(stylesVar)
.set(o.literalArr( .set(o.literalArr(
styleExpressions, new o.ArrayType(o.DYNAMIC_TYPE, [o.TypeModifier.Const]))) styleExpressions, new o.ArrayType(o.DYNAMIC_TYPE, [o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]); .toDeclStmt(null, isComponentStylesheet ? [o.StmtModifier.Final] : [
return new CompiledStylesheet([stmt], stylesVar, dependencies, shim, stylesheet); o.StmtModifier.Final, o.StmtModifier.Exported
]);
outputCtx.statements.push(stmt);
return new CompiledStylesheet(outputCtx, stylesVar, dependencies, shim, stylesheet);
} }
private _shimIfNeeded(style: string, shim: boolean): string { private _shimIfNeeded(style: string, shim: boolean): string {

View File

@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import * as o from './output/output_ast';
export const MODULE_SUFFIX = ''; export const MODULE_SUFFIX = '';
const CAMEL_CASE_REGEXP = /([A-Z])/g; const CAMEL_CASE_REGEXP = /([A-Z])/g;
@ -138,3 +140,9 @@ export function utf8Encode(str: string): string {
return encoded; return encoded;
} }
export interface OutputContext {
genFilePath: string;
statements: o.Statement[];
importExpr(reference: any, typeParams?: o.Type[]|null): o.Expression;
}

View File

@ -13,8 +13,9 @@ import {Identifiers, createIdentifier, createIdentifierToken, resolveIdentifier}
import * as o from '../output/output_ast'; import * as o from '../output/output_ast';
import {convertValueToOutputAst} from '../output/value_util'; import {convertValueToOutputAst} from '../output/value_util';
import {ProviderAst, ProviderAstType} from '../template_parser/template_ast'; import {ProviderAst, ProviderAstType} from '../template_parser/template_ast';
import {OutputContext} from '../util';
export function providerDef(providerAst: ProviderAst): { export function providerDef(ctx: OutputContext, providerAst: ProviderAst): {
providerExpr: o.Expression, providerExpr: o.Expression,
flags: NodeFlags, flags: NodeFlags,
depsExpr: o.Expression, depsExpr: o.Expression,
@ -36,16 +37,17 @@ export function providerDef(providerAst: ProviderAst): {
} }
}); });
const {providerExpr, flags: providerFlags, depsExpr} = providerAst.multiProvider ? const {providerExpr, flags: providerFlags, depsExpr} = providerAst.multiProvider ?
multiProviderDef(flags, providerAst.providers) : multiProviderDef(ctx, flags, providerAst.providers) :
singleProviderDef(flags, providerAst.providerType, providerAst.providers[0]); singleProviderDef(ctx, flags, providerAst.providerType, providerAst.providers[0]);
return { return {
providerExpr, providerExpr,
flags: providerFlags, depsExpr, flags: providerFlags, depsExpr,
tokenExpr: tokenExpr(providerAst.token), tokenExpr: tokenExpr(ctx, providerAst.token),
}; };
} }
function multiProviderDef(flags: NodeFlags, providers: CompileProviderMetadata[]): function multiProviderDef(
ctx: OutputContext, flags: NodeFlags, providers: CompileProviderMetadata[]):
{providerExpr: o.Expression, flags: NodeFlags, depsExpr: o.Expression} { {providerExpr: o.Expression, flags: NodeFlags, depsExpr: o.Expression} {
const allDepDefs: o.Expression[] = []; const allDepDefs: o.Expression[] = [];
const allParams: o.FnParam[] = []; const allParams: o.FnParam[] = [];
@ -53,15 +55,15 @@ function multiProviderDef(flags: NodeFlags, providers: CompileProviderMetadata[]
let expr: o.Expression; let expr: o.Expression;
if (provider.useClass) { if (provider.useClass) {
const depExprs = convertDeps(providerIndex, provider.deps || provider.useClass.diDeps); const depExprs = convertDeps(providerIndex, provider.deps || provider.useClass.diDeps);
expr = o.importExpr(provider.useClass).instantiate(depExprs); expr = ctx.importExpr(provider.useClass.reference).instantiate(depExprs);
} else if (provider.useFactory) { } else if (provider.useFactory) {
const depExprs = convertDeps(providerIndex, provider.deps || provider.useFactory.diDeps); const depExprs = convertDeps(providerIndex, provider.deps || provider.useFactory.diDeps);
expr = o.importExpr(provider.useFactory).callFn(depExprs); expr = ctx.importExpr(provider.useFactory.reference).callFn(depExprs);
} else if (provider.useExisting) { } else if (provider.useExisting) {
const depExprs = convertDeps(providerIndex, [{token: provider.useExisting}]); const depExprs = convertDeps(providerIndex, [{token: provider.useExisting}]);
expr = depExprs[0]; expr = depExprs[0];
} else { } else {
expr = convertValueToOutputAst(provider.useValue); expr = convertValueToOutputAst(ctx, provider.useValue);
} }
return expr; return expr;
}); });
@ -77,28 +79,29 @@ function multiProviderDef(flags: NodeFlags, providers: CompileProviderMetadata[]
return deps.map((dep, depIndex) => { return deps.map((dep, depIndex) => {
const paramName = `p${providerIndex}_${depIndex}`; const paramName = `p${providerIndex}_${depIndex}`;
allParams.push(new o.FnParam(paramName, o.DYNAMIC_TYPE)); allParams.push(new o.FnParam(paramName, o.DYNAMIC_TYPE));
allDepDefs.push(depDef(dep)); allDepDefs.push(depDef(ctx, dep));
return o.variable(paramName); return o.variable(paramName);
}); });
} }
} }
function singleProviderDef( function singleProviderDef(
flags: NodeFlags, providerType: ProviderAstType, providerMeta: CompileProviderMetadata): ctx: OutputContext, flags: NodeFlags, providerType: ProviderAstType,
providerMeta: CompileProviderMetadata):
{providerExpr: o.Expression, flags: NodeFlags, depsExpr: o.Expression} { {providerExpr: o.Expression, flags: NodeFlags, depsExpr: o.Expression} {
let providerExpr: o.Expression; let providerExpr: o.Expression;
let deps: CompileDiDependencyMetadata[]; let deps: CompileDiDependencyMetadata[];
if (providerType === ProviderAstType.Directive || providerType === ProviderAstType.Component) { if (providerType === ProviderAstType.Directive || providerType === ProviderAstType.Component) {
providerExpr = o.importExpr(providerMeta.useClass !); providerExpr = ctx.importExpr(providerMeta.useClass !.reference);
flags |= NodeFlags.TypeDirective; flags |= NodeFlags.TypeDirective;
deps = providerMeta.deps || providerMeta.useClass !.diDeps; deps = providerMeta.deps || providerMeta.useClass !.diDeps;
} else { } else {
if (providerMeta.useClass) { if (providerMeta.useClass) {
providerExpr = o.importExpr(providerMeta.useClass); providerExpr = ctx.importExpr(providerMeta.useClass.reference);
flags |= NodeFlags.TypeClassProvider; flags |= NodeFlags.TypeClassProvider;
deps = providerMeta.deps || providerMeta.useClass.diDeps; deps = providerMeta.deps || providerMeta.useClass.diDeps;
} else if (providerMeta.useFactory) { } else if (providerMeta.useFactory) {
providerExpr = o.importExpr(providerMeta.useFactory); providerExpr = ctx.importExpr(providerMeta.useFactory.reference);
flags |= NodeFlags.TypeFactoryProvider; flags |= NodeFlags.TypeFactoryProvider;
deps = providerMeta.deps || providerMeta.useFactory.diDeps; deps = providerMeta.deps || providerMeta.useFactory.diDeps;
} else if (providerMeta.useExisting) { } else if (providerMeta.useExisting) {
@ -106,23 +109,24 @@ function singleProviderDef(
flags |= NodeFlags.TypeUseExistingProvider; flags |= NodeFlags.TypeUseExistingProvider;
deps = [{token: providerMeta.useExisting}]; deps = [{token: providerMeta.useExisting}];
} else { } else {
providerExpr = convertValueToOutputAst(providerMeta.useValue); providerExpr = convertValueToOutputAst(ctx, providerMeta.useValue);
flags |= NodeFlags.TypeValueProvider; flags |= NodeFlags.TypeValueProvider;
deps = []; deps = [];
} }
} }
const depsExpr = o.literalArr(deps.map(dep => depDef(dep))); const depsExpr = o.literalArr(deps.map(dep => depDef(ctx, dep)));
return {providerExpr, flags, depsExpr}; return {providerExpr, flags, depsExpr};
} }
function tokenExpr(tokenMeta: CompileTokenMetadata): o.Expression { function tokenExpr(ctx: OutputContext, tokenMeta: CompileTokenMetadata): o.Expression {
return tokenMeta.identifier ? o.importExpr(tokenMeta.identifier) : o.literal(tokenMeta.value); return tokenMeta.identifier ? ctx.importExpr(tokenMeta.identifier.reference) :
o.literal(tokenMeta.value);
} }
export function depDef(dep: CompileDiDependencyMetadata): o.Expression { export function depDef(ctx: OutputContext, dep: CompileDiDependencyMetadata): o.Expression {
// Note: the following fields have already been normalized out by provider_analyzer: // Note: the following fields have already been normalized out by provider_analyzer:
// - isAttribute, isSelf, isHost // - isAttribute, isSelf, isHost
const expr = dep.isValue ? convertValueToOutputAst(dep.value) : tokenExpr(dep.token !); const expr = dep.isValue ? convertValueToOutputAst(ctx, dep.value) : tokenExpr(ctx, dep.token !);
let flags = DepFlags.None; let flags = DepFlags.None;
if (dep.isSkipSelf) { if (dep.isSkipSelf) {
flags |= DepFlags.SkipSelf; flags |= DepFlags.SkipSelf;
@ -168,14 +172,14 @@ export function lifecycleHookToNodeFlag(lifecycleHook: LifecycleHooks): NodeFlag
} }
export function componentFactoryResolverProviderDef( export function componentFactoryResolverProviderDef(
flags: NodeFlags, entryComponents: CompileEntryComponentMetadata[]): { ctx: OutputContext, flags: NodeFlags, entryComponents: CompileEntryComponentMetadata[]): {
providerExpr: o.Expression, providerExpr: o.Expression,
flags: NodeFlags, flags: NodeFlags,
depsExpr: o.Expression, depsExpr: o.Expression,
tokenExpr: o.Expression tokenExpr: o.Expression
} { } {
const entryComponentFactories = entryComponents.map( const entryComponentFactories =
(entryComponent) => o.importExpr({reference: entryComponent.componentFactory})); entryComponents.map((entryComponent) => ctx.importExpr(entryComponent.componentFactory));
const token = createIdentifierToken(Identifiers.ComponentFactoryResolver); const token = createIdentifierToken(Identifiers.ComponentFactoryResolver);
const classMeta = { const classMeta = {
diDeps: [ diDeps: [
@ -187,10 +191,10 @@ export function componentFactoryResolverProviderDef(
reference: resolveIdentifier(Identifiers.CodegenComponentFactoryResolver) reference: resolveIdentifier(Identifiers.CodegenComponentFactoryResolver)
}; };
const {providerExpr, flags: providerFlags, depsExpr} = const {providerExpr, flags: providerFlags, depsExpr} =
singleProviderDef(flags, ProviderAstType.PrivateService, { singleProviderDef(ctx, flags, ProviderAstType.PrivateService, {
token, token,
multi: false, multi: false,
useClass: classMeta, useClass: classMeta,
}); });
return {providerExpr, flags: providerFlags, depsExpr, tokenExpr: tokenExpr(token)}; return {providerExpr, flags: providerFlags, depsExpr, tokenExpr: tokenExpr(ctx, token)};
} }

View File

@ -20,6 +20,7 @@ import {convertValueToOutputAst} from '../output/value_util';
import {ParseSourceSpan} from '../parse_util'; import {ParseSourceSpan} from '../parse_util';
import {ElementSchemaRegistry} from '../schema/element_schema_registry'; import {ElementSchemaRegistry} from '../schema/element_schema_registry';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, ProviderAstType, QueryMatch, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast'; import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, ProviderAstType, QueryMatch, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {OutputContext} from '../util';
import {componentFactoryResolverProviderDef, depDef, lifecycleHookToNodeFlag, providerDef} from './provider_compiler'; import {componentFactoryResolverProviderDef, depDef, lifecycleHookToNodeFlag, providerDef} from './provider_compiler';
@ -29,9 +30,7 @@ const IMPLICIT_TEMPLATE_VAR = '\$implicit';
const NG_CONTAINER_TAG = 'ng-container'; const NG_CONTAINER_TAG = 'ng-container';
export class ViewCompileResult { export class ViewCompileResult {
constructor( constructor(public viewClassVar: string, public rendererTypeVar: string) {}
public statements: o.Statement[], public viewClassVar: string,
public rendererTypeVar: string) {}
} }
@CompilerInjectable() @CompilerInjectable()
@ -40,49 +39,47 @@ export class ViewCompiler {
private _genConfigNext: CompilerConfig, private _schemaRegistry: ElementSchemaRegistry) {} private _genConfigNext: CompilerConfig, private _schemaRegistry: ElementSchemaRegistry) {}
compileComponent( compileComponent(
component: CompileDirectiveMetadata, template: TemplateAst[], styles: o.Expression, outputCtx: OutputContext, component: CompileDirectiveMetadata, template: TemplateAst[],
usedPipes: CompilePipeSummary[]): ViewCompileResult { styles: o.Expression, usedPipes: CompilePipeSummary[]): ViewCompileResult {
let embeddedViewCount = 0; let embeddedViewCount = 0;
const staticQueryIds = findStaticQueryIds(template); const staticQueryIds = findStaticQueryIds(template);
const statements: o.Statement[] = [];
let renderComponentVarName: string = undefined !; let renderComponentVarName: string = undefined !;
if (!component.isHost) { if (!component.isHost) {
const template = component.template !; const template = component.template !;
const customRenderData: o.LiteralMapEntry[] = []; const customRenderData: o.LiteralMapEntry[] = [];
if (template.animations && template.animations.length) { if (template.animations && template.animations.length) {
customRenderData.push( customRenderData.push(new o.LiteralMapEntry(
new o.LiteralMapEntry('animation', convertValueToOutputAst(template.animations), true)); 'animation', convertValueToOutputAst(outputCtx, template.animations), true));
} }
const renderComponentVar = o.variable(rendererTypeName(component.type.reference)); const renderComponentVar = o.variable(rendererTypeName(component.type.reference));
renderComponentVarName = renderComponentVar.name !; renderComponentVarName = renderComponentVar.name !;
statements.push( outputCtx.statements.push(
renderComponentVar renderComponentVar
.set(o.importExpr(createIdentifier(Identifiers.createRendererType2)) .set(o.importExpr(Identifiers.createRendererType2).callFn([new o.LiteralMapExpr([
.callFn([new o.LiteralMapExpr([ new o.LiteralMapEntry('encapsulation', o.literal(template.encapsulation)),
new o.LiteralMapEntry('encapsulation', o.literal(template.encapsulation)), new o.LiteralMapEntry('styles', styles),
new o.LiteralMapEntry('styles', styles), new o.LiteralMapEntry('data', new o.LiteralMapExpr(customRenderData))
new o.LiteralMapEntry('data', new o.LiteralMapExpr(customRenderData)) ])]))
])]))
.toDeclStmt( .toDeclStmt(
o.importType(createIdentifier(Identifiers.RendererType2)), o.importType(Identifiers.RendererType2),
[o.StmtModifier.Final])); [o.StmtModifier.Final, o.StmtModifier.Exported]));
} }
const viewBuilderFactory = (parent: ViewBuilder | null): ViewBuilder => { const viewBuilderFactory = (parent: ViewBuilder | null): ViewBuilder => {
const embeddedViewIndex = embeddedViewCount++; const embeddedViewIndex = embeddedViewCount++;
return new ViewBuilder( return new ViewBuilder(
parent, component, embeddedViewIndex, usedPipes, staticQueryIds, viewBuilderFactory); outputCtx, parent, component, embeddedViewIndex, usedPipes, staticQueryIds,
viewBuilderFactory);
}; };
const visitor = viewBuilderFactory(null); const visitor = viewBuilderFactory(null);
visitor.visitAll([], template); visitor.visitAll([], template);
statements.push(...visitor.build()); outputCtx.statements.push(...visitor.build());
return new ViewCompileResult(statements, visitor.viewName, renderComponentVarName); return new ViewCompileResult(visitor.viewName, renderComponentVarName);
} }
} }
@ -119,15 +116,17 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
private children: ViewBuilder[] = []; private children: ViewBuilder[] = [];
constructor( constructor(
private parent: ViewBuilder|null, private component: CompileDirectiveMetadata, private outputCtx: OutputContext, private parent: ViewBuilder|null,
private embeddedViewIndex: number, private usedPipes: CompilePipeSummary[], private component: CompileDirectiveMetadata, private embeddedViewIndex: number,
private usedPipes: CompilePipeSummary[],
private staticQueryIds: Map<TemplateAst, StaticAndDynamicQueryIds>, private staticQueryIds: Map<TemplateAst, StaticAndDynamicQueryIds>,
private viewBuilderFactory: ViewBuilderFactory) { private viewBuilderFactory: ViewBuilderFactory) {
// TODO(tbosch): The old view compiler used to use an `any` type // TODO(tbosch): The old view compiler used to use an `any` type
// for the context in any embedded view. We keep this behaivor for now // for the context in any embedded view. We keep this behaivor for now
// to be able to introduce the new view compiler without too many errors. // to be able to introduce the new view compiler without too many errors.
this.compType = this.compType = this.embeddedViewIndex > 0 ?
this.embeddedViewIndex > 0 ? o.DYNAMIC_TYPE : o.importType(this.component.type) !; o.DYNAMIC_TYPE :
o.expressionType(outputCtx.importExpr(this.component.type.reference)) !;
} }
get viewName(): string { get viewName(): string {
@ -156,7 +155,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({ this.nodes.push(() => ({
sourceSpan: null, sourceSpan: null,
nodeFlags: flags, nodeFlags: flags,
nodeDef: o.importExpr(createIdentifier(Identifiers.queryDef)).callFn([ nodeDef: o.importExpr(Identifiers.queryDef).callFn([
o.literal(flags), o.literal(queryId), o.literal(flags), o.literal(queryId),
new o.LiteralMapExpr( new o.LiteralMapExpr(
[new o.LiteralMapEntry(query.propertyName, o.literal(bindingType))]) [new o.LiteralMapEntry(query.propertyName, o.literal(bindingType))])
@ -170,7 +169,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({ this.nodes.push(() => ({
sourceSpan: null, sourceSpan: null,
nodeFlags: NodeFlags.TypeElement, nodeFlags: NodeFlags.TypeElement,
nodeDef: o.importExpr(createIdentifier(Identifiers.anchorDef)).callFn([ nodeDef: o.importExpr(Identifiers.anchorDef).callFn([
o.literal(NodeFlags.None), o.NULL_EXPR, o.NULL_EXPR, o.literal(0) o.literal(NodeFlags.None), o.NULL_EXPR, o.NULL_EXPR, o.literal(0)
]) ])
})); }));
@ -193,13 +192,14 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
} }
const viewFactory = new o.DeclareFunctionStmt( const viewFactory = new o.DeclareFunctionStmt(
this.viewName, [new o.FnParam(LOG_VAR.name !)], this.viewName, [new o.FnParam(LOG_VAR.name !)],
[new o.ReturnStatement(o.importExpr(createIdentifier(Identifiers.viewDef)).callFn([ [new o.ReturnStatement(o.importExpr(Identifiers.viewDef).callFn([
o.literal(viewFlags), o.literal(viewFlags),
o.literalArr(nodeDefExprs), o.literalArr(nodeDefExprs),
updateDirectivesFn, updateDirectivesFn,
updateRendererFn, updateRendererFn,
]))], ]))],
o.importType(createIdentifier(Identifiers.ViewDefinition))); o.importType(Identifiers.ViewDefinition),
this.embeddedViewIndex === 0 ? [o.StmtModifier.Exported] : []);
targetStatements.push(viewFactory); targetStatements.push(viewFactory);
return targetStatements; return targetStatements;
@ -229,7 +229,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({ this.nodes.push(() => ({
sourceSpan: ast.sourceSpan, sourceSpan: ast.sourceSpan,
nodeFlags: NodeFlags.TypeNgContent, nodeFlags: NodeFlags.TypeNgContent,
nodeDef: o.importExpr(createIdentifier(Identifiers.ngContentDef)).callFn([ nodeDef: o.importExpr(Identifiers.ngContentDef).callFn([
o.literal(ast.ngContentIndex), o.literal(ast.index) o.literal(ast.ngContentIndex), o.literal(ast.index)
]) ])
})); }));
@ -240,7 +240,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({ this.nodes.push(() => ({
sourceSpan: ast.sourceSpan, sourceSpan: ast.sourceSpan,
nodeFlags: NodeFlags.TypeText, nodeFlags: NodeFlags.TypeText,
nodeDef: o.importExpr(createIdentifier(Identifiers.textDef)).callFn([ nodeDef: o.importExpr(Identifiers.textDef).callFn([
o.literal(ast.ngContentIndex), o.literalArr([o.literal(ast.value)]) o.literal(ast.ngContentIndex), o.literalArr([o.literal(ast.value)])
]) ])
})); }));
@ -262,7 +262,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes[nodeIndex] = () => ({ this.nodes[nodeIndex] = () => ({
sourceSpan: ast.sourceSpan, sourceSpan: ast.sourceSpan,
nodeFlags: NodeFlags.TypeText, nodeFlags: NodeFlags.TypeText,
nodeDef: o.importExpr(createIdentifier(Identifiers.textDef)).callFn([ nodeDef: o.importExpr(Identifiers.textDef).callFn([
o.literal(ast.ngContentIndex), o.literalArr(inter.strings.map(s => o.literal(s))) o.literal(ast.ngContentIndex), o.literalArr(inter.strings.map(s => o.literal(s)))
]), ]),
updateRenderer: updateRendererExpressions updateRenderer: updateRendererExpressions
@ -289,7 +289,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes[nodeIndex] = () => ({ this.nodes[nodeIndex] = () => ({
sourceSpan: ast.sourceSpan, sourceSpan: ast.sourceSpan,
nodeFlags: NodeFlags.TypeElement | flags, nodeFlags: NodeFlags.TypeElement | flags,
nodeDef: o.importExpr(createIdentifier(Identifiers.anchorDef)).callFn([ nodeDef: o.importExpr(Identifiers.anchorDef).callFn([
o.literal(flags), o.literal(flags),
queryMatchesExpr, queryMatchesExpr,
o.literal(ast.ngContentIndex), o.literal(ast.ngContentIndex),
@ -343,11 +343,11 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
const childCount = this.nodes.length - nodeIndex - 1; const childCount = this.nodes.length - nodeIndex - 1;
const compAst = ast.directives.find(dirAst => dirAst.directive.isComponent); const compAst = ast.directives.find(dirAst => dirAst.directive.isComponent);
let compRendererType = o.NULL_EXPR; let compRendererType = o.NULL_EXPR as o.Expression;
let compView = o.NULL_EXPR; let compView = o.NULL_EXPR as o.Expression;
if (compAst) { if (compAst) {
compView = o.importExpr({reference: compAst.directive.componentViewType}); compView = this.outputCtx.importExpr(compAst.directive.componentViewType);
compRendererType = o.importExpr({reference: compAst.directive.rendererType}); compRendererType = this.outputCtx.importExpr(compAst.directive.rendererType);
} }
// elementDef( // elementDef(
@ -361,7 +361,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes[nodeIndex] = () => ({ this.nodes[nodeIndex] = () => ({
sourceSpan: ast.sourceSpan, sourceSpan: ast.sourceSpan,
nodeFlags: NodeFlags.TypeElement | flags, nodeFlags: NodeFlags.TypeElement | flags,
nodeDef: o.importExpr(createIdentifier(Identifiers.elementDef)).callFn([ nodeDef: o.importExpr(Identifiers.elementDef).callFn([
o.literal(flags), o.literal(flags),
queryMatchesExpr, queryMatchesExpr,
o.literal(ast.ngContentIndex), o.literal(ast.ngContentIndex),
@ -492,7 +492,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({ this.nodes.push(() => ({
sourceSpan: dirAst.sourceSpan, sourceSpan: dirAst.sourceSpan,
nodeFlags: flags, nodeFlags: flags,
nodeDef: o.importExpr(createIdentifier(Identifiers.queryDef)).callFn([ nodeDef: o.importExpr(Identifiers.queryDef).callFn([
o.literal(flags), o.literal(queryId), o.literal(flags), o.literal(queryId),
new o.LiteralMapExpr( new o.LiteralMapExpr(
[new o.LiteralMapEntry(query.propertyName, o.literal(bindingType))]) [new o.LiteralMapEntry(query.propertyName, o.literal(bindingType))])
@ -548,9 +548,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
})); }));
} }
const dirContextExpr = o.importExpr(createIdentifier(Identifiers.nodeValue)).callFn([ const dirContextExpr =
VIEW_VAR, o.literal(nodeIndex) o.importExpr(Identifiers.nodeValue).callFn([VIEW_VAR, o.literal(nodeIndex)]);
]);
const hostBindings = dirAst.hostProperties.map((inputAst) => ({ const hostBindings = dirAst.hostProperties.map((inputAst) => ({
context: dirContextExpr, context: dirContextExpr,
dirAst, dirAst,
@ -570,7 +569,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes[nodeIndex] = () => ({ this.nodes[nodeIndex] = () => ({
sourceSpan: dirAst.sourceSpan, sourceSpan: dirAst.sourceSpan,
nodeFlags: NodeFlags.TypeDirective | flags, nodeFlags: NodeFlags.TypeDirective | flags,
nodeDef: o.importExpr(createIdentifier(Identifiers.directiveDef)).callFn([ nodeDef: o.importExpr(Identifiers.directiveDef).callFn([
o.literal(flags), queryMatchExprs.length ? o.literalArr(queryMatchExprs) : o.NULL_EXPR, o.literal(flags), queryMatchExprs.length ? o.literalArr(queryMatchExprs) : o.NULL_EXPR,
o.literal(childCount), providerExpr, depsExpr, o.literal(childCount), providerExpr, depsExpr,
inputDefs.length ? new o.LiteralMapExpr(inputDefs) : o.NULL_EXPR, inputDefs.length ? new o.LiteralMapExpr(inputDefs) : o.NULL_EXPR,
@ -591,7 +590,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
const componentDirMeta = directives.find(dirAst => dirAst.directive.isComponent); const componentDirMeta = directives.find(dirAst => dirAst.directive.isComponent);
if (componentDirMeta && componentDirMeta.directive.entryComponents.length) { if (componentDirMeta && componentDirMeta.directive.entryComponents.length) {
const {providerExpr, depsExpr, flags, tokenExpr} = componentFactoryResolverProviderDef( const {providerExpr, depsExpr, flags, tokenExpr} = componentFactoryResolverProviderDef(
NodeFlags.PrivateProvider, componentDirMeta.directive.entryComponents); this.outputCtx, NodeFlags.PrivateProvider, componentDirMeta.directive.entryComponents);
this._addProviderNode({ this._addProviderNode({
providerExpr, providerExpr,
depsExpr, depsExpr,
@ -619,7 +618,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
() => ({ () => ({
sourceSpan: data.sourceSpan, sourceSpan: data.sourceSpan,
nodeFlags: data.flags, nodeFlags: data.flags,
nodeDef: o.importExpr(createIdentifier(Identifiers.providerDef)).callFn([ nodeDef: o.importExpr(Identifiers.providerDef).callFn([
o.literal(data.flags), o.literal(data.flags),
data.queryMatchExprs.length ? o.literalArr(data.queryMatchExprs) : o.NULL_EXPR, data.queryMatchExprs.length ? o.literalArr(data.queryMatchExprs) : o.NULL_EXPR,
data.tokenExpr, data.providerExpr, data.depsExpr data.tokenExpr, data.providerExpr, data.depsExpr
@ -644,7 +643,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
o.literalArr([o.literal(match.queryId), o.literal(QueryValueType.Provider)])); o.literalArr([o.literal(match.queryId), o.literal(QueryValueType.Provider)]));
} }
}); });
const {providerExpr, depsExpr, flags: providerFlags, tokenExpr} = providerDef(providerAst); const {providerExpr, depsExpr, flags: providerFlags, tokenExpr} =
providerDef(this.outputCtx, providerAst);
return { return {
flags: flags | providerFlags, flags: flags | providerFlags,
queryMatchExprs, queryMatchExprs,
@ -665,9 +665,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
// check references // check references
const refNodeIndex = currBuilder.refNodeIndices[name]; const refNodeIndex = currBuilder.refNodeIndices[name];
if (refNodeIndex != null) { if (refNodeIndex != null) {
return o.importExpr(createIdentifier(Identifiers.nodeValue)).callFn([ return o.importExpr(Identifiers.nodeValue).callFn([currViewExpr, o.literal(refNodeIndex)]);
currViewExpr, o.literal(refNodeIndex)
]);
} }
// check variables // check variables
@ -682,25 +680,23 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
createLiteralArrayConverter(sourceSpan: ParseSourceSpan, argCount: number): BuiltinConverter { createLiteralArrayConverter(sourceSpan: ParseSourceSpan, argCount: number): BuiltinConverter {
if (argCount === 0) { if (argCount === 0) {
const valueExpr = o.importExpr(createIdentifier(Identifiers.EMPTY_ARRAY)); const valueExpr = o.importExpr(Identifiers.EMPTY_ARRAY);
return () => valueExpr; return () => valueExpr;
} }
const nodeIndex = this.nodes.length; const nodeIndex = this.nodes.length;
// pureArrayDef(argCount: number): NodeDef; // pureArrayDef(argCount: number): NodeDef;
this.nodes.push( this.nodes.push(() => ({
() => ({ sourceSpan,
sourceSpan, nodeFlags: NodeFlags.TypePureArray,
nodeFlags: NodeFlags.TypePureArray, nodeDef: o.importExpr(Identifiers.pureArrayDef).callFn([o.literal(argCount)])
nodeDef: }));
o.importExpr(createIdentifier(Identifiers.pureArrayDef)).callFn([o.literal(argCount)])
}));
return (args: o.Expression[]) => callCheckStmt(nodeIndex, args); return (args: o.Expression[]) => callCheckStmt(nodeIndex, args);
} }
createLiteralMapConverter(sourceSpan: ParseSourceSpan, keys: string[]): BuiltinConverter { createLiteralMapConverter(sourceSpan: ParseSourceSpan, keys: string[]): BuiltinConverter {
if (keys.length === 0) { if (keys.length === 0) {
const valueExpr = o.importExpr(createIdentifier(Identifiers.EMPTY_MAP)); const valueExpr = o.importExpr(Identifiers.EMPTY_MAP);
return () => valueExpr; return () => valueExpr;
} }
@ -709,8 +705,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({ this.nodes.push(() => ({
sourceSpan, sourceSpan,
nodeFlags: NodeFlags.TypePureObject, nodeFlags: NodeFlags.TypePureObject,
nodeDef: o.importExpr(createIdentifier(Identifiers.pureObjectDef)) nodeDef: o.importExpr(Identifiers.pureObjectDef).callFn([o.literalArr(
.callFn([o.literalArr(keys.map(key => o.literal(key)))]) keys.map(key => o.literal(key)))])
})); }));
return (args: o.Expression[]) => callCheckStmt(nodeIndex, args); return (args: o.Expression[]) => callCheckStmt(nodeIndex, args);
@ -724,8 +720,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({ this.nodes.push(() => ({
sourceSpan: expression.sourceSpan, sourceSpan: expression.sourceSpan,
nodeFlags: NodeFlags.TypePurePipe, nodeFlags: NodeFlags.TypePurePipe,
nodeDef: o.importExpr(createIdentifier(Identifiers.purePipeDef)) nodeDef: o.importExpr(Identifiers.purePipeDef).callFn([o.literal(argCount)])
.callFn([o.literal(argCount)])
})); }));
// find underlying pipe in the component view // find underlying pipe in the component view
@ -737,18 +732,15 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
} }
const pipeNodeIndex = compBuilder.purePipeNodeIndices[name]; const pipeNodeIndex = compBuilder.purePipeNodeIndices[name];
const pipeValueExpr: o.Expression = const pipeValueExpr: o.Expression =
o.importExpr(createIdentifier(Identifiers.nodeValue)).callFn([ o.importExpr(Identifiers.nodeValue).callFn([compViewExpr, o.literal(pipeNodeIndex)]);
compViewExpr, o.literal(pipeNodeIndex)
]);
return (args: o.Expression[]) => callUnwrapValue( return (args: o.Expression[]) => callUnwrapValue(
expression.nodeIndex, expression.bindingIndex, expression.nodeIndex, expression.bindingIndex,
callCheckStmt(nodeIndex, [pipeValueExpr].concat(args))); callCheckStmt(nodeIndex, [pipeValueExpr].concat(args)));
} else { } else {
const nodeIndex = this._createPipe(expression.sourceSpan, pipe); const nodeIndex = this._createPipe(expression.sourceSpan, pipe);
const nodeValueExpr = o.importExpr(createIdentifier(Identifiers.nodeValue)).callFn([ const nodeValueExpr =
VIEW_VAR, o.literal(nodeIndex) o.importExpr(Identifiers.nodeValue).callFn([VIEW_VAR, o.literal(nodeIndex)]);
]);
return (args: o.Expression[]) => callUnwrapValue( return (args: o.Expression[]) => callUnwrapValue(
expression.nodeIndex, expression.bindingIndex, expression.nodeIndex, expression.bindingIndex,
@ -766,16 +758,17 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
} }
}); });
const depExprs = pipe.type.diDeps.map(depDef); const depExprs = pipe.type.diDeps.map((diDep) => depDef(this.outputCtx, diDep));
// function pipeDef( // function pipeDef(
// flags: NodeFlags, ctor: any, deps: ([DepFlags, any] | any)[]): NodeDef // flags: NodeFlags, ctor: any, deps: ([DepFlags, any] | any)[]): NodeDef
this.nodes.push(() => ({ this.nodes.push(
sourceSpan, () => ({
nodeFlags: NodeFlags.TypePipe, sourceSpan,
nodeDef: o.importExpr(createIdentifier(Identifiers.pipeDef)).callFn([ nodeFlags: NodeFlags.TypePipe,
o.literal(flags), o.importExpr(pipe.type), o.literalArr(depExprs) nodeDef: o.importExpr(Identifiers.pipeDef).callFn([
]) o.literal(flags), this.outputCtx.importExpr(pipe.type.reference), o.literalArr(depExprs)
})); ])
}));
return nodeIndex; return nodeIndex;
} }
@ -984,7 +977,7 @@ function callCheckStmt(nodeIndex: number, exprs: o.Expression[]): o.Expression {
} }
function callUnwrapValue(nodeIndex: number, bindingIdx: number, expr: o.Expression): o.Expression { function callUnwrapValue(nodeIndex: number, bindingIdx: number, expr: o.Expression): o.Expression {
return o.importExpr(createIdentifier(Identifiers.unwrapValue)).callFn([ return o.importExpr(Identifiers.unwrapValue).callFn([
VIEW_VAR, o.literal(nodeIndex), o.literal(bindingIdx), expr VIEW_VAR, o.literal(nodeIndex), o.literal(bindingIdx), expr
]); ]);
} }

View File

@ -8,6 +8,8 @@
import {AotSummaryResolver, AotSummaryResolverHost, CompileSummaryKind, CompileTypeSummary, ResolvedStaticSymbol, StaticSymbol, StaticSymbolCache, StaticSymbolResolver} from '@angular/compiler'; import {AotSummaryResolver, AotSummaryResolverHost, CompileSummaryKind, CompileTypeSummary, ResolvedStaticSymbol, StaticSymbol, StaticSymbolCache, StaticSymbolResolver} from '@angular/compiler';
import {deserializeSummaries, serializeSummaries} from '@angular/compiler/src/aot/summary_serializer'; import {deserializeSummaries, serializeSummaries} from '@angular/compiler/src/aot/summary_serializer';
import * as o from '@angular/compiler/src/output/output_ast';
import {OutputContext} from '@angular/compiler/src/util';
import * as path from 'path'; import * as path from 'path';
import {MockStaticSymbolResolverHost, MockSummaryResolver} from './static_symbol_resolver_spec'; import {MockStaticSymbolResolverHost, MockSummaryResolver} from './static_symbol_resolver_spec';
@ -32,7 +34,9 @@ export function main() {
const mockSummaryResolver = new MockSummaryResolver([]); const mockSummaryResolver = new MockSummaryResolver([]);
const symbolResolver = new StaticSymbolResolver( const symbolResolver = new StaticSymbolResolver(
new MockStaticSymbolResolverHost({}), symbolCache, mockSummaryResolver); new MockStaticSymbolResolverHost({}), symbolCache, mockSummaryResolver);
return serializeSummaries(mockSummaryResolver, symbolResolver, symbols, []).json; return serializeSummaries(
createMockOutputContext(), mockSummaryResolver, symbolResolver, symbols, [])
.json;
} }
it('should load serialized summary files', () => { it('should load serialized summary files', () => {
@ -108,4 +112,8 @@ export class MockAotSummaryResolverHost implements AotSummaryResolverHost {
isSourceFile(filePath: string) { return !filePath.endsWith('.d.ts'); } isSourceFile(filePath: string) { return !filePath.endsWith('.d.ts'); }
loadSummary(filePath: string): string { return this.summaries[filePath]; } loadSummary(filePath: string): string { return this.summaries[filePath]; }
}
export function createMockOutputContext(): OutputContext {
return {statements: [], genFilePath: 'someGenFilePath', importExpr: () => o.NULL_EXPR};
} }

View File

@ -11,7 +11,7 @@ import {deserializeSummaries, serializeSummaries} from '@angular/compiler/src/ao
import {summaryFileName} from '@angular/compiler/src/aot/util'; import {summaryFileName} from '@angular/compiler/src/aot/util';
import {MockStaticSymbolResolverHost} from './static_symbol_resolver_spec'; import {MockStaticSymbolResolverHost} from './static_symbol_resolver_spec';
import {MockAotSummaryResolverHost} from './summary_resolver_spec'; import {MockAotSummaryResolverHost, createMockOutputContext} from './summary_resolver_spec';
export function main() { export function main() {
@ -43,7 +43,7 @@ export function main() {
it('should serialize various data correctly', () => { it('should serialize various data correctly', () => {
init(); init();
const serializedData = serializeSummaries( const serializedData = serializeSummaries(
summaryResolver, symbolResolver, createMockOutputContext(), summaryResolver, symbolResolver,
[ [
{ {
symbol: symbolCache.get('/tmp/some_values.ts', 'Values'), symbol: symbolCache.get('/tmp/some_values.ts', 'Values'),
@ -105,34 +105,35 @@ export function main() {
it('should automatically add exported directives / pipes of NgModules that are not source files', it('should automatically add exported directives / pipes of NgModules that are not source files',
() => { () => {
init(); init();
const externalSerialized = serializeSummaries(summaryResolver, symbolResolver, [], [ const externalSerialized =
{ serializeSummaries(createMockOutputContext(), summaryResolver, symbolResolver, [], [
summary: { {
summaryKind: CompileSummaryKind.Pipe, summary: {
type: { summaryKind: CompileSummaryKind.Pipe,
reference: symbolCache.get('/tmp/external.ts', 'SomeExternalPipe'), type: {
} reference: symbolCache.get('/tmp/external.ts', 'SomeExternalPipe'),
} as any, }
metadata: null as any } as any,
}, metadata: null as any
{
summary: {
summaryKind: CompileSummaryKind.Directive,
type: {
reference: symbolCache.get('/tmp/external.ts', 'SomeExternalDir'),
}, },
providers: [], {
viewProviders: [], summary: {
} as any, summaryKind: CompileSummaryKind.Directive,
metadata: null as any type: {
} reference: symbolCache.get('/tmp/external.ts', 'SomeExternalDir'),
]); },
providers: [],
viewProviders: [],
} as any,
metadata: null as any
}
]);
init({ init({
'/tmp/external.ngsummary.json': externalSerialized.json, '/tmp/external.ngsummary.json': externalSerialized.json,
}); });
const serialized = serializeSummaries( const serialized = serializeSummaries(
summaryResolver, symbolResolver, [], [{ createMockOutputContext(), summaryResolver, symbolResolver, [], [{
summary: <any>{ summary: <any>{
summaryKind: CompileSummaryKind.NgModule, summaryKind: CompileSummaryKind.NgModule,
type: {reference: symbolCache.get('/tmp/some_module.ts', 'SomeModule')}, type: {reference: symbolCache.get('/tmp/some_module.ts', 'SomeModule')},
@ -162,7 +163,7 @@ export function main() {
() => { () => {
init(); init();
const externalSerialized = serializeSummaries( const externalSerialized = serializeSummaries(
summaryResolver, symbolResolver, createMockOutputContext(), summaryResolver, symbolResolver,
[ [
{ {
symbol: symbolCache.get('/tmp/external.ts', 'PROVIDERS'), symbol: symbolCache.get('/tmp/external.ts', 'PROVIDERS'),
@ -194,7 +195,7 @@ export function main() {
{__symbolic: 'module', version: 3, metadata: {'external': 'b'}} {__symbolic: 'module', version: 3, metadata: {'external': 'b'}}
}); });
const serialized = serializeSummaries( const serialized = serializeSummaries(
summaryResolver, symbolResolver, [{ createMockOutputContext(), summaryResolver, symbolResolver, [{
symbol: symbolCache.get('/tmp/test.ts', 'main'), symbol: symbolCache.get('/tmp/test.ts', 'main'),
metadata: { metadata: {
local: symbolCache.get('/tmp/local.ts', 'local'), local: symbolCache.get('/tmp/local.ts', 'local'),
@ -229,7 +230,7 @@ export function main() {
it('should create "importAs" names for non source symbols', () => { it('should create "importAs" names for non source symbols', () => {
init(); init();
const serialized = serializeSummaries( const serialized = serializeSummaries(
summaryResolver, symbolResolver, [{ createMockOutputContext(), summaryResolver, symbolResolver, [{
symbol: symbolCache.get('/tmp/test.ts', 'main'), symbol: symbolCache.get('/tmp/test.ts', 'main'),
metadata: [ metadata: [
symbolCache.get('/tmp/external.d.ts', 'lib'), symbolCache.get('/tmp/external.d.ts', 'lib'),

View File

@ -18,7 +18,7 @@ export function main() {
const fileB = new ParseSourceFile('b0b1b2b3b4b5b6b7b8b9', 'b.js'); const fileB = new ParseSourceFile('b0b1b2b3b4b5b6b7b8b9', 'b.js');
let ctx: EmitterVisitorContext; let ctx: EmitterVisitorContext;
beforeEach(() => { ctx = EmitterVisitorContext.createRoot([]); }); beforeEach(() => { ctx = EmitterVisitorContext.createRoot(); });
it('should add source files to the source map', () => { it('should add source files to the source map', () => {
ctx.print(createSourceSpan(fileA, 0), 'o0'); ctx.print(createSourceSpan(fileA, 0), 'o0');

View File

@ -10,7 +10,6 @@ import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata'; import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
import {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter'; import {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter';
import * as o from '@angular/compiler/src/output/output_ast'; import * as o from '@angular/compiler/src/output/output_ast';
import {ImportResolver} from '@angular/compiler/src/output/path_util';
import {SourceMap} from '@angular/compiler/src/output/source_map'; import {SourceMap} from '@angular/compiler/src/output/source_map';
import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '@angular/compiler/src/parse_util'; import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '@angular/compiler/src/parse_util';
@ -19,31 +18,16 @@ import {extractSourceMap, originalPositionFor} from './source_map_util';
const someGenFilePath = 'somePackage/someGenFile'; const someGenFilePath = 'somePackage/someGenFile';
const someSourceFilePath = 'somePackage/someSourceFile'; const someSourceFilePath = 'somePackage/someSourceFile';
class SimpleJsImportGenerator implements ImportResolver {
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
return importedUrlStr;
}
getImportAs(symbol: StaticSymbol): StaticSymbol|null { return null; }
getTypeArity(symbol: StaticSymbol): number|null { return null; }
}
export function main() { export function main() {
describe('JavaScriptEmitter', () => { describe('JavaScriptEmitter', () => {
let importResolver: ImportResolver;
let emitter: JavaScriptEmitter; let emitter: JavaScriptEmitter;
let someVar: o.ReadVarExpr; let someVar: o.ReadVarExpr;
beforeEach(() => { beforeEach(() => { emitter = new JavaScriptEmitter(); });
importResolver = new SimpleJsImportGenerator();
emitter = new JavaScriptEmitter(importResolver);
});
function emitSourceMap( function emitSourceMap(stmt: o.Statement | o.Statement[], preamble?: string): SourceMap {
stmt: o.Statement | o.Statement[], exportedVars: string[] | null = null,
preamble?: string): SourceMap {
const stmts = Array.isArray(stmt) ? stmt : [stmt]; const stmts = Array.isArray(stmt) ? stmt : [stmt];
const source = emitter.emitStatements( const source = emitter.emitStatements(someSourceFilePath, someGenFilePath, stmts, preamble);
someSourceFilePath, someGenFilePath, stmts, exportedVars || [], preamble);
return extractSourceMap(source) !; return extractSourceMap(source) !;
} }
@ -54,7 +38,7 @@ export function main() {
const endLocation = new ParseLocation(source, 7, 0, 6); const endLocation = new ParseLocation(source, 7, 0, 6);
const sourceSpan = new ParseSourceSpan(startLocation, endLocation); const sourceSpan = new ParseSourceSpan(startLocation, endLocation);
const someVar = o.variable('someVar', null, sourceSpan); const someVar = o.variable('someVar', null, sourceSpan);
const sm = emitSourceMap(someVar.toStmt(), [], '/* MyPreamble \n */'); const sm = emitSourceMap(someVar.toStmt(), '/* MyPreamble \n */');
expect(sm.sources).toEqual([someSourceFilePath, 'in.js']); expect(sm.sources).toEqual([someSourceFilePath, 'in.js']);
expect(sm.sourcesContent).toEqual([' ', ';;;var']); expect(sm.sourcesContent).toEqual([' ', ';;;var']);

View File

@ -7,10 +7,8 @@
*/ */
import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol'; import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
import {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter'; import {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter';
import * as o from '@angular/compiler/src/output/output_ast'; import * as o from '@angular/compiler/src/output/output_ast';
import {ImportResolver} from '@angular/compiler/src/output/path_util';
import {stripSourceMapAndNewLine} from './abstract_emitter_spec'; import {stripSourceMapAndNewLine} from './abstract_emitter_spec';
@ -18,20 +16,9 @@ const someGenFilePath = 'somePackage/someGenFile';
const someSourceFilePath = 'somePackage/someSourceFile'; const someSourceFilePath = 'somePackage/someSourceFile';
const anotherModuleUrl = 'somePackage/someOtherPath'; const anotherModuleUrl = 'somePackage/someOtherPath';
const sameModuleIdentifier: CompileIdentifierMetadata = { const sameModuleIdentifier = new o.ExternalReference(null, 'someLocalId', null);
reference: new StaticSymbol(someGenFilePath, 'someLocalId', [])
};
const externalModuleIdentifier: CompileIdentifierMetadata = {
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId', [])
};
class SimpleJsImportGenerator implements ImportResolver { const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'someExternalId', null);
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
return importedUrlStr;
}
getImportAs(symbol: StaticSymbol): StaticSymbol|null { return null; }
getTypeArity(symbol: StaticSymbol): number|null { return null; }
}
export function main() { export function main() {
// Note supported features of our OutputAstin JavaScript / ES5: // Note supported features of our OutputAstin JavaScript / ES5:
@ -39,29 +26,26 @@ export function main() {
// - declaring fields // - declaring fields
describe('JavaScriptEmitter', () => { describe('JavaScriptEmitter', () => {
let importResolver: ImportResolver;
let emitter: JavaScriptEmitter; let emitter: JavaScriptEmitter;
let someVar: o.ReadVarExpr; let someVar: o.ReadVarExpr;
beforeEach(() => { beforeEach(() => {
importResolver = new SimpleJsImportGenerator(); emitter = new JavaScriptEmitter();
emitter = new JavaScriptEmitter(importResolver);
someVar = o.variable('someVar'); someVar = o.variable('someVar');
}); });
function emitStmt( function emitStmt(stmt: o.Statement, preamble?: string): string {
stmt: o.Statement, exportedVars: string[] | null = null, preamble?: string): string { const source = emitter.emitStatements(someSourceFilePath, someGenFilePath, [stmt], preamble);
const source = emitter.emitStatements(
someSourceFilePath, someGenFilePath, [stmt], exportedVars || [], preamble);
return stripSourceMapAndNewLine(source); return stripSourceMapAndNewLine(source);
} }
it('should declare variables', () => { it('should declare variables', () => {
expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt())).toEqual(`var someVar = 1;`); expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt())).toEqual(`var someVar = 1;`);
expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt(), ['someVar'])).toEqual([ expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt(null, [o.StmtModifier.Exported])))
'var someVar = 1;', .toEqual([
`Object.defineProperty(exports, 'someVar', { get: function() { return someVar; }});` 'var someVar = 1;',
].join('\n')); `Object.defineProperty(exports, 'someVar', { get: function() { return someVar; }});`
].join('\n'));
}); });
it('should read and write variables', () => { it('should read and write variables', () => {
@ -144,16 +128,6 @@ export function main() {
].join('\n')); ].join('\n'));
}); });
it('should support `importAs` for external identifiers', () => {
spyOn(importResolver, 'getImportAs')
.and.returnValue(new StaticSymbol('somePackage/importAsModule', 'importAsName', []));
expect(emitStmt(o.importExpr(externalModuleIdentifier).toStmt())).toEqual([
`var i0 = re` +
`quire('somePackage/importAsModule');`,
`i0.importAsName;`
].join('\n'));
});
it('should support operators', () => { it('should support operators', () => {
const lhs = o.variable('lhs'); const lhs = o.variable('lhs');
const rhs = o.variable('rhs'); const rhs = o.variable('rhs');
@ -193,10 +167,11 @@ export function main() {
it('should support function statements', () => { it('should support function statements', () => {
expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [ expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [
]))).toEqual(['function someFn() {', '}'].join('\n')); ]))).toEqual(['function someFn() {', '}'].join('\n'));
expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], []), ['someFn'])).toEqual([ expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [], null, [o.StmtModifier.Exported])))
'function someFn() {', '}', .toEqual([
`Object.defineProperty(exports, 'someFn', { get: function() { return someFn; }});` 'function someFn() {', '}',
].join('\n')); `Object.defineProperty(exports, 'someFn', { get: function() { return someFn; }});`
].join('\n'));
expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [ expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [
new o.ReturnStatement(o.literal(1)) new o.ReturnStatement(o.literal(1))
]))).toEqual(['function someFn() {', ' return 1;', '}'].join('\n')); ]))).toEqual(['function someFn() {', ' return 1;', '}'].join('\n'));
@ -240,7 +215,8 @@ export function main() {
it('should support declaring classes', () => { it('should support declaring classes', () => {
expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [
]))).toEqual(['function SomeClass() {', '}'].join('\n')); ]))).toEqual(['function SomeClass() {', '}'].join('\n'));
expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, []), ['SomeClass'])) expect(emitStmt(new o.ClassStmt(
'SomeClass', null !, [], [], null !, [], [o.StmtModifier.Exported])))
.toEqual([ .toEqual([
'function SomeClass() {', '}', 'function SomeClass() {', '}',
`Object.defineProperty(exports, 'SomeClass', { get: function() { return SomeClass; }});` `Object.defineProperty(exports, 'SomeClass', { get: function() { return SomeClass; }});`
@ -319,7 +295,7 @@ export function main() {
}); });
it('should support a preamble', () => { it('should support a preamble', () => {
expect(emitStmt(o.variable('a').toStmt(), [], '/* SomePreamble */')).toBe([ expect(emitStmt(o.variable('a').toStmt(), '/* SomePreamble */')).toBe([
'/* SomePreamble */', 'a;' '/* SomePreamble */', 'a;'
].join('\n')); ].join('\n'));
}); });

View File

@ -9,7 +9,6 @@
import {ParseLocation, ParseSourceFile} from '@angular/compiler'; import {ParseLocation, ParseSourceFile} from '@angular/compiler';
import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol'; import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
import * as o from '@angular/compiler/src/output/output_ast'; import * as o from '@angular/compiler/src/output/output_ast';
import {ImportResolver} from '@angular/compiler/src/output/path_util';
import {SourceMap} from '@angular/compiler/src/output/source_map'; import {SourceMap} from '@angular/compiler/src/output/source_map';
import {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter'; import {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter';
import {ParseSourceSpan} from '@angular/compiler/src/parse_util'; import {ParseSourceSpan} from '@angular/compiler/src/parse_util';
@ -19,36 +18,23 @@ import {extractSourceMap, originalPositionFor} from './source_map_util';
const someGenFilePath = 'somePackage/someGenFile'; const someGenFilePath = 'somePackage/someGenFile';
const someSourceFilePath = 'somePackage/someSourceFile'; const someSourceFilePath = 'somePackage/someSourceFile';
class SimpleJsImportGenerator implements ImportResolver {
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
return importedUrlStr;
}
getImportAs(symbol: StaticSymbol): StaticSymbol|null { return null; }
getTypeArity(symbol: StaticSymbol): number|null { return null; }
}
export function main() { export function main() {
// Not supported features of our OutputAst in TS: // Not supported features of our OutputAst in TS:
// - real `const` like in Dart // - real `const` like in Dart
// - final fields // - final fields
describe('TypeScriptEmitter', () => { describe('TypeScriptEmitter', () => {
let importResolver: ImportResolver;
let emitter: TypeScriptEmitter; let emitter: TypeScriptEmitter;
let someVar: o.ReadVarExpr; let someVar: o.ReadVarExpr;
beforeEach(() => { beforeEach(() => {
importResolver = new SimpleJsImportGenerator(); emitter = new TypeScriptEmitter();
emitter = new TypeScriptEmitter(importResolver);
someVar = o.variable('someVar'); someVar = o.variable('someVar');
}); });
function emitSourceMap( function emitSourceMap(stmt: o.Statement | o.Statement[], preamble?: string): SourceMap {
stmt: o.Statement | o.Statement[], exportedVars: string[] | null = null,
preamble?: string): SourceMap {
const stmts = Array.isArray(stmt) ? stmt : [stmt]; const stmts = Array.isArray(stmt) ? stmt : [stmt];
const source = emitter.emitStatements( const source = emitter.emitStatements(someSourceFilePath, someGenFilePath, stmts, preamble);
someSourceFilePath, someGenFilePath, stmts, exportedVars || [], preamble);
return extractSourceMap(source) !; return extractSourceMap(source) !;
} }
@ -59,7 +45,7 @@ export function main() {
const endLocation = new ParseLocation(source, 7, 0, 6); const endLocation = new ParseLocation(source, 7, 0, 6);
const sourceSpan = new ParseSourceSpan(startLocation, endLocation); const sourceSpan = new ParseSourceSpan(startLocation, endLocation);
const someVar = o.variable('someVar', null, sourceSpan); const someVar = o.variable('someVar', null, sourceSpan);
const sm = emitSourceMap(someVar.toStmt(), [], '/* MyPreamble \n */'); const sm = emitSourceMap(someVar.toStmt(), '/* MyPreamble \n */');
expect(sm.sources).toEqual([someSourceFilePath, 'in.js']); expect(sm.sources).toEqual([someSourceFilePath, 'in.js']);
expect(sm.sourcesContent).toEqual([' ', ';;;var']); expect(sm.sourcesContent).toEqual([' ', ';;;var']);

View File

@ -7,9 +7,7 @@
*/ */
import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol'; import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
import * as o from '@angular/compiler/src/output/output_ast'; import * as o from '@angular/compiler/src/output/output_ast';
import {ImportResolver} from '@angular/compiler/src/output/path_util';
import {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter'; import {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter';
import {stripSourceMapAndNewLine} from './abstract_emitter_spec'; import {stripSourceMapAndNewLine} from './abstract_emitter_spec';
@ -18,21 +16,9 @@ const someGenFilePath = 'somePackage/someGenFile';
const someSourceFilePath = 'somePackage/someSourceFile'; const someSourceFilePath = 'somePackage/someSourceFile';
const anotherModuleUrl = 'somePackage/someOtherPath'; const anotherModuleUrl = 'somePackage/someOtherPath';
const sameModuleIdentifier: CompileIdentifierMetadata = { const sameModuleIdentifier = new o.ExternalReference(null, 'someLocalId', null);
reference: new StaticSymbol(someGenFilePath, 'someLocalId', [])
};
const externalModuleIdentifier: CompileIdentifierMetadata = { const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'someExternalId', null);
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId', [])
};
class SimpleJsImportGenerator implements ImportResolver {
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
return importedUrlStr;
}
getImportAs(symbol: StaticSymbol): StaticSymbol|null { return null; }
getTypeArity(symbol: StaticSymbol): number|null { return null; }
}
export function main() { export function main() {
// Not supported features of our OutputAst in TS: // Not supported features of our OutputAst in TS:
@ -40,22 +26,17 @@ export function main() {
// - final fields // - final fields
describe('TypeScriptEmitter', () => { describe('TypeScriptEmitter', () => {
let importResolver: ImportResolver;
let emitter: TypeScriptEmitter; let emitter: TypeScriptEmitter;
let someVar: o.ReadVarExpr; let someVar: o.ReadVarExpr;
beforeEach(() => { beforeEach(() => {
importResolver = new SimpleJsImportGenerator(); emitter = new TypeScriptEmitter();
emitter = new TypeScriptEmitter(importResolver);
someVar = o.variable('someVar', null, null); someVar = o.variable('someVar', null, null);
}); });
function emitStmt( function emitStmt(stmt: o.Statement | o.Statement[], preamble?: string): string {
stmt: o.Statement | o.Statement[], exportedVars: string[] | null = null,
preamble?: string): string {
const stmts = Array.isArray(stmt) ? stmt : [stmt]; const stmts = Array.isArray(stmt) ? stmt : [stmt];
const source = emitter.emitStatements( const source = emitter.emitStatements(someSourceFilePath, someGenFilePath, stmts, preamble);
someSourceFilePath, someGenFilePath, stmts, exportedVars || [], preamble);
return stripSourceMapAndNewLine(source); return stripSourceMapAndNewLine(source);
} }
@ -63,7 +44,7 @@ export function main() {
expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt())).toEqual(`var someVar:any = 1;`); expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt())).toEqual(`var someVar:any = 1;`);
expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt(null, [o.StmtModifier.Final]))) expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt(null, [o.StmtModifier.Final])))
.toEqual(`const someVar:any = 1;`); .toEqual(`const someVar:any = 1;`);
expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt(), ['someVar'])) expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt(null, [o.StmtModifier.Exported])))
.toEqual(`export var someVar:any = 1;`); .toEqual(`export var someVar:any = 1;`);
expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt(o.INT_TYPE))) expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt(o.INT_TYPE)))
.toEqual(`var someVar:number = 1;`); .toEqual(`var someVar:number = 1;`);
@ -74,8 +55,9 @@ export function main() {
describe('declare variables with ExternExpressions as values', () => { describe('declare variables with ExternExpressions as values', () => {
it('should create no reexport if the identifier is in the same module', () => { it('should create no reexport if the identifier is in the same module', () => {
// identifier is in the same module -> no reexport // identifier is in the same module -> no reexport
expect(emitStmt(someVar.set(o.importExpr(sameModuleIdentifier)).toDeclStmt(), ['someVar'])) expect(emitStmt(someVar.set(o.importExpr(sameModuleIdentifier)).toDeclStmt(null, [
.toEqual('export var someVar:any = someLocalId;'); o.StmtModifier.Exported
]))).toEqual('export var someVar:any = someLocalId;');
}); });
it('should create no reexport if the variable is not exported', () => { it('should create no reexport if the variable is not exported', () => {
@ -85,31 +67,17 @@ export function main() {
}); });
it('should create no reexport if the variable is typed', () => { it('should create no reexport if the variable is typed', () => {
expect(emitStmt( expect(emitStmt(someVar.set(o.importExpr(externalModuleIdentifier))
someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(o.DYNAMIC_TYPE), .toDeclStmt(o.DYNAMIC_TYPE, [o.StmtModifier.Exported])))
['someVar']))
.toEqual([ .toEqual([
`import * as i0 from 'somePackage/someOtherPath';`, `import * as i0 from 'somePackage/someOtherPath';`,
`export var someVar:any = i0.someExternalId;` `export var someVar:any = i0.someExternalId;`
].join('\n')); ].join('\n'));
}); });
it('should create no reexport if the identifier has members', () => {
const externalModuleIdentifierWithMembers: CompileIdentifierMetadata = {
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId', ['a'])
};
expect(emitStmt(
someVar.set(o.importExpr(externalModuleIdentifierWithMembers)).toDeclStmt(),
['someVar']))
.toEqual([
`import * as i0 from 'somePackage/someOtherPath';`,
`export var someVar:any = i0.someExternalId.a;`
].join('\n'));
});
it('should create a reexport', () => { it('should create a reexport', () => {
expect( expect(emitStmt(someVar.set(o.importExpr(externalModuleIdentifier))
emitStmt(someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(), ['someVar'])) .toDeclStmt(null, [o.StmtModifier.Exported])))
.toEqual([ .toEqual([
`export {someExternalId as someVar} from 'somePackage/someOtherPath';`, `` `export {someExternalId as someVar} from 'somePackage/someOtherPath';`, ``
].join('\n')); ].join('\n'));
@ -117,30 +85,19 @@ export function main() {
it('should create multiple reexports from the same file', () => { it('should create multiple reexports from the same file', () => {
const someVar2 = o.variable('someVar2'); const someVar2 = o.variable('someVar2');
const externalModuleIdentifier2: CompileIdentifierMetadata = { const externalModuleIdentifier2 =
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId2', []) new o.ExternalReference(anotherModuleUrl, 'someExternalId2', null);
}; expect(emitStmt([
expect(emitStmt( someVar.set(o.importExpr(externalModuleIdentifier))
[ .toDeclStmt(null, [o.StmtModifier.Exported]),
someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(), someVar2.set(o.importExpr(externalModuleIdentifier2))
someVar2.set(o.importExpr(externalModuleIdentifier2)).toDeclStmt() .toDeclStmt(null, [o.StmtModifier.Exported])
], ]))
['someVar', 'someVar2']))
.toEqual([ .toEqual([
`export {someExternalId as someVar,someExternalId2 as someVar2} from 'somePackage/someOtherPath';`, `export {someExternalId as someVar,someExternalId2 as someVar2} from 'somePackage/someOtherPath';`,
`` ``
].join('\n')); ].join('\n'));
}); });
it('should use `importAs` for reexports', () => {
spyOn(importResolver, 'getImportAs')
.and.returnValue(new StaticSymbol('somePackage/importAsModule', 'importAsName', []));
expect(
emitStmt(someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(), ['someVar']))
.toEqual([
`export {importAsName as someVar} from 'somePackage/importAsModule';`, ``
].join('\n'));
});
}); });
it('should read and write variables', () => { it('should read and write variables', () => {
@ -230,14 +187,6 @@ export function main() {
].join('\n')); ].join('\n'));
}); });
it('should support `importAs` for external identifiers', () => {
spyOn(importResolver, 'getImportAs')
.and.returnValue(new StaticSymbol('somePackage/importAsModule', 'importAsName', []));
expect(emitStmt(o.importExpr(externalModuleIdentifier).toStmt())).toEqual([
`import * as i0 from 'somePackage/importAsModule';`, `i0.importAsName;`
].join('\n'));
});
it('should support operators', () => { it('should support operators', () => {
const lhs = o.variable('lhs'); const lhs = o.variable('lhs');
const rhs = o.variable('rhs'); const rhs = o.variable('rhs');
@ -277,9 +226,8 @@ export function main() {
it('should support function statements', () => { it('should support function statements', () => {
expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [ expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [
]))).toEqual(['function someFn():void {', '}'].join('\n')); ]))).toEqual(['function someFn():void {', '}'].join('\n'));
expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], []), ['someFn'])).toEqual([ expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [], null, [o.StmtModifier.Exported])))
'export function someFn():void {', '}' .toEqual(['export function someFn():void {', '}'].join('\n'));
].join('\n'));
expect(emitStmt(new o.DeclareFunctionStmt( expect(emitStmt(new o.DeclareFunctionStmt(
'someFn', [], [new o.ReturnStatement(o.literal(1))], o.INT_TYPE))) 'someFn', [], [new o.ReturnStatement(o.literal(1))], o.INT_TYPE)))
.toEqual(['function someFn():number {', ' return 1;', '}'].join('\n')); .toEqual(['function someFn():number {', ' return 1;', '}'].join('\n'));
@ -324,8 +272,9 @@ export function main() {
it('should support declaring classes', () => { it('should support declaring classes', () => {
expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [
]))).toEqual(['class SomeClass {', '}'].join('\n')); ]))).toEqual(['class SomeClass {', '}'].join('\n'));
expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, []), ['SomeClass'])) expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [], [
.toEqual(['export class SomeClass {', '}'].join('\n')); o.StmtModifier.Exported
]))).toEqual(['export class SomeClass {', '}'].join('\n'));
expect(emitStmt(new o.ClassStmt('SomeClass', o.variable('SomeSuperClass'), [], [], null !, [ expect(emitStmt(new o.ClassStmt('SomeClass', o.variable('SomeSuperClass'), [], [], null !, [
]))).toEqual(['class SomeClass extends SomeSuperClass {', '}'].join('\n')); ]))).toEqual(['class SomeClass extends SomeSuperClass {', '}'].join('\n'));
}); });
@ -439,16 +388,6 @@ export function main() {
].join('\n')); ].join('\n'));
}); });
it('should support `importAs` for external types', () => {
spyOn(importResolver, 'getImportAs')
.and.returnValue(new StaticSymbol('somePackage/importAsModule', 'importAsName', []));
const writeVarExpr = o.variable('a').set(o.NULL_EXPR);
expect(emitStmt(writeVarExpr.toDeclStmt(o.importType(externalModuleIdentifier)))).toEqual([
`import * as i0 from 'somePackage/importAsModule';`,
`var a:i0.importAsName = (null as any);`
].join('\n'));
});
it('should support expression types', () => { it('should support expression types', () => {
expect( expect(
emitStmt(o.variable('a').set(o.NULL_EXPR).toDeclStmt(o.expressionType(o.variable('b'))))) emitStmt(o.variable('a').set(o.NULL_EXPR).toDeclStmt(o.expressionType(o.variable('b')))))
@ -479,7 +418,7 @@ export function main() {
}); });
it('should support a preamble', () => { it('should support a preamble', () => {
expect(emitStmt(o.variable('a').toStmt(), [], '/* SomePreamble */')).toBe([ expect(emitStmt(o.variable('a').toStmt(), '/* SomePreamble */')).toBe([
'/* SomePreamble */', 'a;' '/* SomePreamble */', 'a;'
].join('\n')); ].join('\n'));
}); });