/** * @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 {PluginCompilerHost} from '@bazel/typescript/internal/tsc_wrapped/plugin_api'; import * as ts from 'typescript'; /** * Extension of the TypeScript compiler host that supports files added to the Program which * were never on disk. * * This is used for backwards-compatibility with the ViewEngine compiler, which used ngsummary * and ngfactory files as inputs to the program. We call these inputs "synthetic". * * They need to be program inputs because user code may import from these generated files. * * TODO(alxhub): remove this after all ng_module users have migrated to Ivy */ export class SyntheticFilesCompilerHost implements PluginCompilerHost { /** * SourceFiles which are added to the program but which never existed on disk. */ syntheticFiles = new Map(); constructor( private rootFiles: string[], private delegate: ts.CompilerHost, generatedFiles: (rootFiles: string[]) => { [fileName: string]: (host: ts.CompilerHost) => ts.SourceFile | undefined }) { // Allow ngtsc to contribute in-memory synthetic files, which will be loaded // as if they existed on disk as action inputs. const angularGeneratedFiles = generatedFiles !(rootFiles); for (const f of Object.keys(angularGeneratedFiles)) { const generator = angularGeneratedFiles[f]; const generated = generator(delegate); if (generated) { this.syntheticFiles.set(generated.fileName, generated); } } if (delegate.getDirectories !== undefined) { this.getDirectories = (path: string) => delegate.getDirectories !(path); } } fileExists(filePath: string): boolean { if (this.syntheticFiles.has(filePath)) { return true; } return this.delegate.fileExists(filePath); } /** Loads a source file from in-memory map, or delegates. */ getSourceFile( fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile|undefined { const syntheticFile = this.syntheticFiles.get(fileName); if (syntheticFile) { return syntheticFile !; } return this.delegate.getSourceFile(fileName, languageVersion, onError); } get inputFiles() { return [...this.rootFiles, ...Array.from(this.syntheticFiles.keys())]; } fileNameToModuleId(fileName: string) { return fileName; // TODO: Ivy logic. don't forget that the delegate has the google3 logic } // Delegate everything else to the original compiler host. getDefaultLibFileName(options: ts.CompilerOptions): string { return this.delegate.getDefaultLibFileName(options); } writeFile( fileName: string, content: string, writeByteOrderMark: boolean, onError: ((message: string) => void)|undefined, sourceFiles: ReadonlyArray|undefined): void { this.delegate.writeFile(fileName, content, writeByteOrderMark, onError, sourceFiles); } getCanonicalFileName(path: string) { return this.delegate.getCanonicalFileName(path); } getCurrentDirectory(): string { return this.delegate.getCurrentDirectory(); } useCaseSensitiveFileNames(): boolean { return this.delegate.useCaseSensitiveFileNames(); } getNewLine(): string { return this.delegate.getNewLine(); } getDirectories?: (path: string) => string[]; readFile(fileName: string): string|undefined { return this.delegate.readFile(fileName); } trace(s: string): void { console.error(s); } }