@mpxjs/core 2.9.38 → 2.9.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/core/proxy.js +48 -2
- package/src/dynamic/astCache.js +25 -0
- package/src/dynamic/dynamicRenderMixin.js +77 -0
- package/src/dynamic/vnode/context.js +17 -0
- package/src/dynamic/vnode/css-select/cssauron.js +445 -0
- package/src/dynamic/vnode/css-select/index.js +116 -0
- package/src/dynamic/vnode/css-select/through.js +19 -0
- package/src/dynamic/vnode/css-select/tokenizer.js +371 -0
- package/src/dynamic/vnode/interpreter.js +449 -0
- package/src/dynamic/vnode/render.js +289 -0
- package/src/index.js +2 -0
- package/src/platform/builtInMixins/index.js +8 -0
- package/src/platform/builtInMixins/proxyEventMixin.js +12 -3
- package/src/platform/builtInMixins/renderHelperMixin.js +2 -2
- package/src/platform/patch/ali/getDefaultOptions.js +20 -0
- package/src/platform/patch/wx/getDefaultOptions.js +20 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import cssauron from './cssauron'
|
|
2
|
+
|
|
3
|
+
const language = cssauron({
|
|
4
|
+
tag: function (node) {
|
|
5
|
+
return node.nodeType
|
|
6
|
+
},
|
|
7
|
+
class: function (node) {
|
|
8
|
+
return node.data?.class
|
|
9
|
+
},
|
|
10
|
+
id: function (node) {
|
|
11
|
+
return node.data?.id
|
|
12
|
+
},
|
|
13
|
+
children: function (node) {
|
|
14
|
+
return node.children
|
|
15
|
+
},
|
|
16
|
+
parent: function (node) {
|
|
17
|
+
return node.parent
|
|
18
|
+
},
|
|
19
|
+
contents: function (node) {
|
|
20
|
+
return node.contents || ''
|
|
21
|
+
},
|
|
22
|
+
attr: function (node, attr) {
|
|
23
|
+
if (node.properties) {
|
|
24
|
+
const attrs = node.properties.attributes
|
|
25
|
+
if (attrs && attrs[attr]) {
|
|
26
|
+
return attrs[attr]
|
|
27
|
+
}
|
|
28
|
+
return node.properties[attr]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
export default function cssSelect (sel, options) {
|
|
34
|
+
options = options || {}
|
|
35
|
+
const selector = language(sel, options.moduleId)
|
|
36
|
+
function match (vtree) {
|
|
37
|
+
const node = mapTree(vtree, null, options) || {}
|
|
38
|
+
const matched = []
|
|
39
|
+
|
|
40
|
+
// Traverse each node in the tree and see if it matches our selector
|
|
41
|
+
traverse(node, function (node) {
|
|
42
|
+
let result = selector(node)
|
|
43
|
+
if (result) {
|
|
44
|
+
if (!Array.isArray(result)) {
|
|
45
|
+
result = [result]
|
|
46
|
+
}
|
|
47
|
+
matched.push.apply(matched, result)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const results = mapResult(matched)
|
|
52
|
+
if (results.length === 0) {
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
return results
|
|
56
|
+
}
|
|
57
|
+
match.matches = function (vtree) {
|
|
58
|
+
const node = mapTree(vtree, null, options)
|
|
59
|
+
return !!selector(node)
|
|
60
|
+
}
|
|
61
|
+
return match
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function traverse (vtree, fn) {
|
|
65
|
+
fn(vtree)
|
|
66
|
+
if (vtree.children) {
|
|
67
|
+
vtree.children.forEach(function (vtree) {
|
|
68
|
+
traverse(vtree, fn)
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function mapResult (result) {
|
|
74
|
+
return result
|
|
75
|
+
.filter(function (node) {
|
|
76
|
+
return !!node.vtree
|
|
77
|
+
})
|
|
78
|
+
.map(function (node) {
|
|
79
|
+
return node.vtree
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getNormalizeCaseFn (caseSensitive) {
|
|
84
|
+
return caseSensitive
|
|
85
|
+
? function noop (str) {
|
|
86
|
+
return str
|
|
87
|
+
}
|
|
88
|
+
: function toLowerCase (str) {
|
|
89
|
+
return str.toLowerCase()
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Map a virtual-dom node tree into a data structure that cssauron can use to
|
|
94
|
+
// traverse.
|
|
95
|
+
function mapTree (vtree, parent, options) {
|
|
96
|
+
const normalizeTagCase = getNormalizeCaseFn(options.caseSensitiveTag)
|
|
97
|
+
|
|
98
|
+
if (vtree.nt != null) {
|
|
99
|
+
const node = {}
|
|
100
|
+
node.parent = parent
|
|
101
|
+
node.vtree = vtree
|
|
102
|
+
node.nodeType = normalizeTagCase(vtree.nt)
|
|
103
|
+
if (vtree.d) {
|
|
104
|
+
node.data = vtree.d
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (vtree.c) {
|
|
108
|
+
node.children = vtree.c
|
|
109
|
+
.map(function (child) {
|
|
110
|
+
return mapTree(child, node, options)
|
|
111
|
+
})
|
|
112
|
+
.filter(Boolean)
|
|
113
|
+
}
|
|
114
|
+
return node
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default function through (onData) {
|
|
2
|
+
let dataCb = null
|
|
3
|
+
|
|
4
|
+
return {
|
|
5
|
+
on: function (name, callback) {
|
|
6
|
+
if (name === 'data') {
|
|
7
|
+
dataCb = callback
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
end: function (data) {
|
|
11
|
+
onData(data)
|
|
12
|
+
},
|
|
13
|
+
queue: function (data) {
|
|
14
|
+
if (dataCb) {
|
|
15
|
+
dataCb(data)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import through from './through'
|
|
2
|
+
|
|
3
|
+
const PSEUDOSTART = 'pseudo-start'
|
|
4
|
+
const ATTR_START = 'attr-start'
|
|
5
|
+
const ANY_CHILD = 'any-child'
|
|
6
|
+
const ATTR_COMP = 'attr-comp'
|
|
7
|
+
const ATTR_END = 'attr-end'
|
|
8
|
+
const PSEUDOPSEUDO = '::'
|
|
9
|
+
const PSEUDOCLASS = ':'
|
|
10
|
+
const READY = '(ready)' // 重置标志位
|
|
11
|
+
const OPERATION = 'op'
|
|
12
|
+
const CLASS = 'class'
|
|
13
|
+
const COMMA = 'comma'
|
|
14
|
+
const ATTR = 'attr'
|
|
15
|
+
const SUBJECT = '!'
|
|
16
|
+
const TAG = 'tag'
|
|
17
|
+
const STAR = '*'
|
|
18
|
+
const ID = 'id'
|
|
19
|
+
|
|
20
|
+
export default function tokenize () {
|
|
21
|
+
let escaped = false
|
|
22
|
+
let gathered = []
|
|
23
|
+
let state = READY
|
|
24
|
+
let data = []
|
|
25
|
+
let idx = 0
|
|
26
|
+
let stream
|
|
27
|
+
let length
|
|
28
|
+
let quote
|
|
29
|
+
let depth
|
|
30
|
+
let lhs
|
|
31
|
+
let rhs
|
|
32
|
+
let cmp
|
|
33
|
+
let c
|
|
34
|
+
|
|
35
|
+
return (stream = through(ondata, onend))
|
|
36
|
+
|
|
37
|
+
function ondata (chunk) {
|
|
38
|
+
data = data.concat(chunk.split(''))
|
|
39
|
+
length = data.length
|
|
40
|
+
|
|
41
|
+
while (idx < length && (c = data[idx++])) {
|
|
42
|
+
switch (state) {
|
|
43
|
+
case READY:
|
|
44
|
+
state_ready()
|
|
45
|
+
break
|
|
46
|
+
case ANY_CHILD:
|
|
47
|
+
state_any_child()
|
|
48
|
+
break
|
|
49
|
+
case OPERATION:
|
|
50
|
+
state_op()
|
|
51
|
+
break
|
|
52
|
+
case ATTR_START:
|
|
53
|
+
state_attr_start()
|
|
54
|
+
break
|
|
55
|
+
case ATTR_COMP:
|
|
56
|
+
state_attr_compare()
|
|
57
|
+
break
|
|
58
|
+
case ATTR_END:
|
|
59
|
+
state_attr_end()
|
|
60
|
+
break
|
|
61
|
+
case PSEUDOCLASS:
|
|
62
|
+
case PSEUDOPSEUDO:
|
|
63
|
+
state_pseudo()
|
|
64
|
+
break
|
|
65
|
+
case PSEUDOSTART:
|
|
66
|
+
state_pseudostart()
|
|
67
|
+
break
|
|
68
|
+
case ID:
|
|
69
|
+
case TAG:
|
|
70
|
+
case CLASS:
|
|
71
|
+
state_gather()
|
|
72
|
+
break
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
data = data.slice(idx)
|
|
77
|
+
|
|
78
|
+
if (gathered.length) {
|
|
79
|
+
stream.queue(token())
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function onend (chunk) {
|
|
84
|
+
// if (arguments.length) {
|
|
85
|
+
// ondata(chunk)
|
|
86
|
+
// }
|
|
87
|
+
|
|
88
|
+
// if (gathered.length) {
|
|
89
|
+
// stream.queue(token())
|
|
90
|
+
// }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function state_ready () {
|
|
94
|
+
switch (true) {
|
|
95
|
+
case c === '#':
|
|
96
|
+
state = ID
|
|
97
|
+
break
|
|
98
|
+
case c === '.':
|
|
99
|
+
state = CLASS
|
|
100
|
+
break
|
|
101
|
+
case c === ':':
|
|
102
|
+
state = PSEUDOCLASS
|
|
103
|
+
break
|
|
104
|
+
case c === '[':
|
|
105
|
+
state = ATTR_START
|
|
106
|
+
break
|
|
107
|
+
case c === '!':
|
|
108
|
+
subject()
|
|
109
|
+
break
|
|
110
|
+
case c === '*':
|
|
111
|
+
star()
|
|
112
|
+
break
|
|
113
|
+
case c === ',':
|
|
114
|
+
comma()
|
|
115
|
+
break
|
|
116
|
+
case /[>+~]/.test(c):
|
|
117
|
+
state = OPERATION
|
|
118
|
+
break
|
|
119
|
+
case /\s/.test(c):
|
|
120
|
+
state = ANY_CHILD
|
|
121
|
+
break
|
|
122
|
+
case /[\w\d\-_]/.test(c):
|
|
123
|
+
state = TAG
|
|
124
|
+
--idx
|
|
125
|
+
break
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function subject () {
|
|
130
|
+
state = SUBJECT
|
|
131
|
+
gathered = ['!']
|
|
132
|
+
stream.queue(token())
|
|
133
|
+
state = READY
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function star () {
|
|
137
|
+
state = STAR
|
|
138
|
+
gathered = ['*']
|
|
139
|
+
stream.queue(token())
|
|
140
|
+
state = READY
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function comma () {
|
|
144
|
+
state = COMMA
|
|
145
|
+
gathered = [',']
|
|
146
|
+
stream.queue(token())
|
|
147
|
+
state = READY
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function state_op () {
|
|
151
|
+
if (/[>+~]/.test(c)) {
|
|
152
|
+
return gathered.push(c)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// chomp down the following whitespace.
|
|
156
|
+
if (/\s/.test(c)) {
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
stream.queue(token())
|
|
161
|
+
state = READY
|
|
162
|
+
--idx // 指针左移,归档,开始匹配下一个 token
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function state_any_child () {
|
|
166
|
+
if (/\s/.test(c)) {
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (/[>+~]/.test(c)) {
|
|
171
|
+
--idx
|
|
172
|
+
state = OPERATION
|
|
173
|
+
return state
|
|
174
|
+
// return --idx, (state = OPERATION)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// 生成 any_child 节点,并重置状态
|
|
178
|
+
stream.queue(token())
|
|
179
|
+
state = READY
|
|
180
|
+
--idx
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function state_pseudo () {
|
|
184
|
+
rhs = state
|
|
185
|
+
state_gather(true)
|
|
186
|
+
|
|
187
|
+
if (state !== READY) {
|
|
188
|
+
return
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (c === '(') {
|
|
192
|
+
lhs = gathered.join('')
|
|
193
|
+
state = PSEUDOSTART
|
|
194
|
+
gathered.length = 0
|
|
195
|
+
depth = 1
|
|
196
|
+
++idx
|
|
197
|
+
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
state = PSEUDOCLASS
|
|
202
|
+
stream.queue(token())
|
|
203
|
+
state = READY
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function state_pseudostart () {
|
|
207
|
+
if (gathered.length === 0 && !quote) {
|
|
208
|
+
quote = /['"]/.test(c) ? c : null
|
|
209
|
+
|
|
210
|
+
if (quote) {
|
|
211
|
+
return
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (quote) {
|
|
216
|
+
if (!escaped && c === quote) {
|
|
217
|
+
quote = null
|
|
218
|
+
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (c === '\\') {
|
|
223
|
+
escaped ? gathered.push(c) : (escaped = true)
|
|
224
|
+
|
|
225
|
+
return
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
escaped = false
|
|
229
|
+
gathered.push(c)
|
|
230
|
+
|
|
231
|
+
return
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
gathered.push(c)
|
|
235
|
+
|
|
236
|
+
if (c === '(') {
|
|
237
|
+
++depth
|
|
238
|
+
} else if (c === ')') {
|
|
239
|
+
--depth
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (!depth) {
|
|
243
|
+
gathered.pop()
|
|
244
|
+
stream.queue({
|
|
245
|
+
type: rhs,
|
|
246
|
+
data: lhs + '(' + gathered.join('') + ')'
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
state = READY
|
|
250
|
+
lhs = rhs = cmp = null
|
|
251
|
+
gathered.length = 0
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function state_attr_start () {
|
|
256
|
+
// 在收集字符的阶段,还会有 state 标志位的判断,因此会影响到下面的逻辑执行
|
|
257
|
+
state_gather(true)
|
|
258
|
+
|
|
259
|
+
if (state !== READY) {
|
|
260
|
+
return
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (c === ']') {
|
|
264
|
+
state = ATTR
|
|
265
|
+
stream.queue(token())
|
|
266
|
+
state = READY
|
|
267
|
+
|
|
268
|
+
return
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
lhs = gathered.join('')
|
|
272
|
+
gathered.length = 0
|
|
273
|
+
state = ATTR_COMP
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// 属性选择器:https://www.w3school.com.cn/css/css_attribute_selectors.asp
|
|
277
|
+
function state_attr_compare () {
|
|
278
|
+
if (/[=~|$^*]/.test(c)) {
|
|
279
|
+
gathered.push(c)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// 操作符&=
|
|
283
|
+
if (gathered.length === 2 || c === '=') {
|
|
284
|
+
cmp = gathered.join('')
|
|
285
|
+
gathered.length = 0
|
|
286
|
+
state = ATTR_END
|
|
287
|
+
quote = null
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function state_attr_end () {
|
|
292
|
+
if (!gathered.length && !quote) {
|
|
293
|
+
quote = /['"]/.test(c) ? c : null
|
|
294
|
+
|
|
295
|
+
if (quote) {
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (quote) {
|
|
301
|
+
if (!escaped && c === quote) {
|
|
302
|
+
quote = null
|
|
303
|
+
|
|
304
|
+
return
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (c === '\\') {
|
|
308
|
+
if (escaped) {
|
|
309
|
+
gathered.push(c)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
escaped = !escaped
|
|
313
|
+
|
|
314
|
+
return
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
escaped = false
|
|
318
|
+
gathered.push(c)
|
|
319
|
+
|
|
320
|
+
return
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
state_gather(true)
|
|
324
|
+
|
|
325
|
+
if (state !== READY) {
|
|
326
|
+
return
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
stream.queue({
|
|
330
|
+
type: ATTR,
|
|
331
|
+
data: {
|
|
332
|
+
lhs: lhs,
|
|
333
|
+
rhs: gathered.join(''),
|
|
334
|
+
cmp: cmp
|
|
335
|
+
}
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
state = READY
|
|
339
|
+
lhs = rhs = cmp = null
|
|
340
|
+
gathered.length = 0
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function state_gather (quietly) {
|
|
344
|
+
// 如果是非单词字符,例如 空格。会更新 state 的状态
|
|
345
|
+
if (/[^\d\w\-_]/.test(c) && !escaped) {
|
|
346
|
+
if (c === '\\') {
|
|
347
|
+
escaped = true
|
|
348
|
+
} else {
|
|
349
|
+
!quietly && stream.queue(token())
|
|
350
|
+
state = READY
|
|
351
|
+
--idx
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
escaped = false
|
|
358
|
+
gathered.push(c)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function token () {
|
|
362
|
+
const data = gathered.join('')
|
|
363
|
+
|
|
364
|
+
gathered.length = 0
|
|
365
|
+
|
|
366
|
+
return {
|
|
367
|
+
type: state,
|
|
368
|
+
data: data
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|