@colyseus/schema 3.0.0-alpha.8 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +148 -62
  2. package/bin/schema-debug +94 -0
  3. package/build/cjs/index.js +2227 -1519
  4. package/build/cjs/index.js.map +1 -1
  5. package/build/esm/index.mjs +2228 -1522
  6. package/build/esm/index.mjs.map +1 -1
  7. package/build/umd/index.js +2230 -1522
  8. package/lib/Metadata.d.ts +21 -9
  9. package/lib/Metadata.js +169 -32
  10. package/lib/Metadata.js.map +1 -1
  11. package/lib/Reflection.d.ts +19 -4
  12. package/lib/Reflection.js +66 -31
  13. package/lib/Reflection.js.map +1 -1
  14. package/lib/Schema.d.ts +12 -5
  15. package/lib/Schema.js +57 -56
  16. package/lib/Schema.js.map +1 -1
  17. package/lib/annotations.d.ts +31 -34
  18. package/lib/annotations.js +110 -160
  19. package/lib/annotations.js.map +1 -1
  20. package/lib/bench_encode.d.ts +1 -0
  21. package/lib/bench_encode.js +130 -0
  22. package/lib/bench_encode.js.map +1 -0
  23. package/lib/codegen/api.js +1 -2
  24. package/lib/codegen/api.js.map +1 -1
  25. package/lib/codegen/languages/cpp.js +1 -2
  26. package/lib/codegen/languages/cpp.js.map +1 -1
  27. package/lib/codegen/languages/csharp.js +9 -46
  28. package/lib/codegen/languages/csharp.js.map +1 -1
  29. package/lib/codegen/languages/haxe.js +4 -2
  30. package/lib/codegen/languages/haxe.js.map +1 -1
  31. package/lib/codegen/languages/java.js +1 -2
  32. package/lib/codegen/languages/java.js.map +1 -1
  33. package/lib/codegen/languages/js.js +1 -2
  34. package/lib/codegen/languages/js.js.map +1 -1
  35. package/lib/codegen/languages/lua.js +23 -25
  36. package/lib/codegen/languages/lua.js.map +1 -1
  37. package/lib/codegen/languages/ts.js +1 -2
  38. package/lib/codegen/languages/ts.js.map +1 -1
  39. package/lib/codegen/parser.js +85 -3
  40. package/lib/codegen/parser.js.map +1 -1
  41. package/lib/codegen/types.js +6 -3
  42. package/lib/codegen/types.js.map +1 -1
  43. package/lib/debug.d.ts +1 -0
  44. package/lib/debug.js +51 -0
  45. package/lib/debug.js.map +1 -0
  46. package/lib/decoder/DecodeOperation.d.ts +3 -4
  47. package/lib/decoder/DecodeOperation.js +35 -17
  48. package/lib/decoder/DecodeOperation.js.map +1 -1
  49. package/lib/decoder/Decoder.d.ts +5 -6
  50. package/lib/decoder/Decoder.js +10 -10
  51. package/lib/decoder/Decoder.js.map +1 -1
  52. package/lib/decoder/ReferenceTracker.js +4 -2
  53. package/lib/decoder/ReferenceTracker.js.map +1 -1
  54. package/lib/decoder/strategy/RawChanges.js +1 -2
  55. package/lib/decoder/strategy/RawChanges.js.map +1 -1
  56. package/lib/decoder/strategy/StateCallbacks.d.ts +44 -11
  57. package/lib/decoder/strategy/StateCallbacks.js +74 -64
  58. package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
  59. package/lib/encoder/ChangeTree.d.ts +28 -20
  60. package/lib/encoder/ChangeTree.js +242 -188
  61. package/lib/encoder/ChangeTree.js.map +1 -1
  62. package/lib/encoder/EncodeOperation.d.ts +3 -6
  63. package/lib/encoder/EncodeOperation.js +51 -65
  64. package/lib/encoder/EncodeOperation.js.map +1 -1
  65. package/lib/encoder/Encoder.d.ts +8 -7
  66. package/lib/encoder/Encoder.js +133 -85
  67. package/lib/encoder/Encoder.js.map +1 -1
  68. package/lib/encoder/Root.d.ts +22 -0
  69. package/lib/encoder/Root.js +81 -0
  70. package/lib/encoder/Root.js.map +1 -0
  71. package/lib/encoder/StateView.d.ts +7 -7
  72. package/lib/encoder/StateView.js +72 -74
  73. package/lib/encoder/StateView.js.map +1 -1
  74. package/lib/encoding/assert.d.ts +7 -6
  75. package/lib/encoding/assert.js +13 -5
  76. package/lib/encoding/assert.js.map +1 -1
  77. package/lib/encoding/decode.d.ts +36 -19
  78. package/lib/encoding/decode.js +54 -84
  79. package/lib/encoding/decode.js.map +1 -1
  80. package/lib/encoding/encode.d.ts +36 -18
  81. package/lib/encoding/encode.js +61 -48
  82. package/lib/encoding/encode.js.map +1 -1
  83. package/lib/encoding/spec.d.ts +4 -5
  84. package/lib/encoding/spec.js +1 -2
  85. package/lib/encoding/spec.js.map +1 -1
  86. package/lib/index.d.ts +10 -9
  87. package/lib/index.js +24 -17
  88. package/lib/index.js.map +1 -1
  89. package/lib/types/HelperTypes.d.ts +34 -2
  90. package/lib/types/HelperTypes.js.map +1 -1
  91. package/lib/types/TypeContext.d.ts +29 -0
  92. package/lib/types/TypeContext.js +151 -0
  93. package/lib/types/TypeContext.js.map +1 -0
  94. package/lib/types/custom/ArraySchema.d.ts +2 -2
  95. package/lib/types/custom/ArraySchema.js +33 -22
  96. package/lib/types/custom/ArraySchema.js.map +1 -1
  97. package/lib/types/custom/CollectionSchema.d.ts +2 -2
  98. package/lib/types/custom/CollectionSchema.js +1 -0
  99. package/lib/types/custom/CollectionSchema.js.map +1 -1
  100. package/lib/types/custom/MapSchema.d.ts +18 -16
  101. package/lib/types/custom/MapSchema.js +12 -4
  102. package/lib/types/custom/MapSchema.js.map +1 -1
  103. package/lib/types/custom/SetSchema.d.ts +2 -2
  104. package/lib/types/custom/SetSchema.js +1 -0
  105. package/lib/types/custom/SetSchema.js.map +1 -1
  106. package/lib/types/registry.d.ts +8 -1
  107. package/lib/types/registry.js +23 -6
  108. package/lib/types/registry.js.map +1 -1
  109. package/lib/types/symbols.d.ts +8 -5
  110. package/lib/types/symbols.js +9 -6
  111. package/lib/types/symbols.js.map +1 -1
  112. package/lib/types/utils.js +1 -2
  113. package/lib/types/utils.js.map +1 -1
  114. package/lib/utils.js +9 -7
  115. package/lib/utils.js.map +1 -1
  116. package/package.json +19 -18
  117. package/src/Metadata.ts +190 -42
  118. package/src/Reflection.ts +76 -38
  119. package/src/Schema.ts +72 -70
  120. package/src/annotations.ts +156 -202
  121. package/src/bench_encode.ts +108 -0
  122. package/src/codegen/languages/csharp.ts +8 -47
  123. package/src/codegen/languages/haxe.ts +4 -0
  124. package/src/codegen/languages/lua.ts +19 -27
  125. package/src/codegen/parser.ts +107 -0
  126. package/src/codegen/types.ts +1 -0
  127. package/src/debug.ts +55 -0
  128. package/src/decoder/DecodeOperation.ts +43 -15
  129. package/src/decoder/Decoder.ts +12 -10
  130. package/src/decoder/ReferenceTracker.ts +5 -3
  131. package/src/decoder/strategy/StateCallbacks.ts +152 -81
  132. package/src/encoder/ChangeTree.ts +282 -209
  133. package/src/encoder/EncodeOperation.ts +78 -78
  134. package/src/encoder/Encoder.ts +157 -93
  135. package/src/encoder/Root.ts +93 -0
  136. package/src/encoder/StateView.ts +80 -88
  137. package/src/encoding/assert.ts +17 -8
  138. package/src/encoding/decode.ts +73 -93
  139. package/src/encoding/encode.ts +76 -45
  140. package/src/encoding/spec.ts +3 -5
  141. package/src/index.ts +12 -20
  142. package/src/types/HelperTypes.ts +54 -2
  143. package/src/types/TypeContext.ts +175 -0
  144. package/src/types/custom/ArraySchema.ts +49 -19
  145. package/src/types/custom/CollectionSchema.ts +1 -0
  146. package/src/types/custom/MapSchema.ts +30 -17
  147. package/src/types/custom/SetSchema.ts +1 -0
  148. package/src/types/registry.ts +22 -3
  149. package/src/types/symbols.ts +10 -7
  150. package/src/utils.ts +7 -3
