@onrails/result 0.3.0 → 0.3.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 +1 -0
- package/dist/{async-SZ7BEl0g.d.ts → async-Ci6WSL5-.d.ts} +6 -0
- package/dist/{async-BR3AX0ck.d.cts → async-DcXR7k9K.d.cts} +6 -0
- package/dist/compat/neverthrow.cjs +3 -0
- package/dist/compat/neverthrow.cjs.map +1 -1
- package/dist/compat/neverthrow.d.cts +1 -1
- package/dist/compat/neverthrow.d.ts +1 -1
- package/dist/compat/neverthrow.js +3 -0
- package/dist/compat/neverthrow.js.map +1 -1
- package/dist/extra.cjs.map +1 -1
- package/dist/extra.d.cts +1 -1
- package/dist/extra.d.ts +1 -1
- package/dist/extra.js.map +1 -1
- package/dist/fluent.cjs +11 -1
- package/dist/fluent.cjs.map +1 -1
- package/dist/fluent.d.cts +5 -1
- package/dist/fluent.d.ts +5 -1
- package/dist/fluent.js +11 -1
- package/dist/fluent.js.map +1 -1
- package/dist/index.cjs +14 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -2
- package/dist/index.d.ts +24 -2
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/railway.cjs +3 -0
- package/dist/railway.cjs.map +1 -1
- package/dist/railway.d.cts +1 -1
- package/dist/railway.d.ts +1 -1
- package/dist/railway.js +3 -0
- package/dist/railway.js.map +1 -1
- package/dist/try-gen.cjs.map +1 -1
- package/dist/try-gen.js.map +1 -1
- package/package.json +1 -1
package/dist/fluent.cjs.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.cjs","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 * 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","import type { ResultAsync } from \"./async.js\";\nimport { bimap, flatMap, map, mapErr, match, recover, tap, tapErr, unwrapOr } 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};\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});\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/dual.ts","../src/result.ts","../src/fluent.ts"],"names":[],"mappings":"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","file":"fluent.cjs","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"]}
|
package/dist/fluent.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as ResultAsync } from './async-
|
|
1
|
+
import { R as ResultAsync } from './async-DcXR7k9K.cjs';
|
|
2
2
|
import { R as Result } from './types-BQ9vv0nD.cjs';
|
|
3
3
|
|
|
4
4
|
/** Opt-in dot chaining over a sync {@link Result} */
|
|
@@ -14,6 +14,10 @@ type FluentResult<T, E> = {
|
|
|
14
14
|
tapErr: (fn: (error: E) => void) => FluentResult<T, E>;
|
|
15
15
|
match: <U>(onOk: (value: T) => U, onErr: (error: E) => U) => U;
|
|
16
16
|
unwrapOr: (defaultValue: T) => T;
|
|
17
|
+
/** Exit the wrapper — hand back the canonical plain-data result. */
|
|
18
|
+
toResult: () => Result<T, E>;
|
|
19
|
+
/** Debug terminal — `Ok(…)` / `Err(…)`, same output as {@link show}. */
|
|
20
|
+
toString: () => string;
|
|
17
21
|
};
|
|
18
22
|
/**
|
|
19
23
|
* Wrap a {@link Result} for opt-in dot chaining — app-edge sugar. Keep the
|
package/dist/fluent.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as ResultAsync } from './async-
|
|
1
|
+
import { R as ResultAsync } from './async-Ci6WSL5-.js';
|
|
2
2
|
import { R as Result } from './types-BQ9vv0nD.js';
|
|
3
3
|
|
|
4
4
|
/** Opt-in dot chaining over a sync {@link Result} */
|
|
@@ -14,6 +14,10 @@ type FluentResult<T, E> = {
|
|
|
14
14
|
tapErr: (fn: (error: E) => void) => FluentResult<T, E>;
|
|
15
15
|
match: <U>(onOk: (value: T) => U, onErr: (error: E) => U) => U;
|
|
16
16
|
unwrapOr: (defaultValue: T) => T;
|
|
17
|
+
/** Exit the wrapper — hand back the canonical plain-data result. */
|
|
18
|
+
toResult: () => Result<T, E>;
|
|
19
|
+
/** Debug terminal — `Ok(…)` / `Err(…)`, same output as {@link show}. */
|
|
20
|
+
toString: () => string;
|
|
17
21
|
};
|
|
18
22
|
/**
|
|
19
23
|
* Wrap a {@link Result} for opt-in dot chaining — app-edge sugar. Keep the
|
package/dist/fluent.js
CHANGED
|
@@ -52,6 +52,14 @@ var unwrapOr = dual(
|
|
|
52
52
|
2,
|
|
53
53
|
(result, defaultValue) => isOk(result) ? result.value : defaultValue
|
|
54
54
|
);
|
|
55
|
+
var printPayload = (payload) => {
|
|
56
|
+
try {
|
|
57
|
+
return JSON.stringify(payload) ?? String(payload);
|
|
58
|
+
} catch {
|
|
59
|
+
return String(payload);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var show = (result) => isOk(result) ? `Ok(${printPayload(result.value)})` : `Err(${printPayload(result.error)})`;
|
|
55
63
|
|
|
56
64
|
// src/fluent.ts
|
|
57
65
|
var fluent = (result) => ({
|
|
@@ -65,7 +73,9 @@ var fluent = (result) => ({
|
|
|
65
73
|
tap: (fn) => fluent(tap(result, fn)),
|
|
66
74
|
tapErr: (fn) => fluent(tapErr(result, fn)),
|
|
67
75
|
match: (onOk, onErr) => match(result, onOk, onErr),
|
|
68
|
-
unwrapOr: (defaultValue) => unwrapOr(result, defaultValue)
|
|
76
|
+
unwrapOr: (defaultValue) => unwrapOr(result, defaultValue),
|
|
77
|
+
toResult: () => result,
|
|
78
|
+
toString: () => show(result)
|
|
69
79
|
});
|
|
70
80
|
var fluentAsync = (resultAsync) => ({
|
|
71
81
|
resultAsync,
|
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 * 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","import type { ResultAsync } from \"./async.js\";\nimport { bimap, flatMap, map, mapErr, match, recover, tap, tapErr, unwrapOr } 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};\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});\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/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"]}
|
package/dist/index.cjs
CHANGED
|
@@ -12,6 +12,7 @@ var ok = (value) => ({
|
|
|
12
12
|
_tag: "Ok",
|
|
13
13
|
value
|
|
14
14
|
});
|
|
15
|
+
var of = ok;
|
|
15
16
|
var err = (error) => ({
|
|
16
17
|
_tag: "Err",
|
|
17
18
|
error
|
|
@@ -79,6 +80,14 @@ function pipe(value, ...fns) {
|
|
|
79
80
|
}
|
|
80
81
|
return acc;
|
|
81
82
|
}
|
|
83
|
+
var printPayload = (payload) => {
|
|
84
|
+
try {
|
|
85
|
+
return JSON.stringify(payload) ?? String(payload);
|
|
86
|
+
} catch {
|
|
87
|
+
return String(payload);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var show = (result) => isOk(result) ? `Ok(${printPayload(result.value)})` : `Err(${printPayload(result.error)})`;
|
|
82
91
|
|
|
83
92
|
// src/types.ts
|
|
84
93
|
var UnexpectedError = class extends Error {
|
|
@@ -172,6 +181,9 @@ var ResultAsync = class _ResultAsync {
|
|
|
172
181
|
static ok(value) {
|
|
173
182
|
return new _ResultAsync(async () => ok(value));
|
|
174
183
|
}
|
|
184
|
+
static of(value) {
|
|
185
|
+
return _ResultAsync.ok(value);
|
|
186
|
+
}
|
|
175
187
|
/**
|
|
176
188
|
* Lifts an error into an `Err` async result.
|
|
177
189
|
*
|
|
@@ -558,10 +570,12 @@ exports.isOk = isOk;
|
|
|
558
570
|
exports.map = map;
|
|
559
571
|
exports.mapErr = mapErr;
|
|
560
572
|
exports.match = match;
|
|
573
|
+
exports.of = of;
|
|
561
574
|
exports.ok = ok;
|
|
562
575
|
exports.okAsync = okAsync;
|
|
563
576
|
exports.pipe = pipe;
|
|
564
577
|
exports.recover = recover;
|
|
578
|
+
exports.show = show;
|
|
565
579
|
exports.tap = tap;
|
|
566
580
|
exports.tapErr = tapErr;
|
|
567
581
|
exports.tryAsync = tryAsync;
|