@lvce-editor/virtual-dom-worker 1.6.0 → 1.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/virtual-dom-worker",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "keywords": [],
@@ -0,0 +1,6 @@
1
+ import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts'
2
+
3
+ export interface AddPatch {
4
+ readonly type: 6
5
+ readonly nodes: readonly VirtualDomNode[]
6
+ }
@@ -1,6 +1,5 @@
1
1
  export interface AttributePatch {
2
2
  readonly type: 3
3
- readonly index: number
4
3
  readonly key: string
5
4
  readonly value: any
6
5
  }
@@ -0,0 +1,16 @@
1
+ import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts'
2
+
3
+ export const getTotalChildCount = (
4
+ nodes: readonly VirtualDomNode[],
5
+ index: number,
6
+ ): number => {
7
+ let i = index
8
+ let pending = 1
9
+ while (pending) {
10
+ const node = nodes[i]
11
+ pending += node.childCount
12
+ pending--
13
+ i++
14
+ }
15
+ return i - index
16
+ }
@@ -0,0 +1,4 @@
1
+ export type NavigateChildPatch = {
2
+ readonly type: 7
3
+ readonly index: number
4
+ }
@@ -0,0 +1,4 @@
1
+ export type NavigateParentPatch = {
2
+ readonly type: 8
3
+ readonly count: number
4
+ }
@@ -0,0 +1,4 @@
1
+ export type NavigateSiblingPatch = {
2
+ readonly type: 10
3
+ readonly index: number
4
+ }
@@ -1,10 +1,22 @@
1
+ import type { AddPatch } from '../AddPatch/AddPatch.ts'
1
2
  import type { AttributePatch } from '../AttributePatch/AttributePatch.ts'
3
+ import type { NavigateChildPatch } from '../NavigateChildPatch/NavigateChildPatch.ts'
4
+ import type { NavigateParentPatch } from '../NavigateParentPatch/NavigateParentPatch.ts'
5
+ import type { NavigateSiblingPatch } from '../NavigateSiblingPatch/NavigateSiblingPatch.ts'
6
+ import type { RemoveAttributePatch } from '../RemoveAttributePatch/RemoveAttributePatch.ts'
7
+ import type { RemoveChildPatch } from '../RemoveChildPatch/RemoveChildPatch.ts'
8
+ import type { RemovePatch } from '../RemovePatch/RemovePatch.ts'
2
9
  import type { ReplacePatch } from '../ReplacePatch/ReplacePatch.ts'
3
10
  import type { TextPatch } from '../TextPatch/TextPatch.ts'
4
- import type { RemoveAttributePatch } from '../RemoveAttributePatch/RemoveAttributePatch.ts'
5
11
 
6
12
  export type Patch =
7
13
  | TextPatch
8
14
  | AttributePatch
9
15
  | ReplacePatch
10
16
  | RemoveAttributePatch
17
+ | RemovePatch
18
+ | AddPatch
19
+ | NavigateChildPatch
20
+ | NavigateParentPatch
21
+ | RemoveChildPatch
22
+ | NavigateSiblingPatch
@@ -2,3 +2,9 @@ export const SetText = 1
2
2
  export const Replace = 2
3
3
  export const SetAttribute = 3
4
4
  export const RemoveAttribute = 4
5
+ export const Remove = 5
6
+ export const Add = 6
7
+ export const NavigateChild = 7
8
+ export const NavigateParent = 8
9
+ export const RemoveChild = 9
10
+ export const NavigateSibling = 10
@@ -1,5 +1,4 @@
1
1
  export interface RemoveAttributePatch {
2
2
  readonly type: 4
3
- readonly index: number
4
3
  readonly key: string
5
4
  }
@@ -0,0 +1,4 @@
1
+ export interface RemoveChildPatch {
2
+ readonly type: 9
3
+ readonly index: number
4
+ }
@@ -0,0 +1,4 @@
1
+ export interface RemovePatch {
2
+ readonly type: 5
3
+ readonly index: number
4
+ }
@@ -1,5 +1,4 @@
1
1
  export interface TextPatch {
2
2
  readonly type: 1
3
- readonly index: number
4
3
  readonly value: string
5
4
  }
@@ -1,5 +1,6 @@
1
1
  import type { Patch } from '../Patch/Patch.ts'
2
2
  import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts'
3
+ import * as GetTotalChildCount from '../GetTotalChildCount/GetTotalChildCount.ts'
3
4
  import * as PatchType from '../PatchType/PatchType.ts'
4
5
  import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts'
5
6
 