@@ -1,6 +1,6 @@
1
- import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $onDecodeEnd, $isNew } from "../symbols";
1
+ import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $onDecodeEnd } from "../symbols";
2
2
  import type { Schema } from "../../Schema";
3
- import { ChangeTree } from "../../encoder/ChangeTree";
3
+ import { ChangeTree, setOperationAtIndex } from "../../encoder/ChangeTree";
4
4
  import { OPERATION } from "../../encoding/spec";
5
5
  import { registerType } from "../registry";
6
6
  import { Collection } from "../HelperTypes";
@@ -8,6 +8,7 @@ import { Collection } from "../HelperTypes";
8
8
  import { encodeArray } from "../../encoder/EncodeOperation";
9
9
  import { decodeArray } from "../../decoder/DecodeOperation";
10
10
  import type { StateView } from "../../encoder/StateView";
11
+ import { assertInstanceType } from "../../encoding/assert";
11
12
 
12
13
  const DEFAULT_SORT = (a: any, b: any) => {
13
14
  const A = a.toString();
@@ -69,6 +70,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
69
70
  get: (obj, prop) => {
70
71
  if (
71
72
  typeof (prop) !== "symbol" &&
73
+ // FIXME: d8 accuses this as low performance
72
74
  !isNaN(prop as any) // https://stackoverflow.com/a/175787/892698
73
75
  ) {
74
76
  return this.items[prop];
@@ -85,8 +87,10 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
85
87
 
86
88
  } else {
87
89
  if (setValue[$changes]) {
90
+ assertInstanceType(setValue, obj[$childType] as typeof Schema, obj, key);
91
+
88
92
  if (obj.items[key as unknown as number] !== undefined) {
89
- if (setValue[$changes][$isNew]) {
93
+ if (setValue[$changes].isNew) {
90
94
  this[$changes].indexedOperation(Number(key), OPERATION.MOVE_AND_ADD);
91
95
 
92
96
  } else {
@@ -96,9 +100,10 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
96
100
  this[$changes].indexedOperation(Number(key), OPERATION.MOVE);
97
101
  }
98
102
  }
99
- } else if (setValue[$changes][$isNew]) {
103
+ } else if (setValue[$changes].isNew) {
100
104
  this[$changes].indexedOperation(Number(key), OPERATION.ADD);
101
105
  }
106
+
102
107
  } else {
103
108
  obj.$changeAt(Number(key), setValue);
104
109
  }
@@ -133,7 +138,11 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
133
138
  });
134
139
 
135
140
  this[$changes] = new ChangeTree(proxy);
136
- this.push.apply(this, items);
141
+ this[$changes].indexes = {};
142
+
143
+ if (items.length > 0) {
144
+ this.push(...items);
145
+ }
137
146
 
138
147
  return proxy;
139
148
  }
