UNPKG

rubico

Version:

[a]synchronous functional programming

338 lines (295 loc) 8.6 kB
/** * rubico v2.6.2 * https://github.com/a-synchronous/rubico * (c) 2019-2024 Richard Tong * rubico may be freely distributed under the MIT license. */ const isPromise = value => value != null && typeof value.then == 'function' const isArray = Array.isArray const areAnyValuesPromises = function (values) { if (isArray(values)) { const length = values.length let index = -1 while (++index < length) { const value = values[index] if (isPromise(value)) { return true } } return false } for (const key in values) { const value = values[key] if (isPromise(value)) { return true } } return false } const areAllValuesNonfunctions = function (values) { if (isArray(values)) { const length = values.length let index = -1 while (++index < length) { if (typeof values[index] == 'function') { return false } } return true } for (const key in values) { if (typeof values[key] == 'function') { return false } } return true } const promiseAll = Promise.all.bind(Promise) const promiseObjectAllExecutor = object => function executor(resolve) { const result = {} let numPromises = 0 for (const key in object) { const value = object[key] if (isPromise(value)) { numPromises += 1 value.then((key => function (res) { result[key] = res numPromises -= 1 if (numPromises == 0) { resolve(result) } })(key)) } else { result[key] = value } } if (numPromises == 0) { resolve(result) } } const promiseObjectAll = object => new Promise(promiseObjectAllExecutor(object)) const __ = Symbol.for('placeholder') // argument resolver for curry2 const curry2ResolveArg0 = ( baseFunc, arg1, ) => function arg0Resolver(arg0) { return baseFunc(arg0, arg1) } // argument resolver for curry2 const curry2ResolveArg1 = ( baseFunc, arg0, ) => function arg1Resolver(arg1) { return baseFunc(arg0, arg1) } const curry2 = function (baseFunc, arg0, arg1) { return arg0 == __ ? curry2ResolveArg0(baseFunc, arg1) : curry2ResolveArg1(baseFunc, arg0) } // argument resolver for curryArgs2 const curryArgs2ResolveArgs0 = ( baseFunc, arg1, arg2, ) => function args0Resolver(...args) { return baseFunc(args, arg1) } // argument resolver for curryArgs2 const curryArgs2ResolveArgs1 = ( baseFunc, arg0, arg2, ) => function arg1Resolver(...args) { return baseFunc(arg0, args) } const curryArgs2 = function (baseFunc, arg0, arg1) { if (arg0 == __) { return curryArgs2ResolveArgs0(baseFunc, arg1) } return curryArgs2ResolveArgs1(baseFunc, arg0) } const functionArrayAll = function (funcs, args) { const funcsLength = funcs.length, result = Array(funcsLength) let funcsIndex = -1, isAsync = false while (++funcsIndex < funcsLength) { const f = funcs[funcsIndex] const resultItem = typeof f == 'function' ? f(...args) : f if (isPromise(resultItem)) { isAsync = true } result[funcsIndex] = resultItem } return isAsync ? promiseAll(result) : result } const funcConcat = ( funcA, funcB, ) => function pipedFunction(...args) { const intermediate = funcA(...args) return isPromise(intermediate) ? intermediate.then(funcB) : funcB(intermediate) } // argument resolver for curry3 const curry3ResolveArg0 = ( baseFunc, arg1, arg2, ) => function arg0Resolver(arg0) { return baseFunc(arg0, arg1, arg2) } // argument resolver for curry3 const curry3ResolveArg1 = ( baseFunc, arg0, arg2, ) => function arg1Resolver(arg1) { return baseFunc(arg0, arg1, arg2) } // argument resolver for curry3 const curry3ResolveArg2 = ( baseFunc, arg0, arg1, ) => function arg2Resolver(arg2) { return baseFunc(arg0, arg1, arg2) } const curry3 = function (baseFunc, arg0, arg1, arg2) { if (arg0 == __) { return curry3ResolveArg0(baseFunc, arg1, arg2) } if (arg1 == __) { return curry3ResolveArg1(baseFunc, arg0, arg2) } return curry3ResolveArg2(baseFunc, arg0, arg1) } // argument resolver for curry4 const curry4ResolveArg0 = ( baseFunc, arg1, arg2, arg3, ) => function arg0Resolver(arg0) { return baseFunc(arg0, arg1, arg2, arg3) } // argument resolver for curry4 const curry4ResolveArg1 = ( baseFunc, arg0, arg2, arg3, ) => function arg1Resolver(arg1) { return baseFunc(arg0, arg1, arg2, arg3) } // argument resolver for curry4 const curry4ResolveArg2 = ( baseFunc, arg0, arg1, arg3, ) => function arg2Resolver(arg2) { return baseFunc(arg0, arg1, arg2, arg3) } // argument resolver for curry4 const curry4ResolveArg3 = ( baseFunc, arg0, arg1, arg2, ) => function arg3Resolver(arg3) { return baseFunc(arg0, arg1, arg2, arg3) } const curry4 = function (baseFunc, arg0, arg1, arg2, arg3) { if (arg0 == __) { return curry4ResolveArg0(baseFunc, arg1, arg2, arg3) } if (arg1 == __) { return curry4ResolveArg1(baseFunc, arg0, arg2, arg3) } if (arg2 == __) { return curry4ResolveArg2(baseFunc, arg0, arg1, arg3) } return curry4ResolveArg3(baseFunc, arg0, arg1, arg2) } const objectSet = function (object, property, value) { object[property] = value return object } const asyncFunctionArrayAllSeries = async function (funcs, args, result, funcsIndex) { const funcsLength = funcs.length while (++funcsIndex < funcsLength) { const resultItem = funcs[funcsIndex](...args) result[funcsIndex] = isPromise(resultItem) ? await resultItem : resultItem } return result } const functionArrayAllSeries = function (funcs, args) { const funcsLength = funcs.length, result = [] let funcsIndex = -1 while (++funcsIndex < funcsLength) { const resultItem = funcs[funcsIndex](...args) if (isPromise(resultItem)) { return resultItem.then(funcConcat( curry3(objectSet, result, funcsIndex, __), curry4(asyncFunctionArrayAllSeries, funcs, args, __, funcsIndex))) } result[funcsIndex] = resultItem } return result } const always = value => function getter() { return value } const functionObjectAll = function (funcs, args) { const result = {}, promises = [] for (const key in funcs) { const f = funcs[key] const resultItem = typeof f == 'function' ? f(...args) : f if (isPromise(resultItem)) { promises.push(resultItem.then(curry3(objectSet, result, key, __))) } else { result[key] = resultItem } } return promises.length == 0 ? result : promiseAll(promises).then(always(result)) } const _allValues = function (values) { if (isArray(values)) { return areAnyValuesPromises(values) ? promiseAll(values) : values } return areAnyValuesPromises(values) ? promiseObjectAll(values) : values } const all = function (...args) { if (args.length == 1) { const resolversOrValues = args[0] if (isPromise(resolversOrValues)) { return resolversOrValues.then(_allValues) } if (areAllValuesNonfunctions(resolversOrValues)) { return _allValues(resolversOrValues) } return isArray(resolversOrValues) ? curryArgs2(functionArrayAll, resolversOrValues, __) : curryArgs2(functionObjectAll, resolversOrValues, __) } const resolversOrValues = args[args.length - 1] const argValues = args.slice(0, -1) if (areAnyValuesPromises(argValues)) { return isArray(resolversOrValues) ? promiseAll(argValues) .then(curry2(functionArrayAll, resolversOrValues, __)) : promiseAll(argValues) .then(curry2(functionObjectAll, resolversOrValues, __)) } return isArray(resolversOrValues) ? functionArrayAll(resolversOrValues, argValues) : functionObjectAll(resolversOrValues, argValues) /* //////////////////////////////////////////////////////////////// const funcs = args.pop() if (args.length == 0) { return isArray(funcs) ? curryArgs2(functionArrayAll, funcs, __) : curryArgs2(functionObjectAll, funcs, __) } if (areAnyValuesPromises(args)) { return isArray(funcs) ? promiseAll(args).then(curry2(functionArrayAll, funcs, __)) : promiseAll(args).then(curry2(functionObjectAll, funcs, __)) } return isArray(funcs) ? functionArrayAll(funcs, args) : functionObjectAll(funcs, args) */ } all.series = function allSeries(...args) { const funcs = args.pop() if (args.length == 0) { return curryArgs2(functionArrayAllSeries, funcs, __) } if (areAnyValuesPromises(args)) { return promiseAll(args).then(curry2(functionArrayAllSeries, funcs, __)) } return functionArrayAllSeries(funcs, args) } export default all