-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
140 lines (130 loc) · 3.53 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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
* Fetches the value of a deeply nested property.
*
* Arguments:
*
* obj Object to fetch property from.
*
* path [string] Dot-separated path specifier to nested
* property to fetch. Array indexes are not supported.
* Example: "contact.name.first".
*
* Returns: [mixed] Value of nested property if it exists,
* `undefined` otherwise.
*/
module.exports.get = function (obj, path) {
var tokens = parse(path);
if (tokens.length == 0) {
return undefined;
}
for (var i = 0, len = tokens.length; i < len; i++) {
if (! obj || ! obj.hasOwnProperty(tokens[i])) {
return undefined;
} else {
obj = obj[tokens[i]];
}
}
return obj;
};
/*
* Sets the value of a deeply nested property.
*
* If an intermediate property of the specified path doesn't exist,
* it will be created as an object.
*
* Arguments:
*
* obj Object to set property on.
*
* path [string] Dot-separated path specifier to nested
* property to set. Array indexes are not supported.
* Example: "contact.name.first".
*
* value [mixed] Value to set on the object's nested property.
*
* Returns: undefined
*/
module.exports.set = function (obj, path, value) {
if (typeof obj === 'undefined' || typeof path === 'undefined') {
return;
}
var tokens = parse(path);
for (var i = 0, len = tokens.length; i < len; i++) {
if (! obj || ! obj.hasOwnProperty(tokens[i])) {
obj[tokens[i]] = { };
}
if (i == (len - 1)) {
obj[tokens[i]] = value;
} else {
obj = obj[tokens[i]];
}
}
};
/*
* Removes a deeply nested property.
*
* If an intermediate property of the specified path doesn't exist,
* we bail early.
*
* Arguments:
*
* obj Object to remove property from.
*
* path [string] Dot-separated path specifier to nested
* property to remove. Array indexes are not supported.
* Example: "contact.name.first".
*
* Returns: [boolean] TRUE if property was removed, otherwise FALSE.
*/
module.exports.remove = function (obj, path) {
if (typeof obj === 'undefined' || typeof path === 'undefined') {
return false;
}
var tokens = parse(path);
for (var i = 0, len = tokens.length; i < len; i++) {
if (! obj || ! obj.hasOwnProperty(tokens[i])) {
return false;
}
if (i == (len - 1)) {
delete obj[tokens[i]];
return true;
} else {
obj = obj[tokens[i]];
}
}
return false
};
/*
* Detects whether a given object has a specified nested property.
*
* Normal checks for deeply nested properties will throw an
* exception if an intermediate property doesn't exist. This
* function will do the same without but without the exception.
*
* Arguments:
*
* obj Object to check properties for.
*
* path [string] Dot-separated path specifier to nested
* property. Array indexes are not supported.
* Example: "contact.name.first"
*
* Returns: [boolean] TRUE if property is defined at the
* given path, otherwise FALSE. If a non-string
* is passed as `path`, FALSE is returned.
*/
module.exports.has = function (obj, path) {
return (typeof module.exports.get(obj, path) !== 'undefined');
};
function parse (path) {
if (typeof path !== 'string') {
path = '';
}
var tokens = path.split('.');
for (var i = 0, len = tokens.length; i < len; i++) {
if (tokens[i] === '') {
return [ ];
}
}
return tokens;
}