@onrails/result 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESIGN.md +4 -3
- package/README.md +166 -13
- package/RECIPES.md +6 -4
- package/dist/async-fns.cjs +52 -0
- package/dist/async-fns.cjs.map +1 -0
- package/dist/async-fns.d.cts +143 -0
- package/dist/async-fns.d.ts +143 -0
- package/dist/async-fns.js +42 -0
- package/dist/async-fns.js.map +1 -0
- package/dist/async-lift.d.cts +109 -0
- package/dist/async-lift.d.ts +109 -0
- package/dist/{async-Ci6WSL5-.d.ts → async.d.cts} +42 -58
- package/dist/{async-DcXR7k9K.d.cts → async.d.ts} +42 -58
- package/dist/collections.d.cts +105 -0
- package/dist/collections.d.ts +105 -0
- package/dist/compat/neverthrow.cjs +57 -45
- package/dist/compat/neverthrow.cjs.map +1 -1
- package/dist/compat/neverthrow.d.cts +21 -24
- package/dist/compat/neverthrow.d.ts +21 -24
- package/dist/compat/neverthrow.js +56 -44
- package/dist/compat/neverthrow.js.map +1 -1
- package/dist/extra.cjs +3 -1
- package/dist/extra.cjs.map +1 -1
- package/dist/extra.d.cts +11 -14
- package/dist/extra.d.ts +11 -14
- package/dist/extra.js +3 -1
- package/dist/extra.js.map +1 -1
- package/dist/fluent.cjs +15 -28
- package/dist/fluent.cjs.map +1 -1
- package/dist/fluent.d.cts +4 -34
- package/dist/fluent.d.ts +4 -34
- package/dist/fluent.js +16 -28
- package/dist/fluent.js.map +1 -1
- package/dist/index.cjs +77 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -490
- package/dist/index.d.ts +28 -490
- package/dist/index.js +77 -53
- package/dist/index.js.map +1 -1
- package/dist/internal/ctor.d.cts +12 -0
- package/dist/internal/ctor.d.ts +12 -0
- package/dist/internal/dual.d.cts +42 -0
- package/dist/internal/dual.d.ts +42 -0
- package/dist/internal/infer.d.cts +40 -0
- package/dist/internal/infer.d.ts +40 -0
- package/dist/internal/lock.d.cts +16 -0
- package/dist/internal/lock.d.ts +16 -0
- package/dist/internal/to-error.d.cts +2 -0
- package/dist/internal/to-error.d.ts +2 -0
- package/dist/pipe.cjs +8 -0
- package/dist/pipe.cjs.map +1 -1
- package/dist/pipe.d.cts +58 -11
- package/dist/pipe.d.ts +58 -11
- package/dist/pipe.js +8 -1
- package/dist/pipe.js.map +1 -1
- package/dist/railway.cjs +87 -63
- package/dist/railway.cjs.map +1 -1
- package/dist/railway.d.cts +49 -19
- package/dist/railway.d.ts +49 -19
- package/dist/railway.js +87 -63
- package/dist/railway.js.map +1 -1
- package/dist/result.d.cts +315 -0
- package/dist/result.d.ts +315 -0
- package/dist/try-gen.cjs +3 -3
- package/dist/try-gen.cjs.map +1 -1
- package/dist/try-gen.d.cts +4 -7
- package/dist/try-gen.d.ts +4 -7
- package/dist/try-gen.js +3 -3
- package/dist/try-gen.js.map +1 -1
- package/dist/{types-BQ9vv0nD.d.cts → types.d.cts} +6 -8
- package/dist/{types-BQ9vv0nD.d.ts → types.d.ts} +6 -8
- package/package.json +69 -24
- package/skills/railway-do-notation/SKILL.md +9 -9
package/dist/fluent.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { R as Result } from './types-BQ9vv0nD.js';
|
|
3
|
-
|
|
1
|
+
import type { Result } from "./types.js";
|
|
4
2
|
/** Opt-in dot chaining over a sync {@link Result} */
|
|
5
|
-
type FluentResult<T, E> = {
|
|
3
|
+
export type FluentResult<T, E> = {
|
|
6
4
|
readonly result: Result<T, E>;
|
|
7
5
|
map: <U>(fn: (value: T) => U) => FluentResult<U, E>;
|
|
8
6
|
mapErr: <F>(fn: (error: E) => F) => FluentResult<T, F>;
|
|
@@ -13,7 +11,7 @@ type FluentResult<T, E> = {
|
|
|
13
11
|
tap: (fn: (value: T) => void) => FluentResult<T, E>;
|
|
14
12
|
tapErr: (fn: (error: E) => void) => FluentResult<T, E>;
|
|
15
13
|
match: <U>(onOk: (value: T) => U, onErr: (error: E) => U) => U;
|
|
16
|
-
unwrapOr: (defaultValue:
|
|
14
|
+
unwrapOr: <U>(defaultValue: U) => T | U;
|
|
17
15
|
/** Exit the wrapper — hand back the canonical plain-data result. */
|
|
18
16
|
toResult: () => Result<T, E>;
|
|
19
17
|
/** Debug terminal — `Ok(…)` / `Err(…)`, same output as {@link show}. */
|
|
@@ -30,32 +28,4 @@ type FluentResult<T, E> = {
|
|
|
30
28
|
* fluent(ok(2)).map((n) => n * 3).unwrapOr(0); // 6
|
|
31
29
|
* ```
|
|
32
30
|
*/
|
|
33
|
-
declare const fluent: <T, E>(result: Result<T, E>) => FluentResult<T, E>;
|
|
34
|
-
/** Opt-in dot chaining over {@link ResultAsync} */
|
|
35
|
-
type FluentResultAsync<T, E> = {
|
|
36
|
-
readonly resultAsync: ResultAsync<T, E>;
|
|
37
|
-
map: <U>(fn: (value: T) => U) => FluentResultAsync<U, E>;
|
|
38
|
-
mapErr: <F>(fn: (error: E) => F) => FluentResultAsync<T, F>;
|
|
39
|
-
flatMap: <U, F = E>(fn: (value: T) => ResultAsync<U, F> | Result<U, F>) => FluentResultAsync<U, E | F>;
|
|
40
|
-
andThen: <U, F = E>(fn: (value: T) => ResultAsync<U, F> | Result<U, F>) => FluentResultAsync<U, E | F>;
|
|
41
|
-
recover: <F>(fn: (error: E) => ResultAsync<T, F> | Result<T, F>) => FluentResultAsync<T, F>;
|
|
42
|
-
orElse: <F>(fn: (error: E) => ResultAsync<T, F> | Result<T, F>) => FluentResultAsync<T, F>;
|
|
43
|
-
tap: (fn: (value: T) => void) => FluentResultAsync<T, E>;
|
|
44
|
-
tapErr: (fn: (error: E) => void) => FluentResultAsync<T, E>;
|
|
45
|
-
match: <U1, U2 = U1>(onOk: (value: T) => U1, onErr: (error: E) => U2) => Promise<U1 | U2>;
|
|
46
|
-
unwrapOr: <U>(defaultValue: U) => Promise<T | U>;
|
|
47
|
-
resolve: () => Promise<Result<T, E>>;
|
|
48
|
-
};
|
|
49
|
-
/**
|
|
50
|
-
* Wrap a {@link ResultAsync} for opt-in dot chaining — the async counterpart of
|
|
51
|
-
* {@link fluent}. App-edge sugar; await a terminal (`match`, `unwrapOr`,
|
|
52
|
-
* `resolve`) to leave the fluent world.
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* ```ts
|
|
56
|
-
* fluentAsync(okAsync(2)).map((n) => n * 3); // FluentResultAsync<number, never>
|
|
57
|
-
* ```
|
|
58
|
-
*/
|
|
59
|
-
declare const fluentAsync: <T, E>(resultAsync: ResultAsync<T, E>) => FluentResultAsync<T, E>;
|
|
60
|
-
|
|
61
|
-
export { type FluentResult, type FluentResultAsync, fluent, fluentAsync };
|
|
31
|
+
export declare const fluent: <T, E>(result: Result<T, E>) => FluentResult<T, E>;
|
package/dist/fluent.js
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// src/internal/ctor.ts
|
|
2
|
+
var mkOk = (value) => ({
|
|
3
|
+
_tag: "Ok",
|
|
4
|
+
value
|
|
5
|
+
});
|
|
6
|
+
var mkErr = (error) => ({
|
|
7
|
+
_tag: "Err",
|
|
8
|
+
error
|
|
9
|
+
});
|
|
10
|
+
|
|
1
11
|
// src/internal/dual.ts
|
|
2
12
|
var dual = (arity, body) => {
|
|
3
13
|
const run = body;
|
|
@@ -6,35 +16,27 @@ var dual = (arity, body) => {
|
|
|
6
16
|
};
|
|
7
17
|
|
|
8
18
|
// src/result.ts
|
|
9
|
-
var ok = (value) => ({
|
|
10
|
-
_tag: "Ok",
|
|
11
|
-
value
|
|
12
|
-
});
|
|
13
|
-
var err = (error) => ({
|
|
14
|
-
_tag: "Err",
|
|
15
|
-
error
|
|
16
|
-
});
|
|
17
19
|
var isOk = (result) => result._tag === "Ok";
|
|
18
20
|
var isErr = (result) => result._tag === "Err";
|
|
19
21
|
var map = dual(
|
|
20
22
|
2,
|
|
21
|
-
(result, fn) => isOk(result) ?
|
|
23
|
+
(result, fn) => isOk(result) ? mkOk(fn(result.value)) : mkErr(result.error)
|
|
22
24
|
);
|
|
23
25
|
var mapErr = dual(
|
|
24
26
|
2,
|
|
25
|
-
(result, fn) => isErr(result) ?
|
|
27
|
+
(result, fn) => isErr(result) ? mkErr(fn(result.error)) : mkOk(result.value)
|
|
26
28
|
);
|
|
27
29
|
var bimap = dual(
|
|
28
30
|
3,
|
|
29
|
-
(result, onOk, onErr) => isOk(result) ?
|
|
31
|
+
(result, onOk, onErr) => isOk(result) ? mkOk(onOk(result.value)) : mkErr(onErr(result.error))
|
|
30
32
|
);
|
|
31
33
|
var flatMap = dual(
|
|
32
34
|
2,
|
|
33
|
-
(result, fn) => isOk(result) ? fn(result.value) :
|
|
35
|
+
(result, fn) => isOk(result) ? fn(result.value) : mkErr(result.error)
|
|
34
36
|
);
|
|
35
37
|
var recover = dual(
|
|
36
38
|
2,
|
|
37
|
-
(result, fn) => isErr(result) ? fn(result.error) :
|
|
39
|
+
(result, fn) => isErr(result) ? fn(result.error) : mkOk(result.value)
|
|
38
40
|
);
|
|
39
41
|
var tap = dual(2, (result, fn) => {
|
|
40
42
|
if (isOk(result)) fn(result.value);
|
|
@@ -77,21 +79,7 @@ var fluent = (result) => ({
|
|
|
77
79
|
toResult: () => result,
|
|
78
80
|
toString: () => show(result)
|
|
79
81
|
});
|
|
80
|
-
var fluentAsync = (resultAsync) => ({
|
|
81
|
-
resultAsync,
|
|
82
|
-
map: (fn) => fluentAsync(resultAsync.map(fn)),
|
|
83
|
-
mapErr: (fn) => fluentAsync(resultAsync.mapErr(fn)),
|
|
84
|
-
flatMap: (fn) => fluentAsync(resultAsync.flatMap(fn)),
|
|
85
|
-
andThen: (fn) => fluentAsync(resultAsync.andThen(fn)),
|
|
86
|
-
recover: (fn) => fluentAsync(resultAsync.recover(fn)),
|
|
87
|
-
orElse: (fn) => fluentAsync(resultAsync.orElse(fn)),
|
|
88
|
-
tap: (fn) => fluentAsync(resultAsync.tap(fn)),
|
|
89
|
-
tapErr: (fn) => fluentAsync(resultAsync.tapErr(fn)),
|
|
90
|
-
match: (onOk, onErr) => resultAsync.match(onOk, onErr),
|
|
91
|
-
unwrapOr: (defaultValue) => resultAsync.unwrapOr(defaultValue),
|
|
92
|
-
resolve: () => resultAsync.resolve()
|
|
93
|
-
});
|
|
94
82
|
|
|
95
|
-
export { fluent
|
|
83
|
+
export { fluent };
|
|
96
84
|
//# sourceMappingURL=fluent.js.map
|
|
97
85
|
//# sourceMappingURL=fluent.js.map
|
package/dist/fluent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/dual.ts","../src/result.ts","../src/fluent.ts"],"names":[],"mappings":"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","file":"fluent.js","sourcesContent":["/**\n * @onrails/result internal — owning module for the **dual-form idiom**.\n *\n * Every dual-form transform in this package (`map`, `flatMap`, `match`, …)\n * accepts either shape:\n *\n * data-first: `map(result, fn)` — full arity, runs immediately\n * curried: `map(fn)(result)` — arity minus the leading `self`, returns\n * a unary function awaiting the data\n *\n * {@link dual} is the single arity dispatcher those transforms derive from;\n * hand-rolled `args.length` checks are not allowed elsewhere.\n *\n * NOTE: a twin copy of this module lives at `packages/maybe/src/internal/dual.ts`\n * — keep the two in sync when editing.\n *\n * Internal only: not listed in package.json `exports` or tsup entries.\n */\n\n/**\n * Derive a dual-form (data-first / curried) function from a single\n * data-first `body`.\n *\n * When called with `args.length >= arity` the wrapper runs `body(...args)`\n * (data-first). With fewer arguments it returns `(self) => body(self, ...args)`\n * — the curried, data-last-`self` form used with `pipe`/`flow`.\n *\n * The public type is supplied entirely by the caller: annotate the exported\n * const with the exact overload set and let `F` be inferred from it.\n *\n * @example\n * ```ts\n * export const map: {\n * <T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;\n * <T, U>(fn: (value: T) => U): <E>(result: Result<T, E>) => Result<U, E>;\n * } = dual(\n * 2,\n * <T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> =>\n * isOk(result) ? ok(fn(result.value)) : err(result.error),\n * );\n * ```\n */\nexport const dual = <F>(arity: number, body: (...args: never[]) => unknown): F => {\n // `(...args: never[]) => unknown` is the top function type, so every typed\n // body is assignable to the parameter — but it cannot be invoked with\n // `unknown` arguments. Re-view it through the variadic shape the dispatcher\n // actually forwards; the constraint is that `body` only ever receives the\n // arguments the caller's overload annotation admitted.\n const run = body as (...args: readonly unknown[]) => unknown;\n const dispatcher = (...args: readonly unknown[]): unknown =>\n args.length >= arity ? run(...args) : (self: unknown) => run(self, ...args);\n // The caller's overload annotation on the exported const supplies the real\n // public type; internally the dispatcher stays `unknown`-typed.\n return dispatcher as F;\n};\n","import { dual } from \"./internal/dual.js\";\nimport type { Err, Ok, Result } from \"./types.js\";\n\nexport type { Err, Ok, Result } from \"./types.js\";\n\n/**\n * Lifts a value into the success track.\n *\n * @example\n * ```ts\n * const r = ok(42); // Result<number, never>\n * const typed: Result<number, \"parse\"> = ok(1);\n * ```\n */\nexport const ok = <T, E = never>(value: T): Result<T, E> => ({\n _tag: \"Ok\",\n value,\n});\n\n/**\n * Fantasy Land `pure` — alias of {@link ok}. One lift name shared across the\n * trio (`of` / `Maybe.of` / `ResultAsync.of`) for generic and FL-style code.\n *\n * @example\n * ```ts\n * const r = of(42); // Result<number, never> — identical to ok(42)\n * ```\n */\nexport const of = ok;\n\n/**\n * Lifts a value into the error track.\n *\n * @example\n * ```ts\n * const r = err({ kind: \"parse\", message: \"bad json\" });\n * // Result<never, { kind: \"parse\"; message: string }>\n * ```\n */\nexport const err = <T = never, E = unknown>(error: E): Result<T, E> => ({\n _tag: \"Err\",\n error,\n});\n\n/**\n * Type-narrowing predicate: returns `true` when the result is `Ok`.\n *\n * @example\n * ```ts\n * if (isOk(r)) {\n * console.log(r.value); // narrowed to Ok branch\n * }\n * ```\n */\nexport const isOk = <T, E>(result: Result<T, E>): result is Ok<T, E> => result._tag === \"Ok\";\n\n/**\n * Type-narrowing predicate: returns `true` when the result is `Err`.\n *\n * @example\n * ```ts\n * if (isErr(r)) {\n * metrics.inc(\"error\", { kind: r.error.kind });\n * }\n * ```\n */\nexport const isErr = <T, E>(result: Result<T, E>): result is Err<T, E> => result._tag === \"Err\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each export accepts either shape:\n// data-first: `map(result, fn)`\n// curried: `map(fn)(result)`\n// Arity dispatch is derived from the internal `dual` combinator\n// (src/internal/dual.ts); the const annotation carries the public overloads.\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Transform the `Ok` value, passing `Err` through unchanged. Dual-form:\n * call data-first or curried (for use with {@link pipe}).\n *\n * @example\n * ```ts\n * map(ok(2), (n) => n * 3); // Ok 6 — data-first\n * pipe(ok(\"x\"), map((s) => s.length));// Ok 1 — curried\n * ```\n */\nexport const map: {\n <T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;\n <T, U>(fn: (value: T) => U): <E>(result: Result<T, E>) => Result<U, E>;\n} = dual(\n 2,\n <T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> =>\n isOk(result) ? ok(fn(result.value)) : err(result.error),\n);\n\n/**\n * Transform the `Err` value, passing `Ok` through unchanged. Useful for\n * unifying heterogeneous failure types into one app-level union.\n *\n * @example\n * ```ts\n * type AppError = { kind: \"http\"; status: number } | { kind: \"parse\" };\n * pipe(\n * fetchSync(url), // Result<Body, { status: number }>\n * mapErr((e): AppError => ({ kind: \"http\", status: e.status })),\n * );\n * ```\n */\nexport const mapErr: {\n <T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F>;\n <E, F>(fn: (error: E) => F): <T>(result: Result<T, E>) => Result<T, F>;\n} = dual(\n 2,\n <T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F> =>\n isErr(result) ? err(fn(result.error)) : ok(result.value),\n);\n\n/**\n * Transform both tracks at once — `Ok` via `onOk`, `Err` via `onErr`.\n * Equivalent to `mapErr(onErr)(map(onOk)(result))` but in one pass.\n *\n * @example\n * ```ts\n * bimap(parsed, (cfg) => cfg.name, (e) => ({ kind: \"input\", cause: e }));\n * ```\n */\nexport const bimap: {\n <T, U, E, F>(result: Result<T, E>, onOk: (value: T) => U, onErr: (error: E) => F): Result<U, F>;\n <T, U, E, F>(\n onOk: (value: T) => U,\n onErr: (error: E) => F,\n ): (result: Result<T, E>) => Result<U, F>;\n} = dual(\n 3,\n <T, U, E, F>(\n result: Result<T, E>,\n onOk: (value: T) => U,\n onErr: (error: E) => F,\n ): Result<U, F> => (isOk(result) ? ok(onOk(result.value)) : err(onErr(result.error))),\n);\n\n/**\n * Canonical bind (Fantasy Land `chain`). Chains a Result-returning step,\n * widening the error union to `E | F`. Short-circuits on `Err`.\n *\n * @example\n * ```ts\n * flatMap(parseInput(raw), (data) =>\n * data.id != null ? ok(data) : err({ kind: \"missing_id\" as const }),\n * );\n * // Result<Data, ParseError | { kind: \"missing_id\" }>\n * ```\n */\nexport const flatMap: {\n <T, U, E, F>(result: Result<T, E>, fn: (value: T) => Result<U, F>): Result<U, E | F>;\n <T, U, F>(fn: (value: T) => Result<U, F>): <E>(result: Result<T, E>) => Result<U, E | F>;\n} = dual(\n 2,\n <T, U, E, F>(result: Result<T, E>, fn: (value: T) => Result<U, F>): Result<U, E | F> =>\n isOk(result) ? fn(result.value) : err(result.error),\n);\n\n/**\n * Error-track bind — runs `fn` only when the result is `Err`, allowing\n * a failed workflow to recover to `Ok` or remap the failure. Mirror of\n * {@link flatMap} on the error channel.\n *\n * @example\n * ```ts\n * recover(networkResult, (e) =>\n * e.kind === \"rate_limit\" ? ok(cachedBody) : err(e),\n * );\n * ```\n */\nexport const recover: {\n <T, E, F>(result: Result<T, E>, fn: (error: E) => Result<T, F>): Result<T, F>;\n <T, E, F>(fn: (error: E) => Result<T, F>): (result: Result<T, E>) => Result<T, F>;\n} = dual(\n 2,\n <T, E, F>(result: Result<T, E>, fn: (error: E) => Result<T, F>): Result<T, F> =>\n isErr(result) ? fn(result.error) : ok(result.value),\n);\n\n/**\n * Observe the `Ok` value for side effects (logging, metrics) without\n * changing the carried value. Passes `Err` through untouched.\n *\n * @example\n * ```ts\n * pipe(\n * parseConfig(raw),\n * tap((cfg) => log.info({ msg: \"parsed\", name: cfg.name })),\n * flatMap(validate),\n * );\n * ```\n */\nexport const tap: {\n <T, E>(result: Result<T, E>, fn: (value: T) => void): Result<T, E>;\n <T>(fn: (value: T) => void): <E>(result: Result<T, E>) => Result<T, E>;\n} = dual(2, <T, E>(result: Result<T, E>, fn: (value: T) => void): Result<T, E> => {\n if (isOk(result)) fn(result.value);\n return result;\n});\n\n/**\n * Observe the `Err` value for side effects (logging, metrics) without\n * changing the carried error. Passes `Ok` through untouched.\n *\n * @example\n * ```ts\n * pipe(\n * loadUser(id),\n * tapErr((e) => metrics.inc(\"user.load.fail\", { kind: e.kind })),\n * );\n * ```\n */\nexport const tapErr: {\n <T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E>;\n <E>(fn: (error: E) => void): <T>(result: Result<T, E>) => Result<T, E>;\n} = dual(2, <T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E> => {\n if (isErr(result)) fn(result.error);\n return result;\n});\n\n/**\n * Terminal collapse — fold both tracks into a single value. Dual-form:\n * 3-args data-first, 2-args curried for {@link pipe}. Returns whatever\n * the handlers return.\n *\n * For files that also import `match` from `ts-pattern`, use a namespace\n * import (`import * as R from \"@onrails/result\"` → `R.match`) to dissolve\n * the collision.\n *\n * @example\n * ```ts\n * const html = match(parsed, (cfg) => render(cfg), (e) => renderError(e));\n * ```\n */\nexport const match: {\n <T, E, U>(result: Result<T, E>, onOk: (value: T) => U, onErr: (error: E) => U): U;\n <T, E, U>(onOk: (value: T) => U, onErr: (error: E) => U): (result: Result<T, E>) => U;\n} = dual(\n 3,\n <T, E, U>(result: Result<T, E>, onOk: (value: T) => U, onErr: (error: E) => U): U =>\n isOk(result) ? onOk(result.value) : onErr(result.error),\n);\n\n/**\n * Returns the `Ok` value, or `defaultValue` when the result is `Err`.\n *\n * @example\n * ```ts\n * unwrapOr(parsedSetting, \"default-value\");\n * ```\n */\nexport const unwrapOr: {\n <T, E>(result: Result<T, E>, defaultValue: T): T;\n <T>(defaultValue: T): <E>(result: Result<T, E>) => T;\n} = dual(\n 2,\n <T, E>(result: Result<T, E>, defaultValue: T): T => (isOk(result) ? result.value : defaultValue),\n);\n\n/**\n * Test/assert helper — returns the `Ok` value, or **throws the original `Err`\n * value** when called on an `Err`. This is the assertion tier (RFC 0001 §4):\n * intended for `*.spec.ts` / `*.test.ts`, where throwing fails the test loudly.\n * In business logic prefer {@link match} or {@link unwrapOr}; the lint plugins\n * flag `unwrapOk` outside test files.\n *\n * @returns the unwrapped `Ok` value\n * @throws the carried `Err` value when the result is `Err`\n *\n * @example\n * ```ts\n * // in a *.spec.ts\n * expect(unwrapOk(ok(5))).toBe(5);\n * expect(() => unwrapOk(err(error))).toThrow(error);\n * ```\n */\nexport function unwrapOk<T, E>(result: Result<T, E>): T {\n if (isErr(result)) throw result.error;\n return result.value;\n}\n\n/** Alias of {@link unwrapOk} for syntax cohesion with `@onrails/maybe`. */\nexport const unwrap = unwrapOk;\n\n/**\n * Test/assert helper — returns the `Err` value, or **throws a `TypeError`**\n * when called on an `Ok`. Mirror of {@link unwrapOk} on the error track and\n * part of the same assertion tier (RFC 0001 §4): intended for `*.spec.ts` /\n * `*.test.ts`. Prefer {@link match} / {@link unwrapOr} in business logic; the\n * lint plugins flag `unwrapErr` outside test files.\n *\n * @returns the unwrapped `Err` value\n * @throws `TypeError` when the result is `Ok`\n *\n * @example\n * ```ts\n * // in a *.spec.ts\n * expect(unwrapErr(err(\"x\"))).toBe(\"x\");\n * expect(() => unwrapErr(ok(5))).toThrow(TypeError);\n * ```\n */\nexport function unwrapErr<T, E>(result: Result<T, E>): E {\n if (isOk(result)) throw new TypeError(\"unwrapErr called on Ok\");\n return result.error;\n}\n\n/**\n * Wraps a throwing sync function, returning a function that produces a\n * {@link Result} instead of throwing. Thrown errors pass through `onThrow` to\n * become a typed `Err`; a normal return becomes `Ok`. The neverthrow analogue\n * is `Result.fromThrowable`.\n *\n * @param fn - the throwing function to wrap\n * @param onThrow - maps a thrown value to the `Err` channel\n * @returns a function with `fn`'s parameters that returns `Result<ReturnType, E>`\n *\n * @example\n * ```ts\n * type ParseError = { kind: \"parse\"; message: string };\n * const parse = trySync(\n * JSON.parse,\n * (e): ParseError => ({ kind: \"parse\", message: String(e) }),\n * );\n * parse(\"{}\"); // Ok({})\n * parse(\"nope\"); // Err({ kind: \"parse\", … })\n * ```\n */\nexport function trySync<A extends readonly unknown[], T, E>(\n fn: (...args: A) => T,\n onThrow: (error: unknown) => E,\n): (...args: A) => Result<T, E>;\nexport function trySync<F extends (...args: never) => unknown, E>(\n fn: F,\n onThrow: (error: unknown) => E,\n): (...args: Parameters<F>) => Result<ReturnType<F>, E>;\nexport function trySync(\n fn: (...args: never) => unknown,\n onThrow: (error: unknown) => unknown,\n): (...args: never) => Result<unknown, unknown> {\n return (...args: never) => {\n try {\n return ok(fn(...args));\n } catch (error) {\n return err(onThrow(error));\n }\n };\n}\n\n/**\n * Variadic value-first pipe — threads `value` through up to nine unary fns,\n * left-to-right. Use {@link pipe} when you already have a starting value;\n * use {@link flow} to define a reusable composed function with no value yet.\n *\n * @example\n * ```ts\n * pipe(\n * parseConfig(raw),\n * map((cfg) => cfg.name),\n * flatMap((name) => (name ? ok(name) : err({ kind: \"empty\" as const }))),\n * tap(log),\n * );\n * ```\n */\nexport function pipe<A>(value: A): A;\nexport function pipe<A, B>(value: A, ab: (a: A) => B): B;\nexport function pipe<A, B, C>(value: A, ab: (a: A) => B, bc: (b: B) => C): C;\nexport function pipe<A, B, C, D>(value: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D;\nexport function pipe<A, B, C, D, E>(\n value: A,\n ab: (a: A) => B,\n bc: (b: B) => C,\n cd: (c: C) => D,\n de: (d: D) => E,\n): E;\nexport function pipe<A, B, C, D, E, F>(\n value: A,\n ab: (a: A) => B,\n bc: (b: B) => C,\n cd: (c: C) => D,\n de: (d: D) => E,\n ef: (e: E) => F,\n): F;\nexport function pipe<A, B, C, D, E, F, G>(\n value: A,\n ab: (a: A) => B,\n bc: (b: B) => C,\n cd: (c: C) => D,\n de: (d: D) => E,\n ef: (e: E) => F,\n fg: (f: F) => G,\n): G;\nexport function pipe<A, B, C, D, E, F, G, H>(\n value: A,\n ab: (a: A) => B,\n bc: (b: B) => C,\n cd: (c: C) => D,\n de: (d: D) => E,\n ef: (e: E) => F,\n fg: (f: F) => G,\n gh: (g: G) => H,\n): H;\nexport function pipe<A, B, C, D, E, F, G, H, I>(\n value: A,\n ab: (a: A) => B,\n bc: (b: B) => C,\n cd: (c: C) => D,\n de: (d: D) => E,\n ef: (e: E) => F,\n fg: (f: F) => G,\n gh: (g: G) => H,\n hi: (h: H) => I,\n): I;\nexport function pipe(value: unknown, ...fns: ReadonlyArray<(x: unknown) => unknown>): unknown {\n let acc = value;\n for (const fn of fns) {\n acc = fn(acc);\n }\n return acc;\n}\n\nconst printPayload = (payload: unknown): string => {\n try {\n return JSON.stringify(payload) ?? String(payload);\n } catch {\n // cyclic or non-JSON payload — a debug printer must not throw\n return String(payload);\n }\n};\n\n/**\n * Debug printer — renders a result as `Ok(…)` / `Err(…)` for logs. Payloads\n * print as JSON (values are plain data by design); non-JSON payloads fall\n * back to `String(...)`.\n *\n * @example\n * ```ts\n * show(ok(1)); // 'Ok(1)'\n * show(err({ kind: \"e\" })); // 'Err({\"kind\":\"e\"})'\n * ```\n */\nexport const show = <T, E>(result: Result<T, E>): string =>\n isOk(result) ? `Ok(${printPayload(result.value)})` : `Err(${printPayload(result.error)})`;\n","import type { ResultAsync } from \"./async.js\";\nimport {\n bimap,\n flatMap,\n map,\n mapErr,\n match,\n recover,\n show,\n tap,\n tapErr,\n unwrapOr,\n} from \"./result.js\";\nimport type { Result } from \"./types.js\";\n\n/** Opt-in dot chaining over a sync {@link Result} */\nexport type FluentResult<T, E> = {\n readonly result: Result<T, E>;\n map: <U>(fn: (value: T) => U) => FluentResult<U, E>;\n mapErr: <F>(fn: (error: E) => F) => FluentResult<T, F>;\n bimap: <U, F>(onOk: (value: T) => U, onErr: (error: E) => F) => FluentResult<U, F>;\n flatMap: <U, F = E>(fn: (value: T) => Result<U, F>) => FluentResult<U, E | F>;\n andThen: <U, F = E>(fn: (value: T) => Result<U, F>) => FluentResult<U, E | F>;\n recover: <F>(fn: (error: E) => Result<T, F>) => FluentResult<T, F>;\n tap: (fn: (value: T) => void) => FluentResult<T, E>;\n tapErr: (fn: (error: E) => void) => FluentResult<T, E>;\n\n match: <U>(onOk: (value: T) => U, onErr: (error: E) => U) => U;\n unwrapOr: (defaultValue: T) => T;\n /** Exit the wrapper — hand back the canonical plain-data result. */\n toResult: () => Result<T, E>;\n /** Debug terminal — `Ok(…)` / `Err(…)`, same output as {@link show}. */\n toString: () => string;\n};\n\n/**\n * Wrap a {@link Result} for opt-in dot chaining — app-edge sugar. Keep the\n * data-first helpers ({@link map}, {@link flatMap}) in library internals.\n *\n * Mirrors every core transform; `test/parity.spec.ts` enforces the mirror.\n *\n * @example\n * ```ts\n * fluent(ok(2)).map((n) => n * 3).unwrapOr(0); // 6\n * ```\n */\nexport const fluent = <T, E>(result: Result<T, E>): FluentResult<T, E> => ({\n result,\n map: (fn) => fluent(map(result, fn)),\n mapErr: (fn) => fluent(mapErr(result, fn)),\n bimap: (onOk, onErr) => fluent(bimap(result, onOk, onErr)),\n flatMap: (fn) => fluent(flatMap(result, fn)),\n andThen: (fn) => fluent(flatMap(result, fn)),\n recover: (fn) => fluent(recover(result, fn)),\n tap: (fn) => fluent(tap(result, fn)),\n tapErr: (fn) => fluent(tapErr(result, fn)),\n\n match: (onOk, onErr) => match(result, onOk, onErr),\n unwrapOr: (defaultValue) => unwrapOr(result, defaultValue),\n toResult: () => result,\n toString: () => show(result),\n});\n\n/** Opt-in dot chaining over {@link ResultAsync} */\nexport type FluentResultAsync<T, E> = {\n readonly resultAsync: ResultAsync<T, E>;\n map: <U>(fn: (value: T) => U) => FluentResultAsync<U, E>;\n mapErr: <F>(fn: (error: E) => F) => FluentResultAsync<T, F>;\n flatMap: <U, F = E>(\n fn: (value: T) => ResultAsync<U, F> | Result<U, F>,\n ) => FluentResultAsync<U, E | F>;\n andThen: <U, F = E>(\n fn: (value: T) => ResultAsync<U, F> | Result<U, F>,\n ) => FluentResultAsync<U, E | F>;\n recover: <F>(fn: (error: E) => ResultAsync<T, F> | Result<T, F>) => FluentResultAsync<T, F>;\n orElse: <F>(fn: (error: E) => ResultAsync<T, F> | Result<T, F>) => FluentResultAsync<T, F>;\n tap: (fn: (value: T) => void) => FluentResultAsync<T, E>;\n tapErr: (fn: (error: E) => void) => FluentResultAsync<T, E>;\n\n match: <U1, U2 = U1>(onOk: (value: T) => U1, onErr: (error: E) => U2) => Promise<U1 | U2>;\n unwrapOr: <U>(defaultValue: U) => Promise<T | U>;\n resolve: () => Promise<Result<T, E>>;\n};\n\n/**\n * Wrap a {@link ResultAsync} for opt-in dot chaining — the async counterpart of\n * {@link fluent}. App-edge sugar; await a terminal (`match`, `unwrapOr`,\n * `resolve`) to leave the fluent world.\n *\n * @example\n * ```ts\n * fluentAsync(okAsync(2)).map((n) => n * 3); // FluentResultAsync<number, never>\n * ```\n */\nexport const fluentAsync = <T, E>(resultAsync: ResultAsync<T, E>): FluentResultAsync<T, E> => ({\n resultAsync,\n map: (fn) => fluentAsync(resultAsync.map(fn)),\n mapErr: (fn) => fluentAsync(resultAsync.mapErr(fn)),\n flatMap: (fn) => fluentAsync(resultAsync.flatMap(fn)),\n andThen: (fn) => fluentAsync(resultAsync.andThen(fn)),\n recover: (fn) => fluentAsync(resultAsync.recover(fn)),\n orElse: (fn) => fluentAsync(resultAsync.orElse(fn)),\n tap: (fn) => fluentAsync(resultAsync.tap(fn)),\n tapErr: (fn) => fluentAsync(resultAsync.tapErr(fn)),\n\n match: (onOk, onErr) => resultAsync.match(onOk, onErr),\n unwrapOr: (defaultValue) => resultAsync.unwrapOr(defaultValue),\n resolve: () => resultAsync.resolve(),\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/ctor.ts","../src/internal/dual.ts","../src/result.ts","../src/fluent.ts"],"names":[],"mappings":"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","file":"fluent.js","sourcesContent":["import type { Result } from \"../types.js\";\n\n/**\n * Unlocked `Ok` constructor for library internals.\n *\n * The public {@link ok} takes a `const` type parameter so caller literals stay\n * narrow. That is wrong inside a generic transform, where the payload type is\n * an unresolved type parameter and the resulting `Locked<T>` would never reduce\n * back to `T`. Internals build results through this constructor instead.\n */\nexport const mkOk = <T, E = never>(value: T): Result<T, E> => ({\n _tag: \"Ok\",\n value,\n});\n\n/** Unlocked `Err` constructor for library internals. Mirror of {@link mkOk}. */\nexport const mkErr = <T = never, E = unknown>(error: E): Result<T, E> => ({\n _tag: \"Err\",\n error,\n});\n","/**\n * @onrails/result internal — owning module for the **dual-form idiom**.\n *\n * Every dual-form transform in this package (`map`, `flatMap`, `match`, …)\n * accepts either shape:\n *\n * data-first: `map(result, fn)` — full arity, runs immediately\n * curried: `map(fn)(result)` — arity minus the leading `self`, returns\n * a unary function awaiting the data\n *\n * {@link dual} is the single arity dispatcher those transforms derive from;\n * hand-rolled `args.length` checks are not allowed elsewhere.\n *\n * NOTE: a twin copy of this module lives at `packages/maybe/src/internal/dual.ts`\n * — keep the two in sync when editing.\n *\n * Internal only: not listed in package.json `exports` or tsup entries.\n */\n\n/**\n * Derive a dual-form (data-first / curried) function from a single\n * data-first `body`.\n *\n * When called with `args.length >= arity` the wrapper runs `body(...args)`\n * (data-first). With fewer arguments it returns `(self) => body(self, ...args)`\n * — the curried, data-last-`self` form used with `pipe`/`flow`.\n *\n * The public type is supplied entirely by the caller: annotate the exported\n * const with the exact overload set and let `F` be inferred from it.\n *\n * @example\n * ```ts\n * export const map: {\n * <T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;\n * <T, U>(fn: (value: T) => U): <E>(result: Result<T, E>) => Result<U, E>;\n * } = dual(\n * 2,\n * <T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> =>\n * isOk(result) ? ok(fn(result.value)) : err(result.error),\n * );\n * ```\n */\nexport const dual = <F>(arity: number, body: (...args: never[]) => unknown): F => {\n // `(...args: never[]) => unknown` is the top function type, so every typed\n // body is assignable to the parameter — but it cannot be invoked with\n // `unknown` arguments. Re-view it through the variadic shape the dispatcher\n // actually forwards; the constraint is that `body` only ever receives the\n // arguments the caller's overload annotation admitted.\n const run = body as (...args: readonly unknown[]) => unknown;\n const dispatcher = (...args: readonly unknown[]): unknown =>\n args.length >= arity ? run(...args) : (self: unknown) => run(self, ...args);\n // The caller's overload annotation on the exported const supplies the real\n // public type; internally the dispatcher stays `unknown`-typed.\n return dispatcher as F;\n};\n","import { mkErr, mkOk } from \"./internal/ctor.js\";\nimport { dual } from \"./internal/dual.js\";\nimport type { Locked } from \"./internal/lock.js\";\nimport { toError } from \"./internal/to-error.js\";\nimport type { Err, Ok, Result } from \"./types.js\";\n\nexport type { Err, Ok, Result } from \"./types.js\";\n\n/**\n * Lifts a value into the success track.\n *\n * @example\n * ```ts\n * const r = ok(42); // Result<42, never> — literal locked\n * const typed: Result<number, \"parse\"> = ok(1);\n * const lift = <T, E>(v: T): Result<T, E> => ok<T, E>(v); // explicit args opt out\n * ```\n *\n * @remarks\n * An inline literal keeps its narrow type instead of widening (`ok(\"a\")` is\n * `Result<\"a\", never>`, not `Result<string, never>`). Pass both type arguments\n * to opt out — generic code that must produce `Result<T, E>` for an unresolved\n * `T` needs that form.\n */\nexport function ok<const T>(value: T): Result<Locked<T>, never>;\nexport function ok<T, E>(value: T): Result<T, E>;\nexport function ok<T>(value: T): Result<T, never> {\n // Safe: `Locked<T>` only unwraps the readonly tuple that `const` inference\n // adds; the runtime payload is the value the caller passed, unchanged.\n return mkOk(value);\n}\n\n/**\n * Fantasy Land `pure` — alias of {@link ok}. One lift name shared across the\n * trio (`of` / `Maybe.of` / `ResultAsync.of`) for generic and FL-style code.\n *\n * @example\n * ```ts\n * const r = of(42); // Result<42, never> — identical to ok(42)\n * ```\n */\nexport const of = ok;\n\n/**\n * Lifts a value into the error track.\n *\n * @example\n * ```ts\n * const r = err({ kind: \"parse\", message: \"bad json\" });\n * // Result<never, { readonly kind: \"parse\"; readonly message: string }>\n *\n * type AppError = { kind: \"parse\" } | { kind: \"io\" };\n * err<AppError>({ kind: \"io\" }); // Result<never, AppError> — one arg names the error\n * err<number, AppError>({ kind: \"io\" }); // Result<number, AppError> — neverthrow's T, E order\n * ```\n *\n * @remarks\n * One explicit type argument names the **error** channel, which is what the\n * call site almost always means. Both channels still take neverthrow's `T, E`\n * order, and that two-argument form is also the escape hatch for generic code:\n * inference-driven calls lock literals, so a generic `E` must be passed\n * explicitly to keep the error type from being rewritten.\n */\nexport function err<const E>(error: E): Result<never, Locked<E>>;\nexport function err<T, E>(error: E): Result<T, E>;\nexport function err<E>(error: E): Result<never, E> {\n // Safe: see the note on `ok` — `Locked` is a type-level unwrap only.\n return mkErr(error);\n}\n\n/**\n * Type-narrowing predicate: returns `true` when the result is `Ok`.\n *\n * @example\n * ```ts\n * if (isOk(r)) {\n * console.log(r.value); // narrowed to Ok branch\n * }\n * ```\n */\nexport const isOk = <T, E>(result: Result<T, E>): result is Ok<T, E> => result._tag === \"Ok\";\n\n/**\n * Type-narrowing predicate: returns `true` when the result is `Err`.\n *\n * @example\n * ```ts\n * if (isErr(r)) {\n * metrics.inc(\"error\", { kind: r.error.kind });\n * }\n * ```\n */\nexport const isErr = <T, E>(result: Result<T, E>): result is Err<T, E> => result._tag === \"Err\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each export accepts either shape:\n// data-first: `map(result, fn)`\n// curried: `map(fn)(result)`\n// Arity dispatch is derived from the internal `dual` combinator\n// (src/internal/dual.ts); the const annotation carries the public overloads.\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Transform the `Ok` value, passing `Err` through unchanged. Dual-form:\n * call data-first or curried (for use with {@link pipe}).\n *\n * @example\n * ```ts\n * map(ok(2), (n) => n * 3); // Ok 6 — data-first\n * pipe(ok(\"x\"), map((s) => s.length));// Ok 1 — curried\n * ```\n */\nexport const map: {\n <T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;\n <T, U>(fn: (value: T) => U): <E>(result: Result<T, E>) => Result<U, E>;\n} = dual(\n 2,\n <T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> =>\n isOk(result) ? mkOk(fn(result.value)) : mkErr(result.error),\n);\n\n/**\n * Transform the `Err` value, passing `Ok` through unchanged. Useful for\n * unifying heterogeneous failure types into one app-level union.\n *\n * @example\n * ```ts\n * type AppError = { kind: \"http\"; status: number } | { kind: \"parse\" };\n * pipe(\n * fetchSync(url), // Result<Body, { status: number }>\n * mapErr((e): AppError => ({ kind: \"http\", status: e.status })),\n * );\n * ```\n */\nexport const mapErr: {\n <T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F>;\n <E, F>(fn: (error: E) => F): <T>(result: Result<T, E>) => Result<T, F>;\n} = dual(\n 2,\n <T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F> =>\n isErr(result) ? mkErr(fn(result.error)) : mkOk(result.value),\n);\n\n/**\n * Transform both tracks at once — `Ok` via `onOk`, `Err` via `onErr`.\n * Equivalent to `mapErr(onErr)(map(onOk)(result))` but in one pass.\n *\n * @example\n * ```ts\n * bimap(parsed, (cfg) => cfg.name, (e) => ({ kind: \"input\", cause: e }));\n * ```\n */\nexport const bimap: {\n <T, U, E, F>(result: Result<T, E>, onOk: (value: T) => U, onErr: (error: E) => F): Result<U, F>;\n <T, U, E, F>(\n onOk: (value: T) => U,\n onErr: (error: E) => F,\n ): (result: Result<T, E>) => Result<U, F>;\n} = dual(\n 3,\n <T, U, E, F>(\n result: Result<T, E>,\n onOk: (value: T) => U,\n onErr: (error: E) => F,\n ): Result<U, F> => (isOk(result) ? mkOk(onOk(result.value)) : mkErr(onErr(result.error))),\n);\n\n/**\n * Canonical bind (Fantasy Land `chain`). Chains a Result-returning step,\n * widening the error union to `E | F`. Short-circuits on `Err`.\n *\n * @example\n * ```ts\n * flatMap(parseInput(raw), (data) =>\n * data.id != null ? ok(data) : err({ kind: \"missing_id\" as const }),\n * );\n * // Result<Data, ParseError | { kind: \"missing_id\" }>\n * ```\n */\nexport const flatMap: {\n <T, U, E, F>(result: Result<T, E>, fn: (value: T) => Result<U, F>): Result<U, E | F>;\n <T, U, F>(fn: (value: T) => Result<U, F>): <E>(result: Result<T, E>) => Result<U, E | F>;\n} = dual(\n 2,\n <T, U, E, F>(result: Result<T, E>, fn: (value: T) => Result<U, F>): Result<U, E | F> =>\n isOk(result) ? fn(result.value) : mkErr(result.error),\n);\n\n/**\n * Error-track bind — runs `fn` only when the result is `Err`, allowing\n * a failed workflow to recover to `Ok` or remap the failure. Mirror of\n * {@link flatMap} on the error channel.\n *\n * @example\n * ```ts\n * recover(networkResult, (e) =>\n * e.kind === \"rate_limit\" ? ok(cachedBody) : err(e),\n * );\n * ```\n */\nexport const recover: {\n <T, E, F>(result: Result<T, E>, fn: (error: E) => Result<T, F>): Result<T, F>;\n <T, E, F>(fn: (error: E) => Result<T, F>): (result: Result<T, E>) => Result<T, F>;\n} = dual(\n 2,\n <T, E, F>(result: Result<T, E>, fn: (error: E) => Result<T, F>): Result<T, F> =>\n isErr(result) ? fn(result.error) : mkOk(result.value),\n);\n\n/**\n * Observe the `Ok` value for side effects (logging, metrics) without\n * changing the carried value. Passes `Err` through untouched.\n *\n * @example\n * ```ts\n * pipe(\n * parseConfig(raw),\n * tap((cfg) => log.info({ msg: \"parsed\", name: cfg.name })),\n * flatMap(validate),\n * );\n * ```\n */\nexport const tap: {\n <T, E>(result: Result<T, E>, fn: (value: T) => void): Result<T, E>;\n <T>(fn: (value: T) => void): <E>(result: Result<T, E>) => Result<T, E>;\n} = dual(2, <T, E>(result: Result<T, E>, fn: (value: T) => void): Result<T, E> => {\n if (isOk(result)) fn(result.value);\n return result;\n});\n\n/**\n * Observe the `Err` value for side effects (logging, metrics) without\n * changing the carried error. Passes `Ok` through untouched.\n *\n * @example\n * ```ts\n * pipe(\n * loadUser(id),\n * tapErr((e) => metrics.inc(\"user.load.fail\", { kind: e.kind })),\n * );\n * ```\n */\nexport const tapErr: {\n <T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E>;\n <E>(fn: (error: E) => void): <T>(result: Result<T, E>) => Result<T, E>;\n} = dual(2, <T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E> => {\n if (isErr(result)) fn(result.error);\n return result;\n});\n\n/**\n * Terminal collapse — fold both tracks into a single value. Dual-form:\n * 3-args data-first, 2-args curried for {@link pipe}. Returns whatever\n * the handlers return.\n *\n * For files that also import `match` from `ts-pattern`, use a namespace\n * import (`import * as R from \"@onrails/result\"` → `R.match`) to dissolve\n * the collision.\n *\n * @example\n * ```ts\n * const html = match(parsed, (cfg) => render(cfg), (e) => renderError(e));\n * ```\n */\nexport const match: {\n <T, E, U>(result: Result<T, E>, onOk: (value: T) => U, onErr: (error: E) => U): U;\n <T, E, U>(onOk: (value: T) => U, onErr: (error: E) => U): (result: Result<T, E>) => U;\n} = dual(\n 3,\n <T, E, U>(result: Result<T, E>, onOk: (value: T) => U, onErr: (error: E) => U): U =>\n isOk(result) ? onOk(result.value) : onErr(result.error),\n);\n\n/**\n * Returns the `Ok` value, or `defaultValue` when the result is `Err`. The\n * fallback may be a different type from `T` — the return widens to `T | U`,\n * matching `ResultAsync.unwrapOr` and the compat shim.\n *\n * @example\n * ```ts\n * unwrapOr(parsedSetting, \"default-value\"); // string\n * unwrapOr(parsedPort, null); // number | null\n * ```\n */\nexport const unwrapOr: {\n <T, E, U>(result: Result<T, E>, defaultValue: U): T | U;\n <U>(defaultValue: U): <T, E>(result: Result<T, E>) => T | U;\n} = dual(2, <T, E, U>(result: Result<T, E>, defaultValue: U): T | U =>\n isOk(result) ? result.value : defaultValue,\n);\n\n/**\n * Test/assert helper — returns the `Ok` value, or **throws the original `Err`\n * value** when called on an `Err`. This is the assertion tier (RFC 0001 §4):\n * intended for `*.spec.ts` / `*.test.ts`, where throwing fails the test loudly.\n * In business logic prefer {@link match} or {@link unwrapOr}; the lint plugins\n * flag `unwrapOk` outside test files.\n *\n * @returns the unwrapped `Ok` value\n * @throws the carried `Err` value when the result is `Err`\n *\n * @example\n * ```ts\n * // in a *.spec.ts\n * expect(unwrapOk(ok(5))).toBe(5);\n * expect(() => unwrapOk(err(error))).toThrow(error);\n * ```\n */\nexport function unwrapOk<T, E>(result: Result<T, E>): T {\n if (isErr(result)) throw result.error;\n return result.value;\n}\n\n/** Alias of {@link unwrapOk} for syntax cohesion with `@onrails/maybe`. */\nexport const unwrap = unwrapOk;\n\n/**\n * Test/assert helper — returns the `Err` value, or **throws a `TypeError`**\n * when called on an `Ok`. Mirror of {@link unwrapOk} on the error track and\n * part of the same assertion tier (RFC 0001 §4): intended for `*.spec.ts` /\n * `*.test.ts`. Prefer {@link match} / {@link unwrapOr} in business logic; the\n * lint plugins flag `unwrapErr` outside test files.\n *\n * @returns the unwrapped `Err` value\n * @throws `TypeError` when the result is `Ok`\n *\n * @example\n * ```ts\n * // in a *.spec.ts\n * expect(unwrapErr(err(\"x\"))).toBe(\"x\");\n * expect(() => unwrapErr(ok(5))).toThrow(TypeError);\n * ```\n */\nexport function unwrapErr<T, E>(result: Result<T, E>): E {\n if (isOk(result)) throw new TypeError(\"unwrapErr called on Ok\");\n return result.error;\n}\n\n/**\n * Wraps a throwing sync **function**, returning a function that produces a\n * {@link Result} instead of throwing. Thrown errors pass through `onThrow` to\n * become a typed `Err`; a normal return becomes `Ok`. Same name and shape as\n * neverthrow's `Result.fromThrowable`.\n *\n * Reach for {@link trySync} instead when you want to run the call right now\n * rather than build a reusable wrapper.\n *\n * @param fn - the throwing function to wrap\n * @param onThrow - maps a thrown value to the `Err` channel\n * @returns a function with `fn`'s parameters that returns `Result<ReturnType, E>`\n *\n * @example\n * ```ts\n * type ParseError = { kind: \"parse\"; message: string };\n * const parse = fromThrowable(\n * JSON.parse,\n * (e): ParseError => ({ kind: \"parse\", message: String(e) }),\n * );\n * parse(\"{}\"); // Ok({})\n * parse(\"nope\"); // Err({ kind: \"parse\", … })\n * ```\n */\nexport function fromThrowable<A extends readonly unknown[], T, E>(\n fn: (...args: A) => T,\n onThrow: (error: unknown) => E,\n): (...args: A) => Result<T, E>;\nexport function fromThrowable<F extends (...args: never) => unknown, E>(\n fn: F,\n onThrow: (error: unknown) => E,\n): (...args: Parameters<F>) => Result<ReturnType<F>, E>;\nexport function fromThrowable(\n fn: (...args: never) => unknown,\n onThrow: (error: unknown) => unknown,\n): (...args: never) => Result<unknown, unknown> {\n return (...args: never) => {\n try {\n return mkOk(fn(...args));\n } catch (error) {\n return mkErr(onThrow(error));\n }\n };\n}\n\n/**\n * Runs `fn` **now**, catching a throw into the `Err` track — the sync mirror\n * of `tryAsync`. Without `onThrow` the thrown value is normalized to an\n * `Error`; pass a mapper for a typed error.\n *\n * To lift a throwing function once and call it many times, use\n * {@link fromThrowable}.\n *\n * @param fn - the throwing thunk to run\n * @param onThrow - maps a thrown value to the `Err` channel\n *\n * @example\n * ```ts\n * trySync(() => JSON.parse(raw)); // Result<unknown, Error>\n * trySync(() => Schema.parse(input), (e): SchemaError => ({\n * kind: \"schema\",\n * cause: e,\n * }));\n * ```\n */\nexport function trySync<T>(fn: () => T): Result<T, Error>;\nexport function trySync<T, E>(fn: () => T, onThrow: (error: unknown) => E): Result<T, E>;\nexport function trySync<T, E>(fn: () => T, onThrow?: (error: unknown) => E): Result<T, E | Error> {\n try {\n return mkOk(fn());\n } catch (error) {\n return mkErr(onThrow ? onThrow(error) : toError(error));\n }\n}\n\nconst printPayload = (payload: unknown): string => {\n try {\n return JSON.stringify(payload) ?? String(payload);\n } catch {\n // cyclic or non-JSON payload — a debug printer must not throw\n return String(payload);\n }\n};\n\n/**\n * Debug printer — renders a result as `Ok(…)` / `Err(…)` for logs. Payloads\n * print as JSON (values are plain data by design); non-JSON payloads fall\n * back to `String(...)`.\n *\n * @example\n * ```ts\n * show(ok(1)); // 'Ok(1)'\n * show(err({ kind: \"e\" })); // 'Err({\"kind\":\"e\"})'\n * ```\n */\nexport const show = <T, E>(result: Result<T, E>): string =>\n isOk(result) ? `Ok(${printPayload(result.value)})` : `Err(${printPayload(result.error)})`;\n","import {\n bimap,\n flatMap,\n map,\n mapErr,\n match,\n recover,\n show,\n tap,\n tapErr,\n unwrapOr,\n} from \"./result.js\";\nimport type { Result } from \"./types.js\";\n\n/** Opt-in dot chaining over a sync {@link Result} */\nexport type FluentResult<T, E> = {\n readonly result: Result<T, E>;\n map: <U>(fn: (value: T) => U) => FluentResult<U, E>;\n mapErr: <F>(fn: (error: E) => F) => FluentResult<T, F>;\n bimap: <U, F>(onOk: (value: T) => U, onErr: (error: E) => F) => FluentResult<U, F>;\n flatMap: <U, F = E>(fn: (value: T) => Result<U, F>) => FluentResult<U, E | F>;\n andThen: <U, F = E>(fn: (value: T) => Result<U, F>) => FluentResult<U, E | F>;\n recover: <F>(fn: (error: E) => Result<T, F>) => FluentResult<T, F>;\n tap: (fn: (value: T) => void) => FluentResult<T, E>;\n tapErr: (fn: (error: E) => void) => FluentResult<T, E>;\n\n match: <U>(onOk: (value: T) => U, onErr: (error: E) => U) => U;\n unwrapOr: <U>(defaultValue: U) => T | U;\n /** Exit the wrapper — hand back the canonical plain-data result. */\n toResult: () => Result<T, E>;\n /** Debug terminal — `Ok(…)` / `Err(…)`, same output as {@link show}. */\n toString: () => string;\n};\n\n/**\n * Wrap a {@link Result} for opt-in dot chaining — app-edge sugar. Keep the\n * data-first helpers ({@link map}, {@link flatMap}) in library internals.\n *\n * Mirrors every core transform; `test/parity.spec.ts` enforces the mirror.\n *\n * @example\n * ```ts\n * fluent(ok(2)).map((n) => n * 3).unwrapOr(0); // 6\n * ```\n */\nexport const fluent = <T, E>(result: Result<T, E>): FluentResult<T, E> => ({\n result,\n map: (fn) => fluent(map(result, fn)),\n mapErr: (fn) => fluent(mapErr(result, fn)),\n bimap: (onOk, onErr) => fluent(bimap(result, onOk, onErr)),\n flatMap: (fn) => fluent(flatMap(result, fn)),\n andThen: (fn) => fluent(flatMap(result, fn)),\n recover: (fn) => fluent(recover(result, fn)),\n tap: (fn) => fluent(tap(result, fn)),\n tapErr: (fn) => fluent(tapErr(result, fn)),\n\n match: (onOk, onErr) => match(result, onOk, onErr),\n unwrapOr: (defaultValue) => unwrapOr(result, defaultValue),\n toResult: () => result,\n toString: () => show(result),\n});\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/internal/ctor.ts
|
|
4
|
+
var mkOk = (value) => ({
|
|
5
|
+
_tag: "Ok",
|
|
6
|
+
value
|
|
7
|
+
});
|
|
8
|
+
var mkErr = (error) => ({
|
|
9
|
+
_tag: "Err",
|
|
10
|
+
error
|
|
11
|
+
});
|
|
12
|
+
|
|
3
13
|
// src/internal/dual.ts
|
|
4
14
|
var dual = (arity, body) => {
|
|
5
15
|
const run = body;
|
|
@@ -7,37 +17,38 @@ var dual = (arity, body) => {
|
|
|
7
17
|
return dispatcher;
|
|
8
18
|
};
|
|
9
19
|
|
|
20
|
+
// src/internal/to-error.ts
|
|
21
|
+
var toError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
22
|
+
|
|
10
23
|
// src/result.ts
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
});
|
|
24
|
+
function ok(value) {
|
|
25
|
+
return mkOk(value);
|
|
26
|
+
}
|
|
15
27
|
var of = ok;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
});
|
|
28
|
+
function err(error) {
|
|
29
|
+
return mkErr(error);
|
|
30
|
+
}
|
|
20
31
|
var isOk = (result) => result._tag === "Ok";
|
|
21
32
|
var isErr = (result) => result._tag === "Err";
|
|
22
33
|
var map = dual(
|
|
23
34
|
2,
|
|
24
|
-
(result, fn) => isOk(result) ?
|
|
35
|
+
(result, fn) => isOk(result) ? mkOk(fn(result.value)) : mkErr(result.error)
|
|
25
36
|
);
|
|
26
37
|
var mapErr = dual(
|
|
27
38
|
2,
|
|
28
|
-
(result, fn) => isErr(result) ?
|
|
39
|
+
(result, fn) => isErr(result) ? mkErr(fn(result.error)) : mkOk(result.value)
|
|
29
40
|
);
|
|
30
41
|
var bimap = dual(
|
|
31
42
|
3,
|
|
32
|
-
(result, onOk, onErr) => isOk(result) ?
|
|
43
|
+
(result, onOk, onErr) => isOk(result) ? mkOk(onOk(result.value)) : mkErr(onErr(result.error))
|
|
33
44
|
);
|
|
34
45
|
var flatMap = dual(
|
|
35
46
|
2,
|
|
36
|
-
(result, fn) => isOk(result) ? fn(result.value) :
|
|
47
|
+
(result, fn) => isOk(result) ? fn(result.value) : mkErr(result.error)
|
|
37
48
|
);
|
|
38
49
|
var recover = dual(
|
|
39
50
|
2,
|
|
40
|
-
(result, fn) => isErr(result) ? fn(result.error) :
|
|
51
|
+
(result, fn) => isErr(result) ? fn(result.error) : mkOk(result.value)
|
|
41
52
|
);
|
|
42
53
|
var tap = dual(2, (result, fn) => {
|
|
43
54
|
if (isOk(result)) fn(result.value);
|
|
@@ -64,21 +75,21 @@ function unwrapErr(result) {
|
|
|
64
75
|
if (isOk(result)) throw new TypeError("unwrapErr called on Ok");
|
|
65
76
|
return result.error;
|
|
66
77
|
}
|
|
67
|
-
function
|
|
78
|
+
function fromThrowable(fn, onThrow) {
|
|
68
79
|
return (...args) => {
|
|
69
80
|
try {
|
|
70
|
-
return
|
|
81
|
+
return mkOk(fn(...args));
|
|
71
82
|
} catch (error) {
|
|
72
|
-
return
|
|
83
|
+
return mkErr(onThrow(error));
|
|
73
84
|
}
|
|
74
85
|
};
|
|
75
86
|
}
|
|
76
|
-
function
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
function trySync(fn, onThrow) {
|
|
88
|
+
try {
|
|
89
|
+
return mkOk(fn());
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return mkErr(onThrow ? onThrow(error) : toError(error));
|
|
80
92
|
}
|
|
81
|
-
return acc;
|
|
82
93
|
}
|
|
83
94
|
var printPayload = (payload) => {
|
|
84
95
|
try {
|
|
@@ -104,11 +115,11 @@ var sequenceSettled = (settled) => {
|
|
|
104
115
|
const values = [];
|
|
105
116
|
for (const result of settled) {
|
|
106
117
|
if (isErr(result)) {
|
|
107
|
-
return
|
|
118
|
+
return mkErr(result.error);
|
|
108
119
|
}
|
|
109
120
|
values.push(result.value);
|
|
110
121
|
}
|
|
111
|
-
return
|
|
122
|
+
return mkOk(values);
|
|
112
123
|
};
|
|
113
124
|
var ResultAsync = class _ResultAsync {
|
|
114
125
|
constructor(run) {
|
|
@@ -145,9 +156,9 @@ var ResultAsync = class _ResultAsync {
|
|
|
145
156
|
static fromPromise(promise, onReject) {
|
|
146
157
|
return new _ResultAsync(async () => {
|
|
147
158
|
try {
|
|
148
|
-
return
|
|
159
|
+
return mkOk(await promise);
|
|
149
160
|
} catch (error) {
|
|
150
|
-
return
|
|
161
|
+
return mkErr(onReject(error));
|
|
151
162
|
}
|
|
152
163
|
});
|
|
153
164
|
}
|
|
@@ -161,7 +172,7 @@ var ResultAsync = class _ResultAsync {
|
|
|
161
172
|
* ```
|
|
162
173
|
*/
|
|
163
174
|
static fromSafePromise(promise) {
|
|
164
|
-
return new _ResultAsync(async () =>
|
|
175
|
+
return new _ResultAsync(async () => mkOk(await promise));
|
|
165
176
|
}
|
|
166
177
|
/**
|
|
167
178
|
* Defers work until {@link resolve}. Unlike {@link fromPromise}, the factory
|
|
@@ -179,21 +190,13 @@ var ResultAsync = class _ResultAsync {
|
|
|
179
190
|
return new _ResultAsync(fn);
|
|
180
191
|
}
|
|
181
192
|
static ok(value) {
|
|
182
|
-
return new _ResultAsync(async () =>
|
|
193
|
+
return new _ResultAsync(async () => mkOk(value));
|
|
183
194
|
}
|
|
184
195
|
static of(value) {
|
|
185
196
|
return _ResultAsync.ok(value);
|
|
186
197
|
}
|
|
187
|
-
/**
|
|
188
|
-
* Lifts an error into an `Err` async result.
|
|
189
|
-
*
|
|
190
|
-
* @example
|
|
191
|
-
* ```ts
|
|
192
|
-
* const r = ResultAsync.err({ kind: "not_found" as const });
|
|
193
|
-
* ```
|
|
194
|
-
*/
|
|
195
198
|
static err(error) {
|
|
196
|
-
return new _ResultAsync(async () =>
|
|
199
|
+
return new _ResultAsync(async () => mkErr(error));
|
|
197
200
|
}
|
|
198
201
|
/**
|
|
199
202
|
* Lifts an existing `Promise<Result<T, E>>` (e.g. from interop code) into a
|
|
@@ -211,7 +214,7 @@ var ResultAsync = class _ResultAsync {
|
|
|
211
214
|
try {
|
|
212
215
|
return await promise;
|
|
213
216
|
} catch (error) {
|
|
214
|
-
return
|
|
217
|
+
return mkErr(mapDefect(error));
|
|
215
218
|
}
|
|
216
219
|
});
|
|
217
220
|
}
|
|
@@ -233,11 +236,11 @@ var ResultAsync = class _ResultAsync {
|
|
|
233
236
|
for (const ra of results) {
|
|
234
237
|
const result = await ra.resolve();
|
|
235
238
|
if (isErr(result)) {
|
|
236
|
-
return
|
|
239
|
+
return mkErr(result.error);
|
|
237
240
|
}
|
|
238
241
|
values.push(result.value);
|
|
239
242
|
}
|
|
240
|
-
return
|
|
243
|
+
return mkOk(values);
|
|
241
244
|
});
|
|
242
245
|
}
|
|
243
246
|
/**
|
|
@@ -249,7 +252,7 @@ var ResultAsync = class _ResultAsync {
|
|
|
249
252
|
*
|
|
250
253
|
* @example
|
|
251
254
|
* ```ts
|
|
252
|
-
* const combined = ResultAsync.combineTuple([loadCfg(), loadCatalog()]
|
|
255
|
+
* const combined = ResultAsync.combineTuple([loadCfg(), loadCatalog()]);
|
|
253
256
|
* // ResultAsync<readonly [Cfg, Catalog], CfgError | CatalogError>
|
|
254
257
|
* const r = await combined;
|
|
255
258
|
* if (isOk(r)) {
|
|
@@ -257,7 +260,7 @@ var ResultAsync = class _ResultAsync {
|
|
|
257
260
|
* }
|
|
258
261
|
* ```
|
|
259
262
|
*/
|
|
260
|
-
static combineTuple(results) {
|
|
263
|
+
static combineTuple(results, ..._guard) {
|
|
261
264
|
return _ResultAsync.combine(
|
|
262
265
|
results
|
|
263
266
|
);
|
|
@@ -272,12 +275,14 @@ var ResultAsync = class _ResultAsync {
|
|
|
272
275
|
* const combined = ResultAsync.combineTupleParallel([
|
|
273
276
|
* loadProfile(id),
|
|
274
277
|
* loadMetrics(id),
|
|
275
|
-
* ]
|
|
278
|
+
* ]);
|
|
276
279
|
* ```
|
|
277
280
|
*/
|
|
278
|
-
static combineTupleParallel(results) {
|
|
281
|
+
static combineTupleParallel(results, ..._guard) {
|
|
279
282
|
return new _ResultAsync(
|
|
280
|
-
async () => sequenceSettled(
|
|
283
|
+
async () => sequenceSettled(
|
|
284
|
+
await Promise.all(results.map((ra) => ra.resolve()))
|
|
285
|
+
)
|
|
281
286
|
);
|
|
282
287
|
}
|
|
283
288
|
/**
|
|
@@ -303,6 +308,18 @@ var ResultAsync = class _ResultAsync {
|
|
|
303
308
|
mapErr(fn) {
|
|
304
309
|
return new _ResultAsync(async () => mapErr(await this.resolve(), fn));
|
|
305
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* Transforms both tracks in one step — the async mirror of the sync
|
|
313
|
+
* `bimap`. Exactly one of `onOk` / `onErr` runs.
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```ts
|
|
317
|
+
* load(id).bimap(toDto, (e): AppError => ({ kind: "load", cause: e }));
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
bimap(onOk, onErr) {
|
|
321
|
+
return new _ResultAsync(async () => bimap(await this.resolve(), onOk, onErr));
|
|
322
|
+
}
|
|
306
323
|
/**
|
|
307
324
|
* Canonical bind — chains a step that itself returns a `ResultAsync` or sync
|
|
308
325
|
* `Result`, short-circuiting on `Err`. Error types accumulate (`E | F`).
|
|
@@ -478,7 +495,6 @@ var asyncAfter = dual(
|
|
|
478
495
|
(result, fn) => fromResult(result).flatMap(fn)
|
|
479
496
|
);
|
|
480
497
|
var fromAsync = (fn, onDefect) => (...args) => ResultAsync.fromResultPromise(fn(...args), onDefect);
|
|
481
|
-
var toError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
482
498
|
function tryAsync(promise, onReject) {
|
|
483
499
|
return onReject ? ResultAsync.fromPromise(promise, onReject) : ResultAsync.fromPromise(promise, toError);
|
|
484
500
|
}
|
|
@@ -487,12 +503,12 @@ function tryAsync(promise, onReject) {
|
|
|
487
503
|
var combine = (results) => {
|
|
488
504
|
const values = [];
|
|
489
505
|
for (const result of results) {
|
|
490
|
-
if (isErr(result)) return
|
|
506
|
+
if (isErr(result)) return mkErr(result.error);
|
|
491
507
|
values.push(result.value);
|
|
492
508
|
}
|
|
493
|
-
return
|
|
509
|
+
return mkOk(values);
|
|
494
510
|
};
|
|
495
|
-
var combineTuple = (results) => (
|
|
511
|
+
var combineTuple = (results, ..._guard) => (
|
|
496
512
|
// Runtime identical to combine; the cast restores per-index tuple types.
|
|
497
513
|
combine(results)
|
|
498
514
|
);
|
|
@@ -506,14 +522,22 @@ function validateAll(results, combineErrors) {
|
|
|
506
522
|
values.push(result.value);
|
|
507
523
|
}
|
|
508
524
|
}
|
|
509
|
-
if (errors.length === 0) return
|
|
510
|
-
return
|
|
525
|
+
if (errors.length === 0) return mkOk(values);
|
|
526
|
+
return mkErr(combineErrors ? errors.reduce(combineErrors) : errors);
|
|
511
527
|
}
|
|
512
|
-
function validateTuple(results,
|
|
528
|
+
function validateTuple(results, ...rest) {
|
|
529
|
+
const combineErrors = rest[0];
|
|
513
530
|
return combineErrors ? validateAll(results, combineErrors) : validateAll(results);
|
|
514
531
|
}
|
|
515
532
|
|
|
516
533
|
// src/pipe.ts
|
|
534
|
+
function pipe(value, ...fns) {
|
|
535
|
+
let acc = value;
|
|
536
|
+
for (const fn of fns) {
|
|
537
|
+
acc = fn(acc);
|
|
538
|
+
}
|
|
539
|
+
return acc;
|
|
540
|
+
}
|
|
517
541
|
function flow(first, ...rest) {
|
|
518
542
|
return (...args) => {
|
|
519
543
|
let acc = first(...args);
|
|
@@ -544,7 +568,7 @@ var tryGen = (fn) => {
|
|
|
544
568
|
return fn();
|
|
545
569
|
} catch (error) {
|
|
546
570
|
if (error instanceof ErrSignal) {
|
|
547
|
-
return
|
|
571
|
+
return mkErr(error.error);
|
|
548
572
|
}
|
|
549
573
|
throw error;
|
|
550
574
|
}
|
|
@@ -565,6 +589,7 @@ exports.fromAsync = fromAsync;
|
|
|
565
589
|
exports.fromPromise = fromPromise;
|
|
566
590
|
exports.fromResult = fromResult;
|
|
567
591
|
exports.fromSafePromise = fromSafePromise;
|
|
592
|
+
exports.fromThrowable = fromThrowable;
|
|
568
593
|
exports.isErr = isErr;
|
|
569
594
|
exports.isOk = isOk;
|
|
570
595
|
exports.map = map;
|