@@ -155,15 +164,23 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
155
164
  push(...values: V[]) {
156
165
  let length = this.tmpItems.length;
157
166
 
158
- values.forEach((value, i) => {
159
- // skip null values
167
+ const changeTree = this[$changes];
168
+
169
+ // values.forEach((value, i) => {
170
+
171
+ for (let i = 0, l = values.length; i < values.length; i++, length++) {
172
+ const value = values[i];
173
+
160
174
  if (value === undefined || value === null) {
175
+ // skip null values
161
176
  return;
177
+
178
+ } else if (typeof (value) === "object" && this[$childType]) {
179
+ assertInstanceType(value as any, this[$childType] as typeof Schema, this, i);
180
+ // TODO: move value[$changes]?.setParent() to this block.
162
181
  }
163
182
 
164
- const changeTree = this[$changes];
165
183
  changeTree.indexedOperation(length, OPERATION.ADD, this.items.length);
166
- // changeTree.indexes[length] = length;
167
184
 
168
185
  this.items.push(value);
169
186
  this.tmpItems.push(value);
@@ -173,9 +190,10 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
173
190
  // (to avoid encoding "refId" operations before parent's "ADD" operation)
174
191
  //
175
192
  value[$changes]?.setParent(this, changeTree.root, length);
193
+ }
176
194
 
177
- length++;
178
- });
195
+ // length++;
196
+ // });
179
197
 
180
198
  return length;
181
199
  }
