@colyseus/schema 4.0.1 → 4.0.3

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 (190) hide show
  1. package/{lib → build}/Metadata.d.ts +2 -2
  2. package/{lib → build}/Reflection.d.ts +13 -13
  3. package/{lib → build}/Schema.d.ts +10 -10
  4. package/{lib → build}/annotations.d.ts +10 -10
  5. package/build/codegen/languages/cpp.d.ts +3 -0
  6. package/build/codegen/languages/csharp.d.ts +4 -0
  7. package/build/codegen/languages/haxe.d.ts +3 -0
  8. package/{lib → build}/codegen/languages/java.d.ts +2 -2
  9. package/build/codegen/languages/js.d.ts +3 -0
  10. package/build/codegen/languages/lua.d.ts +3 -0
  11. package/build/codegen/languages/ts.d.ts +3 -0
  12. package/{lib → build}/codegen/parser.d.ts +1 -1
  13. package/{lib → build}/decoder/DecodeOperation.d.ts +5 -5
  14. package/{lib → build}/decoder/Decoder.d.ts +7 -7
  15. package/{lib → build}/decoder/ReferenceTracker.d.ts +1 -1
  16. package/{lib → build}/decoder/strategy/Callbacks.d.ts +11 -11
  17. package/{lib → build}/decoder/strategy/RawChanges.d.ts +2 -2
  18. package/{lib → build}/decoder/strategy/getDecoderStateCallbacks.d.ts +3 -3
  19. package/{lib → build}/encoder/ChangeTree.d.ts +11 -11
  20. package/{lib → build}/encoder/EncodeOperation.d.ts +5 -5
  21. package/{lib → build}/encoder/Encoder.d.ts +6 -6
  22. package/{lib → build}/encoder/Root.d.ts +2 -2
  23. package/{lib → build}/encoder/StateView.d.ts +1 -1
  24. package/{lib → build}/encoding/assert.d.ts +6 -6
  25. package/{lib → build}/encoding/decode.d.ts +1 -1
  26. package/{lib → build}/encoding/encode.d.ts +1 -1
  27. package/build/{cjs/index.js → index.cjs} +1 -1
  28. package/build/index.cjs.map +1 -0
  29. package/build/index.d.ts +32 -0
  30. package/build/index.mjs.map +1 -0
  31. package/{lib → build}/types/HelperTypes.d.ts +6 -6
  32. package/{lib → build}/types/TypeContext.d.ts +1 -1
  33. package/{lib → build}/types/custom/ArraySchema.d.ts +8 -8
  34. package/{lib → build}/types/custom/CollectionSchema.d.ts +7 -7
  35. package/{lib → build}/types/custom/MapSchema.d.ts +7 -7
  36. package/{lib → build}/types/custom/SetSchema.d.ts +7 -7
  37. package/{lib → build}/types/registry.d.ts +2 -2
  38. package/{lib → build}/utils.d.ts +1 -1
  39. package/package.json +15 -14
  40. package/src/Metadata.ts +5 -5
  41. package/src/Reflection.ts +7 -7
  42. package/src/Schema.ts +11 -11
  43. package/src/annotations.ts +13 -13
  44. package/src/codegen/api.ts +10 -3
  45. package/src/codegen/cli.ts +2 -2
  46. package/src/codegen/languages/cpp.ts +2 -2
  47. package/src/codegen/languages/csharp.ts +3 -3
  48. package/src/codegen/languages/haxe.ts +2 -2
  49. package/src/codegen/languages/java.ts +2 -2
  50. package/src/codegen/languages/js.ts +2 -2
  51. package/src/codegen/languages/lua.ts +2 -2
  52. package/src/codegen/languages/ts.ts +2 -2
  53. package/src/codegen/parser.ts +7 -2
  54. package/src/codegen/types.ts +5 -0
  55. package/src/decoder/DecodeOperation.ts +14 -14
  56. package/src/decoder/Decoder.ts +11 -11
  57. package/src/decoder/ReferenceTracker.ts +8 -8
  58. package/src/decoder/strategy/Callbacks.ts +12 -12
  59. package/src/decoder/strategy/RawChanges.ts +2 -2
  60. package/src/decoder/strategy/getDecoderStateCallbacks.ts +10 -10
  61. package/src/encoder/ChangeTree.ts +13 -13
  62. package/src/encoder/EncodeOperation.ts +9 -9
  63. package/src/encoder/Encoder.ts +10 -10
  64. package/src/encoder/Root.ts +4 -4
  65. package/src/encoder/StateView.ts +7 -7
  66. package/src/encoding/assert.ts +6 -6
  67. package/src/encoding/decode.ts +1 -1
  68. package/src/encoding/encode.ts +1 -1
  69. package/src/index.ts +27 -27
  70. package/src/types/HelperTypes.ts +6 -6
  71. package/src/types/TypeContext.ts +3 -3
  72. package/src/types/custom/ArraySchema.ts +11 -11
  73. package/src/types/custom/CollectionSchema.ts +9 -9
  74. package/src/types/custom/MapSchema.ts +10 -10
  75. package/src/types/custom/SetSchema.ts +9 -9
  76. package/src/types/registry.ts +3 -3
  77. package/src/utils.ts +3 -3
  78. package/src/v3_bench.ts +1 -1
  79. package/build/cjs/index.js.map +0 -1
  80. package/build/esm/index.mjs.map +0 -1
  81. package/lib/Metadata.js +0 -260
  82. package/lib/Metadata.js.map +0 -1
  83. package/lib/Reflection.js +0 -182
  84. package/lib/Reflection.js.map +0 -1
  85. package/lib/Schema.js +0 -356
  86. package/lib/Schema.js.map +0 -1
  87. package/lib/annotations.js +0 -484
  88. package/lib/annotations.js.map +0 -1
  89. package/lib/bench_encode.d.ts +0 -1
  90. package/lib/bench_encode.js +0 -126
  91. package/lib/bench_encode.js.map +0 -1
  92. package/lib/codegen/api.js +0 -87
  93. package/lib/codegen/api.js.map +0 -1
  94. package/lib/codegen/argv.js +0 -41
  95. package/lib/codegen/argv.js.map +0 -1
  96. package/lib/codegen/cli.js +0 -63
  97. package/lib/codegen/cli.js.map +0 -1
  98. package/lib/codegen/languages/cpp.d.ts +0 -3
  99. package/lib/codegen/languages/cpp.js +0 -261
  100. package/lib/codegen/languages/cpp.js.map +0 -1
  101. package/lib/codegen/languages/csharp.d.ts +0 -4
  102. package/lib/codegen/languages/csharp.js +0 -157
  103. package/lib/codegen/languages/csharp.js.map +0 -1
  104. package/lib/codegen/languages/haxe.d.ts +0 -3
  105. package/lib/codegen/languages/haxe.js +0 -103
  106. package/lib/codegen/languages/haxe.js.map +0 -1
  107. package/lib/codegen/languages/java.js +0 -103
  108. package/lib/codegen/languages/java.js.map +0 -1
  109. package/lib/codegen/languages/js.d.ts +0 -3
  110. package/lib/codegen/languages/js.js +0 -104
  111. package/lib/codegen/languages/js.js.map +0 -1
  112. package/lib/codegen/languages/lua.d.ts +0 -3
  113. package/lib/codegen/languages/lua.js +0 -106
  114. package/lib/codegen/languages/lua.js.map +0 -1
  115. package/lib/codegen/languages/ts.d.ts +0 -3
  116. package/lib/codegen/languages/ts.js +0 -119
  117. package/lib/codegen/languages/ts.js.map +0 -1
  118. package/lib/codegen/parser.js +0 -364
  119. package/lib/codegen/parser.js.map +0 -1
  120. package/lib/codegen/types.js +0 -181
  121. package/lib/codegen/types.js.map +0 -1
  122. package/lib/decoder/DecodeOperation.js +0 -255
  123. package/lib/decoder/DecodeOperation.js.map +0 -1
  124. package/lib/decoder/Decoder.js +0 -118
  125. package/lib/decoder/Decoder.js.map +0 -1
  126. package/lib/decoder/ReferenceTracker.js +0 -139
  127. package/lib/decoder/ReferenceTracker.js.map +0 -1
  128. package/lib/decoder/strategy/Callbacks.js +0 -340
  129. package/lib/decoder/strategy/Callbacks.js.map +0 -1
  130. package/lib/decoder/strategy/RawChanges.js +0 -7
  131. package/lib/decoder/strategy/RawChanges.js.map +0 -1
  132. package/lib/decoder/strategy/getDecoderStateCallbacks.js +0 -277
  133. package/lib/decoder/strategy/getDecoderStateCallbacks.js.map +0 -1
  134. package/lib/encoder/ChangeTree.js +0 -542
  135. package/lib/encoder/ChangeTree.js.map +0 -1
  136. package/lib/encoder/EncodeOperation.js +0 -139
  137. package/lib/encoder/EncodeOperation.js.map +0 -1
  138. package/lib/encoder/Encoder.js +0 -208
  139. package/lib/encoder/Encoder.js.map +0 -1
  140. package/lib/encoder/Root.js +0 -233
  141. package/lib/encoder/Root.js.map +0 -1
  142. package/lib/encoder/StateView.js +0 -284
  143. package/lib/encoder/StateView.js.map +0 -1
  144. package/lib/encoding/assert.js +0 -55
  145. package/lib/encoding/assert.js.map +0 -1
  146. package/lib/encoding/decode.js +0 -221
  147. package/lib/encoding/decode.js.map +0 -1
  148. package/lib/encoding/encode.js +0 -282
  149. package/lib/encoding/encode.js.map +0 -1
  150. package/lib/encoding/spec.js +0 -29
  151. package/lib/encoding/spec.js.map +0 -1
  152. package/lib/index.d.ts +0 -32
  153. package/lib/index.js +0 -81
  154. package/lib/index.js.map +0 -1
  155. package/lib/symbol.shim.js +0 -4
  156. package/lib/symbol.shim.js.map +0 -1
  157. package/lib/types/HelperTypes.js +0 -3
  158. package/lib/types/HelperTypes.js.map +0 -1
  159. package/lib/types/TypeContext.js +0 -147
  160. package/lib/types/TypeContext.js.map +0 -1
  161. package/lib/types/custom/ArraySchema.js +0 -737
  162. package/lib/types/custom/ArraySchema.js.map +0 -1
  163. package/lib/types/custom/CollectionSchema.js +0 -174
  164. package/lib/types/custom/CollectionSchema.js.map +0 -1
  165. package/lib/types/custom/MapSchema.js +0 -226
  166. package/lib/types/custom/MapSchema.js.map +0 -1
  167. package/lib/types/custom/SetSchema.js +0 -182
  168. package/lib/types/custom/SetSchema.js.map +0 -1
  169. package/lib/types/registry.js +0 -37
  170. package/lib/types/registry.js.map +0 -1
  171. package/lib/types/symbols.js +0 -37
  172. package/lib/types/symbols.js.map +0 -1
  173. package/lib/types/utils.js +0 -16
  174. package/lib/types/utils.js.map +0 -1
  175. package/lib/utils.js +0 -54
  176. package/lib/utils.js.map +0 -1
  177. package/lib/v3_bench.js +0 -130
  178. package/lib/v3_bench.js.map +0 -1
  179. package/src/bench_encode.ts +0 -64
  180. /package/{lib → build}/codegen/api.d.ts +0 -0
  181. /package/{lib → build}/codegen/argv.d.ts +0 -0
  182. /package/{lib → build}/codegen/cli.d.ts +0 -0
  183. /package/{lib → build}/codegen/types.d.ts +0 -0
  184. /package/{lib → build}/encoding/spec.d.ts +0 -0
  185. /package/build/{umd/index.js → index.js} +0 -0
  186. /package/build/{esm/index.mjs → index.mjs} +0 -0
  187. /package/{lib → build}/symbol.shim.d.ts +0 -0
  188. /package/{lib → build}/types/symbols.d.ts +0 -0
  189. /package/{lib → build}/types/utils.d.ts +0 -0
  190. /package/{lib → build}/v3_bench.d.ts +0 -0
