1/**
2 * The `Pipeable` module defines the shared interface and implementation helpers
3 * for values that support Effect-style method chaining with `.pipe(...)`.
4 *
5 * A `Pipeable` value can pass itself through a sequence of unary functions from
6 * left to right, so code can be written as `value.pipe(f, g, h)` instead of
7 * deeply nesting calls. This is the method form used by many Effect data types
8 * to compose transformations, validations, and effectful operations while
9 * keeping the original value as the starting point of the pipeline.
10 *
11 * @since 2.0.0
12 */
13
14/**
15 * Interface for values that support method-style `pipe` composition.
16 *
17 * **When to use**
18 *
19 * Use to type values that expose an Effect-style `.pipe(...)` method.
20 *
21 * **Details**
22 *
23 * Calling `value.pipe(f, g, h)` passes the value through each function from
24 * left to right, returning the final result. Many Effect data types implement
25 * this so operations can be chained without nesting function calls.
26 *
27 * **Example** (Chaining operations with pipe)
28 *
29 * ```ts import.meta.vitest
30 * import { Effect } from "effect"
31 *
32 * // The Pipeable interface allows Effect values to be chained using the pipe method
33 * const program = Effect.succeed(1).pipe(
34 * Effect.map((x) => x + 1),
35 * Effect.flatMap((x) => Effect.succeed(x * 2))
36 * )
37 *
38 * Effect.runSync(program) // => 4
39 * ```
40 *
41 * @category models
42 * @since 2.0.0
43 */
44export interface Pipeable {
45 pipe<A>(this: A): A
46 pipe<A, B = never>(this: A, ab: (_: A) => B): B
47 pipe<A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C
48 pipe<A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D
49 pipe<A, B = never, C = never, D = never, E = never>(
50 this: A,
51 ab: (_: A) => B,
52 bc: (_: B) => C,
53 cd: (_: C) => D,
54 de: (_: D) => E
55 ): E
56 pipe<A, B = never, C = never, D = never, E = never, F = never>(
57 this: A,
58 ab: (_: A) => B,
59 bc: (_: B) => C,
60 cd: (_: C) => D,
61 de: (_: D) => E,
62 ef: (_: E) => F
63 ): F
64 pipe<A, B = never, C = never, D = never, E = never, F = never, G = never>(
65 this: A,
66 ab: (_: A) => B,
67 bc: (_: B) => C,
68 cd: (_: C) => D,
69 de: (_: D) => E,
70 ef: (_: E) => F,
71 fg: (_: F) => G
72 ): G
73 pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never>(
74 this: A,
75 ab: (_: A) => B,
76 bc: (_: B) => C,
77 cd: (_: C) => D,
78 de: (_: D) => E,
79 ef: (_: E) => F,
80 fg: (_: F) => G,
81 gh: (_: G) => H
82 ): H
83 pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never>(
84 this: A,
85 ab: (_: A) => B,
86 bc: (_: B) => C,
87 cd: (_: C) => D,
88 de: (_: D) => E,
89 ef: (_: E) => F,
90 fg: (_: F) => G,
91 gh: (_: G) => H,
92 hi: (_: H) => I
93 ): I
94 pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never>(
95 this: A,
96 ab: (_: A) => B,
97 bc: (_: B) => C,
98 cd: (_: C) => D,
99 de: (_: D) => E,
100 ef: (_: E) => F,
101 fg: (_: F) => G,
102 gh: (_: G) => H,
103 hi: (_: H) => I,
104 ij: (_: I) => J
105 ): J
106 pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never>(
107 this: A,
108 ab: (_: A) => B,
109 bc: (_: B) => C,
110 cd: (_: C) => D,
111 de: (_: D) => E,
112 ef: (_: E) => F,
113 fg: (_: F) => G,
114 gh: (_: G) => H,
115 hi: (_: H) => I,
116 ij: (_: I) => J,
117 jk: (_: J) => K
118 ): K
119 pipe<
120 A,
121 B = never,
122 C = never,
123 D = never,
124 E = never,
125 F = never,
126 G = never,
127 H = never,
128 I = never,
129 J = never,
130 K = never,
131 L = never
132 >(
133 this: A,
134 ab: (_: A) => B,
135 bc: (_: B) => C,
136 cd: (_: C) => D,
137 de: (_: D) => E,
138 ef: (_: E) => F,
139 fg: (_: F) => G,
140 gh: (_: G) => H,
141 hi: (_: H) => I,
142 ij: (_: I) => J,
143 jk: (_: J) => K,
144 kl: (_: K) => L
145 ): L
146 pipe<
147 A,
148 B = never,
149 C = never,
150 D = never,
151 E = never,
152 F = never,
153 G = never,
154 H = never,
155 I = never,
156 J = never,
157 K = never,
158 L = never,
159 M = never
160 >(
161 this: A,
162 ab: (_: A) => B,
163 bc: (_: B) => C,
164 cd: (_: C) => D,
165 de: (_: D) => E,
166 ef: (_: E) => F,
167 fg: (_: F) => G,
168 gh: (_: G) => H,
169 hi: (_: H) => I,
170 ij: (_: I) => J,
171 jk: (_: J) => K,
172 kl: (_: K) => L,
173 lm: (_: L) => M
174 ): M
175 pipe<
176 A,
177 B = never,
178 C = never,
179 D = never,
180 E = never,
181 F = never,
182 G = never,
183 H = never,
184 I = never,
185 J = never,
186 K = never,
187 L = never,
188 M = never,
189 N = never
190 >(
191 this: A,
192 ab: (_: A) => B,
193 bc: (_: B) => C,
194 cd: (_: C) => D,
195 de: (_: D) => E,
196 ef: (_: E) => F,
197 fg: (_: F) => G,
198 gh: (_: G) => H,
199 hi: (_: H) => I,
200 ij: (_: I) => J,
201 jk: (_: J) => K,
202 kl: (_: K) => L,
203 lm: (_: L) => M,
204 mn: (_: M) => N
205 ): N
206 pipe<
207 A,
208 B = never,
209 C = never,
210 D = never,
211 E = never,
212 F = never,
213 G = never,
214 H = never,
215 I = never,
216 J = never,
217 K = never,
218 L = never,
219 M = never,
220 N = never,
221 O = never
222 >(
223 this: A,
224 ab: (_: A) => B,
225 bc: (_: B) => C,
226 cd: (_: C) => D,
227 de: (_: D) => E,
228 ef: (_: E) => F,
229 fg: (_: F) => G,
230 gh: (_: G) => H,
231 hi: (_: H) => I,
232 ij: (_: I) => J,
233 jk: (_: J) => K,
234 kl: (_: K) => L,
235 lm: (_: L) => M,
236 mn: (_: M) => N,
237 no: (_: N) => O
238 ): O
239 pipe<
240 A,
241 B = never,
242 C = never,
243 D = never,
244 E = never,
245 F = never,
246 G = never,
247 H = never,
248 I = never,
249 J = never,
250 K = never,
251 L = never,
252 M = never,
253 N = never,
254 O = never,
255 P = never
256 >(
257 this: A,
258 ab: (_: A) => B,
259 bc: (_: B) => C,
260 cd: (_: C) => D,
261 de: (_: D) => E,
262 ef: (_: E) => F,
263 fg: (_: F) => G,
264 gh: (_: G) => H,
265 hi: (_: H) => I,
266 ij: (_: I) => J,
267 jk: (_: J) => K,
268 kl: (_: K) => L,
269 lm: (_: L) => M,
270 mn: (_: M) => N,
271 no: (_: N) => O,
272 op: (_: O) => P
273 ): P
274 pipe<
275 A,
276 B = never,
277 C = never,
278 D = never,
279 E = never,
280 F = never,
281 G = never,
282 H = never,
283 I = never,
284 J = never,
285 K = never,
286 L = never,
287 M = never,
288 N = never,
289 O = never,
290 P = never,
291 Q = never
292 >(
293 this: A,
294 ab: (_: A) => B,
295 bc: (_: B) => C,
296 cd: (_: C) => D,
297 de: (_: D) => E,
298 ef: (_: E) => F,
299 fg: (_: F) => G,
300 gh: (_: G) => H,
301 hi: (_: H) => I,
302 ij: (_: I) => J,
303 jk: (_: J) => K,
304 kl: (_: K) => L,
305 lm: (_: L) => M,
306 mn: (_: M) => N,
307 no: (_: N) => O,
308 op: (_: O) => P,
309 pq: (_: P) => Q
310 ): Q
311 pipe<
312 A,
313 B = never,
314 C = never,
315 D = never,
316 E = never,
317 F = never,
318 G = never,
319 H = never,
320 I = never,
321 J = never,
322 K = never,
323 L = never,
324 M = never,
325 N = never,
326 O = never,
327 P = never,
328 Q = never,
329 R = never
330 >(
331 this: A,
332 ab: (_: A) => B,
333 bc: (_: B) => C,
334 cd: (_: C) => D,
335 de: (_: D) => E,
336 ef: (_: E) => F,
337 fg: (_: F) => G,
338 gh: (_: G) => H,
339 hi: (_: H) => I,
340 ij: (_: I) => J,
341 jk: (_: J) => K,
342 kl: (_: K) => L,
343 lm: (_: L) => M,
344 mn: (_: M) => N,
345 no: (_: N) => O,
346 op: (_: O) => P,
347 pq: (_: P) => Q,
348 qr: (_: Q) => R
349 ): R
350 pipe<
351 A,
352 B = never,
353 C = never,
354 D = never,
355 E = never,
356 F = never,
357 G = never,
358 H = never,
359 I = never,
360 J = never,
361 K = never,
362 L = never,
363 M = never,
364 N = never,
365 O = never,
366 P = never,
367 Q = never,
368 R = never,
369 S = never
370 >(
371 this: A,
372 ab: (_: A) => B,
373 bc: (_: B) => C,
374 cd: (_: C) => D,
375 de: (_: D) => E,
376 ef: (_: E) => F,
377 fg: (_: F) => G,
378 gh: (_: G) => H,
379 hi: (_: H) => I,
380 ij: (_: I) => J,
381 jk: (_: J) => K,
382 kl: (_: K) => L,
383 lm: (_: L) => M,
384 mn: (_: M) => N,
385 no: (_: N) => O,
386 op: (_: O) => P,
387 pq: (_: P) => Q,
388 qr: (_: Q) => R,
389 rs: (_: R) => S
390 ): S
391 pipe<
392 A,
393 B = never,
394 C = never,
395 D = never,
396 E = never,
397 F = never,
398 G = never,
399 H = never,
400 I = never,
401 J = never,
402 K = never,
403 L = never,
404 M = never,
405 N = never,
406 O = never,
407 P = never,
408 Q = never,
409 R = never,
410 S = never,
411 T = never
412 >(
413 this: A,
414 ab: (_: A) => B,
415 bc: (_: B) => C,
416 cd: (_: C) => D,
417 de: (_: D) => E,
418 ef: (_: E) => F,
419 fg: (_: F) => G,
420 gh: (_: G) => H,
421 hi: (_: H) => I,
422 ij: (_: I) => J,
423 jk: (_: J) => K,
424 kl: (_: K) => L,
425 lm: (_: L) => M,
426 mn: (_: M) => N,
427 no: (_: N) => O,
428 op: (_: O) => P,
429 pq: (_: P) => Q,
430 qr: (_: Q) => R,
431 rs: (_: R) => S,
432 st: (_: S) => T
433 ): T
434 pipe<
435 A,
436 B = never,
437 C = never,
438 D = never,
439 E = never,
440 F = never,
441 G = never,
442 H = never,
443 I = never,
444 J = never,
445 K = never,
446 L = never,
447 M = never,
448 N = never,
449 O = never,
450 P = never,
451 Q = never,
452 R = never,
453 S = never,
454 T = never,
455 U = never
456 >(
457 this: A,
458 ab: (_: A) => B,
459 bc: (_: B) => C,
460 cd: (_: C) => D,
461 de: (_: D) => E,
462 ef: (_: E) => F,
463 fg: (_: F) => G,
464 gh: (_: G) => H,
465 hi: (_: H) => I,
466 ij: (_: I) => J,
467 jk: (_: J) => K,
468 kl: (_: K) => L,
469 lm: (_: L) => M,
470 mn: (_: M) => N,
471 no: (_: N) => O,
472 op: (_: O) => P,
473 pq: (_: P) => Q,
474 qr: (_: Q) => R,
475 rs: (_: R) => S,
476 st: (_: S) => T,
477 tu: (_: T) => U
478 ): U
479 pipe<
480 A,
481 B = never,
482 C = never,
483 D = never,
484 E = never,
485 F = never,
486 G = never,
487 H = never,
488 I = never,
489 J = never,
490 K = never,
491 L = never,
492 M = never,
493 N = never,
494 O = never,
495 P = never,
496 Q = never,
497 R = never,
498 S = never,
499 T = never,
500 U = never
501 >(
502 this: A,
503 ab: (_: A) => B,
504 bc: (_: B) => C,
505 cd: (_: C) => D,
506 de: (_: D) => E,
507 ef: (_: E) => F,
508 fg: (_: F) => G,
509 gh: (_: G) => H,
510 hi: (_: H) => I,
511 ij: (_: I) => J,
512 jk: (_: J) => K,
513 kl: (_: K) => L,
514 lm: (_: L) => M,
515 mn: (_: M) => N,
516 no: (_: N) => O,
517 op: (_: O) => P,
518 pq: (_: P) => Q,
519 qr: (_: Q) => R,
520 rs: (_: R) => S,
521 st: (_: S) => T,
522 tu: (_: T) => U
523 ): U
524}
525
526/**
527 * Applies a `pipe` method's variadic arguments to an initial value from left
528 * to right.
529 *
530 * **When to use**
531 *
532 * Use to implement a custom `.pipe(...)` method from JavaScript's `arguments`
533 * object.
534 *
535 * **Details**
536 *
537 * This helper is intended for implementing `Pipeable.pipe` methods that
538 * receive JavaScript's `arguments` object. With no functions it returns the
539 * original value; otherwise it feeds each result into the next function.
540 *
541 * **Example** (Implementing a pipe method)
542 *
543 * ```ts import.meta.vitest
544 * import { Pipeable } from "effect"
545 *
546 * class NumberBox {
547 * constructor(readonly value: number) {}
548 *
549 * pipe(..._fns: ReadonlyArray<(value: number) => number>): number {
550 * return Pipeable.pipeArguments(this.value, arguments) as number
551 * }
552 * }
553 *
554 * const result = new NumberBox(5).pipe(
555 * (n) => n + 2,
556 * (n) => n * 3
557 * )
558 * result // => 21
559 * ```
560 *
561 * @category combinators
562 * @since 2.0.0
563 */
564export const pipeArguments = <A>(self: A, args: IArguments): unknown => {
565 switch (args.length) {
566 case 0:
567 return self
568 case 1:
569 return args[0](self)
570 case 2:
571 return args[1](args[0](self))
572 case 3:
573 return args[2](args[1](args[0](self)))
574 case 4:
575 return args[3](args[2](args[1](args[0](self))))
576 case 5:
577 return args[4](args[3](args[2](args[1](args[0](self)))))
578 case 6:
579 return args[5](args[4](args[3](args[2](args[1](args[0](self))))))
580 case 7:
581 return args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))))
582 case 8:
583 return args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self))))))))
584 case 9:
585 return args[8](args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))))))
586 default: {
587 let ret = self
588 for (let i = 0, len = args.length; i < len; i++) {
589 ret = args[i](ret)
590 }
591 return ret
592 }
593 }
594}
595
596/**
597 * Reusable prototype that implements `Pipeable.pipe`.
598 *
599 * **When to use**
600 *
601 * Use when classes or object prototypes can reuse this value when they need the
602 * standard pipe implementation backed by `pipeArguments`.
603 *
604 * @category prototypes
605 * @since 3.15.0
606 */
607export const Prototype: Pipeable = {
608 pipe() {
609 return pipeArguments(this, arguments)
610 }
611}
612
613/**
614 * Provides a base constructor whose instances implement the standard `Pipeable.pipe`
615 * method.
616 *
617 * **When to use**
618 *
619 * Use when you need to define a class that supports Effect-style method
620 * chaining through `.pipe(...)`.
621 *
622 * @category constructors
623 * @since 3.15.0
624 */
625export const Class: new() => Pipeable = (function() {
626 function PipeableBase() {}
627 PipeableBase.prototype = Prototype
628 return PipeableBase as any
629})()
630
631/**
632 * Constructor type for classes whose instances implement `Pipeable`.
633 *
634 * **When to use**
635 *
636 * Use as the constructor-side type when a class value should be known to create
637 * instances that support Effect-style method chaining with `.pipe(...)`.
638 *
639 * @see {@link Pipeable} for the instance-side contract
640 * @see {@link Class} for the base constructor
641 * @see {@link Mixin} for wrapping an existing class constructor
642 *
643 * @category models
644 * @since 3.15.0
645 */
646export interface PipeableConstructor {
647 new(...args: ReadonlyArray<any>): Pipeable
648}
649
650/**
651 * Returns a subclass of the provided class that adds the standard `pipe`
652 * method.
653 *
654 * **When to use**
655 *
656 * Use to add pipe support to an existing class without extending a base class
657 * or modifying its prototype.
658 *
659 * **Details**
660 *
661 * The original constructor and instance members are preserved, and the added
662 * method delegates to `pipeArguments`.
663 *
664 * @see {@link Prototype} for a reusable prototype object
665 * @see {@link Class} for a base constructor to extend
666 * @category constructors
667 * @since 4.0.0
668 */
669export const Mixin = <TBase extends new(...args: ReadonlyArray<any>) => any>(
670 klass: TBase
671): TBase & PipeableConstructor => (class extends klass {
672 pipe() {
673 return pipeArguments(this, arguments)
674 }
675})