You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
1.8 KiB
76 lines
1.8 KiB
'use strict'; |
|
|
|
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'; |
|
} |
|
};
|
|
|