From 352c582f9834ca35da5ff04a97804b3ac2bc1ce0 Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Wed, 5 Dec 2018 15:46:21 -0800 Subject: [PATCH] refactor(ivy): allow for shim generators not based on existing files (#27497) Previously the ngtsc ShimGenerator interface expected that all shims would be generated using the contents of existing ts.SourceFiles. This assumption was true for ngfactory and ngsummary files, but breaks down for flat module index files, which are standalone. This commit prepares for flat module index generation by enabling shim generators which don't require an existing file. PR Close #27497 --- .../src/ngtsc/shims/src/factory_generator.ts | 11 ++++-- .../compiler-cli/src/ngtsc/shims/src/host.ts | 36 +++++++++---------- .../src/ngtsc/shims/src/summary_generator.ts | 11 ++++-- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts b/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts index 552f4cdcea..90829bbaac 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts @@ -26,9 +26,16 @@ export class FactoryGenerator implements ShimGenerator { get factoryFileMap(): Map { return this.map; } - getOriginalSourceOfShim(fileName: string): string|null { return this.map.get(fileName) || null; } + recognize(fileName: string): boolean { return this.map.has(fileName); } + + generate(genFilePath: string, readFile: (fileName: string) => ts.SourceFile | null): ts.SourceFile + |null { + const originalPath = this.map.get(genFilePath) !; + const original = readFile(originalPath); + if (original === null) { + return null; + } - generate(original: ts.SourceFile, genFilePath: string): ts.SourceFile { const relativePathToSource = './' + path.posix.basename(original.fileName).replace(TS_DTS_SUFFIX, ''); // Collect a list of classes that need to have factory types emitted for them. This list is diff --git a/packages/compiler-cli/src/ngtsc/shims/src/host.ts b/packages/compiler-cli/src/ngtsc/shims/src/host.ts index 1c83b09939..4bcf98e2f8 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/host.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/host.ts @@ -11,17 +11,20 @@ import * as ts from 'typescript'; export interface ShimGenerator { /** - * Get the original source file for the given shim path, the contents of which determine the - * contents of the shim file. - * - * If this returns `null` then the given file was not a shim file handled by this generator. + * Returns `true` if this generator is intended to handle the given file. */ - getOriginalSourceOfShim(fileName: string): string|null; + recognize(fileName: string): boolean; /** * Generate a shim's `ts.SourceFile` for the given original file. + * + * `readFile` is a function which allows the generator to look up the contents of existing source + * files. It returns null if the requested file doesn't exist. + * + * If `generate` returns null, then the shim generator declines to generate the file after all. */ - generate(original: ts.SourceFile, genFileName: string): ts.SourceFile; + generate(genFileName: string, readFile: (fileName: string) => ts.SourceFile | null): ts.SourceFile + |null; } /** @@ -55,17 +58,14 @@ export class GeneratedShimsHostWrapper implements ts.CompilerHost { shouldCreateNewSourceFile?: boolean|undefined): ts.SourceFile|undefined { for (let i = 0; i < this.shimGenerators.length; i++) { const generator = this.shimGenerators[i]; - const originalFile = generator.getOriginalSourceOfShim(fileName); - if (originalFile !== null) { - // This shim generator has recognized the filename being requested, and is now responsible - // for generating its contents, based on the contents of the original file it has requested. - const originalSource = this.delegate.getSourceFile( - originalFile, languageVersion, onError, shouldCreateNewSourceFile); - if (originalSource === undefined) { - // The original requested file doesn't exist, so the shim cannot exist either. - return undefined; - } - return generator.generate(originalSource, fileName); + if (generator.recognize(fileName)) { + const readFile = (originalFile: string) => { + return this.delegate.getSourceFile( + originalFile, languageVersion, onError, shouldCreateNewSourceFile) || + null; + }; + + return generator.generate(fileName, readFile) || undefined; } } return this.delegate.getSourceFile( @@ -100,7 +100,7 @@ export class GeneratedShimsHostWrapper implements ts.CompilerHost { // Consider the file as existing whenever 1) it really does exist in the delegate host, or // 2) at least one of the shim generators recognizes it. return this.delegate.fileExists(fileName) || - this.shimGenerators.some(gen => gen.getOriginalSourceOfShim(canonical) !== null); + this.shimGenerators.some(gen => gen.recognize(canonical)); } readFile(fileName: string): string|undefined { return this.delegate.readFile(fileName); } diff --git a/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts b/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts index bbb8e35266..158f0fdba6 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts @@ -16,9 +16,16 @@ export class SummaryGenerator implements ShimGenerator { getSummaryFileNames(): string[] { return Array.from(this.map.keys()); } - getOriginalSourceOfShim(fileName: string): string|null { return this.map.get(fileName) || null; } + recognize(fileName: string): boolean { return this.map.has(fileName); } + + generate(genFilePath: string, readFile: (fileName: string) => ts.SourceFile | null): ts.SourceFile + |null { + const originalPath = this.map.get(genFilePath) !; + const original = readFile(originalPath); + if (original === null) { + return null; + } - generate(original: ts.SourceFile, genFilePath: string): ts.SourceFile { // Collect a list of classes that need to have factory types emitted for them. This list is // overly broad as at this point the ts.TypeChecker has not been created and so it can't be used // to semantically understand which decorators are Angular decorators. It's okay to output an