@onrails/result 0.1.1 → 0.1.3

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 (52) hide show
  1. package/DESIGN.md +0 -1
  2. package/README.md +10 -17
  3. package/RECIPES.md +143 -21
  4. package/dist/{async-CCA1yK8q.d.cts → async-CH8Cs8KE.d.cts} +14 -0
  5. package/dist/{async-DH_-dNIo.d.ts → async-DKISqIBc.d.ts} +14 -0
  6. package/dist/compat/neverthrow.cjs +78 -63
  7. package/dist/compat/neverthrow.cjs.map +1 -1
  8. package/dist/compat/neverthrow.d.cts +1 -1
  9. package/dist/compat/neverthrow.d.ts +1 -1
  10. package/dist/compat/neverthrow.js +78 -63
  11. package/dist/compat/neverthrow.js.map +1 -1
  12. package/dist/extra.cjs +17 -10
  13. package/dist/extra.cjs.map +1 -1
  14. package/dist/extra.d.cts +10 -2
  15. package/dist/extra.d.ts +10 -2
  16. package/dist/extra.js +17 -10
  17. package/dist/extra.js.map +1 -1
  18. package/dist/fluent.cjs.map +1 -1
  19. package/dist/fluent.d.cts +3 -1
  20. package/dist/fluent.d.ts +3 -1
  21. package/dist/fluent.js.map +1 -1
  22. package/dist/index.cjs +53 -58
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +21 -5
  25. package/dist/index.d.ts +21 -5
  26. package/dist/index.js +53 -58
  27. package/dist/index.js.map +1 -1
  28. package/dist/interop.cjs +49 -50
  29. package/dist/interop.cjs.map +1 -1
  30. package/dist/interop.d.cts +1 -1
  31. package/dist/interop.d.ts +1 -1
  32. package/dist/interop.js +49 -50
  33. package/dist/interop.js.map +1 -1
  34. package/dist/railway.cjs +58 -59
  35. package/dist/railway.cjs.map +1 -1
  36. package/dist/railway.d.cts +7 -6
  37. package/dist/railway.d.ts +7 -6
  38. package/dist/railway.js +58 -59
  39. package/dist/railway.js.map +1 -1
  40. package/dist/try-gen.cjs.map +1 -1
  41. package/dist/try-gen.js.map +1 -1
  42. package/dist/validation.cjs +8 -25
  43. package/dist/validation.cjs.map +1 -1
  44. package/dist/validation.js +8 -25
  45. package/dist/validation.js.map +1 -1
  46. package/package.json +1 -6
  47. package/dist/mcp.cjs +0 -292
  48. package/dist/mcp.cjs.map +0 -1
  49. package/dist/mcp.d.cts +0 -62
  50. package/dist/mcp.d.ts +0 -62
  51. package/dist/mcp.js +0 -284
  52. package/dist/mcp.js.map +0 -1
