From 6123b9c0c6ad2ee6969af935cd9f5d70ff00fee0 Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Tue, 16 May 2017 16:30:37 -0700 Subject: [PATCH] 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. --- packages/compiler/src/aot/compiler.ts | 164 ++++++++++-------- packages/compiler/src/aot/compiler_factory.ts | 5 +- .../compiler/src/aot/summary_serializer.ts | 45 ++--- packages/compiler/src/compiler.ts | 1 - .../src/compiler_util/expression_converter.ts | 6 +- packages/compiler/src/identifiers.ts | 154 ++++++++-------- packages/compiler/src/jit/compiler.ts | 56 +++--- packages/compiler/src/ng_module_compiler.ts | 39 +++-- .../compiler/src/output/abstract_emitter.ts | 12 +- packages/compiler/src/output/class_builder.ts | 65 ------- packages/compiler/src/output/js_emitter.ts | 39 ++--- packages/compiler/src/output/output_ast.ts | 15 +- .../compiler/src/output/output_interpreter.ts | 25 ++- packages/compiler/src/output/output_jit.ts | 42 ++++- packages/compiler/src/output/path_util.ts | 31 ---- packages/compiler/src/output/ts_emitter.ts | 98 ++++------- packages/compiler/src/output/value_util.ts | 10 +- packages/compiler/src/style_compiler.ts | 61 +++---- packages/compiler/src/util.ts | 8 + .../src/view_compiler/provider_compiler.ts | 52 +++--- .../src/view_compiler/view_compiler.ts | 147 ++++++++-------- .../test/aot/summary_resolver_spec.ts | 10 +- .../test/aot/summary_serializer_spec.ts | 55 +++--- .../output/abstract_emitter_node_only_spec.ts | 2 +- .../test/output/js_emitter_node_only_spec.ts | 24 +-- .../compiler/test/output/js_emitter_spec.ts | 60 ++----- .../test/output/ts_emitter_node_only_spec.ts | 22 +-- .../compiler/test/output/ts_emitter_spec.ts | 115 +++--------- 28 files changed, 589 insertions(+), 774 deletions(-) delete mode 100644 packages/compiler/src/output/class_builder.ts delete mode 100644 packages/compiler/src/output/path_util.ts diff --git a/packages/compiler/src/aot/compiler.ts b/packages/compiler/src/aot/compiler.ts index aaccce05af..988a6f7870 100644 --- a/packages/compiler/src/aot/compiler.ts +++ b/packages/compiler/src/aot/compiler.ts @@ -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.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 { diff --git a/packages/compiler/src/aot/compiler_factory.ts b/packages/compiler/src/aot/compiler_factory.ts index 3a8b6ad7f2..0ed14b0443 100644 --- a/packages/compiler/src/aot/compiler_factory.ts +++ b/packages/compiler/src/aot/compiler_factory.ts @@ -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}; } diff --git a/packages/compiler/src/aot/summary_serializer.ts b/packages/compiler/src/aot/summary_serializer.ts index 8257894469..d6c64e6ba1 100644 --- a/packages/compiler/src/aot/summary_serializer.ts +++ b/packages/compiler/src/aot/summary_serializer.ts @@ -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, symbolResolver: StaticSymbolResolver, - symbols: ResolvedStaticSymbol[], types: { + forJitCtx: OutputContext, summaryResolver: SummaryResolver, + 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(); 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}`); } diff --git a/packages/compiler/src/compiler.ts b/packages/compiler/src/compiler.ts index 8799eebe4d..9f0b536da6 100644 --- a/packages/compiler/src/compiler.ts +++ b/packages/compiler/src/compiler.ts @@ -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'; diff --git a/packages/compiler/src/compiler_util/expression_converter.ts b/packages/compiler/src/compiler_util/expression_converter.ts index 2924cd10a4..4439433684 100644 --- a/packages/compiler/src/compiler_util/expression_converter.ts +++ b/packages/compiler/src/compiler_util/expression_converter.ts @@ -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 { diff --git a/packages/compiler/src/identifiers.ts b/packages/compiler/src/identifiers.ts index 383dae80fd..cf7069b650 100644 --- a/packages/compiler/src/identifiers.ts +++ b/packages/compiler/src/identifiers.ts @@ -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}; } diff --git a/packages/compiler/src/jit/compiler.ts b/packages/compiler/src/jit/compiler.ts index 094a5a39f6..504a78530a 100644 --- a/packages/compiler/src/jit/compiler.ts +++ b/packages/compiler/src/jit/compiler.ts @@ -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(); - 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[] { 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}; +} diff --git a/packages/compiler/src/ng_module_compiler.ts b/packages/compiler/src/ng_module_compiler.ts index bf34ddd7c3..ad787efb1c 100644 --- a/packages/compiler/src/ng_module_compiler.ts +++ b/packages/compiler/src/ng_module_compiler.ts @@ -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); } } diff --git a/packages/compiler/src/output/abstract_emitter.ts b/packages/compiler/src/output/abstract_emitter.ts index 88843bd576..9ec0019dd8 100644 --- a/packages/compiler/src/output/abstract_emitter.ts +++ b/packages/compiler/src/output/abstract_emitter.ts @@ -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); } diff --git a/packages/compiler/src/output/class_builder.ts b/packages/compiler/src/output/class_builder.ts deleted file mode 100644 index 372be1fa71..0000000000 --- a/packages/compiler/src/output/class_builder.ts +++ /dev/null @@ -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[]; -} diff --git a/packages/compiler/src/output/js_emitter.ts b/packages/compiler/src/output/js_emitter.ts index 9f8b7635f1..5a022b74ae 100644 --- a/packages/compiler/src/output/js_emitter.ts +++ b/packages/compiler/src/output/js_emitter.ts @@ -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(); - 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; diff --git a/packages/compiler/src/output/output_ast.ts b/packages/compiler/src/output/output_ast.ts index 286a1931d9..05a375889d 100644 --- a/packages/compiler/src/output/output_ast.ts +++ b/packages/compiler/src/output/output_ast.ts @@ -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; } diff --git a/packages/compiler/src/output/output_interpreter.ts b/packages/compiler/src/output/output_interpreter.ts index 2a58d9b5a8..a87661f462 100644 --- a/packages/compiler/src/output/output_interpreter.ts +++ b/packages/compiler/src/output/output_interpreter.ts @@ -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()); 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) {} @@ -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 { diff --git a/packages/compiler/src/output/output_jit.ts b/packages/compiler/src/output/output_jit.ts index 660c5ffc7f..b42b81c119 100644 --- a/packages/compiler/src/output/output_jit.ts +++ b/packages/compiler/src/output/output_jit.ts @@ -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); + } } diff --git a/packages/compiler/src/output/path_util.ts b/packages/compiler/src/output/path_util.ts deleted file mode 100644 index 2c626b6e52..0000000000 --- a/packages/compiler/src/output/path_util.ts +++ /dev/null @@ -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; -} diff --git a/packages/compiler/src/output/ts_emitter.ts b/packages/compiler/src/output/ts_emitter.ts index 0f7d91d17b..9a7d74ff75 100644 --- a/packages/compiler/src/output/ts_emitter.ts +++ b/packages/compiler/src/output/ts_emitter.ts @@ -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(); reexports = new Map(); @@ -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, `>`); } } diff --git a/packages/compiler/src/output/value_util.ts b/packages/compiler/src/output/value_util.ts index 58e44bf38e..c043800a6f 100644 --- a/packages/compiler/src/output/value_util.ts +++ b/packages/compiler/src/output/value_util.ts @@ -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); } } } diff --git a/packages/compiler/src/style_compiler.ts b/packages/compiler/src/style_compiler.ts index 7004eec06f..71c84d25dc 100644 --- a/packages/compiler/src/style_compiler.ts +++ b/packages/compiler/src/style_compiler.ts @@ -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 { diff --git a/packages/compiler/src/util.ts b/packages/compiler/src/util.ts index 34a5c35c40..a076a605da 100644 --- a/packages/compiler/src/util.ts +++ b/packages/compiler/src/util.ts @@ -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; +} diff --git a/packages/compiler/src/view_compiler/provider_compiler.ts b/packages/compiler/src/view_compiler/provider_compiler.ts index 4a3c32d547..cc821ec742 100644 --- a/packages/compiler/src/view_compiler/provider_compiler.ts +++ b/packages/compiler/src/view_compiler/provider_compiler.ts @@ -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)}; } diff --git a/packages/compiler/src/view_compiler/view_compiler.ts b/packages/compiler/src/view_compiler/view_compiler.ts index 87b79a0093..5701204806 100644 --- a/packages/compiler/src/view_compiler/view_compiler.ts +++ b/packages/compiler/src/view_compiler/view_compiler.ts @@ -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, 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 ]); } diff --git a/packages/compiler/test/aot/summary_resolver_spec.ts b/packages/compiler/test/aot/summary_resolver_spec.ts index c85b4b8129..60681bb609 100644 --- a/packages/compiler/test/aot/summary_resolver_spec.ts +++ b/packages/compiler/test/aot/summary_resolver_spec.ts @@ -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}; } \ No newline at end of file diff --git a/packages/compiler/test/aot/summary_serializer_spec.ts b/packages/compiler/test/aot/summary_serializer_spec.ts index 377c74fdd6..6a177df793 100644 --- a/packages/compiler/test/aot/summary_serializer_spec.ts +++ b/packages/compiler/test/aot/summary_serializer_spec.ts @@ -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: { 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'), diff --git a/packages/compiler/test/output/abstract_emitter_node_only_spec.ts b/packages/compiler/test/output/abstract_emitter_node_only_spec.ts index 93958da70e..d4685d8920 100644 --- a/packages/compiler/test/output/abstract_emitter_node_only_spec.ts +++ b/packages/compiler/test/output/abstract_emitter_node_only_spec.ts @@ -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'); diff --git a/packages/compiler/test/output/js_emitter_node_only_spec.ts b/packages/compiler/test/output/js_emitter_node_only_spec.ts index bdaf5010c4..3d9cc0084d 100644 --- a/packages/compiler/test/output/js_emitter_node_only_spec.ts +++ b/packages/compiler/test/output/js_emitter_node_only_spec.ts @@ -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']); diff --git a/packages/compiler/test/output/js_emitter_spec.ts b/packages/compiler/test/output/js_emitter_spec.ts index 9b293f4830..ff6e803798 100644 --- a/packages/compiler/test/output/js_emitter_spec.ts +++ b/packages/compiler/test/output/js_emitter_spec.ts @@ -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')); }); diff --git a/packages/compiler/test/output/ts_emitter_node_only_spec.ts b/packages/compiler/test/output/ts_emitter_node_only_spec.ts index 6afd4fa517..00fb814cdc 100644 --- a/packages/compiler/test/output/ts_emitter_node_only_spec.ts +++ b/packages/compiler/test/output/ts_emitter_node_only_spec.ts @@ -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']); diff --git a/packages/compiler/test/output/ts_emitter_spec.ts b/packages/compiler/test/output/ts_emitter_spec.ts index 962ad0ff68..910654069a 100644 --- a/packages/compiler/test/output/ts_emitter_spec.ts +++ b/packages/compiler/test/output/ts_emitter_spec.ts @@ -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')); });