kiru 0.47.1 → 0.48.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/src/dom.ts CHANGED
@@ -3,16 +3,15 @@ import {
3
3
  commitSnapshot,
4
4
  propFilters,
5
5
  propToHtmlAttr,
6
- postOrderApply,
7
6
  getVNodeAppContext,
8
7
  } from "./utils.js"
9
8
  import {
10
9
  booleanAttributes,
11
- FLAG_DELETION,
12
10
  FLAG_PLACEMENT,
13
11
  FLAG_UPDATE,
14
12
  FLAG_STATIC_DOM,
15
13
  svgTags,
14
+ FLAG_NOOP,
16
15
  } from "./constants.js"
17
16
  import { Signal } from "./signals/base.js"
18
17
  import { unwrap } from "./signals/utils.js"
@@ -35,7 +34,7 @@ export { commitWork, commitDeletion, createDom, hydrateDom }
35
34
  type VNode = Kiru.VNode
36
35
  type HostNode = {
37
36
  node: ElementVNode
38
- lastChild?: DomVNode
37
+ lastChild?: SomeDom
39
38
  }
40
39
  type PlacementScope = {
41
40
  parent: VNode
@@ -551,7 +550,7 @@ function placeDom(vNode: DomVNode, hostNode: HostNode) {
551
550
  const { node: parentVNodeWithDom, lastChild } = hostNode
552
551
  const dom = vNode.dom
553
552
  if (lastChild) {
554
- lastChild.dom.after(dom)
553
+ lastChild.after(dom)
555
554
  return
556
555
  }
557
556
  // TODO: we can probably skip the 'next sibling search' if we're appending
@@ -608,72 +607,124 @@ function commitWork(vNode: VNode) {
608
607
  handlePrePlacementFocusPersistence()
609
608
 
610
609
  const hostNodes: HostNode[] = []
611
- let currentHostNode: HostNode
610
+ let currentHostNode: HostNode | undefined
612
611
  const placementScopes: PlacementScope[] = []
613
612
  let currentPlacementScope: PlacementScope | undefined
614
613
 
615
- postOrderApply(vNode, {
616
- onDescent: (node) => {
617
- if (node.dom) {
618
- // collect host nodes as we go
619
- currentHostNode = { node: node as ElementVNode }
614
+ const root = vNode
615
+ const rootChild = root.child
616
+
617
+ const onAscent = (node: VNode) => {
618
+ let inheritsPlacement = false
619
+ if (currentPlacementScope?.child === node) {
620
+ currentPlacementScope.active = true
621
+ inheritsPlacement = true
622
+ }
623
+ if (node.dom) {
624
+ if (!currentHostNode) {
625
+ currentHostNode = { node: getDomParent(node) }
620
626
  hostNodes.push(currentHostNode)
627
+ }
628
+ if (!(node.flags & FLAG_STATIC_DOM)) {
629
+ commitDom(node as DomVNode, currentHostNode, inheritsPlacement)
630
+ }
631
+ }
632
+ commitSnapshot(node)
633
+ }
621
634
 
622
- if (node.prev && "innerHTML" in node.prev.props) {
623
- /**
624
- * We need to update innerHTML during descent in cases
625
- * where we previously set innerHTML on this element but
626
- * now we provide children. Setting innerHTML _after_
627
- * appending children will yeet em into the abyss.
628
- */
629
- delete node.props.innerHTML
630
- setInnerHTML(node.dom as SomeElement, "")
631
- // remove innerHTML from prev to prevent our ascension pass from doing this again
632
- delete node.prev.props.innerHTML
633
- }
635
+ if (!rootChild) {
636
+ onAscent(root)
637
+ return
638
+ }
634
639
 
635
- if (currentPlacementScope?.active) {
636
- currentPlacementScope.child = node
637
- // prevent scope applying to descendants of this element node
638
- currentPlacementScope.active = false
639
- }
640
- } else if (node.flags & FLAG_PLACEMENT) {
641
- currentPlacementScope = { parent: node, active: true }
642
- placementScopes.push(currentPlacementScope)
640
+ const onDescent = (node: VNode) => {
641
+ if (node.dom) {
642
+ // collect host nodes as we go
643
+ currentHostNode = { node: node as ElementVNode }
644
+ hostNodes.push(currentHostNode)
645
+
646
+ if (node.prev && "innerHTML" in node.prev.props) {
647
+ /**
648
+ * We need to update innerHTML during descent in cases
649
+ * where we previously set innerHTML on this element but
650
+ * now we provide children. Setting innerHTML _after_
651
+ * appending children will yeet em into the abyss.
652
+ */
653
+ delete node.props.innerHTML
654
+ setInnerHTML(node.dom as SomeElement, "")
655
+ // remove innerHTML from prev to prevent our ascension pass from doing this again
656
+ delete node.prev.props.innerHTML
643
657
  }
644
- },
645
- onAscent: (node) => {
646
- let inheritsPlacement = false
647
- if (currentPlacementScope?.child === node) {
648
- currentPlacementScope.active = true
649
- inheritsPlacement = true
650
- }
651
- if (node.flags & FLAG_DELETION) {
652
- return commitDeletion(node)
658
+
659
+ if (currentPlacementScope?.active) {
660
+ currentPlacementScope.child = node
661
+ // prevent scope applying to descendants of this element node
662
+ currentPlacementScope.active = false
653
663
  }
654
- if (node.dom) {
655
- if (!currentHostNode) {
656
- currentHostNode = { node: getDomParent(node) }
657
- hostNodes.push(currentHostNode)
658
- }
659
- if (!(node.flags & FLAG_STATIC_DOM)) {
660
- commitDom(node as DomVNode, currentHostNode, inheritsPlacement)
664
+ } else if (node.flags & FLAG_PLACEMENT) {
665
+ currentPlacementScope = { parent: node, active: true }
666
+ placementScopes.push(currentPlacementScope)
667
+ }
668
+ }
669
+
670
+ onDescent(root)
671
+ let branch = rootChild
672
+ while (branch) {
673
+ let c = branch
674
+ while (c) {
675
+ if (!c.child) break
676
+ if (c.flags & FLAG_NOOP) {
677
+ if (c.flags & FLAG_PLACEMENT) {
678
+ const directDomChildren = findDirectDomChildren(c)
679
+ if (directDomChildren.length === 0) {
680
+ break
681
+ }
682
+ if (!currentHostNode) {
683
+ currentHostNode = { node: getDomParent(c) }
684
+ hostNodes.push(currentHostNode)
685
+ }
686
+ const { node, lastChild } = currentHostNode
687
+ if (lastChild) {
688
+ lastChild.after(...directDomChildren)
689
+ } else {
690
+ const nextSiblingDom = getNextSiblingDom(c, node)
691
+ const parentDom = node.dom
692
+ if (nextSiblingDom) {
693
+ const [first, ...rest] = directDomChildren
694
+ parentDom.insertBefore(first, nextSiblingDom)
695
+ first.after(...rest)
696
+ } else {
697
+ parentDom.append(...directDomChildren)
698
+ }
699
+ }
700
+ currentHostNode.lastChild =
701
+ directDomChildren[directDomChildren.length - 1]
661
702
  }
703
+ break
662
704
  }
663
- commitSnapshot(node)
664
- },
665
- onBeforeAscent(node) {
666
- if (currentPlacementScope?.parent === node) {
705
+ onDescent(c)
706
+ c = c.child
707
+ }
708
+
709
+ while (c && c !== root) {
710
+ onAscent(c)
711
+ if (c.sibling) {
712
+ branch = c.sibling
713
+ break
714
+ }
715
+ if (currentPlacementScope?.parent === c) {
667
716
  placementScopes.pop()
668
717
  currentPlacementScope = placementScopes[placementScopes.length - 1]
669
718
  }
670
- if (currentHostNode?.node === node.parent) {
719
+ if (currentHostNode?.node === c.parent) {
671
720
  hostNodes.pop()
672
721
  currentHostNode = hostNodes[hostNodes.length - 1]
673
722
  }
674
- },
675
- })
676
-
723
+ c = c.parent!
724
+ }
725
+ if (c === root) break
726
+ }
727
+ onAscent(root)
677
728
  handlePostPlacementFocusPersistence()
678
729
  }
679
730
 
@@ -692,7 +743,7 @@ function commitDom(
692
743
  if (!vNode.prev || vNode.flags & FLAG_UPDATE) {
693
744
  updateDom(vNode)
694
745
  }
695
- hostNode.lastChild = vNode
746
+ hostNode.lastChild = vNode.dom
696
747
  }
697
748
 
698
749
  function commitDeletion(vNode: VNode) {
@@ -730,3 +781,25 @@ function commitDeletion(vNode: VNode) {
730
781
 
731
782
  vNode.parent = null
732
783
  }
784
+
785
+ function findDirectDomChildren(vNode: VNode): SomeDom[] {
786
+ const domChildren: SomeDom[] = []
787
+
788
+ function collectDomNodes(node: VNode | null): void {
789
+ while (node) {
790
+ if (node.dom) {
791
+ // Found a DOM node, add it to the collection
792
+ domChildren.push(node.dom)
793
+ } else if (node.child) {
794
+ // This is a component or fragment, traverse its children
795
+ collectDomNodes(node.child)
796
+ }
797
+ node = node.sibling
798
+ }
799
+ }
800
+
801
+ // Start collecting from the memo's children
802
+ collectDomNodes(vNode.child)
803
+
804
+ return domChildren
805
+ }
package/src/reconciler.ts CHANGED
@@ -1,10 +1,4 @@
1
- import {
2
- $FRAGMENT,
3
- FLAG_HAS_MEMO_ANCESTOR,
4
- FLAG_MEMO,
5
- FLAG_PLACEMENT,
6
- FLAG_UPDATE,
7
- } from "./constants.js"
1
+ import { $FRAGMENT, FLAG_PLACEMENT, FLAG_UPDATE } from "./constants.js"
8
2
  import { getVNodeAppContext, isVNode, latest } from "./utils.js"
9
3
  import { Signal } from "./signals/base.js"
10
4
  import { __DEV__ } from "./env.js"
@@ -32,7 +26,6 @@ export function reconcileChildren(parent: VNode, children: unknown) {
32
26
  }
33
27
 
34
28
  function reconcileSingleChild(parent: VNode, child: unknown) {
35
- const deletions: VNode[] = (parent.deletions = [])
36
29
  const oldChild = parent.child
37
30
  if (oldChild === null) {
38
31
  return createChild(parent, child)
@@ -60,13 +53,12 @@ function reconcileSingleChild(parent: VNode, child: unknown) {
60
53
  }
61
54
  placeChild(newNode, 0, 0)
62
55
  }
63
- existingChildren.forEach((child) => deletions.push(child))
56
+ existingChildren.forEach((child) => deleteChild(parent, child))
64
57
  return newNode
65
58
  }
66
59
  }
67
60
 
68
61
  function reconcileChildrenArray(parent: VNode, children: unknown[]) {
69
- const deletions: VNode[] = (parent.deletions = [])
70
62
  let resultingChild: VNode | null = null
71
63
  let prevNewChild: VNode | null = null
72
64
 
@@ -90,7 +82,7 @@ function reconcileChildrenArray(parent: VNode, children: unknown[]) {
90
82
  break
91
83
  }
92
84
  if (oldChild && !newChild.prev) {
93
- deletions.push(oldChild)
85
+ deleteChild(parent, oldChild)
94
86
  }
95
87
  lastPlacedIndex = placeChild(newChild, lastPlacedIndex, newIdx)
96
88
  if (prevNewChild === null) {
@@ -151,7 +143,7 @@ function reconcileChildrenArray(parent: VNode, children: unknown[]) {
151
143
  }
152
144
  }
153
145
 
154
- existingChildren.forEach((child) => deletions.push(child))
146
+ existingChildren.forEach((child) => deleteChild(parent, child))
155
147
  return resultingChild
156
148
  }
157
149
 
@@ -460,9 +452,6 @@ function propsChanged(oldProps: VNode["props"], newProps: VNode["props"]) {
460
452
  function setParent(child: VNode, parent: VNode) {
461
453
  child.parent = parent
462
454
  child.depth = parent.depth + 1
463
- if (parent.flags & (FLAG_MEMO | FLAG_HAS_MEMO_ANCESTOR)) {
464
- child.flags |= FLAG_HAS_MEMO_ANCESTOR
465
- }
466
455
  }
467
456
 
468
457
  function dev_emitUpdateNode() {
@@ -490,9 +479,17 @@ function mapRemainingChildren(child: VNode | null) {
490
479
  return map
491
480
  }
492
481
 
482
+ function deleteChild(parent: VNode, child: VNode) {
483
+ if (parent.deletions === null) {
484
+ parent.deletions = [child]
485
+ } else {
486
+ parent.deletions.push(child)
487
+ }
488
+ }
489
+
493
490
  function deleteRemainingChildren(parent: VNode, child: VNode | null) {
494
491
  while (child) {
495
- parent.deletions!.push(child)
492
+ deleteChild(parent, child)
496
493
  child = child.sibling
497
494
  }
498
495
  }
package/src/scheduler.ts CHANGED
@@ -7,7 +7,9 @@ import {
7
7
  $CONTEXT_PROVIDER,
8
8
  CONSECUTIVE_DIRTY_LIMIT,
9
9
  FLAG_DELETION,
10
+ FLAG_DIRTY,
10
11
  FLAG_MEMO,
12
+ FLAG_NOOP,
11
13
  } from "./constants.js"
12
14
  import { commitDeletion, commitWork, createDom, hydrateDom } from "./dom.js"
13
15
  import { __DEV__ } from "./env.js"
@@ -17,10 +19,8 @@ import { hydrationStack } from "./hydration.js"
17
19
  import { assertValidElementProps } from "./props.js"
18
20
  import { reconcileChildren } from "./reconciler.js"
19
21
  import {
20
- willMemoBlockUpdate,
21
22
  latest,
22
23
  traverseApply,
23
- vNodeContains,
24
24
  isExoticType,
25
25
  getVNodeAppContext,
26
26
  } from "./utils.js"
@@ -29,9 +29,7 @@ import type { AppContext } from "./appContext"
29
29
  type VNode = Kiru.VNode
30
30
 
31
31
  let appCtx: AppContext | null
32
- let nextUnitOfWork: VNode | null = null
33
32
  let treesInProgress: VNode[] = []
34
- let currentTreeIndex = 0
35
33
  let isRunningOrQueued = false
36
34
  let nextIdleEffects: (() => void)[] = []
37
35
  let deletions: VNode[] = []
@@ -39,7 +37,6 @@ let isImmediateEffectsMode = false
39
37
  let immediateEffectDirtiedRender = false
40
38
  let isRenderDirtied = false
41
39
  let consecutiveDirtyCount = 0
42
- let pendingContextChanges = new Set<ContextProviderNode<any>>()
43
40
  let preEffects: Array<Function> = []
44
41
  let postEffects: Array<Function> = []
45
42
  let animationFrameHandle = -1
@@ -106,91 +103,14 @@ function queueUpdate(vNode: VNode) {
106
103
  return
107
104
  }
108
105
 
109
- // If it's already the next unit of work, no need to queue again
110
- if (nextUnitOfWork === vNode) {
111
- return
112
- }
106
+ if (vNode.flags & (FLAG_DIRTY | FLAG_DELETION)) return
107
+ vNode.flags |= FLAG_DIRTY
113
108
 
114
- if (nextUnitOfWork === null) {
109
+ if (!treesInProgress.length) {
115
110
  treesInProgress.push(vNode)
116
- nextUnitOfWork = vNode
117
111
  return queueBeginWork()
118
112
  }
119
113
 
120
- for (let i = 0; i < treesInProgress.length; i++) {
121
- const tree = treesInProgress[i]
122
- if (tree !== vNode) continue
123
- if (i < currentTreeIndex) {
124
- // It was already processed; requeue it to the end
125
- currentTreeIndex--
126
- treesInProgress.splice(i, 1)
127
- treesInProgress.push(tree)
128
- }
129
- return
130
- }
131
-
132
- // Check if this node is a descendant of any trees already queued
133
- for (let i = 0; i < treesInProgress.length; i++) {
134
- const tree = treesInProgress[i]
135
- if (!vNodeContains(tree, vNode)) continue
136
-
137
- if (i === currentTreeIndex) {
138
- // It's a child of the currently worked-on tree
139
- // If it's deeper within the same tree, we can skip
140
- if (vNodeContains(nextUnitOfWork, vNode)) return
141
- // If it's not in the current work subtree, move back up to it
142
- nextUnitOfWork = vNode
143
- } else if (i < currentTreeIndex) {
144
- // It's a descendant of an already processed tree; treat as a new update
145
- treesInProgress.push(vNode)
146
- }
147
-
148
- return
149
- }
150
-
151
- // Check if this node contains any of the currently queued trees
152
- let didReplaceTree = false
153
- let shouldQueueAtEnd = false
154
- for (let i = 0; i < treesInProgress.length; ) {
155
- const tree = treesInProgress[i]
156
- if (!vNodeContains(vNode, tree)) {
157
- i++
158
- continue
159
- }
160
- // This node contains another update root, replace it
161
-
162
- if (i === currentTreeIndex) {
163
- if (!didReplaceTree) {
164
- treesInProgress.splice(i, 1, vNode)
165
- nextUnitOfWork = vNode
166
- didReplaceTree = true
167
- i++ // advance past replaced node
168
- } else {
169
- treesInProgress.splice(i, 1)
170
- // no increment
171
- }
172
- } else if (i < currentTreeIndex) {
173
- currentTreeIndex--
174
- treesInProgress.splice(i, 1)
175
- if (!didReplaceTree) {
176
- shouldQueueAtEnd = true
177
- didReplaceTree = true
178
- }
179
- // no increment
180
- } else {
181
- // i > currentTreeIndex
182
- treesInProgress.splice(i, 1)
183
- if (!didReplaceTree) {
184
- shouldQueueAtEnd = true
185
- didReplaceTree = true
186
- }
187
- // no increment
188
- }
189
- }
190
- if (!shouldQueueAtEnd && didReplaceTree) {
191
- return
192
- }
193
- // If it doesn't overlap with any queued tree, queue as new independent update root
194
114
  treesInProgress.push(vNode)
195
115
  }
196
116
 
@@ -199,9 +119,13 @@ function queueDelete(vNode: VNode) {
199
119
  deletions.push(vNode)
200
120
  }
201
121
 
122
+ const depthSort = (a: VNode, b: VNode) => b.depth - a.depth
123
+
124
+ let currentWorkRoot: VNode | null = null
125
+
202
126
  function doWork(): void {
203
127
  if (__DEV__) {
204
- const n = nextUnitOfWork ?? deletions[0] ?? treesInProgress[0]
128
+ const n = deletions[0] ?? treesInProgress[0]
205
129
  if (n) {
206
130
  appCtx = getVNodeAppContext(n)!
207
131
  window.__kiru?.profilingContext?.beginTick(appCtx)
@@ -210,21 +134,29 @@ function doWork(): void {
210
134
  }
211
135
  }
212
136
 
213
- while (nextUnitOfWork) {
214
- nextUnitOfWork =
215
- performUnitOfWork(nextUnitOfWork) ??
216
- treesInProgress[++currentTreeIndex] ??
217
- queueBlockedContextDependencyRoots()
218
- }
137
+ let len = 1
219
138
 
220
- while (deletions.length) {
221
- commitDeletion(deletions.shift()!)
222
- }
223
- const workRoots = [...treesInProgress]
224
- treesInProgress.length = 0
225
- currentTreeIndex = 0
226
- for (const root of workRoots) {
227
- commitWork(root)
139
+ while (treesInProgress.length) {
140
+ if (treesInProgress.length > len) {
141
+ treesInProgress.sort(depthSort)
142
+ }
143
+
144
+ currentWorkRoot = treesInProgress.shift()!
145
+ len = treesInProgress.length
146
+
147
+ const flags = currentWorkRoot.flags
148
+ if (flags & FLAG_DELETION) continue
149
+ if (flags & FLAG_DIRTY) {
150
+ let n: VNode | void = currentWorkRoot
151
+ while ((n = performUnitOfWork(n))) {}
152
+
153
+ while (deletions.length) {
154
+ commitDeletion(deletions.pop()!)
155
+ }
156
+ commitWork(currentWorkRoot)
157
+
158
+ currentWorkRoot.flags &= ~FLAG_DIRTY
159
+ }
228
160
  }
229
161
 
230
162
  isImmediateEffectsMode = true
@@ -253,39 +185,6 @@ function doWork(): void {
253
185
  }
254
186
  }
255
187
 
256
- function queueBlockedContextDependencyRoots(): VNode | null {
257
- if (pendingContextChanges.size === 0) return null
258
-
259
- // TODO: it's possible that a 'job' created by this process is
260
- // blocked by a parent memo after a queueUpdate -> replaceTree action.
261
- // To prevent this, we might need to add these to a distinct queue.
262
- const jobRoots: VNode[] = []
263
- pendingContextChanges.forEach((provider) => {
264
- provider.props.dependents.forEach((dep) => {
265
- if (!willMemoBlockUpdate(provider, dep)) return
266
- for (let i = 0; i < jobRoots.length; i++) {
267
- const root = jobRoots[i]
268
- if (vNodeContains(root, dep)) {
269
- if (willMemoBlockUpdate(root, dep)) {
270
- // root is a parent of dep and there's a memo between them, prevent consolidation and queue as new root
271
- break
272
- }
273
- return
274
- }
275
- if (vNodeContains(dep, root)) {
276
- jobRoots[i] = dep
277
- return
278
- }
279
- }
280
- jobRoots.push(dep)
281
- })
282
- })
283
-
284
- pendingContextChanges.clear()
285
- treesInProgress.push(...jobRoots)
286
- return jobRoots[0] ?? null
287
- }
288
-
289
188
  function performUnitOfWork(vNode: VNode): VNode | void {
290
189
  let renderChild = true
291
190
  try {
@@ -293,15 +192,15 @@ function performUnitOfWork(vNode: VNode): VNode | void {
293
192
  if (typeof vNode.type === "string") {
294
193
  updateHostComponent(vNode as DomVNode)
295
194
  } else if (isExoticType(vNode.type)) {
296
- if (vNode.type === $CONTEXT_PROVIDER) {
195
+ if (vNode?.type === $CONTEXT_PROVIDER) {
297
196
  const asProvider = vNode as ContextProviderNode<any>
298
- const { dependents, value } = asProvider.props
299
- if (
300
- dependents.size &&
301
- asProvider.prev &&
302
- asProvider.prev.props.value !== value
303
- ) {
304
- pendingContextChanges.add(asProvider)
197
+ const {
198
+ props: { dependents, value },
199
+ prev,
200
+ } = asProvider
201
+
202
+ if (dependents.size && prev && prev.props.value !== value) {
203
+ dependents.forEach(queueUpdate)
305
204
  }
306
205
  }
307
206
  vNode.child = reconcileChildren(vNode, props.children)
@@ -351,7 +250,7 @@ function performUnitOfWork(vNode: VNode): VNode | void {
351
250
  nextNode.effects = undefined
352
251
  }
353
252
 
354
- if (nextNode === treesInProgress[currentTreeIndex]) return
253
+ if (nextNode === currentWorkRoot) return
355
254
  if (nextNode.sibling) {
356
255
  return nextNode.sibling
357
256
  }
@@ -372,14 +271,17 @@ function updateFunctionComponent(vNode: FunctionVNode) {
372
271
  vNode.arePropsEqual!(prev.memoizedProps, props) &&
373
272
  !vNode.hmrUpdated
374
273
  ) {
274
+ vNode.flags |= FLAG_NOOP
375
275
  return false
376
276
  }
277
+ vNode.flags &= ~FLAG_NOOP
377
278
  }
378
279
  try {
379
280
  node.current = vNode
380
281
  let newChild
381
282
  let renderTryCount = 0
382
283
  do {
284
+ vNode.flags &= ~FLAG_DIRTY
383
285
  isRenderDirtied = false
384
286
  hookIndex.current = 0
385
287
 
package/src/utils.ts CHANGED
@@ -5,10 +5,8 @@ import {
5
5
  $HYDRATION_BOUNDARY,
6
6
  booleanAttributes,
7
7
  FLAG_DELETION,
8
- FLAG_HAS_MEMO_ANCESTOR,
9
8
  FLAG_PLACEMENT,
10
9
  FLAG_UPDATE,
11
- FLAG_MEMO,
12
10
  REGEX_UNIT,
13
11
  } from "./constants.js"
14
12
  import { unwrap } from "./signals/utils.js"
@@ -25,12 +23,10 @@ export {
25
23
  isExoticType,
26
24
  isVNodeDeleted,
27
25
  vNodeContains,
28
- willMemoBlockUpdate,
29
26
  getCurrentVNode,
30
27
  getVNodeAppContext,
31
28
  commitSnapshot,
32
29
  traverseApply,
33
- postOrderApply,
34
30
  findParent,
35
31
  propToHtmlAttr,
36
32
  propValueToHtmlAttrValue,
@@ -158,26 +154,6 @@ function vNodeContains(haystack: VNode, needle: VNode): boolean {
158
154
  return false
159
155
  }
160
156
 
161
- function willMemoBlockUpdate(root: VNode, target: VNode): boolean {
162
- let node: VNode | null = target
163
-
164
- while (node && node !== root && node.flags & FLAG_HAS_MEMO_ANCESTOR) {
165
- const parent = node.parent
166
- if (!parent) return false
167
- if (
168
- parent.flags & FLAG_MEMO &&
169
- parent.prev?.memoizedProps &&
170
- parent.arePropsEqual!(parent.prev.memoizedProps, parent.props)
171
- ) {
172
- return true
173
- }
174
-
175
- node = node.parent
176
- }
177
-
178
- return false
179
- }
180
-
181
157
  function traverseApply(vNode: VNode, func: (node: VNode) => void): void {
182
158
  let applyToSiblings = false
183
159
  const nodes: VNode[] = [vNode]
@@ -190,49 +166,6 @@ function traverseApply(vNode: VNode, func: (node: VNode) => void): void {
190
166
  while (nodes.length) apply(nodes.shift()!)
191
167
  }
192
168
 
193
- function postOrderApply(
194
- tree: VNode,
195
- callbacks: {
196
- /** called upon traversing to the next parent, and on the root */
197
- onAscent: (vNode: VNode) => void
198
- /** called before traversing to the next parent */
199
- onBeforeAscent?: (vNode: VNode) => void
200
- /** called before traversing to the next child */
201
- onDescent?: (vNode: VNode) => void
202
- }
203
- ): void {
204
- const root = tree
205
- const rootChild = root.child
206
- if (!rootChild) {
207
- callbacks.onAscent(root)
208
- return
209
- }
210
-
211
- callbacks.onDescent?.(root)
212
- let branch = rootChild
213
- while (branch) {
214
- let c = branch
215
- while (c) {
216
- if (!c.child) break
217
- callbacks.onDescent?.(c)
218
- c = c.child
219
- }
220
-
221
- while (c && c !== root) {
222
- callbacks.onAscent(c)
223
- if (c.sibling) {
224
- branch = c.sibling
225
- break
226
- }
227
- callbacks.onBeforeAscent?.(c)
228
- c = c.parent!
229
- }
230
- if (c === root) break
231
- }
232
-
233
- callbacks.onAscent(root)
234
- }
235
-
236
169
  function findParent(vNode: Kiru.VNode, predicate: (n: Kiru.VNode) => boolean) {
237
170
  let n: Kiru.VNode | null = vNode.parent
238
171
  while (n) {