@colyseus/schema 3.0.0-alpha.9 → 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 +2222 -1513
  4. package/build/cjs/index.js.map +1 -1
  5. package/build/esm/index.mjs +2223 -1516
  6. package/build/esm/index.mjs.map +1 -1
  7. package/build/umd/index.js +2225 -1516
  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 +128 -79
  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 +152 -87
  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
package/src/Schema.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { OPERATION } from './encoding/spec';
2
- import { DEFAULT_VIEW_TAG, DefinitionType } from "./annotations";
2
+ import { DEFAULT_VIEW_TAG, type DefinitionType } from "./annotations";
3
3
 
4
4
  import { NonFunctionPropNames, ToJSON } from './types/HelperTypes';
5
5
 
6
- import { ChangeTree, Ref } from './encoder/ChangeTree';
7
- import { $changes, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $track } from './types/symbols';
6
+ import { ChangeSet, ChangeTree, Ref } from './encoder/ChangeTree';
7
+ import { $changes, $decoder, $deleteByIndex, $descriptors, $encoder, $filter, $getByIndex, $track } from './types/symbols';
8
8
  import { StateView } from './encoder/StateView';
9
9
 
10
10
  import { encodeSchemaOperation } from './encoder/EncodeOperation';
@@ -15,11 +15,12 @@ import { getIndent } from './utils';
15
15
  /**
16
16
  * Schema encoder / decoder
17
17
  */
