rubico
Version:
[a]synchronous functional programming
104 lines (97 loc) • 2.84 kB
JavaScript
const areAnyValuesPromises = require('./_internal/areAnyValuesPromises')
const promiseAll = require('./_internal/promiseAll')
const funcConcat = require('./_internal/funcConcat')
const funcApply = require('./_internal/funcApply')
const curry2 = require('./_internal/curry2')
const __ = require('./_internal/placeholder')
/**
* @name pipe
*
* @synopsis
* ```coffeescript [specscript]
* funcs Array<function>
* args Array<any>
* argsOrPromises Array<Promise|any>
*
* pipe(funcs)(...args) -> result Promise|any
* pipe(...argsOrPromises, funcs Array<function>) -> result Promise|any
* pipe(...funcs)(...args) -> result Promise|any
* ```
*
* @description
* Creates a function pipeline from multiple functions. Each function in the pipeline is evaluated in series, passing its return value as an argument to the next function. The result of a pipeline execution is the return value of the last function in the pipeline. If any function in the pipeline is asynchronous, the result of the pipeline execution is a Promise.
*
* ```javascript [playground]
* const syncAdd123 = pipe([
* number => number + 1,
* number => number + 2,
* number => number + 3,
* ])
*
* console.log(syncAdd123(5)) // 11
*
* const asyncAdd123 = pipe([
* async number => number + 1,
* async number => number + 2,
* async number => number + 3,
* ])
*
* asyncAdd123(5).then(console.log) // 11
* ```
*
* `pipe` supports a mathematical API.
*
* ```javascript [playground]
* const appendB = x => x + 'b'
* const appendC = x => x + 'c'
*
* const appendBC = pipe(appendB, appendC)
*
* console.log(appendBC('a')) // 'abc'
* ```
*
* When passed any amount of arguments before the array of functions, `pipe` executes eagerly; the array of functions is immediately invoked with the supplied arguments.
*
* ```javascript [playground]
* pipe(1, 2, 3, [
* Array.of,
* map(number => number * 3),
* console.log, // [3, 6, 9]
* ])
* ```
*
* Any promises passed in argument position are resolved for their values before further execution. This only applies to the eager version of the API.
*
* ```javascript [playground]
* pipe(Promise.resolve(1), 2, Promise.resolve(3), [
* console.log, // [1, 2, 3]
* ])
* ```
*
* See also:
* * [compose](/docs/compose)
* * [tap](/docs/tap)
* * [switchCase](/docs/switchCase)
* * [tryCatch](/docs/tryCatch)
*
* @execution series
*
* @transducing
*
* @since 1.6.0
*/
const pipe = function (...args) {
if (typeof args[0] == 'function') {
return args.reduce(funcConcat)
}
const funcs = args.pop()
const pipeline = funcs.reduce(funcConcat)
if (args.length == 0) {
return pipeline
}
if (areAnyValuesPromises(args)) {
return promiseAll(args).then(curry2(funcApply, pipeline, __))
}
return pipeline(...args)
}
module.exports = pipe