UNPKG

@zerothrow/core

Version:

Core ZeroThrow functionality - Rust-style Result<T,E> for TypeScript

309 lines (302 loc) 8.68 kB
var __defProp = Object.defineProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; // src/core-exports.ts var core_exports_exports = {}; __export(core_exports_exports, { ZeroError: () => ZeroError, attempt: () => attempt, collect: () => collect2, collectAsync: () => collectAsync2, enhance: () => enhance, err: () => err2, firstSuccess: () => firstSuccess2, fromAsync: () => fromAsync, isErr: () => isErr, isOk: () => isOk, isResult: () => isResult, ok: () => ok, pipe: () => pipe2, try: () => attempt, tryAsync: () => tryAsync, wrap: () => wrap }); // src/error.ts var ZeroError = class _ZeroError extends Error { code; context; constructor(code, message, opts = {}) { super(message, { cause: opts.cause }); this.code = code; this.context = opts.context; this.name = "ZeroError"; Object.setPrototypeOf(this, new.target.prototype); } /** * Override toString to include full error chain with context */ toString() { let result = `${this.name} [${String(this.code)}]: ${this.message}`; if (this.context && Object.keys(this.context).length > 0) { result += ` Context: ${JSON.stringify(this.context, null, 2).replace(/\n/g, "\n ")}`; } let currentCause = this.cause; let depth = 1; while (currentCause instanceof Error) { const indent = " ".repeat(depth); const causeName = currentCause.name || "Error"; result += ` ${indent}Caused by: ${causeName}: ${currentCause.message}`; if (currentCause instanceof _ZeroError && currentCause.context) { const contextStr = JSON.stringify( currentCause.context, null, 2 ).replace(/\n/g, ` ${indent} `); result += ` ${indent} Context: ${contextStr}`; } currentCause = currentCause.cause; depth++; } return result; } /** * Get the full stack trace including all causes */ getFullStack() { let fullStack = this.stack || ""; let currentCause = this.cause; while (currentCause instanceof Error) { fullStack += "\n\nCaused by:\n" + (currentCause.stack || currentCause.toString()); currentCause = currentCause.cause; } return fullStack; } }; // src/result.ts function createResult(base) { const result = base; result.andThen = function(fn) { if (!result.ok) return createResult({ ok: false, error: result.error }); return fn(result.value); }; result.mapErr = function(fn) { if (result.ok) return createResult({ ok: true, value: result.value }); return createResult({ ok: false, error: fn(result.error) }); }; result.map = function(fn) { if (!result.ok) return createResult({ ok: false, error: result.error }); return createResult({ ok: true, value: fn(result.value) }); }; result.orElse = function(fallback) { if (result.ok) return result; return fallback(); }; result.unwrapOr = function(fallback) { return result.ok ? result.value : fallback; }; result.unwrapOrThrow = function() { if (!result.ok) throw result.error; return result.value; }; result.tap = function(fn) { if (result.ok) fn(result.value); return result; }; result.tapErr = function(fn) { if (!result.ok) fn(result.error); return result; }; result.finally = function(fn) { if (result.ok) fn(result.value); else fn(); return result; }; result.void = function() { if (!result.ok) return createResult({ ok: false, error: result.error }); return createResult({ ok: true, value: void 0 }); }; return result; } var ok = (value) => createResult({ ok: true, value }); var err = (error) => createResult({ ok: false, error }); var normalise = (e) => { if (e instanceof ZeroError) return e; if (e instanceof Error) { if ("code" in e && typeof e.code === "string" && "context" in e) { return e; } return new ZeroError("UNKNOWN_ERR", e.message, { cause: e }); } return new ZeroError("UNKNOWN_ERR", String(e)); }; function wrap(cause, code, msg, ctx) { const errorCode = code ?? (cause instanceof ZeroError ? cause.code : "code" in cause && cause.code ? cause.code : "WRAPPED_ERROR"); const message = msg ?? cause.message; return new ZeroError(errorCode, message, { cause, ...ctx !== void 0 && { context: ctx } }); } // src/combinators.ts function pipe(...fns) { return (input) => fns.reduce((acc, fn) => fn(acc), input); } function collect(results) { const values = new Array(results.length); let index = 0; for (const result of results) { if (!result.ok) return result; values[index++] = result.value; } return ok(values); } async function collectAsync(promises) { const results = await Promise.all(promises); return collect(results); } function firstSuccess(attempts) { if (attempts.length === 0) { return err(new ZeroError("ALL_FAILED", "All alternatives failed")); } for (const attempt2 of attempts) { const result = attempt2(); if (result.ok) return result; } return err(new ZeroError("ALL_FAILED", "All alternatives failed")); } // src/core-exports.ts function err2(errorOrCode, message) { if (typeof errorOrCode === "string") { return err(new ZeroError(errorOrCode, message || errorOrCode)); } return err(errorOrCode); } function attempt(fnOrOps, mapError) { if (Array.isArray(fnOrOps)) { return attemptBatch(fnOrOps, mapError); } try { const result = fnOrOps(); if (result && typeof result === "object" && "then" in result) { return result.then( (value) => ok(value), (error) => { const base = normalise(error); return err(mapError ? mapError(base) : base); } ); } return ok(result); } catch (e) { const base = normalise(e); return err(mapError ? mapError(base) : base); } } async function attemptBatch(fns, map) { const results = []; for (const fn of fns) { const promisedResult = Promise.resolve().then(() => fn()).then( (value) => ok(value), (error) => { const base = normalise(error); return err(map ? map(base) : base); } ); const result = await promisedResult; if (!result.ok) { return result; } results.push(result.value); } return ok(results); } async function tryAsync(fn) { try { const value = await fn(); return ok(value); } catch (e) { const base = normalise(e); return err(base); } } function enhance(promise) { const enhanced = promise; enhanced.andThen = function(fn) { return enhance(this.then((result) => { if (!result.ok) return err(result.error); const fnResult = fn(result.value); if (fnResult && typeof fnResult === "object" && "then" in fnResult) { return fnResult; } return fnResult; })); }; enhanced.map = function(fn) { return enhance(this.then((result) => result.map(fn))); }; enhanced.mapErr = function(fn) { return enhance(this.then((result) => result.mapErr(fn))); }; enhanced.orElse = function(fallback) { return enhance(this.then((result) => result.orElse(fallback))); }; enhanced.unwrapOr = function(fallback) { return this.then((result) => result.unwrapOr(fallback)); }; enhanced.unwrapOrThrow = function() { return this.then((result) => result.unwrapOrThrow()); }; enhanced.tap = function(fn) { return enhance(this.then((result) => result.tap(fn))); }; enhanced.tapErr = function(fn) { return enhance(this.then((result) => result.tapErr(fn))); }; enhanced.finally = function(fn) { return enhance(this.then((result) => result.finally(fn))); }; enhanced.void = function() { return enhance(this.then((result) => result.void())); }; return enhanced; } function fromAsync(fn) { return enhance(fn()); } var pipe2 = pipe; var collect2 = collect; var collectAsync2 = collectAsync; var firstSuccess2 = firstSuccess; function isResult(value) { if (value === null || typeof value !== "object" || !("ok" in value) || typeof value.ok !== "boolean") { return false; } const v = value; if (v.ok === true) { return "value" in v; } else { return "error" in v && v.error instanceof globalThis.Error; } } function isOk(value) { return isResult(value) && value.ok === true; } function isErr(value) { return isResult(value) && value.ok === false; } // src/zt-pocket-knife.ts var ZT = { try: attempt, tryAsync, ok, err: err2 }; export { ZT, ZeroError, core_exports_exports as ZeroThrow }; //# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map