Spaces:
Sleeping
Sleeping
; | |
const Assert = require('./assert'); | |
const internals = {}; | |
module.exports = function (obj, chain, options) { | |
if (chain === false || | |
chain === null || | |
chain === undefined) { | |
return obj; | |
} | |
options = options || {}; | |
if (typeof options === 'string') { | |
options = { separator: options }; | |
} | |
const isChainArray = Array.isArray(chain); | |
Assert(!isChainArray || !options.separator, 'Separator option no valid for array-based chain'); | |
const path = isChainArray ? chain : chain.split(options.separator || '.'); | |
let ref = obj; | |
for (let i = 0; i < path.length; ++i) { | |
let key = path[i]; | |
const type = options.iterables && internals.iterables(ref); | |
if (Array.isArray(ref) || | |
type === 'set') { | |
const number = Number(key); | |
if (Number.isInteger(number)) { | |
key = number < 0 ? ref.length + number : number; | |
} | |
} | |
if (!ref || | |
typeof ref === 'function' && options.functions === false || // Defaults to true | |
!type && ref[key] === undefined) { | |
Assert(!options.strict || i + 1 === path.length, 'Missing segment', key, 'in reach path ', chain); | |
Assert(typeof ref === 'object' || options.functions === true || typeof ref !== 'function', 'Invalid segment', key, 'in reach path ', chain); | |
ref = options.default; | |
break; | |
} | |
if (!type) { | |
ref = ref[key]; | |
} | |
else if (type === 'set') { | |
ref = [...ref][key]; | |
} | |
else { // type === 'map' | |
ref = ref.get(key); | |
} | |
} | |
return ref; | |
}; | |
internals.iterables = function (ref) { | |
if (ref instanceof Set) { | |
return 'set'; | |
} | |
if (ref instanceof Map) { | |
return 'map'; | |
} | |
}; | |