@@ -202,6 +220,8 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
202
220
  this[$changes].delete(index, undefined, this.items.length - 1);
203
221
 
204
222
  // this.tmpItems[index] = undefined;
223
+ // this.tmpItems.pop();
224
+
205
225
  this.deletedIndexes[index] = true;
206
226
 
207
227
  return this.items.pop();
@@ -263,10 +283,12 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
263
283
 
264
284
  clear() {
265
285
  // skip if already clear
266
- if (this.items.length === 0) { return; }
286
+ if (this.items.length === 0) {
287
+ return;
288
+ }
267
289
 
268
290
  // discard previous operations.
269
- const changeTree = this[$changes]
291
+ const changeTree = this[$changes];
270
292
 
271
293
  // discard children
272
294
  changeTree.forEachChild((changeTree, _) => {
@@ -278,9 +300,12 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
278
300
  //
279
301
  // TODO: do not use [$changes] at decoding time.
280
302
  //
281
- changeTree.root?.changes.delete(changeTree);
282
- changeTree.root?.allChanges.delete(changeTree);
283
- changeTree.root?.allFilteredChanges.delete(changeTree);
303
+ const root = changeTree.root;
304
+ if (root !== undefined) {
305
+ root.removeChangeFromChangeSet("changes", changeTree);
306
+ root.removeChangeFromChangeSet("allChanges", changeTree);
307
+ root.removeChangeFromChangeSet("allFilteredChanges", changeTree);
308
+ }
284
309
  });
285
310
 
286
311
  changeTree.discard(true);
@@ -331,6 +356,8 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
331
356
  changeTree.delete(index);
332
357
  changeTree.shiftAllChangeIndexes(-1, index);
333
358
 
359
+ // this.deletedIndexes[index] = true;
360
+
334
361
  return this.items.shift();
335
362
  }
336
363
 
@@ -430,9 +457,11 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
430
457
 
431
458
  // new index
432
459
  if (changeTree.isFiltered) {
433
- changeTree.filteredChanges.set(this.items.length, OPERATION.ADD);
460
+ setOperationAtIndex(changeTree.filteredChanges, this.items.length);
461
+ // changeTree.filteredChanges[this.items.length] = OPERATION.ADD;
434
462
  } else {
435
- changeTree.allChanges.set(this.items.length, OPERATION.ADD);
463
+ setOperationAtIndex(changeTree.allChanges, this.items.length);
464
+ // changeTree.allChanges[this.items.length] = OPERATION.ADD;
436
465
  }
