* Get a cached value by key. On first call for a key, computes and caches it. * Subsequent calls return the cached value until a watched file changes, * which marks the entry dirty. The next get() re-computes from disk. * * Race condition handling: dirty is cleared BEFORE the async compu
(key: string, compute: () => Promise<T>)
| 461 | * get() will re-read again rather than serving a stale value. |
| 462 | */ |
| 463 | async get<T>(key: string, compute: () => Promise<T>): Promise<T> { |
| 464 | await this.ensureStarted() |
| 465 | const existing = this.cache.get(key) |
| 466 | if (existing && !existing.dirty) { |
| 467 | return existing.value as T |
| 468 | } |
| 469 | // Clear dirty before compute — if the file changes again during the |
| 470 | // async read, invalidate() will re-set dirty and we'll re-read on |
| 471 | // the next get() call. |
| 472 | if (existing) { |
| 473 | existing.dirty = false |
| 474 | } |
| 475 | const value = await compute() |
| 476 | // Only update the cached value if no new invalidation arrived during compute |
| 477 | const entry = this.cache.get(key) |
| 478 | if (entry && !entry.dirty) { |
| 479 | entry.value = value |
| 480 | } |
| 481 | if (!entry) { |
| 482 | this.cache.set(key, { value, dirty: false, compute }) |
| 483 | } |
| 484 | return value |
| 485 | } |
| 486 | |
| 487 | /** Reset all state. Stops file watchers. For testing only. */ |
| 488 | reset(): void { |
nothing calls this directly
no test coverage detected