UNPKG

rubico

Version:

[a]synchronous functional programming

1,922 lines (1,700 loc) 97.4 kB
/** * Rubico v2.13.0 * https://rubico.land/ * * © Richard Yufei Tong, King of Software * Rubico may be freely distributed under the CFOSS 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) { 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) } const compose = function (...args) { if (typeof args[0] == 'function') { return args.reduceRight(funcConcat) } 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 resultElement = typeof f == 'function' ? f(...args) : f if (isPromise(resultElement)) { isAsync = true } result[funcsIndex] = resultElement } 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 resultElement = funcs[funcsIndex](...args) result[funcsIndex] = isPromise(resultElement) ? await resultElement : resultElement } return result } const functionArrayAllSeries = function (funcs, args) { const funcsLength = funcs.length, result = [] let funcsIndex = -1 while (++funcsIndex < funcsLength) { const f = funcs[funcsIndex] const resultElement = typeof f == 'function' ? f(...args) : f if (isPromise(resultElement)) { return resultElement.then(funcConcat( curry3(objectSet, result, funcsIndex, __), curry4(asyncFunctionArrayAllSeries, funcs, args, __, funcsIndex))) } result[funcsIndex] = resultElement } 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 asyncFunctionObjectAllSeries = async function (funcs, args, result, keys, keysIndex) { const keysLength = keys.length while (++keysIndex < keysLength) { const key = keys[keysIndex] const f = funcs[key] let resultElement = typeof f == 'function' ? f(...args) : f if (isPromise(resultElement)) { resultElement = await resultElement } result[key] = resultElement } return result } const functionObjectAllSeries = function (funcs, args) { const result = {} const keys = Object.keys(funcs) const keysLength = keys.length let keysIndex = -1 while (++keysIndex < keysLength) { const key = keys[keysIndex] const f = funcs[key] const resultElement = typeof f == 'function' ? f(...args) : f if (isPromise(resultElement)) { return resultElement.then(funcConcat( curry3(objectSet, result, key, __), curry5(asyncFunctionObjectAllSeries, funcs, args, __, keys, keysIndex))) } result[key] = resultElement } return result } const functionObjectAll = function (funcs, args) { const result = {}, promises = [] for (const key in funcs) { const f = funcs[key] const resultElement = typeof f == 'function' ? f(...args) : f if (isPromise(resultElement)) { promises.push(resultElement.then(curry3(objectSet, result, key, __))) } else { result[key] = resultElement } } 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) } all.series = function allSeries(...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(functionArrayAllSeries, resolversOrValues, __) : curryArgs2(functionObjectAllSeries, resolversOrValues, __) } const resolversOrValues = args[args.length - 1] const argValues = args.slice(0, -1) if (areAnyValuesPromises(argValues)) { return isArray(resolversOrValues) ? promiseAll(argValues) .then(curry2(functionArrayAllSeries, resolversOrValues, __)) : promiseAll(argValues) .then(curry2(functionObjectAllSeries, resolversOrValues, __)) } return isArray(resolversOrValues) ? functionArrayAllSeries(resolversOrValues, argValues) : functionObjectAllSeries(resolversOrValues, argValues) } 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 promiseRace = Promise.race.bind(Promise) class LinkedList { constructor() { this.first = null this.last = null this.length = 0 } // popFirst() -> firstValue any popFirst() { const first = this.first if (first == null) { return undefined } if (first.next) { this.first = first.next } else { this.first = null } this.length -= 1 return first.value } // append(value any) -> undefined append(value) { const node = { value } if (this.first == null) { this.first = node } if (this.last == null) { this.last = node } else { this.last.next = node this.last = node } this.length += 1 } } const symbolAsyncIterator = Symbol.asyncIterator const arrayPush = function (array, value) { array.push(value) return array } const sleep = time => new Promise(resolve => { setTimeout(resolve, time) }) const MappingAsyncIterator = (asyncIterator, mapper) => { const buffer = new LinkedList() let index = -1 let consumingAsyncIterator = false let isAsyncIteratorDone = false return { [symbolAsyncIterator]() { return this }, // _consumeAsyncIterator() -> Promise<> async _consumeAsyncIterator() { for await (const item of asyncIterator) { index += 1 const mappedItem = mapper(item) buffer.append(mappedItem) } isAsyncIteratorDone = true }, async next() { if (!consumingAsyncIterator) { this._consumeAsyncIterator() consumingAsyncIterator = true } while (!isAsyncIteratorDone) { if (buffer.length > 0) { let value = buffer.popFirst() if (isPromise(value)) { value = await value } return { value, done: false } } await sleep(10) } if (buffer.length > 0) { let value = buffer.popFirst() if (isPromise(value)) { value = await value } return { value, done: false } } return { value: undefined, done: true } }, } } const SerialMappingAsyncIterator = (asyncIterator, mapper) => { const buffer = new LinkedList() let index = -1 let consumingAsyncIterator = false let isAsyncIteratorDone = false return { [symbolAsyncIterator]() { return this }, // _consumeAsyncIterator() -> Promise<> async _consumeAsyncIterator() { for await (const item of asyncIterator) { index += 1 let mappedItem = mapper(item) if (isPromise(mappedItem)) { mappedItem = await mappedItem } buffer.append(mappedItem) } isAsyncIteratorDone = true }, async next() { if (!consumingAsyncIterator) { this._consumeAsyncIterator() consumingAsyncIterator = true } while (!isAsyncIteratorDone) { if (buffer.length > 0) { return { value: buffer.popFirst(), done: false } } await sleep(10) } if (buffer.length > 0) { return { value: buffer.popFirst(), done: false } } return { value: undefined, done: true } }, } } 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 resultElement = mapper(array[index], index, array) if (isPromise(resultElement)) { isAsync = true } result[index] = resultElement } 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 element of set) { const resultElement = mapper(element, element, set) if (isPromise(resultElement)) { promises.push(resultElement.then(curry3(callPropUnary, result, 'add', __))) } else { result.add(resultElement) } } 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, element] of value) { const resultElement = mapper(element, key, value) if (isPromise(resultElement)) { promises.push(resultElement.then( curry4(callPropBinary, result, 'set', key, __))) } else { result.set(key, resultElement) } } 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 resultElement = mapper(object[key], key, object) if (isPromise(resultElement)) { isAsync = true } result[key] = resultElement } return isAsync ? promiseObjectAll(result) : result } const arrayMapSeriesAsync = async function ( array, mapper, result, index, ) { const arrayLength = array.length while (++index < arrayLength) { const resultElement = mapper(array[index], index) result[index] = isPromise(resultElement) ? await resultElement : resultElement } return result } const arrayMapSeries = function (array, mapper) { const arrayLength = array.length, result = Array(arrayLength) let index = -1 while (++index < arrayLength) { const resultElement = mapper(array[index], index) if (isPromise(resultElement)) { return resultElement.then(funcConcat( curry3(objectSet, result, index, __), curry4(arrayMapSeriesAsync, array, mapper, __, index))) } result[index] = resultElement } 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 resultElement = f(object[key]) if (isPromise(resultElement)) { resultElement = await resultElement } result[key] = resultElement } return result } const objectMapSeries = function (object, f) { const result = {} const doneKeys = {} for (const key in object) { doneKeys[key] = true const resultElement = f(object[key], key, object) if (isPromise(resultElement)) { return resultElement.then(funcConcat( curry3(objectSet, result, key, __), thunkify4(_objectMapSeriesAsync, object, f, result, doneKeys), )) } result[key] = resultElement } 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 resultElement = f(iteration.value) if (isPromise(resultElement)) { resultElement = await resultElement } result.add(resultElement) 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 resultElement = f(iteration.value) if (isPromise(resultElement)) { return resultElement.then(funcConcat( curry2(setAdd, result, __), thunkify3(_setMapSeriesAsync, iterator, f, result), )) } result.add(resultElement) 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 resultElement = f(iteration.value[1]) if (isPromise(resultElement)) { resultElement = await resultElement } result.set(iteration.value[0], resultElement) 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 resultElement = f(iteration.value[1]) if (isPromise(resultElement)) { return resultElement.then(funcConcat( curry3(mapSet, result, key, __), thunkify3(_mapMapSeriesAsync, iterator, f, result), )) } result.set(key, resultElement) iteration = iterator.next() } return result } const tapSync = func => function tapping(...args) { func(...args) return args[0] } 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 resultElement = f(array[index]) if (isPromise(resultElement)) { const selfDeletingPromise = resultElement.then( tapSync(() => promises.delete(selfDeletingPromise))) promises.add(selfDeletingPromise) result[index] = selfDeletingPromise } else { result[index] = resultElement } } return promiseAll(result) } const arrayMapPool = function (array, concurrency, f) { const arrayLength = array.length, result = Array(arrayLength) let index = -1 while (++index < arrayLength) { const resultElement = f(array[index]) if (isPromise(resultElement)) { const promises = new Set(), selfDeletingPromise = resultElement.then( tapSync(() => promises.delete(selfDeletingPromise))) promises.add(selfDeletingPromise) result[index] = selfDeletingPromise return arrayMapPoolAsync( array, f, concurrency, result, index, promises) } result[index] = resultElement } 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 resultElement = f(iteration.value, iteration.value, s) if (isPromise(resultElement)) { const selfDeletingPromise = resultElement.then(resolvedValue => { promises.delete(selfDeletingPromise) result.add(resolvedValue) }) promises.add(selfDeletingPromise) } else { result.add(resultElement) } 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 resultElement = f(iteration.value, iteration.value, s) if (isPromise(resultElement)) { const promises = new Set() const selfDeletingPromise = resultElement.then(resolvedValue => { promises.delete(selfDeletingPromise) result.add(resolvedValue) }) promises.add(selfDeletingPromise) return _setMapPoolAsync(s, iterator, concurrency, f, result, promises) } result.add(resultElement) 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 resultElement = f(iteration.value[1], key, m) if (isPromise(resultElement)) { result.set(key, resultElement) const selfDeletingPromise = resultElement.then(resolvedValue => { promises.delete(selfDeletingPromise) result.set(key, resolvedValue) }) promises.add(selfDeletingPromise) } else { result.set(key, resultElement) } 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 resultElement = f(iteration.value[1], key, m) if (isPromise(resultElement)) { const promises = new Set() result.set(key, resultElement) const selfDeletingPromise = resultElement.then(resolvedValue => { promises.delete(selfDeletingPromise) result.set(key, resolvedValue) }) promises.add(selfDeletingPromise) return _mapMapPoolAsync(m, iterator, concurrency, f, result, promises) } result.set(key, resultElement) 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 resultElement = f(o[key], key, o) if (isPromise(resultElement)) { result[key] = resultElement const selfDeletingPromise = resultElement.then(resolvedValue => { promises.delete(selfDeletingPromise) result[key] = resolvedValue }) promises.add(selfDeletingPromise) } else { result[key] = resultElement } } 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 resultElement = f(o[key], key, o) if (isPromise(resultElement)) { const promises = new Set() result[key] = resultElement const selfDeletingPromise = resultElement.then(resolvedValue => { promises.delete(selfDeletingPromise) result[key] = resolvedValue }) promises.add(selfDeletingPromise) return _objectMapPoolAsync(o, concurrency, f, result, doneKeys, promises) } result[key] = resultElement } return result } const funcApply2 = (func, context, args) => func.apply(context, args) const _curryArity = (arity, func, context, args) => function curried(...curriedArgs) { const argsLength = args.length, curriedArgsLength = curriedArgs.length, nextArgs = [] let argsIndex = -1, curriedArgsIndex = -1, numCurriedPlaceholders = 0 while ((argsIndex += 1) < 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) { if (areAnyValuesPromises(nextArgs)) { return numCurriedPlaceholders == 0 ? promiseAll(nextArgs).then(curry3(funcApply2, func, context, __)) : promiseAll(nextArgs).then(curry4(curryArity, arity, func, context, __)) } return numCurriedPlaceholders == 0 ? func.apply(context, nextArgs) : curryArity(arity, func, context, nextArgs) } } while ((curriedArgsIndex += 1) < curriedArgsLength) { const curriedArg = curriedArgs[curriedArgsIndex] if (curriedArg == __) { numCurriedPlaceholders += 1 } nextArgs.push(curriedArg) if (nextArgs.length == arity) { if (areAnyValuesPromises(nextArgs)) { return numCurriedPlaceholders == 0 ? promiseAll(nextArgs).then(curry3(funcApply2, func, context, __)) : promiseAll(nextArgs).then(curry4(curryArity, arity, func, context, __)) } return numCurriedPlaceholders == 0 ? func.apply(context, nextArgs) : curryArity(arity, func, context, nextArgs) } } return areAnyValuesPromises(nextArgs) ? promiseAll(nextArgs).then(curry4(curryArity, arity, func, context, __)) : curryArity(arity, func, context, nextArgs) } const curryArity = function (arity, func, context, args) { const argsLength = args.length if (argsLength < arity) { return _curryArity(arity, func, context, args) } let argsIndex = -1 while ((argsIndex += 1) < argsLength) { const arg = args[argsIndex] if (arg == __) { return _curryArity(arity, func, context, args) } } return func.apply(context, 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, this, [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, this, [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, f) { if (isArray(value)) { return arrayMap(value, f) } if (value == null) { return value } if (typeof value.then == 'function') { return value.then(f) } if (typeof value == 'string' || value.constructor == String) { return stringMap(value, f) } if (value.constructor == Set) { return setMap(value, f) } if (value.constructor == Map) { return mapMap(value, f) } if (typeof value[symbolIterator] == 'function') { return MappingIterator(value[symbolIterator](), f) } if (typeof value[symbolAsyncIterator] == 'function') { return MappingAsyncIterator(value[symbolAsyncIterator](), f) } if (typeof value.map == 'function') { return value.map(f) } if (value.constructor == Object) { return objectMap(value, f) } return f(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, f function) -> Object|Map const _mapEntries = (value, f) => { if (value == null) { throw new TypeError('value is not an Object or Map') } if (value.constructor == Object) { return objectMapEntries(value, f) } if (value.constructor == Map) { return mapMapEntries(value, f) } 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 (functor, f) { if (isArray(functor)) { return arrayMapSeries(functor, f) } if (functor == null) { throw new TypeError(`invalid functor ${functor}`) } if (typeof functor == 'string' || functor.constructor == String) { return stringMapSeries(functor, f) } if (functor.constructor == Set) { return setMapSeries(functor, f) } if (functor.constructor == Map) { return mapMapSeries(functor, f) } if (typeof functor[symbolIterator] == 'function') { return MappingIterator(functor[symbolIterator](), f) } if (typeof functor[symbolAsyncIterator] == 'function') { return SerialMappingAsyncIterator(functor[symbolAsyncIterator](), f) } if (typeof functor.map == 'function') { return functor.map(f) } if (functor.constructor == Object) { return objectMapSeries(functor, f) } throw new TypeError(`invalid functor ${functor}`) } 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 (f, concurrency, mapper) { if (isArray(f)) { return arrayMapPool(f, concurrency, mapper) } if (f == null) { throw new TypeError(`invalid functor ${f}`) } if (typeof f == 'string' || f.constructor == String) { return stringMapPool(f, concurrency, mapper) } if (f.constructor == Set) { return setMapPool(f, concurrency, mapper) } if (f.constructor == Map) { return mapMapPool(f, concurrency, mapper) } if (f.constructor == Object) { return objectMapPool(f, concurrency, mapper) } throw new TypeError(`invalid functor ${f}`) } 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) => { const buffer = new LinkedList() let index = -1 let consumingAsyncIterator = false let isAsyncIteratorDone = false return { [symbolAsyncIterator]() { return this }, // _consumeAsyncIterator() -> Promise<> async _consumeAsyncIterator() { for await (const item of asyncIterator) { index += 1 const booleanResult = predicate(item) buffer.append([booleanResult, item]) } isAsyncIteratorDone = true }, async next() { if (!consumingAsyncIterator) { this._consumeAsyncIterator() consumingAsyncIterator = true } while (!isAsyncIteratorDone) { if (buffer.length > 0) { let [booleanResult, item] = buffer.popFirst() if (isPromise(booleanResult)) { booleanResult = await booleanResult } if (booleanResult) { return { value: item, done: false } } continue } await sleep(10) } while (buffer.length > 0) { let [booleanResult, item] = buffer.popFirst() if (isPromise(booleanResult)) { booleanResult = await booleanResult } if (booleanResult) { return { value: item, 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 element = array[index], shouldIncludeElement = predicate(element, index, array) if (isPromise(shouldIncludeElement)) { return promiseAll( arrayExtendMap([shouldIncludeElement], array, predicate, index) ).then(curry4(arrayFilterByConditions, array, result, index - 1, __)) } if (shouldIncludeElement) { result[++resultIndex] = element } } 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 element of value) { const predication = predicate(element, element, value) if (isPromise(predication)) { promises.push(predication.then(curry3( thunkConditional, __, thunkify1(resultAdd, element), noop))) } else if (predication) { result.add(element) } } return promises.length == 0 ? result : promiseAll(promises).then(always(result)) } const mapFilter = function (map, predicate) { const result = new Map(), promises = [] for (const [key, element] of map) { const predication = predicate(element, key, map) if (isPromise(predication)) { promises.push(predication.then(curry3(thunkConditional, __, thunkify4(callPropBinary, result, 'set', key, element), noop))) } else if (predication) { result.set(key, element) } } 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 element = object[key], shouldIncludeElement = predicate(element, key, object) if (isPromise(shouldIncludeElement)) { promises.push(shouldIncludeElement.then( curry4(objectSetIf, result, key, object[key], __))) } else if (shouldIncludeElement) { result[key] = element } } 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[symbolIterator] == 'function') { return FilteringIterator(value[symbolIterator](), predicate) } if (typeof value[symbolAsyncIterator] == 'function') { return FilteringAsyncIterator(value[symbolAsyncIterator](), predicate) } if (typeof value.filter == 'function') { return value.filter(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 isPromise(arg0) ? arg0.then(curry2(_filter, __, arg1)) : _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 } 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