import "../_dnt.polyfills.js"; import * as dntShim from "../_dnt.shims.js"; import { getOrInit } from "./state.js" export class AsyncMemo { running = new Map>() run(key: K, run: () => Promise) { return getOrInit(this.running, key, () => run().finally(() => this.running.delete(key))) } } export class TimedMemo extends AsyncMemo { done = new Map() timers = new Set() constructor(readonly ttl: number, readonly signal: AbortSignal) { super() this.signal.addEventListener("abort", () => { for (const timer of this.timers) { clearTimeout(timer) } }) } override run(key: K, run: () => Promise, ttl = this.ttl) { const existing = this.done.get(key) if (existing) return Promise.resolve(existing) return super.run(key, () => run().then((value) => { this.done.set(key, value) const timer = setTimeout(() => { this.done.delete(key) this.timers.delete(timer) }, ttl) this.timers.add(timer) if (dntShim.Deno.unrefTimer) { dntShim.Deno.unrefTimer(timer) } return value })) } } export class PermanentMemo extends AsyncMemo { done = new Map() override run(key: K, run: () => Promise) { const existing = this.done.get(key) if (existing) return Promise.resolve(existing) return super.run(key, () => run().then((value) => { this.done.set(key, value) return value })) } } export class WeakMemo extends AsyncMemo { done = new Map>() finReg = new FinalizationRegistry((key) => this.done.delete(key)) override run(key: K, run: () => Promise) { const existing = this.done.get(key)?.deref() if (existing) return Promise.resolve(existing) return super.run(key, () => run().then((value) => { this.done.set(key, new WeakRef(value)) return value })) } }