@colyseus/schema 4.0.0 → 4.0.2

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.
Files changed (241) hide show
  1. package/build/cjs/{index.js → index.cjs} +1 -1
  2. package/build/cjs/index.cjs.map +1 -0
  3. package/build/esm/index.mjs.map +1 -1
  4. package/lib/Metadata.js +54 -58
  5. package/lib/Metadata.js.map +1 -1
  6. package/lib/Reflection.js +29 -32
  7. package/lib/Reflection.js.map +1 -1
  8. package/lib/Schema.js +41 -45
  9. package/lib/Schema.js.map +1 -1
  10. package/lib/annotations.d.ts +1 -1
  11. package/lib/annotations.js +58 -69
  12. package/lib/annotations.js.map +1 -1
  13. package/lib/bench_encode.js +24 -59
  14. package/lib/bench_encode.js.map +1 -1
  15. package/lib/benchmark.d.ts +1 -0
  16. package/lib/benchmark.js +218 -0
  17. package/lib/benchmark.js.map +1 -0
  18. package/lib/codegen/api.js +10 -41
  19. package/lib/codegen/api.js.map +1 -1
  20. package/lib/codegen/argv.js +1 -3
  21. package/lib/codegen/argv.js.map +1 -1
  22. package/lib/codegen/cli.js +4 -9
  23. package/lib/codegen/cli.js.map +1 -1
  24. package/lib/codegen/languages/cpp.js +5 -8
  25. package/lib/codegen/languages/cpp.js.map +1 -1
  26. package/lib/codegen/languages/csharp.js +5 -8
  27. package/lib/codegen/languages/csharp.js.map +1 -1
  28. package/lib/codegen/languages/haxe.js +3 -6
  29. package/lib/codegen/languages/haxe.js.map +1 -1
  30. package/lib/codegen/languages/java.js +3 -6
  31. package/lib/codegen/languages/java.js.map +1 -1
  32. package/lib/codegen/languages/js.js +4 -7
  33. package/lib/codegen/languages/js.js.map +1 -1
  34. package/lib/codegen/languages/lua.js +4 -7
  35. package/lib/codegen/languages/lua.js.map +1 -1
  36. package/lib/codegen/languages/ts.js +5 -8
  37. package/lib/codegen/languages/ts.js.map +1 -1
  38. package/lib/codegen/parser.js +22 -59
  39. package/lib/codegen/parser.js.map +1 -1
  40. package/lib/codegen/types.js +12 -51
  41. package/lib/codegen/types.js.map +1 -1
  42. package/lib/decoder/DecodeOperation.js +44 -51
  43. package/lib/decoder/DecodeOperation.js.map +1 -1
  44. package/lib/decoder/Decoder.js +24 -28
  45. package/lib/decoder/Decoder.js.map +1 -1
  46. package/lib/decoder/ReferenceTracker.js +10 -14
  47. package/lib/decoder/ReferenceTracker.js.map +1 -1
  48. package/lib/decoder/strategy/Callbacks.js +39 -43
  49. package/lib/decoder/strategy/Callbacks.js.map +1 -1
  50. package/lib/decoder/strategy/RawChanges.js +1 -4
  51. package/lib/decoder/strategy/RawChanges.js.map +1 -1
  52. package/lib/decoder/strategy/getDecoderStateCallbacks.js +24 -27
  53. package/lib/decoder/strategy/getDecoderStateCallbacks.js.map +1 -1
  54. package/lib/encoder/ChangeTree.js +36 -44
  55. package/lib/encoder/ChangeTree.js.map +1 -1
  56. package/lib/encoder/EncodeOperation.js +25 -32
  57. package/lib/encoder/EncodeOperation.js.map +1 -1
  58. package/lib/encoder/Encoder.d.ts +5 -5
  59. package/lib/encoder/Encoder.js +25 -29
  60. package/lib/encoder/Encoder.js.map +1 -1
  61. package/lib/encoder/Root.js +17 -21
  62. package/lib/encoder/Root.js.map +1 -1
  63. package/lib/encoder/StateView.js +40 -45
  64. package/lib/encoder/StateView.js.map +1 -1
  65. package/lib/encoding/assert.js +3 -9
  66. package/lib/encoding/assert.js.map +1 -1
  67. package/lib/encoding/decode.js +2 -6
  68. package/lib/encoding/decode.js.map +1 -1
  69. package/lib/encoding/encode.js +1 -4
  70. package/lib/encoding/encode.js.map +1 -1
  71. package/lib/encoding/spec.js +4 -7
  72. package/lib/encoding/spec.js.map +1 -1
  73. package/lib/index.d.ts +2 -2
  74. package/lib/index.js +33 -75
  75. package/lib/index.js.map +1 -1
  76. package/lib/src/Metadata.d.ts +49 -0
  77. package/lib/src/Metadata.js +256 -0
  78. package/lib/src/Metadata.js.map +1 -0
  79. package/lib/src/Reflection.d.ts +71 -0
  80. package/lib/src/Reflection.js +179 -0
  81. package/lib/src/Reflection.js.map +1 -0
  82. package/lib/src/Schema.d.ts +86 -0
  83. package/lib/src/Schema.js +352 -0
  84. package/lib/src/Schema.js.map +1 -0
  85. package/lib/src/annotations.d.ts +109 -0
  86. package/lib/src/annotations.js +473 -0
  87. package/lib/src/annotations.js.map +1 -0
  88. package/lib/src/bench_encode.d.ts +1 -0
  89. package/lib/src/bench_encode.js +91 -0
  90. package/lib/src/bench_encode.js.map +1 -0
  91. package/lib/src/codegen/api.d.ts +7 -0
  92. package/lib/src/codegen/api.js +56 -0
  93. package/lib/src/codegen/api.js.map +1 -0
  94. package/lib/src/codegen/argv.d.ts +6 -0
  95. package/lib/src/codegen/argv.js +39 -0
  96. package/lib/src/codegen/argv.js.map +1 -0
  97. package/lib/src/codegen/cli.d.ts +1 -0
  98. package/lib/src/codegen/cli.js +58 -0
  99. package/lib/src/codegen/cli.js.map +1 -0
  100. package/lib/src/codegen/languages/cpp.d.ts +3 -0
  101. package/lib/src/codegen/languages/cpp.js +258 -0
  102. package/lib/src/codegen/languages/cpp.js.map +1 -0
  103. package/lib/src/codegen/languages/csharp.d.ts +4 -0
  104. package/lib/src/codegen/languages/csharp.js +154 -0
  105. package/lib/src/codegen/languages/csharp.js.map +1 -0
  106. package/lib/src/codegen/languages/haxe.d.ts +3 -0
  107. package/lib/src/codegen/languages/haxe.js +100 -0
  108. package/lib/src/codegen/languages/haxe.js.map +1 -0
  109. package/lib/src/codegen/languages/java.d.ts +6 -0
  110. package/lib/src/codegen/languages/java.js +100 -0
  111. package/lib/src/codegen/languages/java.js.map +1 -0
  112. package/lib/src/codegen/languages/js.d.ts +3 -0
  113. package/lib/src/codegen/languages/js.js +101 -0
  114. package/lib/src/codegen/languages/js.js.map +1 -0
  115. package/lib/src/codegen/languages/lua.d.ts +3 -0
  116. package/lib/src/codegen/languages/lua.js +103 -0
  117. package/lib/src/codegen/languages/lua.js.map +1 -0
  118. package/lib/src/codegen/languages/ts.d.ts +3 -0
  119. package/lib/src/codegen/languages/ts.js +116 -0
  120. package/lib/src/codegen/languages/ts.js.map +1 -0
  121. package/lib/src/codegen/parser.d.ts +13 -0
  122. package/lib/src/codegen/parser.js +327 -0
  123. package/lib/src/codegen/parser.js.map +1 -0
  124. package/lib/src/codegen/types.d.ts +52 -0
  125. package/lib/src/codegen/types.js +142 -0
  126. package/lib/src/codegen/types.js.map +1 -0
  127. package/lib/src/decoder/DecodeOperation.d.ts +23 -0
  128. package/lib/src/decoder/DecodeOperation.js +248 -0
  129. package/lib/src/decoder/DecodeOperation.js.map +1 -0
  130. package/lib/src/decoder/Decoder.d.ts +21 -0
  131. package/lib/src/decoder/Decoder.js +114 -0
  132. package/lib/src/decoder/Decoder.js.map +1 -0
  133. package/lib/src/decoder/ReferenceTracker.d.ts +25 -0
  134. package/lib/src/decoder/ReferenceTracker.js +135 -0
  135. package/lib/src/decoder/ReferenceTracker.js.map +1 -0
  136. package/lib/src/decoder/strategy/Callbacks.d.ts +154 -0
  137. package/lib/src/decoder/strategy/Callbacks.js +336 -0
  138. package/lib/src/decoder/strategy/Callbacks.js.map +1 -0
  139. package/lib/src/decoder/strategy/RawChanges.d.ts +3 -0
  140. package/lib/src/decoder/strategy/RawChanges.js +4 -0
  141. package/lib/src/decoder/strategy/RawChanges.js.map +1 -0
  142. package/lib/src/decoder/strategy/getDecoderStateCallbacks.d.ts +76 -0
  143. package/lib/src/decoder/strategy/getDecoderStateCallbacks.js +274 -0
  144. package/lib/src/decoder/strategy/getDecoderStateCallbacks.js.map +1 -0
  145. package/lib/src/encoder/ChangeTree.d.ts +135 -0
  146. package/lib/src/encoder/ChangeTree.js +534 -0
  147. package/lib/src/encoder/ChangeTree.js.map +1 -0
  148. package/lib/src/encoder/EncodeOperation.d.ts +22 -0
  149. package/lib/src/encoder/EncodeOperation.js +132 -0
  150. package/lib/src/encoder/EncodeOperation.js.map +1 -0
  151. package/lib/src/encoder/Encoder.d.ts +22 -0
  152. package/lib/src/encoder/Encoder.js +204 -0
  153. package/lib/src/encoder/Encoder.js.map +1 -0
  154. package/lib/src/encoder/Root.d.ts +28 -0
  155. package/lib/src/encoder/Root.js +229 -0
  156. package/lib/src/encoder/Root.js.map +1 -0
  157. package/lib/src/encoder/StateView.d.ts +34 -0
  158. package/lib/src/encoder/StateView.js +279 -0
  159. package/lib/src/encoder/StateView.js.map +1 -0
  160. package/lib/src/encoding/assert.d.ts +10 -0
  161. package/lib/src/encoding/assert.js +49 -0
  162. package/lib/src/encoding/assert.js.map +1 -0
  163. package/lib/src/encoding/decode.d.ts +67 -0
  164. package/lib/src/encoding/decode.js +217 -0
  165. package/lib/src/encoding/decode.js.map +1 -0
  166. package/lib/src/encoding/encode.d.ts +40 -0
  167. package/lib/src/encoding/encode.js +279 -0
  168. package/lib/src/encoding/encode.js.map +1 -0
  169. package/lib/src/encoding/spec.d.ts +24 -0
  170. package/lib/src/encoding/spec.js +26 -0
  171. package/lib/src/encoding/spec.js.map +1 -0
  172. package/lib/src/index.d.ts +32 -0
  173. package/lib/src/index.js +39 -0
  174. package/lib/src/index.js.map +1 -0
  175. package/lib/src/symbol.shim.d.ts +6 -0
  176. package/lib/src/symbol.shim.js +3 -0
  177. package/lib/src/symbol.shim.js.map +1 -0
  178. package/lib/src/types/HelperTypes.d.ts +77 -0
  179. package/lib/src/types/HelperTypes.js +2 -0
  180. package/lib/src/types/HelperTypes.js.map +1 -0
  181. package/lib/src/types/TypeContext.d.ts +31 -0
  182. package/lib/src/types/TypeContext.js +143 -0
  183. package/lib/src/types/TypeContext.js.map +1 -0
  184. package/lib/src/types/custom/ArraySchema.d.ts +270 -0
  185. package/lib/src/types/custom/ArraySchema.js +733 -0
  186. package/lib/src/types/custom/ArraySchema.js.map +1 -0
  187. package/lib/src/types/custom/CollectionSchema.d.ts +51 -0
  188. package/lib/src/types/custom/CollectionSchema.js +170 -0
  189. package/lib/src/types/custom/CollectionSchema.js.map +1 -0
  190. package/lib/src/types/custom/MapSchema.d.ts +51 -0
  191. package/lib/src/types/custom/MapSchema.js +222 -0
  192. package/lib/src/types/custom/MapSchema.js.map +1 -0
  193. package/lib/src/types/custom/SetSchema.d.ts +48 -0
  194. package/lib/src/types/custom/SetSchema.js +178 -0
  195. package/lib/src/types/custom/SetSchema.js.map +1 -0
  196. package/lib/src/types/registry.d.ts +16 -0
  197. package/lib/src/types/registry.js +30 -0
  198. package/lib/src/types/registry.js.map +1 -0
  199. package/lib/src/types/symbols.d.ts +33 -0
  200. package/lib/src/types/symbols.js +34 -0
  201. package/lib/src/types/symbols.js.map +1 -0
  202. package/lib/src/types/utils.d.ts +1 -0
  203. package/lib/src/types/utils.js +13 -0
  204. package/lib/src/types/utils.js.map +1 -0
  205. package/lib/src/utils.d.ts +13 -0
  206. package/lib/src/utils.js +49 -0
  207. package/lib/src/utils.js.map +1 -0
  208. package/lib/src/v3_bench.d.ts +1 -0
  209. package/lib/src/v3_bench.js +128 -0
  210. package/lib/src/v3_bench.js.map +1 -0
  211. package/lib/symbol.shim.js +1 -2
  212. package/lib/symbol.shim.js.map +1 -1
  213. package/lib/types/HelperTypes.js +1 -2
  214. package/lib/types/TypeContext.js +8 -12
  215. package/lib/types/TypeContext.js.map +1 -1
  216. package/lib/types/custom/ArraySchema.js +63 -67
  217. package/lib/types/custom/ArraySchema.js.map +1 -1
  218. package/lib/types/custom/CollectionSchema.js +27 -31
  219. package/lib/types/custom/CollectionSchema.js.map +1 -1
  220. package/lib/types/custom/MapSchema.js +37 -41
  221. package/lib/types/custom/MapSchema.js.map +1 -1
  222. package/lib/types/custom/SetSchema.js +28 -32
  223. package/lib/types/custom/SetSchema.js.map +1 -1
  224. package/lib/types/registry.js +13 -20
  225. package/lib/types/registry.js.map +1 -1
  226. package/lib/types/symbols.js +16 -19
  227. package/lib/types/symbols.js.map +1 -1
  228. package/lib/types/utils.js +1 -4
  229. package/lib/types/utils.js.map +1 -1
  230. package/lib/utils.js +9 -14
  231. package/lib/utils.js.map +1 -1
  232. package/lib/v3_bench.js +17 -19
  233. package/lib/v3_bench.js.map +1 -1
  234. package/package.json +9 -7
  235. package/src/codegen/api.ts +7 -0
  236. package/src/codegen/parser.ts +2 -2
  237. package/src/codegen/types.ts +5 -0
  238. package/src/encoder/Encoder.ts +24 -7
  239. package/src/index.ts +2 -2
  240. package/build/cjs/index.js.map +0 -1
  241. package/src/bench_encode.ts +0 -64