@@ -8,44 +9,46 @@ export const diff = (
8
9
  newNodes: readonly VirtualDomNode[],
9
10
  ): readonly Patch[] => {
10
11
  const patches: Patch[] = []
12
+ let i = 0 // Index for oldNodes
13
+ let j = 0 // Index for newNodes
14
+ let siblingOffset = 0
11
15
 
12
- // Compare nodes at each index
13
- for (let i = 0; i < Math.max(oldNodes.length, newNodes.length); i++) {
16
+ const oldNodeCount = oldNodes.length
17
+ const newNodeCount = newNodes.length
18
+
19
+ while (i < oldNodeCount && j < newNodeCount) {
14
20
  const oldNode = oldNodes[i]
15
- const newNode = newNodes[i]
21
+ const newNode = newNodes[j]
16
22
 
17
- // Handle node removal
18
- if (!newNode) {
23
+ if (oldNode.type !== newNode.type) {
24
+ const oldTotal = GetTotalChildCount.getTotalChildCount(oldNodes, i)
25
+ const newTotal = GetTotalChildCount.getTotalChildCount(newNodes, j)
26
+ const last = patches.at(-1)
27
+ if (last && last.type === PatchType.NavigateChild) {
28
+ patches.pop()
29
+ }
19
30
  patches.push({
20
- type: PatchType.Replace,
21
- index: i,
22
- // @ts-ignore
23
- node: undefined,
31
+ type: PatchType.RemoveChild,
32
+ index: 0,
24
33
  })
25
- continue
26
- }
27
-
28
- // Handle node addition
29
- if (!oldNode) {
30
34
  patches.push({
31
- type: PatchType.Replace,
32
- index: i,
33
- node: newNode,
35
+ type: PatchType.Add,
36
+ nodes: newNodes.slice(j, j + newTotal),
34
37
  })
38
+ i += oldTotal
39
+ j += newTotal
35
40
  continue
36
41
  }
37
42
 
38
- // Different node types - complete replacement
39
- if (oldNode.type !== newNode.type) {
43
+ if (siblingOffset > 0) {
40
44
  patches.push({
41
- type: PatchType.Replace,
42
- index: i,
43
- node: newNode,
45
+ type: PatchType.NavigateSibling,
46
+ index: siblingOffset,
44
47
  })
45
- continue
48
+ siblingOffset = 0
46
49
  }
47
50
 
48
- // Text node changes
51
+ // text node
49
52
  if (
50
53
  oldNode.type === VirtualDomElements.Text &&
51
54
  newNode.type === VirtualDomElements.Text
@@ -53,10 +56,12 @@ export const diff = (
53
56
  if (oldNode.text !== newNode.text) {
54
57
  patches.push({
55
58
  type: PatchType.SetText,
56
- index: i,
57
59
  value: newNode.text,
58
60
  })
59
61
  }
62
+ i++
63
+ j++
64
+ siblingOffset++
60
65
  continue
61
66
  }
62
67
 
@@ -73,7 +78,6 @@ export const diff = (
73
78
  if (oldNode[key] !== newNode[key]) {
74
79
  patches.push({
75
80
  type: PatchType.SetAttribute,
76
- index: i,
77
81
  key,
78
82
  value: newNode[key],
79
83
  })
@@ -85,11 +89,83 @@ export const diff = (
85
89
  if (!(key in newNode)) {
86
90
  patches.push({
87
91
  type: PatchType.RemoveAttribute,
88
- index: i,
89
92
  key,
90
93
  })
91
94
  }
92
95
  }
96
+
97
+ if (oldNode.childCount && newNode.childCount) {
98
+ patches.push({
99
+ type: PatchType.NavigateChild,
100
+ index: 0,
101
+ })
102
+ i++
103
+ j++
104
+ continue
105
+ }
106
+
107
+ if (oldNode.childCount) {
108
+ const total = GetTotalChildCount.getTotalChildCount(oldNodes, i)
109
+ // const last = patches.at(-1)
110
+ // if (last && last.type === PatchType.NavigateChild) {
111
+ // patches.pop()
112
+ // }
113
+ patches.push({
114
+ type: PatchType.RemoveChild,
115
+ index: 0,
116
+ })
117
+ i += total
118
+ j++
119
+ continue
120
+ }
121
+
122
+ if (newNode.childCount) {
123
+ const total = GetTotalChildCount.getTotalChildCount(newNodes, j)
124
+ patches.push({
125
+ type: PatchType.Add,
126
+ nodes: newNodes.slice(j + 1, j + total),
127
+ })
128
+ i++
129
+ j += total
130
+ continue
131
+ }
132
+
133
+ i++
134
+ j++
135
+ siblingOffset++
136
+ }
137
+
138
+ // Handle remaining old nodes
139
+ while (i < oldNodes.length) {
140
+ if (siblingOffset > 0) {
141
+ patches.push({
142
+ type: PatchType.NavigateSibling,
143
+ index: siblingOffset,
144
+ })
145
+ siblingOffset = 0
146
+ }
147
+ patches.push({
148
+ type: PatchType.RemoveChild,
149
+ index: 0,
150
+ })
151
+ i += GetTotalChildCount.getTotalChildCount(oldNodes, i)
152
+ }
153
+
154
+ // Handle remaining new nodes
155
+ while (j < newNodes.length) {
156
+ if (siblingOffset > 0) {
157
+ patches.push({
158
+ type: PatchType.NavigateSibling,
159
+ index: siblingOffset,
160
+ })
161
+ siblingOffset = 0
162
+ }
163
+ const count = GetTotalChildCount.getTotalChildCount(newNodes, j)
164
+ patches.push({
165
+ type: PatchType.Add,
166
+ nodes: newNodes.slice(j, j + count),
167
+ })
168
+ j += count
93
169
  }
94
170
 
95
171
  return patches