UNPKG

rubico

Version:

[a]synchronous functional programming

1,890 lines (1,691 loc) 90 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. */ (function (root, rubico) { if (typeof module == 'object') (module.exports = rubico) // CommonJS else if (typeof define == 'function') define(() => rubico) // AMD else (root.rubico = rubico) // Browser }(typeof globalThis == 'object' ? globalThis : this, (function () { 'use strict' const isArray = Array.isArray const isPromise = value => value != null && typeof value.then == 'function' 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 promiseAll = Promise.all.bind(Promise) const funcConcat = ( funcA, funcB, ) => function pipedFunction(...args) { const intermediate = funcA(...args) return isPromise(intermediate) ? intermediate.then(funcB) : funcB(intermediate) } const funcApply = (func, args) => func(...args) 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) } const pipe = function (...args) { 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) } const compose = function (...args) { const funcs = args.pop() const composition = funcs.reduceRight(funcConcat) if (args.length == 0) { return composition } if (areAnyValuesPromises(args)) { return promiseAll(args).then(curry2(funcApply, composition, __)) } return composition(...args) } const always = value => function getter() { return value } const thunkifyArgs = (func, args) => function thunk() { return func(...args) } const thunkConditional = ( conditionalExpression, thunkOnTruthy, thunkOnFalsy, ) => conditionalExpression ? thunkOnTruthy() : thunkOnFalsy() // 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 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) } // argument resolver for curryArgs3 const curryArgs3ResolveArgs0 = ( baseFunc, arg1, arg2, ) => function args0Resolver(...args) { return baseFunc(args, arg1, arg2) } // argument resolver for curryArgs3 const curryArgs3ResolveArgs1 = ( baseFunc, arg0, arg2, ) => function arg1Resolver(...args) { return baseFunc(arg0, args, arg2) } // argument resolver for curryArgs3 const curryArgs3ResolveArgs2 = ( baseFunc, arg0, arg1, ) => function arg2Resolver(...args) { return baseFunc(arg0, arg1, args) } const curryArgs3 = function (baseFunc, arg0, arg1, arg2) { if (arg0 == __) { return curryArgs3ResolveArgs0(baseFunc, arg1, arg2) } if (arg1 == __) { return curryArgs3ResolveArgs1(baseFunc, arg0, arg2) } return curryArgs3ResolveArgs2(baseFunc, arg0, arg1) } // _tap(args Array, f function) -> Promise|any const _tap = function (args, f) { const result = args[0], call = f(...args) return isPromise(call) ? call.then(always(result)) : result } const tap = function (...args) { const f = args.pop() if (args.length == 0) { return curryArgs2(_tap, __, f) } if (areAnyValuesPromises(args)) { return promiseAll(args).then(curry2(_tap, __, f)) } return _tap(args, f) } const _tapIf = function (predicate, f, args) { const b = predicate(...args) if (isPromise(b)) { return b.then(curry3( thunkConditional, __, thunkifyArgs(tap(f), args), always(args[0]), )) } if (b) { const execution = f(...args) if (isPromise(execution)) { return execution.then(always(args[0])) } } return args[0] } tap.if = function (...args) { if (args.length == 2) { return curryArgs3(_tapIf, args[0], args[1], __) } const argsLength = args.length const f = args[argsLength - 1] const predicate = args[argsLength - 2] const argValues = args.slice(0, -2) if (areAnyValuesPromises(argValues)) { return promiseAll(argValues).then(curry3(_tapIf, predicate, f, __)) } return _tapIf(predicate, f, args) } 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 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 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 } // 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 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) } const objectAssign = Object.assign // _assign(object Object, funcs Object<function>) -> Promise|Object const _assign = function (object, funcs) { const result = functionObjectAll(funcs, [object]) return isPromise(result) ? result.then(curry3(objectAssign, {}, object, __)) : ({ ...object, ...result }) } const assign = function (arg0, arg1) { if (arg1 == null) { return curry2(_assign, __, arg0) } return isPromise(arg0) ? arg0.then(curry2(_assign, __, arg1)) : _assign(arg0, arg1) } const catcherApply = function (catcher, err, args) { return catcher(err, ...args) } // _tryCatch(tryer function, catcher function, args Array) -> Promise const _tryCatch = function (tryer, catcher, args) { try { const result = tryer(...args) return isPromise(result) ? result.catch(curry3(catcherApply, catcher, __, args)) : result } catch (error) { return catcher(error, ...args) } } const tryCatch = function (...args) { if (args.length > 2) { const catcher = args.pop(), tryer = args.pop() if (areAnyValuesPromises(args)) { return promiseAll(args) .then(curry3(_tryCatch, tryer, catcher, __)) } return _tryCatch(tryer, catcher, args) } const tryer = args[0], catcher = args[1] return function tryCatcher(...args) { return _tryCatch(tryer, catcher, args) } } const thunkify3 = (func, arg0, arg1, arg2) => function thunk() { return func(arg0, arg1, arg2) } const arrayConditional = function (array, args, funcsIndex) { const lastIndex = array.length - 1 while ((funcsIndex += 2) < lastIndex) { const predicate = array[funcsIndex], resolverOrValue = array[funcsIndex + 1] const predication = typeof predicate == 'function' ? predicate(...args) : predicate if (isPromise(predication)) { return predication.then(curry3( thunkConditional, __, typeof resolverOrValue == 'function' ? thunkifyArgs(resolverOrValue, args) : always(resolverOrValue), thunkify3(arrayConditional, array, args, funcsIndex), )) } if (predication) { return typeof resolverOrValue == 'function' ? resolverOrValue(...args) : resolverOrValue } } // even number of array if (funcsIndex == array.length) { return undefined } const defaultResolverOrValue = array[lastIndex] return typeof defaultResolverOrValue == 'function' ? defaultResolverOrValue(...args) : defaultResolverOrValue } const thunkify2 = (func, arg0, arg1) => function thunk() { return func(arg0, arg1) } const nonfunctionsConditional = function (array, index) { const length = array.length, lastIndex = length - 1 while ((index += 2) < lastIndex) { const predication = array[index], value = array[index + 1] if (isPromise(predication)) { return predication.then(curry3( thunkConditional, __, always(value), thunkify2(nonfunctionsConditional, array, index), )) } if (predication) { return value } } // even number of array values if (index == length) { return undefined } return array[index] } const switchCase = (...args) => { const values = args.pop() if (areAllValuesNonfunctions(values)) { return nonfunctionsConditional(values, -2) } if (args.length == 0) { return curryArgs3(arrayConditional, values, __, -2) } if (areAnyValuesPromises(args)) { return promiseAll(args).then(curry3(arrayConditional, values, __, -2)) } return arrayConditional(values, args, -2) } const symbolIterator = Symbol.iterator const MappingIterator = (iterator, mapper) => ({ toString() { return '[object MappingIterator]' }, [symbolIterator]() { return this }, next() { const iteration = iterator.next() return iteration.done ? iteration : { value: mapper(iteration.value), done: false } }, }) const NextIteration = value => ({ value, done: false }) const symbolAsyncIterator = Symbol.asyncIterator const MappingAsyncIterator = (asyncIterator, mapper) => ({ [symbolAsyncIterator]() { return this }, async next() { const iteration = await asyncIterator.next() if (iteration.done) { return iteration } const mapped = mapper(iteration.value) return isPromise(mapped) ? mapped.then(NextIteration) : { value: mapped, done: false } } }) const isObject = value => { if (value == null) { return false } const typeofValue = typeof value return (typeofValue == 'object') || (typeofValue == 'function') } const arrayMap = function (array, mapper) { const arrayLength = array.length, result = Array(arrayLength) let index = -1, isAsync = false while (++index < arrayLength) { const resultItem = mapper(array[index], index, array) if (isPromise(resultItem)) { isAsync = true } result[index] = resultItem } return isAsync ? promiseAll(result) : result } const callPropUnary = (value, property, arg0) => value[property](arg0) const stringMap = function (string, mapper) { const result = arrayMap(string, mapper) return isPromise(result) ? result.then(curry3(callPropUnary, __, 'join', '')) : result.join('') } const setMap = function (set, mapper) { const result = new Set(), promises = [] for (const item of set) { const resultItem = mapper(item, item, set) if (isPromise(resultItem)) { promises.push(resultItem.then(curry3(callPropUnary, result, 'add', __))) } else { result.add(resultItem) } } return promises.length == 0 ? result : promiseAll(promises).then(always(result)) } const callPropBinary = (value, property, arg0, arg1) => value[property](arg0, arg1) const mapMap = function (value, mapper) { const result = new Map(), promises = [] for (const [key, item] of value) { const resultItem = mapper(item, key, value) if (isPromise(resultItem)) { promises.push(resultItem.then( curry4(callPropBinary, result, 'set', key, __))) } else { result.set(key, resultItem) } } return promises.length == 0 ? result : promiseAll(promises).then(always(result)) } const objectMap = function (object, mapper) { const result = {} let isAsync = false for (const key in object) { const resultItem = mapper(object[key], key, object) if (isPromise(resultItem)) { isAsync = true } result[key] = resultItem } return isAsync ? promiseObjectAll(result) : result } const arrayMapSeriesAsync = async function ( array, mapper, result, index, ) { const arrayLength = array.length while (++index < arrayLength) { const resultItem = mapper(array[index], index) result[index] = isPromise(resultItem) ? await resultItem : resultItem } return result } const arrayMapSeries = function (array, mapper) { const arrayLength = array.length, result = Array(arrayLength) let index = -1 while (++index < arrayLength) { const resultItem = mapper(array[index], index) if (isPromise(resultItem)) { return resultItem.then(funcConcat( curry3(objectSet, result, index, __), curry4(arrayMapSeriesAsync, array, mapper, __, index))) } result[index] = resultItem } return result } const stringMapSeries = function (string, mapper) { const result = arrayMapSeries(string, mapper) return isPromise(result) ? result.then(curry3(callPropUnary, __, 'join', '')) : result.join('') } const thunkify4 = (func, arg0, arg1, arg2, arg3) => function thunk() { return func(arg0, arg1, arg2, arg3) } // _objectMapSeriesAsync( // object Object, // f function, // result Object, // doneKeys Object // ) -> Promise<object> const _objectMapSeriesAsync = async function (object, f, result, doneKeys) { for (const key in object) { if (key in doneKeys) { continue } let resultItem = f(object[key]) if (isPromise(resultItem)) { resultItem = await resultItem } result[key] = resultItem } return result } const objectMapSeries = function (object, f) { const result = {} const doneKeys = {} for (const key in object) { doneKeys[key] = true const resultItem = f(object[key], key, object) if (isPromise(resultItem)) { return resultItem.then(funcConcat( curry3(objectSet, result, key, __), thunkify4(_objectMapSeriesAsync, object, f, result, doneKeys), )) } result[key] = resultItem } return result } const setAdd = function (set, value) { set.add(value) return set } // _setMapSeriesAsync( // iterator Iterator, // f function, // result Set, // ) -> Promise<Set> const _setMapSeriesAsync = async function (iterator, f, result) { let iteration = iterator.next() while (!iteration.done) { let resultItem = f(iteration.value) if (isPromise(resultItem)) { resultItem = await resultItem } result.add(resultItem) iteration = iterator.next() } return result } const setMapSeries = function (set, f) { const result = new Set() const iterator = set[symbolIterator]() let iteration = iterator.next() while (!iteration.done) { const resultItem = f(iteration.value) if (isPromise(resultItem)) { return resultItem.then(funcConcat( curry2(setAdd, result, __), thunkify3(_setMapSeriesAsync, iterator, f, result), )) } result.add(resultItem) iteration = iterator.next() } return result } const mapSet = function setting(source, key, value) { return source.set(key, value) } // _mapMapSeriesAsync( // iterator Iterator, // f function, // result Map, // ) -> Promise<Map> const _mapMapSeriesAsync = async function (iterator, f, result) { let iteration = iterator.next() while (!iteration.done) { let resultItem = f(iteration.value[1]) if (isPromise(resultItem)) { resultItem = await resultItem } result.set(iteration.value[0], resultItem) iteration = iterator.next() } return result } const mapMapSeries = function (map, f) { const result = new Map() const iterator = map[symbolIterator]() let iteration = iterator.next() while (!iteration.done) { const key = iteration.value[0] const resultItem = f(iteration.value[1]) if (isPromise(resultItem)) { return resultItem.then(funcConcat( curry3(mapSet, result, key, __), thunkify3(_mapMapSeriesAsync, iterator, f, result), )) } result.set(key, resultItem) iteration = iterator.next() } return result } const tapSync = func => function tapping(...args) { func(...args) return args[0] } const promiseRace = Promise.race.bind(Promise) const arrayMapPoolAsync = async function ( array, f, concurrencyLimit, result, index, promises, ) { const arrayLength = array.length while (++index < arrayLength) { if (promises.size >= concurrencyLimit) { await promiseRace(promises) } const resultItem = f(array[index]) if (isPromise(resultItem)) { const selfDeletingPromise = resultItem.then( tapSync(() => promises.delete(selfDeletingPromise))) promises.add(selfDeletingPromise) result[index] = selfDeletingPromise } else { result[index] = resultItem } } return promiseAll(result) } const arrayMapPool = function (array, concurrency, f) { const arrayLength = array.length, result = Array(arrayLength) let index = -1 while (++index < arrayLength) { const resultItem = f(array[index]) if (isPromise(resultItem)) { const promises = new Set(), selfDeletingPromise = resultItem.then( tapSync(() => promises.delete(selfDeletingPromise))) promises.add(selfDeletingPromise) result[index] = selfDeletingPromise return arrayMapPoolAsync( array, f, concurrency, result, index, promises) } result[index] = resultItem } return result } const stringMapPool = function (s, concurrency, f) { const result = arrayMapPool(s, concurrency, f) return isPromise(result) ? result.then(curry3(callPropUnary, __, 'join', '')) : result.join('') } const _setMapPoolAsync = async function ( s, iterator, concurrency, f, result, promises, ) { let iteration = iterator.next() while (!iteration.done) { if (promises.size >= concurrency) { await promiseRace(promises) } const resultItem = f(iteration.value, iteration.value, s) if (isPromise(resultItem)) { const selfDeletingPromise = resultItem.then(resolvedValue => { promises.delete(selfDeletingPromise) result.add(resolvedValue) }) promises.add(selfDeletingPromise) } else { result.add(resultItem) } iteration = iterator.next() } if (promises.size > 0) { await promiseAll(promises) } return result } const setMapPool = function (s, concurrency, f) { const result = new Set() const iterator = s[symbolIterator]() let iteration = iterator.next() while (!iteration.done) { const resultItem = f(iteration.value, iteration.value, s) if (isPromise(resultItem)) { const promises = new Set() const selfDeletingPromise = resultItem.then(resolvedValue => { promises.delete(selfDeletingPromise) result.add(resolvedValue) }) promises.add(selfDeletingPromise) return _setMapPoolAsync(s, iterator, concurrency, f, result, promises) } result.add(resultItem) iteration = iterator.next() } return result } const _mapMapPoolAsync = async function ( m, iterator, concurrency, f, result, promises, ) { let iteration = iterator.next() while (!iteration.done) { if (promises.size >= concurrency) { await promiseRace(promises) } const key = iteration.value[0] const resultItem = f(iteration.value[1], key, m) if (isPromise(resultItem)) { result.set(key, resultItem) const selfDeletingPromise = resultItem.then(resolvedValue => { promises.delete(selfDeletingPromise) result.set(key, resolvedValue) }) promises.add(selfDeletingPromise) } else { result.set(key, resultItem) } iteration = iterator.next() } if (promises.size > 0) { await promiseAll(promises) } return result } const mapMapPool = function (m, concurrency, f) { const result = new Map() const iterator = m[symbolIterator]() let iteration = iterator.next() while (!iteration.done) { const key = iteration.value[0] const resultItem = f(iteration.value[1], key, m) if (isPromise(resultItem)) { const promises = new Set() result.set(key, resultItem) const selfDeletingPromise = resultItem.then(resolvedValue => { promises.delete(selfDeletingPromise) result.set(key, resolvedValue) }) promises.add(selfDeletingPromise) return _mapMapPoolAsync(m, iterator, concurrency, f, result, promises) } result.set(key, resultItem) iteration = iterator.next() } return result } const _objectMapPoolAsync = async function ( o, concurrency, f, result, doneKeys, promises, ) { for (const key in o) { if (key in doneKeys) { continue } if (promises.size >= concurrency) { await promiseRace(promises) } const resultItem = f(o[key], key, o) if (isPromise(resultItem)) { result[key] = resultItem const selfDeletingPromise = resultItem.then(resolvedValue => { promises.delete(selfDeletingPromise) result[key] = resolvedValue }) promises.add(selfDeletingPromise) } else { result[key] = resultItem } } if (promises.size > 0) { await promiseAll(promises) } return result } const objectMapPool = function (o, concurrency, f) { const result = {} const doneKeys = {} for (const key in o) { doneKeys[key] = true const resultItem = f(o[key], key, o) if (isPromise(resultItem)) { const promises = new Set() result[key] = resultItem const selfDeletingPromise = resultItem.then(resolvedValue => { promises.delete(selfDeletingPromise) result[key] = resolvedValue }) promises.add(selfDeletingPromise) return _objectMapPoolAsync(o, concurrency, f, result, doneKeys, promises) } result[key] = resultItem } return result } const _curryArity = (arity, func, args) => function curried(...curriedArgs) { const argsLength = args.length, curriedArgsLength = curriedArgs.length, nextArgs = [] let argsIndex = -1, curriedArgsIndex = -1, numCurriedPlaceholders = 0 while (++argsIndex < argsLength) { const arg = args[argsIndex] if (arg == __ && (curriedArgsIndex += 1) < curriedArgsLength) { const curriedArg = curriedArgs[curriedArgsIndex] if (curriedArg == __) { numCurriedPlaceholders += 1 } nextArgs.push(curriedArg) } else { nextArgs.push(arg) } if (nextArgs.length == arity) { return numCurriedPlaceholders == 0 ? func(...nextArgs) : curryArity(arity, func, nextArgs) } } while (++curriedArgsIndex < curriedArgsLength) { const curriedArg = curriedArgs[curriedArgsIndex] if (curriedArg == __) { numCurriedPlaceholders += 1 } nextArgs.push(curriedArg) if (nextArgs.length == arity) { return numCurriedPlaceholders == 0 ? func(...nextArgs) : curryArity(arity, func, nextArgs) } } return curryArity(arity, func, nextArgs) } const curryArity = function (arity, func, args) { const argsLength = args.length if (argsLength < arity) { return _curryArity(arity, func, args) } let argsIndex = -1 while (++argsIndex < argsLength) { const arg = args[argsIndex] if (arg == __) { return _curryArity(arity, func, args) } } return func(...args) } const spread2 = func => function spreading2([arg0, arg1]) { return func(arg0, arg1) } const objectMapEntries = function (object, mapper) { const result = {}, promises = [] for (const key in object) { const value = object[key], mapping = mapper([key, value]) if (isPromise(mapping)) { promises.push(mapping.then( spread2(curryArity(3, objectSet, [result])))) } else { result[mapping[0]] = mapping[1] } } return promises.length == 0 ? result : promiseAll(promises).then(always(result)) } // (mapper function, result Map, promises Array<Promise>) => (key any, value any) => () const mapMapEntriesForEachCallback = ( mapper, result, promises, ) => function callback(value, key) { const mapping = mapper([key, value]) if (isPromise(mapping)) { promises.push(mapping.then(spread2(curryArity(3, mapSet, [result])))) } else { result.set(mapping[0], mapping[1]) } } const mapMapEntries = function (source, mapper) { const result = new Map(), promises = [] source.forEach(mapMapEntriesForEachCallback(mapper, result, promises)) return promises.length == 0 ? result : promiseAll(promises).then(always(result)) } const _map = function (value, mapper) { if (isArray(value)) { return arrayMap(value, mapper) } if (value == null) { return value } if (typeof value.then == 'function') { return value.then(mapper) } if (typeof value.map == 'function') { return value.map(mapper) } if (typeof value == 'string' || value.constructor == String) { return stringMap(value, mapper) } if (value.constructor == Set) { return setMap(value, mapper) } if (value.constructor == Map) { return mapMap(value, mapper) } if (typeof value[symbolIterator] == 'function') { return MappingIterator(value[symbolIterator](), mapper) } if (typeof value[symbolAsyncIterator] == 'function') { return MappingAsyncIterator(value[symbolAsyncIterator](), mapper) } if (value.constructor == Object) { return objectMap(value, mapper) } return mapper(value) } const map = function (arg0, arg1) { if (arg1 == null) { return curry2(_map, __, arg0) } return isPromise(arg0) ? arg0.then(curry2(_map, __, arg1)) : _map(arg0, arg1) } // _mapEntries(value Object|Map, mapper function) -> Object|Map const _mapEntries = (value, mapper) => { if (value == null) { throw new TypeError('value is not an Object or Map') } if (value.constructor == Object) { return objectMapEntries(value, mapper) } if (value.constructor == Map) { return mapMapEntries(value, mapper) } throw new TypeError('value is not an Object or Map') } map.entries = function mapEntries(arg0, arg1) { if (arg1 == null) { return curry2(_mapEntries, __, arg0) } return isPromise(arg0) ? arg0.then(curry2(_mapEntries, __, arg1)) : _mapEntries(arg0, arg1) } const _mapSeries = function (collection, f) { if (isArray(collection)) { return arrayMapSeries(collection, f) } if (collection == null) { throw new TypeError(`invalid collection ${collection}`) } if (typeof collection == 'string' || collection.constructor == String) { return stringMapSeries(collection, f) } if (collection.constructor == Set) { return setMapSeries(collection, f) } if (collection.constructor == Map) { return mapMapSeries(collection, f) } if (collection.constructor == Object) { return objectMapSeries(collection, f) } throw new TypeError(`invalid collection ${collection}`) } map.series = function mapSeries(arg0, arg1) { if (arg1 == null) { return curry2(_mapSeries, __, arg0) } return isPromise(arg0) ? arg0.then(curry2(_mapSeries, __, arg1)) : _mapSeries(arg0, arg1) } const _mapPool = function (collection, concurrency, f) { if (isArray(collection)) { return arrayMapPool(collection, concurrency, f) } if (collection == null) { throw new TypeError(`invalid collection ${collection}`) } if (typeof collection == 'string' || collection.constructor == String) { return stringMapPool(collection, concurrency, f) } if (collection.constructor == Set) { return setMapPool(collection, concurrency, f) } if (collection.constructor == Map) { return mapMapPool(collection, concurrency, f) } if (collection.constructor == Object) { return objectMapPool(collection, concurrency, f) } throw new TypeError(`invalid collection ${collection}`) } map.pool = function mapPool(arg0, arg1, arg2) { if (arg2 == null) { return curry3(_mapPool, __, arg0, arg1) } return isPromise(arg0) ? arg0.then(curry3(_mapPool, __, arg1, arg2)) : _mapPool(arg0, arg1, arg2) } const FilteringIterator = (iterator, predicate) => ({ [symbolIterator]() { return this }, next() { let iteration = iterator.next() while (!iteration.done) { const { value } = iteration if (predicate(value)) { return { value, done: false } } iteration = iterator.next() } return iteration }, }) const FilteringAsyncIterator = (asyncIterator, predicate) => ({ isAsyncIteratorDone: false, [symbolAsyncIterator]() { return this }, async next() { while (!this.isAsyncIteratorDone) { const { value, done } = await asyncIterator.next() if (done) { this.isAsyncIteratorDone = true } else { const predication = predicate(value) if (isPromise(predication) ? await predication : predication) { return { value, done: false } } } } return { value: undefined, done: true } }, }) const arrayExtendMap = function ( array, values, valuesMapper, valuesIndex, ) { const valuesLength = values.length let arrayIndex = array.length - 1 while (++valuesIndex < valuesLength) { array[++arrayIndex] = valuesMapper(values[valuesIndex], valuesIndex, array) } return array } const arrayFilterByConditions = function ( array, result, index, conditions, ) { const arrayLength = array.length let conditionsIndex = -1 while (++index < arrayLength) { if (conditions[++conditionsIndex]) { result.push(array[index]) } } return result } const arrayFilter = function (array, predicate) { const arrayLength = array.length, result = [] let index = -1, resultIndex = -1 while (++index < arrayLength) { const item = array[index], shouldIncludeItem = predicate(item, index, array) if (isPromise(shouldIncludeItem)) { return promiseAll( arrayExtendMap([shouldIncludeItem], array, predicate, index) ).then(curry4(arrayFilterByConditions, array, result, index - 1, __)) } if (shouldIncludeItem) { result[++resultIndex] = item } } return result } const stringFilter = function (string, predicate) { const filteredCharactersArray = arrayFilter(string, predicate) return isPromise(filteredCharactersArray) ? filteredCharactersArray.then(curry3(callPropUnary, __, 'join', '')) : filteredCharactersArray.join('') } const thunkify1 = (func, arg0) => function thunk() { return func(arg0) } const noop = function () {} const setFilter = function (value, predicate) { const result = new Set(), resultAdd = result.add.bind(result), promises = [] for (const item of value) { const predication = predicate(item, item, value) if (isPromise(predication)) { promises.push(predication.then(curry3( thunkConditional, __, thunkify1(resultAdd, item), noop))) } else if (predication) { result.add(item) } } return promises.length == 0 ? result : promiseAll(promises).then(always(result)) } const mapFilter = function (map, predicate) { const result = new Map(), promises = [] for (const [key, item] of map) { const predication = predicate(item, key, map) if (isPromise(predication)) { promises.push(predication.then(curry3(thunkConditional, __, thunkify4(callPropBinary, result, 'set', key, item), noop))) } else if (predication) { result.set(key, item) } } return promises.length == 0 ? result : promiseAll(promises).then(always(result)) } const objectSetIf = function ( object, key, value, condition, ) { if (condition) { object[key] = value } } const objectFilter = function (object, predicate) { const result = {}, promises = [] for (const key in object) { const item = object[key], shouldIncludeItem = predicate(item, key, object) if (isPromise(shouldIncludeItem)) { promises.push(shouldIncludeItem.then( curry4(objectSetIf, result, key, object[key], __))) } else if (shouldIncludeItem) { result[key] = item } } return promises.length == 0 ? result : promiseAll(promises).then(always(result)) } const _filter = function (value, predicate) { if (isArray(value)) { return arrayFilter(value, predicate) } if (value == null) { return value } if (typeof value == 'string' || value.constructor == String) { return stringFilter(value, predicate) } if (value.constructor == Set) { return setFilter(value, predicate) } if (value.constructor == Map) { return mapFilter(value, predicate) } if (typeof value.filter == 'function') { return value.filter(predicate) } if (typeof value[symbolIterator] == 'function') { return FilteringIterator(value[symbolIterator](), predicate) } if (typeof value[symbolAsyncIterator] == 'function') { return FilteringAsyncIterator(value[symbolAsyncIterator](), predicate) } if (value.constructor == Object) { return objectFilter(value, predicate) } return value } const filter = function (arg0, arg1) { if (typeof arg0 == 'function') { return curry2(_filter, __, arg0) } return _filter(arg0, arg1) } const objectValues = Object.values const objectProto = Object.prototype const nativeObjectToString = objectProto.toString const objectToString = value => nativeObjectToString.call(value) const generatorFunctionTag = '[object GeneratorFunction]' const isGeneratorFunction = value => objectToString(value) == generatorFunctionTag const asyncGeneratorFunctionTag = '[object AsyncGeneratorFunction]' const isAsyncGeneratorFunction = value => objectToString(value) == asyncGeneratorFunctionTag const iteratorReduceAsync = async function ( iterator, reducer, result, ) { let iteration = iterator.next() if (iteration.done) { return result } while (!iteration.done) { result = reducer(result, iteration.value) if (isPromise(result)) { result = await result } iteration = iterator.next() } return result } const iteratorReduce = function (iterator, reducer, result) { let iteration = iterator.next() if (iteration.done) { return result } if (result === undefined) { result = iteration.value iteration = iterator.next() } while (!iteration.done) { result = reducer(result, iteration.value) if (isPromise(result)) { return result.then(curry3(iteratorReduceAsync, iterator, reducer, __)) } iteration = iterator.next() } return result } const asyncIteratorReduce = async function (asyncIterator, reducer, result) { let iteration = await asyncIterator.next() if (iteration.done) { return result } if (result === undefined) { result = iteration.value iteration = await asyncIterator.next() } while (!iteration.done) { result = await reducer(result, iteration.value) iteration = await asyncIterator.next() } return result } const arrayReduceAsync = async function ( array, reducer, result, index, ) { const length = array.length while (++index < length) { result = reducer(result, array[index], index, array) if (isPromise(result)) { result = await result } } return result } const arrayReduce = function (array, reducer, result) { const arrayLength = array.length let index = -1 if (result === undefined) { result = array[++index] } while (++index < arrayLength) { result = reducer(result, array[index], index, array) if (isPromise(result)) { return result.then(curry4(arrayReduceAsync, array, reducer, __, index)) } } return result } // argument resolver for curry5 const curry5ResolveArg0 = ( baseFunc, arg1, arg2, arg3, arg4, ) => function arg0Resolver(arg0) { return baseFunc(arg0, arg1, arg2, arg3, arg4) } // argument resolver for curry5 const curry5ResolveArg1 = ( baseFunc, arg0, arg2, arg3, arg4, ) => function arg1Resolver(arg1) { return baseFunc(arg0, arg1, arg2, arg3, arg4) } // argument resolver for curry5 const curry5ResolveArg2 = ( baseFunc, arg0, arg1, arg3, arg4, ) => function arg2Resolver(arg2) { return baseFunc(arg0, arg1, arg2, arg3, arg4) } // argument resolver for curry5 const curry5ResolveArg3 = ( baseFunc, arg0, arg1, arg2, arg4, ) => function arg3Resolver(arg3) { return baseFunc(arg0, arg1, arg2, arg3, arg4) } // argument resolver for curry5 const curry5ResolveArg4 = ( baseFunc, arg0, arg1, arg2, arg3, ) => function arg3Resolver(arg4) { return baseFunc(arg0, arg1, arg2, arg3, arg4) } const curry5 = function (baseFunc, arg0, arg1, arg2, arg3, arg4) { if (arg0 == __) { return curry5ResolveArg0(baseFunc, arg1, arg2, arg3, arg4) } if (arg1 == __) { return curry5ResolveArg1(baseFunc, arg0, arg2, arg3, arg4) } if (arg2 == __) { return curry5ResolveArg2(baseFunc, arg0, arg1, arg3, arg4) } if (arg3 == __) { return curry5ResolveArg3(baseFunc, arg0, arg1, arg2, arg4) } return curry5ResolveArg4(baseFunc, arg0, arg1, arg2, arg3) } const objectKeys = Object.keys const objectReduceAsync = async function (object, reducer, result, keys, index) { const keysLength = keys.length while (++index < keysLength) { const key = keys[index] result = reducer(result, object[key], key, object) if (isPromise(result)) { result = await result } } return result } const objectReduce = function (object, reducer, result) { const keys = objectKeys(object), keysLength = keys.length let index = -1 if (result === undefined) { result = object[keys[++index]] } while (++index < keysLength) { const key = keys[index] result = reducer(result, object[key], key, object) if (isPromise(result)) { return result.then(curry5(objectReduceAsync, object, reducer, __, keys, index)) } } return result } const mapReduceAsync = async function ( map, reducer, result, mapEntriesIter, ) { for (const [key, value] of mapEntriesIter) { result = reducer(result, value, key, map) if (isPromise(result)) { result = await result } } return result } const mapReduce = function (map, reducer, result) { const mapEntriesIter = map.entries() if (result === undefined) { const firstIteration = mapEntriesIter.next() if (firstIteration.done) { return result } result = firstIteration.value[1] } for (const [key, value] of mapEntriesIter) { result = reducer(result, value, key, map) if (isPromise(result)) { return result.then(curry4( mapReduceAsync, map, reducer, __, mapEntriesIter)) } } return result } const reducerConcat = ( reducerA, reducerB, ) => function pipedReducer(result, item) { const intermediate = reducerA(result, item) return isPromise(intermediate) ? intermediate.then(curry2(reducerB, __, item)) : reducerB(intermediate, item) } const genericReduce = function (collection, reducer, result) { if (isArray(collection)) { return arrayReduce(collection, reducer, result) } if (collection == null) { return result === undefined ? curry2(reducer, collection, __) : reducer(result, collection) } if (collection.constructor == Map) { return mapReduce(collection, reducer, result) } if (typeof collection[symbolIterator] == 'function') { return iteratorReduce( collection[symbolIterator](), reducer, result) } if (typeof collection[symbolAsyncIterator] == 'function') { return asyncIteratorReduce( collection[symbolAsyncIterator](), reducer, result) } if (typeof collection.reduce == 'function') { return collection.reduce(reducer, result) } if (typeof collection.chain == 'function') { return collection.chain(curry2(reducer, result, __)) } if (typeof collection.flatMap == 'function') { return collection.flatMap(curry2(reducer, result, __)) } if (collection.constructor == Object) { return objectReduce(collection, reducer, result) } return result === undefined ? curry2(reducer, collection, __) : reducer(result, collection) } // _reduce(collection any, reducer function, initialValue function|any) -> Promise const _reduce = function (collection, reducer, initialValue) { if (typeof initialValue == 'function') { const actualInitialValue = initialValue(collection) return isPromise(actualInitialValue) ? actualInitialValue.then(curry3(genericReduce, collection, reducer, __)) : genericReduce(collection, reducer, actualInitialValue) } return isPromise(initialValue) ? initialValue.then(curry3(genericReduce, collection, reducer, __)) : genericReduce(collection, reducer, initialValue) } const reduce = function (...args) { if (typeof args[0] == 'function') { return curry3(_reduce, __, args[0], args[1]) } if (isPromise(args[0])) { return args[0].then(curry3(_reduce, __, args[1], args[2])) } return _reduce(args[0], args[1], args[2]) } const isBinary = ArrayBuffer.isView const add = (a, b) => a + b const _arrayExtend = function (array, values) { const arrayLength = array.length, valuesLength = values.length let valuesIndex = -1 while (++valuesIndex < valuesLength) { array[arrayLength + valuesIndex] = values[valuesIndex] } return array } const arrayExtend = function (array, values) { if (isArray(values) || isBinary(values)) { return _arrayExtend(array, values) } array.push(values) return array } const globalThisHasBuffer = typeof Buffer == 'function' const bufferAlloc = globalThisHasBuffer ? Buffer.alloc : noop const _binaryExtend = function (typedArray, array) { const offset = typedArray.length const result = globalThisHasBuffer && typedArray.constructor == Buffer ? bufferAlloc(offset + array.length) : new typedArray.constructor(offset + array.length) result.set(typedArray) result.set(array, offset) return result } const binaryExtend = function (typedArray, array) { if (isArray(array) || isBinary(array)) { return _binaryExtend(typedArray, array) } return _binaryExtend(typedArray, [array]) } const isNodeReadStream = value => value != null && typeof value.pipe == 'function' const __streamWrite = stream => function appender( chunk, encoding, callback, ) { stream.write(chunk, encoding, callback) return stream } const _streamExtendExecutor = ( resultStream, stream, ) => function executor(resolve, reject) { stream.on('data', __streamWrite(resultStream)) stream.on('end', thunkify1(resolve, resultStream)) stream.on('error', reject) } const _streamExtend = ( resultStream, stream, ) => new Promise(_streamExtendExecutor(resultStream, stream)) const streamExtend = function (stream, values) { if (isNodeReadStream(values)) { return _streamExtend(stream, values) } stream.write(values) return stream } const setExtend = function (set, values) { if (values != null && values.constructor == Set) { for (const value of values) { set.add(value) } return set } return set.add(values) } const callConcat = function (object, values) { return object.concat(values) } const identityTransform = function (collection, transducer, accum) { const nil = genericReduce(collection, transducer(noop), null) return isPromise(nil) ? nil.then(always(accum)) : accum } const genericTransform = function (collection, transducer, accum) { if (isArray(accum)) { return genericReduce(collection, transducer(arrayExtend), accum) } if (isBinary(accum)) { const intermediateArray = genericReduce(collection, transducer(arrayExtend), []) return isPromise(intermediateArray) ? intermediateArray.then(curry2(binaryExtend, accum, __)) : binaryExtend(accum, intermediateArray) } if (accum == n