UNPKG

rubico

Version:

[a]synchronous functional programming

322 lines (283 loc) 8.29 kB
/** * rubico v2.6.2 * https://github.com/a-synchronous/rubico * (c) 2019-2024 Richard Tong * rubico may be freely distributed under the MIT license. */ const __ = 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 symbolIterator = Symbol.iterator 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 isPromise = value => value != null && typeof value.then == 'function' const symbolAsyncIterator = Symbol.asyncIterator 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 isArray = Array.isArray // 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 promiseAll = Promise.all.bind(Promise) 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 } // 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) } const callPropUnary = (value, property, arg0) => value[property](arg0) const stringFilter = function (string, predicate) { const filteredCharactersArray = arrayFilter(string, predicate) return isPromise(filteredCharactersArray) ? filteredCharactersArray.then(curry3(callPropUnary, __, 'join', '')) : filteredCharactersArray.join('') } const always = value => function getter() { return value } const thunkConditional = ( conditionalExpression, thunkOnTruthy, thunkOnFalsy, ) => conditionalExpression ? thunkOnTruthy() : thunkOnFalsy() 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 thunkify4 = (func, arg0, arg1, arg2, arg3) => function thunk() { return func(arg0, arg1, arg2, arg3) } const callPropBinary = (value, property, arg0, arg1) => value[property](arg0, arg1) 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) } export default filter