Source: methods/pipeline.js

/**
 * Method to handle sequential tasks that rely on the output of the previous task
 *
 * @param {Array.<Function>} fns The functions you would like to run over the input
 * @memberof module:Utilities
 * @returns {any} The result of the pipeline processing
 */
const pipeline = (...fns) => (x) => fns.reduce((v, f) => v.then(f), Promise.resolve(x));

/**
 * This method allows you to pass more arguments through the pipeline via a closure
 *
 * @param {Function} func The method you want to run in the pipeline
 * @param {...any} args The closure args you want to use in the method
 * @memberof module:Utilities
 * @returns {Function} A method to be called with a new argumnet as well
 *  as those captured in the closure
 */
function pipelineClosureMethod(func, ...args) {
  return async (x) => func(x, ...args);
}

/**
 * Method to handle sequential tasks that all act on the same value, short circuiting when
 * one returns true
 *
 * @param {Array.<Function>} fns Array of functions to run over single value
 * @returns {void} Nothing
 */
const shortCircuitPipeline = (...fns) => (val) => fns.reduce(
  async (current, fn) => current.then((value) => value || fn(val)),
  Promise.resolve(false),
);

export { pipeline, pipelineClosureMethod, shortCircuitPipeline };