@@ -1 +1 @@
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,KACwB;AACxB,EAAA,MAAM,SAAoB,EAAC;AAC3B,EAAA,IAAI,WAAA;AAEJ,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,KAAA,CAAM,MAAM,CAAA,EAAG;AACjB,MAAA,MAAM,QAAQ,MAAA,CAAO,KAAA;AACrB,MAAA,WAAA,GAAc,WAAA,KAAgB,MAAA,GAAY,KAAA,GAAQ,aAAA,CAAc,aAAa,KAAK,CAAA;AAAA,IACpF,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,IAC1B;AAAA,EACF;AAEA,EAAA,OAAQ,gBAAgB,MAAA,GAAY,EAAA,CAAG,MAAM,CAAA,GAAI,IAAI,WAAW,CAAA;AAClE;AAaO,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,kBAAA,GAAqB,CAChC,OAAA,KACgD;AAChD,EAAA,MAAM,SAAoB,EAAC;AAC3B,EAAA,MAAM,SAA2B,EAAC;AAElC,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,KAAA,CAAM,MAAM,CAAA,EAAG;AACjB,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAuB,CAAA;AAAA,IAC5C,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,IAC1B;AAAA,EACF;AAEA,EAAA,OAAQ,OAAO,MAAA,KAAW,CAAA,GAAI,GAAG,MAAM,CAAA,GAAI,IAAI,MAAM,CAAA;AAIvD","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/** Fantasy Land `of` — alias of {@link ok}. */\nexport const of = ok;\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`, the\n * collision-free alias {@link matchResult} is identical.\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/** Collision-free alias for files that also import `match` from ts-pattern. */\nexport const matchResult = match;\n\n/**\n * Curried collapse with named slots — escape valve when positional `match`\n * order is unclear at the call site (e.g. when both handlers return the same\n * type and a transposed `match(r, onErr, onOk)` would silently compile).\n */\nexport const fold =\n <T, E, U>(handlers: { readonly ok: (value: T) => U; readonly err: (error: E) => U }) =>\n (result: Result<T, E>): U =>\n matchImpl(result, handlers.ok, handlers.err);\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/** Test/assert helper — throws the original Err value when called on Err. */\nexport function unwrapOk<T, E>(result: Result<T, E>): T {\n if (isErr(result)) throw result.error;\n return result.value;\n}\n\n/** Test/assert helper — throws TypeError when called on Ok. */\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/** Wrap a throwing sync function — neverthrow `Result.fromThrowable` */\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/** First failure wins; otherwise collects values in order */\nexport const combine = <T, E>(results: readonly Result<T, E>[]): Result<T[], E> => {\n const values: T[] = [];\n for (const result of results) {\n if (isErr(result)) return err(result.error);\n values.push(result.value);\n }\n return ok(values);\n};\n\n/** Tuple-preserving combine (neverthrow-style) */\nexport const combineTuple = <const R extends readonly Result<unknown, unknown>[]>(\n results: R,\n): CombineTuple<R> => {\n const values: unknown[] = [];\n for (const result of results) {\n if (isErr(result)) return err(result.error) as CombineTuple<R>;\n values.push(result.value);\n }\n return ok(values) as CombineTuple<R>;\n};\n\ntype _OkValue<R> = R extends { _tag: \"Ok\"; readonly value: infer T } ? T : never;\ntype _ErrValue<R> = R extends { _tag: \"Err\"; readonly error: infer E } ? E : never;\n\ntype CombineTuple<R extends readonly Result<unknown, unknown>[]> = Result<\n { [K in keyof R]: _OkValue<R[K]> },\n { [K in keyof R]: _ErrValue<R[K]> }[number]\n>;\n\n/**\n * Variadic value-first pipe — threads `value` through up to nine unary fns.\n *\n * ```ts\n * pipe(\n * parseConfig(raw),\n * map((cfg) => cfg.name),\n * flatMap((name) => name ? ok(name) : err({ kind: \"empty\" })),\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 const values: unknown[] = [];\n let accumulated: E | undefined;\n\n for (const result of results) {\n if (isErr(result)) {\n const error = result.error;\n accumulated = accumulated === undefined ? error : combineErrors(accumulated, error);\n } else {\n values.push(result.value);\n }\n }\n\n return (accumulated === undefined ? ok(values) : err(accumulated)) as ValidateTuple<R, E>;\n};\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 const values: unknown[] = [];\n const errors: TupleErrors<R>[] = [];\n\n for (const result of results) {\n if (isErr(result)) {\n errors.push(result.error as TupleErrors<R>);\n } else {\n values.push(result.value);\n }\n }\n\n return (errors.length === 0 ? ok(values) : err(errors)) as ValidateTuple<\n R,\n readonly TupleErrors<R>[]\n >;\n};\n"]}
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 * Fantasy Land `of` — alias of {@link ok}.\n * @deprecated Use {@link ok} instead.\n */\nexport const of = ok;\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`, the\n * collision-free alias {@link matchResult} is identical.\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 * Collision-free alias for files that also import `match` from ts-pattern.\n * @deprecated Namespace import carriers (e.g., `import * as R from \"@onrails/result\"`) and use canonical {@link match} instead.\n */\nexport const matchResult = match;\n\n/**\n * Curried collapse with named slots — escape valve when positional `match`\n * order is unclear at the call site (e.g. when both handlers return the same\n * type and a transposed `match(r, onErr, onOk)` would silently compile).\n * @deprecated Use curried {@link match}(onOk, onErr)(result) instead.\n */\nexport const fold =\n <T, E, U>(handlers: { readonly ok: (value: T) => U; readonly err: (error: E) => U }) =>\n (result: Result<T, E>): U =>\n matchImpl(result, handlers.ok, handlers.err);\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 — throws the original Err value when called on Err.\n *\n * @throws when the result is Err — assertion-tier; use {@link match} / {@link unwrapOr} in business logic.\n * Allowed in `*.spec.ts` / `*.test.ts`; flagged elsewhere by the plugins.\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 — throws TypeError when called on Ok.\n *\n * @throws when the result is Ok — assertion-tier; allowed in `*.spec.ts` / `*.test.ts`; flagged elsewhere by the plugins.\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/** Wrap a throwing sync function — neverthrow `Result.fromThrowable` */\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/** First failure wins; otherwise collects values in order */\nexport const combine = <T, E>(results: readonly Result<T, E>[]): Result<T[], E> => {\n const values: T[] = [];\n for (const result of results) {\n if (isErr(result)) return err(result.error);\n values.push(result.value);\n }\n return ok(values);\n};\n\n/** Tuple-preserving combine (neverthrow-style) */\nexport const combineTuple = <const R extends readonly Result<unknown, unknown>[]>(\n results: R,\n): CombineTuple<R> =>\n // Runtime identical to combine; the cast restores per-index tuple types.\n combine(results as readonly Result<unknown, unknown>[]) as CombineTuple<R>;\n\ntype _OkValue<R> = R extends { _tag: \"Ok\"; readonly value: infer T } ? T : never;\ntype _ErrValue<R> = R extends { _tag: \"Err\"; readonly error: infer E } ? E : never;\n\ntype CombineTuple<R extends readonly Result<unknown, unknown>[]> = Result<\n { [K in keyof R]: _OkValue<R[K]> },\n { [K in keyof R]: _ErrValue<R[K]> }[number]\n>;\n\n/**\n * Variadic value-first pipe — threads `value` through up to nine unary fns.\n *\n * ```ts\n * pipe(\n * parseConfig(raw),\n * map((cfg) => cfg.name),\n * flatMap((name) => name ? ok(name) : err({ kind: \"empty\" })),\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"]}
@@ -22,19 +22,10 @@ var validateAll = (results, combineErrors) => {
22
22
  }