@@ -1,139 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.encodeArray = exports.encodeKeyValueOperation = exports.encodeSchemaOperation = void 0;
4
- exports.encodeValue = encodeValue;
5
- const spec_1 = require("../encoding/spec");
6
- const symbols_1 = require("../types/symbols");
7
- const encode_1 = require("../encoding/encode");
8
- function encodeValue(encoder, bytes, type, value, operation, it) {
9
- if (typeof (type) === "string") {
10
- encode_1.encode[type]?.(bytes, value, it);
11
- }
12
- else if (type[Symbol.metadata] !== undefined) {
13
- //
14
- // Encode refId for this instance.
15
- // The actual instance is going to be encoded on next `changeTree` iteration.
16
- //
17
- encode_1.encode.number(bytes, value[symbols_1.$refId], it);
18
- // Try to encode inherited TYPE_ID if it's an ADD operation.
19
- if ((operation & spec_1.OPERATION.ADD) === spec_1.OPERATION.ADD) {
20
- encoder.tryEncodeTypeId(bytes, type, value.constructor, it);
21
- }
22
- }
23
- else {
24
- //
25
- // Encode refId for this instance.
26
- // The actual instance is going to be encoded on next `changeTree` iteration.
27
- //
28
- encode_1.encode.number(bytes, value[symbols_1.$refId], it);
29
- }
30
- }
31
- /**
32
- * Used for Schema instances.
33
- * @private
34
- */
35
- const encodeSchemaOperation = function (encoder, bytes, changeTree, index, operation, it, _, __, metadata) {
36
- // "compress" field index + operation
37
- bytes[it.offset++] = (index | operation) & 255;
38
- // Do not encode value for DELETE operations
39
- if (operation === spec_1.OPERATION.DELETE) {
40
- return;
41
- }
42
- const ref = changeTree.ref;
43
- const field = metadata[index];
44
- // TODO: inline this function call small performance gain
45
- encodeValue(encoder, bytes, metadata[index].type, ref[field.name], operation, it);
46
- };
47
- exports.encodeSchemaOperation = encodeSchemaOperation;
48
- /**
49
- * Used for collections (MapSchema, CollectionSchema, SetSchema)
50
- * @private
51
- */
52
- const encodeKeyValueOperation = function (encoder, bytes, changeTree, index, operation, it) {
53
- // encode operation
54
- bytes[it.offset++] = operation & 255;
55
- // encode index
56
- encode_1.encode.number(bytes, index, it);
57
- // Do not encode value for DELETE operations
58
- if (operation === spec_1.OPERATION.DELETE) {
59
- return;
60
- }
61
- const ref = changeTree.ref;
62
- //
63
- // encode "alias" for dynamic fields (maps)
64
- //
65
- if ((operation & spec_1.OPERATION.ADD) === spec_1.OPERATION.ADD) { // ADD or DELETE_AND_ADD
66
- if (typeof (ref['set']) === "function") {
67
- //
68
- // MapSchema dynamic key
69
- //
70
- const dynamicIndex = changeTree.ref['$indexes'].get(index);
71
- encode_1.encode.string(bytes, dynamicIndex, it);
72
- }
73
- }
74
- const type = ref[symbols_1.$childType];
75
- const value = ref[symbols_1.$getByIndex](index);
76
- // try { throw new Error(); } catch (e) {
77
- // // only print if not coming from Reflection.ts
78
- // if (!e.stack.includes("src/Reflection.ts")) {
79
- // console.log("encodeKeyValueOperation -> ", {
80
- // ref: changeTree.ref.constructor.name,
81
- // field,
82
- // operation: OPERATION[operation],
83
- // value: value?.toJSON(),
84
- // items: ref.toJSON(),
85
- // });
86
- // }
87
- // }
88
- // TODO: inline this function call small performance gain
89
- encodeValue(encoder, bytes, type, value, operation, it);
90
- };
91
- exports.encodeKeyValueOperation = encodeKeyValueOperation;
92
- /**
93
- * Used for collections (MapSchema, ArraySchema, etc.)
94
- * @private
95
- */
96
- const encodeArray = function (encoder, bytes, changeTree, field, operation, it, isEncodeAll, hasView) {
97
- const ref = changeTree.ref;
98
- const useOperationByRefId = hasView && changeTree.isFiltered && (typeof (changeTree.getType(field)) !== "string");
99
- let refOrIndex;
100
- if (useOperationByRefId) {
101
- const item = ref['tmpItems'][field];
102
- // Skip encoding if item is undefined (e.g. when clear() is called)
103
- if (!item) {
104
- return;
105
- }
106
- refOrIndex = item[symbols_1.$refId];
107
- if (operation === spec_1.OPERATION.DELETE) {
108
- operation = spec_1.OPERATION.DELETE_BY_REFID;
109
- }
110
- else if (operation === spec_1.OPERATION.ADD) {
111
- operation = spec_1.OPERATION.ADD_BY_REFID;
112
- }
113
- }
114
- else {
115
- refOrIndex = field;
116
- }
117
- // encode operation
118
- bytes[it.offset++] = operation & 255;
119
- // encode index
120
- encode_1.encode.number(bytes, refOrIndex, it);
121
- // Do not encode value for DELETE operations
122
- if (operation === spec_1.OPERATION.DELETE || operation === spec_1.OPERATION.DELETE_BY_REFID) {
123
- return;
124
- }
125
- const type = changeTree.getType(field);
126
- const value = changeTree.getValue(field, isEncodeAll);
127
- // console.log({ type, field, value });
128
- // console.log("encodeArray -> ", {
129
- // ref: changeTree.ref.constructor.name,
130
- // field,
131
- // operation: OPERATION[operation],
132
- // value: value?.toJSON(),
133
- // items: ref.toJSON(),
134
- // });
135
- // TODO: inline this function call small performance gain
136
- encodeValue(encoder, bytes, type, value, operation, it);
137
- };
138
- exports.encodeArray = encodeArray;
139
- //# sourceMappingURL=EncodeOperation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"EncodeOperation.js","sourceRoot":"","sources":["../../src/encoder/EncodeOperation.ts"],"names":[],"mappings":"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","sourcesContent":["import { OPERATION } from \"../encoding/spec\";\nimport { $changes, $childType, $getByIndex, $refId } from \"../types/symbols\";\n\nimport { encode } from \"../encoding/encode\";\n\nimport type { ChangeTree, Ref } from \"./ChangeTree\";\nimport type { Encoder } from \"./Encoder\";\nimport type { Schema } from \"../Schema\";\n\nimport type { Iterator } from \"../encoding/decode\";\nimport type { ArraySchema } from \"../types/custom/ArraySchema\";\nimport type { Metadata } from \"../Metadata\";\n\nexport type EncodeOperation<T extends Ref = any> = (\n encoder: Encoder,\n bytes: Uint8Array,\n changeTree: ChangeTree<T>,\n index: number,\n operation: OPERATION,\n it: Iterator,\n isEncodeAll: boolean,\n hasView: boolean,\n metadata?: Metadata,\n) => void;\n\nexport function encodeValue(\n encoder: Encoder,\n bytes: Uint8Array,\n type: any,\n value: any,\n operation: OPERATION,\n it: Iterator,\n) {\n if (typeof (type) === \"string\") {\n (encode as any)[type]?.(bytes, value, it);\n\n } else if (type[Symbol.metadata] !== undefined) {\n //\n // Encode refId for this instance.\n // The actual instance is going to be encoded on next `changeTree` iteration.\n //\n encode.number(bytes, value[$refId], it);\n\n // Try to encode inherited TYPE_ID if it's an ADD operation.\n if ((operation & OPERATION.ADD) === OPERATION.ADD) {\n encoder.tryEncodeTypeId(bytes, type as typeof Schema, value.constructor as typeof Schema, it);\n }\n\n } else {\n //\n // Encode refId for this instance.\n // The actual instance is going to be encoded on next `changeTree` iteration.\n //\n encode.number(bytes, value[$refId], it);\n }\n}\n\n/**\n * Used for Schema instances.\n * @private\n */\nexport const encodeSchemaOperation: EncodeOperation = function <T extends Schema> (\n encoder: Encoder,\n bytes: Uint8Array,\n changeTree: ChangeTree<T>,\n index: number,\n operation: OPERATION,\n it: Iterator,\n _: any,\n __: any,\n metadata: Metadata,\n) {\n // \"compress\" field index + operation\n bytes[it.offset++] = (index | operation) & 255;\n\n // Do not encode value for DELETE operations\n if (operation === OPERATION.DELETE) {\n return;\n }\n\n const ref = changeTree.ref;\n const field = metadata[index];\n\n // TODO: inline this function call small performance gain\n encodeValue(\n encoder,\n bytes,\n metadata[index].type,\n ref[field.name as keyof T],\n operation,\n it\n );\n}\n\n/**\n * Used for collections (MapSchema, CollectionSchema, SetSchema)\n * @private\n */\nexport const encodeKeyValueOperation: EncodeOperation = function (\n encoder: Encoder,\n bytes: Uint8Array,\n changeTree: ChangeTree,\n index: number,\n operation: OPERATION,\n it: Iterator,\n) {\n // encode operation\n bytes[it.offset++] = operation & 255;\n\n // encode index\n encode.number(bytes, index, it);\n\n // Do not encode value for DELETE operations\n if (operation === OPERATION.DELETE) {\n return;\n }\n\n const ref = changeTree.ref;\n\n //\n // encode \"alias\" for dynamic fields (maps)\n //\n if ((operation & OPERATION.ADD) === OPERATION.ADD) { // ADD or DELETE_AND_ADD\n if (typeof(ref['set']) === \"function\") {\n //\n // MapSchema dynamic key\n //\n const dynamicIndex = changeTree.ref['$indexes'].get(index);\n encode.string(bytes, dynamicIndex, it);\n }\n }\n\n const type = ref[$childType];\n const value = ref[$getByIndex](index);\n\n // try { throw new Error(); } catch (e) {\n // // only print if not coming from Reflection.ts\n // if (!e.stack.includes(\"src/Reflection.ts\")) {\n // console.log(\"encodeKeyValueOperation -> \", {\n // ref: changeTree.ref.constructor.name,\n // field,\n // operation: OPERATION[operation],\n // value: value?.toJSON(),\n // items: ref.toJSON(),\n // });\n // }\n // }\n\n // TODO: inline this function call small performance gain\n encodeValue(\n encoder,\n bytes,\n type,\n value,\n operation,\n it\n );\n}\n\n/**\n * Used for collections (MapSchema, ArraySchema, etc.)\n * @private\n */\nexport const encodeArray: EncodeOperation = function (\n encoder: Encoder,\n bytes: Uint8Array,\n changeTree: ChangeTree<ArraySchema>,\n field: number,\n operation: OPERATION,\n it: Iterator,\n isEncodeAll: boolean,\n hasView: boolean,\n) {\n const ref = changeTree.ref;\n const useOperationByRefId = hasView && changeTree.isFiltered && (typeof (changeTree.getType(field)) !== \"string\");\n\n let refOrIndex: number;\n\n if (useOperationByRefId) {\n const item = ref['tmpItems'][field];\n\n // Skip encoding if item is undefined (e.g. when clear() is called)\n if (!item) { return; }\n\n refOrIndex = item[$refId];\n\n if (operation === OPERATION.DELETE) {\n operation = OPERATION.DELETE_BY_REFID;\n\n } else if (operation === OPERATION.ADD) {\n operation = OPERATION.ADD_BY_REFID;\n }\n\n } else {\n refOrIndex = field;\n }\n\n // encode operation\n bytes[it.offset++] = operation & 255;\n\n // encode index\n encode.number(bytes, refOrIndex, it);\n\n // Do not encode value for DELETE operations\n if (operation === OPERATION.DELETE || operation === OPERATION.DELETE_BY_REFID) {\n return;\n }\n\n const type = changeTree.getType(field);\n const value = changeTree.getValue(field, isEncodeAll);\n\n // console.log({ type, field, value });\n\n // console.log(\"encodeArray -> \", {\n // ref: changeTree.ref.constructor.name,\n // field,\n // operation: OPERATION[operation],\n // value: value?.toJSON(),\n // items: ref.toJSON(),\n // });\n\n // TODO: inline this function call small performance gain\n encodeValue(\n encoder,\n bytes,\n type,\n value,\n operation,\n it\n );\n}"]}
@@ -1,208 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Encoder = void 0;
4
- const TypeContext_1 = require("../types/TypeContext");
5
- const symbols_1 = require("../types/symbols");
6
- const encode_1 = require("../encoding/encode");
7
- const spec_1 = require("../encoding/spec");
8
- const Root_1 = require("./Root");
9
- const ChangeTree_1 = require("./ChangeTree");
10
- function concatBytes(a, b) {
11
- const result = new Uint8Array(a.length + b.length);
12
- result.set(a, 0);
13
- result.set(b, a.length);
14
- return result;
15
- }
16
- class Encoder {
17
- static { this.BUFFER_SIZE = 8 * 1024; } // 8KB
18
- constructor(state) {
19
- this.sharedBuffer = new Uint8Array(Encoder.BUFFER_SIZE);
20
- //
21
- // Use .cache() here to avoid re-creating a new context for every new room instance.
22
- //
23
- // We may need to make this optional in case of dynamically created
24
- // schemas - which would lead to memory leaks
25
- //
26
- this.context = TypeContext_1.TypeContext.cache(state.constructor);
27
- this.root = new Root_1.Root(this.context);
28
- this.setState(state);
29
- // console.log(">>>>>>>>>>>>>>>> Encoder types");
30
- // this.context.schemas.forEach((id, schema) => {
31
- // console.log("type:", id, schema.name, Object.keys(schema[Symbol.metadata]));
32
- // });
33
- }
34
- setState(state) {
35
- this.state = state;
36
- this.state[symbols_1.$changes].setRoot(this.root);
37
- }
38
- encode(it = { offset: 0 }, view, buffer = this.sharedBuffer, changeSetName = "changes", isEncodeAll = changeSetName === "allChanges", initialOffset = it.offset // cache current offset in case we need to resize the buffer
39
- ) {
40
- const hasView = (view !== undefined);
41
- const rootChangeTree = this.state[symbols_1.$changes];
42
- let current = this.root[changeSetName];
43
- while (current = current.next) {
44
- const changeTree = current.changeTree;
45
- if (hasView) {
46
- if (!view.isChangeTreeVisible(changeTree)) {
47
- // console.log("MARK AS INVISIBLE:", { ref: changeTree.ref.constructor.name, refId: changeTree.ref[$refId], raw: changeTree.ref.toJSON() });
48
- view.invisible.add(changeTree);
49
- continue; // skip this change tree
50
- }
51
- view.invisible.delete(changeTree); // remove from invisible list
52
- }
53
- const changeSet = changeTree[changeSetName];
54
- const ref = changeTree.ref;
55
- // TODO: avoid iterating over change tree if no changes were made
56
- const numChanges = changeSet.operations.length;
57
- if (numChanges === 0) {
58
- continue;
59
- }
60
- const ctor = ref.constructor;
61
- const encoder = ctor[symbols_1.$encoder];
62
- const filter = ctor[symbols_1.$filter];
63
- const metadata = ctor[Symbol.metadata];
64
- // skip root `refId` if it's the first change tree
65
- // (unless it "hasView", which will need to revisit the root)
66
- if (hasView || it.offset > initialOffset || changeTree !== rootChangeTree) {
67
- buffer[it.offset++] = spec_1.SWITCH_TO_STRUCTURE & 255;
68
- encode_1.encode.number(buffer, ref[symbols_1.$refId], it);
69
- }
70
- for (let j = 0; j < numChanges; j++) {
71
- const fieldIndex = changeSet.operations[j];
72
- if (fieldIndex < 0) {
73
- // "pure" operation without fieldIndex (e.g. CLEAR, REVERSE, etc.)
74
- // encode and continue early - no need to reach $filter check
75
- buffer[it.offset++] = Math.abs(fieldIndex) & 255;
76
- continue;
77
- }
78
- const operation = (isEncodeAll)
79
- ? spec_1.OPERATION.ADD
80
- : changeTree.indexedOperations[fieldIndex];
81
- //
82
- // first pass (encodeAll), identify "filtered" operations without encoding them
83
- // they will be encoded per client, based on their view.
84
- //
85
- // TODO: how can we optimize filtering out "encode all" operations?
86
- // TODO: avoid checking if no view tags were defined
87
- //
88
- if (fieldIndex === undefined || operation === undefined || (filter && !filter(ref, fieldIndex, view))) {
89
- // console.log("ADD AS INVISIBLE:", fieldIndex, changeTree.ref.constructor.name)
90
- // view?.invisible.add(changeTree);
91
- continue;
92
- }
93
- encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView, metadata);
94
- }
95
- }
96
- if (it.offset > buffer.byteLength) {
97
- // we can assume that n + 1 BUFFER_SIZE will suffice given that we are likely done with encoding at this point
98
- // multiples of BUFFER_SIZE are faster to allocate than arbitrary sizes
99
- const newSize = Math.ceil(it.offset / Encoder.BUFFER_SIZE) * Encoder.BUFFER_SIZE;
100
- console.warn(`@colyseus/schema buffer overflow. Encoded state is higher than default BUFFER_SIZE. Use the following to increase default BUFFER_SIZE:
101
-
102
- import { Encoder } from "@colyseus/schema";
103
- Encoder.BUFFER_SIZE = ${Math.round(newSize / 1024)} * 1024; // ${Math.round(newSize / 1024)} KB
104
- `);
105
- //
106
- // resize buffer and re-encode (TODO: can we avoid re-encoding here?)
107
- // -> No we probably can't unless we catch the need for resize before encoding which is likely more computationally expensive than resizing on demand
108
- //
109
- const newBuffer = new Uint8Array(newSize);
110
- newBuffer.set(buffer); // copy previous encoding steps beyond the initialOffset
111
- buffer = newBuffer;
112
- // assign resized buffer to local sharedBuffer
113
- if (buffer === this.sharedBuffer) {
114
- this.sharedBuffer = buffer;
115
- }
116
- return this.encode({ offset: initialOffset }, view, buffer, changeSetName, isEncodeAll);
117
- }
118
- else {
119
- return buffer.subarray(0, it.offset);
120
- }
121
- }
122
- encodeAll(it = { offset: 0 }, buffer = this.sharedBuffer) {
123
- return this.encode(it, undefined, buffer, "allChanges", true);
124
- }
125
- encodeAllView(view, sharedOffset, it, bytes = this.sharedBuffer) {
126
- const viewOffset = it.offset;
127
- // try to encode "filtered" changes
128
- this.encode(it, view, bytes, "allFilteredChanges", true, viewOffset);
129
- return concatBytes(bytes.subarray(0, sharedOffset), bytes.subarray(viewOffset, it.offset));
130
- }
131
- encodeView(view, sharedOffset, it, bytes = this.sharedBuffer) {
132
- const viewOffset = it.offset;
133
- // encode visibility changes (add/remove for this view)
134
- for (const [refId, changes] of view.changes) {
135
- const changeTree = this.root.changeTrees[refId];
136
- if (changeTree === undefined) {
137
- // detached instance, remove from view and skip.
138
- // console.log("detached instance, remove from view and skip.", refId);
139
- view.changes.delete(refId);
140
- continue;
141
- }
142
- const keys = Object.keys(changes);
143
- if (keys.length === 0) {
144
- // FIXME: avoid having empty changes if no changes were made
145
- // console.log("changes.size === 0, skip", refId, changeTree.ref.constructor.name);
146
- continue;
147
- }
148
- const ref = changeTree.ref;
149
- const ctor = ref.constructor;
150
- const encoder = ctor[symbols_1.$encoder];
151
- const metadata = ctor[Symbol.metadata];
152
- bytes[it.offset++] = spec_1.SWITCH_TO_STRUCTURE & 255;
153
- encode_1.encode.number(bytes, ref[symbols_1.$refId], it);
154
- for (let i = 0, numChanges = keys.length; i < numChanges; i++) {
155
- const index = Number(keys[i]);
156
- // workaround when using view.add() on item that has been deleted from state (see test "adding to view item that has been removed from state")
157
- const value = changeTree.ref[symbols_1.$getByIndex](index);
158
- const operation = (value !== undefined && changes[index]) || spec_1.OPERATION.DELETE;
159
- // isEncodeAll = false
160
- // hasView = true
161
- encoder(this, bytes, changeTree, index, operation, it, false, true, metadata);
162
- }
163
- }
164
- //
165
- // TODO: only clear view changes after all views are encoded
166
- // (to allow re-using StateView's for multiple clients)
167
- //
168
- // clear "view" changes after encoding
169
- view.changes.clear();
170
- // try to encode "filtered" changes
171
- this.encode(it, view, bytes, "filteredChanges", false, viewOffset);
172
- return concatBytes(bytes.subarray(0, sharedOffset), bytes.subarray(viewOffset, it.offset));
173
- }
174
- discardChanges() {
175
- // discard shared changes
176
- let current = this.root.changes.next;
177
- while (current) {
178
- current.changeTree.endEncode('changes');
179
- current = current.next;
180
- }
181
- this.root.changes = (0, ChangeTree_1.createChangeTreeList)();
182
- // discard filtered changes
183
- current = this.root.filteredChanges.next;
184
- while (current) {
185
- current.changeTree.endEncode('filteredChanges');
186
- current = current.next;
187
- }
188
- this.root.filteredChanges = (0, ChangeTree_1.createChangeTreeList)();
189
- }
190
- tryEncodeTypeId(bytes, baseType, targetType, it) {
191
- const baseTypeId = this.context.getTypeId(baseType);
192
- const targetTypeId = this.context.getTypeId(targetType);
193
- if (targetTypeId === undefined) {
194
- console.warn(`@colyseus/schema WARNING: Class "${targetType.name}" is not registered on TypeRegistry - Please either tag the class with @entity or define a @type() field.`);
195
- return;
196
- }
197
- if (baseTypeId !== targetTypeId) {
198
- bytes[it.offset++] = spec_1.TYPE_ID & 255;
199
- encode_1.encode.number(bytes, targetTypeId, it);
200
- }
201
- }
202
- get hasChanges() {
203
- return (this.root.changes.next !== undefined ||
204
- this.root.filteredChanges.next !== undefined);
205
- }
206
- }
207
- exports.Encoder = Encoder;
208
- //# sourceMappingURL=Encoder.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Encoder.js","sourceRoot":"","sources":["../../src/encoder/Encoder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Schema } from \"../Schema\";\nimport { TypeContext } from \"../types/TypeContext\";\nimport { $changes, $encoder, $filter, $getByIndex, $refId } from \"../types/symbols\";\n\nimport { encode } from \"../encoding/encode\";\nimport type { Iterator } from \"../encoding/decode\";\n\nimport { OPERATION, SWITCH_TO_STRUCTURE, TYPE_ID } from '../encoding/spec';\nimport { Root } from \"./Root\";\n\nimport type { StateView } from \"./StateView\";\nimport type { ChangeSetName, ChangeTree, ChangeTreeList, ChangeTreeNode } from \"./ChangeTree\";\nimport { createChangeTreeList } from \"./ChangeTree\";\n\nfunction concatBytes(a: Uint8Array, b: Uint8Array): Uint8Array {\n const result = new Uint8Array(a.length + b.length);\n result.set(a, 0);\n result.set(b, a.length);\n return result;\n}\n\nexport class Encoder<T extends Schema = any> {\n static BUFFER_SIZE = 8 * 1024; // 8KB\n sharedBuffer: Uint8Array = new Uint8Array(Encoder.BUFFER_SIZE);\n\n context: TypeContext;\n state: T;\n\n root: Root;\n\n constructor(state: T) {\n //\n // Use .cache() here to avoid re-creating a new context for every new room instance.\n //\n // We may need to make this optional in case of dynamically created\n // schemas - which would lead to memory leaks\n //\n this.context = TypeContext.cache(state.constructor as typeof Schema);\n this.root = new Root(this.context);\n\n this.setState(state);\n\n // console.log(\">>>>>>>>>>>>>>>> Encoder types\");\n // this.context.schemas.forEach((id, schema) => {\n // console.log(\"type:\", id, schema.name, Object.keys(schema[Symbol.metadata]));\n // });\n }\n\n protected setState(state: T) {\n this.state = state;\n this.state[$changes].setRoot(this.root);\n }\n\n encode(\n it: Iterator = { offset: 0 },\n view?: StateView,\n buffer: Uint8Array = this.sharedBuffer,\n changeSetName: ChangeSetName = \"changes\",\n isEncodeAll = changeSetName === \"allChanges\",\n initialOffset = it.offset // cache current offset in case we need to resize the buffer\n ): Uint8Array {\n const hasView = (view !== undefined);\n const rootChangeTree = this.state[$changes];\n\n let current: ChangeTreeList | ChangeTreeNode = this.root[changeSetName];\n\n while (current = current.next) {\n const changeTree = (current as ChangeTreeNode).changeTree;\n\n if (hasView) {\n if (!view.isChangeTreeVisible(changeTree)) {\n // console.log(\"MARK AS INVISIBLE:\", { ref: changeTree.ref.constructor.name, refId: changeTree.ref[$refId], raw: changeTree.ref.toJSON() });\n view.invisible.add(changeTree);\n continue; // skip this change tree\n }\n view.invisible.delete(changeTree); // remove from invisible list\n }\n\n const changeSet = changeTree[changeSetName];\n const ref = changeTree.ref;\n\n // TODO: avoid iterating over change tree if no changes were made\n const numChanges = changeSet.operations.length;\n if (numChanges === 0) { continue; }\n\n const ctor = ref.constructor;\n const encoder = ctor[$encoder];\n const filter = ctor[$filter];\n const metadata = ctor[Symbol.metadata];\n\n // skip root `refId` if it's the first change tree\n // (unless it \"hasView\", which will need to revisit the root)\n if (hasView || it.offset > initialOffset || changeTree !== rootChangeTree) {\n buffer[it.offset++] = SWITCH_TO_STRUCTURE & 255;\n encode.number(buffer, ref[$refId], it);\n }\n\n for (let j = 0; j < numChanges; j++) {\n const fieldIndex = changeSet.operations[j];\n\n if (fieldIndex < 0) {\n // \"pure\" operation without fieldIndex (e.g. CLEAR, REVERSE, etc.)\n // encode and continue early - no need to reach $filter check\n buffer[it.offset++] = Math.abs(fieldIndex) & 255;\n continue;\n }\n\n const operation = (isEncodeAll)\n ? OPERATION.ADD\n : changeTree.indexedOperations[fieldIndex];\n\n //\n // first pass (encodeAll), identify \"filtered\" operations without encoding them\n // they will be encoded per client, based on their view.\n //\n // TODO: how can we optimize filtering out \"encode all\" operations?\n // TODO: avoid checking if no view tags were defined\n //\n if (fieldIndex === undefined || operation === undefined || (filter && !filter(ref, fieldIndex, view))) {\n // console.log(\"ADD AS INVISIBLE:\", fieldIndex, changeTree.ref.constructor.name)\n // view?.invisible.add(changeTree);\n continue;\n }\n\n encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView, metadata);\n }\n }\n\n if (it.offset > buffer.byteLength) {\n // we can assume that n + 1 BUFFER_SIZE will suffice given that we are likely done with encoding at this point\n // multiples of BUFFER_SIZE are faster to allocate than arbitrary sizes\n const newSize = Math.ceil(it.offset / Encoder.BUFFER_SIZE) * Encoder.BUFFER_SIZE;\n\n console.warn(`@colyseus/schema buffer overflow. Encoded state is higher than default BUFFER_SIZE. Use the following to increase default BUFFER_SIZE:\n\n import { Encoder } from \"@colyseus/schema\";\n Encoder.BUFFER_SIZE = ${Math.round(newSize / 1024)} * 1024; // ${Math.round(newSize / 1024)} KB\n`);\n\n //\n // resize buffer and re-encode (TODO: can we avoid re-encoding here?)\n // -> No we probably can't unless we catch the need for resize before encoding which is likely more computationally expensive than resizing on demand\n //\n const newBuffer = new Uint8Array(newSize);\n newBuffer.set(buffer); // copy previous encoding steps beyond the initialOffset\n buffer = newBuffer;\n\n // assign resized buffer to local sharedBuffer\n if (buffer === this.sharedBuffer) {\n this.sharedBuffer = buffer;\n }\n\n return this.encode({ offset: initialOffset }, view, buffer, changeSetName, isEncodeAll);\n\n } else {\n\n return buffer.subarray(0, it.offset);\n }\n }\n\n encodeAll(\n it: Iterator = { offset: 0 },\n buffer: Uint8Array = this.sharedBuffer\n ) {\n return this.encode(it, undefined, buffer, \"allChanges\", true);\n }\n\n encodeAllView(\n view: StateView,\n sharedOffset: number,\n it: Iterator,\n bytes: Uint8Array = this.sharedBuffer\n ) {\n const viewOffset = it.offset;\n\n // try to encode \"filtered\" changes\n this.encode(it, view, bytes, \"allFilteredChanges\", true, viewOffset);\n\n return concatBytes(\n bytes.subarray(0, sharedOffset),\n bytes.subarray(viewOffset, it.offset)\n );\n }\n\n encodeView(\n view: StateView,\n sharedOffset: number,\n it: Iterator,\n bytes: Uint8Array = this.sharedBuffer\n ) {\n const viewOffset = it.offset;\n\n // encode visibility changes (add/remove for this view)\n for (const [refId, changes] of view.changes) {\n const changeTree: ChangeTree = this.root.changeTrees[refId];\n\n if (changeTree === undefined) {\n // detached instance, remove from view and skip.\n // console.log(\"detached instance, remove from view and skip.\", refId);\n view.changes.delete(refId);\n continue;\n }\n\n const keys = Object.keys(changes);\n if (keys.length === 0) {\n // FIXME: avoid having empty changes if no changes were made\n // console.log(\"changes.size === 0, skip\", refId, changeTree.ref.constructor.name);\n continue;\n }\n\n const ref = changeTree.ref;\n\n const ctor = ref.constructor;\n const encoder = ctor[$encoder];\n const metadata = ctor[Symbol.metadata];\n\n bytes[it.offset++] = SWITCH_TO_STRUCTURE & 255;\n encode.number(bytes, ref[$refId], it);\n\n for (let i = 0, numChanges = keys.length; i < numChanges; i++) {\n const index = Number(keys[i]);\n // workaround when using view.add() on item that has been deleted from state (see test \"adding to view item that has been removed from state\")\n const value = changeTree.ref[$getByIndex](index);\n const operation = (value !== undefined && changes[index]) || OPERATION.DELETE;\n\n // isEncodeAll = false\n // hasView = true\n encoder(this, bytes, changeTree, index, operation, it, false, true, metadata);\n }\n }\n\n //\n // TODO: only clear view changes after all views are encoded\n // (to allow re-using StateView's for multiple clients)\n //\n // clear \"view\" changes after encoding\n view.changes.clear();\n\n // try to encode \"filtered\" changes\n this.encode(it, view, bytes, \"filteredChanges\", false, viewOffset);\n\n return concatBytes(\n bytes.subarray(0, sharedOffset),\n bytes.subarray(viewOffset, it.offset)\n );\n }\n\n discardChanges() {\n // discard shared changes\n let current = this.root.changes.next;\n while (current) {\n current.changeTree.endEncode('changes');\n current = current.next;\n }\n this.root.changes = createChangeTreeList();\n\n // discard filtered changes\n current = this.root.filteredChanges.next;\n while (current) {\n current.changeTree.endEncode('filteredChanges');\n current = current.next;\n }\n this.root.filteredChanges = createChangeTreeList();\n }\n\n tryEncodeTypeId(\n bytes: Uint8Array,\n baseType: typeof Schema,\n targetType: typeof Schema,\n it: Iterator\n ) {\n const baseTypeId = this.context.getTypeId(baseType);\n const targetTypeId = this.context.getTypeId(targetType);\n\n if (targetTypeId === undefined) {\n console.warn(`@colyseus/schema WARNING: Class \"${targetType.name}\" is not registered on TypeRegistry - Please either tag the class with @entity or define a @type() field.`);\n return;\n }\n\n if (baseTypeId !== targetTypeId) {\n bytes[it.offset++] = TYPE_ID & 255;\n encode.number(bytes, targetTypeId, it);\n }\n }\n\n get hasChanges() {\n return (\n this.root.changes.next !== undefined ||\n this.root.filteredChanges.next !== undefined\n );\n }\n}\n"]}
@@ -1,233 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Root = void 0;
4
- const spec_1 = require("../encoding/spec");
5
- const ChangeTree_1 = require("./ChangeTree");
6
- const symbols_1 = require("../types/symbols");
7
- class Root {
8
- constructor(types) {
9
- this.types = types;
10
- this.nextUniqueId = 0;
11
- this.refCount = {};
12
- this.changeTrees = {};
13
- // all changes
14
- this.allChanges = (0, ChangeTree_1.createChangeTreeList)();
15
- this.allFilteredChanges = (0, ChangeTree_1.createChangeTreeList)(); // TODO: do not initialize it if filters are not used
16
- // pending changes to be encoded
17
- this.changes = (0, ChangeTree_1.createChangeTreeList)();
18
- this.filteredChanges = (0, ChangeTree_1.createChangeTreeList)(); // TODO: do not initialize it if filters are not used
19
- }
20
- getNextUniqueId() {
21
- return this.nextUniqueId++;
22
- }
23
- add(changeTree) {
24
- const ref = changeTree.ref;
25
- // Assign unique `refId` to ref if it doesn't have one yet.
26
- if (ref[symbols_1.$refId] === undefined) {
27
- ref[symbols_1.$refId] = this.getNextUniqueId();
28
- }
29
- const refId = ref[symbols_1.$refId];
30
- const isNewChangeTree = (this.changeTrees[refId] === undefined);
31
- if (isNewChangeTree) {
32
- this.changeTrees[refId] = changeTree;
33
- }
34
- const previousRefCount = this.refCount[refId];
35
- if (previousRefCount === 0) {
36
- //
37
- // When a ChangeTree is re-added, it means that it was previously removed.
38
- // We need to re-add all changes to the `changes` map.
39
- //
40
- const ops = changeTree.allChanges.operations;
41
- let len = ops.length;
42
- while (len--) {
43
- changeTree.indexedOperations[ops[len]] = spec_1.OPERATION.ADD;
44
- (0, ChangeTree_1.setOperationAtIndex)(changeTree.changes, len);
45
- }
46
- }
47
- this.refCount[refId] = (previousRefCount || 0) + 1;
48
- // console.log("ADD", { refId, ref: ref.constructor.name, refCount: this.refCount[refId], isNewChangeTree });
49
- return isNewChangeTree;
50
- }
51
- remove(changeTree) {
52
- const refId = changeTree.ref[symbols_1.$refId];
53
- const refCount = (this.refCount[refId]) - 1;
54
- // console.log("REMOVE", { refId, ref: changeTree.ref.constructor.name, refCount, needRemove: refCount <= 0 });
55
- if (refCount <= 0) {
56
- //
57
- // Only remove "root" reference if it's the last reference
58
- //
59
- changeTree.root = undefined;
60
- delete this.changeTrees[refId];
61
- this.removeChangeFromChangeSet("allChanges", changeTree);
62
- this.removeChangeFromChangeSet("changes", changeTree);
63
- if (changeTree.filteredChanges) {
64
- this.removeChangeFromChangeSet("allFilteredChanges", changeTree);
65
- this.removeChangeFromChangeSet("filteredChanges", changeTree);
66
- }
67
- this.refCount[refId] = 0;
68
- changeTree.forEachChild((child, _) => {
69
- if (child.removeParent(changeTree.ref)) {
70
- if ((child.parentChain === undefined || // no parent, remove it
71
- (child.parentChain && this.refCount[child.ref[symbols_1.$refId]] > 0) // parent is still in use, but has more than one reference, remove it
72
- )) {
73
- this.remove(child);
74
- }
75
- else if (child.parentChain) {
76
- // re-assigning a child of the same root, move it next to parent
77
- this.moveNextToParent(child);
78
- }
79
- }
80
- });
81
- }
82
- else {
83
- this.refCount[refId] = refCount;
84
- //
85
- // When losing a reference to an instance, it is best to move the
86
- // ChangeTree next to its parent in the encoding queue.
87
- //
88
- // This way, at decoding time, the instance that contains the
89
- // ChangeTree will be available before the ChangeTree itself. If the
90
- // containing instance is not available, the Decoder will throw
91
- // "refId not found" error.
92
- //
93
- this.recursivelyMoveNextToParent(changeTree);
94
- }
95
- return refCount;
96
- }
97
- recursivelyMoveNextToParent(changeTree) {
98
- this.moveNextToParent(changeTree);
99
- changeTree.forEachChild((child, _) => this.recursivelyMoveNextToParent(child));
100
- }
101
- moveNextToParent(changeTree) {
102
- if (changeTree.filteredChanges) {
103
- this.moveNextToParentInChangeTreeList("filteredChanges", changeTree);
104
- this.moveNextToParentInChangeTreeList("allFilteredChanges", changeTree);
105
- }
106
- else {
107
- this.moveNextToParentInChangeTreeList("changes", changeTree);
108
- this.moveNextToParentInChangeTreeList("allChanges", changeTree);
109
- }
110
- }
111
- moveNextToParentInChangeTreeList(changeSetName, changeTree) {
112
- const changeSet = this[changeSetName];
113
- const node = changeTree[changeSetName].queueRootNode;
114
- if (!node)
115
- return;
116
- // Find the parent in the linked list
117
- const parent = changeTree.parent;
118
- if (!parent || !parent[symbols_1.$changes])
119
- return;
120
- const parentNode = parent[symbols_1.$changes][changeSetName]?.queueRootNode;
121
- if (!parentNode || parentNode === node)
122
- return;
123
- // Use cached positions - no iteration needed!
124
- const parentPosition = parentNode.position;
125
- const childPosition = node.position;
126
- // If child is already after parent, no need to move
127
- if (childPosition > parentPosition)
128
- return;
129
- // Child is before parent, so we need to move it after parent
130
- // This maintains decoding order (parent before child)
131
- // Remove node from current position
132
- if (node.prev) {
133
- node.prev.next = node.next;
134
- }
135
- else {
136
- changeSet.next = node.next;
137
- }
138
- if (node.next) {
139
- node.next.prev = node.prev;
140
- }
141
- else {
142
- changeSet.tail = node.prev;
143
- }
144
- // Insert node right after parent
145
- node.prev = parentNode;
146
- node.next = parentNode.next;
147
- if (parentNode.next) {
148
- parentNode.next.prev = node;
149
- }
150
- else {
151
- changeSet.tail = node;
152
- }
153
- parentNode.next = node;
154
- // Update positions after the move
155
- this.updatePositionsAfterMove(changeSet, node, parentPosition + 1);
156
- }
157
- enqueueChangeTree(changeTree, changeSet, queueRootNode = changeTree[changeSet].queueRootNode) {
158
- // skip
159
- if (queueRootNode) {
160
- return;
161
- }
162
- // Add to linked list if not already present
163
- changeTree[changeSet].queueRootNode = this.addToChangeTreeList(this[changeSet], changeTree);
164
- }
165
- addToChangeTreeList(list, changeTree) {
166
- const node = {
167
- changeTree,
168
- next: undefined,
169
- prev: undefined,
170
- position: list.tail ? list.tail.position + 1 : 0
171
- };
172
- if (!list.next) {
173
- list.next = node;
174
- list.tail = node;
175
- }
176
- else {
177
- node.prev = list.tail;
178
- list.tail.next = node;
179
- list.tail = node;
180
- }
181
- return node;
182
- }
183
- updatePositionsAfterRemoval(list, removedPosition) {
184
- // Update positions for all nodes after the removed position
185
- let current = list.next;
186
- let position = 0;
187
- while (current) {
188
- if (position >= removedPosition) {
189
- current.position = position;
190
- }
191
- current = current.next;
192
- position++;
193
- }
194
- }
195
- updatePositionsAfterMove(list, node, newPosition) {
196
- // Recalculate all positions - this is more reliable than trying to be clever
197
- let current = list.next;
198
- let position = 0;
199
- while (current) {
200
- current.position = position;
201
- current = current.next;
202
- position++;
203
- }
204
- }
205
- removeChangeFromChangeSet(changeSetName, changeTree) {
206
- const changeSet = this[changeSetName];
207
- const node = changeTree[changeSetName].queueRootNode;
208
- if (node && node.changeTree === changeTree) {
209
- const removedPosition = node.position;
210
- // Remove the node from the linked list
211
- if (node.prev) {
212
- node.prev.next = node.next;
213
- }
214
- else {
215
- changeSet.next = node.next;
216
- }
217
- if (node.next) {
218
- node.next.prev = node.prev;
219
- }
220
- else {
221
- changeSet.tail = node.prev;
222
- }
223
- // Update positions for nodes that came after the removed node
224
- this.updatePositionsAfterRemoval(changeSet, removedPosition);
225
- // Clear ChangeTree reference
226
- changeTree[changeSetName].queueRootNode = undefined;
227
- return true;
228
- }
229
- return false;
230
- }
231
- }
232
- exports.Root = Root;
233
- //# sourceMappingURL=Root.js.map