/
index.js
80 lines (67 loc) · 1.55 KB
/
index.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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
'use strict';
var isArray = require('@fav/type.is-array');
var disallowProtoPath = function(path, value) {
if (value === Object.prototype) {
throw new Error('Unsafe path encountered: ' + path);
}
};
function setDeep(obj, propPath, value) {
if (arguments.length < 3) {
return;
}
if (!isArray(propPath)) {
return;
}
if (!canHaveProp(obj)) {
return;
}
var i, last = propPath.length - 1;
for (i = 0; i < last; i++) {
var existentProp = propPath[i];
if (isArray(existentProp)) {
// This function doesn't allow to use an array as a property.
return;
}
var child = obj[existentProp];
if (!canHaveProp(child)) {
break;
}
disallowProtoPath(existentProp, child);
obj = child;
}
for (var j = last; j > i; j--) {
var nonExistentProp = propPath[j];
if (isArray(nonExistentProp)) {
// This function doesn't allow to use an array as a property.
return;
}
var parent = {};
parent[nonExistentProp] = value;
value = parent;
}
try {
var graftedProp = propPath[i];
if (isArray(graftedProp)) {
// This function doesn't allow to use an array as a property.
return;
}
obj[graftedProp] = value;
} catch (e) {
// If a property is read only, TypeError is thrown,
// but this function ignores it.
}
}
function canHaveProp(obj) {
switch (typeof obj) {
case 'object': {
return (obj != null);
}
case 'function': {
return true;
}
default: {
return false;
}
}
}
module.exports = setDeep;