goog.provide("promesa.impl.promise"); goog.provide("promesa.impl.promise.PromiseImpl"); goog.provide("promesa.impl.promise.CancellationError"); goog.scope(function() { function isCancellationError(v) { return v instanceof CancellationError; } function fmtValue(o) { if (isThenable(o)) { return ``; } else if (o instanceof Error) { return ``; } else if (o === null || o === undefined) { return `${o}`; } else if (typeof o === "function") { return ``; } else { return `${o.toString()}`; } } function isSome(o) { return o !== null && o !== undefined; } function isFunction(o) { return typeof o === "function"; } function isThenable(o) { if (goog.isObject(o)) { const thenFn = o.then; return isFunction(thenFn); } else { return false; } } function constantly(v) { return () => { return v; }; } function identity(v) { return v; } function isPromiseImpl(v) { return v instanceof PromiseImpl; } function completeDeferredFn(deferred) { return (value, cause) => { if (cause) { deferred.reject(cause); } else { deferred.resolve(value); } }; } function process(p) { if (p[STATE] === PENDING) { return; } nextTick(processNextTick, p); return p; } function processNextTick(p) { if (p[QUEUE].length === 0) { return; } const state = p[STATE]; const value = p[VALUE]; let task; let rvalue; let rcause; for (; p[QUEUE].length;) { task = p[QUEUE].shift(); try { if (state === RESOLVED) { rvalue = task.resolve(value); } else if (state === REJECTED) { rvalue = task.reject(value); } else { rcause = new TypeError("invalid state"); } } catch (e) { rcause = e; } resolveTask(task, rvalue, rcause); } } function resolveTask(task, value, cause) { if (task.complete === undefined) { return; } if (cause) { task.complete(null, cause); } else { if (task.type === RESOLVE_TYPE_MAP) { task.complete(value, null); } else if (task.type === RESOLVE_TYPE_FLATTEN) { if (isPromiseImpl(value)) { value.handle((v, c) => { resolveTask(task, v, c); }); } else if (isThenable(value)) { value.then(v => { resolveTask(task, v, null); }, c => { resolveTask(task, null, c); }); } else { task.complete(value, null); } } else if (task.type === RESOLVE_TYPE_BIND) { if (isPromiseImpl(value)) { value.handle((v, c) => { task.complete(v, c); }); } else if (isThenable(value)) { value.then(v => { task.complete(v, null); }, c => { task.complete(null, c); }); } else { task.complete(null, new TypeError("expected thenable")); } } else { task.complete(null, new TypeError("internal: invalid resolve type")); } } } function transition(p, state, value) { if (p[STATE] === state || p[STATE] !== PENDING) { return; } p[STATE] = state; p[VALUE] = value; return processNextTick(p); } const self = promesa.impl.promise; const root = goog.global; const PENDING = Symbol("state/pending"); const RESOLVED = Symbol("state/resolved"); const REJECTED = Symbol("state/rejected"); const QUEUE = Symbol("queue"); const STATE = Symbol("state"); const VALUE = Symbol("value"); const RESOLVE_TYPE_FLATTEN = Symbol("resolve-type/flatten"); const RESOLVE_TYPE_BIND = Symbol("resolve-type/bind"); const RESOLVE_TYPE_MAP = Symbol("resolve-type/map"); const defaultResolveMapHandler = v => { return v; }; const defaultResolveBindHandler = v => { return self.resolved(v); }; const defaultRejectHandler = c => { throw c; }; class CancellationError extends Error { } class PromiseImpl { constructor(val) { this[QUEUE] = []; this[STATE] = PENDING; this[VALUE] = undefined; if (val !== undefined) { transition(this, RESOLVED, val); } } get state() { return this[STATE]; } get value() { return this[VALUE]; } then(resolve, reject) { const deferred = new PromiseImpl(); this[QUEUE].push({type:RESOLVE_TYPE_FLATTEN, resolve:resolve ?? defaultResolveMapHandler, reject:reject ?? defaultRejectHandler, complete:completeDeferredFn(deferred)}); process(this); return deferred; } catch(reject) { return this.then(null, reject); } finally(f) { this[QUEUE].push({type:RESOLVE_TYPE_FLATTEN, resolve:value => { return f(); }, reject:cause => { return f(); }, complete:(value, cause) => { return null; }}); return this; } fmap(resolve, reject) { const deferred = new PromiseImpl(); this[QUEUE].push({type:RESOLVE_TYPE_MAP, resolve:resolve ?? defaultResolveMapHandler, reject:reject ?? defaultRejectHandler, complete:completeDeferredFn(deferred)}); process(this); return deferred; } fbind(resolve, reject) { const deferred = new PromiseImpl(); this[QUEUE].push({type:RESOLVE_TYPE_BIND, resolve:resolve ?? defaultResolveBindHandler, reject:reject ?? defaultRejectHandler, complete:completeDeferredFn(deferred)}); process(this); return deferred; } handle(fn, resolveType) { resolveType = resolveType ?? RESOLVE_TYPE_MAP; this[QUEUE].push({type:resolveType, resolve:defaultResolveMapHandler, reject:defaultRejectHandler, complete:fn}); process(this); } resolve(value) { if (this[STATE] === PENDING) { transition(this, RESOLVED, value); } return null; } reject(cause) { if (this[STATE] === PENDING) { transition(this, REJECTED, cause); } return null; } isPending() { const state = this[STATE]; return state === PENDING; } isResolved() { const state = this[STATE]; return state === RESOLVED; } isRejected() { const state = this[STATE]; return state === REJECTED; } isCancelled() { const state = this[STATE]; const value = this[VALUE]; return state === REJECTED && isCancellationError(value); } cancel() { this.reject(new CancellationError("promise cancelled")); } } const nextTick = (() => { if (typeof root.Promise === "function") { const resolved = Promise.resolve(null); return function queueMicrotaskWithPromise(f, p) { resolved.then(() => { return f(p); }); }; } else if (typeof root.setImmediate === "function") { return root.setImmediate; } else if (typeof root.setTimeout === "function") { return (f, p) => { return root.setTimeout(f, 0, p); }; } else { return (f, p) => { return f.call(this, p); }; } })(); self.PromiseImpl = PromiseImpl; self.CancellationError = CancellationError; self.isCancellationError = isCancellationError; self.deferred = () => { return new PromiseImpl(); }; const NULL_PROMISE = new PromiseImpl(null); self.resolved = function resolved(value) { if (value === null) { return NULL_PROMISE; } else { const p = new PromiseImpl(); p[STATE] = RESOLVED; p[VALUE] = value; return p; } }; self.rejected = function rejected(reason) { const p = new PromiseImpl(); p[STATE] = REJECTED; p[VALUE] = reason; return p; }; self.all = function all(promises) { return promises.reduce((acc, p) => { return acc.then(results => { return self.coerce(p).fmap(v => { results.push(v); return results; }); }); }, self.resolved([])); }; self.coerce = function coerce(promise) { if (promise instanceof PromiseImpl) { return promise; } else if (isThenable(promise)) { const deferred = self.deferred(); promise.then(v => { deferred.resolve(v); }, c => { deferred.reject(c); }); return deferred; } else if (promise instanceof Error) { return self.rejected(promise); } else { return self.resolved(promise); } }; self.race = function race(promises) { const deferred = self.deferred(); promises.forEach(p => { self.coerce(p).handle((v, c) => { if (c) { deferred.reject(c); } else { deferred.resolve(v); } }); }); return deferred; }; self.nextTick = nextTick; self.PENDING = PENDING; self.RESOLVED = RESOLVED; self.REJECTED = REJECTED; }); //# sourceMappingURL=promesa.impl.promise.js.map