rubico
Version:
[a]synchronous functional programming
182 lines (159 loc) • 4.76 kB
JavaScript
/**
* 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 __ = 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 isArray = Array.isArray
const objectValues = Object.values
const SelfReferencingPromise = function (basePromise) {
const promise = basePromise.then(res => [res, promise])
return promise
}
const promiseRace = Promise.race.bind(Promise)
const asyncArraySome = async function (
array, predicate, index, promisesInFlight,
) {
const length = array.length
while (++index < length) {
const predication = predicate(array[index])
if (isPromise(predication)) {
promisesInFlight.add(SelfReferencingPromise(predication))
} else if (predication) {
return true
}
}
while (promisesInFlight.size > 0) {
const [predication, promise] = await promiseRace(promisesInFlight)
promisesInFlight.delete(promise)
if (predication) {
return true
}
}
return false
}
const arraySome = function (array, predicate) {
const length = array.length
let index = -1
while (++index < length) {
const predication = predicate(array[index])
if (isPromise(predication)) {
return asyncArraySome(
array, predicate, index, new Set([SelfReferencingPromise(predication)]))
}
if (predication) {
return true
}
}
return false
}
const asyncIteratorSome = async function (
iterator, predicate, promisesInFlight, maxConcurrency = 20,
) {
let iteration = iterator.next()
if (isPromise(iteration)) {
iteration = await iteration
}
while (!iteration.done) {
if (promisesInFlight.size >= maxConcurrency) {
const [predication, promise] = await promiseRace(promisesInFlight)
promisesInFlight.delete(promise)
if (predication) {
return true
}
}
const predication = predicate(iteration.value)
if (isPromise(predication)) {
promisesInFlight.add(SelfReferencingPromise(predication))
} else if (predication) {
return true
}
iteration = iterator.next()
if (isPromise(iteration)) {
iteration = await iteration
}
}
while (promisesInFlight.size > 0) {
const [predication, promise] = await promiseRace(promisesInFlight)
promisesInFlight.delete(promise)
if (predication) {
return true
}
}
return false
}
const iteratorSome = function (iterator, predicate) {
for (const item of iterator) {
const predication = predicate(item)
if (isPromise(predication)) {
return asyncIteratorSome(
iterator, predicate, new Set([SelfReferencingPromise(predication)]))
}
if (predication) {
return true
}
}
return false
}
const reducerAnySync = predicate => function anyReducer(result, item) {
return result ? true : predicate(item)
}
const reducerSome = predicate => function anyReducer(result, item) {
return result === true ? result
: isPromise(result) ? result.then(curry2(reducerAnySync(predicate), __, item))
: result ? true : predicate(item)
}
const symbolIterator = Symbol.iterator
const symbolAsyncIterator = Symbol.asyncIterator
// _some(collection Array|Iterable|AsyncIterable|{ reduce: function }|Object, predicate function) -> Promise|boolean
const _some = function (collection, predicate) {
if (isArray(collection)) {
return arraySome(collection, predicate)
}
if (collection == null) {
return predicate(collection)
}
if (typeof collection[symbolIterator] == 'function') {
return iteratorSome(collection[symbolIterator](), predicate)
}
if (typeof collection[symbolAsyncIterator] == 'function') {
return asyncIteratorSome(
collection[symbolAsyncIterator](), predicate, new Set()
)
}
if (typeof collection.reduce == 'function') {
return collection.reduce(reducerSome(predicate), false)
}
if (collection.constructor == Object) {
return arraySome(objectValues(collection), predicate)
}
return predicate(collection)
}
const some = function (arg0, arg1) {
if (typeof arg0 == 'function') {
return curry2(_some, __, arg0)
}
return isPromise(arg0)
? arg0.then(curry2(_some, __, arg1))
: _some(arg0, arg1)
}
export default some