@onrails/result 0.2.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.
Files changed (60) hide show
  1. package/DESIGN.md +11 -18
  2. package/README.md +14 -59
  3. package/RECIPES.md +12 -25
  4. package/dist/{async-1fIhfzFu.d.ts → async-Ci6WSL5-.d.ts} +60 -18
  5. package/dist/{async-u8U5P2EH.d.cts → async-DcXR7k9K.d.cts} +60 -18
  6. package/dist/compat/neverthrow.cjs +42 -51
  7. package/dist/compat/neverthrow.cjs.map +1 -1
  8. package/dist/compat/neverthrow.d.cts +3 -3
  9. package/dist/compat/neverthrow.d.ts +3 -3
  10. package/dist/compat/neverthrow.js +42 -51
  11. package/dist/compat/neverthrow.js.map +1 -1
  12. package/dist/extra.cjs +1 -1
  13. package/dist/extra.cjs.map +1 -1
  14. package/dist/extra.d.cts +5 -11
  15. package/dist/extra.d.ts +5 -11
  16. package/dist/extra.js +1 -1
  17. package/dist/extra.js.map +1 -1
  18. package/dist/fluent.cjs +66 -28
  19. package/dist/fluent.cjs.map +1 -1
  20. package/dist/fluent.d.cts +41 -6
  21. package/dist/fluent.d.ts +41 -6
  22. package/dist/fluent.js +66 -28
  23. package/dist/fluent.js.map +1 -1
  24. package/dist/index.cjs +95 -95
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +168 -44
  27. package/dist/index.d.ts +168 -44
  28. package/dist/index.js +90 -95
  29. package/dist/index.js.map +1 -1
  30. package/dist/railway.cjs +101 -172
  31. package/dist/railway.cjs.map +1 -1
  32. package/dist/railway.d.cts +25 -179
  33. package/dist/railway.d.ts +25 -179
  34. package/dist/railway.js +102 -162
  35. package/dist/railway.js.map +1 -1
  36. package/dist/try-gen.cjs +1 -1
  37. package/dist/try-gen.cjs.map +1 -1
  38. package/dist/try-gen.js +1 -1
  39. package/dist/try-gen.js.map +1 -1
  40. package/package.json +1 -16
  41. package/skills/railway-do-notation/SKILL.md +29 -68
  42. package/skills/result-composition/SKILL.md +2 -4
  43. package/dist/$.cjs +0 -40
  44. package/dist/$.cjs.map +0 -1
  45. package/dist/$.js +0 -36
  46. package/dist/$.js.map +0 -1
  47. package/dist/_.d.cts +0 -2
  48. package/dist/_.d.ts +0 -2
  49. package/dist/interop.cjs +0 -433
  50. package/dist/interop.cjs.map +0 -1
  51. package/dist/interop.d.cts +0 -75
  52. package/dist/interop.d.ts +0 -75
  53. package/dist/interop.js +0 -429
  54. package/dist/interop.js.map +0 -1
  55. package/dist/validation.cjs +0 -53
  56. package/dist/validation.cjs.map +0 -1
  57. package/dist/validation.d.cts +0 -72
  58. package/dist/validation.d.ts +0 -72
  59. package/dist/validation.js +0 -48
  60. package/dist/validation.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/result.ts","../src/validation.ts"],"names":[],"mappings":";;;AAaO,IAAM,EAAA,GAAK,CAAe,KAAA,MAA4B;AAAA,EAC3D,IAAA,EAAM,IAAA;AAAA,EACN;AACF,CAAA,CAAA;AAWO,IAAM,GAAA,GAAM,CAAyB,KAAA,MAA4B;AAAA,EACtE,IAAA,EAAM,KAAA;AAAA,EACN;AACF,CAAA,CAAA;AAwBO,IAAM,KAAA,GAAQ,CAAO,MAAA,KAA8C,MAAA,CAAO,IAAA,KAAS,KAAA;;;ACzBnF,IAAM,WAAA,GAAc,CACzB,OAAA,EACA,aAAA,KACmB;AACnB,EAAA,MAAM,SAAc,EAAC;AACrB,EAAA,IAAI,WAAA;AAEJ,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,KAAA,CAAM,MAAM,CAAA,EAAG;AACjB,MAAA,WAAA,GACE,gBAAgB,MAAA,GAAY,MAAA,CAAO,QAAQ,aAAA,CAAc,WAAA,EAAa,OAAO,KAAK,CAAA;AAAA,IACtF,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,IAC1B;AAAA,EACF;AAEA,EAAA,OAAO,gBAAgB,MAAA,GAAY,EAAA,CAAG,MAAM,CAAA,GAAI,IAAI,WAAW,CAAA;AACjE;AAeO,IAAM,aAAA,GAAgB,CAC3B,OAAA,EACA,aAAA;AAAA;AAAA,EAGA,WAAA,CAAY,SAAS,aAAa;AAAA;AAa7B,IAAM,gBAAA,GAAmB,CAC9B,OAAA,KAC8B;AAC9B,EAAA,MAAM,SAAc,EAAC;AACrB,EAAA,MAAM,SAAc,EAAC;AAErB,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,KAAA,CAAM,MAAM,CAAA,EAAG;AACjB,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,IAC1B,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,IAC1B;AAAA,EACF;AAEA,EAAA,OAAO,OAAO,MAAA,KAAW,CAAA,GAAI,GAAG,MAAM,CAAA,GAAI,IAAI,MAAM,CAAA;AACtD;AAaO,IAAM,qBAAqB,CAChC,OAAA;AAAA;AAAA,EAGA,iBAAiB,OAAqD;AAAA","file":"validation.cjs","sourcesContent":["import 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 at the call site selects the overload.\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <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 * 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 function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;\nexport function map<T, U>(fn: (value: T) => U): <E>(result: Result<T, E>) => Result<U, E>;\nexport function map(\n ...args: [Result<unknown, unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => mapImpl(result, fn);\n}\n\nconst mapErrImpl = <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 * 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 function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F>;\nexport function mapErr<E, F>(fn: (error: E) => F): <T>(result: Result<T, E>) => Result<T, F>;\nexport function mapErr(\n ...args: [Result<unknown, unknown>, (error: unknown) => unknown] | [(error: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapErrImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => mapErrImpl(result, fn);\n}\n\nconst bimapImpl = <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 * 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 function bimap<T, U, E, F>(\n result: Result<T, E>,\n onOk: (value: T) => U,\n onErr: (error: E) => F,\n): Result<U, F>;\nexport function bimap<T, U, E, F>(\n onOk: (value: T) => U,\n onErr: (error: E) => F,\n): (result: Result<T, E>) => Result<U, F>;\nexport function bimap(\n ...args:\n | [Result<unknown, unknown>, (value: unknown) => unknown, (error: unknown) => unknown]\n | [(value: unknown) => unknown, (error: unknown) => unknown]\n): unknown {\n if (args.length === 3) return bimapImpl(args[0], args[1], args[2]);\n const [onOk, onErr] = args;\n return (result: Result<unknown, unknown>) => bimapImpl(result, onOk, onErr);\n}\n\nconst flatMapImpl = <T, U, E, F>(\n result: Result<T, E>,\n fn: (value: T) => Result<U, F>,\n): Result<U, E | F> => (isOk(result) ? fn(result.value) : err(result.error));\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 function flatMap<T, U, E, F>(\n result: Result<T, E>,\n fn: (value: T) => Result<U, F>,\n): Result<U, E | F>;\nexport function flatMap<T, U, F>(\n fn: (value: T) => Result<U, F>,\n): <E>(result: Result<T, E>) => Result<U, E | F>;\nexport function flatMap(\n ...args:\n | [Result<unknown, unknown>, (value: unknown) => Result<unknown, unknown>]\n | [(value: unknown) => Result<unknown, unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => flatMapImpl(result, fn);\n}\n\nconst recoverImpl = <T, E, F>(\n result: Result<T, E>,\n fn: (error: E) => Result<T, F>,\n): Result<T, F> => (isErr(result) ? fn(result.error) : ok(result.value));\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 function recover<T, E, F>(\n result: Result<T, E>,\n fn: (error: E) => Result<T, F>,\n): Result<T, F>;\nexport function recover<T, E, F>(\n fn: (error: E) => Result<T, F>,\n): (result: Result<T, E>) => Result<T, F>;\nexport function recover(\n ...args:\n | [Result<unknown, unknown>, (error: unknown) => Result<unknown, unknown>]\n | [(error: unknown) => Result<unknown, unknown>]\n): unknown {\n if (args.length === 2) return recoverImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => recoverImpl(result, fn);\n}\n\nconst tapImpl = <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 `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 function tap<T, E>(result: Result<T, E>, fn: (value: T) => void): Result<T, E>;\nexport function tap<T>(fn: (value: T) => void): <E>(result: Result<T, E>) => Result<T, E>;\nexport function tap(\n ...args: [Result<unknown, unknown>, (value: unknown) => void] | [(value: unknown) => void]\n): unknown {\n if (args.length === 2) return tapImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => tapImpl(result, fn);\n}\n\nconst tapErrImpl = <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 * 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 function tapErr<T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E>;\nexport function tapErr<E>(fn: (error: E) => void): <T>(result: Result<T, E>) => Result<T, E>;\nexport function tapErr(\n ...args: [Result<unknown, unknown>, (error: unknown) => void] | [(error: unknown) => void]\n): unknown {\n if (args.length === 2) return tapErrImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => tapErrImpl(result, fn);\n}\n\nconst matchImpl = <T, E, U>(\n result: Result<T, E>,\n onOk: (value: T) => U,\n onErr: (error: E) => U,\n): U => (isOk(result) ? onOk(result.value) : onErr(result.error));\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 function match<T, E, U>(\n result: Result<T, E>,\n onOk: (value: T) => U,\n onErr: (error: E) => U,\n): U;\nexport function match<T, E, U>(\n onOk: (value: T) => U,\n onErr: (error: E) => U,\n): (result: Result<T, E>) => U;\nexport function match(\n ...args:\n | [Result<unknown, unknown>, (value: unknown) => unknown, (error: unknown) => unknown]\n | [(value: unknown) => unknown, (error: unknown) => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onOk, onErr] = args;\n return (result: Result<unknown, unknown>) => matchImpl(result, onOk, onErr);\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 = <T, E>(result: Result<T, E>, defaultValue: T): T =>\n isOk(result) ? result.value : defaultValue;\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/**\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 { err, isErr, ok } from \"./result.js\";\nimport type { Result } from \"./types.js\";\n\ntype OkValue<R> = R extends { readonly _tag: \"Ok\"; readonly value: infer T } ? T : never;\ntype ErrValue<R> = R extends { readonly _tag: \"Err\"; readonly error: infer E } ? E : never;\n\ntype ValidateTuple<R extends readonly Result<unknown, unknown>[], E> = Result<\n { [K in keyof R]: OkValue<R[K]> },\n E\n>;\ntype TupleErrors<R extends readonly Result<unknown, unknown>[]> = ErrValue<R[number]>;\n\n/**\n * Accumulate independent validation failures into a single combined error\n * via `combineErrors`. Returns `Ok<T[]>` only when every input is `Ok`;\n * otherwise returns `Err<E>` where `E` is the fold of all failures.\n *\n * Unlike `combine`, this does **not** short-circuit on first failure — use\n * for independent checks where you want to report all problems at once.\n *\n * @example\n * ```ts\n * validateAll(\n * [validateName(input), validateAge(input), validateEmail(input)],\n * (left, right) => [...left, ...right],\n * );\n * // Result<string[], FieldError[]>\n * ```\n */\nexport const validateAll = <T, E>(\n results: readonly Result<T, E>[],\n combineErrors: (left: E, right: E) => E,\n): Result<T[], E> => {\n const values: T[] = [];\n let accumulated: E | undefined;\n\n for (const result of results) {\n if (isErr(result)) {\n accumulated =\n accumulated === undefined ? result.error : combineErrors(accumulated, result.error);\n } else {\n values.push(result.value);\n }\n }\n\n return accumulated === undefined ? ok(values) : err(accumulated);\n};\n\n/**\n * Tuple-preserving variant of {@link validateAll}. All inputs must share\n * the same error type `E`. Output Ok preserves tuple positions.\n *\n * @example\n * ```ts\n * validateTuple(\n * [validateName(s), validateAge(s)] as const,\n * (l, r) => [...l, ...r],\n * );\n * // Result<readonly [string, number], FieldError[]>\n * ```\n */\nexport const validateTuple = <E, const R extends readonly Result<unknown, E>[]>(\n results: R,\n combineErrors: (left: E, right: E) => E,\n): ValidateTuple<R, E> =>\n // Runtime identical to validateAll; the cast restores per-index tuple types.\n validateAll(results, combineErrors) as ValidateTuple<R, E>;\n\n/**\n * Like {@link validateAll}, but collects every failure into a readonly\n * array instead of folding via a combine function. The default choice\n * when you want \"all errors\" without an explicit join.\n *\n * @example\n * ```ts\n * validateAllArray([validateName(input), validateAge(input)]);\n * // Result<readonly Field[], readonly FieldError[]>\n * ```\n */\nexport const validateAllArray = <T, E>(\n results: readonly Result<T, E>[],\n): Result<T[], readonly E[]> => {\n const values: T[] = [];\n const errors: E[] = [];\n\n for (const result of results) {\n if (isErr(result)) {\n errors.push(result.error);\n } else {\n values.push(result.value);\n }\n }\n\n return errors.length === 0 ? ok(values) : err(errors);\n};\n\n/**\n * Tuple-preserving variant of {@link validateAllArray}. Heterogeneous\n * input tuple → preserved Ok tuple shape with a union of all input\n * error types collected into a readonly array.\n *\n * @example\n * ```ts\n * validateTupleArray([validateName(s), validateAge(s)] as const);\n * // Result<readonly [string, number], readonly FieldError[]>\n * ```\n */\nexport const validateTupleArray = <const R extends readonly Result<unknown, unknown>[]>(\n results: R,\n): ValidateTuple<R, readonly TupleErrors<R>[]> =>\n // Runtime identical to validateAllArray; the cast restores per-index tuple types.\n validateAllArray(results as readonly Result<unknown, TupleErrors<R>>[]) as ValidateTuple<\n R,\n readonly TupleErrors<R>[]\n >;\n"]}
@@ -1,72 +0,0 @@
1
- import { R as Result } from './types-BQ9vv0nD.cjs';
2
-
3
- type OkValue<R> = R extends {
4
- readonly _tag: "Ok";
5
- readonly value: infer T;
6
- } ? T : never;
7
- type ErrValue<R> = R extends {
8
- readonly _tag: "Err";
9
- readonly error: infer E;
10
- } ? E : never;
11
- type ValidateTuple<R extends readonly Result<unknown, unknown>[], E> = Result<{
12
- [K in keyof R]: OkValue<R[K]>;
13
- }, E>;
14
- type TupleErrors<R extends readonly Result<unknown, unknown>[]> = ErrValue<R[number]>;
15
- /**
16
- * Accumulate independent validation failures into a single combined error
17
- * via `combineErrors`. Returns `Ok<T[]>` only when every input is `Ok`;
18
- * otherwise returns `Err<E>` where `E` is the fold of all failures.
19
- *
20
- * Unlike `combine`, this does **not** short-circuit on first failure — use
21
- * for independent checks where you want to report all problems at once.
22
- *
23
- * @example
24
- * ```ts
25
- * validateAll(
26
- * [validateName(input), validateAge(input), validateEmail(input)],
27
- * (left, right) => [...left, ...right],
28
- * );
29
- * // Result<string[], FieldError[]>
30
- * ```
31
- */
32
- declare const validateAll: <T, E>(results: readonly Result<T, E>[], combineErrors: (left: E, right: E) => E) => Result<T[], E>;
33
- /**
34
- * Tuple-preserving variant of {@link validateAll}. All inputs must share
35
- * the same error type `E`. Output Ok preserves tuple positions.
36
- *
37
- * @example
38
- * ```ts
39
- * validateTuple(
40
- * [validateName(s), validateAge(s)] as const,
41
- * (l, r) => [...l, ...r],
42
- * );
43
- * // Result<readonly [string, number], FieldError[]>
44
- * ```
45
- */
46
- declare const validateTuple: <E, const R extends readonly Result<unknown, E>[]>(results: R, combineErrors: (left: E, right: E) => E) => ValidateTuple<R, E>;
47
- /**
48
- * Like {@link validateAll}, but collects every failure into a readonly
49
- * array instead of folding via a combine function. The default choice
50
- * when you want "all errors" without an explicit join.
51
- *
52
- * @example
53
- * ```ts
54
- * validateAllArray([validateName(input), validateAge(input)]);
55
- * // Result<readonly Field[], readonly FieldError[]>
56
- * ```
57
- */
58
- declare const validateAllArray: <T, E>(results: readonly Result<T, E>[]) => Result<T[], readonly E[]>;
59
- /**
60
- * Tuple-preserving variant of {@link validateAllArray}. Heterogeneous
61
- * input tuple → preserved Ok tuple shape with a union of all input
62
- * error types collected into a readonly array.
63
- *
64
- * @example
65
- * ```ts
66
- * validateTupleArray([validateName(s), validateAge(s)] as const);
67
- * // Result<readonly [string, number], readonly FieldError[]>
68
- * ```
69
- */
70
- declare const validateTupleArray: <const R extends readonly Result<unknown, unknown>[]>(results: R) => ValidateTuple<R, readonly TupleErrors<R>[]>;
71
-
72
- export { validateAll, validateAllArray, validateTuple, validateTupleArray };
@@ -1,72 +0,0 @@
1
- import { R as Result } from './types-BQ9vv0nD.js';
2
-
3
- type OkValue<R> = R extends {
4
- readonly _tag: "Ok";
5
- readonly value: infer T;
6
- } ? T : never;
7
- type ErrValue<R> = R extends {
8
- readonly _tag: "Err";
9
- readonly error: infer E;
10
- } ? E : never;
11
- type ValidateTuple<R extends readonly Result<unknown, unknown>[], E> = Result<{
12
- [K in keyof R]: OkValue<R[K]>;
13
- }, E>;
14
- type TupleErrors<R extends readonly Result<unknown, unknown>[]> = ErrValue<R[number]>;
15
- /**
16
- * Accumulate independent validation failures into a single combined error
17
- * via `combineErrors`. Returns `Ok<T[]>` only when every input is `Ok`;
18
- * otherwise returns `Err<E>` where `E` is the fold of all failures.
19
- *
20
- * Unlike `combine`, this does **not** short-circuit on first failure — use
21
- * for independent checks where you want to report all problems at once.
22
- *
23
- * @example
24
- * ```ts
25
- * validateAll(
26
- * [validateName(input), validateAge(input), validateEmail(input)],
27
- * (left, right) => [...left, ...right],
28
- * );
29
- * // Result<string[], FieldError[]>
30
- * ```
31
- */
32
- declare const validateAll: <T, E>(results: readonly Result<T, E>[], combineErrors: (left: E, right: E) => E) => Result<T[], E>;
33
- /**
34
- * Tuple-preserving variant of {@link validateAll}. All inputs must share
35
- * the same error type `E`. Output Ok preserves tuple positions.
36
- *
37
- * @example
38
- * ```ts
39
- * validateTuple(
40
- * [validateName(s), validateAge(s)] as const,
41
- * (l, r) => [...l, ...r],
42
- * );
43
- * // Result<readonly [string, number], FieldError[]>
44
- * ```
45
- */
46
- declare const validateTuple: <E, const R extends readonly Result<unknown, E>[]>(results: R, combineErrors: (left: E, right: E) => E) => ValidateTuple<R, E>;
47
- /**
48
- * Like {@link validateAll}, but collects every failure into a readonly
49
- * array instead of folding via a combine function. The default choice
50
- * when you want "all errors" without an explicit join.
51
- *
52
- * @example
53
- * ```ts
54
- * validateAllArray([validateName(input), validateAge(input)]);
55
- * // Result<readonly Field[], readonly FieldError[]>
56
- * ```
57
- */
58
- declare const validateAllArray: <T, E>(results: readonly Result<T, E>[]) => Result<T[], readonly E[]>;
59
- /**
60
- * Tuple-preserving variant of {@link validateAllArray}. Heterogeneous
61
- * input tuple → preserved Ok tuple shape with a union of all input
62
- * error types collected into a readonly array.
63
- *
64
- * @example
65
- * ```ts
66
- * validateTupleArray([validateName(s), validateAge(s)] as const);
67
- * // Result<readonly [string, number], readonly FieldError[]>
68
- * ```
69
- */
70
- declare const validateTupleArray: <const R extends readonly Result<unknown, unknown>[]>(results: R) => ValidateTuple<R, readonly TupleErrors<R>[]>;
71
-
72
- export { validateAll, validateAllArray, validateTuple, validateTupleArray };
@@ -1,48 +0,0 @@
1
- // src/result.ts
2
- var ok = (value) => ({
3
- _tag: "Ok",
4
- value
5
- });
6
- var err = (error) => ({
7
- _tag: "Err",
8
- error
9
- });
10
- var isErr = (result) => result._tag === "Err";
11
-
12
- // src/validation.ts
13
- var validateAll = (results, combineErrors) => {
14
- const values = [];
15
- let accumulated;
16
- for (const result of results) {
17
- if (isErr(result)) {
18
- accumulated = accumulated === void 0 ? result.error : combineErrors(accumulated, result.error);
19
- } else {
20
- values.push(result.value);
21
- }
22
- }
23
- return accumulated === void 0 ? ok(values) : err(accumulated);
24
- };
25
- var validateTuple = (results, combineErrors) => (
26
- // Runtime identical to validateAll; the cast restores per-index tuple types.
27
- validateAll(results, combineErrors)
28
- );
29
- var validateAllArray = (results) => {
30
- const values = [];
31
- const errors = [];
32
- for (const result of results) {
33
- if (isErr(result)) {
34
- errors.push(result.error);
35
- } else {
36
- values.push(result.value);
37
- }
38
- }
39
- return errors.length === 0 ? ok(values) : err(errors);
40
- };
41
- var validateTupleArray = (results) => (
42
- // Runtime identical to validateAllArray; the cast restores per-index tuple types.
43
- validateAllArray(results)
44
- );
45
-
46
- export { validateAll, validateAllArray, validateTuple, validateTupleArray };
47
- //# sourceMappingURL=validation.js.map
48
- //# sourceMappingURL=validation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/result.ts","../src/validation.ts"],"names":[],"mappings":";AAaO,IAAM,EAAA,GAAK,CAAe,KAAA,MAA4B;AAAA,EAC3D,IAAA,EAAM,IAAA;AAAA,EACN;AACF,CAAA,CAAA;AAWO,IAAM,GAAA,GAAM,CAAyB,KAAA,MAA4B;AAAA,EACtE,IAAA,EAAM,KAAA;AAAA,EACN;AACF,CAAA,CAAA;AAwBO,IAAM,KAAA,GAAQ,CAAO,MAAA,KAA8C,MAAA,CAAO,IAAA,KAAS,KAAA;;;ACzBnF,IAAM,WAAA,GAAc,CACzB,OAAA,EACA,aAAA,KACmB;AACnB,EAAA,MAAM,SAAc,EAAC;AACrB,EAAA,IAAI,WAAA;AAEJ,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,KAAA,CAAM,MAAM,CAAA,EAAG;AACjB,MAAA,WAAA,GACE,gBAAgB,MAAA,GAAY,MAAA,CAAO,QAAQ,aAAA,CAAc,WAAA,EAAa,OAAO,KAAK,CAAA;AAAA,IACtF,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,IAC1B;AAAA,EACF;AAEA,EAAA,OAAO,gBAAgB,MAAA,GAAY,EAAA,CAAG,MAAM,CAAA,GAAI,IAAI,WAAW,CAAA;AACjE;AAeO,IAAM,aAAA,GAAgB,CAC3B,OAAA,EACA,aAAA;AAAA;AAAA,EAGA,WAAA,CAAY,SAAS,aAAa;AAAA;AAa7B,IAAM,gBAAA,GAAmB,CAC9B,OAAA,KAC8B;AAC9B,EAAA,MAAM,SAAc,EAAC;AACrB,EAAA,MAAM,SAAc,EAAC;AAErB,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,KAAA,CAAM,MAAM,CAAA,EAAG;AACjB,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,IAC1B,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,IAC1B;AAAA,EACF;AAEA,EAAA,OAAO,OAAO,MAAA,KAAW,CAAA,GAAI,GAAG,MAAM,CAAA,GAAI,IAAI,MAAM,CAAA;AACtD;AAaO,IAAM,qBAAqB,CAChC,OAAA;AAAA;AAAA,EAGA,iBAAiB,OAAqD;AAAA","file":"validation.js","sourcesContent":["import 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 at the call site selects the overload.\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <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 * 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 function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;\nexport function map<T, U>(fn: (value: T) => U): <E>(result: Result<T, E>) => Result<U, E>;\nexport function map(\n ...args: [Result<unknown, unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => mapImpl(result, fn);\n}\n\nconst mapErrImpl = <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 * 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 function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F>;\nexport function mapErr<E, F>(fn: (error: E) => F): <T>(result: Result<T, E>) => Result<T, F>;\nexport function mapErr(\n ...args: [Result<unknown, unknown>, (error: unknown) => unknown] | [(error: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapErrImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => mapErrImpl(result, fn);\n}\n\nconst bimapImpl = <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 * 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 function bimap<T, U, E, F>(\n result: Result<T, E>,\n onOk: (value: T) => U,\n onErr: (error: E) => F,\n): Result<U, F>;\nexport function bimap<T, U, E, F>(\n onOk: (value: T) => U,\n onErr: (error: E) => F,\n): (result: Result<T, E>) => Result<U, F>;\nexport function bimap(\n ...args:\n | [Result<unknown, unknown>, (value: unknown) => unknown, (error: unknown) => unknown]\n | [(value: unknown) => unknown, (error: unknown) => unknown]\n): unknown {\n if (args.length === 3) return bimapImpl(args[0], args[1], args[2]);\n const [onOk, onErr] = args;\n return (result: Result<unknown, unknown>) => bimapImpl(result, onOk, onErr);\n}\n\nconst flatMapImpl = <T, U, E, F>(\n result: Result<T, E>,\n fn: (value: T) => Result<U, F>,\n): Result<U, E | F> => (isOk(result) ? fn(result.value) : err(result.error));\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 function flatMap<T, U, E, F>(\n result: Result<T, E>,\n fn: (value: T) => Result<U, F>,\n): Result<U, E | F>;\nexport function flatMap<T, U, F>(\n fn: (value: T) => Result<U, F>,\n): <E>(result: Result<T, E>) => Result<U, E | F>;\nexport function flatMap(\n ...args:\n | [Result<unknown, unknown>, (value: unknown) => Result<unknown, unknown>]\n | [(value: unknown) => Result<unknown, unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => flatMapImpl(result, fn);\n}\n\nconst recoverImpl = <T, E, F>(\n result: Result<T, E>,\n fn: (error: E) => Result<T, F>,\n): Result<T, F> => (isErr(result) ? fn(result.error) : ok(result.value));\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 function recover<T, E, F>(\n result: Result<T, E>,\n fn: (error: E) => Result<T, F>,\n): Result<T, F>;\nexport function recover<T, E, F>(\n fn: (error: E) => Result<T, F>,\n): (result: Result<T, E>) => Result<T, F>;\nexport function recover(\n ...args:\n | [Result<unknown, unknown>, (error: unknown) => Result<unknown, unknown>]\n | [(error: unknown) => Result<unknown, unknown>]\n): unknown {\n if (args.length === 2) return recoverImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => recoverImpl(result, fn);\n}\n\nconst tapImpl = <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 `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 function tap<T, E>(result: Result<T, E>, fn: (value: T) => void): Result<T, E>;\nexport function tap<T>(fn: (value: T) => void): <E>(result: Result<T, E>) => Result<T, E>;\nexport function tap(\n ...args: [Result<unknown, unknown>, (value: unknown) => void] | [(value: unknown) => void]\n): unknown {\n if (args.length === 2) return tapImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => tapImpl(result, fn);\n}\n\nconst tapErrImpl = <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 * 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 function tapErr<T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E>;\nexport function tapErr<E>(fn: (error: E) => void): <T>(result: Result<T, E>) => Result<T, E>;\nexport function tapErr(\n ...args: [Result<unknown, unknown>, (error: unknown) => void] | [(error: unknown) => void]\n): unknown {\n if (args.length === 2) return tapErrImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => tapErrImpl(result, fn);\n}\n\nconst matchImpl = <T, E, U>(\n result: Result<T, E>,\n onOk: (value: T) => U,\n onErr: (error: E) => U,\n): U => (isOk(result) ? onOk(result.value) : onErr(result.error));\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 function match<T, E, U>(\n result: Result<T, E>,\n onOk: (value: T) => U,\n onErr: (error: E) => U,\n): U;\nexport function match<T, E, U>(\n onOk: (value: T) => U,\n onErr: (error: E) => U,\n): (result: Result<T, E>) => U;\nexport function match(\n ...args:\n | [Result<unknown, unknown>, (value: unknown) => unknown, (error: unknown) => unknown]\n | [(value: unknown) => unknown, (error: unknown) => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onOk, onErr] = args;\n return (result: Result<unknown, unknown>) => matchImpl(result, onOk, onErr);\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 = <T, E>(result: Result<T, E>, defaultValue: T): T =>\n isOk(result) ? result.value : defaultValue;\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/**\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 { err, isErr, ok } from \"./result.js\";\nimport type { Result } from \"./types.js\";\n\ntype OkValue<R> = R extends { readonly _tag: \"Ok\"; readonly value: infer T } ? T : never;\ntype ErrValue<R> = R extends { readonly _tag: \"Err\"; readonly error: infer E } ? E : never;\n\ntype ValidateTuple<R extends readonly Result<unknown, unknown>[], E> = Result<\n { [K in keyof R]: OkValue<R[K]> },\n E\n>;\ntype TupleErrors<R extends readonly Result<unknown, unknown>[]> = ErrValue<R[number]>;\n\n/**\n * Accumulate independent validation failures into a single combined error\n * via `combineErrors`. Returns `Ok<T[]>` only when every input is `Ok`;\n * otherwise returns `Err<E>` where `E` is the fold of all failures.\n *\n * Unlike `combine`, this does **not** short-circuit on first failure — use\n * for independent checks where you want to report all problems at once.\n *\n * @example\n * ```ts\n * validateAll(\n * [validateName(input), validateAge(input), validateEmail(input)],\n * (left, right) => [...left, ...right],\n * );\n * // Result<string[], FieldError[]>\n * ```\n */\nexport const validateAll = <T, E>(\n results: readonly Result<T, E>[],\n combineErrors: (left: E, right: E) => E,\n): Result<T[], E> => {\n const values: T[] = [];\n let accumulated: E | undefined;\n\n for (const result of results) {\n if (isErr(result)) {\n accumulated =\n accumulated === undefined ? result.error : combineErrors(accumulated, result.error);\n } else {\n values.push(result.value);\n }\n }\n\n return accumulated === undefined ? ok(values) : err(accumulated);\n};\n\n/**\n * Tuple-preserving variant of {@link validateAll}. All inputs must share\n * the same error type `E`. Output Ok preserves tuple positions.\n *\n * @example\n * ```ts\n * validateTuple(\n * [validateName(s), validateAge(s)] as const,\n * (l, r) => [...l, ...r],\n * );\n * // Result<readonly [string, number], FieldError[]>\n * ```\n */\nexport const validateTuple = <E, const R extends readonly Result<unknown, E>[]>(\n results: R,\n combineErrors: (left: E, right: E) => E,\n): ValidateTuple<R, E> =>\n // Runtime identical to validateAll; the cast restores per-index tuple types.\n validateAll(results, combineErrors) as ValidateTuple<R, E>;\n\n/**\n * Like {@link validateAll}, but collects every failure into a readonly\n * array instead of folding via a combine function. The default choice\n * when you want \"all errors\" without an explicit join.\n *\n * @example\n * ```ts\n * validateAllArray([validateName(input), validateAge(input)]);\n * // Result<readonly Field[], readonly FieldError[]>\n * ```\n */\nexport const validateAllArray = <T, E>(\n results: readonly Result<T, E>[],\n): Result<T[], readonly E[]> => {\n const values: T[] = [];\n const errors: E[] = [];\n\n for (const result of results) {\n if (isErr(result)) {\n errors.push(result.error);\n } else {\n values.push(result.value);\n }\n }\n\n return errors.length === 0 ? ok(values) : err(errors);\n};\n\n/**\n * Tuple-preserving variant of {@link validateAllArray}. Heterogeneous\n * input tuple → preserved Ok tuple shape with a union of all input\n * error types collected into a readonly array.\n *\n * @example\n * ```ts\n * validateTupleArray([validateName(s), validateAge(s)] as const);\n * // Result<readonly [string, number], readonly FieldError[]>\n * ```\n */\nexport const validateTupleArray = <const R extends readonly Result<unknown, unknown>[]>(\n results: R,\n): ValidateTuple<R, readonly TupleErrors<R>[]> =>\n // Runtime identical to validateAllArray; the cast restores per-index tuple types.\n validateAllArray(results as readonly Result<unknown, TupleErrors<R>>[]) as ValidateTuple<\n R,\n readonly TupleErrors<R>[]\n >;\n"]}