evnty
Version:
Async-first, reactive event handling library for complex event flows in browser and Node.js
115 lines (113 loc) • 3.43 kB
JavaScript
import { isThenable, noop } from "./utils.js";
const ERR_BRAND = Symbol.for('evnty.ResultError');
function ResultError(error) {
this.error = error;
}
ResultError.prototype[ERR_BRAND] = true;
export function err(error) {
return new ResultError(error);
}
export function isErr(result) {
return typeof result === 'object' && result !== null && result[ERR_BRAND] === true;
}
export function isOk(result) {
return typeof result !== 'object' || result === null || !result[ERR_BRAND];
}
export function unwrap(results) {
const len = results.length;
const unwrapped = new Array(len);
for(let i = 0; i < len; i++){
const r = results[i];
unwrapped[i] = isErr(r) ? Promise.reject(r.error) : r;
}
return unwrapped;
}
async function resolveMaybePromises(items, asyncIndices) {
const pending = new Array(asyncIndices.length);
for(let j = 0; j < asyncIndices.length; j++){
pending[j] = items[asyncIndices[j]];
}
const resolved = await Promise.all(pending);
for(let j = 0; j < asyncIndices.length; j++){
items[asyncIndices[j]] = resolved[j];
}
return items;
}
function resolveAll(results) {
const len = results.length;
if (len === 0) return results;
let firstError;
let hasError = false;
let asyncIndices = null;
for(let i = 0; i < len; i++){
const r = results[i];
if (isErr(r)) {
if (!hasError) {
hasError = true;
firstError = r.error;
}
} else if (isThenable(r)) {
(asyncIndices ??= []).push(i);
}
}
if (hasError) {
if (asyncIndices !== null) {
for(let j = 0; j < asyncIndices.length; j++){
results[asyncIndices[j]].then(noop, noop);
}
}
return Promise.reject(firstError);
}
if (asyncIndices === null) return results;
return resolveMaybePromises(results, asyncIndices);
}
function settleAll(results) {
const len = results.length;
if (len === 0) return [];
let asyncIndices = null;
const settled = new Array(len);
for(let i = 0; i < len; i++){
const r = results[i];
if (isErr(r)) {
settled[i] = {
status: 'rejected',
reason: r.error
};
} else if (isThenable(r)) {
(asyncIndices ??= []).push(i);
settled[i] = r.then((value)=>({
status: 'fulfilled',
value
}), (reason)=>({
status: 'rejected',
reason
}));
} else {
settled[i] = {
status: 'fulfilled',
value: r
};
}
}
if (asyncIndices === null) return settled;
return resolveMaybePromises(settled, asyncIndices);
}
export class DispatchResult {
#results;
[Symbol.toStringTag] = 'DispatchResult';
constructor(results){
this.#results = results;
}
then(onfulfilled, onrejected) {
const resolved = this.all();
if (resolved instanceof Promise) return resolved.then(onfulfilled, onrejected);
return Promise.resolve(resolved).then(onfulfilled, onrejected);
}
all() {
return resolveAll(this.#results);
}
settled() {
return settleAll(this.#results);
}
}
//# sourceMappingURL=dispatch-result.js.map