@duydang2311/attempt
Version:
A functional type for error handling in JS/TS
154 lines (152 loc) • 3.37 kB
JavaScript
// lib/pipe.ts
function pipe(value, ...fns) {
let current = value;
for (let i = 0, size = fns.length;i < size; ++i) {
current = fns[i](current);
if (current instanceof Promise) {
return current.then(async (resolved) => {
for (let j = i + 1;j < size; ++j) {
resolved = fns[j](resolved);
if (resolved instanceof Promise) {
resolved = await resolved;
}
}
return resolved;
});
}
}
return current;
}
// lib/attempt.ts
function attemptSync(fn) {
return (mapException) => {
try {
return attemptOk(fn());
} catch (e) {
return attemptFail(mapException ? mapException(e) : e);
}
};
}
function attemptAsync(fn) {
return async (mapException) => {
try {
const ret = await fn();
if (isAttempt(ret)) {
return ret;
}
return attemptOk(ret);
} catch (e) {
return attemptFail(mapException ? mapException(e) : e);
}
};
}
function attemptOk(data) {
return {
ok: true,
data,
pipe: attemptPipe
};
}
function attemptFail(error) {
return {
ok: false,
error,
pipe: attemptPipe
};
}
function attemptMap(f) {
return (attempt) => {
if (!attempt.ok) {
return attempt;
}
const ret = f(attempt.data);
if (ret instanceof Promise) {
return ret.then(attemptOk);
}
return attemptOk(ret);
};
}
function attemptFlatMap(f) {
return (attempt) => {
if (!attempt.ok) {
return attempt;
}
return f(attempt.data);
};
}
function attemptMapError(f) {
return (attempt) => {
if (attempt.ok) {
return attempt;
}
const ret = f(attempt.error);
if (ret instanceof Promise) {
return ret.then(attemptFail);
}
return attemptFail(ret);
};
}
function attemptFlatMapError(f) {
return (attempt) => {
if (attempt.ok) {
return attempt;
}
return f(attempt.error);
};
}
function attemptUnwrap(attempt) {
if (!attempt.ok) {
throw attempt.error;
}
return attempt.data;
}
function attemptUnwrapOr(attemptOrDefault, defaultValue) {
if (defaultValue) {
const attempt = attemptOrDefault;
return attempt.ok ? attempt.data : defaultValue;
}
return (attempt) => attempt.ok ? attempt.data : attemptOrDefault;
}
function attemptUnwrapOrElse(attemptOrF, f) {
if (f) {
const attempt = attemptOrF;
return attempt.ok ? attempt.data : f(attempt.error);
}
return (attempt) => attempt.ok ? attempt.data : attemptOrF(attempt.error);
}
function isAttempt(obj) {
return typeof obj === "object" && obj !== null && "ok" in obj && typeof obj.ok === "boolean" && (obj.ok === true && ("data" in obj) || obj.ok === false && ("error" in obj));
}
var attempt = {
sync: attemptSync,
async: attemptAsync,
ok: attemptOk,
fail: attemptFail,
map: attemptMap,
flatMap: attemptFlatMap,
check: isAttempt,
mapError: attemptMapError,
flatMapError: attemptFlatMapError,
orElse: attemptFlatMapError,
unwrap: attemptUnwrap,
unwrapOr: attemptUnwrapOr,
unwrapOrElse: attemptUnwrapOrElse
};
function attemptPipe(...fns) {
return pipe(this, ...fns);
}
export {
isAttempt,
attemptUnwrapOrElse,
attemptUnwrapOr,
attemptUnwrap,
attemptSync,
attemptOk,
attemptMapError,
attemptMap,
attemptFlatMapError,
attemptFlatMap,
attemptFail,
attemptAsync,
attempt
};