rubico
Version:
[a]synchronous functional programming
131 lines (111 loc) • 3.52 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 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 isArray = Array.isArray
const isObject = value => {
if (value == null) {
return false
}
const typeofValue = typeof value
return (typeofValue == 'object') || (typeofValue == 'function')
}
const memoizeCappedUnary = function (func, cap) {
const cache = new Map(),
memoized = function memoized(arg0) {
if (cache.has(arg0)) {
return cache.get(arg0)
}
const result = func(arg0)
cache.set(arg0, result)
if (cache.size > cap) {
cache.clear()
}
return result
}
memoized.cache = cache
return memoized
}
// a[0].b.c
const pathDelimiters = /[.|[|\]]+/
const parsePropertyPath = function (pathString) {
const pathStringLastIndex = pathString.length - 1,
firstChar = pathString[0],
lastChar = pathString[pathStringLastIndex],
isFirstCharLeftBracket = firstChar == '[',
isLastCharRightBracket = lastChar == ']'
if (isFirstCharLeftBracket && isLastCharRightBracket) {
return pathString.slice(1, pathStringLastIndex).split(pathDelimiters)
} else if (isFirstCharLeftBracket) {
return pathString.slice(1).split(pathDelimiters)
} else if (isLastCharRightBracket) {
return pathString.slice(0, pathStringLastIndex).split(pathDelimiters)
}
return pathString.split(pathDelimiters)
}
// memoized version of parsePropertyPath, max cache size 500
const memoizedCappedParsePropertyPath = memoizeCappedUnary(parsePropertyPath, 500)
const propertyPathToArray = path => isArray(path) ? path
: typeof path == 'string' ? memoizedCappedParsePropertyPath(path)
: [path]
const getByPath = function (value, path) {
const propertyPathArray = propertyPathToArray(path),
length = propertyPathArray.length
let index = -1,
result = value
while (++index < length) {
result = result[propertyPathArray[index]]
if (result == null) {
return undefined
}
}
return result
}
// _get(object Object, path string, defaultValue function|any)
const _get = function (object, path, defaultValue) {
const result = object == null ? undefined : getByPath(object, path)
return result === undefined
? typeof defaultValue == 'function' ? defaultValue(object) : defaultValue
: result
}
const get = function (arg0, arg1, arg2) {
if (typeof arg0 == 'string' || typeof arg0 == 'number' || isArray(arg0)) {
return curry3(_get, __, arg0, arg1)
}
if (isPromise(arg0)) {
return arg0.then(curry3(_get, __, arg1, arg2))
}
return _get(arg0, arg1, arg2)
}
export default get