UNPKG

@effectful/cc

Version:

Multi-prompt delimited continuations runtime

124 lines (123 loc) 4.51 kB
"use strict"; exports.__esModule = true; exports.CancellationCallbacksSymbol = void 0; exports.addOnCancel = addOnCancel; exports.cancel = cancel; exports.currentCancellationCallbacks = currentCancellationCallbacks; exports.getCancellationCallbacks = getCancellationCallbacks; exports.installCancelablePromise = installCancelablePromise; exports.removeOnCancel = removeOnCancel; exports.setCancellationCallbacks = setCancellationCallbacks; exports.withCancellationCallbacks = withCancellationCallbacks; const CancellationCallbacksSymbol = exports.CancellationCallbacksSymbol = Symbol.for("@effectful/cancelable/cancellationCallbacks"); const kInstalled = Symbol.for("@effectful/cancelable/installed"); let activeCancellationCallbacks; function currentCancellationCallbacks() { return activeCancellationCallbacks; } function addOnCancel(callback) { const callbacks = activeCancellationCallbacks; if (!callbacks) { throw new Error("No active cancellation context"); } callbacks.add(callback); } function removeOnCancel(callback) { const callbacks = activeCancellationCallbacks; if (!callbacks) { throw new Error("No active cancellation context"); } callbacks.delete(callback); } function withCancellationCallbacks(callbacks, body) { const prev = activeCancellationCallbacks; activeCancellationCallbacks = callbacks; try { return body(); } finally { activeCancellationCallbacks = prev; } } function getCancellationCallbacks(target) { if (!target || typeof target !== "object" && typeof target !== "function") { return undefined; } return target[CancellationCallbacksSymbol]; } function setCancellationCallbacks(target, callbacks) { if (!target || typeof target !== "object" && typeof target !== "function") { return; } const obj = target; if (obj[CancellationCallbacksSymbol] === callbacks) return; Object.defineProperty(obj, CancellationCallbacksSymbol, { value: callbacks, configurable: true }); } function cancel(target) { if (target instanceof Set) { drain(target); return; } const callbacks = getCancellationCallbacks(target); if (callbacks) drain(callbacks); } function drain(callbacks) { for (const cb of Array.from(callbacks)) { callbacks.delete(cb); try { cb(); } catch (_e) { // ignore cancellation errors } } } function wrapCombinator(PromiseImpl, name) { const original = PromiseImpl[name]; if (typeof original !== "function") return; PromiseImpl[name] = function patchedCombinator() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } const parentCallbacks = activeCancellationCallbacks; const callCallbacks = new Set(); let parentDrain; if (parentCallbacks) { parentDrain = () => drain(callCallbacks); parentCallbacks.add(parentDrain); } const base = withCancellationCallbacks(callCallbacks, () => original.apply(this, args)); setCancellationCallbacks(base, callCallbacks); return base.then(value => { if (parentCallbacks && parentDrain) parentCallbacks.delete(parentDrain); drain(callCallbacks); return value; }, error => { if (parentCallbacks && parentDrain) parentCallbacks.delete(parentDrain); drain(callCallbacks); throw error; }); }; } function installCancelablePromise(PromiseImpl) { const BasePromise = PromiseImpl != null ? PromiseImpl : require("promise"); if (BasePromise[kInstalled]) return BasePromise; Object.defineProperty(BasePromise, kInstalled, { value: true }); const originalThen = BasePromise.prototype.then; BasePromise.prototype.then = function patchedThen(onFulfilled, onRejected) { const callbacks = getCancellationCallbacks(this) || activeCancellationCallbacks; const wrappedOnFulfilled = typeof onFulfilled === "function" && callbacks ? value => withCancellationCallbacks(callbacks, () => onFulfilled(value)) : onFulfilled; const wrappedOnRejected = typeof onRejected === "function" && callbacks ? reason => withCancellationCallbacks(callbacks, () => onRejected(reason)) : onRejected; const next = originalThen.call(this, wrappedOnFulfilled, wrappedOnRejected); if (callbacks) setCancellationCallbacks(next, callbacks); return next; }; wrapCombinator(BasePromise, "all"); wrapCombinator(BasePromise, "race"); wrapCombinator(BasePromise, "any"); wrapCombinator(BasePromise, "allSettled"); return BasePromise; }