@railway-ts/pipelines 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Railway-oriented programming for TypeScript. Result and Option types that don't suck.
6
6
 
7
- **Design philosophy:** Small, focused API surface. Practical over academic. No fp-ts complexity, no Effect-TS kitchen sink.
7
+ Small, focused API surface. Errors propagate automatically, you handle them once at the end.
8
8
 
9
9
  ## Install
10
10
 
@@ -14,11 +14,53 @@ bun add @railway-ts/pipelines # or npm, pnpm, yarn
14
14
 
15
15
  Requires TypeScript 5.0+ and Node.js 18+.
16
16
 
17
- ## Quick Start
17
+ ## Quick Example
18
18
 
19
19
  ```typescript
20
20
  import { pipe } from '@railway-ts/pipelines/composition';
21
- import { ok, match, andThen } from '@railway-ts/pipelines/result';
21
+ import { ok, err, mapWith, match } from '@railway-ts/pipelines/result';
22
+
23
+ const divide = (a: number, b: number) =>
24
+ b === 0 ? err('div by zero') : ok(a / b);
25
+
26
+ const result = pipe(
27
+ divide(10, 2),
28
+ mapWith((x) => x * 3),
29
+ );
30
+
31
+ match(result, {
32
+ ok: (value) => console.log(value), // 15
33
+ err: (error) => console.error(error),
34
+ });
35
+ ```
36
+
37
+ ## Documentation
38
+
39
+ -> **[Getting Started](docs/GETTING_STARTED.md)** - Guided walkthrough from first principles to full pipelines
40
+ -> **[Recipes](docs/RECIPES.md)** - Point-free composition, error recovery, async pipelines, validation patterns
41
+ -> **[Advanced](docs/ADVANCED.md)** - Symbol branding, type inference, implementation details
42
+ -> **[Examples](examples/)** - Working code you can run
43
+
44
+ For a complete real-world pipeline, see the [Launch Decision Pipeline](docs/RECIPES.md#full-example-launch-decision-pipeline) -- validates input, fetches weather data, and makes a GO/NO-GO decision.
45
+
46
+ ## What's Included
47
+
48
+ - **Result\<T, E\>** -- typed success/failure with map, flatMap, match, and recovery
49
+ - **Option\<T\>** -- nullable handling without null checks
50
+ - **Schema validation** -- parse unknown data, accumulate all errors, infer TypeScript types
51
+ - **Composition** -- `pipe`, `flow`, `pipeAsync`, `flowAsync`, `curry`
52
+ - **Async** -- sync-preserving overloads, parallel field validation, seamless sync/async mixing
53
+ - **Standard Schema v1** -- `toStandardSchema()` for tRPC, TanStack Form, React Hook Form, and other consumers
54
+
55
+ ## Two Styles
56
+
57
+ Same task, two approaches -- use whichever fits your codebase.
58
+
59
+ **Pipeline-first** -- keep validation and computation as separate pipeline steps:
60
+
61
+ ```typescript
62
+ import { pipeAsync } from '@railway-ts/pipelines/composition';
63
+ import { mapWith, match } from '@railway-ts/pipelines/result';
22
64
  import {
23
65
  validate,
24
66
  object,
@@ -36,8 +78,11 @@ const schema = object({
36
78
  y: required(chain(parseNumber(), min(1))),
37
79
  });
38
80
 
39
- async function compute(input: unknown): Promise<ValidationResult<number>> {
40
- const result = await pipe(validate(input, schema), (r) => andThen(r, ({ x, y }) => ok(x / y)));
81
+ async function compute(input: unknown) {
82
+ const result = await pipeAsync(
83
+ validate(input, schema),
84
+ mapWith(({ x, y }) => x / y),
85
+ );
41
86
 
42
87
  return match<number, ValidationError[], ValidationResult<number>>(result, {
43
88
  ok: (value) => ({ valid: true, data: value }),
@@ -45,40 +90,51 @@ async function compute(input: unknown): Promise<ValidationResult<number>> {
45
90
  });
46
91
  }
47
92
 
48
- await compute({ x: 10, y: 2 }).then(console.log); // { valid: true, data: 5 }
93
+ await compute({ x: '10', y: '2' }).then(console.log); // { valid: true, data: 5 }
49
94
  ```
50
95
 
51
- **The pattern:** Validate at boundaries, chain operations, branch once at the end. Errors propagate automatically.
52
-
53
- ## Documentation
54
-
55
- → **[Getting Started](GETTING_STARTED.md)** - Your first pipeline
56
- → **[Recipes](docs/RECIPES.md)** - Common patterns (point-free composition, async, validation)
57
- → **[Advanced](docs/ADVANCED.md)** - Symbol branding, tuple preservation, type inference
58
- → **[Examples](examples/)** - Working code you can run
96
+ **Schema-first** -- fold the transform into the schema, get the result in one call:
59
97
 
60
- ## Why This Library
61
-
62
- **Focused scope:** Result, Option, validation, composition. That's it. No monads seminar.
98
+ ```typescript
99
+ import {
100
+ validateAndFormatResult,
101
+ object,
102
+ required,
103
+ chain,
104
+ parseNumber,
105
+ min,
106
+ transform,
107
+ } from '@railway-ts/pipelines/schema';
63
108
 
64
- **Practical:** Eliminates boilerplate for real patterns. Documentation shows you how, doesn't make it part of the API.
109
+ const schema = chain(
110
+ object({
111
+ x: required(chain(parseNumber(), min(0))),
112
+ y: required(chain(parseNumber(), min(1))),
113
+ }),
114
+ transform(({ x, y }) => x / y),
115
+ );
65
116
 
66
- **Type-safe:** Symbol branding prevents duck typing bugs. Tuple preservation means no type casts.
117
+ const result = validateAndFormatResult({ x: '10', y: '2' }, schema);
118
+ console.log(result); // { valid: true, data: 5 }
119
+ ```
67
120
 
68
- **Railway-oriented:** Errors propagate automatically. Write happy path code, handle errors once at the end.
121
+ **The pattern:** Validate at boundaries, chain operations, branch once at the end. Errors propagate automatically.
69
122
 
70
123
  ## API Reference
71
124
 
72
125
  ### Option
73
126
 
74
- Handle nullable values without `if (x != null)` everywhere.
127
+ Handle nullable values without `if (x !== null)` everywhere.
75
128
 
76
129
  ```typescript
77
130
  import { pipe } from '@railway-ts/pipelines/composition';
78
- import { some, map, match } from '@railway-ts/pipelines/option';
131
+ import { some, mapWith, match } from '@railway-ts/pipelines/option';
79
132
 
80
133
  const user = some({ name: 'Alice', age: 25 });
81
- const name = pipe(user, (o) => map(o, (u) => u.name));
134
+ const name = pipe(
135
+ user,
136
+ mapWith((u) => u.name),
137
+ );
82
138
 
83
139
  match(name, {
84
140
  some: (n) => console.log(n),
@@ -86,11 +142,12 @@ match(name, {
86
142
  }); // Output: Alice
87
143
  ```
88
144
 
89
- **Core:** `some`, `none`, `isSome`, `isNone`
90
- **Transform:** `map`, `flatMap`, `bimap`, `filter`, `tap`
91
- **Unwrap:** `unwrap`, `unwrapOr`, `unwrapOrElse`
92
- **Combine:** `combine`
93
- **Convert:** `fromNullable`, `mapToResult`
145
+ **Core:** `some`, `none`, `isSome`, `isNone`
146
+ **Transform:** `map`, `flatMap`, `bimap`, `filter`, `tap`
147
+ **Curried:** `mapWith`, `flatMapWith`, `filterWith`, `tapWith`
148
+ **Unwrap:** `unwrap`, `unwrapOr`, `unwrapOrElse`
149
+ **Combine:** `combine`
150
+ **Convert:** `fromNullable`, `mapToResult`
94
151
  **Branch:** `match`
95
152
 
96
153
  ### Result
@@ -99,11 +156,14 @@ Explicit error handling. No exceptions, no try-catch pyramids.
99
156
 
100
157
  ```typescript
101
158
  import { pipe } from '@railway-ts/pipelines/composition';
102
- import { ok, err, map, match } from '@railway-ts/pipelines/result';
159
+ import { ok, err, mapWith, match } from '@railway-ts/pipelines/result';
103
160
 
104
161
  const divide = (a: number, b: number) => (b === 0 ? err('div by zero') : ok(a / b));
105
162
 
106
- const result = pipe(divide(10, 2), (r) => map(r, (x) => x * 3));
163
+ const result = pipe(
164
+ divide(10, 2),
165
+ mapWith((x) => x * 3),
166
+ );
107
167
 
108
168
  match(result, {
109
169
  ok: (value) => console.log(value),
@@ -111,18 +171,21 @@ match(result, {
111
171
  }); // Output: 15
112
172
  ```
113
173
 
114
- **Core:** `ok`, `err`, `isOk`, `isErr`
115
- **Transform:** `map`, `mapErr`, `flatMap`, `bimap`, `filter`, `tap`, `tapErr`
116
- **Unwrap:** `unwrap`, `unwrapOr`, `unwrapOrElse`
117
- **Combine:** `combine`, `combineAll`
118
- **Convert:** `fromTry`, `fromTryWithError`, `fromPromise`, `fromPromiseWithError`, `toPromise`, `mapToOption`
119
- **Async:** `andThen`
174
+ **Core:** `ok`, `err`, `isOk`, `isErr`
175
+ **Transform:** `map`, `mapErr`, `flatMap`, `bimap`, `filter`, `tap`, `tapErr`
176
+ **Curried:** `mapWith`, `flatMapWith`, `mapErrWith`, `filterWith`, `tapWith`, `tapErrWith`
177
+ **Recovery:** `orElse`, `orElseWith`
178
+ **Unwrap:** `unwrap`, `unwrapOr`, `unwrapOrElse`
179
+ **Combine:** `combine`, `combineAll`
180
+ **Convert:** `fromTry`, `fromTryWithError`, `fromPromise`, `fromPromiseWithError`, `toPromise`, `mapToOption`
120
181
  **Branch:** `match`
121
182
 
122
183
  ### Schema
123
184
 
124
185
  Parse untrusted data into typed values. Accumulates all validation errors.
125
186
 
187
+ > **Standard Schema v1 compliant** — use `toStandardSchema()` for interop with tRPC, TanStack Form, React Hook Form, and other Standard Schema consumers. See [Recipes → Standard Schema Interop](docs/RECIPES.md#standard-schema-interop).
188
+
126
189
  ```typescript
127
190
  import {
128
191
  validate,
@@ -150,23 +213,29 @@ const result = validate(input, userSchema);
150
213
  // Result<User, ValidationError[]>
151
214
  ```
152
215
 
153
- **Primitives:** `string`, `number`, `boolean`, `date`, `bigint`
154
- **Parsers:** `parseNumber`, `parseInt`, `parseFloat`, `parseJSON`, `parseString`, `parseBigInt`, `parseBool`, `parseDate`, `parseISODate`, `parseURL`, `parseEnum`
155
- **Structures:** `object`, `array`, `tuple`, `tupleOf`
156
- **Unions:** `union`, `discriminatedUnion`, `literal`
157
- **Modifiers:** `required`, `optional`, `nullable`, `emptyAsOptional`
158
- **String Constraints:** `minLength`, `maxLength`, `pattern`, `nonEmpty`, `email`, `phoneNumber`
159
- **Number Constraints:** `min`, `max`, `integer`, `finite`, `between`
160
- **Enums:** `stringEnum`, `numberEnum`
161
- **Combinators:** `chain`, `transform`, `refine`, `matches`
162
- **Utilities:** `validate`, `formatErrors`, `InferSchemaType`, `Validator`, `ValidationError`
216
+ **Primitives:** `string`, `number`, `boolean`, `date`, `bigint`
217
+ **Parsers:** `parseNumber`, `parseString`, `parseBool`, `parseBigInt`, `parseDate`, `parseISODate`, `parseJSON`, `parseURL`, `parseEnum`
218
+ **Structures:** `object`, `array`, `tuple`, `tupleOf`
219
+ **Unions:** `union`, `discriminatedUnion`, `literal`
220
+ **Modifiers:** `required`, `optional`, `nullable`, `emptyAsOptional`
221
+ **String Constraints:** `minLength`, `maxLength`, `pattern`, `nonEmpty`, `email`, `phoneNumber`
222
+ **Number Constraints:** `min`, `max`, `integer`, `finite`, `between`, `positive`, `negative`, `nonZero`, `divisibleBy`, `precision`
223
+ **Date Constraints:** `dateRange`, `pastDate`, `futureDate`, `todayOrFuture`
224
+ **Enums:** `stringEnum`, `enumValue`, `oneOf`
225
+ **Boolean Constraints:** `matches`
226
+ **Array Constraints:** `minItems`, `maxItems`, `notEmpty`, `unique`
227
+ **Combinators:** `chain`, `transform`, `refine`
228
+ **Cross-field:** `refineAt`, `refineAtAsync`
229
+ **Async:** `chainAsync`, `refineAsync`, `refineAtAsync`
230
+ **Utilities:** `validate`, `validateAndFormatResult`, `formatErrors`, `toStandardSchema`, `ROOT_ERROR_KEY`
231
+ **Types:** `Validator`, `AsyncValidator`, `MaybeAsyncValidator`, `Schema`, `SyncSchema`, `InferSchemaType`, `ValidatorMapOutput`, `ValidationError`, `ValidationResult`, `StandardSchemaV1`
163
232
 
164
233
  ### Composition
165
234
 
166
235
  Build pipelines. No nested function calls.
167
236
 
168
237
  ```typescript
169
- import { pipe, flow, curry } from '@railway-ts/pipelines/composition';
238
+ import { pipe, flow, pipeAsync, flowAsync } from '@railway-ts/pipelines/composition';
170
239
 
171
240
  // Immediate execution
172
241
  const result = pipe(
@@ -175,34 +244,24 @@ const result = pipe(
175
244
  (x) => x + 1,
176
245
  ); // 11
177
246
 
178
- // Build reusable pipeline
247
+ // Reusable pipeline
179
248
  const process = flow(
180
249
  (x: number) => x * 2,
181
250
  (x) => x + 1,
182
251
  );
183
252
  process(5); // 11
184
- ```
185
-
186
- **Functions:** `pipe`, `flow`, `curry`, `uncurry`, `tupled`, `untupled`
187
253
 
188
- ## Import Patterns
254
+ // Async pipeline (awaits each step)
255
+ const data = await pipeAsync(userId, fetchUser, validateUser, enrichProfile);
189
256
 
190
- ### Subpath imports (recommended for tree-shaking)
191
-
192
- ```typescript
193
- import { some, none, map } from '@railway-ts/pipelines/option';
194
- import { ok, err, flatMap } from '@railway-ts/pipelines/result';
195
- import { pipe, flow } from '@railway-ts/pipelines/composition';
196
- import { string, number, validate } from '@railway-ts/pipelines/schema';
197
- ```
198
-
199
- ### Root imports (adds type suffixes)
200
-
201
- ```typescript
202
- import { mapOption, mapResult, pipe, ok, validate } from '@railway-ts/pipelines';
257
+ // Reusable async pipeline
258
+ const processOrder = flowAsync(validateOrder, chargePayment, createShipment);
259
+ await processOrder(orderInput);
203
260
  ```
204
261
 
205
- Functions that exist in both Result and Option get suffixes when imported from root: `mapResult`, `mapOption`, etc. Result-only functions stay unsuffixed: `mapErr`, `andThen`.
262
+ **Sync:** `pipe`, `flow`, `curry`, `uncurry`, `tupled`, `untupled`
263
+ **Async:** `pipeAsync`, `flowAsync`
264
+ **Types:** `MaybeAsync`
206
265
 
207
266
  ## Examples
208
267
 
@@ -217,10 +276,10 @@ bun run examples/index.ts
217
276
 
218
277
  **What's in there:**
219
278
 
220
- - `option/` - Nullable handling patterns
221
- - `result/` - Error handling patterns
222
- - `schema/` - Validation (basic, unions, tuples)
223
- - `composition/` - Function composition techniques
279
+ - `option/` - Nullable handling patterns, curried helpers
280
+ - `result/` - Error handling patterns, curried helpers, recovery
281
+ - `schema/` - Validation (basic, unions, tuples, async validation)
282
+ - `composition/` - Function composition (sync and async)
224
283
  - `complete-pipelines/` - Full examples with validation + async + logic
225
284
 
226
285
  Start with `examples/complete-pipelines/async-launch.ts` for a real-world pattern.
@@ -24,6 +24,26 @@ function flow(...fns) {
24
24
  };
25
25
  }
26
26
 
27
+ // src/composition/pipe-async.ts
28
+ async function pipeAsync(a, ...fns) {
29
+ let result = await a;
30
+ for (const fn of fns) {
31
+ result = await fn(result);
32
+ }
33
+ return result;
34
+ }
35
+
36
+ // src/composition/flow-async.ts
37
+ function flowAsync(first, ...fns) {
38
+ return async (...args) => {
39
+ let result = await first(...args);
40
+ for (const fn of fns) {
41
+ result = await fn(result);
42
+ }
43
+ return result;
44
+ };
45
+ }
46
+
27
47
  // src/composition/curry.ts
28
48
  function curry(fn) {
29
49
  const arity = fn.length;
@@ -64,7 +84,9 @@ function untupled(fn) {
64
84
 
65
85
  exports.curry = curry;
66
86
  exports.flow = flow;
87
+ exports.flowAsync = flowAsync;
67
88
  exports.pipe = pipe;
89
+ exports.pipeAsync = pipeAsync;
68
90
  exports.tupled = tupled;
69
91
  exports.uncurry = uncurry;
70
92
  exports.untupled = untupled;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/composition/pipe.ts","../../src/composition/flow.ts","../../src/composition/curry.ts","../../src/composition/uncurry.ts","../../src/composition/tupled.ts","../../src/composition/untupled.ts"],"names":[],"mappings":";;;AA8GO,SAAS,IAAA,CAAK,UAAmB,GAAA,EAAiC;AACvE,EAAA,IAAI,MAAA,GAAS,KAAA;AACb,EAAA,KAAA,MAAW,MAAM,GAAA,EAAK;AACpB,IAAA,MAAA,GAAS,GAAG,MAAM,CAAA;AAAA,EACpB;AACA,EAAA,OAAO,MAAA;AACT;;;ACkBO,SAAS,QAAQ,GAAA,EAA+D;AACrF,EAAA,IAAI,GAAA,CAAI,WAAW,CAAA,EAAG;AACpB,IAAA,OAAO,IAAI,CAAC,CAAA;AAAA,EACd;AAEA,EAAA,MAAM,CAAC,KAAA,EAAO,GAAG,IAAI,CAAA,GAAI,GAAA;AACzB,EAAA,OAAO,IAAI,IAAA,KAA6B;AACtC,IAAA,IAAI,MAAA,GAAS,KAAA,CAAM,GAAG,IAAI,CAAA;AAC1B,IAAA,KAAA,MAAW,MAAM,IAAA,EAAM;AACrB,MAAA,MAAA,GAAS,GAAG,MAAM,CAAA;AAAA,IACpB;AACA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;;;AC9FO,SAAS,MAAiC,EAAA,EAAwB;AACvE,EAAA,MAAM,QAAQ,EAAA,CAAG,MAAA;AAEjB,EAAA,OAAO,SAAS,WAAW,IAAA,EAA0B;AACnD,IAAA,IAAI,IAAA,CAAK,UAAU,KAAA,EAAO;AACxB,MAAA,OAAQ,EAAA,CAAuB,GAAG,IAAI,CAAA;AAAA,IACxC;AAEA,IAAA,OAAO,YAAa,QAAA,EAA8B;AAChD,MAAA,OAAO,OAAA,CAAQ,GAAG,IAAA,EAAM,GAAG,QAAQ,CAAA;AAAA,IACrC,CAAA;AAAA,EACF,CAAA;AACF;;;ACPO,SAAS,QAAQ,EAAA,EAAsB;AAC5C,EAAA,OAAO,SAAS,aAAa,IAAA,EAA0B;AAErD,IAAA,IAAI,MAAA,GAAS,EAAA;AAEb,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,MAAA,GAAU,OAA2B,GAAG,CAAA;AAAA,IAC1C;AAEA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;;;ACbO,SAAS,OAAkC,EAAA,EAAqC;AACrF,EAAA,OAAO,SAAS,SAAS,IAAA,EAA0B;AACjD,IAAA,OAAO,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,EACnB,CAAA;AACF;;;ACPO,SAAS,SAAoC,EAAA,EAAwB;AAC1E,EAAA,OAAO,SAAS,cAAc,IAAA,EAA0B;AACtD,IAAA,OAAO,GAAG,IAAI,CAAA;AAAA,EAChB,CAAA;AACF","file":"index.cjs","sourcesContent":["type UnknownFunction = (...params: unknown[]) => unknown;\n\n/**\n * Pipes a value through a series of functions, from left to right.\n * Each function receives the output of the previous function.\n * Unlike flow, pipe immediately executes the functions with the provided initial value.\n *\n * @example\n * // Basic usage\n * const result = pipe(\n * 5,\n * (n) => n * 2, // 10\n * (n) => n + 1, // 11\n * (n) => n.toString() // \"11\"\n * );\n * // result: \"11\"\n *\n * @example\n * // With Option\n * import { some, mapOption } from \"@railway-ts/pipelines/option\";\n *\n * const optionResult = pipe(\n * some(5),\n * (o) => mapOption(o, (n) => n * 2),\n * (o) => mapOption(o, (n) => n.toString())\n * );\n * // optionResult: Option<string> containing \"10\"\n *\n * @example\n * // With Result\n * import { ok, mapResult } from \"@railway-ts/pipelines/result\";\n *\n * const resultValue = pipe(\n * ok(5),\n * (r) => mapResult(r, (n) => n * 2),\n * (r) => mapResult(r, (n) => n.toString())\n * );\n * // resultValue: Result<string, never> containing \"10\"\n *\n * @param a - The initial value to pipe through the functions\n * @param ab - The first function to apply to the initial value\n * @param functions - Additional functions to apply in sequence\n * @returns The final result after applying all functions\n */\n\nexport function pipe<A, B>(a: A, ab: (this: void, a: A) => B): B;\nexport function pipe<A, B, C>(a: A, ab: (this: void, a: A) => B, bc: (this: void, b: B) => C): C;\nexport function pipe<A, B, C, D>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n): D;\nexport function pipe<A, B, C, D, E>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n): E;\nexport function pipe<A, B, C, D, E, F>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n): F;\nexport function pipe<A, B, C, D, E, F, G>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n): G;\nexport function pipe<A, B, C, D, E, F, G, H>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n): H;\nexport function pipe<A, B, C, D, E, F, G, H, I>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n hi: (this: void, h: H) => I,\n): I;\nexport function pipe<A, B, C, D, E, F, G, H, I, J>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n hi: (this: void, h: H) => I,\n ij: (this: void, i: I) => J,\n): J;\nexport function pipe(value: unknown, ...fns: UnknownFunction[]): unknown {\n let result = value;\n for (const fn of fns) {\n result = fn(result);\n }\n return result;\n}\n","type UnknownFunction = (...params: unknown[]) => unknown;\n\n/**\n * Creates a new function that is the composition of the provided functions, applied from left to right.\n * Unlike pipe, flow doesn't immediately execute the functions but returns a new function that,\n * when called, will run the composed functions in sequence.\n *\n * @example\n * // Basic usage\n * const processNumber = flow(\n * (n: number) => n * 2,\n * (n) => n + 1,\n * (n) => n.toString()\n * );\n *\n * const result = processNumber(5); // \"11\"\n *\n * @example\n * // With multiple arguments\n * const formatName = flow(\n * (first: string, last: string) => `${first} ${last}`,\n * (name) => name.toUpperCase()\n * );\n *\n * const name = formatName(\"John\", \"Doe\"); // \"JOHN DOE\"\n *\n * @example\n * // With Option type\n * import { some, none, mapOption, flatMapOption, type Option } from \"@railway-ts/pipelines/option\";\n *\n * const safeParseInt = (radix: number) => (str: string): Option<number> => {\n * const n = Number.parseInt(str, radix);\n * return Number.isNaN(n) ? none() : some(n);\n * };\n *\n * const processString = flow(\n * (s: string) => some(s),\n * (o) => mapOption(o, (s) => s + \"0\"),\n * (o) => flatMapOption(o, safeParseInt(10))\n * );\n *\n * const option = processString(\"42\"); // Option<number> containing 420\n *\n * @example\n * // With Result type\n * import { ok, err, flatMapResult } from \"@railway-ts/pipelines/result\";\n *\n * const validatePositive = (n: number) => (n > 0 ? ok(n) : err(\"Not positive\"));\n *\n * const validateNumber = flow(\n * (n: number) => ok(n),\n * (r) => flatMapResult(r, validatePositive),\n * (r) => flatMapResult(r, (n) => ok(n * 2))\n * );\n *\n * const result = validateNumber(5); // Result<number, string> containing 10\n *\n * @param ab - The first function in the composition\n * @param functions - Additional functions to compose in sequence\n * @returns A new function that applies all the composed functions in sequence\n */\nexport function flow<A extends unknown[], B>(ab: (this: void, ...a: A) => B): (...a: A) => B;\nexport function flow<A extends unknown[], B, C>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n): (...a: A) => C;\nexport function flow<A extends unknown[], B, C, D>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n): (...a: A) => D;\nexport function flow<A extends unknown[], B, C, D, E>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n): (...a: A) => E;\nexport function flow<A extends unknown[], B, C, D, E, F>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n): (...a: A) => F;\nexport function flow<A extends unknown[], B, C, D, E, F, G>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n): (...a: A) => G;\nexport function flow<A extends unknown[], B, C, D, E, F, G, H>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n): (...a: A) => H;\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n hi: (this: void, h: H) => I,\n): (...a: A) => I;\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I, J>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n hi: (this: void, h: H) => I,\n ij: (this: void, i: I) => J,\n): (...a: A) => J;\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I, J, K>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n hi: (this: void, h: H) => I,\n ij: (this: void, i: I) => J,\n jk: (this: void, j: J) => K,\n): (...a: A) => K;\nexport function flow(...fns: [UnknownFunction, ...UnknownFunction[]]): UnknownFunction {\n if (fns.length === 1) {\n return fns[0];\n }\n\n const [first, ...rest] = fns;\n return (...args: unknown[]): unknown => {\n let result = first(...args);\n for (const fn of rest) {\n result = fn(result);\n }\n return result;\n };\n}\n","type UnknownFunction = (...params: unknown[]) => unknown;\n\n/**\n * Curries a multi-parameter function into a sequence of unary functions.\n * Enables partial application at any depth and composes cleanly with `pipe`.\n *\n * Note: This curry is unary-only at each step to ensure compatibility with `pipe` and `flow`.\n *\n * @example\n * // Basic (2-arity)\n * const add = (a: number, b: number) => a + b;\n * const add5 = curry(add)(5);\n * add5(3); // 8\n *\n * @example\n * // 3-arity and partial application\n * const multiply = (a: number, b: number, c: number) => a * b * c;\n * const curriedMultiply = curry(multiply);\n * curriedMultiply(2)(3)(4); // 24\n *\n * @example\n * // With pipe\n * import { pipe } from \"@/utils\";\n * const divide = (divisor: number, dividend: number) => dividend / divisor;\n * const result = pipe(100, curry(divide)(2), (n) => n + 1); // 51\n *\n * @example\n * // With Result validators\n * import { ok, err, flatMapResult, type Result } from \"@/index\";\n * const between = (min: number, max: number, n: number): Result<number, string> =>\n * n >= min && n <= max ? ok(n) : err(`Value must be between ${min} and ${max}`);\n * const validateAge = curry(between)(0)(120);\n * pipe(ok(25), (r) => flatMapResult(r, validateAge)); // ok(25)\n *\n * @param fn - The multi-argument function to transform into a unary curried chain\n * @returns A curried function that takes one argument at each application step\n */\n\n// 2-arity\nexport function curry<A, B, R>(fn: (a: A, b: B) => R): (a: A) => (b: B) => R;\n\n// 3-arity\nexport function curry<A, B, C, R>(fn: (a: A, b: B, c: C) => R): (a: A) => (b: B) => (c: C) => R;\n\n// 4-arity\nexport function curry<A, B, C, D, R>(fn: (a: A, b: B, c: C, d: D) => R): (a: A) => (b: B) => (c: C) => (d: D) => R;\n\n// 5-arity\nexport function curry<A, B, C, D, E, R>(\n fn: (a: A, b: B, c: C, d: D, e: E) => R,\n): (a: A) => (b: B) => (c: C) => (d: D) => (e: E) => R;\n\n// Implementation\nexport function curry<T extends UnknownFunction>(fn: T): UnknownFunction {\n const arity = fn.length;\n\n return function curried(...args: unknown[]): unknown {\n if (args.length >= arity) {\n return (fn as UnknownFunction)(...args);\n }\n\n return function (...nextArgs: unknown[]): unknown {\n return curried(...args, ...nextArgs);\n };\n };\n}\n","type UnknownFunction = (...params: unknown[]) => unknown;\n\n/**\n * Uncurries a curried unary function chain back into a multi-argument function.\n * Inverse of `curry`. Useful when calling curried APIs with positional arguments.\n *\n * Note: Expects strictly unary nesting (the shape produced by `curry`).\n *\n * @example\n * // 2-arity\n * const addCurried = (a: number) => (b: number) => a + b;\n * const add = uncurry(addCurried);\n * add(5, 3); // 8\n *\n * @example\n * // 3-arity\n * const multiplyCurried = (a: number) => (b: number) => (c: number) => a * b * c;\n * const multiply = uncurry(multiplyCurried);\n * multiply(2, 3, 4); // 24\n *\n * @example\n * // Round-trip with curry\n * import { curry } from \"@railway-ts/pipelines\";\n * const divide = (divisor: number, dividend: number) => dividend / divisor;\n * const divideCurried = curry(divide);\n * const divideUncurried = uncurry(divideCurried);\n * divideUncurried(2, 100); // 50\n *\n * @param fn - A curried unary function chain (e.g., a => b => c => r)\n * @returns A multi-argument function equivalent to applying the curried chain in sequence\n */\n\n// Overloads ordered from most specific (5-arity) to least specific (2-arity)\n// This ensures TypeScript matches the correct overload\n\n// 5-arity\nexport function uncurry<A, B, C, D, E, R>(\n fn: (a: A) => (b: B) => (c: C) => (d: D) => (e: E) => R,\n): (a: A, b: B, c: C, d: D, e: E) => R;\n\n// 5-arity\nexport function uncurry<A, B, C, D, E, R>(\n fn: (a: A) => (b: B) => (c: C) => (d: D) => (e: E) => R,\n): (a: A, b: B, c: C, d: D, e: E) => R;\n\n// 4-arity\nexport function uncurry<A, B, C, D, R>(fn: (a: A) => (b: B) => (c: C) => (d: D) => R): (a: A, b: B, c: C, d: D) => R;\n\n// 3-arity\nexport function uncurry<A, B, C, R>(fn: (a: A) => (b: B) => (c: C) => R): (a: A, b: B, c: C) => R;\n\n// 2-arity\nexport function uncurry<A, B, R>(fn: (a: A) => (b: B) => R): (a: A, b: B) => R;\n\n// 1-arity (identity - technically not curried, but allows for consistent API)\nexport function uncurry<A, R>(fn: (a: A) => R): (a: A) => R;\n\n// Implementation - looser types allow overloads to work correctly\nexport function uncurry(fn: unknown): unknown {\n return function uncurried(...args: unknown[]): unknown {\n // Apply arguments sequentially to the curried function chain\n let result = fn;\n\n for (const arg of args) {\n result = (result as UnknownFunction)(arg);\n }\n\n return result;\n };\n}\n","type UnknownFunction = (...params: unknown[]) => unknown;\n\n/**\n * Transforms a multi-argument function into one that accepts a single tuple argument.\n * This makes multi-arg functions composable in `pipe`/`flow` when your data is a tuple.\n *\n * @example\n * // Basic\n * const add = (a: number, b: number) => a + b;\n * const tupledAdd = tupled(add);\n * tupledAdd([5, 3]); // 8\n *\n * @example\n * // With pipe (tuple input)\n * import { pipe } from \"@/utils\";\n * const distance = (x: number, y: number) => Math.hypot(x, y);\n * pipe([3, 4] as [number, number], tupled(distance)); // 5\n *\n * @example\n * // With Result\n * import { ok, err, flatMapResult, mapResult, type Result } from \"@railway-ts/pipelines/result\";\n * const divide = (dividend: number, divisor: number): Result<number, string> =>\n * divisor === 0 ? err(\"Division by zero\") : ok(dividend / divisor);\n * const tupledDivide = tupled(divide);\n * pipe(ok<[number, number], string>([10, 2]),\n * (r) => flatMapResult(r, tupledDivide),\n * (r) => mapResult(r, (n) => n * 2)\n * ); // ok(10)\n *\n * @example\n * // With Option\n * import { some, none, flatMapOption, type Option } from \"@railway-ts/pipelines/option\";\n * const safeParse = (str: string, radix: number): Option<number> => {\n * const n = Number.parseInt(str, radix);\n * return Number.isNaN(n) ? none() : some(n);\n * };\n * const tupledParse = tupled(safeParse);\n * flatMapOption(some([\"FF\", 16] as [string, number]), tupledParse); // some(255)\n *\n * @param fn - A function taking positional arguments to be adapted to a single tuple argument\n * @returns A function that takes a tuple and applies it to `fn` as positional args\n */\n\n// 2-arity\nexport function tupled<A, B, R>(fn: (a: A, b: B) => R): (args: [A, B]) => R;\n\n// 3-arity\nexport function tupled<A, B, C, R>(fn: (a: A, b: B, c: C) => R): (args: [A, B, C]) => R;\n\n// 4-arity\nexport function tupled<A, B, C, D, R>(fn: (a: A, b: B, c: C, d: D) => R): (args: [A, B, C, D]) => R;\n\n// 5-arity\nexport function tupled<A, B, C, D, E, R>(fn: (a: A, b: B, c: C, d: D, e: E) => R): (args: [A, B, C, D, E]) => R;\n\n// Implementation\nexport function tupled<T extends UnknownFunction>(fn: T): (args: unknown[]) => unknown {\n return function tupledFn(args: unknown[]): unknown {\n return fn(...args);\n };\n}\n","type UnknownFunction = (...params: unknown[]) => unknown;\n\n/**\n * Transforms a function that accepts a tuple into a multi-argument function.\n * Inverse of `tupled`. Useful when callers have positional arguments but your core API uses tuples.\n *\n * @example\n * // Basic\n * const tupledAdd = ([a, b]: [number, number]) => a + b;\n * const add = untupled(tupledAdd);\n * add(5, 3); // 8\n *\n * @example\n * // 3-arity\n * const sum3Tupled = ([a, b, c]: [number, number, number]) => a + b + c;\n * const sum3 = untupled(sum3Tupled);\n * sum3(1, 2, 3); // 6\n *\n * @example\n * // With Result\n * import { ok, err, flatMapResult, type Result } from \"@railway-ts/pipelines/result\";\n * const validateRange = ([min, max, value]: [number, number, number]): Result<number, string> =>\n * value >= min && value <= max ? ok(value) : err(`Value ${value} not between ${min} and ${max}`);\n * const validate = untupled(validateRange);\n * flatMapResult(ok(50), (n) => validate(0, 100, n)); // ok(50)\n *\n * @example\n * // With Option\n * import { some, none, type Option } from \"@railway-ts/pipelines/option\";\n * const parsePair = ([x, y]: [string, string]): Option<number> => {\n * const a = Number(x), b = Number(y);\n * return Number.isNaN(a) || Number.isNaN(b) ? none() : some(a + b);\n * };\n * const parse = untupled(parsePair);\n * parse(\"2\", \"3\"); // some(5)\n *\n * @param fn - A function that accepts a tuple of arguments\n * @returns A function that accepts the same arguments positionally\n */\n\n// 2-arity\nexport function untupled<A, B, R>(fn: (args: [A, B]) => R): (a: A, b: B) => R;\n\n// 3-arity\nexport function untupled<A, B, C, R>(fn: (args: [A, B, C]) => R): (a: A, b: B, c: C) => R;\n\n// 4-arity\nexport function untupled<A, B, C, D, R>(fn: (args: [A, B, C, D]) => R): (a: A, b: B, c: C, d: D) => R;\n\n// 5-arity\nexport function untupled<A, B, C, D, E, R>(fn: (args: [A, B, C, D, E]) => R): (a: A, b: B, c: C, d: D, e: E) => R;\n\n// Implementation\nexport function untupled<T extends UnknownFunction>(fn: T): UnknownFunction {\n return function untupledFn(...args: unknown[]): unknown {\n return fn(args);\n };\n}\n"]}