18
- export abstract class Schema {
19
-
18
+ export class Schema {
20
19
  static [$encoder] = encodeSchemaOperation;
21
20
  static [$decoder] = decodeSchemaOperation;
22
21
 
22
+ // public [$changes]: ChangeTree;
23
+
23
24
  /**
24
25
  * Assign the property descriptors required to track changes on this instance.
25
26
  * @param instance
@@ -31,37 +32,7 @@ export abstract class Schema {
31
32
  writable: true
32
33
  });
33
34
 
34
- const metadata = instance.constructor[Symbol.metadata];
35
-
36
- // Define property descriptors
37
- for (const field in metadata) {
38
- if (metadata[field].descriptor) {
39
- // for encoder
40
- Object.defineProperty(instance, `_${field}`, {
41
- value: undefined,
42
- writable: true,
43
- enumerable: false,
44
- configurable: true,
45
- });
46
- Object.defineProperty(instance, field, metadata[field].descriptor);
47
-
48
- } else {
49
- // for decoder
50
- Object.defineProperty(instance, field, {
51
- value: undefined,
52
- writable: true,
53
- enumerable: true,
54
- configurable: true,
55
- });
56
- }
57
-
58
- // Object.defineProperty(instance, field, {
59
- // ...instance.constructor[Symbol.metadata][field].descriptor
60
- // });
61
- // if (args[0]?.hasOwnProperty(field)) {
62
- // instance[field] = args[0][field];
63
- // }
64
- }
35
+ Object.defineProperties(instance, instance.constructor[Symbol.metadata]?.[$descriptors] || {});
65
36
  }
66
37
 
67
38
  static is(type: DefinitionType) {
@@ -88,7 +59,7 @@ export abstract class Schema {
88
59
  */
89
60
  static [$filter] (ref: Schema, index: number, view: StateView) {
90
61
  const metadata: Metadata = ref.constructor[Symbol.metadata];
91
- const tag = metadata[metadata[index]].tag;
62
+ const tag = metadata[index]?.tag;
92
63
 
93
64
  if (view === undefined) {
94
65
  // shared pass/encode: encode if doesn't have a tag
@@ -111,13 +82,17 @@ export abstract class Schema {
111
82
 
112
83
  // allow inherited classes to have a constructor
113
84
  constructor(...args: any[]) {
85
+ //
86
+ // inline
87
+ // Schema.initialize(this);
88
+ //
114
89
  Schema.initialize(this);
115
90
 
116
91
  //
117
92
  // Assign initial values
118
93
  //
119
94
  if (args[0]) {
120
- this.assign(args[0]);
95
+ Object.assign(this, args[0]);
121
96
  }
122
97
  }
123
98
 
@@ -135,21 +110,25 @@ export abstract class Schema {
135
110
  * @param operation OPERATION to perform (detected automatically)
136
111
  */
137
112
  public setDirty<K extends NonFunctionPropNames<this>>(property: K | number, operation?: OPERATION) {
113
+ const metadata: Metadata = this.constructor[Symbol.metadata];
138
114
  this[$changes].change(
139
- this.constructor[Symbol.metadata][property as string].index,
115
+ metadata[metadata[property as string]].index,
140
116
  operation
141
117
  );
142
118
  }
143
119
 
144
120
  clone (): this {
145
121
  const cloned = new ((this as any).constructor);
146
- const metadata = this.constructor[Symbol.metadata];
122
+ const metadata: Metadata = this.constructor[Symbol.metadata];
147
123
 
148
124
  //
149
125
  // TODO: clone all properties, not only annotated ones
150
126
  //
151
127
  // for (const field in this) {
152
- for (const field in metadata) {
128
+ for (const fieldIndex in metadata) {
129
+ // const field = metadata[metadata[fieldIndex]].name;
130
+ const field = metadata[fieldIndex as any as number].name;
131
+
153
132
  if (
154
133
  typeof (this[field]) === "object" &&
155
134
  typeof (this[field]?.clone) === "function"
@@ -162,15 +141,16 @@ export abstract class Schema {
162
141
  cloned[field] = this[field];
163
142
  }
164
143
  }
144
+
165
145
  return cloned;
166
146
  }
167
147
 
168
148
  toJSON () {
169
- const metadata = this.constructor[Symbol.metadata];
170
-
171
149
  const obj: unknown = {};
172
- for (const fieldName in metadata) {
173
- const field = metadata[fieldName];
150
+ const metadata = this.constructor[Symbol.metadata];
151
+ for (const index in metadata) {
152
+ const field = metadata[index];
153
+ const fieldName = field.name;
174
154
  if (!field.deprecated && this[fieldName] !== null && typeof (this[fieldName]) !== "undefined") {
175
155
  obj[fieldName] = (typeof (this[fieldName]['toJSON']) === "function")
176
156
  ? this[fieldName]['toJSON']()
@@ -185,24 +165,33 @@ export abstract class Schema {
185
165
  }
186
166
 
187
167
  protected [$getByIndex](index: number) {
188
- return this[this.constructor[Symbol.metadata][index]];
168
+ const metadata: Metadata = this.constructor[Symbol.metadata];
169
+ return this[metadata[index].name];
189
170
  }
190
171
 
191
172
  protected [$deleteByIndex](index: number) {
192
- this[this.constructor[Symbol.metadata][index]] = undefined;
173
+ const metadata: Metadata = this.constructor[Symbol.metadata];
174
+ this[metadata[index].name] = undefined;
193
175
  }
194
176
 
195
- static debugRefIds(instance: Ref, jsonContents: boolean = true, level: number = 0) {
177
+ /**
178
+ * Inspect the `refId` of all Schema instances in the tree. Optionally display the contents of the instance.
179
+ *
180
+ * @param instance Schema instance
181
+ * @param showContents display JSON contents of the instance
182
+ * @returns
183
+ */
184
+ static debugRefIds(instance: Ref, showContents: boolean = false, level: number = 0) {
196
185
  const ref = instance;
197
186
  const changeTree = ref[$changes];
198
187
 
199
- const contents = (jsonContents) ? ` - ${JSON.stringify(ref.toJSON())}` : "";
188
+ const contents = (showContents) ? ` - ${JSON.stringify(ref.toJSON())}` : "";
200
189
 
201
190
  let output = "";
202
- output += `${getIndent(level)}${ref.constructor.name} (${ref[$changes].refId})${contents}\n`;
191
+ output += `${getIndent(level)}${ref.constructor.name} (refId: ${ref[$changes].refId})${contents}\n`;
203
192
 
204
193
  changeTree.forEachChild((childChangeTree) =>
205
- output += this.debugRefIds(childChangeTree.ref, jsonContents, level + 1));
194
+ output += this.debugRefIds(childChangeTree.ref, showContents, level + 1));
206
195
 
207
196
  return output;
208
197
  }
@@ -216,31 +205,41 @@ export abstract class Schema {
216
205
  * @returns
217
206
  */
218
207
  static debugChanges(instance: Ref, isEncodeAll: boolean = false) {
219
- const changeTree = instance[$changes];
208
+ const changeTree: ChangeTree = instance[$changes];
220
209
 
221
210
  const changeSet = (isEncodeAll) ? changeTree.allChanges : changeTree.changes;
222
211
  const changeSetName = (isEncodeAll) ? "allChanges" : "changes";
223
212
 
224
213
  let output = `${instance.constructor.name} (${changeTree.refId}) -> .${changeSetName}:\n`;
225
214
 
226
- function dumpChangeSet(changeSet: Map<number, OPERATION>) {
227
- Array.from(changeSet)
228
- .sort((a, b) => a[0] - b[0])
229
- .forEach(([index, operation]) =>
230
- output += `- [${index}]: ${OPERATION[operation]} (${JSON.stringify(changeTree.getValue(index, isEncodeAll))})\n`
231
- );
215
+ function dumpChangeSet(changeSet: ChangeSet) {
216
+ changeSet.operations
217
+ .filter(op => op)
218
+ .forEach((index) => {
219
+ const operation = changeTree.indexedOperations[index];
220
+ console.log({ index, operation })
221
+ output += `- [${index}]: ${OPERATION[operation]} (${JSON.stringify(changeTree.getValue(Number(index), isEncodeAll))})\n`
222
+ });
232
223
  }
233
224
 
234
225
  dumpChangeSet(changeSet);
235
226
 
236
227
  // display filtered changes
237
- if (!isEncodeAll && changeTree.filteredChanges?.size > 0) {
228
+ if (
229
+ !isEncodeAll &&
230
+ changeTree.filteredChanges &&
231
+ (changeTree.filteredChanges.operations).filter(op => op).length > 0
232
+ ) {
238
233
  output += `${instance.constructor.name} (${changeTree.refId}) -> .filteredChanges:\n`;
239
234
  dumpChangeSet(changeTree.filteredChanges);
240
235
  }
241
236
 
242
237
  // display filtered changes
243
- if (isEncodeAll && changeTree.allFilteredChanges?.size > 0) {
238
+ if (
239
+ isEncodeAll &&
240
+ changeTree.allFilteredChanges &&
241
+ (changeTree.allFilteredChanges.operations).filter(op => op).length > 0
242
+ ) {
244
243
  output += `${instance.constructor.name} (${changeTree.refId}) -> .allFilteredChanges:\n`;
245
244
  dumpChangeSet(changeTree.allFilteredChanges);
246
245
  }
@@ -248,16 +247,19 @@ export abstract class Schema {
248
247
  return output;
249
248
  }
250
249
 
251
- static debugChangesDeep(ref: Ref) {
250
+ static debugChangesDeep(ref: Ref, changeSetName: "changes" | "allChanges" | "allFilteredChanges" | "filteredChanges" = "changes") {
252
251
  let output = "";
253
252
 
254
253
  const rootChangeTree = ref[$changes];
254
+ const root = rootChangeTree.root;
255
255
  const changeTrees: Map<ChangeTree, ChangeTree[]> = new Map();
256
256
 
257
- let totalInstances = 0;
257
+ const instanceRefIds = [];
258
258
  let totalOperations = 0;
259
259
 
260
- for (const [changeTree, changes] of (rootChangeTree.root.changes.entries())) {
260
+ for (const [refId, changes] of Object.entries(root[changeSetName])) {
261
+ const changeTree = root.changeTrees[refId];
262
+
261
263
  let includeChangeTree = false;
262
264
  let parentChangeTrees: ChangeTree[] = [];
263
265
  let parentChangeTree = changeTree.parent?.[$changes];
@@ -277,15 +279,15 @@ export abstract class Schema {
277
279
  }
278
280
 
279
281
  if (includeChangeTree) {
280
- totalInstances += 1;
281
- totalOperations += changes.size;
282
+ instanceRefIds.push(changeTree.refId);
283
+ totalOperations += Object.keys(changes).length;
282
284
  changeTrees.set(changeTree, parentChangeTrees.reverse());
283
285
  }
284
286
  }
285
287
 
286
288
  output += "---\n"
287
289
  output += `root refId: ${rootChangeTree.refId}\n`;
288
- output += `Total instances: ${totalInstances}\n`;
290
+ output += `Total instances: ${instanceRefIds.length} (refIds: ${instanceRefIds.join(", ")})\n`;
289
291
  output += `Total changes: ${totalOperations}\n`;
290
292
  output += "---\n"
291
293
 
@@ -299,17 +301,17 @@ export abstract class Schema {
299
301
  }
300
302
  });
301
303
 
302
- const changes = changeTree.changes;
304
+ const changes = changeTree.indexedOperations;
303
305
  const level = parentChangeTrees.length;
304
306
  const indent = getIndent(level);
305
307
 
306
308
  const parentIndex = (level > 0) ? `(${changeTree.parentIndex}) ` : "";
307
- output += `${indent}${parentIndex}${changeTree.ref.constructor.name} (refId: ${changeTree.refId}) - changes: ${changes.size}\n`;
309
+ output += `${indent}${parentIndex}${changeTree.ref.constructor.name} (refId: ${changeTree.refId}) - changes: ${Object.keys(changes).length}\n`;
308
310
 
309
- for (const [index, operation] of changes) {
311
+ for (const index in changes) {
312
+ const operation = changes[index];
310
313
  output += `${getIndent(level + 1)}${OPERATION[operation]}: ${index}\n`;
311
314
  }
312
-
313
315
  }
314
316
 
315
317
  return `${output}`;