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