1
+ {"version":3,"sources":["../../src/composition/pipe.ts","../../src/composition/flow.ts","../../src/composition/pipe-async.ts","../../src/composition/flow-async.ts","../../src/composition/curry.ts","../../src/composition/uncurry.ts","../../src/composition/tupled.ts","../../src/composition/untupled.ts"],"names":[],"mappings":";;;AA8GO,SAAS,IAAA,CAAK,UAAmB,GAAA,EAAiC;AACvE,EAAA,IAAI,MAAA,GAAS,KAAA;AACb,EAAA,KAAA,MAAW,MAAM,GAAA,EAAK;AACpB,IAAA,MAAA,GAAS,GAAG,MAAM,CAAA;AAAA,EACpB;AACA,EAAA,OAAO,MAAA;AACT;;;ACkBO,SAAS,QAAQ,GAAA,EAA+D;AACrF,EAAA,IAAI,GAAA,CAAI,WAAW,CAAA,EAAG;AACpB,IAAA,OAAO,IAAI,CAAC,CAAA;AAAA,EACd;AAEA,EAAA,MAAM,CAAC,KAAA,EAAO,GAAG,IAAI,CAAA,GAAI,GAAA;AACzB,EAAA,OAAO,IAAI,IAAA,KAA6B;AACtC,IAAA,IAAI,MAAA,GAAS,KAAA,CAAM,GAAG,IAAI,CAAA;AAC1B,IAAA,KAAA,MAAW,MAAM,IAAA,EAAM;AACrB,MAAA,MAAA,GAAS,GAAG,MAAM,CAAA;AAAA,IACpB;AACA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;;;AC5CA,eAAsB,SAAA,CAAU,MAAe,GAAA,EAA0C;AACvF,EAAA,IAAI,SAAS,MAAM,CAAA;AACnB,EAAA,KAAA,MAAW,MAAM,GAAA,EAAK;AACpB,IAAA,MAAA,GAAS,MAAM,GAAG,MAAM,CAAA;AAAA,EAC1B;AACA,EAAA,OAAO,MAAA;AACT;;;ACHO,SAAS,SAAA,CACd,UACG,GAAA,EACuC;AAC1C,EAAA,OAAO,UAAU,IAAA,KAAoB;AACnC,IAAA,IAAI,MAAA,GAAS,MAAM,KAAA,CAAM,GAAG,IAAI,CAAA;AAChC,IAAA,KAAA,MAAW,MAAM,GAAA,EAAK;AACpB,MAAA,MAAA,GAAS,MAAM,GAAG,MAAM,CAAA;AAAA,IAC1B;AACA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;;;AChEO,SAAS,MAAiC,EAAA,EAAwB;AACvE,EAAA,MAAM,QAAQ,EAAA,CAAG,MAAA;AAEjB,EAAA,OAAO,SAAS,WAAW,IAAA,EAA0B;AACnD,IAAA,IAAI,IAAA,CAAK,UAAU,KAAA,EAAO;AACxB,MAAA,OAAQ,EAAA,CAAuB,GAAG,IAAI,CAAA;AAAA,IACxC;AAEA,IAAA,OAAO,YAAa,QAAA,EAA8B;AAChD,MAAA,OAAO,OAAA,CAAQ,GAAG,IAAA,EAAM,GAAG,QAAQ,CAAA;AAAA,IACrC,CAAA;AAAA,EACF,CAAA;AACF;;;ACPO,SAAS,QAAQ,EAAA,EAAsB;AAC5C,EAAA,OAAO,SAAS,aAAa,IAAA,EAA0B;AAErD,IAAA,IAAI,MAAA,GAAS,EAAA;AAEb,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,MAAA,GAAU,OAA2B,GAAG,CAAA;AAAA,IAC1C;AAEA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;;;ACbO,SAAS,OAAkC,EAAA,EAAqC;AACrF,EAAA,OAAO,SAAS,SAAS,IAAA,EAA0B;AACjD,IAAA,OAAO,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,EACnB,CAAA;AACF;;;ACPO,SAAS,SAAoC,EAAA,EAAwB;AAC1E,EAAA,OAAO,SAAS,cAAc,IAAA,EAA0B;AACtD,IAAA,OAAO,GAAG,IAAI,CAAA;AAAA,EAChB,CAAA;AACF","file":"index.cjs","sourcesContent":["import type { UnknownFunction } from './types';\n\n/**\n * Pipes a value through a series of functions, from left to right.\n * Each function receives the output of the previous function.\n * Unlike flow, pipe immediately executes the functions with the provided initial value.\n *\n * @example\n * // Basic usage\n * const result = pipe(\n * 5,\n * (n) => n * 2, // 10\n * (n) => n + 1, // 11\n * (n) => n.toString() // \"11\"\n * );\n * // result: \"11\"\n *\n * @example\n * // With Option\n * import { some, mapOption } from \"@railway-ts/pipelines/option\";\n *\n * const optionResult = pipe(\n * some(5),\n * (o) => mapOption(o, (n) => n * 2),\n * (o) => mapOption(o, (n) => n.toString())\n * );\n * // optionResult: Option<string> containing \"10\"\n *\n * @example\n * // With Result\n * import { ok, mapResult } from \"@railway-ts/pipelines/result\";\n *\n * const resultValue = pipe(\n * ok(5),\n * (r) => mapResult(r, (n) => n * 2),\n * (r) => mapResult(r, (n) => n.toString())\n * );\n * // resultValue: Result<string, never> containing \"10\"\n *\n * @param a - The initial value to pipe through the functions\n * @param ab - The first function to apply to the initial value\n * @param functions - Additional functions to apply in sequence\n * @returns The final result after applying all functions\n */\n\nexport function pipe<A, B>(a: A, ab: (this: void, a: A) => B): B;\nexport function pipe<A, B, C>(a: A, ab: (this: void, a: A) => B, bc: (this: void, b: B) => C): C;\nexport function pipe<A, B, C, D>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n): D;\nexport function pipe<A, B, C, D, E>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n): E;\nexport function pipe<A, B, C, D, E, F>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n): F;\nexport function pipe<A, B, C, D, E, F, G>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n): G;\nexport function pipe<A, B, C, D, E, F, G, H>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n): H;\nexport function pipe<A, B, C, D, E, F, G, H, I>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n hi: (this: void, h: H) => I,\n): I;\nexport function pipe<A, B, C, D, E, F, G, H, I, J>(\n a: A,\n ab: (this: void, a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n hi: (this: void, h: H) => I,\n ij: (this: void, i: I) => J,\n): J;\nexport function pipe(value: unknown, ...fns: UnknownFunction[]): unknown {\n let result = value;\n for (const fn of fns) {\n result = fn(result);\n }\n return result;\n}\n","import type { UnknownFunction } from './types';\n\n/**\n * Creates a new function that is the composition of the provided functions, applied from left to right.\n * Unlike pipe, flow doesn't immediately execute the functions but returns a new function that,\n * when called, will run the composed functions in sequence.\n *\n * @example\n * // Basic usage\n * const processNumber = flow(\n * (n: number) => n * 2,\n * (n) => n + 1,\n * (n) => n.toString()\n * );\n *\n * const result = processNumber(5); // \"11\"\n *\n * @example\n * // With multiple arguments\n * const formatName = flow(\n * (first: string, last: string) => `${first} ${last}`,\n * (name) => name.toUpperCase()\n * );\n *\n * const name = formatName(\"John\", \"Doe\"); // \"JOHN DOE\"\n *\n * @example\n * // With Option type\n * import { some, none, mapOption, flatMapOption, type Option } from \"@railway-ts/pipelines/option\";\n *\n * const safeParseInt = (radix: number) => (str: string): Option<number> => {\n * const n = Number.parseInt(str, radix);\n * return Number.isNaN(n) ? none() : some(n);\n * };\n *\n * const processString = flow(\n * (s: string) => some(s),\n * (o) => mapOption(o, (s) => s + \"0\"),\n * (o) => flatMapOption(o, safeParseInt(10))\n * );\n *\n * const option = processString(\"42\"); // Option<number> containing 420\n *\n * @example\n * // With Result type\n * import { ok, err, flatMapResult } from \"@railway-ts/pipelines/result\";\n *\n * const validatePositive = (n: number) => (n > 0 ? ok(n) : err(\"Not positive\"));\n *\n * const validateNumber = flow(\n * (n: number) => ok(n),\n * (r) => flatMapResult(r, validatePositive),\n * (r) => flatMapResult(r, (n) => ok(n * 2))\n * );\n *\n * const result = validateNumber(5); // Result<number, string> containing 10\n *\n * @param ab - The first function in the composition\n * @param functions - Additional functions to compose in sequence\n * @returns A new function that applies all the composed functions in sequence\n */\nexport function flow<A extends unknown[], B>(ab: (this: void, ...a: A) => B): (...a: A) => B;\nexport function flow<A extends unknown[], B, C>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n): (...a: A) => C;\nexport function flow<A extends unknown[], B, C, D>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n): (...a: A) => D;\nexport function flow<A extends unknown[], B, C, D, E>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n): (...a: A) => E;\nexport function flow<A extends unknown[], B, C, D, E, F>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n): (...a: A) => F;\nexport function flow<A extends unknown[], B, C, D, E, F, G>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n): (...a: A) => G;\nexport function flow<A extends unknown[], B, C, D, E, F, G, H>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n): (...a: A) => H;\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n hi: (this: void, h: H) => I,\n): (...a: A) => I;\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I, J>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n hi: (this: void, h: H) => I,\n ij: (this: void, i: I) => J,\n): (...a: A) => J;\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I, J, K>(\n ab: (this: void, ...a: A) => B,\n bc: (this: void, b: B) => C,\n cd: (this: void, c: C) => D,\n de: (this: void, d: D) => E,\n ef: (this: void, e: E) => F,\n fg: (this: void, f: F) => G,\n gh: (this: void, g: G) => H,\n hi: (this: void, h: H) => I,\n ij: (this: void, i: I) => J,\n jk: (this: void, j: J) => K,\n): (...a: A) => K;\nexport function flow(...fns: [UnknownFunction, ...UnknownFunction[]]): UnknownFunction {\n if (fns.length === 1) {\n return fns[0];\n }\n\n const [first, ...rest] = fns;\n return (...args: unknown[]): unknown => {\n let result = first(...args);\n for (const fn of rest) {\n result = fn(result);\n }\n return result;\n };\n}\n","import type { MaybeAsync, UnknownFunction } from './types';\n\n/**\n * Pipes a value through a series of potentially async functions, from left to right.\n * Each function receives the awaited output of the previous function.\n * Unlike pipe, pipeAsync awaits between each step, enabling async composition.\n *\n * @example\n * // Basic async usage\n * const result = await pipeAsync(\n * 5,\n * async (n) => n * 2, // 10\n * (n) => n + 1, // 11\n * async (n) => n.toString() // \"11\"\n * );\n * // result: \"11\"\n *\n * @example\n * // With Result and curried helpers\n * import { ok, flatMapWith, mapWith } from \"@railway-ts/pipelines/result\";\n *\n * const result = await pipeAsync(\n * ok(5),\n * flatMapWith(async (n) => ok(n * 2)),\n * mapWith((n) => n.toString())\n * );\n * // result: Result<string, never> containing \"10\"\n *\n * @param a - The initial value (or Promise) to pipe through the functions\n * @param ab - The first function to apply to the initial value\n * @param functions - Additional functions to apply in sequence\n * @returns A Promise of the final result after applying all functions\n */\n\nexport function pipeAsync<A, B>(a: MaybeAsync<A>, ab: (this: void, a: A) => MaybeAsync<B>): Promise<B>;\nexport function pipeAsync<A, B, C>(\n a: MaybeAsync<A>,\n ab: (this: void, a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n): Promise<C>;\nexport function pipeAsync<A, B, C, D>(\n a: MaybeAsync<A>,\n ab: (this: void, a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n): Promise<D>;\nexport function pipeAsync<A, B, C, D, E>(\n a: MaybeAsync<A>,\n ab: (this: void, a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n): Promise<E>;\nexport function pipeAsync<A, B, C, D, E, F>(\n a: MaybeAsync<A>,\n ab: (this: void, a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n ef: (this: void, e: E) => MaybeAsync<F>,\n): Promise<F>;\nexport function pipeAsync<A, B, C, D, E, F, G>(\n a: MaybeAsync<A>,\n ab: (this: void, a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n ef: (this: void, e: E) => MaybeAsync<F>,\n fg: (this: void, f: F) => MaybeAsync<G>,\n): Promise<G>;\nexport function pipeAsync<A, B, C, D, E, F, G, H>(\n a: MaybeAsync<A>,\n ab: (this: void, a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n ef: (this: void, e: E) => MaybeAsync<F>,\n fg: (this: void, f: F) => MaybeAsync<G>,\n gh: (this: void, g: G) => MaybeAsync<H>,\n): Promise<H>;\nexport function pipeAsync<A, B, C, D, E, F, G, H, I>(\n a: MaybeAsync<A>,\n ab: (this: void, a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n ef: (this: void, e: E) => MaybeAsync<F>,\n fg: (this: void, f: F) => MaybeAsync<G>,\n gh: (this: void, g: G) => MaybeAsync<H>,\n hi: (this: void, h: H) => MaybeAsync<I>,\n): Promise<I>;\nexport function pipeAsync<A, B, C, D, E, F, G, H, I, J>(\n a: MaybeAsync<A>,\n ab: (this: void, a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n ef: (this: void, e: E) => MaybeAsync<F>,\n fg: (this: void, f: F) => MaybeAsync<G>,\n gh: (this: void, g: G) => MaybeAsync<H>,\n hi: (this: void, h: H) => MaybeAsync<I>,\n ij: (this: void, i: I) => MaybeAsync<J>,\n): Promise<J>;\nexport async function pipeAsync(a: unknown, ...fns: UnknownFunction[]): Promise<unknown> {\n let result = await a;\n for (const fn of fns) {\n result = await fn(result);\n }\n return result;\n}\n","import type { MaybeAsync, UnknownFunction } from './types';\n\n/**\n * Creates a new function that is the async composition of the provided functions, applied from left to right.\n * Unlike flow, flowAsync awaits between each step, enabling async composition.\n * The returned function always returns a Promise.\n *\n * @example\n * // Basic async usage\n * const processNumber = flowAsync(\n * async (n: number) => n * 2,\n * (n) => n + 1,\n * async (n) => n.toString()\n * );\n *\n * const result = await processNumber(5); // \"11\"\n *\n * @example\n * // With Result and curried helpers\n * import { ok, flatMapWith, mapWith } from \"@railway-ts/pipelines/result\";\n *\n * const process = flowAsync(\n * (n: number) => ok(n),\n * flatMapWith(async (n) => ok(n * 2)),\n * mapWith((n) => n.toString())\n * );\n *\n * const result = await process(5); // Result<string, never> containing \"10\"\n *\n * @param ab - The first function in the composition\n * @param functions - Additional functions to compose in sequence\n * @returns A new function that applies all the composed functions in sequence, returning a Promise\n */\nexport function flowAsync<A extends unknown[], B>(ab: (this: void, ...a: A) => MaybeAsync<B>): (...a: A) => Promise<B>;\nexport function flowAsync<A extends unknown[], B, C>(\n ab: (this: void, ...a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n): (...a: A) => Promise<C>;\nexport function flowAsync<A extends unknown[], B, C, D>(\n ab: (this: void, ...a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n): (...a: A) => Promise<D>;\nexport function flowAsync<A extends unknown[], B, C, D, E>(\n ab: (this: void, ...a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n): (...a: A) => Promise<E>;\nexport function flowAsync<A extends unknown[], B, C, D, E, F>(\n ab: (this: void, ...a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n ef: (this: void, e: E) => MaybeAsync<F>,\n): (...a: A) => Promise<F>;\nexport function flowAsync<A extends unknown[], B, C, D, E, F, G>(\n ab: (this: void, ...a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n ef: (this: void, e: E) => MaybeAsync<F>,\n fg: (this: void, f: F) => MaybeAsync<G>,\n): (...a: A) => Promise<G>;\nexport function flowAsync<A extends unknown[], B, C, D, E, F, G, H>(\n ab: (this: void, ...a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n ef: (this: void, e: E) => MaybeAsync<F>,\n fg: (this: void, f: F) => MaybeAsync<G>,\n gh: (this: void, g: G) => MaybeAsync<H>,\n): (...a: A) => Promise<H>;\nexport function flowAsync<A extends unknown[], B, C, D, E, F, G, H, I>(\n ab: (this: void, ...a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n ef: (this: void, e: E) => MaybeAsync<F>,\n fg: (this: void, f: F) => MaybeAsync<G>,\n gh: (this: void, g: G) => MaybeAsync<H>,\n hi: (this: void, h: H) => MaybeAsync<I>,\n): (...a: A) => Promise<I>;\nexport function flowAsync<A extends unknown[], B, C, D, E, F, G, H, I, J>(\n ab: (this: void, ...a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n ef: (this: void, e: E) => MaybeAsync<F>,\n fg: (this: void, f: F) => MaybeAsync<G>,\n gh: (this: void, g: G) => MaybeAsync<H>,\n hi: (this: void, h: H) => MaybeAsync<I>,\n ij: (this: void, i: I) => MaybeAsync<J>,\n): (...a: A) => Promise<J>;\nexport function flowAsync<A extends unknown[], B, C, D, E, F, G, H, I, J, K>(\n ab: (this: void, ...a: A) => MaybeAsync<B>,\n bc: (this: void, b: B) => MaybeAsync<C>,\n cd: (this: void, c: C) => MaybeAsync<D>,\n de: (this: void, d: D) => MaybeAsync<E>,\n ef: (this: void, e: E) => MaybeAsync<F>,\n fg: (this: void, f: F) => MaybeAsync<G>,\n gh: (this: void, g: G) => MaybeAsync<H>,\n hi: (this: void, h: H) => MaybeAsync<I>,\n ij: (this: void, i: I) => MaybeAsync<J>,\n jk: (this: void, j: J) => MaybeAsync<K>,\n): (...a: A) => Promise<K>;\nexport function flowAsync(\n first: (...args: unknown[]) => unknown,\n ...fns: UnknownFunction[]\n): (...args: unknown[]) => Promise<unknown> {\n return async (...args: unknown[]) => {\n let result = await first(...args);\n for (const fn of fns) {\n result = await fn(result);\n }\n return result;\n };\n}\n","import type { UnknownFunction } from './types';\n\n/**\n * Curries a multi-parameter function into a sequence of unary functions.\n * Enables partial application at any depth and composes cleanly with `pipe`.\n *\n * Note: This curry is unary-only at each step to ensure compatibility with `pipe` and `flow`.\n *\n * @example\n * // Basic (2-arity)\n * const add = (a: number, b: number) => a + b;\n * const add5 = curry(add)(5);\n * add5(3); // 8\n *\n * @example\n * // 3-arity and partial application\n * const multiply = (a: number, b: number, c: number) => a * b * c;\n * const curriedMultiply = curry(multiply);\n * curriedMultiply(2)(3)(4); // 24\n *\n * @example\n * // With pipe\n * import { pipe } from \"@/utils\";\n * const divide = (divisor: number, dividend: number) => dividend / divisor;\n * const result = pipe(100, curry(divide)(2), (n) => n + 1); // 51\n *\n * @example\n * // With Result validators\n * import { ok, err, flatMap, type Result } from \"@/result\";\n * const between = (min: number, max: number, n: number): Result<number, string> =>\n * n >= min && n <= max ? ok(n) : err(`Value must be between ${min} and ${max}`);\n * const validateAge = curry(between)(0)(120);\n * pipe(ok(25), (r) => flatMap(r, validateAge)); // ok(25)\n *\n * @param fn - The multi-argument function to transform into a unary curried chain\n * @returns A curried function that takes one argument at each application step\n */\n\n// 2-arity\nexport function curry<A, B, R>(fn: (a: A, b: B) => R): (a: A) => (b: B) => R;\n\n// 3-arity\nexport function curry<A, B, C, R>(fn: (a: A, b: B, c: C) => R): (a: A) => (b: B) => (c: C) => R;\n\n// 4-arity\nexport function curry<A, B, C, D, R>(fn: (a: A, b: B, c: C, d: D) => R): (a: A) => (b: B) => (c: C) => (d: D) => R;\n\n// 5-arity\nexport function curry<A, B, C, D, E, R>(\n fn: (a: A, b: B, c: C, d: D, e: E) => R,\n): (a: A) => (b: B) => (c: C) => (d: D) => (e: E) => R;\n\n// Implementation\nexport function curry<T extends UnknownFunction>(fn: T): UnknownFunction {\n const arity = fn.length;\n\n return function curried(...args: unknown[]): unknown {\n if (args.length >= arity) {\n return (fn as UnknownFunction)(...args);\n }\n\n return function (...nextArgs: unknown[]): unknown {\n return curried(...args, ...nextArgs);\n };\n };\n}\n","import type { UnknownFunction } from './types';\n\n/**\n * Uncurries a curried unary function chain back into a multi-argument function.\n * Inverse of `curry`. Useful when calling curried APIs with positional arguments.\n *\n * Note: Expects strictly unary nesting (the shape produced by `curry`).\n *\n * @example\n * // 2-arity\n * const addCurried = (a: number) => (b: number) => a + b;\n * const add = uncurry(addCurried);\n * add(5, 3); // 8\n *\n * @example\n * // 3-arity\n * const multiplyCurried = (a: number) => (b: number) => (c: number) => a * b * c;\n * const multiply = uncurry(multiplyCurried);\n * multiply(2, 3, 4); // 24\n *\n * @example\n * // Round-trip with curry\n * import { curry } from \"@railway-ts/pipelines\";\n * const divide = (divisor: number, dividend: number) => dividend / divisor;\n * const divideCurried = curry(divide);\n * const divideUncurried = uncurry(divideCurried);\n * divideUncurried(2, 100); // 50\n *\n * @param fn - A curried unary function chain (e.g., a => b => c => r)\n * @returns A multi-argument function equivalent to applying the curried chain in sequence\n */\n\n// Overloads ordered from most specific (5-arity) to least specific (2-arity)\n// This ensures TypeScript matches the correct overload\n\n// 5-arity\nexport function uncurry<A, B, C, D, E, R>(\n fn: (a: A) => (b: B) => (c: C) => (d: D) => (e: E) => R,\n): (a: A, b: B, c: C, d: D, e: E) => R;\n\n// 5-arity\nexport function uncurry<A, B, C, D, E, R>(\n fn: (a: A) => (b: B) => (c: C) => (d: D) => (e: E) => R,\n): (a: A, b: B, c: C, d: D, e: E) => R;\n\n// 4-arity\nexport function uncurry<A, B, C, D, R>(fn: (a: A) => (b: B) => (c: C) => (d: D) => R): (a: A, b: B, c: C, d: D) => R;\n\n// 3-arity\nexport function uncurry<A, B, C, R>(fn: (a: A) => (b: B) => (c: C) => R): (a: A, b: B, c: C) => R;\n\n// 2-arity\nexport function uncurry<A, B, R>(fn: (a: A) => (b: B) => R): (a: A, b: B) => R;\n\n// 1-arity (identity - technically not curried, but allows for consistent API)\nexport function uncurry<A, R>(fn: (a: A) => R): (a: A) => R;\n\n// Implementation - looser types allow overloads to work correctly\nexport function uncurry(fn: unknown): unknown {\n return function uncurried(...args: unknown[]): unknown {\n // Apply arguments sequentially to the curried function chain\n let result = fn;\n\n for (const arg of args) {\n result = (result as UnknownFunction)(arg);\n }\n\n return result;\n };\n}\n","import type { UnknownFunction } from './types';\n\n/**\n * Transforms a multi-argument function into one that accepts a single tuple argument.\n * This makes multi-arg functions composable in `pipe`/`flow` when your data is a tuple.\n *\n * @example\n * // Basic\n * const add = (a: number, b: number) => a + b;\n * const tupledAdd = tupled(add);\n * tupledAdd([5, 3]); // 8\n *\n * @example\n * // With pipe (tuple input)\n * import { pipe } from \"@/utils\";\n * const distance = (x: number, y: number) => Math.hypot(x, y);\n * pipe([3, 4] as [number, number], tupled(distance)); // 5\n *\n * @example\n * // With Result\n * import { ok, err, flatMapResult, mapResult, type Result } from \"@railway-ts/pipelines/result\";\n * const divide = (dividend: number, divisor: number): Result<number, string> =>\n * divisor === 0 ? err(\"Division by zero\") : ok(dividend / divisor);\n * const tupledDivide = tupled(divide);\n * pipe(ok<[number, number], string>([10, 2]),\n * (r) => flatMapResult(r, tupledDivide),\n * (r) => mapResult(r, (n) => n * 2)\n * ); // ok(10)\n *\n * @example\n * // With Option\n * import { some, none, flatMapOption, type Option } from \"@railway-ts/pipelines/option\";\n * const safeParse = (str: string, radix: number): Option<number> => {\n * const n = Number.parseInt(str, radix);\n * return Number.isNaN(n) ? none() : some(n);\n * };\n * const tupledParse = tupled(safeParse);\n * flatMapOption(some([\"FF\", 16] as [string, number]), tupledParse); // some(255)\n *\n * @param fn - A function taking positional arguments to be adapted to a single tuple argument\n * @returns A function that takes a tuple and applies it to `fn` as positional args\n */\n\n// 2-arity\nexport function tupled<A, B, R>(fn: (a: A, b: B) => R): (args: [A, B]) => R;\n\n// 3-arity\nexport function tupled<A, B, C, R>(fn: (a: A, b: B, c: C) => R): (args: [A, B, C]) => R;\n\n// 4-arity\nexport function tupled<A, B, C, D, R>(fn: (a: A, b: B, c: C, d: D) => R): (args: [A, B, C, D]) => R;\n\n// 5-arity\nexport function tupled<A, B, C, D, E, R>(fn: (a: A, b: B, c: C, d: D, e: E) => R): (args: [A, B, C, D, E]) => R;\n\n// Implementation\nexport function tupled<T extends UnknownFunction>(fn: T): (args: unknown[]) => unknown {\n return function tupledFn(args: unknown[]): unknown {\n return fn(...args);\n };\n}\n","import type { UnknownFunction } from './types';\n\n/**\n * Transforms a function that accepts a tuple into a multi-argument function.\n * Inverse of `tupled`. Useful when callers have positional arguments but your core API uses tuples.\n *\n * @example\n * // Basic\n * const tupledAdd = ([a, b]: [number, number]) => a + b;\n * const add = untupled(tupledAdd);\n * add(5, 3); // 8\n *\n * @example\n * // 3-arity\n * const sum3Tupled = ([a, b, c]: [number, number, number]) => a + b + c;\n * const sum3 = untupled(sum3Tupled);\n * sum3(1, 2, 3); // 6\n *\n * @example\n * // With Result\n * import { ok, err, flatMapResult, type Result } from \"@railway-ts/pipelines/result\";\n * const validateRange = ([min, max, value]: [number, number, number]): Result<number, string> =>\n * value >= min && value <= max ? ok(value) : err(`Value ${value} not between ${min} and ${max}`);\n * const validate = untupled(validateRange);\n * flatMapResult(ok(50), (n) => validate(0, 100, n)); // ok(50)\n *\n * @example\n * // With Option\n * import { some, none, type Option } from \"@railway-ts/pipelines/option\";\n * const parsePair = ([x, y]: [string, string]): Option<number> => {\n * const a = Number(x), b = Number(y);\n * return Number.isNaN(a) || Number.isNaN(b) ? none() : some(a + b);\n * };\n * const parse = untupled(parsePair);\n * parse(\"2\", \"3\"); // some(5)\n *\n * @param fn - A function that accepts a tuple of arguments\n * @returns A function that accepts the same arguments positionally\n */\n\n// 2-arity\nexport function untupled<A, B, R>(fn: (args: [A, B]) => R): (a: A, b: B) => R;\n\n// 3-arity\nexport function untupled<A, B, C, R>(fn: (args: [A, B, C]) => R): (a: A, b: B, c: C) => R;\n\n// 4-arity\nexport function untupled<A, B, C, D, R>(fn: (args: [A, B, C, D]) => R): (a: A, b: B, c: C, d: D) => R;\n\n// 5-arity\nexport function untupled<A, B, C, D, E, R>(fn: (args: [A, B, C, D, E]) => R): (a: A, b: B, c: C, d: D, e: E) => R;\n\n// Implementation\nexport function untupled<T extends UnknownFunction>(fn: T): UnknownFunction {\n return function untupledFn(...args: unknown[]): unknown {\n return fn(args);\n };\n}\n"]}
@@ -1,3 +1,6 @@
1
+ type MaybeAsync<T> = T | Promise<T>;
2
+ type UnknownFunction = (...params: unknown[]) => unknown;
3
+
1
4
  /**
2
5
  * Pipes a value through a series of functions, from left to right.
3
6
  * Each function receives the output of the previous function.
@@ -120,6 +123,89 @@ declare function flow<A extends unknown[], B, C, D, E, F, G, H, I>(ab: (this: vo
120
123
  declare function flow<A extends unknown[], B, C, D, E, F, G, H, I, J>(ab: (this: void, ...a: A) => B, bc: (this: void, b: B) => C, cd: (this: void, c: C) => D, de: (this: void, d: D) => E, ef: (this: void, e: E) => F, fg: (this: void, f: F) => G, gh: (this: void, g: G) => H, hi: (this: void, h: H) => I, ij: (this: void, i: I) => J): (...a: A) => J;
121
124
  declare function flow<A extends unknown[], B, C, D, E, F, G, H, I, J, K>(ab: (this: void, ...a: A) => B, bc: (this: void, b: B) => C, cd: (this: void, c: C) => D, de: (this: void, d: D) => E, ef: (this: void, e: E) => F, fg: (this: void, f: F) => G, gh: (this: void, g: G) => H, hi: (this: void, h: H) => I, ij: (this: void, i: I) => J, jk: (this: void, j: J) => K): (...a: A) => K;
122
125
 
126
+ /**
127
+ * Pipes a value through a series of potentially async functions, from left to right.
128
+ * Each function receives the awaited output of the previous function.
129
+ * Unlike pipe, pipeAsync awaits between each step, enabling async composition.
130
+ *
131
+ * @example
132
+ * // Basic async usage
133
+ * const result = await pipeAsync(
134
+ * 5,
135
+ * async (n) => n * 2, // 10
136
+ * (n) => n + 1, // 11
137
+ * async (n) => n.toString() // "11"
138
+ * );
139
+ * // result: "11"
140
+ *
141
+ * @example
142
+ * // With Result and curried helpers
143
+ * import { ok, flatMapWith, mapWith } from "@railway-ts/pipelines/result";
144
+ *
145
+ * const result = await pipeAsync(
146
+ * ok(5),
147
+ * flatMapWith(async (n) => ok(n * 2)),
148
+ * mapWith((n) => n.toString())
149
+ * );
150
+ * // result: Result<string, never> containing "10"
151
+ *
152
+ * @param a - The initial value (or Promise) to pipe through the functions
153
+ * @param ab - The first function to apply to the initial value
154
+ * @param functions - Additional functions to apply in sequence
155
+ * @returns A Promise of the final result after applying all functions
156
+ */
157
+ declare function pipeAsync<A, B>(a: MaybeAsync<A>, ab: (this: void, a: A) => MaybeAsync<B>): Promise<B>;
158
+ declare function pipeAsync<A, B, C>(a: MaybeAsync<A>, ab: (this: void, a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>): Promise<C>;
159
+ declare function pipeAsync<A, B, C, D>(a: MaybeAsync<A>, ab: (this: void, a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>): Promise<D>;
160
+ declare function pipeAsync<A, B, C, D, E>(a: MaybeAsync<A>, ab: (this: void, a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>): Promise<E>;
161
+ declare function pipeAsync<A, B, C, D, E, F>(a: MaybeAsync<A>, ab: (this: void, a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>, ef: (this: void, e: E) => MaybeAsync<F>): Promise<F>;
162
+ declare function pipeAsync<A, B, C, D, E, F, G>(a: MaybeAsync<A>, ab: (this: void, a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>, ef: (this: void, e: E) => MaybeAsync<F>, fg: (this: void, f: F) => MaybeAsync<G>): Promise<G>;
163
+ declare function pipeAsync<A, B, C, D, E, F, G, H>(a: MaybeAsync<A>, ab: (this: void, a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>, ef: (this: void, e: E) => MaybeAsync<F>, fg: (this: void, f: F) => MaybeAsync<G>, gh: (this: void, g: G) => MaybeAsync<H>): Promise<H>;
164
+ declare function pipeAsync<A, B, C, D, E, F, G, H, I>(a: MaybeAsync<A>, ab: (this: void, a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>, ef: (this: void, e: E) => MaybeAsync<F>, fg: (this: void, f: F) => MaybeAsync<G>, gh: (this: void, g: G) => MaybeAsync<H>, hi: (this: void, h: H) => MaybeAsync<I>): Promise<I>;
165
+ declare function pipeAsync<A, B, C, D, E, F, G, H, I, J>(a: MaybeAsync<A>, ab: (this: void, a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>, ef: (this: void, e: E) => MaybeAsync<F>, fg: (this: void, f: F) => MaybeAsync<G>, gh: (this: void, g: G) => MaybeAsync<H>, hi: (this: void, h: H) => MaybeAsync<I>, ij: (this: void, i: I) => MaybeAsync<J>): Promise<J>;
166
+
167
+ /**
168
+ * Creates a new function that is the async composition of the provided functions, applied from left to right.
169
+ * Unlike flow, flowAsync awaits between each step, enabling async composition.
170
+ * The returned function always returns a Promise.
171
+ *
172
+ * @example
173
+ * // Basic async usage
174
+ * const processNumber = flowAsync(
175
+ * async (n: number) => n * 2,
176
+ * (n) => n + 1,
177
+ * async (n) => n.toString()
178
+ * );
179
+ *
180
+ * const result = await processNumber(5); // "11"
181
+ *
182
+ * @example
183
+ * // With Result and curried helpers
184
+ * import { ok, flatMapWith, mapWith } from "@railway-ts/pipelines/result";
185
+ *
186
+ * const process = flowAsync(
187
+ * (n: number) => ok(n),
188
+ * flatMapWith(async (n) => ok(n * 2)),
189
+ * mapWith((n) => n.toString())
190
+ * );
191
+ *
192
+ * const result = await process(5); // Result<string, never> containing "10"
193
+ *
194
+ * @param ab - The first function in the composition
195
+ * @param functions - Additional functions to compose in sequence
196
+ * @returns A new function that applies all the composed functions in sequence, returning a Promise
197
+ */
198
+ declare function flowAsync<A extends unknown[], B>(ab: (this: void, ...a: A) => MaybeAsync<B>): (...a: A) => Promise<B>;
199
+ declare function flowAsync<A extends unknown[], B, C>(ab: (this: void, ...a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>): (...a: A) => Promise<C>;
200
+ declare function flowAsync<A extends unknown[], B, C, D>(ab: (this: void, ...a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>): (...a: A) => Promise<D>;
201
+ declare function flowAsync<A extends unknown[], B, C, D, E>(ab: (this: void, ...a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>): (...a: A) => Promise<E>;
202
+ declare function flowAsync<A extends unknown[], B, C, D, E, F>(ab: (this: void, ...a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>, ef: (this: void, e: E) => MaybeAsync<F>): (...a: A) => Promise<F>;
203
+ declare function flowAsync<A extends unknown[], B, C, D, E, F, G>(ab: (this: void, ...a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>, ef: (this: void, e: E) => MaybeAsync<F>, fg: (this: void, f: F) => MaybeAsync<G>): (...a: A) => Promise<G>;
204
+ declare function flowAsync<A extends unknown[], B, C, D, E, F, G, H>(ab: (this: void, ...a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>, ef: (this: void, e: E) => MaybeAsync<F>, fg: (this: void, f: F) => MaybeAsync<G>, gh: (this: void, g: G) => MaybeAsync<H>): (...a: A) => Promise<H>;
205
+ declare function flowAsync<A extends unknown[], B, C, D, E, F, G, H, I>(ab: (this: void, ...a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>, ef: (this: void, e: E) => MaybeAsync<F>, fg: (this: void, f: F) => MaybeAsync<G>, gh: (this: void, g: G) => MaybeAsync<H>, hi: (this: void, h: H) => MaybeAsync<I>): (...a: A) => Promise<I>;
206
+ declare function flowAsync<A extends unknown[], B, C, D, E, F, G, H, I, J>(ab: (this: void, ...a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>, ef: (this: void, e: E) => MaybeAsync<F>, fg: (this: void, f: F) => MaybeAsync<G>, gh: (this: void, g: G) => MaybeAsync<H>, hi: (this: void, h: H) => MaybeAsync<I>, ij: (this: void, i: I) => MaybeAsync<J>): (...a: A) => Promise<J>;
207
+ declare function flowAsync<A extends unknown[], B, C, D, E, F, G, H, I, J, K>(ab: (this: void, ...a: A) => MaybeAsync<B>, bc: (this: void, b: B) => MaybeAsync<C>, cd: (this: void, c: C) => MaybeAsync<D>, de: (this: void, d: D) => MaybeAsync<E>, ef: (this: void, e: E) => MaybeAsync<F>, fg: (this: void, f: F) => MaybeAsync<G>, gh: (this: void, g: G) => MaybeAsync<H>, hi: (this: void, h: H) => MaybeAsync<I>, ij: (this: void, i: I) => MaybeAsync<J>, jk: (this: void, j: J) => MaybeAsync<K>): (...a: A) => Promise<K>;
208
+
123
209
  /**
124
210
  * Curries a multi-parameter function into a sequence of unary functions.
125
211
  * Enables partial application at any depth and composes cleanly with `pipe`.
@@ -146,11 +232,11 @@ declare function flow<A extends unknown[], B, C, D, E, F, G, H, I, J, K>(ab: (th
146
232
  *
147
233
  * @example
148
234
  * // With Result validators
149
- * import { ok, err, flatMapResult, type Result } from "@/index";
235
+ * import { ok, err, flatMap, type Result } from "@/result";
150
236
  * const between = (min: number, max: number, n: number): Result<number, string> =>
151
237
  * n >= min && n <= max ? ok(n) : err(`Value must be between ${min} and ${max}`);
152
238
  * const validateAge = curry(between)(0)(120);
153
- * pipe(ok(25), (r) => flatMapResult(r, validateAge)); // ok(25)
239
+ * pipe(ok(25), (r) => flatMap(r, validateAge)); // ok(25)
154
240
  *
155
241
  * @param fn - The multi-argument function to transform into a unary curried chain
156
242
  * @returns A curried function that takes one argument at each application step
@@ -283,4 +369,4 @@ declare function untupled<A, B, C, R>(fn: (args: [A, B, C]) => R): (a: A, b: B,
283
369
  declare function untupled<A, B, C, D, R>(fn: (args: [A, B, C, D]) => R): (a: A, b: B, c: C, d: D) => R;
284
370
  declare function untupled<A, B, C, D, E, R>(fn: (args: [A, B, C, D, E]) => R): (a: A, b: B, c: C, d: D, e: E) => R;
285
371
 
286
- export { curry, flow, pipe, tupled, uncurry, untupled };
372
+ export { type MaybeAsync, type UnknownFunction, curry, flow, flowAsync, pipe, pipeAsync, tupled, uncurry, untupled };