437
466
 
438
467
  // FIXME: should we use OPERATION.MOVE here instead?
@@ -471,6 +500,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
471
500
  * @param thisArg An object to which the this keyword can refer in the callbackfn function.
472
501
  * If thisArg is omitted, undefined is used as the this value.
473
502
  */
503
+ every<S extends V>(predicate: (value: V, index: number, array: V[]) => value is S, thisArg?: any): this is S[];
474
504
  every(callbackfn: (value: V, index: number, array: V[]) => unknown, thisArg?: any): boolean {
475
505
  return this.items.every(callbackfn, thisArg);
476
506
  }
@@ -690,7 +720,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
690
720
  //
691
721
  // ES2023
692
722
  //
693
- with(index: number, value: V): V[] {
723
+ with(index: number, value: V): ArraySchema<V> {
694
724
  const copy = this.items.slice();
695
725
  copy[index] = value;
696
726
  return new ArraySchema(...copy);
@@ -41,6 +41,7 @@ export class CollectionSchema<V=any> implements Collection<K, V>{
41
41
 
42
42
  constructor (initialValues?: Array<V>) {
43
43
  this[$changes] = new ChangeTree(this);
44
+ this[$changes].indexes = {};
44
45
 
45
46
  if (initialValues) {
46
47
  initialValues.forEach((v) => this.add(v));
@@ -1,4 +1,4 @@
1
- import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex } from "../symbols";
1
+ import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $numFields } from "../symbols";
2
2
  import { ChangeTree } from "../../encoder/ChangeTree";
3
3
  import { OPERATION } from "../../encoding/spec";
4
4
  import { registerType } from "../registry";
@@ -6,12 +6,16 @@ import { Collection } from "../HelperTypes";
6
6
  import { decodeKeyValueOperation } from "../../decoder/DecodeOperation";
7
7
  import { encodeKeyValueOperation } from "../../encoder/EncodeOperation";
8
8
  import type { StateView } from "../../encoder/StateView";
9
+ import type { Schema } from "../../Schema";
10
+ import { assertInstanceType } from "../../encoding/assert";
9
11
 
10
- export class MapSchema<V=any, K extends string = string> implements Map<K, V>, Collection<K, V, [K, V]> {
12
+ export class MapSchema<V=any> implements Map<string, V>, Collection<string, V, [string, V]> {
11
13
  protected childType: new () => V;
12
14
 
13
- protected $items: Map<K, V> = new Map<K, V>();
14
- protected $indexes: Map<number, K> = new Map<number, K>();
15
+ protected $items: Map<string, V> = new Map<string, V>();
16
+ protected $indexes: Map<number, string> = new Map<number, string>();
17
+
18
+ protected [$changes]: ChangeTree;
15
19
 
16
20
  static [$encoder] = encodeKeyValueOperation;
17
21
  static [$decoder] = decodeKeyValueOperation;
@@ -37,8 +41,9 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
37
41
  return type['map'] !== undefined;
38
42
  }
39
43
 
40
- constructor (initialValues?: Map<K, V> | Record<K, V>) {
44
+ constructor (initialValues?: Map<string, V> | Record<string, V>) {
41
45
  this[$changes] = new ChangeTree(this);
46
+ this[$changes].indexes = {};
42
47
 
43
48
  if (initialValues) {
44
49
  if (
@@ -63,19 +68,22 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
63
68
  }
64
69
 
65
70
  /** Iterator */
66
- [Symbol.iterator](): IterableIterator<[K, V]> { return this.$items[Symbol.iterator](); }
71
+ [Symbol.iterator](): IterableIterator<[string, V]> { return this.$items[Symbol.iterator](); }
67
72
  get [Symbol.toStringTag]() { return this.$items[Symbol.toStringTag] }
68
73
 
69
74
  static get [Symbol.species]() { return MapSchema; }
70
75
 
71
- set(key: K, value: V) {
76
+ set(key: string, value: V) {
72
77
  if (value === undefined || value === null) {
73
78
  throw new Error(`MapSchema#set('${key}', ${value}): trying to set ${value} value on '${key}'.`);
79
+
80
+ } else if (typeof(value) === "object" && this[$childType]) {
81
+ assertInstanceType(value as any, this[$childType] as typeof Schema, this, key);
74
82
  }
75
83
 
76
84
  // Force "key" as string
77
85
  // See: https://github.com/colyseus/colyseus/issues/561#issuecomment-1646733468
78
- key = key.toString() as K;
86
+ key = key.toString() as string;
79
87
 
80
88
  const changeTree = this[$changes];
81
89
 
@@ -84,7 +92,7 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
84
92
 
85
93
  const index = (isReplace)
86
94
  ? changeTree.indexes[key]
87
- : changeTree.indexes[-1] ?? 0;
95
+ : changeTree.indexes[$numFields] ?? 0;
88
96
 
89
97
  let operation: OPERATION = (isReplace)
90
98
  ? OPERATION.REPLACE
@@ -99,7 +107,7 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
99
107
  if (!isReplace) {
100
108
  this.$indexes.set(index, key);
101
109
  changeTree.indexes[key] = index;
102
- changeTree.indexes[-1] = index + 1;
110
+ changeTree.indexes[$numFields] = index + 1;
103
111
 
104
112
  } else if (
105
113
  !isRef &&
@@ -130,11 +138,11 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
130
138
  return this;
131
139
  }
132
140
 
133
- get(key: K): V | undefined {
141
+ get(key: string): V | undefined {
134
142
  return this.$items.get(key);
135
143
  }
136
144
 
137
- delete(key: K) {
145
+ delete(key: string) {
138
146
  const index = this[$changes].indexes[key];
139
147
 
140
148
  this[$changes].delete(index);
@@ -158,11 +166,11 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
158
166
  changeTree.operation(OPERATION.CLEAR);
159
167
  }
160
168
 
161
- has (key: K) {
169
+ has (key: string) {
162
170
  return this.$items.has(key);
163
171
  }
164
172
 
165
- forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void) {
173
+ forEach(callbackfn: (value: V, key: string, map: Map<string, V>) => void) {
166
174
  this.$items.forEach(callbackfn);
167
175
  }
168
176
 
@@ -182,7 +190,7 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
182
190
  return this.$items.size;
183
191
  }
184
192
 
185
- protected setIndex(index: number, key: K) {
193
+ protected setIndex(index: number, key: string) {
186
194
  this.$indexes.set(index, key);
187
195
  }
188
196
 
@@ -202,8 +210,13 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
202
210
 
203
211
  protected [$onEncodeEnd]() {
204
212
  const changeTree = this[$changes];
205
- const changes = changeTree.changes.entries();
206
- for (const [fieldIndex, operation] of changes) {
213
+ const keys = Object.keys(changeTree.indexedOperations);
214
+
215
+ for (let i = 0, len = keys.length; i < len; i++) {
216
+ const key = keys[i];
217
+ const fieldIndex = Number(key);
218
+ const operation = changeTree.indexedOperations[key];
219
+
207
220
  if (operation === OPERATION.DELETE) {
208
221
  const index = this[$getByIndex](fieldIndex) as string;
209
222
  delete changeTree.indexes[index];
@@ -40,6 +40,7 @@ export class SetSchema<V=any> implements Collection<number, V> {
40
40
 
41
41
  constructor (initialValues?: Array<V>) {
42
42
  this[$changes] = new ChangeTree(this);
43
+ this[$changes].indexes = {};
43
44
 
44
45
  if (initialValues) {
45
46
  initialValues.forEach((v) => this.add(v));
@@ -1,13 +1,24 @@
1
+ import { DefinitionType, type } from "../annotations";
2
+ import { BufferLike, encode } from "../encoding/encode";
3
+ import { decode, Iterator } from "../encoding/decode";
4
+
1
5
  export interface TypeDefinition {
2
- constructor: any,
6
+ constructor?: any,
7
+ encode?: (bytes: BufferLike, value: any, it: Iterator) => any;
8
+ decode?: (bytes: BufferLike, it: Iterator) => any;
3
9
  }
4
10
 
5
11
  const registeredTypes: {[identifier: string] : TypeDefinition} = {};
6
12
  const identifiers = new Map<any, string>();
7
13
 
8
14
  export function registerType(identifier: string, definition: TypeDefinition) {
9
- identifiers.set(definition.constructor, identifier);
10
- registeredTypes[identifier] = definition;
15
+ if (definition.constructor) {
16
+ identifiers.set(definition.constructor, identifier);
17
+ registeredTypes[identifier] = definition;
18
+ }
19
+
20
+ if (definition.encode) { encode[identifier] = definition.encode; }
21
+ if (definition.decode) { decode[identifier] = definition.decode; }
11
22
  }
12
23
 
13
24
  export function getIdentifier(klass: any): string {
@@ -17,3 +28,11 @@ export function getIdentifier(klass: any): string {
17
28
  export function getType(identifier: string): TypeDefinition {
18
29
  return registeredTypes[identifier];
19
30
  }
31
+
32
+ export function defineCustomTypes<T extends {[key: string]: TypeDefinition}>(types: T) {
33
+ for (const identifier in types) {
34
+ registerType(identifier, types[identifier]);
35
+ }
36
+
37
+ return (t: keyof T) => type(t as DefinitionType);
38
+ }
@@ -18,12 +18,6 @@ export const $changes = Symbol('$changes');
18
18
  */
19
19
  export const $childType = Symbol('$childType');
20
20
 
21
- /**
22
- * Special ChangeTree property to identify new instances
23
- * (Once they're encoded, they're not new anymore)
24
- */
25
- export const $isNew = Symbol("$isNew");
26
-
27
21
  /**
28
22
  * Optional "discard" method for custom types (ArraySchema)
29
23
  * (Discards changes for next serialization)
@@ -33,4 +27,13 @@ export const $onEncodeEnd = Symbol('$onEncodeEnd');
33
27
  /**
34
28
  * When decoding, this method is called after the instance is fully decoded
35
29
  */
36
- export const $onDecodeEnd = Symbol("$onDecodeEnd");
30
+ export const $onDecodeEnd = Symbol("$onDecodeEnd");
31
+
32
+ /**
33
+ * Metadata
34
+ */
35
+ export const $descriptors = Symbol("$descriptors");
36
+ export const $numFields = "$__numFields";
37
+ export const $refTypeFieldIndexes = "$__refTypeFieldIndexes";
38
+ export const $viewFieldIndexes = "$__viewFieldIndexes";
39
+ export const $fieldIndexesByViewTag = "$__fieldIndexesByViewTag";
package/src/utils.ts CHANGED
@@ -27,13 +27,17 @@ export function dumpChanges(schema: Schema) {
27
27
  refs: []
28
28
  };
29
29
 
30
- $root.changes.forEach((operations, changeTree) => {
30
+ // for (const refId in $root.changes) {
31
+ $root.changes.forEach(changeTree => {
32
+ const changes = changeTree.indexedOperations;
33
+
31
34
  dump.refs.push(`refId#${changeTree.refId}`);
32
- operations.forEach((op, index) => {
35
+ for (const index in changes) {
36
+ const op = changes[index];
33
37
  const opName = OPERATION[op];
34
38
  if (!dump.ops[opName]) { dump.ops[opName] = 0; }
35
39
  dump.ops[OPERATION[op]]++;
36
- });
40
+ }
37
41
  });
38
42
 
39
43
  return dump;