UNPKG

go-go-try

Version:

Tries to execute a sync/async function, returns a result tuple

281 lines (269 loc) 8.14 kB
function isSuccess(result) { return result[0] === void 0; } function isFailure(result) { return result[0] !== void 0; } function success(value) { return [void 0, value]; } function failure(error) { return [error, void 0]; } function assertNever(value) { throw new Error(`Unhandled case: ${String(value)}`); } function getErrorMessage(error) { if (error === void 0) return "undefined"; if (typeof error === "string") return error; if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") { return error.message; } try { return JSON.stringify(error); } catch { return String(error); } } function isPromise$1(value) { return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function"; } function isError(value) { return value instanceof Error; } function resolveDefault(defaultValue) { return typeof defaultValue === "function" ? defaultValue() : defaultValue; } function goTry(value) { try { const result = typeof value === "function" ? value() : value; if (isPromise$1(result)) { return result.then((resolvedValue) => success(resolvedValue)).catch((err) => failure(getErrorMessage(err))); } return success(result); } catch (err) { return failure(getErrorMessage(err)); } } function taggedError(tag) { return class TaggedErrorClass extends Error { constructor(message, options) { super(message); this._tag = tag; this.name = tag; this.cause = options?.cause; } }; } const UnknownError = taggedError("UnknownError"); function isTaggedError$1(err) { return isError(err) && "_tag" in err && typeof err._tag === "string"; } function goTryRaw(value, options) { const { errorClass, systemErrorClass } = options || {}; const actualSystemErrorClass = systemErrorClass ?? UnknownError; const wrapError = (err) => { if (errorClass) { if (err === void 0) { return new errorClass("undefined"); } if (isError(err)) { return new errorClass(err.message, { cause: err }); } return new errorClass(String(err)); } if (actualSystemErrorClass) { if (isTaggedError$1(err)) { return err; } if (err === void 0) { return new actualSystemErrorClass("undefined"); } if (isError(err)) { return new actualSystemErrorClass(err.message, { cause: err }); } return new actualSystemErrorClass(String(err)); } if (err === void 0) { return new Error("undefined"); } return isError(err) ? err : new Error(String(err)); }; try { const result = typeof value === "function" ? value() : value; if (isPromise$1(result)) { return result.then((resolvedValue) => success(resolvedValue)).catch((err) => failure(wrapError(err))); } return success(result); } catch (err) { return failure(wrapError(err)); } } function goTryOr(value, defaultValue) { try { const result = typeof value === "function" ? value() : value; if (isPromise$1(result)) { return result.then((resolvedValue) => success(resolvedValue)).catch((err) => [getErrorMessage(err), resolveDefault(defaultValue)]); } return success(result); } catch (err) { return [getErrorMessage(err), resolveDefault(defaultValue)]; } } function isTaggedError(err) { return isError(err) && "_tag" in err && typeof err._tag === "string"; } function wrapError(err, errorClass, systemErrorClass) { if (errorClass) { if (err === void 0) { return new errorClass("undefined"); } if (isError(err)) { return new errorClass(err.message, { cause: err }); } return new errorClass(String(err)); } const actualSystemErrorClass = systemErrorClass ?? UnknownError; if (isTaggedError(err)) { return err; } if (err === void 0) { return new actualSystemErrorClass("undefined"); } if (isError(err)) { return new actualSystemErrorClass(err.message, { cause: err }); } return new actualSystemErrorClass(String(err)); } async function runWithConcurrency(items, concurrency) { if (items.length === 0) { return []; } const isFactoryMode = typeof items[0] === "function"; if (!isFactoryMode && concurrency <= 0) { return Promise.allSettled(items); } const results = new Array(items.length); let index = 0; async function worker() { while (index < items.length) { const currentIndex = index++; try { const item = items[currentIndex]; const value = isFactoryMode ? await item() : await item; results[currentIndex] = { status: "fulfilled", value }; } catch (reason) { results[currentIndex] = { status: "rejected", reason }; } } } const workerCount = concurrency <= 0 ? items.length : Math.min(concurrency, items.length); const workers = []; for (let i = 0; i < workerCount; i++) { workers.push(worker()); } await Promise.all(workers); return results; } async function goTryAll(items, options) { const settled = await runWithConcurrency(items, options?.concurrency ?? 0); const errors = []; const results = []; for (let i = 0; i < settled.length; i++) { const item = settled[i]; if (item.status === "fulfilled") { errors[i] = void 0; results[i] = item.value; } else { errors[i] = getErrorMessage(item.reason); results[i] = void 0; } } return [errors, results]; } async function goTryAllRaw(items, options) { const { errorClass, systemErrorClass } = options || {}; const settled = await runWithConcurrency(items, options?.concurrency ?? 0); const errors = []; const results = []; for (let i = 0; i < settled.length; i++) { const item = settled[i]; if (item.status === "fulfilled") { errors[i] = void 0; results[i] = item.value; } else { const reason = item.reason; errors[i] = wrapError(reason, errorClass, systemErrorClass); results[i] = void 0; } } return [errors, results]; } function assert(condition, errorOrClass, message) { if (!condition) { if (typeof errorOrClass === "string") { throw new Error(errorOrClass); } if (typeof errorOrClass === "function" && message !== void 0) { throw new errorOrClass(message); } throw errorOrClass; } } function isPromise(value) { return value instanceof Promise; } function isErrorConstructor(error) { return typeof error === "function" && error.prototype !== void 0 && error.prototype instanceof Error; } function throwError(value, error) { if (isErrorConstructor(error)) { throw new error(String(value), { cause: value }); } throw error(value); } function ensure(value, predicate, error = UnknownError) { if (typeof value === "function") { const result = value(); if (isPromise(result)) { return result.then((resolved) => { if (!predicate(resolved)) { throwError(resolved, error); } return resolved; }); } if (!predicate(result)) { throwError(result, error); } return result; } if (isPromise(value)) { return value.then((resolved) => { if (!predicate(resolved)) { throwError(resolved, error); } return resolved; }); } if (!predicate(value)) { throwError(value, error); } return value; } function goElse(value, defaultValue) { try { const result = typeof value === "function" ? value() : value; if (isPromise$1(result)) { return result.then((resolvedValue) => [void 0, resolvedValue]).catch((err) => { const error = err instanceof Error ? err : new Error(String(err)); return [error, resolveDefault(defaultValue)]; }); } return [void 0, result]; } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); return [error, resolveDefault(defaultValue)]; } } export { UnknownError, assert, assertNever, ensure, failure, goTryRaw as go, goTryAllRaw as goAll, goElse, goTry, goTryAll, goTryAllRaw, goTryOr, goTryRaw, isFailure, isSuccess, success, taggedError };