Skip to content

Commit

Permalink
feat(pipe)!: accept only two functions at a time
Browse files Browse the repository at this point in the history
  • Loading branch information
drizzer14 committed Nov 23, 2022
1 parent a521a3b commit c28dae3
Showing 1 changed file with 63 additions and 48 deletions.
111 changes: 63 additions & 48 deletions src/pipe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,77 @@
* @module Composition
*/

import type { Last } from './types/last'
import type { UnaryFunction, VariadicFunction } from './types/function';
import type { UnaryFunction } from './types/function';

/**
* Creates a `Pipeline` type which parses all of the provided functions' types.
* Any function with either an incorrect argument or a return type will not fit
* into the pipeline and should be typed according to it, so that its argument's
* type matches the return type of the previous function and its return type
* matches the type of the next function's argument.
* Makes a pipeline of functions from received arguments.
*/
export type Pipeline<
Functions extends [VariadicFunction, ...UnaryFunction[]],
Length extends number = Functions['length']
> =
Length extends 1
export type Pipe<
Arguments extends any[],
Functions extends any[] = []
> =
Arguments['length'] extends 0
? Functions
: Functions extends [infer First, infer Second, ...infer Rest]
? [
First,
...Pipeline<
First extends UnaryFunction
? Second extends UnaryFunction
? Rest extends UnaryFunction[]
? [(arg: ReturnType<First>) => ReturnType<Second>, ...Rest]
: never
: never
: First extends VariadicFunction
? Second extends UnaryFunction
? Rest extends UnaryFunction[]
? [(arg: ReturnType<First>) => ReturnType<Second>, ...Rest]
: never
: never
: never

>
]
: Functions
: Arguments extends [infer A, infer B]
? [(arg: A) => B, ...Functions]
: Arguments extends [infer A, ...infer Rest, infer P, infer L]
? Pipe<[A, ...Rest, P], [(arg: P) => L, ...Functions]>
: []

/**
* Applies all of the provided `functions` one-by-one in left-to-right order.
* Destructures a pipeline of functions into arguments.
*/
export default function pipe
<Functions extends [VariadicFunction, ...UnaryFunction[]]>(
...functions: Pipeline<Functions>
): (...args: Parameters<Functions[0]>) => ReturnType<Last<Functions>> {
return (...args) => {
const length = functions.length
export type Depipe<
Functions extends UnaryFunction[],
Arguments extends any[] = []
> = Functions extends [(arg: infer Arg) => infer Return]
? [...Arguments, Arg, Return]
: Functions extends [(arg: infer Arg) => any, ...infer Rest extends UnaryFunction[]]
? Depipe<Rest, [...Arguments, Arg]>
: []

let pipeline = functions[0](...args)
/**
* (A -> B) . (B -> C) = A -> C
*/
export default function pipe<
A extends any[],
B,
C
> (
first: (...args: A) => B,
second: (arg: B) => C
): (...args: A) => C

if (length > 1) {
for (let index = 1; index < length; index += 1) {
pipeline = functions[index](pipeline)
}
}
/**
* (A -> B) . (B -> C) = A -> C
*/
export default function pipe<
A extends any[],
B,
C
> (
...args: [
...args: A,
first: (...args: A) => B,
second: (arg: B) => C
]
): C

return pipeline as ReturnType<Last<Functions>>
}
/**
* (A -> B) . (B -> C) = A -> C
*/
export default function pipe<
A extends any[],
B,
C
> (
...maybeArgs: [
...args: A,
first: (...args: A) => B,
second: (arg: B) => C
]
) {
return maybeArgs.length === 2
? (...args: A) => maybeArgs[1](maybeArgs[0](...args))
: maybeArgs[maybeArgs.length - 1](maybeArgs[maybeArgs.length - 2](...maybeArgs.slice(0, -2)))
}

0 comments on commit c28dae3

Please sign in to comment.