From 307d3ca09b6a2d1bae2754b9aaf1be98e77d016f Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Fri, 12 Nov 2021 19:48:17 +0100 Subject: [PATCH] fix(rosetta): cache source file parses (#3163) Store parsed source files in a cache, so that we can avoid re-parsing the same TypeScript library files every time we compile a sample in a batch. Reduces compilation time by ~4x on my machine. --- By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license]. [Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0 --- .../lib/typescript/ts-compiler.ts | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/jsii-rosetta/lib/typescript/ts-compiler.ts b/packages/jsii-rosetta/lib/typescript/ts-compiler.ts index 0ad5b91637..134c5adf3a 100644 --- a/packages/jsii-rosetta/lib/typescript/ts-compiler.ts +++ b/packages/jsii-rosetta/lib/typescript/ts-compiler.ts @@ -3,6 +3,11 @@ import * as ts from 'typescript'; export class TypeScriptCompiler { private readonly realHost = ts.createCompilerHost(STANDARD_COMPILER_OPTIONS, true); + /** + * A compiler-scoped cache to avoid having to re-parse the same library files for every compilation + */ + private readonly fileCache = new Map(); + public createInMemoryCompilerHost( sourcePath: string, sourceContents: string, @@ -13,12 +18,23 @@ export class TypeScriptCompiler { return { ...realHost, - fileExists: (filePath) => filePath === sourcePath || realHost.fileExists(filePath), + fileExists: (filePath) => + filePath === sourcePath || this.fileCache.has(filePath) || realHost.fileExists(filePath), getCurrentDirectory: currentDirectory != null ? () => currentDirectory : realHost.getCurrentDirectory, - getSourceFile: (fileName, languageVersion, onError, shouldCreateNewSourceFile) => - fileName === sourcePath - ? sourceFile - : realHost.getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile), + getSourceFile: (fileName, languageVersion, onError, shouldCreateNewSourceFile) => { + if (fileName === sourcePath) { + return sourceFile; + } + + const existing = this.fileCache.get(fileName); + if (existing) { + return existing; + } + + const parsed = realHost.getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile); + this.fileCache.set(fileName, parsed); + return parsed; + }, readFile: (filePath) => (filePath === sourcePath ? sourceContents : realHost.readFile(filePath)), writeFile: () => void undefined, };