forked from cosmosio/nested-property
/
index.js
145 lines (136 loc) · 4.81 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
141
142
143
144
145
/**
* @license nested-property https://github.com/cosmosio/nested-property
*
* The MIT License (MIT)
*
* Copyright (c) 2014-2015 Olivier Scherrer <pode.fr@gmail.com>
*/
"use strict";
module.exports = {
set: setNestedProperty,
get: getNestedProperty,
has: hasNestedProperty,
hasOwn: function (object, property, options) {
return this.has(object, property, options || {own: true});
},
isIn: isInNestedProperty
};
/**
* Get the property of an object nested in one or more objects
* given an object such as a.b.c.d = 5, getNestedProperty(a, "b.c.d") will return 5.
* @param {Object} object the object to get the property from
* @param {String} property the path to the property as a string
* @returns the object or the the property value if found
*/
function getNestedProperty(object, property) {
if (object && typeof object == "object") {
if (typeof property == "string" && property !== "") {
var split = property.split(".");
return split.reduce(function (obj, prop) {
return obj && obj[prop];
}, object);
} else if (typeof property == "number") {
return object[property];
} else {
return object;
}
} else {
return object;
}
}
/**
* Tell if a nested object has a given property (or array a given index)
* given an object such as a.b.c.d = 5, hasNestedProperty(a, "b.c.d") will return true.
* It also returns true if the property is in the prototype chain.
* @param {Object} object the object to get the property from
* @param {String} property the path to the property as a string
* @param {Object} options:
* - own: set to reject properties from the prototype
* @returns true if has (property in object), false otherwise
*/
function hasNestedProperty(object, property, options) {
options = options || {};
if (object && typeof object == "object") {
if (typeof property == "string" && property !== "") {
var split = property.split(".");
return split.reduce(function (obj, prop, idx, array) {
if (idx == array.length - 1) {
if (options.own) {
return !!(obj && obj.hasOwnProperty(prop));
} else {
return !!(obj !== null && typeof obj == "object" && prop in obj);
}
}
return obj && obj[prop];
}, object);
} else if (typeof property == "number") {
return property in object;
} else {
return false;
}
} else {
return false;
}
}
/**
* Set the property of an object nested in one or more objects
* If the property doesn't exist, it gets created.
* @param {Object} object
* @param {String} property
* @param value the value to set
* @returns object if no assignment was made or the value if the assignment was made
*/
function setNestedProperty(object, property, value) {
if (object && typeof object == "object") {
if (typeof property == "string" && property !== "") {
var split = property.split(".");
return split.reduce(function (obj, prop, idx) {
obj[prop] = obj[prop] || {};
if (split.length == (idx + 1)) {
obj[prop] = value;
}
return obj[prop];
}, object);
} else if (typeof property == "number") {
object[property] = value;
return object[property];
} else {
return object;
}
} else {
return object;
}
}
/**
* Tell if an object is on the path to a nested property
* If the object is on the path, and the path exists, it returns true, and false otherwise.
* @param {Object} object to get the nested property from
* @param {String} property name of the nested property
* @param {Object} objectInPath the object to check
* @param {Object} options:
* - validPath: return false if the path is invalid, even if the object is in the path
* @returns {boolean} true if the object is on the path
*/
function isInNestedProperty(object, property, objectInPath, options) {
options = options || {};
if (object && typeof object == "object") {
if (typeof property == "string" && property !== "") {
var split = property.split("."),
isIn = false,
pathExists;
pathExists = !!split.reduce(function (obj, prop) {
isIn = isIn || obj === objectInPath || (!!obj && obj[prop] === objectInPath);
return obj && obj[prop];
}, object);
if (options.validPath) {
return isIn && pathExists;
} else {
return isIn;
}
} else {
return false;
}
} else {
return false;
}
}