-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathget-safe.js
executable file
·42 lines (40 loc) · 1.46 KB
/
get-safe.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// Utils
const isFnCall = function(key) {
if (typeof key !== "string") return false;
return key.slice(-2) === "()";
};
/*
* You can't use '.' on null or undefined values
*/
const hasProperties = function(obj) {
return obj !== null && obj !== undefined;
};
/*
* @param {key} string concatenation of nested keys in this form: 'foo.bar.toto'.
* You can even call a function if the last key ends with '()'.
* @param {obj} the object we are accessing
* @param {...args} a sequence of arguments that may be passed to the fn you are calling.
* If you are NOT making a fn call, args[0] may contain the default to return
* instead of undefined.
* @return a nested value OR
* the result of a nested function OR
* undefined OR
* the default value if you are not making a fn call
*/
module.exports = (key, obj, ...args) => {
const splitted = key.split(".");
let lastkey = splitted.pop();
const isFnCallLastkey = isFnCall(lastkey);
lastkey = isFnCallLastkey ? lastkey.slice(0, -2) : lastkey;
const beforelast = splitted.reduce((a, b) => {
return hasProperties(a) ? a[b] : undefined;
}, obj);
const defaultValueIfNotFnCall = args[0];
return hasProperties(beforelast)
? isFnCallLastkey
? beforelast[lastkey] && typeof beforelast[lastkey] === "function"
? beforelast[lastkey](...args)
: undefined
: beforelast[lastkey]
: isFnCallLastkey ? undefined : defaultValueIfNotFnCall;
};