23
23
  return accumulated === void 0 ? ok(values) : err(accumulated);
24
24
  };
25
- var validateTuple = (results, combineErrors) => {
26
- const values = [];
27
- let accumulated;
28
- for (const result of results) {
29
- if (isErr(result)) {
30
- const error = result.error;
31
- accumulated = accumulated === void 0 ? error : combineErrors(accumulated, error);
32
- } else {
33
- values.push(result.value);
34
- }
35
- }
36
- return accumulated === void 0 ? ok(values) : err(accumulated);
37
- };
25
+ var validateTuple = (results, combineErrors) => (
26
+ // Runtime identical to validateAll; the cast restores per-index tuple types.
27
+ validateAll(results, combineErrors)
28
+ );
38
29
  var validateAllArray = (results) => {
39
30
  const values = [];
40
31
  const errors = [];
@@ -47,18 +38,10 @@ var validateAllArray = (results) => {
47
38
  }
48
39
  return errors.length === 0 ? ok(values) : err(errors);
49
40
  };
50
- var validateTupleArray = (results) => {
51
- const values = [];
52
- const errors = [];
53
- for (const result of results) {
54
- if (isErr(result)) {
55
- errors.push(result.error);
56
- } else {
57
- values.push(result.value);
58
- }
59
- }
60
- return errors.length === 0 ? ok(values) : err(errors);
61
- };
41
+ var validateTupleArray = (results) => (
42
+ // Runtime identical to validateAllArray; the cast restores per-index tuple types.
43
+ validateAllArray(results)
44
+ );
62
45
 
