froebel
Version:
TypeScript utility library
59 lines (52 loc) • 1.59 kB
JavaScript
import isPromise from "./isPromise.mjs";
/**
* Given a list of functions returns a function that will execute the given
* functions one after another, always passing the result of the previous
* function as an argument to the next function.
*
* If one of the given functions returns a promise, the promise will be resolved
* before being passed to the next function.
*
* @example
* ```
* const join = (...chars: string[]) => chars.join('')
* pipe(join, parseInt)('1', '2', '3') // -> 123
*
* const square = (n: number) => n ** 2
*
* // this is equivalent to: square(square(square(2)))
* pipe(square, square, square)(2) // -> 256
*
* // also works with promises:
* fetchNumber :: async () => Promise<number>
* pipe(fetchNumber, n => n.toString()) // async () => Promise<string>
* ```
*/
const pipe = (...funs) => (...args) => {
let nextArgs = args;
for (let i = 0; i < funs.length; i++) {
const [result] = nextArgs = [funs[i](...nextArgs)];
if (isPromise(result)) return resolveAsync(result, funs.slice(i + 1));
}
return nextArgs[0];
};
export default pipe;
/**
* Like `pipe` but takes an argument as its first parameter and invokes the pipe
* with it.
*
* Note: unlike in `pipe`, the first function of the pipe must take exactly one
* argument.
*
* @see {@link pipe}
*
* @example
* ```
* applyPipe(2, double, square, half) // -> 8
* ```
*/
export const applyPipe = (arg, ...funs) => pipe(...funs)(arg);
const resolveAsync = async (result, funs) => {
for (const fun of funs) result = fun(await result);
return await result;
};