| 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258 |
1x
1x
5x
4x
1x
9x
1x
4x
1x
4x
1x
3x
1x
22x
3x
19x
27x
9x
18x
10x
8x
1x
22x
3x
19x
26x
9x
17x
10x
7x
1x
11x
3x
8x
12x
4x
8x
4x
4x
4x
1x
12x
4x
8x
15x
15x
15x
8x
8x
7x
6x
7x
54x
54x
54x
54x
54x
80x
80x
80x
47x
33x
33x
80x
80x
80x
26x
54x
54x
54x
54x
83x
83x
5x
5x
83x
54x
1x
| /**
* @module libs/lang/DotProp
* @createdAt 2016-07-01
*
* @copyright Copyright (c) 2016 Zhonglei Qiu
* @license Licensed under the MIT license.
*/
var hasOwnEnumProp = require('./hasOwnEnumProp')
var isObject = require('./isObject')
/**
* 创建一个对象,使你可以通过 get/set/has/del 的方法来对其值
* 做增删改查的操作,并且路径名支持 . 链接
*
* @class
* @param {Objet} data 要操作的数据池
*
* @example
* var dp = new DotProp({foo: {bar: 1}})
* dp.has('foo.bar') // true
* dp.get('foo') // {bar: 1}
* dp.set('x', 'x') // true
* dp.del('foo') // true
* dp.data // {x: 'x'}
*
*
* @see [dot-prop@3.0.0]{@link https://github.com/sindresorhus/dot-prop/tree/v3.0.0}
* @author Zhonglei Qiu
* @since 2.0.0
*/
function DotProp(data) {
if (!(this instanceof DotProp)) return new DotProp(data)
this.data = Object(data)
}
/**
* 获取数据池中路径为 path 的值
* @param {String} path 路径
* @return {*}
*
* @author Zhonglei Qiu
* @since 2.0.0
*/
DotProp.prototype.get = function(path) {
return DotProp.get(this.data, path)
}
/**
* 设置数据池中路径为 path 的值,如果中间的路径不存在,
* 或者不为 Object,则自动添加或修改成 Object
*
* @param {String} path 路径
* @param {String} value 要设置的值
* @return {Boolean} 是否设置成功(当 p 不为字符串时设置不成功)
*
* @author Zhonglei Qiu
* @since 2.0.0
*/
DotProp.prototype.set = function(path, value) {
return DotProp.set(this.data, path, value)
}
/**
* 判断数据池中是否有路径 path
*
* @param {String} path 路径
* @return {Boolean}
*
* @author Zhonglei Qiu
* @since 2.0.0
*/
DotProp.prototype.has = function(path) {
return DotProp.has(this.data, path)
}
/**
* 删除数据池中的路径上的值
* @param {String} path 路径
* @return {Boolean} 是否删除成功
*
* @author Zhonglei Qiu
* @since 2.0.0
*/
DotProp.prototype.del = function(path) {
return DotProp.del(this.data, path)
}
/**
* 判断数据池 obj 中是否有路径 path
*
* @static
* @param {Object} obj 数据池
* @param {String} path 路径
* @return {Boolean}
*
* @author Zhonglei Qiu
* @since 2.0.0
*/
DotProp.has = function(obj, path) {
if (!isObject(obj) || typeof path !== 'string') {
return false
}
return find(obj, getPathSegments(path), function(data) {
if (data.isDrained) {
return {next: false, value: false}
} else if (data.isLast) {
return {next: false, value: true}
} else {
return {next: true}
}
})
}
/**
* 获取数据池 obj 中的路径 path 中的值
*
* @static
* @param {Object} obj 数据池
* @param {String} path 路径
* @return {*} 获取到的值或者 `undefined`
*
* @author Zhonglei Qiu
* @since 2.0.0
*/
DotProp.get = function(obj, path) {
if (!isObject(obj) || typeof path !== 'string') {
return obj
}
return find(obj, getPathSegments(path), function(data) {
if (data.isDrained) {
return {next: false, value: undefined}
} else if (data.isLast) {
return {next: false, value: data.current}
} else {
return {next: true}
}
})
}
/**
* 删除数据池 obj 中的路径 path
*
* @static
* @param {Object} obj 数据池
* @param {String} path 路径
* @return {Boolean} 是否删除成功
*
* @author Zhonglei Qiu
* @since 2.0.0
*/
DotProp.del = function(obj, path) {
if (!isObject(obj) || typeof path !== 'string') {
return false
}
return find(obj, getPathSegments(path), function(data) {
if (data.isDrained) {
return {next: false, value: false}
} else if (data.isLast) {
delete data.parent[data.segment]
return {next: false, value: true}
} else {
return {next: true}
}
})
}
/**
* 设置数据池 obj 中路径 path 的值为 value
*
* @static
* @param {Object} obj 数据池
* @param {String} path 路径
* @param {*} value 要设置的值
* @return {Boolean} 是否设置成功
*
* @author Zhonglei Qiu
* @since 2.0.0
*/
DotProp.set = function(obj, path, value) {
if (!isObject(obj) || typeof path !== 'string') {
return false
}
return find(obj, getPathSegments(path), function(data) {
var current = data.current
var segment = data.segment
if (data.isLast) {
data.parent[segment] = value
return {next: false, value: true}
}
if (!isObject(current)) {
current = data.parent[segment] = {}
}
return {next: true, current: current}
})
}
function find(obj, segments, fn) {
var len = segments.length
var parent = null
var current = obj
var isDrained = false
var i, segment, fnRtn, result
for (i = 0; i < len; i++) {
segment = segments[i]
parent = current
if (hasOwnEnumProp(current, segment)) {
current = current[segment]
} else {
current = null
isDrained = true
}
fnRtn = fn({
isLast: i === len - 1,
isDrained: isDrained,
segment: segment,
parent: parent,
current: current
})
result = fnRtn.value
if (!fnRtn.next) break
else if ('current' in fnRtn) current = fnRtn.current // 回调更新了 current 对象
}
return result
}
function getPathSegments(path) {
var p
var parts = []
var pathArr = path.split('.')
for (var i = 0; i < pathArr.length; i++) {
p = pathArr[i]
while (p[p.length - 1] === '\\' && pathArr[i + 1] !== undefined) {
p = p.slice(0, -1) + '.'
p += pathArr[++i]
}
parts.push(p)
}
return parts
}
module.exports = DotProp
|