@@ -0,0 +1,229 @@
1
+ import { OPERATION } from "../encoding/spec";
2
+ import { setOperationAtIndex, createChangeTreeList } from "./ChangeTree";
3
+ import { $changes, $refId } from "../types/symbols";
4
+ export class Root {
5
+ constructor(types) {
6
+ this.types = types;
7
+ this.nextUniqueId = 0;
8
+ this.refCount = {};
9
+ this.changeTrees = {};
10
+ // all changes
11
+ this.allChanges = createChangeTreeList();
12
+ this.allFilteredChanges = createChangeTreeList(); // TODO: do not initialize it if filters are not used
13
+ // pending changes to be encoded
14
+ this.changes = createChangeTreeList();
15
+ this.filteredChanges = createChangeTreeList(); // TODO: do not initialize it if filters are not used
16
+ }
17
+ getNextUniqueId() {
18
+ return this.nextUniqueId++;
19
+ }
20
+ add(changeTree) {
21
+ const ref = changeTree.ref;
22
+ // Assign unique `refId` to ref if it doesn't have one yet.
23
+ if (ref[$refId] === undefined) {
24
+ ref[$refId] = this.getNextUniqueId();
25
+ }
26
+ const refId = ref[$refId];
27
+ const isNewChangeTree = (this.changeTrees[refId] === undefined);
28
+ if (isNewChangeTree) {
29
+ this.changeTrees[refId] = changeTree;
30
+ }
31
+ const previousRefCount = this.refCount[refId];
32
+ if (previousRefCount === 0) {
33
+ //
34
+ // When a ChangeTree is re-added, it means that it was previously removed.
35
+ // We need to re-add all changes to the `changes` map.
36
+ //
37
+ const ops = changeTree.allChanges.operations;
38
+ let len = ops.length;
39
+ while (len--) {
40
+ changeTree.indexedOperations[ops[len]] = OPERATION.ADD;
41
+ setOperationAtIndex(changeTree.changes, len);
42
+ }
43
+ }
44
+ this.refCount[refId] = (previousRefCount || 0) + 1;
45
+ // console.log("ADD", { refId, ref: ref.constructor.name, refCount: this.refCount[refId], isNewChangeTree });
46
+ return isNewChangeTree;
47
+ }
48
+ remove(changeTree) {
49
+ const refId = changeTree.ref[$refId];
50
+ const refCount = (this.refCount[refId]) - 1;
51
+ // console.log("REMOVE", { refId, ref: changeTree.ref.constructor.name, refCount, needRemove: refCount <= 0 });
52
+ if (refCount <= 0) {
53
+ //
54
+ // Only remove "root" reference if it's the last reference
55
+ //
56
+ changeTree.root = undefined;
57
+ delete this.changeTrees[refId];
58
+ this.removeChangeFromChangeSet("allChanges", changeTree);
59
+ this.removeChangeFromChangeSet("changes", changeTree);
60
+ if (changeTree.filteredChanges) {
61
+ this.removeChangeFromChangeSet("allFilteredChanges", changeTree);
62
+ this.removeChangeFromChangeSet("filteredChanges", changeTree);
63
+ }
64
+ this.refCount[refId] = 0;
65
+ changeTree.forEachChild((child, _) => {
66
+ if (child.removeParent(changeTree.ref)) {
67
+ if ((child.parentChain === undefined || // no parent, remove it
68
+ (child.parentChain && this.refCount[child.ref[$refId]] > 0) // parent is still in use, but has more than one reference, remove it
69
+ )) {
70
+ this.remove(child);
71
+ }
72
+ else if (child.parentChain) {
73
+ // re-assigning a child of the same root, move it next to parent
74
+ this.moveNextToParent(child);
75
+ }
76
+ }
77
+ });
78
+ }
79
+ else {
80
+ this.refCount[refId] = refCount;
81
+ //
82
+ // When losing a reference to an instance, it is best to move the
83
+ // ChangeTree next to its parent in the encoding queue.
84
+ //
85
+ // This way, at decoding time, the instance that contains the
86
+ // ChangeTree will be available before the ChangeTree itself. If the
87
+ // containing instance is not available, the Decoder will throw
88
+ // "refId not found" error.
89
+ //
90
+ this.recursivelyMoveNextToParent(changeTree);
91
+ }
92
+ return refCount;
93
+ }
94
+ recursivelyMoveNextToParent(changeTree) {
95
+ this.moveNextToParent(changeTree);
96
+ changeTree.forEachChild((child, _) => this.recursivelyMoveNextToParent(child));
97
+ }
98
+ moveNextToParent(changeTree) {
99
+ if (changeTree.filteredChanges) {
100
+ this.moveNextToParentInChangeTreeList("filteredChanges", changeTree);
101
+ this.moveNextToParentInChangeTreeList("allFilteredChanges", changeTree);
102
+ }
103
+ else {
104
+ this.moveNextToParentInChangeTreeList("changes", changeTree);
105
+ this.moveNextToParentInChangeTreeList("allChanges", changeTree);
106
+ }
107
+ }
108
+ moveNextToParentInChangeTreeList(changeSetName, changeTree) {
109
+ const changeSet = this[changeSetName];
110
+ const node = changeTree[changeSetName].queueRootNode;
111
+ if (!node)
112
+ return;
113
+ // Find the parent in the linked list
114
+ const parent = changeTree.parent;
115
+ if (!parent || !parent[$changes])
116
+ return;
117
+ const parentNode = parent[$changes][changeSetName]?.queueRootNode;
118
+ if (!parentNode || parentNode === node)
119
+ return;
120
+ // Use cached positions - no iteration needed!
121
+ const parentPosition = parentNode.position;
122
+ const childPosition = node.position;
123
+ // If child is already after parent, no need to move
124
+ if (childPosition > parentPosition)
125
+ return;
126
+ // Child is before parent, so we need to move it after parent
127
+ // This maintains decoding order (parent before child)
128
+ // Remove node from current position
129
+ if (node.prev) {
130
+ node.prev.next = node.next;
131
+ }
132
+ else {
133
+ changeSet.next = node.next;
134
+ }
135
+ if (node.next) {
136
+ node.next.prev = node.prev;
137
+ }
138
+ else {
139
+ changeSet.tail = node.prev;
140
+ }
141
+ // Insert node right after parent
142
+ node.prev = parentNode;
143
+ node.next = parentNode.next;
144
+ if (parentNode.next) {
145
+ parentNode.next.prev = node;
146
+ }
147
+ else {
148
+ changeSet.tail = node;
149
+ }
150
+ parentNode.next = node;
151
+ // Update positions after the move
152
+ this.updatePositionsAfterMove(changeSet, node, parentPosition + 1);
153
+ }
154
+ enqueueChangeTree(changeTree, changeSet, queueRootNode = changeTree[changeSet].queueRootNode) {
155
+ // skip
156
+ if (queueRootNode) {
157
+ return;
158
+ }
159
+ // Add to linked list if not already present
160
+ changeTree[changeSet].queueRootNode = this.addToChangeTreeList(this[changeSet], changeTree);
161
+ }
162
+ addToChangeTreeList(list, changeTree) {
163
+ const node = {
164
+ changeTree,
165
+ next: undefined,
166
+ prev: undefined,
167
+ position: list.tail ? list.tail.position + 1 : 0
168
+ };
169
+ if (!list.next) {
170
+ list.next = node;
171
+ list.tail = node;
172
+ }
173
+ else {
174
+ node.prev = list.tail;
175
+ list.tail.next = node;
176
+ list.tail = node;
177
+ }
178
+ return node;
179
+ }
180
+ updatePositionsAfterRemoval(list, removedPosition) {
181
+ // Update positions for all nodes after the removed position
182
+ let current = list.next;
183
+ let position = 0;
184
+ while (current) {
185
+ if (position >= removedPosition) {
186
+ current.position = position;
187
+ }
188
+ current = current.next;
189
+ position++;
190
+ }
191
+ }
192
+ updatePositionsAfterMove(list, node, newPosition) {
193
+ // Recalculate all positions - this is more reliable than trying to be clever
194
+ let current = list.next;
195
+ let position = 0;
196
+ while (current) {
197
+ current.position = position;
198
+ current = current.next;
199
+ position++;
200
+ }
201
+ }
202
+ removeChangeFromChangeSet(changeSetName, changeTree) {
203
+ const changeSet = this[changeSetName];
204
+ const node = changeTree[changeSetName].queueRootNode;
205
+ if (node && node.changeTree === changeTree) {
206
+ const removedPosition = node.position;
207
+ // Remove the node from the linked list
208
+ if (node.prev) {
209
+ node.prev.next = node.next;
210
+ }
211
+ else {
212
+ changeSet.next = node.next;
213
+ }
214
+ if (node.next) {
215
+ node.next.prev = node.prev;
216
+ }
217
+ else {
218
+ changeSet.tail = node.prev;
219
+ }
220
+ // Update positions for nodes that came after the removed node
221
+ this.updatePositionsAfterRemoval(changeSet, removedPosition);
222
+ // Clear ChangeTree reference
223
+ changeTree[changeSetName].queueRootNode = undefined;
224
+ return true;
225
+ }
226
+ return false;
227
+ }
228
+ }
229
+ //# sourceMappingURL=Root.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Root.js","sourceRoot":"","sources":["../../../src/encoder/Root.ts"],"names":[],"mappings":"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","sourcesContent":["import { OPERATION } from \"../encoding/spec\";\nimport { TypeContext } from \"../types/TypeContext\";\nimport { ChangeTree, setOperationAtIndex, ChangeTreeList, createChangeTreeList, ChangeSetName, type ChangeTreeNode } from \"./ChangeTree\";\nimport { $changes, $refId } from \"../types/symbols\";\n\nexport class Root {\n protected nextUniqueId: number = 0;\n\n refCount: {[id: number]: number} = {};\n changeTrees: {[refId: number]: ChangeTree} = {};\n\n // all changes\n allChanges: ChangeTreeList = createChangeTreeList();\n allFilteredChanges: ChangeTreeList = createChangeTreeList();// TODO: do not initialize it if filters are not used\n\n // pending changes to be encoded\n changes: ChangeTreeList = createChangeTreeList();\n filteredChanges: ChangeTreeList = createChangeTreeList();// TODO: do not initialize it if filters are not used\n\n constructor(public types: TypeContext) { }\n\n getNextUniqueId() {\n return this.nextUniqueId++;\n }\n\n add(changeTree: ChangeTree) {\n const ref = changeTree.ref;\n\n // Assign unique `refId` to ref if it doesn't have one yet.\n if (ref[$refId] === undefined) {\n ref[$refId] = this.getNextUniqueId();\n }\n\n const refId = ref[$refId];\n\n const isNewChangeTree = (this.changeTrees[refId] === undefined);\n if (isNewChangeTree) { this.changeTrees[refId] = changeTree; }\n\n const previousRefCount = this.refCount[refId];\n if (previousRefCount === 0) {\n //\n // When a ChangeTree is re-added, it means that it was previously removed.\n // We need to re-add all changes to the `changes` map.\n //\n const ops = changeTree.allChanges.operations;\n let len = ops.length;\n while (len--) {\n changeTree.indexedOperations[ops[len]] = OPERATION.ADD;\n setOperationAtIndex(changeTree.changes, len);\n }\n }\n\n this.refCount[refId] = (previousRefCount || 0) + 1;\n\n // console.log(\"ADD\", { refId, ref: ref.constructor.name, refCount: this.refCount[refId], isNewChangeTree });\n\n return isNewChangeTree;\n }\n\n remove(changeTree: ChangeTree) {\n const refId = changeTree.ref[$refId];\n const refCount = (this.refCount[refId]) - 1;\n\n // console.log(\"REMOVE\", { refId, ref: changeTree.ref.constructor.name, refCount, needRemove: refCount <= 0 });\n\n if (refCount <= 0) {\n //\n // Only remove \"root\" reference if it's the last reference\n //\n changeTree.root = undefined;\n delete this.changeTrees[refId];\n\n this.removeChangeFromChangeSet(\"allChanges\", changeTree);\n this.removeChangeFromChangeSet(\"changes\", changeTree);\n\n if (changeTree.filteredChanges) {\n this.removeChangeFromChangeSet(\"allFilteredChanges\", changeTree);\n this.removeChangeFromChangeSet(\"filteredChanges\", changeTree);\n }\n\n this.refCount[refId] = 0;\n\n changeTree.forEachChild((child, _) => {\n if (child.removeParent(changeTree.ref)) {\n if ((\n child.parentChain === undefined || // no parent, remove it\n (child.parentChain && this.refCount[child.ref[$refId]] > 0) // parent is still in use, but has more than one reference, remove it\n )) {\n this.remove(child);\n\n } else if (child.parentChain) {\n // re-assigning a child of the same root, move it next to parent\n this.moveNextToParent(child);\n }\n }\n });\n\n } else {\n this.refCount[refId] = refCount;\n\n //\n // When losing a reference to an instance, it is best to move the\n // ChangeTree next to its parent in the encoding queue.\n //\n // This way, at decoding time, the instance that contains the\n // ChangeTree will be available before the ChangeTree itself. If the\n // containing instance is not available, the Decoder will throw\n // \"refId not found\" error.\n //\n this.recursivelyMoveNextToParent(changeTree);\n }\n\n return refCount;\n }\n\n recursivelyMoveNextToParent(changeTree: ChangeTree) {\n this.moveNextToParent(changeTree);\n changeTree.forEachChild((child, _) => this.recursivelyMoveNextToParent(child));\n }\n\n moveNextToParent(changeTree: ChangeTree) {\n if (changeTree.filteredChanges) {\n this.moveNextToParentInChangeTreeList(\"filteredChanges\", changeTree);\n this.moveNextToParentInChangeTreeList(\"allFilteredChanges\", changeTree);\n } else {\n this.moveNextToParentInChangeTreeList(\"changes\", changeTree);\n this.moveNextToParentInChangeTreeList(\"allChanges\", changeTree);\n }\n }\n\n moveNextToParentInChangeTreeList(changeSetName: ChangeSetName, changeTree: ChangeTree): void {\n const changeSet = this[changeSetName];\n const node = changeTree[changeSetName].queueRootNode;\n if (!node) return;\n\n // Find the parent in the linked list\n const parent = changeTree.parent;\n if (!parent || !parent[$changes]) return;\n\n const parentNode = parent[$changes][changeSetName]?.queueRootNode;\n if (!parentNode || parentNode === node) return;\n\n // Use cached positions - no iteration needed!\n const parentPosition = parentNode.position;\n const childPosition = node.position;\n\n // If child is already after parent, no need to move\n if (childPosition > parentPosition) return;\n\n // Child is before parent, so we need to move it after parent\n // This maintains decoding order (parent before child)\n\n // Remove node from current position\n if (node.prev) {\n node.prev.next = node.next;\n } else {\n changeSet.next = node.next;\n }\n\n if (node.next) {\n node.next.prev = node.prev;\n } else {\n changeSet.tail = node.prev;\n }\n\n // Insert node right after parent\n node.prev = parentNode;\n node.next = parentNode.next;\n\n if (parentNode.next) {\n parentNode.next.prev = node;\n } else {\n changeSet.tail = node;\n }\n\n parentNode.next = node;\n\n // Update positions after the move\n this.updatePositionsAfterMove(changeSet, node, parentPosition + 1);\n }\n\n public enqueueChangeTree(\n changeTree: ChangeTree,\n changeSet: 'changes' | 'filteredChanges' | 'allFilteredChanges' | 'allChanges',\n queueRootNode = changeTree[changeSet].queueRootNode\n ) {\n // skip\n if (queueRootNode) { return; }\n\n // Add to linked list if not already present\n changeTree[changeSet].queueRootNode = this.addToChangeTreeList(this[changeSet], changeTree);\n }\n\n protected addToChangeTreeList(list: ChangeTreeList, changeTree: ChangeTree): ChangeTreeNode {\n const node: ChangeTreeNode = {\n changeTree,\n next: undefined,\n prev: undefined,\n position: list.tail ? list.tail.position + 1 : 0\n };\n\n if (!list.next) {\n list.next = node;\n list.tail = node;\n } else {\n node.prev = list.tail;\n list.tail!.next = node;\n list.tail = node;\n }\n\n return node;\n }\n\n protected updatePositionsAfterRemoval(list: ChangeTreeList, removedPosition: number) {\n // Update positions for all nodes after the removed position\n let current = list.next;\n let position = 0;\n\n while (current) {\n if (position >= removedPosition) {\n current.position = position;\n }\n current = current.next;\n position++;\n }\n }\n\n protected updatePositionsAfterMove(list: ChangeTreeList, node: ChangeTreeNode, newPosition: number) {\n // Recalculate all positions - this is more reliable than trying to be clever\n let current = list.next;\n let position = 0;\n\n while (current) {\n current.position = position;\n current = current.next;\n position++;\n }\n }\n\n public removeChangeFromChangeSet(changeSetName: ChangeSetName, changeTree: ChangeTree) {\n const changeSet = this[changeSetName];\n const node = changeTree[changeSetName].queueRootNode;\n\n if (node && node.changeTree === changeTree) {\n const removedPosition = node.position;\n\n // Remove the node from the linked list\n if (node.prev) {\n node.prev.next = node.next;\n } else {\n changeSet.next = node.next;\n }\n\n if (node.next) {\n node.next.prev = node.prev;\n } else {\n changeSet.tail = node.prev;\n }\n\n // Update positions for nodes that came after the removed node\n this.updatePositionsAfterRemoval(changeSet, removedPosition);\n\n // Clear ChangeTree reference\n changeTree[changeSetName].queueRootNode = undefined;\n return true;\n }\n\n return false;\n }\n}\n"]}
@@ -0,0 +1,34 @@
1
+ import { ChangeTree, IndexedOperations, Ref } from "./ChangeTree";
2
+ export declare function createView(iterable?: boolean): StateView;
3
+ export declare class StateView {
4
+ iterable: boolean;
5
+ /**
6
+ * Iterable list of items that are visible to this view
7
+ * (Available only if constructed with `iterable: true`)
8
+ */
9
+ items: Ref[];
10
+ /**
11
+ * List of ChangeTree's that are visible to this view
12
+ */
13
+ visible: WeakSet<ChangeTree>;
14
+ /**
15
+ * List of ChangeTree's that are invisible to this view
16
+ */
17
+ invisible: WeakSet<ChangeTree>;
18
+ tags?: WeakMap<ChangeTree, Set<number>>;
19
+ /**
20
+ * Manual "ADD" operations for changes per ChangeTree, specific to this view.
21
+ * (This is used to force encoding a property, even if it was not changed)
22
+ */
23
+ changes: Map<number, IndexedOperations>;
24
+ constructor(iterable?: boolean);
25
+ add(obj: Ref, tag?: number, checkIncludeParent?: boolean): boolean;
26
+ protected addParentOf(childChangeTree: ChangeTree, tag: number): void;
27
+ remove(obj: Ref, tag?: number): this;
28
+ remove(obj: Ref, tag?: number, _isClear?: boolean): this;
29
+ has(obj: Ref): boolean;
30
+ hasTag(ob: Ref, tag?: number): boolean;
31
+ clear(): void;
32
+ isChangeTreeVisible(changeTree: ChangeTree): boolean;
33
+ protected _recursiveDeleteVisibleChangeTree(changeTree: ChangeTree): void;
34
+ }
@@ -0,0 +1,279 @@
1
+ import { $changes, $fieldIndexesByViewTag, $refId, $viewFieldIndexes } from "../types/symbols";
2
+ import { DEFAULT_VIEW_TAG } from "../annotations";
3
+ import { OPERATION } from "../encoding/spec";
4
+ import { Metadata } from "../Metadata";
5
+ import { spliceOne } from "../types/utils";
6
+ export function createView(iterable = false) {
7
+ return new StateView(iterable);
8
+ }
9
+ export class StateView {
10
+ constructor(iterable = false) {
11
+ this.iterable = iterable;
12
+ /**
13
+ * List of ChangeTree's that are visible to this view
14
+ */
15
+ this.visible = new WeakSet();
16
+ /**
17
+ * List of ChangeTree's that are invisible to this view
18
+ */
19
+ this.invisible = new WeakSet();
20
+ /**
21
+ * Manual "ADD" operations for changes per ChangeTree, specific to this view.
22
+ * (This is used to force encoding a property, even if it was not changed)
23
+ */
24
+ this.changes = new Map();
25
+ if (iterable) {
26
+ this.items = [];
27
+ }
28
+ }
29
+ // TODO: allow to set multiple tags at once
30
+ add(obj, tag = DEFAULT_VIEW_TAG, checkIncludeParent = true) {
31
+ const changeTree = obj?.[$changes];
32
+ const parentChangeTree = changeTree.parent;
33
+ if (!changeTree) {
34
+ console.warn("StateView#add(), invalid object:", obj);
35
+ return false;
36
+ }
37
+ else if (!parentChangeTree &&
38
+ obj[$refId] !== 0 // allow root object
39
+ ) {
40
+ /**
41
+ * TODO: can we avoid this?
42
+ *
43
+ * When the "parent" structure has the @view() tag, it is currently
44
+ * not possible to identify it has to be added to the view as well
45
+ * (this.addParentOf() is not called).
46
+ */
47
+ throw new Error(`Cannot add a detached instance to the StateView. Make sure to assign the "${changeTree.ref.constructor.name}" instance to the state before calling view.add()`);
48
+ }
49
+ // FIXME: ArraySchema/MapSchema do not have metadata
50
+ const metadata = obj.constructor[Symbol.metadata];
51
+ this.visible.add(changeTree);
52
+ // add to iterable list (only the explicitly added items)
53
+ if (this.iterable && checkIncludeParent) {
54
+ this.items.push(obj);
55
+ }
56
+ // add parent ChangeTree's
57
+ // - if it was invisible to this view
58
+ // - if it were previously filtered out
59
+ if (checkIncludeParent && parentChangeTree) {
60
+ this.addParentOf(changeTree, tag);
61
+ }
62
+ let changes = this.changes.get(obj[$refId]);
63
+ if (changes === undefined) {
64
+ changes = {};
65
+ // FIXME / OPTIMIZE: do not add if no changes are needed
66
+ this.changes.set(obj[$refId], changes);
67
+ }
68
+ let isChildAdded = false;
69
+ //
70
+ // Add children of this ChangeTree first.
71
+ // If successful, we must link the current ChangeTree to the child.
72
+ //
73
+ changeTree.forEachChild((change, index) => {
74
+ // Do not ADD children that don't have the same tag
75
+ if (metadata &&
76
+ metadata[index].tag !== undefined &&
77
+ metadata[index].tag !== tag) {
78
+ return;
79
+ }
80
+ if (this.add(change.ref, tag, false)) {
81
+ isChildAdded = true;
82
+ }
83
+ });
84
+ // set tag
85
+ if (tag !== DEFAULT_VIEW_TAG) {
86
+ if (!this.tags) {
87
+ this.tags = new WeakMap();
88
+ }
89
+ let tags;
90
+ if (!this.tags.has(changeTree)) {
91
+ tags = new Set();
92
+ this.tags.set(changeTree, tags);
93
+ }
94
+ else {
95
+ tags = this.tags.get(changeTree);
96
+ }
97
+ tags.add(tag);
98
+ // Ref: add tagged properties
99
+ metadata?.[$fieldIndexesByViewTag]?.[tag]?.forEach((index) => {
100
+ if (changeTree.getChange(index) !== OPERATION.DELETE) {
101
+ changes[index] = OPERATION.ADD;
102
+ }
103
+ });
104
+ }
105
+ else if (!changeTree.isNew || isChildAdded) {
106
+ // new structures will be added as part of .encode() call, no need to force it to .encodeView()
107
+ const changeSet = (changeTree.filteredChanges !== undefined)
108
+ ? changeTree.allFilteredChanges
109
+ : changeTree.allChanges;
110
+ const isInvisible = this.invisible.has(changeTree);
111
+ for (let i = 0, len = changeSet.operations.length; i < len; i++) {
112
+ const index = changeSet.operations[i];
113
+ if (index === undefined) {
114
+ continue;
115
+ } // skip "undefined" indexes
116
+ const op = changeTree.indexedOperations[index] ?? OPERATION.ADD;
117
+ const tagAtIndex = metadata?.[index].tag;
118
+ if (op !== OPERATION.DELETE &&
119
+ (isInvisible || // if "invisible", include all
120
+ tagAtIndex === undefined || // "all change" with no tag
121
+ tagAtIndex === tag // tagged property
122
+ )) {
123
+ changes[index] = op;
124
+ isChildAdded = true; // FIXME: assign only once
125
+ }
126
+ }
127
+ }
128
+ return isChildAdded;
129
+ }
130
+ addParentOf(childChangeTree, tag) {
131
+ const changeTree = childChangeTree.parent[$changes];
132
+ const parentIndex = childChangeTree.parentIndex;
133
+ if (!this.visible.has(changeTree)) {
134
+ // view must have all "changeTree" parent tree
135
+ this.visible.add(changeTree);
136
+ // add parent's parent
137
+ const parentChangeTree = changeTree.parent?.[$changes];
138
+ if (parentChangeTree && (parentChangeTree.filteredChanges !== undefined)) {
139
+ this.addParentOf(changeTree, tag);
140
+ }
141
+ // // parent is already available, no need to add it!
142
+ // if (!this.invisible.has(changeTree)) { return; }
143
+ }
144
+ // add parent's tag properties
145
+ if (changeTree.getChange(parentIndex) !== OPERATION.DELETE) {
146
+ let changes = this.changes.get(changeTree.ref[$refId]);
147
+ if (changes === undefined) {
148
+ changes = {};
149
+ this.changes.set(changeTree.ref[$refId], changes);
150
+ }
151
+ if (!this.tags) {
152
+ this.tags = new WeakMap();
153
+ }
154
+ let tags;
155
+ if (!this.tags.has(changeTree)) {
156
+ tags = new Set();
157
+ this.tags.set(changeTree, tags);
158
+ }
159
+ else {
160
+ tags = this.tags.get(changeTree);
161
+ }
162
+ tags.add(tag);
163
+ changes[parentIndex] = OPERATION.ADD;
164
+ }
165
+ }
166
+ remove(obj, tag = DEFAULT_VIEW_TAG, _isClear = false) {
167
+ const changeTree = obj[$changes];
168
+ if (!changeTree) {
169
+ console.warn("StateView#remove(), invalid object:", obj);
170
+ return this;
171
+ }
172
+ this.visible.delete(changeTree);
173
+ // remove from iterable list
174
+ if (this.iterable &&
175
+ !_isClear // no need to remove during clear(), as it will be cleared entirely
176
+ ) {
177
+ spliceOne(this.items, this.items.indexOf(obj));
178
+ }
179
+ const ref = changeTree.ref;
180
+ const metadata = ref.constructor[Symbol.metadata]; // ArraySchema/MapSchema do not have metadata
181
+ const refId = ref[$refId];
182
+ let changes = this.changes.get(refId);
183
+ if (changes === undefined) {
184
+ changes = {};
185
+ this.changes.set(refId, changes);
186
+ }
187
+ if (tag === DEFAULT_VIEW_TAG) {
188
+ // parent is collection (Map/Array)
189
+ const parent = changeTree.parent;
190
+ if (parent && !Metadata.isValidInstance(parent) && changeTree.isFiltered) {
191
+ const parentRefId = parent[$refId];
192
+ let changes = this.changes.get(parentRefId);
193
+ if (changes === undefined) {
194
+ changes = {};
195
+ this.changes.set(parentRefId, changes);
196
+ }
197
+ else if (changes[changeTree.parentIndex] === OPERATION.ADD) {
198
+ //
199
+ // SAME PATCH ADD + REMOVE:
200
+ // The 'changes' of deleted structure should be ignored.
201
+ //
202
+ this.changes.delete(refId);
203
+ }
204
+ // DELETE / DELETE BY REF ID
205
+ changes[changeTree.parentIndex] = OPERATION.DELETE;
206
+ // Remove child schema from visible set
207
+ this._recursiveDeleteVisibleChangeTree(changeTree);
208
+ }
209
+ else {
210
+ // delete all "tagged" properties.
211
+ metadata?.[$viewFieldIndexes]?.forEach((index) => changes[index] = OPERATION.DELETE);
212
+ }
213
+ }
214
+ else {
215
+ // delete only tagged properties
216
+ metadata?.[$fieldIndexesByViewTag][tag].forEach((index) => changes[index] = OPERATION.DELETE);
217
+ }
218
+ // remove tag
219
+ if (this.tags && this.tags.has(changeTree)) {
220
+ const tags = this.tags.get(changeTree);
221
+ if (tag === undefined) {
222
+ // delete all tags
223
+ this.tags.delete(changeTree);
224
+ }
225
+ else {
226
+ // delete specific tag
227
+ tags.delete(tag);
228
+ // if tag set is empty, delete it entirely
229
+ if (tags.size === 0) {
230
+ this.tags.delete(changeTree);
231
+ }
232
+ }
233
+ }
234
+ return this;
235
+ }
236
+ has(obj) {
237
+ return this.visible.has(obj[$changes]);
238
+ }
239
+ hasTag(ob, tag = DEFAULT_VIEW_TAG) {
240
+ const tags = this.tags?.get(ob[$changes]);
241
+ return tags?.has(tag) ?? false;
242
+ }
243
+ clear() {
244
+ if (!this.iterable) {
245
+ throw new Error("StateView#clear() is only available for iterable StateView's. Use StateView(iterable: true) constructor.");
246
+ }
247
+ for (let i = 0, l = this.items.length; i < l; i++) {
248
+ this.remove(this.items[i], DEFAULT_VIEW_TAG, true);
249
+ }
250
+ // clear items array
251
+ this.items.length = 0;
252
+ }
253
+ isChangeTreeVisible(changeTree) {
254
+ let isVisible = this.visible.has(changeTree);
255
+ //
256
+ // TODO: avoid checking for parent visibility, most of the time it's not needed
257
+ // See test case: 'should not be required to manually call view.add() items to child arrays without @view() tag'
258
+ //
259
+ if (!isVisible && changeTree.isVisibilitySharedWithParent) {
260
+ // console.log("CHECK AGAINST PARENT...", {
261
+ // ref: changeTree.ref.constructor.name,
262
+ // refId: changeTree.ref[$refId],
263
+ // parent: changeTree.parent.constructor.name,
264
+ // });
265
+ if (this.visible.has(changeTree.parent[$changes])) {
266
+ this.visible.add(changeTree);
267
+ isVisible = true;
268
+ }
269
+ }
270
+ return isVisible;
271
+ }
272
+ _recursiveDeleteVisibleChangeTree(changeTree) {
273
+ changeTree.forEachChild((childChangeTree) => {
274
+ this.visible.delete(childChangeTree);
275
+ this._recursiveDeleteVisibleChangeTree(childChangeTree);
276
+ });
277
+ }
278
+ }
279
+ //# sourceMappingURL=StateView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StateView.js","sourceRoot":"","sources":["../../../src/encoder/StateView.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeTree, IndexedOperations, Ref } from \"./ChangeTree\";\nimport { $changes, $fieldIndexesByViewTag, $refId, $viewFieldIndexes } from \"../types/symbols\";\nimport { DEFAULT_VIEW_TAG } from \"../annotations\";\nimport { OPERATION } from \"../encoding/spec\";\nimport { Metadata } from \"../Metadata\";\nimport { spliceOne } from \"../types/utils\";\nimport type { Schema } from \"../Schema\";\n\nexport function createView(iterable: boolean = false) {\n return new StateView(iterable);\n}\n\nexport class StateView {\n /**\n * Iterable list of items that are visible to this view\n * (Available only if constructed with `iterable: true`)\n */\n items: Ref[];\n\n /**\n * List of ChangeTree's that are visible to this view\n */\n visible: WeakSet<ChangeTree> = new WeakSet<ChangeTree>();\n\n /**\n * List of ChangeTree's that are invisible to this view\n */\n invisible: WeakSet<ChangeTree> = new WeakSet<ChangeTree>();\n\n tags?: WeakMap<ChangeTree, Set<number>>; // TODO: use bit manipulation instead of Set<number> ()\n\n /**\n * Manual \"ADD\" operations for changes per ChangeTree, specific to this view.\n * (This is used to force encoding a property, even if it was not changed)\n */\n changes = new Map<number, IndexedOperations>();\n\n constructor(public iterable: boolean = false) {\n if (iterable) {\n this.items = [];\n }\n }\n\n // TODO: allow to set multiple tags at once\n add(obj: Ref, tag: number = DEFAULT_VIEW_TAG, checkIncludeParent: boolean = true) {\n const changeTree: ChangeTree = obj?.[$changes];\n const parentChangeTree = changeTree.parent;\n\n if (!changeTree) {\n console.warn(\"StateView#add(), invalid object:\", obj);\n return false;\n\n } else if (\n !parentChangeTree &&\n obj[$refId] !== 0 // allow root object\n ) {\n /**\n * TODO: can we avoid this?\n *\n * When the \"parent\" structure has the @view() tag, it is currently\n * not possible to identify it has to be added to the view as well\n * (this.addParentOf() is not called).\n */\n throw new Error(\n `Cannot add a detached instance to the StateView. Make sure to assign the \"${changeTree.ref.constructor.name}\" instance to the state before calling view.add()`\n );\n }\n\n // FIXME: ArraySchema/MapSchema do not have metadata\n const metadata: Metadata = (obj.constructor as typeof Schema)[Symbol.metadata];\n this.visible.add(changeTree);\n\n // add to iterable list (only the explicitly added items)\n if (this.iterable && checkIncludeParent) {\n this.items.push(obj);\n }\n\n // add parent ChangeTree's\n // - if it was invisible to this view\n // - if it were previously filtered out\n if (checkIncludeParent && parentChangeTree) {\n this.addParentOf(changeTree, tag);\n }\n\n let changes = this.changes.get(obj[$refId]);\n if (changes === undefined) {\n changes = {};\n // FIXME / OPTIMIZE: do not add if no changes are needed\n this.changes.set(obj[$refId], changes);\n }\n\n let isChildAdded = false;\n\n //\n // Add children of this ChangeTree first.\n // If successful, we must link the current ChangeTree to the child.\n //\n changeTree.forEachChild((change, index) => {\n // Do not ADD children that don't have the same tag\n if (\n metadata &&\n metadata[index].tag !== undefined &&\n metadata[index].tag !== tag\n ) {\n return;\n }\n\n if (this.add(change.ref, tag, false)) {\n isChildAdded = true;\n }\n });\n\n // set tag\n if (tag !== DEFAULT_VIEW_TAG) {\n if (!this.tags) {\n this.tags = new WeakMap<ChangeTree, Set<number>>();\n }\n let tags: Set<number>;\n if (!this.tags.has(changeTree)) {\n tags = new Set<number>();\n this.tags.set(changeTree, tags);\n } else {\n tags = this.tags.get(changeTree);\n }\n tags.add(tag);\n\n // Ref: add tagged properties\n metadata?.[$fieldIndexesByViewTag]?.[tag]?.forEach((index) => {\n if (changeTree.getChange(index) !== OPERATION.DELETE) {\n changes[index] = OPERATION.ADD;\n }\n });\n\n } else if (!changeTree.isNew || isChildAdded) {\n // new structures will be added as part of .encode() call, no need to force it to .encodeView()\n const changeSet = (changeTree.filteredChanges !== undefined)\n ? changeTree.allFilteredChanges\n : changeTree.allChanges;\n\n const isInvisible = this.invisible.has(changeTree);\n\n for (let i = 0, len = changeSet.operations.length; i < len; i++) {\n const index = changeSet.operations[i];\n if (index === undefined) { continue; } // skip \"undefined\" indexes\n\n const op = changeTree.indexedOperations[index] ?? OPERATION.ADD;\n const tagAtIndex = metadata?.[index].tag;\n if (\n op !== OPERATION.DELETE &&\n (\n isInvisible || // if \"invisible\", include all\n tagAtIndex === undefined || // \"all change\" with no tag\n tagAtIndex === tag // tagged property\n )\n ) {\n changes[index] = op;\n isChildAdded = true; // FIXME: assign only once\n }\n }\n }\n\n return isChildAdded;\n }\n\n protected addParentOf(childChangeTree: ChangeTree, tag: number) {\n const changeTree = childChangeTree.parent[$changes];\n const parentIndex = childChangeTree.parentIndex;\n\n if (!this.visible.has(changeTree)) {\n // view must have all \"changeTree\" parent tree\n this.visible.add(changeTree);\n\n // add parent's parent\n const parentChangeTree: ChangeTree = changeTree.parent?.[$changes];\n if (parentChangeTree && (parentChangeTree.filteredChanges !== undefined)) {\n this.addParentOf(changeTree, tag);\n }\n\n // // parent is already available, no need to add it!\n // if (!this.invisible.has(changeTree)) { return; }\n }\n\n // add parent's tag properties\n if (changeTree.getChange(parentIndex) !== OPERATION.DELETE) {\n let changes = this.changes.get(changeTree.ref[$refId]);\n if (changes === undefined) {\n changes = {};\n this.changes.set(changeTree.ref[$refId], changes);\n }\n\n if (!this.tags) {\n this.tags = new WeakMap<ChangeTree, Set<number>>();\n }\n\n let tags: Set<number>;\n if (!this.tags.has(changeTree)) {\n tags = new Set<number>();\n this.tags.set(changeTree, tags);\n } else {\n tags = this.tags.get(changeTree);\n }\n tags.add(tag);\n\n changes[parentIndex] = OPERATION.ADD;\n }\n }\n\n remove(obj: Ref, tag?: number): this; // hide _isClear parameter from public API\n remove(obj: Ref, tag?: number, _isClear?: boolean): this;\n remove(obj: Ref, tag: number = DEFAULT_VIEW_TAG, _isClear: boolean = false): this {\n const changeTree: ChangeTree = obj[$changes];\n if (!changeTree) {\n console.warn(\"StateView#remove(), invalid object:\", obj);\n return this;\n }\n\n this.visible.delete(changeTree);\n\n // remove from iterable list\n if (\n this.iterable &&\n !_isClear // no need to remove during clear(), as it will be cleared entirely\n ) {\n spliceOne(this.items, this.items.indexOf(obj));\n }\n\n const ref = changeTree.ref;\n const metadata: Metadata = ref.constructor[Symbol.metadata]; // ArraySchema/MapSchema do not have metadata\n\n const refId = ref[$refId];\n\n let changes = this.changes.get(refId);\n if (changes === undefined) {\n changes = {};\n this.changes.set(refId, changes);\n }\n\n if (tag === DEFAULT_VIEW_TAG) {\n // parent is collection (Map/Array)\n const parent = changeTree.parent;\n if (parent && !Metadata.isValidInstance(parent) && changeTree.isFiltered) {\n const parentRefId = parent[$refId];\n let changes = this.changes.get(parentRefId);\n if (changes === undefined) {\n changes = {};\n this.changes.set(parentRefId, changes);\n\n } else if (changes[changeTree.parentIndex] === OPERATION.ADD) {\n //\n // SAME PATCH ADD + REMOVE:\n // The 'changes' of deleted structure should be ignored.\n //\n this.changes.delete(refId);\n }\n\n // DELETE / DELETE BY REF ID\n changes[changeTree.parentIndex] = OPERATION.DELETE;\n\n // Remove child schema from visible set\n this._recursiveDeleteVisibleChangeTree(changeTree);\n\n } else {\n // delete all \"tagged\" properties.\n metadata?.[$viewFieldIndexes]?.forEach((index) =>\n changes[index] = OPERATION.DELETE);\n }\n\n } else {\n // delete only tagged properties\n metadata?.[$fieldIndexesByViewTag][tag].forEach((index) =>\n changes[index] = OPERATION.DELETE);\n }\n\n // remove tag\n if (this.tags && this.tags.has(changeTree)) {\n const tags = this.tags.get(changeTree);\n if (tag === undefined) {\n // delete all tags\n this.tags.delete(changeTree);\n } else {\n // delete specific tag\n tags.delete(tag);\n\n // if tag set is empty, delete it entirely\n if (tags.size === 0) {\n this.tags.delete(changeTree);\n }\n }\n }\n\n return this;\n }\n\n has(obj: Ref) {\n return this.visible.has(obj[$changes]);\n }\n\n hasTag(ob: Ref, tag: number = DEFAULT_VIEW_TAG) {\n const tags = this.tags?.get(ob[$changes]);\n return tags?.has(tag) ?? false;\n }\n\n clear() {\n if (!this.iterable) {\n throw new Error(\"StateView#clear() is only available for iterable StateView's. Use StateView(iterable: true) constructor.\");\n }\n\n for (let i = 0, l = this.items.length; i < l; i++) {\n this.remove(this.items[i], DEFAULT_VIEW_TAG, true);\n }\n\n // clear items array\n this.items.length = 0;\n }\n\n isChangeTreeVisible(changeTree: ChangeTree) {\n let isVisible = this.visible.has(changeTree);\n\n //\n // TODO: avoid checking for parent visibility, most of the time it's not needed\n // See test case: 'should not be required to manually call view.add() items to child arrays without @view() tag'\n //\n if (!isVisible && changeTree.isVisibilitySharedWithParent){\n\n // console.log(\"CHECK AGAINST PARENT...\", {\n // ref: changeTree.ref.constructor.name,\n // refId: changeTree.ref[$refId],\n // parent: changeTree.parent.constructor.name,\n // });\n\n if (this.visible.has(changeTree.parent[$changes])) {\n this.visible.add(changeTree);\n isVisible = true;\n }\n }\n\n return isVisible;\n }\n\n protected _recursiveDeleteVisibleChangeTree(changeTree: ChangeTree) {\n changeTree.forEachChild((childChangeTree) => {\n this.visible.delete(childChangeTree);\n this._recursiveDeleteVisibleChangeTree(childChangeTree);\n });\n }\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import type { Schema } from "../Schema";
2
+ import type { CollectionSchema } from "../types/custom/CollectionSchema";
3
+ import type { MapSchema } from "../types/custom/MapSchema";
4
+ import type { SetSchema } from "../types/custom/SetSchema";
5
+ import type { ArraySchema } from "../types/custom/ArraySchema";
6
+ import type { Ref } from "../encoder/ChangeTree";
7
+ export declare class EncodeSchemaError extends Error {
8
+ }
9
+ export declare function assertType(value: any, type: string, klass: Schema, field: string | number): void;
10
+ export declare function assertInstanceType(value: Ref, type: typeof Schema | typeof ArraySchema | typeof MapSchema | typeof CollectionSchema | typeof SetSchema, instance: Ref, field: string | number): void;