UNPKG

2.74 kBJavaScriptView Raw
1/** @module fp **/
2
3/** Reducer function used by `pipe` and `compose` functions to compose sync and async functions
4 * @argument {function|Promise} chain a chain of functions or promises
5 * @argument {function|Promise} func a new function or promise to add to the chain
6 * @method
7 */
8const mixCompose = (chain, func) => (chain instanceof Promise || typeof chain.then === 'function' ? chain.then(func) : func(chain));
9
10/** Compose regular functions or promises generating a final function.
11 * - Compose works from left to right.
12 * - If you compose one single promise the final result will be a promise too.
13 * - You can only compose functions with the same arity.
14 * @argument {function|Promise} arguments N number of functions or promises.
15 * @returns {function|Promise} function or Promise that execute the all composed ones.
16 * @example
17 * const sum3 = a => a+3
18 * const mult2 = a => a*2
19 * const sum2Async = a => Promise.resolve(a+2) // Simulate async response
20 *
21 * const sumAndMult = pipe(sum3,mult2);
22 * sumAndMult(1) // -> (1+3)*2 = 8
23 *
24 * const sumAndMultAsync = pipe(sum3,mult2,sum2Async);
25 * await sumAndMultAsync(1) // -> ((1+3)*2)+2 = 10
26 * @method
27 */
28const pipe = (...fn) => input => fn.reduce(mixCompose, input);
29
30/** Compose regular functions or promises generating a final function.
31 * - Compose works from right to left.
32 * - If you compose one single promise the final result will be a promise too.
33 * - You can only compose functions with the same arity.
34 * @argument {function|Promise} arguments N number of functions or promises.
35 * @returns {function|Promise} function or Promise that execute the all composed ones.
36 * @example
37 * const sum3 = a => a+3
38 * const mult2 = a => a*2
39 * const sum2Async = a => Promise.resolve(a+2) // Simulate async response
40 *
41 * const sumAndMult = compose(sum3,mult2);
42 * sumAndMult(1) // -> (1*2)+3 = 5
43 *
44 * const sumAndMultAsync = compose(sum3,mult2,sum2Async);
45 * await sumAndMultAsync(1) // -> ((1+2)*2)+3 = 9
46 * @method
47 */
48const compose = (...fn) => input => fn.reduceRight(mixCompose, input);
49
50/** Currify any function allowing the partial application of its arguments
51 * @argument {function} function function with at least two arguments
52 * @returns {function} curried function.
53 * @example
54 * const sum = curry((a,b) = a+b);
55 * const sum3 = sum(3);
56 * sum3(3) // -> 6
57 * sum(3,3) // -> 6
58 * sum(3)(3) // -> 6
59 * @method
60 */
61const curry = f => {
62 if (typeof f !== 'function') {
63 throw new Error(`curry requires a function, [${typeof f}] passed`);
64 }
65 return function currify(...arg) {
66 const args = Array.prototype.slice.call(arg);
67 return args.length >= f.length ? f(...args) : currify.bind(null, ...args);
68 };
69};
70module.exports = { pipe, compose, curry };