@rybr/lenses
Version:
a simple and light package meant to ease data traversal, manipulation, mutation, and transformation
76 lines (61 loc) • 2 kB
JavaScript
const { loadGlobal, getConstructorName, TYPES, getOperationType } = require('./helpers')
const getProperty = (property, source) => {
if (source == null) {
return source
}
return Object.prototype.hasOwnProperty.call(source, property) ? source[property] : undefined
}
const applyFunction = (func, source, i) => {
if (!TYPES.FUNCTION.is(func)) {
throw new Error(`At index ${i}: cannot apply function since it is not a Function`)
}
return func(source)
}
const performOperation = ({ operation, type }, source, i) =>
source == null
? !TYPES.FUNCTION.is(type)
? source
: applyFunction(operation, source, i)
: TYPES.STRING.is(type) || TYPES.NUMBER.is(type)
? getProperty(operation, source)
: TYPES.FUNCTION.is(type)
? applyFunction(operation, source, i)
: source
//Curried version
// prettier-ignore
const _get = (...operationInputs) => (input) => {
//default return
if (operationInputs.length === 0) {
return input
}
const operations = [...operationInputs]
return (
operations
//operation validation
.map((operation, i) => {
const type = getOperationType(operation)
if (TYPES.INVALID.is(type)) {
throw new Error(
`Invalid Get operation at index ${i}: expecting String, Number, or Function but received ${getConstructorName(
operation
)}`
)
}
return {
operation,
type,
}
})
//operation execution
.reduce((acc, operationInfo, i) => performOperation(operationInfo, acc, i), input)
)
}
const defaults = defaultValue => input => {
return input == null ? defaultValue : input
}
const get = (input, ...operationInputs) => _get(...operationInputs)(input)
module.exports._get = _get
module.exports.defaults = defaults
module.exports.get = get
//for browser static import
loadGlobal(module.exports)