|
1 | 1 | import type { ErrorLevel, NodeError, NodeWithoutPosition, Position, Range } from 'twoslash-protocol' |
2 | | -import type { CompilerOptions, CompletionEntry, CompletionTriggerKind, DiagnosticCategory, JsxEmit } from 'typescript' |
| 2 | +import type { CompilerOptions, CompletionEntry, CompletionTriggerKind, DiagnosticCategory, JsxEmit, System } from 'typescript' |
3 | 3 |
|
4 | 4 | import type { CompilerOptionDeclaration, CreateTwoslashOptions, TwoslashExecuteOptions, TwoslashInstance, TwoslashOptions, TwoslashReturn, TwoslashReturnMeta, VirtualFile } from './types' |
5 | 5 | import { createFSBackedSystem, createSystem, createVirtualTypeScriptEnvironment } from '@typescript/vfs' |
@@ -28,15 +28,7 @@ export function createTwoslasher(createOptions: CreateTwoslashOptions = {}): Two |
28 | 28 | const vfs = createOptions.fsMap || new Map<string, string>() |
29 | 29 | const system = useFS |
30 | 30 | ? createSystem(vfs) |
31 | | - : { |
32 | | - ...createFSBackedSystem(vfs, _root, ts, createOptions.tsLibDirectory), |
33 | | - // To work with non-hoisted packages structure |
34 | | - realpath(path: string) { |
35 | | - if (vfs.has(path)) |
36 | | - return path |
37 | | - return ts.sys.realpath?.(path) || path |
38 | | - }, |
39 | | - } |
| 31 | + : createCacheableFSBackedSystem(vfs, _root, ts, createOptions.tsLibDirectory, createOptions.fsCache) |
40 | 32 | const fsRoot = useFS ? '/' : `${_root}/` |
41 | 33 |
|
42 | 34 | const cache = createOptions.cache === false |
@@ -508,6 +500,55 @@ export function createTwoslasher(createOptions: CreateTwoslashOptions = {}): Two |
508 | 500 | return twoslasher |
509 | 501 | } |
510 | 502 |
|
| 503 | +function createCacheableFSBackedSystem( |
| 504 | + vfs: Map<string, string>, |
| 505 | + root: string, |
| 506 | + ts: TS, |
| 507 | + tsLibDirectory?: string, |
| 508 | + enableFsCache = true, |
| 509 | +): System { |
| 510 | + function withCache<T>(fn: (key: string) => T) { |
| 511 | + const cache = new Map<string, T>() |
| 512 | + return (key: string) => { |
| 513 | + const cached = cache.get(key) |
| 514 | + if (cached !== undefined) |
| 515 | + return cached |
| 516 | + |
| 517 | + const result = fn(key) |
| 518 | + cache.set(key, result) |
| 519 | + return result |
| 520 | + } |
| 521 | + } |
| 522 | + const cachedReadFile = withCache(ts.sys.readFile) |
| 523 | + |
| 524 | + const cachedTs = enableFsCache |
| 525 | + ? { |
| 526 | + ...ts, |
| 527 | + sys: { |
| 528 | + ...ts.sys, |
| 529 | + directoryExists: withCache(ts.sys.directoryExists), |
| 530 | + fileExists: withCache(ts.sys.fileExists), |
| 531 | + ...(ts.sys.realpath ? { realpath: withCache(ts.sys.realpath) } : {}), |
| 532 | + readFile(path, encoding) { |
| 533 | + if (encoding === undefined) |
| 534 | + return cachedReadFile(path) |
| 535 | + return ts.sys.readFile(path, encoding) |
| 536 | + }, |
| 537 | + } satisfies System, |
| 538 | + } |
| 539 | + : ts |
| 540 | + |
| 541 | + return { |
| 542 | + ...createFSBackedSystem(vfs, root, cachedTs, tsLibDirectory), |
| 543 | + // To work with non-hoisted packages structure |
| 544 | + realpath(path: string) { |
| 545 | + if (vfs.has(path)) |
| 546 | + return path |
| 547 | + return cachedTs.sys.realpath?.(path) || path |
| 548 | + }, |
| 549 | + } |
| 550 | +} |
| 551 | + |
511 | 552 | /** |
512 | 553 | * Run Twoslash on a string of code |
513 | 554 | * |
|
0 commit comments