|
1 | 1 | import ts from "typescript";
|
| 2 | +import { LRUCache } from "lru-cache"; |
2 | 3 | import type { ModuleKind } from "../types.js";
|
3 | 4 | import type { Package } from "../createPackage.js";
|
4 | 5 |
|
@@ -37,6 +38,7 @@ const getCanonicalFileName = ts.createGetCanonicalFileName(false);
|
37 | 38 | const toPath = (fileName: string) => ts.toPath(fileName, "/", getCanonicalFileName);
|
38 | 39 |
|
39 | 40 | export class CompilerHostWrapper {
|
| 41 | + private programCache = new LRUCache<string, ts.Program>({ max: 2 }); |
40 | 42 | private compilerHost: ts.CompilerHost;
|
41 | 43 | private compilerOptions: ts.CompilerOptions;
|
42 | 44 | private normalModuleResolutionCache: ts.ModuleResolutionCache;
|
@@ -162,12 +164,17 @@ export class CompilerHostWrapper {
|
162 | 164 | return `${resolutionMode ?? 1}:${+!!noDtsResolution}:${+!!allowJs}:${moduleSpecifier}`;
|
163 | 165 | }
|
164 | 166 |
|
| 167 | + private getProgram(rootNames: readonly string[], options: ts.CompilerOptions) { |
| 168 | + const key = programKey(rootNames, options); |
| 169 | + let program = this.programCache.get(key); |
| 170 | + if (!program) { |
| 171 | + this.programCache.set(key, (program = ts.createProgram({ rootNames, options, host: this.compilerHost }))); |
| 172 | + } |
| 173 | + return program; |
| 174 | + } |
| 175 | + |
165 | 176 | createPrimaryProgram(rootName: string) {
|
166 |
| - const program = ts.createProgram({ |
167 |
| - rootNames: [rootName], |
168 |
| - options: this.compilerOptions, |
169 |
| - host: this.compilerHost, |
170 |
| - }); |
| 177 | + const program = this.getProgram([rootName], this.compilerOptions); |
171 | 178 |
|
172 | 179 | program.resolvedModules?.forEach((cache, path) => {
|
173 | 180 | let ownCache = this.resolvedModules.get(path);
|
@@ -199,11 +206,8 @@ export class CompilerHostWrapper {
|
199 | 206 | ) {
|
200 | 207 | throw new Error("Cannot override resolution-affecting options for host due to potential cache polution");
|
201 | 208 | }
|
202 |
| - return ts.createProgram({ |
203 |
| - rootNames, |
204 |
| - options: extraOptions ? { ...this.compilerOptions, ...extraOptions } : this.compilerOptions, |
205 |
| - host: this.compilerHost, |
206 |
| - }); |
| 209 | + const options = extraOptions ? { ...this.compilerOptions, ...extraOptions } : this.compilerOptions; |
| 210 | + return this.getProgram(rootNames, options); |
207 | 211 | }
|
208 | 212 |
|
209 | 213 | getResolvedModule(sourceFile: ts.SourceFile, moduleName: string, resolutionMode: ts.ResolutionMode) {
|
@@ -304,3 +308,7 @@ class TraceCollector {
|
304 | 308 | this.traces.length = 0;
|
305 | 309 | }
|
306 | 310 | }
|
| 311 | + |
| 312 | +function programKey(rootNames: readonly string[], options: ts.CompilerOptions) { |
| 313 | + return JSON.stringify([rootNames, Object.entries(options).sort(([k1], [k2]) => k1.localeCompare(k2))]); |
| 314 | +} |
0 commit comments