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
*/
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 {Identifiers, createIdentifier, createIdentifierToken} from '../identifiers';
import {CompileMetadataResolver} from '../metadata_resolver';
@ -16,8 +16,8 @@ import * as o from '../output/output_ast';
import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
import {SummaryResolver} from '../summary_resolver';
import {TemplateParser} from '../template_parser/template_parser';
import {syntaxError} from '../util';
import {ViewCompiler} from '../view_compiler/view_compiler';
import {OutputContext, syntaxError} from '../util';
import {ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler';
import {AotCompilerHost} from './compiler_host';
import {GeneratedFile} from './generated_file';
@ -60,16 +60,15 @@ export class AotCompiler {
directives: StaticSymbol[], pipes: StaticSymbol[], ngModules: StaticSymbol[],
injectables: StaticSymbol[]): GeneratedFile[] {
const fileSuffix = splitTypescriptSuffix(srcFileUrl, true)[1];
const statements: o.Statement[] = [];
const exportedVars: string[] = [];
const generatedFiles: GeneratedFile[] = [];
generatedFiles.push(...this._createSummary(
srcFileUrl, directives, pipes, ngModules, injectables, statements, exportedVars));
const outputCtx = this._createOutputContext(ngfactoryFilePath(srcFileUrl, true));
generatedFiles.push(
...this._createSummary(srcFileUrl, directives, pipes, ngModules, injectables, outputCtx));
// compile all ng modules
exportedVars.push(
...ngModules.map((ngModuleType) => this._compileModule(ngModuleType, statements)));
ngModules.forEach((ngModuleType) => this._compileModule(outputCtx, ngModuleType));
// compile components
directives.forEach((dirType) => {
@ -86,22 +85,20 @@ export class AotCompiler {
_assertComponent(compMeta);
// compile styles
const stylesCompileResults = this._styleCompiler.compileComponent(compMeta);
stylesCompileResults.externalStylesheets.forEach((compiledStyleSheet) => {
generatedFiles.push(this._codgenStyles(srcFileUrl, compiledStyleSheet, fileSuffix));
const componentStylesheet = this._styleCompiler.compileComponent(outputCtx, compMeta);
// Note: compMeta is a component and therefore template is non null.
compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => {
generatedFiles.push(this._codegenStyles(srcFileUrl, compMeta, stylesheetMeta, fileSuffix));
});
// compile components
const compViewVars = this._compileComponent(
compMeta, ngModule, ngModule.transitiveModule.directives,
stylesCompileResults.componentStylesheet, fileSuffix, statements);
exportedVars.push(
this._compileComponentFactory(compMeta, ngModule, fileSuffix, statements),
compViewVars.viewClassVar, compViewVars.compRenderTypeVar);
outputCtx, compMeta, ngModule, ngModule.transitiveModule.directives, componentStylesheet,
fileSuffix);
this._compileComponentFactory(outputCtx, compMeta, ngModule, fileSuffix);
});
if (statements.length > 0) {
const srcModule = this._codegenSourceModule(
srcFileUrl, ngfactoryFilePath(srcFileUrl, true), statements, exportedVars);
if (outputCtx.statements.length > 0) {
const srcModule = this._codegenSourceModule(srcFileUrl, outputCtx);
generatedFiles.unshift(srcModule);
}
return generatedFiles;
@ -109,8 +106,8 @@ export class AotCompiler {
private _createSummary(
srcFileUrl: string, directives: StaticSymbol[], pipes: StaticSymbol[],
ngModules: StaticSymbol[], injectables: StaticSymbol[], targetStatements: o.Statement[],
targetExportedVars: string[]): GeneratedFile[] {
ngModules: StaticSymbol[], injectables: StaticSymbol[],
ngFactoryCtx: OutputContext): GeneratedFile[] {
const symbolSummaries = this._symbolResolver.getSymbolsOf(srcFileUrl)
.map(symbol => this._symbolResolver.resolveSymbol(symbol));
const typeData: {
@ -136,22 +133,23 @@ export class AotCompiler {
metadata: this._metadataResolver.getInjectableSummary(ref) !.type
}))
];
const {json, exportAs, forJit} =
serializeSummaries(this._summaryResolver, this._symbolResolver, symbolSummaries, typeData);
const forJitOutputCtx = this._createOutputContext(summaryForJitFileName(srcFileUrl, true));
const forJitTargetFilePath = summaryForJitFileName(srcFileUrl, true);
const {json, exportAs} = serializeSummaries(
forJitOutputCtx, this._summaryResolver, this._symbolResolver, symbolSummaries, typeData);
exportAs.forEach((entry) => {
targetStatements.push(
o.variable(entry.exportAs).set(o.importExpr({reference: entry.symbol})).toDeclStmt());
targetExportedVars.push(entry.exportAs);
ngFactoryCtx.statements.push(
o.variable(entry.exportAs).set(ngFactoryCtx.importExpr(entry.symbol)).toDeclStmt(null, [
o.StmtModifier.Exported
]));
});
return [
new GeneratedFile(srcFileUrl, summaryFileName(srcFileUrl), json),
this._codegenSourceModule(
srcFileUrl, summaryForJitFileName(srcFileUrl, true), forJit.statements,
forJit.exportedVars)
this._codegenSourceModule(srcFileUrl, forJitOutputCtx)
];
}
private _compileModule(ngModuleType: StaticSymbol, targetStatements: o.Statement[]): string {
private _compileModule(outputCtx: OutputContext, ngModuleType: StaticSymbol): void {
const ngModule = this._metadataResolver.getNgModuleMetadata(ngModuleType) !;
const providers: CompileProviderMetadata[] = [];
@ -169,20 +167,17 @@ export class AotCompiler {
});
}
const appCompileResult = this._ngModuleCompiler.compile(ngModule, providers);
targetStatements.push(...appCompileResult.statements);
return appCompileResult.ngModuleFactoryVar;
this._ngModuleCompiler.compile(outputCtx, ngModule, providers);
}
private _compileComponentFactory(
compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata, fileSuffix: string,
targetStatements: o.Statement[]): string {
outputCtx: OutputContext, compMeta: CompileDirectiveMetadata,
ngModule: CompileNgModuleMetadata, fileSuffix: string): void {
const hostType = this._metadataResolver.getHostComponentType(compMeta.type.reference);
const hostMeta = createHostComponentMeta(
hostType, compMeta, this._metadataResolver.getHostComponentViewClass(hostType));
const hostViewFactoryVar =
this._compileComponent(
hostMeta, ngModule, [compMeta.type], null, fileSuffix, targetStatements)
this._compileComponent(outputCtx, hostMeta, ngModule, [compMeta.type], null, fileSuffix)
.viewClassVar;
const compFactoryVar = componentFactoryName(compMeta.type.reference);
const inputsExprs: o.LiteralMapEntry[] = [];
@ -198,10 +193,10 @@ export class AotCompiler {
outputsExprs.push(new o.LiteralMapEntry(propName, o.literal(templateName), false));
}
targetStatements.push(
outputCtx.statements.push(
o.variable(compFactoryVar)
.set(o.importExpr(createIdentifier(Identifiers.createComponentFactory)).callFn([
o.literal(compMeta.selector), o.importExpr(compMeta.type),
.set(o.importExpr(Identifiers.createComponentFactory).callFn([
o.literal(compMeta.selector), outputCtx.importExpr(compMeta.type.reference),
o.variable(hostViewFactoryVar), new o.LiteralMapExpr(inputsExprs),
new o.LiteralMapExpr(outputsExprs),
o.literalArr(
@ -209,17 +204,16 @@ export class AotCompiler {
]))
.toDeclStmt(
o.importType(
createIdentifier(Identifiers.ComponentFactory), [o.importType(compMeta.type) !],
Identifiers.ComponentFactory,
[o.expressionType(outputCtx.importExpr(compMeta.type.reference)) !],
[o.TypeModifier.Const]),
[o.StmtModifier.Final]));
return compFactoryVar;
[o.StmtModifier.Final, o.StmtModifier.Exported]));
}
private _compileComponent(
compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata,
directiveIdentifiers: CompileIdentifierMetadata[], componentStyles: CompiledStylesheet|null,
fileSuffix: string,
targetStatements: o.Statement[]): {viewClassVar: string, compRenderTypeVar: string} {
outputCtx: OutputContext, compMeta: CompileDirectiveMetadata,
ngModule: CompileNgModuleMetadata, directiveIdentifiers: CompileIdentifierMetadata[],
componentStyles: CompiledStylesheet|null, fileSuffix: string): ViewCompileResult {
const directives =
directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
const pipes = ngModule.transitiveModule.pipes.map(
@ -229,44 +223,70 @@ export class AotCompiler {
compMeta, compMeta.template !.template !, directives, pipes, ngModule.schemas,
templateSourceUrl(ngModule.type, compMeta, compMeta.template !));
const stylesExpr = componentStyles ? o.variable(componentStyles.stylesVar) : o.literalArr([]);
const viewResult =
this._viewCompiler.compileComponent(compMeta, parsedTemplate, stylesExpr, usedPipes);
const viewResult = this._viewCompiler.compileComponent(
outputCtx, compMeta, parsedTemplate, stylesExpr, usedPipes);
if (componentStyles) {
targetStatements.push(
..._resolveStyleStatements(this._symbolResolver, componentStyles, fileSuffix));
_resolveStyleStatements(
this._symbolResolver, componentStyles, this._styleCompiler.needsStyleShim(compMeta),
fileSuffix);
}
targetStatements.push(...viewResult.statements);
return {viewClassVar: viewResult.viewClassVar, compRenderTypeVar: viewResult.rendererTypeVar};
return viewResult;
}
private _codgenStyles(
fileUrl: string, stylesCompileResult: CompiledStylesheet, fileSuffix: string): GeneratedFile {
_resolveStyleStatements(this._symbolResolver, stylesCompileResult, fileSuffix);
return this._codegenSourceModule(
fileUrl,
_stylesModuleUrl(
stylesCompileResult.meta.moduleUrl !, stylesCompileResult.isShimmed, fileSuffix),
stylesCompileResult.statements, [stylesCompileResult.stylesVar]);
private _createOutputContext(genFilePath: string): OutputContext {
const importExpr = (symbol: StaticSymbol, typeParams: o.Type[] | null = null) => {
if (!(symbol instanceof StaticSymbol)) {
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
}
const arity = this._symbolResolver.getTypeArity(symbol) || 0;
const {filePath, name, members} = this._symbolResolver.getImportAs(symbol) || symbol;
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(
srcFileUrl: string, genFileUrl: string, statements: o.Statement[],
exportedVars: string[]): GeneratedFile {
private _codegenStyles(
srcFileUrl: string, compMeta: CompileDirectiveMetadata,
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(
srcFileUrl, genFileUrl,
srcFileUrl, ctx.genFilePath,
this._outputEmitter.emitStatements(
sourceUrl(srcFileUrl), genFileUrl, statements, exportedVars, this._genFilePreamble));
sourceUrl(srcFileUrl), ctx.genFilePath, ctx.statements, this._genFilePreamble));
}
}
function _resolveStyleStatements(
reflector: StaticSymbolResolver, compileResult: CompiledStylesheet,
fileSuffix: string): o.Statement[] {
symbolResolver: StaticSymbolResolver, compileResult: CompiledStylesheet, needsShim: boolean,
fileSuffix: string): void {
compileResult.dependencies.forEach((dep) => {
dep.valuePlaceholder.reference = reflector.getStaticSymbol(
_stylesModuleUrl(dep.moduleUrl, dep.isShimmed, fileSuffix), dep.name);
dep.setValue(symbolResolver.getStaticSymbol(
_stylesModuleUrl(dep.moduleUrl, needsShim, fileSuffix), dep.name));
});
return compileResult.statements;
}
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 compiler = new AotCompiler(
config, compilerHost, resolver, tmplParser, new StyleCompiler(urlResolver), viewCompiler,
new NgModuleCompiler(), new TypeScriptEmitter(symbolResolver), summaryResolver,
options.locale || null, options.i18nFormat || null, options.genFilePreamble || null,
symbolResolver);
new NgModuleCompiler(), new TypeScriptEmitter(), summaryResolver, options.locale || null,
options.i18nFormat || null, options.genFilePreamble || null, symbolResolver);
return {compiler, reflector: staticReflector};
}

View File

@ -8,25 +8,21 @@
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileNgModuleMetadata, CompileNgModuleSummary, CompilePipeMetadata, CompileProviderMetadata, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary} from '../compile_metadata';
import * as o from '../output/output_ast';
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 {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
import {summaryForJitFileName, summaryForJitName} from './util';
export function serializeSummaries(
summaryResolver: SummaryResolver<StaticSymbol>, symbolResolver: StaticSymbolResolver,
symbols: ResolvedStaticSymbol[], types: {
forJitCtx: OutputContext, summaryResolver: SummaryResolver<StaticSymbol>,
symbolResolver: StaticSymbolResolver, symbols: ResolvedStaticSymbol[], types: {
summary: CompileTypeSummary,
metadata: CompileNgModuleMetadata | CompileDirectiveMetadata | CompilePipeMetadata |
CompileTypeMetadata
}[]): {
json: string,
exportAs: {symbol: StaticSymbol, exportAs: string}[],
forJit: {statements: o.Statement[], exportedVars: string[]}
} {
}[]): {json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} {
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
// (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 {statements, exportedVars} = forJitSerializer.serialize(exportAs);
return {json, forJit: {statements, exportedVars}, exportAs};
forJitSerializer.serialize(exportAs);
return {json, exportAs};
}
export function deserializeSummaries(symbolCache: StaticSymbolCache, json: string):
@ -192,7 +188,7 @@ class ForJitSerializer {
isLibrary: boolean
}>();
constructor(private symbolResolver: StaticSymbolResolver) {}
constructor(private outputCtx: OutputContext, private symbolResolver: StaticSymbolResolver) {}
addSourceType(
summary: CompileTypeSummary, metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|
@ -204,10 +200,7 @@ class ForJitSerializer {
this.data.set(summary.type.reference, {summary, metadata: null, isLibrary: true});
}
serialize(exportAs: {symbol: StaticSymbol, exportAs: string}[]):
{statements: o.Statement[], exportedVars: string[]} {
const statements: o.Statement[] = [];
const exportedVars: string[] = [];
serialize(exportAs: {symbol: StaticSymbol, exportAs: string}[]): void {
const ngModuleSymbols = new Set<StaticSymbol>();
Array.from(this.data.values()).forEach(({summary, metadata, isLibrary}) => {
@ -222,11 +215,10 @@ class ForJitSerializer {
}
if (!isLibrary) {
const fnName = summaryForJitName(summary.type.reference.name);
statements.push(
this.outputCtx.statements.push(
o.fn([], [new o.ReturnStatement(this.serializeSummaryWithDeps(summary, metadata !))],
new o.ArrayType(o.DYNAMIC_TYPE))
.toDeclStmt(fnName, [o.StmtModifier.Final]));
exportedVars.push(fnName);
.toDeclStmt(fnName, [o.StmtModifier.Final, o.StmtModifier.Exported]));
}
});
@ -234,13 +226,12 @@ class ForJitSerializer {
const symbol = entry.symbol;
if (ngModuleSymbols.has(symbol)) {
const jitExportAsName = summaryForJitName(entry.exportAs);
statements.push(
o.variable(jitExportAsName).set(this.serializeSummaryRef(symbol)).toDeclStmt());
exportedVars.push(jitExportAsName);
this.outputCtx.statements.push(
o.variable(jitExportAsName).set(this.serializeSummaryRef(symbol)).toDeclStmt(null, [
o.StmtModifier.Exported
]));
}
});
return {statements, exportedVars};
}
private serializeSummaryWithDeps(
@ -283,10 +274,12 @@ class ForJitSerializer {
private serializeSummaryRef(typeSymbol: StaticSymbol): o.Expression {
const jitImportedSymbol = this.symbolResolver.getStaticSymbol(
summaryForJitFileName(typeSymbol.filePath), summaryForJitName(typeSymbol.name));
return o.importExpr({reference: jitImportedSymbol});
return this.outputCtx.importExpr(jitImportedSymbol);
}
private serializeSummary(data: {[key: string]: any}): o.Expression {
const outputCtx = this.outputCtx;
class Transformer implements ValueVisitor {
visitArray(arr: any[], context: any): any {
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); }
visitOther(value: any, context: any): any {
if (value instanceof StaticSymbol) {
return o.importExpr({reference: value});
return outputCtx.importExpr(value);
} else {
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/tags';
export {NgModuleCompiler} from './ng_module_compiler';
export * from './output/path_util';
export * from './output/ts_emitter';
export * from './parse_util';
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]));
return ast.expressions.length <= 9 ?
o.importExpr(createIdentifier(Identifiers.inlineInterpolate)).callFn(args) :
o.importExpr(createIdentifier(Identifiers.interpolate)).callFn([
args[0], o.literalArr(args.slice(1))
]);
o.importExpr(Identifiers.inlineInterpolate).callFn(args) :
o.importExpr(Identifiers.interpolate).callFn([args[0], o.literalArr(args.slice(1))]);
}
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 {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
import * as o from './output/output_ast';
const CORE = assetUrl('core');
export interface IdentifierSpec {
name: string;
moduleUrl: string;
runtime: any;
}
export class Identifiers {
static ANALYZE_FOR_ENTRY_COMPONENTS: IdentifierSpec = {
static ANALYZE_FOR_ENTRY_COMPONENTS: o.ExternalReference = {
name: 'ANALYZE_FOR_ENTRY_COMPONENTS',
moduleUrl: CORE,
moduleName: CORE,
runtime: ANALYZE_FOR_ENTRY_COMPONENTS
};
static ElementRef: IdentifierSpec = {name: 'ElementRef', moduleUrl: CORE, runtime: ElementRef};
static NgModuleRef: IdentifierSpec = {name: 'NgModuleRef', moduleUrl: CORE, runtime: NgModuleRef};
static ElementRef:
o.ExternalReference = {name: 'ElementRef', moduleName: CORE, runtime: ElementRef};
static NgModuleRef:
o.ExternalReference = {name: 'NgModuleRef', moduleName: CORE, runtime: NgModuleRef};
static ViewContainerRef:
IdentifierSpec = {name: 'ViewContainerRef', moduleUrl: CORE, runtime: ViewContainerRef};
static ChangeDetectorRef:
IdentifierSpec = {name: 'ChangeDetectorRef', moduleUrl: CORE, runtime: ChangeDetectorRef};
static QueryList: IdentifierSpec = {name: 'QueryList', moduleUrl: CORE, runtime: QueryList};
static TemplateRef: IdentifierSpec = {name: 'TemplateRef', moduleUrl: CORE, runtime: TemplateRef};
static CodegenComponentFactoryResolver: IdentifierSpec = {
o.ExternalReference = {name: 'ViewContainerRef', moduleName: CORE, runtime: ViewContainerRef};
static ChangeDetectorRef: o.ExternalReference = {
name: 'ChangeDetectorRef',
moduleName: CORE,
runtime: ChangeDetectorRef
};
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',
moduleUrl: CORE,
moduleName: CORE,
runtime: ɵCodegenComponentFactoryResolver
};
static ComponentFactoryResolver: IdentifierSpec = {
static ComponentFactoryResolver: o.ExternalReference = {
name: 'ComponentFactoryResolver',
moduleUrl: CORE,
moduleName: CORE,
runtime: ComponentFactoryResolver
};
static ComponentFactory:
IdentifierSpec = {name: 'ComponentFactory', moduleUrl: CORE, runtime: ComponentFactory};
o.ExternalReference = {name: 'ComponentFactory', moduleName: CORE, runtime: ComponentFactory};
static ComponentRef:
IdentifierSpec = {name: 'ComponentRef', moduleUrl: CORE, runtime: ComponentRef};
o.ExternalReference = {name: 'ComponentRef', moduleName: CORE, runtime: ComponentRef};
static NgModuleFactory:
IdentifierSpec = {name: 'NgModuleFactory', moduleUrl: CORE, runtime: NgModuleFactory};
static createModuleFactory: IdentifierSpec = {
o.ExternalReference = {name: 'NgModuleFactory', moduleName: CORE, runtime: NgModuleFactory};
static createModuleFactory: o.ExternalReference = {
name: 'ɵcmf',
moduleUrl: CORE,
moduleName: CORE,
runtime: ɵcmf,
};
static moduleDef: IdentifierSpec = {
static moduleDef: o.ExternalReference = {
name: 'ɵmod',
moduleUrl: CORE,
moduleName: CORE,
runtime: ɵmod,
};
static moduleProviderDef: IdentifierSpec = {
static moduleProviderDef: o.ExternalReference = {
name: 'ɵmpd',
moduleUrl: CORE,
moduleName: CORE,
runtime: ɵmpd,
};
static RegisterModuleFactoryFn: IdentifierSpec = {
static RegisterModuleFactoryFn: o.ExternalReference = {
name: 'ɵregisterModuleFactory',
moduleUrl: CORE,
moduleName: CORE,
runtime: ɵregisterModuleFactory,
};
static Injector: IdentifierSpec = {name: 'Injector', moduleUrl: CORE, runtime: Injector};
static ViewEncapsulation:
IdentifierSpec = {name: 'ViewEncapsulation', moduleUrl: CORE, runtime: ViewEncapsulation};
static ChangeDetectionStrategy: IdentifierSpec = {
static Injector: o.ExternalReference = {name: 'Injector', moduleName: CORE, runtime: Injector};
static ViewEncapsulation: o.ExternalReference = {
name: 'ViewEncapsulation',
moduleName: CORE,
runtime: ViewEncapsulation
};
static ChangeDetectionStrategy: o.ExternalReference = {
name: 'ChangeDetectionStrategy',
moduleUrl: CORE,
moduleName: CORE,
runtime: ChangeDetectionStrategy
};
static SecurityContext: IdentifierSpec = {
static SecurityContext: o.ExternalReference = {
name: 'SecurityContext',
moduleUrl: CORE,
moduleName: CORE,
runtime: SecurityContext,
};
static LOCALE_ID: IdentifierSpec = {name: 'LOCALE_ID', moduleUrl: CORE, runtime: LOCALE_ID};
static TRANSLATIONS_FORMAT:
IdentifierSpec = {name: 'TRANSLATIONS_FORMAT', moduleUrl: CORE, runtime: TRANSLATIONS_FORMAT};
static inlineInterpolate:
IdentifierSpec = {name: 'ɵinlineInterpolate', moduleUrl: CORE, runtime: ɵinlineInterpolate};
static LOCALE_ID: o.ExternalReference = {name: 'LOCALE_ID', moduleName: CORE, runtime: LOCALE_ID};
static TRANSLATIONS_FORMAT: o.ExternalReference = {
name: 'TRANSLATIONS_FORMAT',
moduleName: CORE,
runtime: TRANSLATIONS_FORMAT
};
static inlineInterpolate: o.ExternalReference = {
name: 'ɵinlineInterpolate',
moduleName: CORE,
runtime: ɵinlineInterpolate
};
static interpolate:
IdentifierSpec = {name: 'ɵinterpolate', moduleUrl: CORE, runtime: ɵinterpolate};
o.ExternalReference = {name: 'ɵinterpolate', moduleName: CORE, runtime: ɵinterpolate};
static EMPTY_ARRAY:
IdentifierSpec = {name: 'ɵEMPTY_ARRAY', moduleUrl: CORE, runtime: ɵEMPTY_ARRAY};
static EMPTY_MAP: IdentifierSpec = {name: 'ɵEMPTY_MAP', moduleUrl: CORE, runtime: ɵEMPTY_MAP};
static Renderer: IdentifierSpec = {name: 'Renderer', moduleUrl: CORE, runtime: Renderer};
static viewDef: IdentifierSpec = {name: 'ɵvid', moduleUrl: CORE, runtime: ɵvid};
static elementDef: IdentifierSpec = {name: 'ɵeld', moduleUrl: CORE, runtime: ɵeld};
static anchorDef: IdentifierSpec = {name: 'ɵand', moduleUrl: CORE, runtime: ɵand};
static textDef: IdentifierSpec = {name: 'ɵted', moduleUrl: CORE, runtime: ɵted};
static directiveDef: IdentifierSpec = {name: 'ɵdid', moduleUrl: CORE, runtime: ɵdid};
static providerDef: IdentifierSpec = {name: 'ɵprd', moduleUrl: CORE, runtime: ɵprd};
static queryDef: IdentifierSpec = {name: 'ɵqud', moduleUrl: CORE, runtime: ɵqud};
static pureArrayDef: IdentifierSpec = {name: 'ɵpad', moduleUrl: CORE, runtime: ɵpad};
static pureObjectDef: IdentifierSpec = {name: 'ɵpod', moduleUrl: CORE, runtime: ɵpod};
static purePipeDef: IdentifierSpec = {name: 'ɵppd', moduleUrl: CORE, runtime: ɵppd};
static pipeDef: IdentifierSpec = {name: 'ɵpid', moduleUrl: CORE, runtime: ɵpid};
static nodeValue: IdentifierSpec = {name: 'ɵnov', moduleUrl: CORE, runtime: ɵnov};
static ngContentDef: IdentifierSpec = {name: 'ɵncd', moduleUrl: CORE, runtime: ɵncd};
static unwrapValue: IdentifierSpec = {name: 'ɵunv', moduleUrl: CORE, runtime: ɵunv};
static createRendererType2: IdentifierSpec = {name: 'ɵcrt', moduleUrl: CORE, runtime: ɵcrt};
static RendererType2: IdentifierSpec = {
o.ExternalReference = {name: 'ɵEMPTY_ARRAY', moduleName: CORE, runtime: ɵEMPTY_ARRAY};
static EMPTY_MAP:
o.ExternalReference = {name: 'ɵEMPTY_MAP', moduleName: CORE, runtime: ɵEMPTY_MAP};
static Renderer: o.ExternalReference = {name: 'Renderer', moduleName: CORE, runtime: Renderer};
static viewDef: o.ExternalReference = {name: 'ɵvid', moduleName: CORE, runtime: ɵvid};
static elementDef: o.ExternalReference = {name: 'ɵeld', moduleName: CORE, runtime: ɵeld};
static anchorDef: o.ExternalReference = {name: 'ɵand', moduleName: CORE, runtime: ɵand};
static textDef: o.ExternalReference = {name: 'ɵted', moduleName: CORE, runtime: ɵted};
static directiveDef: o.ExternalReference = {name: 'ɵdid', moduleName: CORE, runtime: ɵdid};
static providerDef: o.ExternalReference = {name: 'ɵprd', moduleName: CORE, runtime: ɵprd};
static queryDef: o.ExternalReference = {name: 'ɵqud', moduleName: CORE, runtime: ɵqud};
static pureArrayDef: o.ExternalReference = {name: 'ɵpad', moduleName: CORE, runtime: ɵpad};
static pureObjectDef: o.ExternalReference = {name: 'ɵpod', moduleName: CORE, runtime: ɵpod};
static purePipeDef: o.ExternalReference = {name: 'ɵppd', moduleName: CORE, runtime: ɵppd};
static pipeDef: o.ExternalReference = {name: 'ɵpid', moduleName: CORE, runtime: ɵpid};
static nodeValue: o.ExternalReference = {name: 'ɵnov', moduleName: CORE, runtime: ɵnov};
static ngContentDef: o.ExternalReference = {name: 'ɵncd', moduleName: CORE, runtime: ɵncd};
static unwrapValue: o.ExternalReference = {name: 'ɵunv', moduleName: CORE, runtime: ɵunv};
static createRendererType2: o.ExternalReference = {name: 'ɵcrt', moduleName: CORE, runtime: ɵcrt};
static RendererType2: o.ExternalReference = {
name: 'RendererType2',
moduleUrl: CORE,
moduleName: CORE,
// type only
runtime: null
};
static ViewDefinition: IdentifierSpec = {
static ViewDefinition: o.ExternalReference = {
name: 'ɵViewDefinition',
moduleUrl: CORE,
moduleName: CORE,
// type only
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 {
@ -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;
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)};
}
@ -143,12 +155,12 @@ export function identifierToken(identifier: CompileIdentifierMetadata): CompileT
return {identifier: identifier};
}
export function createIdentifierToken(identifier: IdentifierSpec): CompileTokenMetadata {
export function createIdentifierToken(identifier: o.ExternalReference): CompileTokenMetadata {
return identifierToken(createIdentifier(identifier));
}
export function createEnumIdentifier(
enumType: IdentifierSpec, name: string): CompileIdentifierMetadata {
enumType: o.ExternalReference, name: string): CompileIdentifierMetadata {
const resolvedEnum = ɵreflector.resolveEnum(resolveIdentifier(enumType), name);
return {reference: resolvedEnum};
}

View File

@ -19,7 +19,7 @@ import {jitStatements} from '../output/output_jit';
import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
import {SummaryResolver} from '../summary_resolver';
import {TemplateParser} from '../template_parser/template_parser';
import {SyncAsyncResult} from '../util';
import {OutputContext, SyncAsyncResult} from '../util';
import {ViewCompiler} from '../view_compiler/view_compiler';
@ -153,14 +153,14 @@ export class JitCompiler implements Compiler {
// Always provide a bound Compiler
const extraProviders = [this._metadataResolver.getProviderMetadata(new ProviderMeta(
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) {
ngModuleFactory =
interpretStatements(compileResult.statements, [compileResult.ngModuleFactoryVar])[0];
interpretStatements(outputCtx.statements)[compileResult.ngModuleFactoryVar];
} else {
ngModuleFactory = jitStatements(
ngModuleJitUrl(moduleMeta), compileResult.statements,
[compileResult.ngModuleFactoryVar])[0];
ngModuleJitUrl(moduleMeta), outputCtx.statements, )[compileResult.ngModuleFactoryVar];
}
this._compiledNgModuleCache.set(moduleMeta.type.reference, ngModuleFactory);
}
@ -272,11 +272,14 @@ export class JitCompiler implements Compiler {
}
const compMeta = template.compMeta;
const externalStylesheetsByModuleUrl = new Map<string, CompiledStylesheet>();
const stylesCompileResult = this._styleCompiler.compileComponent(compMeta);
stylesCompileResult.externalStylesheets.forEach(
(r) => { externalStylesheetsByModuleUrl.set(r.meta.moduleUrl !, r); });
this._resolveStylesCompileResult(
stylesCompileResult.componentStylesheet, externalStylesheetsByModuleUrl);
const outputContext = createOutputContext();
const componentStylesheet = this._styleCompiler.compileComponent(outputContext, compMeta);
compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => {
const compiledStylesheet =
this._styleCompiler.compileStyles(createOutputContext(), compMeta, stylesheetMeta);
externalStylesheetsByModuleUrl.set(stylesheetMeta.moduleUrl !, compiledStylesheet);
});
this._resolveStylesCompileResult(componentStylesheet, externalStylesheetsByModuleUrl);
const directives =
template.directives.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
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,
templateSourceUrl(template.ngModule.type, template.compMeta, template.compMeta.template !));
const compileResult = this._viewCompiler.compileComponent(
compMeta, parsedTemplate, ir.variable(stylesCompileResult.componentStylesheet.stylesVar),
outputContext, compMeta, parsedTemplate, ir.variable(componentStylesheet.stylesVar),
usedPipes);
const statements =
stylesCompileResult.componentStylesheet.statements.concat(compileResult.statements);
let viewClassAndRendererTypeVars = compMeta.isHost ?
[compileResult.viewClassVar] :
[compileResult.viewClassVar, compileResult.rendererTypeVar];
let viewClass: any;
let rendererType: any;
let evalResult: any;
if (!this._compilerConfig.useJit) {
[viewClass, rendererType] = interpretStatements(statements, viewClassAndRendererTypeVars);
evalResult = interpretStatements(outputContext.statements);
} else {
[viewClass, rendererType] = jitStatements(
templateJitUrl(template.ngModule.type, template.compMeta), statements,
viewClassAndRendererTypeVars);
evalResult = jitStatements(
templateJitUrl(template.ngModule.type, template.compMeta), outputContext.statements);
}
const viewClass = evalResult[compileResult.viewClassVar];
const rendererType = evalResult[compileResult.rendererTypeVar];
template.compiled(viewClass, rendererType);
}
@ -310,7 +308,7 @@ export class JitCompiler implements Compiler {
const nestedCompileResult = externalStylesheetsByModuleUrl.get(dep.moduleUrl) !;
const nestedStylesArr = this._resolveAndEvalStylesCompileResult(
nestedCompileResult, externalStylesheetsByModuleUrl);
dep.valuePlaceholder.reference = nestedStylesArr;
dep.setValue(nestedStylesArr);
});
}
@ -319,11 +317,11 @@ export class JitCompiler implements Compiler {
externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>): string[] {
this._resolveStylesCompileResult(result, externalStylesheetsByModuleUrl);
if (!this._compilerConfig.useJit) {
return interpretStatements(result.statements, [result.stylesVar])[0];
return interpretStatements(result.outputCtx.statements)[result.stylesVar];
} else {
return jitStatements(
sharedStylesheetJitUrl(result.meta, this._sharedStylesheetCount++), result.statements,
[result.stylesVar])[0];
sharedStylesheetJitUrl(result.meta, this._sharedStylesheetCount++),
result.outputCtx.statements)[result.stylesVar];
}
}
}
@ -404,3 +402,9 @@ function flattenSummaries(fn: () => any[], out: CompileTypeSummary[] = []): Comp
});
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 {typeSourceSpan} from './parse_util';
import {NgModuleProviderAnalyzer} from './provider_analyzer';
import {OutputContext} from './util';
import {componentFactoryResolverProviderDef, depDef, providerDef} from './view_compiler/provider_compiler';
export class NgModuleCompileResult {
constructor(public statements: o.Statement[], public ngModuleFactoryVar: string) {}
constructor(public ngModuleFactoryVar: string) {}
}
const LOG_VAR = o.variable('_l');
@CompilerInjectable()
export class NgModuleCompiler {
compile(ngModuleMeta: CompileNgModuleMetadata, extraProviders: CompileProviderMetadata[]):
NgModuleCompileResult {
compile(
ctx: OutputContext, ngModuleMeta: CompileNgModuleMetadata,
extraProviders: CompileProviderMetadata[]): NgModuleCompileResult {
const sourceSpan = typeSourceSpan('NgModule', ngModuleMeta.type);
const entryComponentFactories = ngModuleMeta.transitiveModule.entryComponents;
const bootstrapComponents = ngModuleMeta.bootstrapComponents;
const providerParser = new NgModuleProviderAnalyzer(ngModuleMeta, extraProviders, sourceSpan);
const providerDefs =
[componentFactoryResolverProviderDef(NodeFlags.None, entryComponentFactories)]
.concat(providerParser.parse().map((provider) => providerDef(provider)))
[componentFactoryResolverProviderDef(ctx, NodeFlags.None, entryComponentFactories)]
.concat(providerParser.parse().map((provider) => providerDef(ctx, provider)))
.map(({providerExpr, depsExpr, flags, tokenExpr}) => {
return o.importExpr(createIdentifier(Identifiers.moduleProviderDef)).callFn([
return o.importExpr(Identifiers.moduleProviderDef).callFn([
o.literal(flags), tokenExpr, providerExpr, depsExpr
]);
});
const ngModuleDef =
o.importExpr(createIdentifier(Identifiers.moduleDef)).callFn([o.literalArr(providerDefs)]);
const ngModuleDef = o.importExpr(Identifiers.moduleDef).callFn([o.literalArr(providerDefs)]);
const ngModuleDefFactory = o.fn(
[new o.FnParam(LOG_VAR.name !)], [new o.ReturnStatement(ngModuleDef)], o.INFERRED_TYPE);
const ngModuleFactoryVar = `${identifierName(ngModuleMeta.type)}NgFactory`;
const ngModuleFactoryStmt =
o.variable(ngModuleFactoryVar)
.set(o.importExpr(createIdentifier(Identifiers.createModuleFactory)).callFn([
o.importExpr(ngModuleMeta.type),
o.literalArr(bootstrapComponents.map(id => o.importExpr(id))), ngModuleDefFactory
.set(o.importExpr(Identifiers.createModuleFactory).callFn([
ctx.importExpr(ngModuleMeta.type.reference),
o.literalArr(bootstrapComponents.map(id => ctx.importExpr(id.reference))),
ngModuleDefFactory
]))
.toDeclStmt(
o.importType(
createIdentifier(Identifiers.NgModuleFactory),
[o.importType(ngModuleMeta.type) !], [o.TypeModifier.Const]),
[o.StmtModifier.Final]);
Identifiers.NgModuleFactory,
[o.expressionType(ctx.importExpr(ngModuleMeta.type.reference)) !],
[o.TypeModifier.Const]),
[o.StmtModifier.Final, o.StmtModifier.Exported]);
const stmts: o.Statement[] = [ngModuleFactoryStmt];
ctx.statements.push(ngModuleFactoryStmt);
if (ngModuleMeta.id) {
const registerFactoryStmt =
o.importExpr(createIdentifier(Identifiers.RegisterModuleFactoryFn))
o.importExpr(Identifiers.RegisterModuleFactoryFn)
.callFn([o.literal(ngModuleMeta.id), o.variable(ngModuleFactoryVar)])
.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 {
abstract emitStatements(
srcFilePath: string, genFilePath: string, stmts: o.Statement[], exportedVars: string[],
srcFilePath: string, genFilePath: string, stmts: o.Statement[],
preamble?: string|null): string;
}
@ -31,21 +31,15 @@ class _EmittedLine {
}
export class EmitterVisitorContext {
static createRoot(exportedVars: string[]): EmitterVisitorContext {
return new EmitterVisitorContext(exportedVars, 0);
}
static createRoot(): EmitterVisitorContext { return new EmitterVisitorContext(0); }
private _lines: _EmittedLine[];
private _classes: o.ClassStmt[] = [];
constructor(private _exportedVars: string[], private _indent: number) {
this._lines = [new _EmittedLine(_indent)];
}
constructor(private _indent: number) { this._lines = [new _EmittedLine(_indent)]; }
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 {
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 {AbstractJsEmitterVisitor} from './abstract_js_emitter';
import * as o from './output_ast';
import {ImportResolver} from './path_util';
export class JavaScriptEmitter implements OutputEmitter {
constructor(private _importResolver: ImportResolver) {}
emitStatements(
srcFilePath: string, genFilePath: string, stmts: o.Statement[], exportedVars: string[],
srcFilePath: string, genFilePath: string, stmts: o.Statement[],
preamble: string = ''): string {
const converter = new JsEmitterVisitor(genFilePath, this._importResolver);
const ctx = EmitterVisitorContext.createRoot(exportedVars);
const converter = new JsEmitterVisitor();
const ctx = EmitterVisitorContext.createRoot();
converter.visitAllStatements(stmts, ctx);
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...
preambleLines.push(
`var ${prefix} = req` +
`uire('${this._importResolver.fileNameToModuleName(importedFilePath, genFilePath)}');`);
`uire('${importedModuleName}');`);
});
const sm =
@ -47,46 +44,36 @@ export class JavaScriptEmitter implements OutputEmitter {
class JsEmitterVisitor extends AbstractJsEmitterVisitor {
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 {
const {name, filePath} = this._resolveStaticSymbol(ast.value);
if (filePath != this._genFilePath) {
let prefix = this.importsWithPrefixes.get(filePath);
const {name, moduleName} = ast.value;
if (moduleName) {
let prefix = this.importsWithPrefixes.get(moduleName);
if (prefix == null) {
prefix = `i${this.importsWithPrefixes.size}`;
this.importsWithPrefixes.set(filePath, prefix);
this.importsWithPrefixes.set(moduleName, prefix);
}
ctx.print(ast, `${prefix}.`);
}
ctx.print(ast, name);
ctx.print(ast, name !);
return null;
}
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
super.visitDeclareVarStmt(stmt, ctx);
if (ctx.isExportedVar(stmt.name)) {
if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.println(stmt, exportVar(stmt.name));
}
return null;
}
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any {
super.visitDeclareFunctionStmt(stmt, ctx);
if (ctx.isExportedVar(stmt.name)) {
if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.println(stmt, exportVar(stmt.name));
}
return null;
}
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
super.visitDeclareClassStmt(stmt, ctx);
if (ctx.isExportedVar(stmt.name)) {
if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.println(stmt, exportVar(stmt.name));
}
return null;

View File

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

View File

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

View File

@ -35,19 +35,24 @@ function evalExpression(
return new Function(...fnArgNames.concat(fnBody))(...fnArgValues);
}
export function jitStatements(
sourceUrl: string, statements: o.Statement[], resultVars: string[]): any[] {
export function jitStatements(sourceUrl: string, statements: o.Statement[]): {[key: string]: any} {
const converter = new JitEmitterVisitor();
const ctx = EmitterVisitorContext.createRoot(resultVars);
const returnStmt =
new o.ReturnStatement(o.literalArr(resultVars.map(resultVar => o.variable(resultVar))));
converter.visitAllStatements(statements.concat([returnStmt]), ctx);
const ctx = EmitterVisitorContext.createRoot();
converter.visitAllStatements(statements, ctx);
converter.createReturnStmt(ctx);
return evalExpression(sourceUrl, ctx, converter.getArgs());
}
class JitEmitterVisitor extends AbstractJsEmitterVisitor {
private _evalArgNames: string[] = [];
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} {
const result: {[key: string]: any} = {};
@ -58,15 +63,36 @@ class JitEmitterVisitor extends AbstractJsEmitterVisitor {
}
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
const value = ast.value.reference;
const value = ast.value.runtime;
let id = this._evalArgValues.indexOf(value);
if (id === -1) {
id = this._evalArgValues.length;
this._evalArgValues.push(value);
const name = identifierName(ast.value) || 'val';
const name = identifierName({reference: ast.value.runtime}) || 'val';
this._evalArgNames.push(`jit_${name}${id}`);
}
ctx.print(ast, this._evalArgNames[id]);
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 * as o from './output_ast';
import {ImportResolver} from './path_util';
const _debugFilePath = '/debug/lib';
export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type | any[]):
string {
const converter = new _TsEmitterVisitor(_debugFilePath, {
fileNameToModuleName(filePath: string, containingFilePath: string) { return filePath; },
getImportAs(symbol: StaticSymbol | null) { return null; },
getTypeArity: symbol => null
});
const ctx = EmitterVisitorContext.createRoot([]);
const converter = new _TsEmitterVisitor();
const ctx = EmitterVisitorContext.createRoot();
const asts: any[] = Array.isArray(ast) ? ast : [ast];
asts.forEach((ast) => {
@ -42,30 +37,27 @@ export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.T
export class TypeScriptEmitter implements OutputEmitter {
constructor(private _importResolver: ImportResolver) {}
emitStatements(
srcFilePath: string, genFilePath: string, stmts: o.Statement[], exportedVars: string[],
srcFilePath: string, genFilePath: string, stmts: o.Statement[],
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);
const preambleLines = preamble ? preamble.split('\n') : [];
converter.reexports.forEach((reexports, exportedFilePath) => {
converter.reexports.forEach((reexports, exportedModuleName) => {
const reexportsCode =
reexports.map(reexport => `${reexport.name} as ${reexport.as}`).join(',');
preambleLines.push(
`export {${reexportsCode}} from '${this._importResolver.fileNameToModuleName(exportedFilePath, genFilePath)}';`);
preambleLines.push(`export {${reexportsCode}} from '${exportedModuleName}';`);
});
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...
preambleLines.push(
`imp` +
`ort * as ${prefix} from '${this._importResolver.fileNameToModuleName(importedFilePath, genFilePath)}';`);
`ort * as ${prefix} from '${importedModuleName}';`);
});
const sm =
@ -82,9 +74,7 @@ export class TypeScriptEmitter implements OutputEmitter {
class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor {
private typeExpression = 0;
constructor(private _genFilePath: string, private _importResolver: ImportResolver) {
super(false);
}
constructor() { super(false); }
importsWithPrefixes = new Map<string, 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 {
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
const {name, filePath, members} = this._resolveStaticSymbol(stmt.value.value);
if (members !.length === 0 && filePath !== this._genFilePath) {
let reexports = this.reexports.get(filePath);
const {name, moduleName} = stmt.value.value;
if (moduleName) {
let reexports = this.reexports.get(moduleName);
if (!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;
}
}
if (ctx.isExportedVar(stmt.name)) {
if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.print(stmt, `export `);
}
if (stmt.hasModifier(o.StmtModifier.Final)) {
@ -187,7 +178,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
ctx.pushClass(stmt);
if (ctx.isExportedVar(stmt.name)) {
if (stmt.hasModifier(o.StmtModifier.Exported)) {
ctx.print(stmt, `export `);
}
ctx.print(stmt, `class ${stmt.name}`);
@ -273,7 +264,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
}
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, `function ${stmt.name}(`);
@ -376,40 +367,18 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
}, 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(
value: CompileIdentifierMetadata, typeParams: o.Type[]|null,
ctx: EmitterVisitorContext): void {
const {name, filePath, members, arity} = this._resolveStaticSymbol(value);
if (filePath != this._genFilePath) {
let prefix = this.importsWithPrefixes.get(filePath);
value: o.ExternalReference, typeParams: o.Type[]|null, ctx: EmitterVisitorContext): void {
const {name, moduleName} = value;
if (moduleName) {
let prefix = this.importsWithPrefixes.get(moduleName);
if (prefix == null) {
prefix = `i${this.importsWithPrefixes.size}`;
this.importsWithPrefixes.set(filePath, prefix);
this.importsWithPrefixes.set(moduleName, prefix);
}
ctx.print(null, `${prefix}.`);
}
if (members !.length) {
ctx.print(null, name);
ctx.print(null, '.');
ctx.print(null, members !.join('.'));
} else {
ctx.print(null, name);
}
ctx.print(null, name !);
if (this.typeExpression > 0) {
// 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
// should not supply type parameters and be treated as a simple value reference
// to the constructor function itself.
const suppliedParameters = (typeParams && typeParams.length) || 0;
const additionalParameters = (arity || 0) - suppliedParameters;
if (suppliedParameters > 0 || additionalParameters > 0) {
const suppliedParameters = typeParams || [];
if (suppliedParameters.length > 0) {
ctx.print(null, `<`);
if (suppliedParameters > 0) {
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');
}
}
this.visitAllObjects(type => type.visitType(this, ctx), typeParams !, ctx, ',');
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';
export const QUOTED_KEYS = '$quoted$';
export function convertValueToOutputAst(value: any, type: o.Type | null = null): o.Expression {
return visitValue(value, new _ValueOutputAstTransformer(), type);
export function convertValueToOutputAst(
ctx: OutputContext, value: any, type: o.Type | null = null): o.Expression {
return visitValue(value, new _ValueOutputAstTransformer(ctx), type);
}
class _ValueOutputAstTransformer implements ValueTransformer {
constructor(private ctx: OutputContext) {}
visitArray(arr: any[], type: o.Type): o.Expression {
return o.literalArr(arr.map(value => visitValue(value, this, null)), type);
}
@ -38,7 +40,7 @@ class _ValueOutputAstTransformer implements ValueTransformer {
if (value instanceof o.Expression) {
return value;
} 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 {ShadowCss} from './shadow_css';
import {UrlResolver} from './url_resolver';
import {OutputContext} from './util';
const COMPONENT_VARIABLE = '%COMP%';
const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
@ -20,19 +21,12 @@ const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
export class StylesCompileDependency {
constructor(
public name: string, public moduleUrl: string, public isShimmed: boolean,
public valuePlaceholder: CompileIdentifierMetadata) {}
}
export class StylesCompileResult {
constructor(
public componentStylesheet: CompiledStylesheet,
public externalStylesheets: CompiledStylesheet[]) {}
public name: string, public moduleUrl: string, public setValue: (value: any) => void) {}
}
export class CompiledStylesheet {
constructor(
public statements: o.Statement[], public stylesVar: string,
public outputCtx: OutputContext, public stylesVar: string,
public dependencies: StylesCompileDependency[], public isShimmed: boolean,
public meta: CompileStylesheetMetadata) {}
}
@ -43,44 +37,53 @@ export class StyleCompiler {
constructor(private _urlResolver: UrlResolver) {}
compileComponent(comp: CompileDirectiveMetadata): StylesCompileResult {
compileComponent(outputCtx: OutputContext, comp: CompileDirectiveMetadata): CompiledStylesheet {
const template = comp.template !;
const externalStylesheets: CompiledStylesheet[] = [];
const componentStylesheet: CompiledStylesheet = this._compileStyles(
comp, new CompileStylesheetMetadata({
return this._compileStyles(
outputCtx, comp, new CompileStylesheetMetadata({
styles: template.styles,
styleUrls: template.styleUrls,
moduleUrl: identifierModuleUrl(comp.type)
}),
true);
template.externalStylesheets.forEach((stylesheetMeta) => {
const compiledStylesheet = this._compileStyles(comp, stylesheetMeta, false);
externalStylesheets.push(compiledStylesheet);
});
return new StylesCompileResult(componentStylesheet, externalStylesheets);
}
compileStyles(
outputCtx: OutputContext, comp: CompileDirectiveMetadata,
stylesheet: CompileStylesheetMetadata): CompiledStylesheet {
return this._compileStyles(outputCtx, comp, stylesheet, false);
}
needsStyleShim(comp: CompileDirectiveMetadata): boolean {
return comp.template !.encapsulation === ViewEncapsulation.Emulated;
}
private _compileStyles(
comp: CompileDirectiveMetadata, stylesheet: CompileStylesheetMetadata,
isComponentStylesheet: boolean): CompiledStylesheet {
const shim = comp.template !.encapsulation === ViewEncapsulation.Emulated;
const styleExpressions =
outputCtx: OutputContext, comp: CompileDirectiveMetadata,
stylesheet: CompileStylesheetMetadata, isComponentStylesheet: boolean): CompiledStylesheet {
const shim = this.needsStyleShim(comp);
const styleExpressions: o.Expression[] =
stylesheet.styles.map(plainStyle => o.literal(this._shimIfNeeded(plainStyle, shim)));
const dependencies: StylesCompileDependency[] = [];
for (let i = 0; i < stylesheet.styleUrls.length; i++) {
const identifier: CompileIdentifierMetadata = {reference: null};
stylesheet.styleUrls.forEach((styleUrl) => {
const exprIndex = styleExpressions.length;
// Note: This placeholder will be filled later.
styleExpressions.push(null !);
dependencies.push(new StylesCompileDependency(
getStylesVarName(null), stylesheet.styleUrls[i], shim, identifier));
styleExpressions.push(new o.ExternalExpr(identifier));
}
getStylesVarName(null), styleUrl,
(value) => styleExpressions[exprIndex] = outputCtx.importExpr(value)));
});
// styles variable contains plain strings and arrays of other styles arrays (recursive),
// so we set its type to dynamic.
const stylesVar = getStylesVarName(isComponentStylesheet ? comp : null);
const stmt = o.variable(stylesVar)
.set(o.literalArr(
styleExpressions, new o.ArrayType(o.DYNAMIC_TYPE, [o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]);
return new CompiledStylesheet([stmt], stylesVar, dependencies, shim, stylesheet);
.toDeclStmt(null, isComponentStylesheet ? [o.StmtModifier.Final] : [
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 {

View File

@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import * as o from './output/output_ast';
export const MODULE_SUFFIX = '';
const CAMEL_CASE_REGEXP = /([A-Z])/g;
@ -138,3 +140,9 @@ export function utf8Encode(str: string): string {
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 {convertValueToOutputAst} from '../output/value_util';
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,
flags: NodeFlags,
depsExpr: o.Expression,
@ -36,16 +37,17 @@ export function providerDef(providerAst: ProviderAst): {
}
});
const {providerExpr, flags: providerFlags, depsExpr} = providerAst.multiProvider ?
multiProviderDef(flags, providerAst.providers) :
singleProviderDef(flags, providerAst.providerType, providerAst.providers[0]);
multiProviderDef(ctx, flags, providerAst.providers) :
singleProviderDef(ctx, flags, providerAst.providerType, providerAst.providers[0]);
return {
providerExpr,
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} {
const allDepDefs: o.Expression[] = [];
const allParams: o.FnParam[] = [];
@ -53,15 +55,15 @@ function multiProviderDef(flags: NodeFlags, providers: CompileProviderMetadata[]
let expr: o.Expression;
if (provider.useClass) {
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) {
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) {
const depExprs = convertDeps(providerIndex, [{token: provider.useExisting}]);
expr = depExprs[0];
} else {
expr = convertValueToOutputAst(provider.useValue);
expr = convertValueToOutputAst(ctx, provider.useValue);
}
return expr;
});
@ -77,28 +79,29 @@ function multiProviderDef(flags: NodeFlags, providers: CompileProviderMetadata[]
return deps.map((dep, depIndex) => {
const paramName = `p${providerIndex}_${depIndex}`;
allParams.push(new o.FnParam(paramName, o.DYNAMIC_TYPE));
allDepDefs.push(depDef(dep));
allDepDefs.push(depDef(ctx, dep));
return o.variable(paramName);
});
}
}
function singleProviderDef(
flags: NodeFlags, providerType: ProviderAstType, providerMeta: CompileProviderMetadata):
ctx: OutputContext, flags: NodeFlags, providerType: ProviderAstType,
providerMeta: CompileProviderMetadata):
{providerExpr: o.Expression, flags: NodeFlags, depsExpr: o.Expression} {
let providerExpr: o.Expression;
let deps: CompileDiDependencyMetadata[];
if (providerType === ProviderAstType.Directive || providerType === ProviderAstType.Component) {
providerExpr = o.importExpr(providerMeta.useClass !);
providerExpr = ctx.importExpr(providerMeta.useClass !.reference);
flags |= NodeFlags.TypeDirective;
deps = providerMeta.deps || providerMeta.useClass !.diDeps;
} else {
if (providerMeta.useClass) {
providerExpr = o.importExpr(providerMeta.useClass);
providerExpr = ctx.importExpr(providerMeta.useClass.reference);
flags |= NodeFlags.TypeClassProvider;
deps = providerMeta.deps || providerMeta.useClass.diDeps;
} else if (providerMeta.useFactory) {
providerExpr = o.importExpr(providerMeta.useFactory);
providerExpr = ctx.importExpr(providerMeta.useFactory.reference);
flags |= NodeFlags.TypeFactoryProvider;
deps = providerMeta.deps || providerMeta.useFactory.diDeps;
} else if (providerMeta.useExisting) {
@ -106,23 +109,24 @@ function singleProviderDef(
flags |= NodeFlags.TypeUseExistingProvider;
deps = [{token: providerMeta.useExisting}];
} else {
providerExpr = convertValueToOutputAst(providerMeta.useValue);
providerExpr = convertValueToOutputAst(ctx, providerMeta.useValue);
flags |= NodeFlags.TypeValueProvider;
deps = [];
}
}
const depsExpr = o.literalArr(deps.map(dep => depDef(dep)));
const depsExpr = o.literalArr(deps.map(dep => depDef(ctx, dep)));
return {providerExpr, flags, depsExpr};
}
function tokenExpr(tokenMeta: CompileTokenMetadata): o.Expression {
return tokenMeta.identifier ? o.importExpr(tokenMeta.identifier) : o.literal(tokenMeta.value);
function tokenExpr(ctx: OutputContext, tokenMeta: CompileTokenMetadata): o.Expression {
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:
// - 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;
if (dep.isSkipSelf) {
flags |= DepFlags.SkipSelf;
@ -168,14 +172,14 @@ export function lifecycleHookToNodeFlag(lifecycleHook: LifecycleHooks): NodeFlag
}
export function componentFactoryResolverProviderDef(
flags: NodeFlags, entryComponents: CompileEntryComponentMetadata[]): {
ctx: OutputContext, flags: NodeFlags, entryComponents: CompileEntryComponentMetadata[]): {
providerExpr: o.Expression,
flags: NodeFlags,
depsExpr: o.Expression,
tokenExpr: o.Expression
} {
const entryComponentFactories = entryComponents.map(
(entryComponent) => o.importExpr({reference: entryComponent.componentFactory}));
const entryComponentFactories =
entryComponents.map((entryComponent) => ctx.importExpr(entryComponent.componentFactory));
const token = createIdentifierToken(Identifiers.ComponentFactoryResolver);
const classMeta = {
diDeps: [
@ -187,10 +191,10 @@ export function componentFactoryResolverProviderDef(
reference: resolveIdentifier(Identifiers.CodegenComponentFactoryResolver)
};
const {providerExpr, flags: providerFlags, depsExpr} =
singleProviderDef(flags, ProviderAstType.PrivateService, {
singleProviderDef(ctx, flags, ProviderAstType.PrivateService, {
token,
multi: false,
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 {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 {OutputContext} from '../util';
import {componentFactoryResolverProviderDef, depDef, lifecycleHookToNodeFlag, providerDef} from './provider_compiler';
@ -29,9 +30,7 @@ const IMPLICIT_TEMPLATE_VAR = '\$implicit';
const NG_CONTAINER_TAG = 'ng-container';
export class ViewCompileResult {
constructor(
public statements: o.Statement[], public viewClassVar: string,
public rendererTypeVar: string) {}
constructor(public viewClassVar: string, public rendererTypeVar: string) {}
}
@CompilerInjectable()
@ -40,49 +39,47 @@ export class ViewCompiler {
private _genConfigNext: CompilerConfig, private _schemaRegistry: ElementSchemaRegistry) {}
compileComponent(
component: CompileDirectiveMetadata, template: TemplateAst[], styles: o.Expression,
usedPipes: CompilePipeSummary[]): ViewCompileResult {
outputCtx: OutputContext, component: CompileDirectiveMetadata, template: TemplateAst[],
styles: o.Expression, usedPipes: CompilePipeSummary[]): ViewCompileResult {
let embeddedViewCount = 0;
const staticQueryIds = findStaticQueryIds(template);
const statements: o.Statement[] = [];
let renderComponentVarName: string = undefined !;
if (!component.isHost) {
const template = component.template !;
const customRenderData: o.LiteralMapEntry[] = [];
if (template.animations && template.animations.length) {
customRenderData.push(
new o.LiteralMapEntry('animation', convertValueToOutputAst(template.animations), true));
customRenderData.push(new o.LiteralMapEntry(
'animation', convertValueToOutputAst(outputCtx, template.animations), true));
}
const renderComponentVar = o.variable(rendererTypeName(component.type.reference));
renderComponentVarName = renderComponentVar.name !;
statements.push(
outputCtx.statements.push(
renderComponentVar
.set(o.importExpr(createIdentifier(Identifiers.createRendererType2))
.callFn([new o.LiteralMapExpr([
new o.LiteralMapEntry('encapsulation', o.literal(template.encapsulation)),
new o.LiteralMapEntry('styles', styles),
new o.LiteralMapEntry('data', new o.LiteralMapExpr(customRenderData))
])]))
.set(o.importExpr(Identifiers.createRendererType2).callFn([new o.LiteralMapExpr([
new o.LiteralMapEntry('encapsulation', o.literal(template.encapsulation)),
new o.LiteralMapEntry('styles', styles),
new o.LiteralMapEntry('data', new o.LiteralMapExpr(customRenderData))
])]))
.toDeclStmt(
o.importType(createIdentifier(Identifiers.RendererType2)),
[o.StmtModifier.Final]));
o.importType(Identifiers.RendererType2),
[o.StmtModifier.Final, o.StmtModifier.Exported]));
}
const viewBuilderFactory = (parent: ViewBuilder | null): ViewBuilder => {
const embeddedViewIndex = embeddedViewCount++;
return new ViewBuilder(
parent, component, embeddedViewIndex, usedPipes, staticQueryIds, viewBuilderFactory);
outputCtx, parent, component, embeddedViewIndex, usedPipes, staticQueryIds,
viewBuilderFactory);
};
const visitor = viewBuilderFactory(null);
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[] = [];
constructor(
private parent: ViewBuilder|null, private component: CompileDirectiveMetadata,
private embeddedViewIndex: number, private usedPipes: CompilePipeSummary[],
private outputCtx: OutputContext, private parent: ViewBuilder|null,
private component: CompileDirectiveMetadata, private embeddedViewIndex: number,
private usedPipes: CompilePipeSummary[],
private staticQueryIds: Map<TemplateAst, StaticAndDynamicQueryIds>,
private viewBuilderFactory: ViewBuilderFactory) {
// 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
// to be able to introduce the new view compiler without too many errors.
this.compType =
this.embeddedViewIndex > 0 ? o.DYNAMIC_TYPE : o.importType(this.component.type) !;
this.compType = this.embeddedViewIndex > 0 ?
o.DYNAMIC_TYPE :
o.expressionType(outputCtx.importExpr(this.component.type.reference)) !;
}
get viewName(): string {
@ -156,7 +155,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({
sourceSpan: null,
nodeFlags: flags,
nodeDef: o.importExpr(createIdentifier(Identifiers.queryDef)).callFn([
nodeDef: o.importExpr(Identifiers.queryDef).callFn([
o.literal(flags), o.literal(queryId),
new o.LiteralMapExpr(
[new o.LiteralMapEntry(query.propertyName, o.literal(bindingType))])
@ -170,7 +169,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({
sourceSpan: null,
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)
])
}));
@ -193,13 +192,14 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
}
const viewFactory = new o.DeclareFunctionStmt(
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.literalArr(nodeDefExprs),
updateDirectivesFn,
updateRendererFn,
]))],
o.importType(createIdentifier(Identifiers.ViewDefinition)));
o.importType(Identifiers.ViewDefinition),
this.embeddedViewIndex === 0 ? [o.StmtModifier.Exported] : []);
targetStatements.push(viewFactory);
return targetStatements;
@ -229,7 +229,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({
sourceSpan: ast.sourceSpan,
nodeFlags: NodeFlags.TypeNgContent,
nodeDef: o.importExpr(createIdentifier(Identifiers.ngContentDef)).callFn([
nodeDef: o.importExpr(Identifiers.ngContentDef).callFn([
o.literal(ast.ngContentIndex), o.literal(ast.index)
])
}));
@ -240,7 +240,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({
sourceSpan: ast.sourceSpan,
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)])
])
}));
@ -262,7 +262,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes[nodeIndex] = () => ({
sourceSpan: ast.sourceSpan,
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)))
]),
updateRenderer: updateRendererExpressions
@ -289,7 +289,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes[nodeIndex] = () => ({
sourceSpan: ast.sourceSpan,
nodeFlags: NodeFlags.TypeElement | flags,
nodeDef: o.importExpr(createIdentifier(Identifiers.anchorDef)).callFn([
nodeDef: o.importExpr(Identifiers.anchorDef).callFn([
o.literal(flags),
queryMatchesExpr,
o.literal(ast.ngContentIndex),
@ -343,11 +343,11 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
const childCount = this.nodes.length - nodeIndex - 1;
const compAst = ast.directives.find(dirAst => dirAst.directive.isComponent);
let compRendererType = o.NULL_EXPR;
let compView = o.NULL_EXPR;
let compRendererType = o.NULL_EXPR as o.Expression;
let compView = o.NULL_EXPR as o.Expression;
if (compAst) {
compView = o.importExpr({reference: compAst.directive.componentViewType});
compRendererType = o.importExpr({reference: compAst.directive.rendererType});
compView = this.outputCtx.importExpr(compAst.directive.componentViewType);
compRendererType = this.outputCtx.importExpr(compAst.directive.rendererType);
}
// elementDef(
@ -361,7 +361,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes[nodeIndex] = () => ({
sourceSpan: ast.sourceSpan,
nodeFlags: NodeFlags.TypeElement | flags,
nodeDef: o.importExpr(createIdentifier(Identifiers.elementDef)).callFn([
nodeDef: o.importExpr(Identifiers.elementDef).callFn([
o.literal(flags),
queryMatchesExpr,
o.literal(ast.ngContentIndex),
@ -492,7 +492,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({
sourceSpan: dirAst.sourceSpan,
nodeFlags: flags,
nodeDef: o.importExpr(createIdentifier(Identifiers.queryDef)).callFn([
nodeDef: o.importExpr(Identifiers.queryDef).callFn([
o.literal(flags), o.literal(queryId),
new o.LiteralMapExpr(
[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([
VIEW_VAR, o.literal(nodeIndex)
]);
const dirContextExpr =
o.importExpr(Identifiers.nodeValue).callFn([VIEW_VAR, o.literal(nodeIndex)]);
const hostBindings = dirAst.hostProperties.map((inputAst) => ({
context: dirContextExpr,
dirAst,
@ -570,7 +569,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes[nodeIndex] = () => ({
sourceSpan: dirAst.sourceSpan,
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(childCount), providerExpr, depsExpr,
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);
if (componentDirMeta && componentDirMeta.directive.entryComponents.length) {
const {providerExpr, depsExpr, flags, tokenExpr} = componentFactoryResolverProviderDef(
NodeFlags.PrivateProvider, componentDirMeta.directive.entryComponents);
this.outputCtx, NodeFlags.PrivateProvider, componentDirMeta.directive.entryComponents);
this._addProviderNode({
providerExpr,
depsExpr,
@ -619,7 +618,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
() => ({
sourceSpan: data.sourceSpan,
nodeFlags: data.flags,
nodeDef: o.importExpr(createIdentifier(Identifiers.providerDef)).callFn([
nodeDef: o.importExpr(Identifiers.providerDef).callFn([
o.literal(data.flags),
data.queryMatchExprs.length ? o.literalArr(data.queryMatchExprs) : o.NULL_EXPR,
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)]));
}
});
const {providerExpr, depsExpr, flags: providerFlags, tokenExpr} = providerDef(providerAst);
const {providerExpr, depsExpr, flags: providerFlags, tokenExpr} =
providerDef(this.outputCtx, providerAst);
return {
flags: flags | providerFlags,
queryMatchExprs,
@ -665,9 +665,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
// check references
const refNodeIndex = currBuilder.refNodeIndices[name];
if (refNodeIndex != null) {
return o.importExpr(createIdentifier(Identifiers.nodeValue)).callFn([
currViewExpr, o.literal(refNodeIndex)
]);
return o.importExpr(Identifiers.nodeValue).callFn([currViewExpr, o.literal(refNodeIndex)]);
}
// check variables
@ -682,25 +680,23 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
createLiteralArrayConverter(sourceSpan: ParseSourceSpan, argCount: number): BuiltinConverter {
if (argCount === 0) {
const valueExpr = o.importExpr(createIdentifier(Identifiers.EMPTY_ARRAY));
const valueExpr = o.importExpr(Identifiers.EMPTY_ARRAY);
return () => valueExpr;
}
const nodeIndex = this.nodes.length;
// pureArrayDef(argCount: number): NodeDef;
this.nodes.push(
() => ({
sourceSpan,
nodeFlags: NodeFlags.TypePureArray,
nodeDef:
o.importExpr(createIdentifier(Identifiers.pureArrayDef)).callFn([o.literal(argCount)])
}));
this.nodes.push(() => ({
sourceSpan,
nodeFlags: NodeFlags.TypePureArray,
nodeDef: o.importExpr(Identifiers.pureArrayDef).callFn([o.literal(argCount)])
}));
return (args: o.Expression[]) => callCheckStmt(nodeIndex, args);
}
createLiteralMapConverter(sourceSpan: ParseSourceSpan, keys: string[]): BuiltinConverter {
if (keys.length === 0) {
const valueExpr = o.importExpr(createIdentifier(Identifiers.EMPTY_MAP));
const valueExpr = o.importExpr(Identifiers.EMPTY_MAP);
return () => valueExpr;
}
@ -709,8 +705,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({
sourceSpan,
nodeFlags: NodeFlags.TypePureObject,
nodeDef: o.importExpr(createIdentifier(Identifiers.pureObjectDef))
.callFn([o.literalArr(keys.map(key => o.literal(key)))])
nodeDef: o.importExpr(Identifiers.pureObjectDef).callFn([o.literalArr(
keys.map(key => o.literal(key)))])
}));
return (args: o.Expression[]) => callCheckStmt(nodeIndex, args);
@ -724,8 +720,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(() => ({
sourceSpan: expression.sourceSpan,
nodeFlags: NodeFlags.TypePurePipe,
nodeDef: o.importExpr(createIdentifier(Identifiers.purePipeDef))
.callFn([o.literal(argCount)])
nodeDef: o.importExpr(Identifiers.purePipeDef).callFn([o.literal(argCount)])
}));
// find underlying pipe in the component view
@ -737,18 +732,15 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
}
const pipeNodeIndex = compBuilder.purePipeNodeIndices[name];
const pipeValueExpr: o.Expression =
o.importExpr(createIdentifier(Identifiers.nodeValue)).callFn([
compViewExpr, o.literal(pipeNodeIndex)
]);
o.importExpr(Identifiers.nodeValue).callFn([compViewExpr, o.literal(pipeNodeIndex)]);
return (args: o.Expression[]) => callUnwrapValue(
expression.nodeIndex, expression.bindingIndex,
callCheckStmt(nodeIndex, [pipeValueExpr].concat(args)));
} else {
const nodeIndex = this._createPipe(expression.sourceSpan, pipe);
const nodeValueExpr = o.importExpr(createIdentifier(Identifiers.nodeValue)).callFn([
VIEW_VAR, o.literal(nodeIndex)
]);
const nodeValueExpr =
o.importExpr(Identifiers.nodeValue).callFn([VIEW_VAR, o.literal(nodeIndex)]);
return (args: o.Expression[]) => callUnwrapValue(
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(
// flags: NodeFlags, ctor: any, deps: ([DepFlags, any] | any)[]): NodeDef
this.nodes.push(() => ({
sourceSpan,
nodeFlags: NodeFlags.TypePipe,
nodeDef: o.importExpr(createIdentifier(Identifiers.pipeDef)).callFn([
o.literal(flags), o.importExpr(pipe.type), o.literalArr(depExprs)
])
}));
this.nodes.push(
() => ({
sourceSpan,
nodeFlags: NodeFlags.TypePipe,
nodeDef: o.importExpr(Identifiers.pipeDef).callFn([
o.literal(flags), this.outputCtx.importExpr(pipe.type.reference), o.literalArr(depExprs)
])
}));
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 {
return o.importExpr(createIdentifier(Identifiers.unwrapValue)).callFn([
return o.importExpr(Identifiers.unwrapValue).callFn([
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 {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 {MockStaticSymbolResolverHost, MockSummaryResolver} from './static_symbol_resolver_spec';
@ -32,7 +34,9 @@ export function main() {
const mockSummaryResolver = new MockSummaryResolver([]);
const symbolResolver = new StaticSymbolResolver(
new MockStaticSymbolResolverHost({}), symbolCache, mockSummaryResolver);
return serializeSummaries(mockSummaryResolver, symbolResolver, symbols, []).json;
return serializeSummaries(
createMockOutputContext(), mockSummaryResolver, symbolResolver, symbols, [])
.json;
}
it('should load serialized summary files', () => {
@ -108,4 +112,8 @@ export class MockAotSummaryResolverHost implements AotSummaryResolverHost {
isSourceFile(filePath: string) { return !filePath.endsWith('.d.ts'); }
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 {MockStaticSymbolResolverHost} from './static_symbol_resolver_spec';
import {MockAotSummaryResolverHost} from './summary_resolver_spec';
import {MockAotSummaryResolverHost, createMockOutputContext} from './summary_resolver_spec';
export function main() {
@ -43,7 +43,7 @@ export function main() {
it('should serialize various data correctly', () => {
init();
const serializedData = serializeSummaries(
summaryResolver, symbolResolver,
createMockOutputContext(), summaryResolver, symbolResolver,
[
{
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',
() => {
init();
const externalSerialized = serializeSummaries(summaryResolver, symbolResolver, [], [
{
summary: {
summaryKind: CompileSummaryKind.Pipe,
type: {
reference: symbolCache.get('/tmp/external.ts', 'SomeExternalPipe'),
}
} as any,
metadata: null as any
},
{
summary: {
summaryKind: CompileSummaryKind.Directive,
type: {
reference: symbolCache.get('/tmp/external.ts', 'SomeExternalDir'),
const externalSerialized =
serializeSummaries(createMockOutputContext(), summaryResolver, symbolResolver, [], [
{
summary: {
summaryKind: CompileSummaryKind.Pipe,
type: {
reference: symbolCache.get('/tmp/external.ts', 'SomeExternalPipe'),
}
} as any,
metadata: null as any
},
providers: [],
viewProviders: [],
} as any,
metadata: null as any
}
]);
{
summary: {
summaryKind: CompileSummaryKind.Directive,
type: {
reference: symbolCache.get('/tmp/external.ts', 'SomeExternalDir'),
},
providers: [],
viewProviders: [],
} as any,
metadata: null as any
}
]);
init({
'/tmp/external.ngsummary.json': externalSerialized.json,
});
const serialized = serializeSummaries(
summaryResolver, symbolResolver, [], [{
createMockOutputContext(), summaryResolver, symbolResolver, [], [{
summary: <any>{
summaryKind: CompileSummaryKind.NgModule,
type: {reference: symbolCache.get('/tmp/some_module.ts', 'SomeModule')},
@ -162,7 +163,7 @@ export function main() {
() => {
init();
const externalSerialized = serializeSummaries(
summaryResolver, symbolResolver,
createMockOutputContext(), summaryResolver, symbolResolver,
[
{
symbol: symbolCache.get('/tmp/external.ts', 'PROVIDERS'),
@ -194,7 +195,7 @@ export function main() {
{__symbolic: 'module', version: 3, metadata: {'external': 'b'}}
});
const serialized = serializeSummaries(
summaryResolver, symbolResolver, [{
createMockOutputContext(), summaryResolver, symbolResolver, [{
symbol: symbolCache.get('/tmp/test.ts', 'main'),
metadata: {
local: symbolCache.get('/tmp/local.ts', 'local'),
@ -229,7 +230,7 @@ export function main() {
it('should create "importAs" names for non source symbols', () => {
init();
const serialized = serializeSummaries(
summaryResolver, symbolResolver, [{
createMockOutputContext(), summaryResolver, symbolResolver, [{
symbol: symbolCache.get('/tmp/test.ts', 'main'),
metadata: [
symbolCache.get('/tmp/external.d.ts', 'lib'),

View File

@ -18,7 +18,7 @@ export function main() {
const fileB = new ParseSourceFile('b0b1b2b3b4b5b6b7b8b9', 'b.js');
let ctx: EmitterVisitorContext;
beforeEach(() => { ctx = EmitterVisitorContext.createRoot([]); });
beforeEach(() => { ctx = EmitterVisitorContext.createRoot(); });
it('should add source files to the source map', () => {
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 {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter';
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 {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 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() {
describe('JavaScriptEmitter', () => {
let importResolver: ImportResolver;
let emitter: JavaScriptEmitter;
let someVar: o.ReadVarExpr;
beforeEach(() => {
importResolver = new SimpleJsImportGenerator();
emitter = new JavaScriptEmitter(importResolver);
});
beforeEach(() => { emitter = new JavaScriptEmitter(); });
function emitSourceMap(
stmt: o.Statement | o.Statement[], exportedVars: string[] | null = null,
preamble?: string): SourceMap {
function emitSourceMap(stmt: o.Statement | o.Statement[], preamble?: string): SourceMap {
const stmts = Array.isArray(stmt) ? stmt : [stmt];
const source = emitter.emitStatements(
someSourceFilePath, someGenFilePath, stmts, exportedVars || [], preamble);
const source = emitter.emitStatements(someSourceFilePath, someGenFilePath, stmts, preamble);
return extractSourceMap(source) !;
}
@ -54,7 +38,7 @@ export function main() {
const endLocation = new ParseLocation(source, 7, 0, 6);
const sourceSpan = new ParseSourceSpan(startLocation, endLocation);
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.sourcesContent).toEqual([' ', ';;;var']);

View File

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

View File

@ -9,7 +9,6 @@
import {ParseLocation, ParseSourceFile} from '@angular/compiler';
import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
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 {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter';
import {ParseSourceSpan} from '@angular/compiler/src/parse_util';
@ -19,36 +18,23 @@ import {extractSourceMap, originalPositionFor} from './source_map_util';
const someGenFilePath = 'somePackage/someGenFile';
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() {
// Not supported features of our OutputAst in TS:
// - real `const` like in Dart
// - final fields
describe('TypeScriptEmitter', () => {
let importResolver: ImportResolver;
let emitter: TypeScriptEmitter;
let someVar: o.ReadVarExpr;
beforeEach(() => {
importResolver = new SimpleJsImportGenerator();
emitter = new TypeScriptEmitter(importResolver);
emitter = new TypeScriptEmitter();
someVar = o.variable('someVar');
});
function emitSourceMap(
stmt: o.Statement | o.Statement[], exportedVars: string[] | null = null,
preamble?: string): SourceMap {
function emitSourceMap(stmt: o.Statement | o.Statement[], preamble?: string): SourceMap {
const stmts = Array.isArray(stmt) ? stmt : [stmt];
const source = emitter.emitStatements(
someSourceFilePath, someGenFilePath, stmts, exportedVars || [], preamble);
const source = emitter.emitStatements(someSourceFilePath, someGenFilePath, stmts, preamble);
return extractSourceMap(source) !;
}
@ -59,7 +45,7 @@ export function main() {
const endLocation = new ParseLocation(source, 7, 0, 6);
const sourceSpan = new ParseSourceSpan(startLocation, endLocation);
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.sourcesContent).toEqual([' ', ';;;var']);

View File

@ -7,9 +7,7 @@
*/
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 {ImportResolver} from '@angular/compiler/src/output/path_util';
import {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter';
import {stripSourceMapAndNewLine} from './abstract_emitter_spec';
@ -18,21 +16,9 @@ const someGenFilePath = 'somePackage/someGenFile';
const someSourceFilePath = 'somePackage/someSourceFile';
const anotherModuleUrl = 'somePackage/someOtherPath';
const sameModuleIdentifier: CompileIdentifierMetadata = {
reference: new StaticSymbol(someGenFilePath, 'someLocalId', [])
};
const sameModuleIdentifier = new o.ExternalReference(null, 'someLocalId', null);
const externalModuleIdentifier: CompileIdentifierMetadata = {
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; }
}
const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'someExternalId', null);
export function main() {
// Not supported features of our OutputAst in TS:
@ -40,22 +26,17 @@ export function main() {
// - final fields
describe('TypeScriptEmitter', () => {
let importResolver: ImportResolver;
let emitter: TypeScriptEmitter;
let someVar: o.ReadVarExpr;
beforeEach(() => {
importResolver = new SimpleJsImportGenerator();
emitter = new TypeScriptEmitter(importResolver);
emitter = new TypeScriptEmitter();
someVar = o.variable('someVar', null, null);
});
function emitStmt(
stmt: o.Statement | o.Statement[], exportedVars: string[] | null = null,
preamble?: string): string {
function emitStmt(stmt: o.Statement | o.Statement[], preamble?: string): string {
const stmts = Array.isArray(stmt) ? stmt : [stmt];
const source = emitter.emitStatements(
someSourceFilePath, someGenFilePath, stmts, exportedVars || [], preamble);
const source = emitter.emitStatements(someSourceFilePath, someGenFilePath, stmts, preamble);
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(null, [o.StmtModifier.Final])))
.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;`);
expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt(o.INT_TYPE)))
.toEqual(`var someVar:number = 1;`);
@ -74,8 +55,9 @@ export function main() {
describe('declare variables with ExternExpressions as values', () => {
it('should create no reexport if the identifier is in the same module', () => {
// identifier is in the same module -> no reexport
expect(emitStmt(someVar.set(o.importExpr(sameModuleIdentifier)).toDeclStmt(), ['someVar']))
.toEqual('export var someVar:any = someLocalId;');
expect(emitStmt(someVar.set(o.importExpr(sameModuleIdentifier)).toDeclStmt(null, [
o.StmtModifier.Exported
]))).toEqual('export var someVar:any = someLocalId;');
});
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', () => {
expect(emitStmt(
someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(o.DYNAMIC_TYPE),
['someVar']))
expect(emitStmt(someVar.set(o.importExpr(externalModuleIdentifier))
.toDeclStmt(o.DYNAMIC_TYPE, [o.StmtModifier.Exported])))
.toEqual([
`import * as i0 from 'somePackage/someOtherPath';`,
`export var someVar:any = i0.someExternalId;`
].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', () => {
expect(
emitStmt(someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(), ['someVar']))
expect(emitStmt(someVar.set(o.importExpr(externalModuleIdentifier))
.toDeclStmt(null, [o.StmtModifier.Exported])))
.toEqual([
`export {someExternalId as someVar} from 'somePackage/someOtherPath';`, ``
].join('\n'));
@ -117,30 +85,19 @@ export function main() {
it('should create multiple reexports from the same file', () => {
const someVar2 = o.variable('someVar2');
const externalModuleIdentifier2: CompileIdentifierMetadata = {
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId2', [])
};
expect(emitStmt(
[
someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(),
someVar2.set(o.importExpr(externalModuleIdentifier2)).toDeclStmt()
],
['someVar', 'someVar2']))
const externalModuleIdentifier2 =
new o.ExternalReference(anotherModuleUrl, 'someExternalId2', null);
expect(emitStmt([
someVar.set(o.importExpr(externalModuleIdentifier))
.toDeclStmt(null, [o.StmtModifier.Exported]),
someVar2.set(o.importExpr(externalModuleIdentifier2))
.toDeclStmt(null, [o.StmtModifier.Exported])
]))
.toEqual([
`export {someExternalId as someVar,someExternalId2 as someVar2} from 'somePackage/someOtherPath';`,
``
].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', () => {
@ -230,14 +187,6 @@ export function main() {
].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', () => {
const lhs = o.variable('lhs');
const rhs = o.variable('rhs');
@ -277,9 +226,8 @@ export function main() {
it('should support function statements', () => {
expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [
]))).toEqual(['function someFn():void {', '}'].join('\n'));
expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], []), ['someFn'])).toEqual([
'export function someFn():void {', '}'
].join('\n'));
expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [], null, [o.StmtModifier.Exported])))
.toEqual(['export function someFn():void {', '}'].join('\n'));
expect(emitStmt(new o.DeclareFunctionStmt(
'someFn', [], [new o.ReturnStatement(o.literal(1))], o.INT_TYPE)))
.toEqual(['function someFn():number {', ' return 1;', '}'].join('\n'));
@ -324,8 +272,9 @@ export function main() {
it('should support declaring classes', () => {
expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [
]))).toEqual(['class SomeClass {', '}'].join('\n'));
expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, []), ['SomeClass']))
.toEqual(['export class SomeClass {', '}'].join('\n'));
expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [], [
o.StmtModifier.Exported
]))).toEqual(['export class SomeClass {', '}'].join('\n'));
expect(emitStmt(new o.ClassStmt('SomeClass', o.variable('SomeSuperClass'), [], [], null !, [
]))).toEqual(['class SomeClass extends SomeSuperClass {', '}'].join('\n'));
});
@ -439,16 +388,6 @@ export function main() {
].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', () => {
expect(
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', () => {
expect(emitStmt(o.variable('a').toStmt(), [], '/* SomePreamble */')).toBe([
expect(emitStmt(o.variable('a').toStmt(), '/* SomePreamble */')).toBe([
'/* SomePreamble */', 'a;'
].join('\n'));
});