Repository navigation
Expand file tree
/
Copy pathpath.js
More file actions
194 lines (177 loc) · 4.73 KB
/
Copy pathpath.js
File metadata and controls
194 lines (177 loc) · 4.73 KB
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
let curStack
let targetStacks
let property
class Stack {
constructor (mark) {
this.mark = mark
// 字符串stack需要特殊处理
this.type = /['"]/.test(mark) ? 'string' : 'normal'
this.value = []
}
push (data) {
this.value.push(data)
}
}
function startStack (mark) {
// 开启栈或关闭栈都意味着前面的字符拼接截止
propertyJoinOver()
curStack && targetStacks.push(curStack)
curStack = new Stack(mark)
}
function endStack () {
// 开启栈或关闭栈都意味着前面的字符拼接截止
propertyJoinOver()
// 字符串栈直接拼接
const result = curStack.type === 'string' ? '__mpx_str_' + curStack.value.join('') : curStack.value
curStack = targetStacks.pop()
// 将当前stack结果保存到父级stack里
curStack.push(result)
}
function propertyJoinOver () {
property = property.trim()
if (property) curStack.push(property)
property = ''
}
function init () {
property = ''
// 根stack
curStack = new Stack()
targetStacks = []
}
function parse (str) {
init()
for (const char of str) {
// 当前遍历引号内的字符串时
if (curStack.type === 'string') {
// 若为对应的结束flag,则出栈,反之直接push
curStack.mark === char ? endStack() : curStack.push(char)
} else if (/['"[]/.test(char)) {
startStack(char)
} else if (char === ']') {
endStack()
} else if (char === '.' || char === '+') {
propertyJoinOver()
if (char === '+') curStack.push(char)
} else {
property += char
}
}
// 字符解析收尾
propertyJoinOver()
return curStack.value
}
function outPutByPath (context, path, isSimple, transfer) {
let result = context
const len = path.length
const meta = {
isEnd: false,
stop: false
}
for (let index = 0; index < len; index++) {
if (index === len - 1) meta.isEnd = true
let key
const item = path[index]
if (result) {
if (isSimple) {
key = item
} else if (Array.isArray(item)) {
// 获取子数组的输出结果作为当前key
key = outPutByPath(context, item, isSimple, transfer)
} else if (/^__mpx_str_/.test(item)) {
// 字符串一定会被[]包裹,一定在子数组中
result = item.replace('__mpx_str_', '')
} else if (/^\d+$/.test(item)) {
// 数字一定会被[]包裹,一定在子数组中
result = +item
} else if (item === '+') {
// 获取加号后面所有path最终的结果
result += outPutByPath(context, path.slice(index + 1), isSimple, transfer)
break
} else {
key = item
}
if (key !== undefined) {
result = transfer ? transfer(result, key, meta) : result[key]
if (meta.stop) break
}
} else {
break
}
}
return result
}
function doGetByPath (context, pathStrOrArr, transfer) {
if (!pathStrOrArr) {
return context
}
let isSimple = false
if (Array.isArray(pathStrOrArr)) {
isSimple = true
} else if (!/[[\]]/.test(pathStrOrArr)) {
pathStrOrArr = pathStrOrArr.split('.')
isSimple = true
}
if (!isSimple) pathStrOrArr = parse(pathStrOrArr)
return outPutByPath(context, pathStrOrArr, isSimple, transfer)
}
function isExist (obj, attr) {
const type = typeof obj
const isNullOrUndefined = obj === null || obj === undefined
if (isNullOrUndefined) {
return false
} else if (type === 'object' || type === 'function') {
return attr in obj
} else {
return obj[attr] !== undefined
}
}
function getByPath (data, pathStrOrArr, defaultVal, errTip) {
const result = doGetByPath(data, pathStrOrArr, (value, key) => {
let newValue
if (isExist(value, key)) {
newValue = value[key]
} else {
newValue = errTip
}
return newValue
})
// 小程序setData时不允许undefined数据
return result === undefined ? defaultVal : result
}
function setByPath (data, pathStrOrArr, value) {
if (!mpxGlobal.__mpx) {
console.warn('[Mpx utils warn]: Can not find "global.__mpx", "setByPath" may encounter some potential problems!')
}
doGetByPath(data, pathStrOrArr, (current, key, meta) => {
if (meta.isEnd) {
if (mpxGlobal.__mpx) {
mpxGlobal.__mpx.set(current, key, value)
} else {
current[key] = value
}
} else if (!current[key]) {
current[key] = {}
}
return current[key]
})
}
function getFirstKey (path) {
return /^[^[.]*/.exec(path)[0]
}
function aIsSubPathOfB (a, b) {
if (a.startsWith(b) && a !== b) {
const nextChar = a[b.length]
if (nextChar === '.') {
return a.slice(b.length + 1)
} else if (nextChar === '[') {
return a.slice(b.length)
}
}
}
export {
getByPath,
setByPath,
doGetByPath,
getFirstKey,
aIsSubPathOfB
}