// @denoify-line-ignore import { Polyfill as Set } from "minimal-polyfills/Set"; // @denoify-line-ignore import { Polyfill as WeakMap } from "minimal-polyfills/WeakMap"; import { assert, is } from "tsafe/assert"; import { LazyEvt } from "./LazyEvt"; import { importProxy } from "./importProxy"; import { overwriteReadonlyProp } from "tsafe/lab/overwriteReadonlyProp"; import type { Handler, NonPostableEvtLike, Evt, CtxLike, DoneOrAborted } from "./types"; export type Ctx = import("./types/interfaces").Ctx; class CtxImpl implements Ctx{ get evtDoneOrAborted(): Evt> { return this.lazyEvtDoneOrAborted.evt; } get evtAttach(): Evt> { return this.lazyEvtAttach.evt; } get evtDetach(): Evt> { return this.lazyEvtDetach.evt; } private __completionStatus: DoneOrAborted | undefined; get completionStatus(): DoneOrAborted | undefined { return this.__completionStatus; } private lazyEvtAttach = new LazyEvt>(); private lazyEvtDetach = new LazyEvt>(); private lazyEvtDoneOrAborted = new LazyEvt>(); private onDoneOrAborted(doneOrAborted: DoneOrAborted): void { this.__completionStatus = doneOrAborted; this.lazyEvtDoneOrAborted.post(doneOrAborted); } waitFor(timeout?: number): Promise { return this.evtDoneOrAborted .waitFor(timeout) .then( data => { if (data.type === "ABORTED") { throw data.error; } return data.result; }, timeoutError => { this.abort(timeoutError); throw timeoutError; } ) ; } abort(error: Error) { return this.__done(error); } done(result: Result) { return this.__done(undefined, result); } /** Detach all handler bound to this context from theirs respective Evt and post getEvtDone() */ private __done(error: Error | undefined, result?: Result): Handler.WithEvt[] { const handlers: Handler.WithEvt[] = []; for (const handler of this.handlers.values()) { const evt = this.evtByHandler.get(handler)!; const wasStillAttached = handler.detach(); //NOTE: It should not be possible if (!wasStillAttached) { continue; } handlers.push({ handler, evt }); } this.onDoneOrAborted({ ...(!!error ? { type: "ABORTED", error } : { type: "DONE", "result": result as NonNullable } ), handlers }); return handlers; } private handlers = new Set< Handler> >(); private evtByHandler = new WeakMap< Handler>, NonPostableEvtLike >(); getHandlers(): Handler.WithEvt[] { return Array.from(this.handlers.values()) .map(handler => ({ handler, "evt": this.evtByHandler.get(handler)! })) ; } zz__addHandler( handler: Handler>, evt: NonPostableEvtLike ) { assert(handler.ctx === this); assert(is>>(handler)); if( this.completionStatus !== undefined ){ handler.detach(); return; } this.handlers.add(handler); this.evtByHandler.set(handler, evt); this.lazyEvtAttach.post({ handler, evt }); } zz__removeHandler( handler: Handler>, ) { assert(handler.ctx === this); assert(is>>(handler)); this.lazyEvtDetach.post({ handler, "evt": this.evtByHandler.get(handler)! }); this.handlers.delete(handler); } } export const Ctx: { new (): Ctx; readonly prototype: Ctx; } = CtxImpl; try{ overwriteReadonlyProp(Ctx as any, "name", "Ctx"); }catch{} importProxy.Ctx = Ctx;