@lvce-editor/virtual-dom-worker 1.8.0 → 1.9.0
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/dist/index.d.ts +7 -0
- package/dist/index.js +208 -0
- package/package.json +1 -1
- package/src/parts/ApplyPendingPatches/ApplyPendingPatches.ts +22 -0
- package/src/parts/GetKeys/GetKeys.ts +10 -0
- package/src/parts/Main/Main.ts +1 -0
- package/src/parts/NavigateParentPatch/NavigateParentPatch.ts +0 -1
- package/src/parts/VirtualDomDiff/VirtualDomDiff.ts +78 -62
package/dist/index.d.ts
CHANGED
|
@@ -6,3 +6,10 @@ export interface VirtualDomNode {
|
|
|
6
6
|
export const text: (data: string) => VirtualDomNode
|
|
7
7
|
|
|
8
8
|
export const mergeClassNames: (...classNames: readonly string[]) => string
|
|
9
|
+
|
|
10
|
+
export interface Patch {}
|
|
11
|
+
|
|
12
|
+
export const diff: (
|
|
13
|
+
oldNodes: readonly VirtualDomNode[],
|
|
14
|
+
newNodes: readonly VirtualDomNode[],
|
|
15
|
+
) => readonly Patch[]
|
package/dist/index.js
CHANGED
|
@@ -130,8 +130,216 @@ var text = (data) => {
|
|
|
130
130
|
childCount: 0
|
|
131
131
|
};
|
|
132
132
|
};
|
|
133
|
+
|
|
134
|
+
// src/parts/PatchType/PatchType.ts
|
|
135
|
+
var SetText = 1;
|
|
136
|
+
var SetAttribute = 3;
|
|
137
|
+
var RemoveAttribute = 4;
|
|
138
|
+
var Add = 6;
|
|
139
|
+
var NavigateChild = 7;
|
|
140
|
+
var NavigateParent = 8;
|
|
141
|
+
var RemoveChild = 9;
|
|
142
|
+
var NavigateSibling = 10;
|
|
143
|
+
|
|
144
|
+
// src/parts/ApplyPendingPatches/ApplyPendingPatches.ts
|
|
145
|
+
var applyPendingPatches = (patches, pendingPatches, skip) => {
|
|
146
|
+
for (let k = 0; k < pendingPatches.length - skip; k += 2) {
|
|
147
|
+
const type = pendingPatches[k];
|
|
148
|
+
const index = pendingPatches[k + 1];
|
|
149
|
+
if (type === NavigateParent) {
|
|
150
|
+
patches.push({ type });
|
|
151
|
+
} else {
|
|
152
|
+
patches.push({
|
|
153
|
+
type,
|
|
154
|
+
index
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
pendingPatches.length = 0;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// src/parts/GetKeys/GetKeys.ts
|
|
162
|
+
var isKey = (key) => {
|
|
163
|
+
return key !== "type" && key !== "childCount";
|
|
164
|
+
};
|
|
165
|
+
var getKeys = (node) => {
|
|
166
|
+
const keys = Object.keys(node).filter(isKey);
|
|
167
|
+
return keys;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// src/parts/GetTotalChildCount/GetTotalChildCount.ts
|
|
171
|
+
var getTotalChildCount = (nodes, index) => {
|
|
172
|
+
let i = index;
|
|
173
|
+
let pending = 1;
|
|
174
|
+
while (pending) {
|
|
175
|
+
const node = nodes[i];
|
|
176
|
+
pending += node.childCount;
|
|
177
|
+
pending--;
|
|
178
|
+
i++;
|
|
179
|
+
}
|
|
180
|
+
return i - index;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// src/parts/VirtualDomDiff/VirtualDomDiff.ts
|
|
184
|
+
var diff = (oldNodes, newNodes) => {
|
|
185
|
+
const patches = [];
|
|
186
|
+
const pendingPatches = [];
|
|
187
|
+
let i = 0;
|
|
188
|
+
let j = 0;
|
|
189
|
+
let siblingOffset = 0;
|
|
190
|
+
let maxSiblingOffset = 1;
|
|
191
|
+
const indexStack = [0, 1];
|
|
192
|
+
while (i < oldNodes.length && j < newNodes.length) {
|
|
193
|
+
const oldNode = oldNodes[i];
|
|
194
|
+
const newNode = newNodes[j];
|
|
195
|
+
if (siblingOffset > 0) {
|
|
196
|
+
}
|
|
197
|
+
if (siblingOffset === maxSiblingOffset) {
|
|
198
|
+
pendingPatches.push(NavigateParent, 0);
|
|
199
|
+
maxSiblingOffset = indexStack.pop();
|
|
200
|
+
siblingOffset = indexStack.pop() + 1;
|
|
201
|
+
}
|
|
202
|
+
if (oldNode.type !== newNode.type) {
|
|
203
|
+
let skip = 0;
|
|
204
|
+
if (pendingPatches.length > 0 && pendingPatches.at(-2) === NavigateChild) {
|
|
205
|
+
skip = 2;
|
|
206
|
+
}
|
|
207
|
+
applyPendingPatches(patches, pendingPatches, skip);
|
|
208
|
+
const oldTotal = getTotalChildCount(oldNodes, i);
|
|
209
|
+
const newTotal = getTotalChildCount(newNodes, j);
|
|
210
|
+
patches.push({
|
|
211
|
+
type: RemoveChild,
|
|
212
|
+
index: siblingOffset
|
|
213
|
+
});
|
|
214
|
+
patches.push({
|
|
215
|
+
type: Add,
|
|
216
|
+
nodes: newNodes.slice(j, j + newTotal)
|
|
217
|
+
});
|
|
218
|
+
siblingOffset++;
|
|
219
|
+
i += oldTotal;
|
|
220
|
+
j += newTotal;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (oldNode.type === Text && newNode.type === Text) {
|
|
224
|
+
if (oldNode.text !== newNode.text) {
|
|
225
|
+
if (siblingOffset !== 0) {
|
|
226
|
+
pendingPatches.push(NavigateSibling, siblingOffset);
|
|
227
|
+
}
|
|
228
|
+
applyPendingPatches(patches, pendingPatches, 0);
|
|
229
|
+
patches.push({
|
|
230
|
+
type: SetText,
|
|
231
|
+
value: newNode.text
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
i++;
|
|
235
|
+
j++;
|
|
236
|
+
siblingOffset++;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const oldKeys = getKeys(oldNode);
|
|
240
|
+
const newKeys = getKeys(newNode);
|
|
241
|
+
let hasAttributeChanges = false;
|
|
242
|
+
for (const key of newKeys) {
|
|
243
|
+
if (oldNode[key] !== newNode[key]) {
|
|
244
|
+
hasAttributeChanges = true;
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
for (const key of oldKeys) {
|
|
249
|
+
if (!(key in newNode)) {
|
|
250
|
+
hasAttributeChanges = true;
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (hasAttributeChanges) {
|
|
255
|
+
applyPendingPatches(patches, pendingPatches, 0);
|
|
256
|
+
for (const key of newKeys) {
|
|
257
|
+
if (oldNode[key] !== newNode[key]) {
|
|
258
|
+
patches.push({
|
|
259
|
+
type: SetAttribute,
|
|
260
|
+
key,
|
|
261
|
+
value: newNode[key]
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
for (const key of oldKeys) {
|
|
266
|
+
if (!(key in newNode)) {
|
|
267
|
+
patches.push({
|
|
268
|
+
type: RemoveAttribute,
|
|
269
|
+
key
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (oldNode.childCount && newNode.childCount) {
|
|
275
|
+
maxSiblingOffset = oldNode.childCount;
|
|
276
|
+
indexStack.push(0, maxSiblingOffset);
|
|
277
|
+
pendingPatches.push(NavigateChild, 0);
|
|
278
|
+
i++;
|
|
279
|
+
j++;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
if (oldNode.childCount) {
|
|
283
|
+
applyPendingPatches(patches, pendingPatches, 0);
|
|
284
|
+
for (let k = 0; k < oldNode.childCount; k++) {
|
|
285
|
+
patches.push({
|
|
286
|
+
type: RemoveChild,
|
|
287
|
+
index: 0
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
i += getTotalChildCount(oldNodes, i);
|
|
291
|
+
j++;
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (newNode.childCount) {
|
|
295
|
+
applyPendingPatches(patches, pendingPatches, 0);
|
|
296
|
+
const total = getTotalChildCount(newNodes, j);
|
|
297
|
+
patches.push({
|
|
298
|
+
type: Add,
|
|
299
|
+
nodes: newNodes.slice(j + 1, j + total)
|
|
300
|
+
});
|
|
301
|
+
i++;
|
|
302
|
+
j += total;
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
i++;
|
|
306
|
+
j++;
|
|
307
|
+
siblingOffset++;
|
|
308
|
+
}
|
|
309
|
+
while (i < oldNodes.length) {
|
|
310
|
+
if (indexStack.length !== 2) {
|
|
311
|
+
patches.push({
|
|
312
|
+
type: NavigateParent
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
patches.push({
|
|
316
|
+
type: RemoveChild,
|
|
317
|
+
index: siblingOffset
|
|
318
|
+
});
|
|
319
|
+
i += getTotalChildCount(oldNodes, i);
|
|
320
|
+
indexStack.pop();
|
|
321
|
+
indexStack.pop();
|
|
322
|
+
}
|
|
323
|
+
while (j < newNodes.length) {
|
|
324
|
+
if (siblingOffset > 0) {
|
|
325
|
+
patches.push({
|
|
326
|
+
type: NavigateSibling,
|
|
327
|
+
index: siblingOffset
|
|
328
|
+
});
|
|
329
|
+
siblingOffset = 0;
|
|
330
|
+
}
|
|
331
|
+
const count = getTotalChildCount(newNodes, j);
|
|
332
|
+
patches.push({
|
|
333
|
+
type: Add,
|
|
334
|
+
nodes: newNodes.slice(j, j + count)
|
|
335
|
+
});
|
|
336
|
+
j += count;
|
|
337
|
+
}
|
|
338
|
+
return patches;
|
|
339
|
+
};
|
|
133
340
|
export {
|
|
134
341
|
VirtualDomElements_exports as VirtualDomElements,
|
|
342
|
+
diff,
|
|
135
343
|
mergeClassNames,
|
|
136
344
|
text
|
|
137
345
|
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Patch } from '../Patch/Patch.ts'
|
|
2
|
+
import * as PatchType from '../PatchType/PatchType.ts'
|
|
3
|
+
|
|
4
|
+
export const applyPendingPatches = (
|
|
5
|
+
patches: Patch[],
|
|
6
|
+
pendingPatches: number[],
|
|
7
|
+
skip: number,
|
|
8
|
+
): void => {
|
|
9
|
+
for (let k = 0; k < pendingPatches.length - skip; k += 2) {
|
|
10
|
+
const type = pendingPatches[k]
|
|
11
|
+
const index = pendingPatches[k + 1]
|
|
12
|
+
if (type === PatchType.NavigateParent) {
|
|
13
|
+
patches.push({ type })
|
|
14
|
+
} else {
|
|
15
|
+
patches.push({
|
|
16
|
+
type,
|
|
17
|
+
index,
|
|
18
|
+
} as Patch)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
pendingPatches.length = 0
|
|
22
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts'
|
|
2
|
+
|
|
3
|
+
const isKey = (key: string): boolean => {
|
|
4
|
+
return key !== 'type' && key !== 'childCount'
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const getKeys = (node: VirtualDomNode): readonly string[] => {
|
|
8
|
+
const keys = Object.keys(node).filter(isKey)
|
|
9
|
+
return keys
|
|
10
|
+
}
|
package/src/parts/Main/Main.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Patch } from '../Patch/Patch.ts'
|
|
2
2
|
import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts'
|
|
3
|
+
import * as ApplyPendingPatches from '../ApplyPendingPatches/ApplyPendingPatches.ts'
|
|
4
|
+
import * as GetKeys from '../GetKeys/GetKeys.ts'
|
|
3
5
|
import * as GetTotalChildCount from '../GetTotalChildCount/GetTotalChildCount.ts'
|
|
4
6
|
import * as PatchType from '../PatchType/PatchType.ts'
|
|
5
7
|
import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts'
|
|
@@ -9,51 +11,60 @@ export const diff = (
|
|
|
9
11
|
newNodes: readonly VirtualDomNode[],
|
|
10
12
|
): readonly Patch[] => {
|
|
11
13
|
const patches: Patch[] = []
|
|
12
|
-
|
|
13
|
-
let
|
|
14
|
+
const pendingPatches: number[] = []
|
|
15
|
+
let i = 0
|
|
16
|
+
let j = 0
|
|
14
17
|
let siblingOffset = 0
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
while (i < oldNodeCount && j < newNodeCount) {
|
|
18
|
+
let maxSiblingOffset = 1
|
|
19
|
+
const indexStack: number[] = [0, 1]
|
|
20
|
+
while (i < oldNodes.length && j < newNodes.length) {
|
|
20
21
|
const oldNode = oldNodes[i]
|
|
21
22
|
const newNode = newNodes[j]
|
|
22
23
|
|
|
24
|
+
if (siblingOffset > 0) {
|
|
25
|
+
// pendingPatches.push(PatchType.NavigateSibling, siblingOffset)
|
|
26
|
+
}
|
|
27
|
+
if (siblingOffset === maxSiblingOffset) {
|
|
28
|
+
pendingPatches.push(PatchType.NavigateParent, 0)
|
|
29
|
+
maxSiblingOffset = indexStack.pop() as number
|
|
30
|
+
siblingOffset = (indexStack.pop() as number) + 1
|
|
31
|
+
}
|
|
32
|
+
|
|
23
33
|
if (oldNode.type !== newNode.type) {
|
|
34
|
+
let skip = 0
|
|
35
|
+
if (
|
|
36
|
+
pendingPatches.length > 0 &&
|
|
37
|
+
pendingPatches.at(-2) === PatchType.NavigateChild
|
|
38
|
+
) {
|
|
39
|
+
skip = 2
|
|
40
|
+
}
|
|
41
|
+
ApplyPendingPatches.applyPendingPatches(patches, pendingPatches, skip)
|
|
24
42
|
const oldTotal = GetTotalChildCount.getTotalChildCount(oldNodes, i)
|
|
25
43
|
const newTotal = GetTotalChildCount.getTotalChildCount(newNodes, j)
|
|
26
|
-
|
|
27
|
-
if (last && last.type === PatchType.NavigateChild) {
|
|
28
|
-
patches.pop()
|
|
29
|
-
}
|
|
44
|
+
|
|
30
45
|
patches.push({
|
|
31
46
|
type: PatchType.RemoveChild,
|
|
32
|
-
index:
|
|
47
|
+
index: siblingOffset,
|
|
33
48
|
})
|
|
34
49
|
patches.push({
|
|
35
50
|
type: PatchType.Add,
|
|
36
51
|
nodes: newNodes.slice(j, j + newTotal),
|
|
37
52
|
})
|
|
53
|
+
siblingOffset++
|
|
38
54
|
i += oldTotal
|
|
39
55
|
j += newTotal
|
|
40
56
|
continue
|
|
41
57
|
}
|
|
42
58
|
|
|
43
|
-
if (siblingOffset > 0) {
|
|
44
|
-
patches.push({
|
|
45
|
-
type: PatchType.NavigateSibling,
|
|
46
|
-
index: siblingOffset,
|
|
47
|
-
})
|
|
48
|
-
siblingOffset = 0
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// text node
|
|
52
59
|
if (
|
|
53
60
|
oldNode.type === VirtualDomElements.Text &&
|
|
54
61
|
newNode.type === VirtualDomElements.Text
|
|
55
62
|
) {
|
|
56
63
|
if (oldNode.text !== newNode.text) {
|
|
64
|
+
if (siblingOffset !== 0) {
|
|
65
|
+
pendingPatches.push(PatchType.NavigateSibling, siblingOffset)
|
|
66
|
+
}
|
|
67
|
+
ApplyPendingPatches.applyPendingPatches(patches, pendingPatches, 0)
|
|
57
68
|
patches.push({
|
|
58
69
|
type: PatchType.SetText,
|
|
59
70
|
value: newNode.text,
|
|
@@ -65,61 +76,68 @@ export const diff = (
|
|
|
65
76
|
continue
|
|
66
77
|
}
|
|
67
78
|
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
)
|
|
72
|
-
const newKeys = Object.keys(newNode).filter(
|
|
73
|
-
(key) => key !== 'type' && key !== 'childCount',
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
// Check for changed or added attributes
|
|
79
|
+
const oldKeys = GetKeys.getKeys(oldNode)
|
|
80
|
+
const newKeys = GetKeys.getKeys(newNode)
|
|
81
|
+
let hasAttributeChanges = false
|
|
77
82
|
for (const key of newKeys) {
|
|
78
83
|
if (oldNode[key] !== newNode[key]) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
key,
|
|
82
|
-
value: newNode[key],
|
|
83
|
-
})
|
|
84
|
+
hasAttributeChanges = true
|
|
85
|
+
break
|
|
84
86
|
}
|
|
85
87
|
}
|
|
86
|
-
|
|
87
|
-
// Check for removed attributes
|
|
88
88
|
for (const key of oldKeys) {
|
|
89
89
|
if (!(key in newNode)) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
hasAttributeChanges = true
|
|
91
|
+
break
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (hasAttributeChanges) {
|
|
96
|
+
ApplyPendingPatches.applyPendingPatches(patches, pendingPatches, 0)
|
|
97
|
+
|
|
98
|
+
for (const key of newKeys) {
|
|
99
|
+
if (oldNode[key] !== newNode[key]) {
|
|
100
|
+
patches.push({
|
|
101
|
+
type: PatchType.SetAttribute,
|
|
102
|
+
key,
|
|
103
|
+
value: newNode[key],
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (const key of oldKeys) {
|
|
108
|
+
if (!(key in newNode)) {
|
|
109
|
+
patches.push({
|
|
110
|
+
type: PatchType.RemoveAttribute,
|
|
111
|
+
key,
|
|
112
|
+
})
|
|
113
|
+
}
|
|
94
114
|
}
|
|
95
115
|
}
|
|
96
116
|
|
|
97
117
|
if (oldNode.childCount && newNode.childCount) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
})
|
|
118
|
+
maxSiblingOffset = oldNode.childCount
|
|
119
|
+
indexStack.push(0, maxSiblingOffset)
|
|
120
|
+
pendingPatches.push(PatchType.NavigateChild, 0)
|
|
102
121
|
i++
|
|
103
122
|
j++
|
|
104
123
|
continue
|
|
105
124
|
}
|
|
106
125
|
|
|
107
126
|
if (oldNode.childCount) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
})
|
|
117
|
-
i += total
|
|
127
|
+
ApplyPendingPatches.applyPendingPatches(patches, pendingPatches, 0)
|
|
128
|
+
for (let k = 0; k < oldNode.childCount; k++) {
|
|
129
|
+
patches.push({
|
|
130
|
+
type: PatchType.RemoveChild,
|
|
131
|
+
index: 0,
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
i += GetTotalChildCount.getTotalChildCount(oldNodes, i)
|
|
118
135
|
j++
|
|
119
136
|
continue
|
|
120
137
|
}
|
|
121
138
|
|
|
122
139
|
if (newNode.childCount) {
|
|
140
|
+
ApplyPendingPatches.applyPendingPatches(patches, pendingPatches, 0)
|
|
123
141
|
const total = GetTotalChildCount.getTotalChildCount(newNodes, j)
|
|
124
142
|
patches.push({
|
|
125
143
|
type: PatchType.Add,
|
|
@@ -135,23 +153,21 @@ export const diff = (
|
|
|
135
153
|
siblingOffset++
|
|
136
154
|
}
|
|
137
155
|
|
|
138
|
-
// Handle remaining old nodes
|
|
139
156
|
while (i < oldNodes.length) {
|
|
140
|
-
if (
|
|
157
|
+
if (indexStack.length !== 2) {
|
|
141
158
|
patches.push({
|
|
142
|
-
type: PatchType.
|
|
143
|
-
index: siblingOffset,
|
|
159
|
+
type: PatchType.NavigateParent,
|
|
144
160
|
})
|
|
145
|
-
siblingOffset = 0
|
|
146
161
|
}
|
|
147
162
|
patches.push({
|
|
148
163
|
type: PatchType.RemoveChild,
|
|
149
|
-
index:
|
|
164
|
+
index: siblingOffset,
|
|
150
165
|
})
|
|
151
166
|
i += GetTotalChildCount.getTotalChildCount(oldNodes, i)
|
|
167
|
+
indexStack.pop()
|
|
168
|
+
indexStack.pop()
|
|
152
169
|
}
|
|
153
170
|
|
|
154
|
-
// Handle remaining new nodes
|
|
155
171
|
while (j < newNodes.length) {
|
|
156
172
|
if (siblingOffset > 0) {
|
|
157
173
|
patches.push({
|