Ever changing implementations of pipes that I reimplement in each codebase for different use cases.
If you do want a package instead. You should go with this https://github.com/barelyhuman/pipe
Ever changing implementations of pipes that I reimplement in each codebase for different use cases.
If you do want a package instead. You should go with this https://github.com/barelyhuman/pipe
| /** | |
| * | |
| * @param {...function} args | |
| * @returns | |
| * @example | |
| * console.log( | |
| * await pipe( | |
| * () => [1, 2, 3], | |
| * () => pipe(() => prev.map((x) => x * 2)), | |
| * (counts) => counts.map(async (x) => x * 2) | |
| * ) | |
| * ); | |
| */ | |
| function pipe(...args) { | |
| return args.reduce((acc, item, index) => { | |
| if (typeof item !== "function") | |
| throw new Error(`[pipe] item at index: ${index} is not a function`); | |
| return acc.then((prev) => { | |
| const res = item(prev); | |
| return Array.isArray(res) && res.every((x) => x instanceof Promise) | |
| ? Promise.all(res) | |
| : res; | |
| }); | |
| }, Promise.resolve()); | |
| } |
| const pipe = (initData, chain = []) => { | |
| let _data = initData; | |
| if (typeof initData === "function") { | |
| _data = initData(); | |
| } | |
| return { | |
| _(fn) { | |
| chain.push(fn); | |
| return this; | |
| }, | |
| async value() { | |
| let initValue = _data; | |
| if (_data instanceof Promise) { | |
| initValue = await _data; | |
| } | |
| return chain.reduce((acc, item) => { | |
| return acc.then((prev) => { | |
| return item(prev); | |
| }); | |
| }, Promise.resolve(initValue)); | |
| }, | |
| }; | |
| }; |
| const isArrayOfPromises = (item) => | |
| Boolean(Array.isArray(item) && item.every((x) => x instanceof Promise)); | |
| const resolveArray = (item) => | |
| (isArrayOfPromises(item) && Promise.all(item)) || item; | |
| /** | |
| * @description handles both sync and async cases. If even on function in the | |
| * pipe params is async or returns an array of promises, the entire pipe is considered | |
| * to be async. | |
| * if not then it runs the functions in sync | |
| * @param {...function} args | |
| * @returns | |
| * @example | |
| * // gives the result as sync, instead of a promise. | |
| * const nextHour = pipe( | |
| * () => new Date(), | |
| * (d) => d.setHours(d.getHours() + 1), | |
| * (x) => new Date(x) | |
| * ) | |
| * | |
| * // gives the result as async, and needs to be awaited | |
| * const nextHour = await pipe( | |
| * () => new Date(), | |
| * async (d) => d.setHours(d.getHours() + 1), | |
| * (x) => new Date(x) | |
| * ) | |
| */ | |
| export const pipe = (...args) => { | |
| let syncFlow = true, | |
| result = undefined; | |
| for (let i = 0; i < args.length; i += 1) { | |
| const fn = args[i]; | |
| if (!syncFlow) { | |
| result = Promise.resolve(result) | |
| .then(resolveArray) | |
| .then((d) => fn(d)); | |
| } else { | |
| result = fn(result); | |
| if (result instanceof Promise || isArrayOfPromises(result)) { | |
| syncFlow = false; | |
| } | |
| } | |
| } | |
| if (result && typeof result.then === "function") { | |
| return result.then(resolveArray); | |
| } | |
| return result; | |
| }; |