@zerothrow/core
Version:
Core ZeroThrow functionality - Rust-style Result<T,E> for TypeScript
309 lines (302 loc) • 8.68 kB
JavaScript
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