63
46
  export { validateAll, validateAllArray, validateTuple, validateTupleArray };
64
47
  //# sourceMappingURL=validation.js.map
@@ -1 +1 @@
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,KACwB;AACxB,EAAA,MAAM,SAAoB,EAAC;AAC3B,EAAA,IAAI,WAAA;AAEJ,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,KAAA,CAAM,MAAM,CAAA,EAAG;AACjB,MAAA,MAAM,QAAQ,MAAA,CAAO,KAAA;AACrB,MAAA,WAAA,GAAc,WAAA,KAAgB,MAAA,GAAY,KAAA,GAAQ,aAAA,CAAc,aAAa,KAAK,CAAA;AAAA,IACpF,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,IAC1B;AAAA,EACF;AAEA,EAAA,OAAQ,gBAAgB,MAAA,GAAY,EAAA,CAAG,MAAM,CAAA,GAAI,IAAI,WAAW,CAAA;AAClE;AAaO,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,kBAAA,GAAqB,CAChC,OAAA,KACgD;AAChD,EAAA,MAAM,SAAoB,EAAC;AAC3B,EAAA,MAAM,SAA2B,EAAC;AAElC,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,KAAA,CAAM,MAAM,CAAA,EAAG;AACjB,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAuB,CAAA;AAAA,IAC5C,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,IAC1B;AAAA,EACF;AAEA,EAAA,OAAQ,OAAO,MAAA,KAAW,CAAA,GAAI,GAAG,MAAM,CAAA,GAAI,IAAI,MAAM,CAAA;AAIvD","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/** Fantasy Land `of` — alias of {@link ok}. */\nexport const of = ok;\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`, the\n * collision-free alias {@link matchResult} is identical.\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/** Collision-free alias for files that also import `match` from ts-pattern. */\nexport const matchResult = match;\n\n/**\n * Curried collapse with named slots — escape valve when positional `match`\n * order is unclear at the call site (e.g. when both handlers return the same\n * type and a transposed `match(r, onErr, onOk)` would silently compile).\n */\nexport const fold =\n <T, E, U>(handlers: { readonly ok: (value: T) => U; readonly err: (error: E) => U }) =>\n (result: Result<T, E>): U =>\n matchImpl(result, handlers.ok, handlers.err);\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/** Test/assert helper — throws the original Err value when called on Err. */\nexport function unwrapOk<T, E>(result: Result<T, E>): T {\n if (isErr(result)) throw result.error;\n return result.value;\n}\n\n/** Test/assert helper — throws TypeError when called on Ok. */\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/** Wrap a throwing sync function — neverthrow `Result.fromThrowable` */\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/** First failure wins; otherwise collects values in order */\nexport const combine = <T, E>(results: readonly Result<T, E>[]): Result<T[], E> => {\n const values: T[] = [];\n for (const result of results) {\n if (isErr(result)) return err(result.error);\n values.push(result.value);\n }\n return ok(values);\n};\n\n/** Tuple-preserving combine (neverthrow-style) */\nexport const combineTuple = <const R extends readonly Result<unknown, unknown>[]>(\n results: R,\n): CombineTuple<R> => {\n const values: unknown[] = [];\n for (const result of results) {\n if (isErr(result)) return err(result.error) as CombineTuple<R>;\n values.push(result.value);\n }\n return ok(values) as CombineTuple<R>;\n};\n\ntype _OkValue<R> = R extends { _tag: \"Ok\"; readonly value: infer T } ? T : never;\ntype _ErrValue<R> = R extends { _tag: \"Err\"; readonly error: infer E } ? E : never;\n\ntype CombineTuple<R extends readonly Result<unknown, unknown>[]> = Result<\n { [K in keyof R]: _OkValue<R[K]> },\n { [K in keyof R]: _ErrValue<R[K]> }[number]\n>;\n\n/**\n * Variadic value-first pipe — threads `value` through up to nine unary fns.\n *\n * ```ts\n * pipe(\n * parseConfig(raw),\n * map((cfg) => cfg.name),\n * flatMap((name) => name ? ok(name) : err({ kind: \"empty\" })),\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 const values: unknown[] = [];\n let accumulated: E | undefined;\n\n for (const result of results) {\n if (isErr(result)) {\n const error = result.error;\n accumulated = accumulated === undefined ? error : combineErrors(accumulated, error);\n } else {\n values.push(result.value);\n }\n }\n\n return (accumulated === undefined ? ok(values) : err(accumulated)) as ValidateTuple<R, E>;\n};\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 const values: unknown[] = [];\n const errors: TupleErrors<R>[] = [];\n\n for (const result of results) {\n if (isErr(result)) {\n errors.push(result.error as TupleErrors<R>);\n } else {\n values.push(result.value);\n }\n }\n\n return (errors.length === 0 ? ok(values) : err(errors)) as ValidateTuple<\n R,\n readonly TupleErrors<R>[]\n >;\n};\n"]}
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 * Fantasy Land `of` — alias of {@link ok}.\n * @deprecated Use {@link ok} instead.\n */\nexport const of = ok;\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`, the\n * collision-free alias {@link matchResult} is identical.\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 * Collision-free alias for files that also import `match` from ts-pattern.\n * @deprecated Namespace import carriers (e.g., `import * as R from \"@onrails/result\"`) and use canonical {@link match} instead.\n */\nexport const matchResult = match;\n\n/**\n * Curried collapse with named slots — escape valve when positional `match`\n * order is unclear at the call site (e.g. when both handlers return the same\n * type and a transposed `match(r, onErr, onOk)` would silently compile).\n * @deprecated Use curried {@link match}(onOk, onErr)(result) instead.\n */\nexport const fold =\n <T, E, U>(handlers: { readonly ok: (value: T) => U; readonly err: (error: E) => U }) =>\n (result: Result<T, E>): U =>\n matchImpl(result, handlers.ok, handlers.err);\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 — throws the original Err value when called on Err.\n *\n * @throws when the result is Err — assertion-tier; use {@link match} / {@link unwrapOr} in business logic.\n * Allowed in `*.spec.ts` / `*.test.ts`; flagged elsewhere by the plugins.\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 — throws TypeError when called on Ok.\n *\n * @throws when the result is Ok — assertion-tier; allowed in `*.spec.ts` / `*.test.ts`; flagged elsewhere by the plugins.\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/** Wrap a throwing sync function — neverthrow `Result.fromThrowable` */\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/** First failure wins; otherwise collects values in order */\nexport const combine = <T, E>(results: readonly Result<T, E>[]): Result<T[], E> => {\n const values: T[] = [];\n for (const result of results) {\n if (isErr(result)) return err(result.error);\n values.push(result.value);\n }\n return ok(values);\n};\n\n/** Tuple-preserving combine (neverthrow-style) */\nexport const combineTuple = <const R extends readonly Result<unknown, unknown>[]>(\n results: R,\n): CombineTuple<R> =>\n // Runtime identical to combine; the cast restores per-index tuple types.\n combine(results as readonly Result<unknown, unknown>[]) as CombineTuple<R>;\n\ntype _OkValue<R> = R extends { _tag: \"Ok\"; readonly value: infer T } ? T : never;\ntype _ErrValue<R> = R extends { _tag: \"Err\"; readonly error: infer E } ? E : never;\n\ntype CombineTuple<R extends readonly Result<unknown, unknown>[]> = Result<\n { [K in keyof R]: _OkValue<R[K]> },\n { [K in keyof R]: _ErrValue<R[K]> }[number]\n>;\n\n/**\n * Variadic value-first pipe — threads `value` through up to nine unary fns.\n *\n * ```ts\n * pipe(\n * parseConfig(raw),\n * map((cfg) => cfg.name),\n * flatMap((name) => name ? ok(name) : err({ kind: \"empty\" })),\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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onrails/result",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Tagged Result / ResultAsync for railway-oriented TypeScript — pure tagged unions, neverthrow-shaped compat shim, FL-friendly",
5
5
  "license": "MIT",
6
6
  "author": "Alan R. Soares",
@@ -67,11 +67,6 @@
67
67
  "import": "./dist/interop.js",
68
68
  "require": "./dist/interop.cjs"
69
69
  },
70
- "./mcp": {
71
- "types": "./dist/mcp.d.ts",
72
- "import": "./dist/mcp.js",
73
- "require": "./dist/mcp.cjs"
74
- },
75
70
  "./pipe": {
76
71
  "types": "./dist/pipe.d.ts",
77
72
  "import": "./dist/pipe.js",
package/dist/mcp.cjs DELETED
@@ -1,292 +0,0 @@
1
- 'use strict';
2
-
3
- // src/result.ts
4
- var ok = (value) => ({
5
- _tag: "Ok",
6
- value
7
- });
8
- var err = (error) => ({
9
- _tag: "Err",
10
- error
11
- });
12
- var isOk = (result) => result._tag === "Ok";
13
- var isErr = (result) => result._tag === "Err";
14
- var mapImpl = (result, fn) => isOk(result) ? ok(fn(result.value)) : err(result.error);
15
- function map(...args) {
16
- if (args.length === 2) return mapImpl(args[0], args[1]);
17
- const fn = args[0];
18
- return (result) => mapImpl(result, fn);
19
- }
20
- var mapErrImpl = (result, fn) => isErr(result) ? err(fn(result.error)) : ok(result.value);
21
- function mapErr(...args) {
22
- if (args.length === 2) return mapErrImpl(args[0], args[1]);
23
- const fn = args[0];
24
- return (result) => mapErrImpl(result, fn);
25
- }
26
-
27
- // src/types.ts
28
- var UnexpectedError = class extends Error {
29
- constructor(message, cause) {
30
- super(message);
31
- this.cause = cause;
32
- this.name = "UnexpectedError";
33
- }
34
- cause;
35
- };
36
-
37
- // src/async.ts
38
- var liftPromiseResult = async (promise, onDefect) => {
39
- try {
40
- const result = await promise;
41
- if (isErr(result)) {
42
- return result;
43
- }
44
- const inner = result.value;
45
- if (inner && typeof inner === "object" && "_tag" in inner) {
46
- if (inner._tag === "Ok" || inner._tag === "Err") {
47
- return inner;
48
- }
49
- }
50
- return result;
51
- } catch (error) {
52
- return err(onDefect(error));
53
- }
54
- };
55
- var ResultAsync = class _ResultAsync {
56
- constructor(run) {
57
- this.run = run;
58
- }
59
- run;
60
- static fromResult(result) {
61
- return new _ResultAsync(async () => result);
62
- }
63
- static fromPromise(promise, onReject) {
64
- return new _ResultAsync(async () => {
65
- try {
66
- return ok(await promise);
67
- } catch (error) {
68
- return err(onReject(error));
69
- }
70
- });
71
- }
72
- static fromSafePromise(promise) {
73
- return new _ResultAsync(async () => ok(await promise));
74
- }
75
- /**
76
- * Defers work until {@link resolve}. Unlike {@link fromPromise}, nothing runs
77
- * until the `ResultAsync` is resolved (e.g. by `combineTuple` / `combineTupleParallel`).
78
- */
79
- static defer(fn) {
80
- return new _ResultAsync(fn);
81
- }
82
- static ok(value) {
83
- return new _ResultAsync(async () => ok(value));
84
- }
85
- static err(error) {
86
- return new _ResultAsync(async () => err(error));
87
- }
88
- /** @see {@link fromAsync} from `@onrails/result/interop` */
89
- static fromResultPromise(promise, onDefect) {
90
- const mapDefect = onDefect ?? ((error) => new UnexpectedError("Unexpected async defect", error));
91
- return new _ResultAsync(() => liftPromiseResult(promise, mapDefect));
92
- }
93
- static combine(results) {
94
- return new _ResultAsync(async () => {
95
- const values = [];
96
- for (const ra of results) {
97
- const result = await ra.resolve();
98
- if (isErr(result)) {
99
- return err(result.error);
100
- }
101
- values.push(result.value);
102
- }
103
- return ok(values);
104
- });
105
- }
106
- static combineTuple(results) {
107
- return new _ResultAsync(async () => {
108
- const values = [];
109
- for (const ra of results) {
110
- const result = await ra.resolve();
111
- if (isErr(result)) {
112
- return err(result.error);
113
- }
114
- values.push(result.value);
115
- }
116
- return ok(values);
117
- });
118
- }
119
- /**
120
- * Like {@link combineTuple}, but starts every branch before awaiting (wall-clock
121
- * parallel for independent IO). On failure, returns the first `Err` in input order.
122
- */
123
- static combineTupleParallel(results) {
124
- return new _ResultAsync(async () => {
125
- const settled = await Promise.all(results.map((ra) => ra.resolve()));
126
- const values = [];
127
- for (const result of settled) {
128
- if (isErr(result)) {
129
- return err(result.error);
130
- }
131
- values.push(result.value);
132
- }
133
- return ok(values);
134
- });
135
- }
136
- map(fn) {
137
- return new _ResultAsync(async () => map(await this.run(), fn));
138
- }
139
- mapErr(fn) {
140
- return new _ResultAsync(async () => mapErr(await this.run(), fn));
141
- }
142
- flatMap(fn) {
143
- return new _ResultAsync(async () => {
144
- const first = await this.run();
145
- if (isErr(first)) {
146
- return err(first.error);
147
- }
148
- const next = fn(first.value);
149
- if (next instanceof _ResultAsync) {
150
- return next.resolve();
151
- }
152
- if (isResultLike(next)) {
153
- return next;
154
- }
155
- if (isCompatLike(next)) {
156
- return next.inner;
157
- }
158
- return next;
159
- });
160
- }
161
- andThen(fn) {
162
- return this.flatMap(fn);
163
- }
164
- chain(fn) {
165
- return this.flatMap(fn);
166
- }
167
- recover(fn) {
168
- return new _ResultAsync(async () => {
169
- const first = await this.run();
170
- if (!isErr(first)) {
171
- return first;
172
- }
173
- const next = fn(first.error);
174
- if (next instanceof _ResultAsync) {
175
- return next.resolve();
176
- }
177
- return next;
178
- });
179
- }
180
- orElse(fn) {
181
- return this.recover(fn);
182
- }
183
- tap(fn) {
184
- return new _ResultAsync(async () => {
185
- const result = await this.run();
186
- if (!isErr(result)) {
187
- fn(result.value);
188
- }
189
- return result;
190
- });
191
- }
192
- tapErr(fn) {
193
- return new _ResultAsync(async () => {
194
- const result = await this.run();
195
- if (isErr(result)) {
196
- fn(result.error);
197
- }
198
- return result;
199
- });
200
- }
201
- unwrapOr(defaultValue) {
202
- return this.run().then((result) => isErr(result) ? defaultValue : result.value);
203
- }
204
- isOk() {
205
- return this.run().then((result) => !isErr(result));
206
- }
207
- isErr() {
208
- return this.run().then((result) => isErr(result));
209
- }
210
- match(onOk, onErr) {
211
- return this.run().then(
212
- (result) => isErr(result) ? onErr(result.error) : onOk(result.value)
213
- );
214
- }
215
- resolve() {
216
- return this.run();
217
- }
218
- /**
219
- * Thenable shim — `await ra` resolves to a bare tagged-union `Result<T, E>`.
220
- * Narrow with `isOk(r)` / `isErr(r)` to read `.value` / `.error`.
221
- */
222
- // biome-ignore lint/suspicious/noThenProperty: makes ResultAsync awaitable
223
- then(onfulfilled, onrejected) {
224
- return this.run().then(
225
- (r) => onfulfilled ? onfulfilled(r) : r,
226
- onrejected ?? void 0
227
- );
228
- }
229
- };
230
- function isResultLike(v) {
231
- return typeof v === "object" && v !== null && "_tag" in v && (v._tag === "Ok" || v._tag === "Err");
232
- }
233
- function isCompatLike(v) {
234
- return typeof v === "object" && v !== null && "inner" in v && isResultLike(v.inner);
235
- }
236
-
237
- // src/interop.ts
238
- function fromAsync(fn, onDefect) {
239
- return (...args) => ResultAsync.fromResultPromise(fn(...args), onDefect);
240
- }
241
-
242
- // src/mcp.ts
243
- var unwrapFetchResult = (result, toError) => {
244
- if (result.error !== void 0 || result.data === void 0) {
245
- return err(toError({ error: result.error, response: result.response }));
246
- }
247
- return ok(result.data);
248
- };
249
- var extractFetchErrorDetail = (error, response) => {
250
- if (error === void 0 || error === null) {
251
- return response.statusText || "unknown error";
252
- }
253
- const raw = typeof error === "object" ? JSON.stringify(error) : String(error);
254
- const lower = raw.toLowerCase();
255
- if (lower.includes("<!doctype") || lower.includes("<html")) {
256
- const statusHint = response.status === 403 ? "request blocked by CDN/WAF" : `unexpected HTML response (${response.status})`;
257
- return `${statusHint} \u2014 retry after a short delay`;
258
- }
259
- return raw;
260
- };
261
- var unwrapFetchResultAsync = (promise, toError, onDefect) => fromAsync(() => promise.then((r) => unwrapFetchResult(r, toError)), onDefect)();
262
- var toToolResponse = (result) => {
263
- if (isOk(result)) {
264
- return {
265
- structuredContent: result.value,
266
- content: [{ type: "text", text: JSON.stringify(result.value, null, 2) }]
267
- };
268
- }
269
- return {
270
- content: [{ type: "text", text: result.error.message }],
271
- isError: true
272
- };
273
- };
274
- var toToolResponseAsync = async (resultAsync) => toToolResponse(await resultAsync.resolve());
275
- var toolOk = (data) => ({
276
- structuredContent: data,
277
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
278
- });
279
- var toolError = (text) => ({
280
- content: [{ type: "text", text }],
281
- isError: true
282
- });
283
-
284
- exports.extractFetchErrorDetail = extractFetchErrorDetail;
285
- exports.toToolResponse = toToolResponse;
286
- exports.toToolResponseAsync = toToolResponseAsync;
287
- exports.toolError = toolError;
288
- exports.toolOk = toolOk;
289
- exports.unwrapFetchResult = unwrapFetchResult;
290
- exports.unwrapFetchResultAsync = unwrapFetchResultAsync;
291
- //# sourceMappingURL=mcp.cjs.map
292
- //# sourceMappingURL=mcp.cjs.map