@colyseus/schema 3.0.62 → 3.0.63

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 (100) hide show
  1. package/build/cjs/index.js +24 -79
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/esm/index.mjs +24 -79
  4. package/build/esm/index.mjs.map +1 -1
  5. package/build/umd/index.js +24 -79
  6. package/lib/Metadata.d.ts +2 -2
  7. package/lib/Metadata.js.map +1 -1
  8. package/lib/Reflection.js +2 -1
  9. package/lib/Reflection.js.map +1 -1
  10. package/lib/Schema.d.ts +14 -14
  11. package/lib/Schema.js +4 -7
  12. package/lib/Schema.js.map +1 -1
  13. package/lib/annotations.d.ts +37 -5
  14. package/lib/annotations.js +17 -7
  15. package/lib/annotations.js.map +1 -1
  16. package/lib/codegen/api.js.map +1 -1
  17. package/lib/codegen/argv.d.ts +1 -1
  18. package/lib/codegen/argv.js.map +1 -1
  19. package/lib/codegen/cli.js.map +1 -1
  20. package/lib/codegen/languages/cpp.js.map +1 -1
  21. package/lib/codegen/languages/csharp.js.map +1 -1
  22. package/lib/codegen/languages/haxe.js.map +1 -1
  23. package/lib/codegen/languages/java.js.map +1 -1
  24. package/lib/codegen/languages/js.js.map +1 -1
  25. package/lib/codegen/languages/lua.js.map +1 -1
  26. package/lib/codegen/languages/ts.js.map +1 -1
  27. package/lib/codegen/parser.js +11 -0
  28. package/lib/codegen/parser.js.map +1 -1
  29. package/lib/codegen/types.d.ts +1 -1
  30. package/lib/codegen/types.js.map +1 -1
  31. package/lib/decoder/DecodeOperation.d.ts +2 -2
  32. package/lib/decoder/DecodeOperation.js.map +1 -1
  33. package/lib/decoder/Decoder.js.map +1 -1
  34. package/lib/decoder/ReferenceTracker.js.map +1 -1
  35. package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
  36. package/lib/encoder/ChangeTree.d.ts +6 -1
  37. package/lib/encoder/ChangeTree.js.map +1 -1
  38. package/lib/encoder/EncodeOperation.js.map +1 -1
  39. package/lib/encoder/Encoder.d.ts +0 -1
  40. package/lib/encoder/Encoder.js +0 -21
  41. package/lib/encoder/Encoder.js.map +1 -1
  42. package/lib/encoder/StateView.js.map +1 -1
  43. package/lib/encoding/decode.js +1 -22
  44. package/lib/encoding/decode.js.map +1 -1
  45. package/lib/encoding/encode.d.ts +1 -23
  46. package/lib/encoding/encode.js +1 -22
  47. package/lib/encoding/encode.js.map +1 -1
  48. package/lib/index.d.ts +3 -2
  49. package/lib/index.js.map +1 -1
  50. package/lib/types/HelperTypes.d.ts +14 -5
  51. package/lib/types/HelperTypes.js.map +1 -1
  52. package/lib/types/TypeContext.js.map +1 -1
  53. package/lib/types/custom/ArraySchema.d.ts +9 -5
  54. package/lib/types/custom/ArraySchema.js.map +1 -1
  55. package/lib/types/custom/CollectionSchema.d.ts +8 -4
  56. package/lib/types/custom/CollectionSchema.js.map +1 -1
  57. package/lib/types/custom/MapSchema.d.ts +8 -6
  58. package/lib/types/custom/MapSchema.js.map +1 -1
  59. package/lib/types/custom/SetSchema.d.ts +8 -4
  60. package/lib/types/custom/SetSchema.js.map +1 -1
  61. package/lib/types/registry.js.map +1 -1
  62. package/lib/utils.js.map +1 -1
  63. package/lib/v3_bench.js.map +1 -1
  64. package/package.json +2 -2
  65. package/src/Metadata.ts +2 -2
  66. package/src/Reflection.ts +5 -4
  67. package/src/Schema.ts +35 -37
  68. package/src/annotations.ts +93 -30
  69. package/src/codegen/api.ts +1 -1
  70. package/src/codegen/argv.ts +5 -5
  71. package/src/codegen/cli.ts +1 -1
  72. package/src/codegen/languages/cpp.ts +5 -4
  73. package/src/codegen/languages/csharp.ts +2 -2
  74. package/src/codegen/languages/haxe.ts +2 -2
  75. package/src/codegen/languages/java.ts +2 -2
  76. package/src/codegen/languages/js.ts +3 -2
  77. package/src/codegen/languages/lua.ts +3 -2
  78. package/src/codegen/languages/ts.ts +3 -2
  79. package/src/codegen/parser.ts +12 -0
  80. package/src/codegen/types.ts +2 -2
  81. package/src/decoder/DecodeOperation.ts +21 -21
  82. package/src/decoder/Decoder.ts +3 -3
  83. package/src/decoder/ReferenceTracker.ts +7 -5
  84. package/src/decoder/strategy/StateCallbacks.ts +10 -10
  85. package/src/encoder/ChangeTree.ts +21 -15
  86. package/src/encoder/EncodeOperation.ts +4 -4
  87. package/src/encoder/Encoder.ts +0 -24
  88. package/src/encoder/StateView.ts +3 -2
  89. package/src/encoding/decode.ts +2 -0
  90. package/src/encoding/encode.ts +3 -1
  91. package/src/index.ts +5 -2
  92. package/src/types/HelperTypes.ts +29 -7
  93. package/src/types/TypeContext.ts +1 -1
  94. package/src/types/custom/ArraySchema.ts +12 -10
  95. package/src/types/custom/CollectionSchema.ts +9 -6
  96. package/src/types/custom/MapSchema.ts +8 -8
  97. package/src/types/custom/SetSchema.ts +9 -6
  98. package/src/types/registry.ts +2 -2
  99. package/src/utils.ts +2 -4
  100. package/src/v3_bench.ts +1 -1
@@ -9,7 +9,7 @@ export type Constructor<T = {}> = new (...args: any[]) => T;
9
9
 
10
10
  export interface Collection<K = any, V = any, IT = V> {
11
11
  [Symbol.iterator](): IterableIterator<IT>;
12
- forEach(callback: Function);
12
+ forEach(callback: Function): void;
13
13
  entries(): IterableIterator<[K, V]>;
14
14
  }
15
15
 
@@ -29,6 +29,7 @@ export type InferValueType<T extends DefinitionType> =
29
29
  : T extends "boolean" ? boolean
30
30
 
31
31
  // Handle { type: ... } patterns
32
+ : T extends { type: infer ChildType extends PrimitiveType } ? InferValueType<ChildType>
32
33
  : T extends { type: infer ChildType extends Constructor } ? InstanceType<ChildType>
33
34
  : T extends { type: Array<infer ChildType> } ? (ChildType extends Record<string | number, string | number> ? ChildType[keyof ChildType][] : ChildType[]) // TS ENUM
34
35
  : T extends { type: { map: infer ChildType } } ? (ChildType extends Record<string | number, string | number> ? MapSchema<ChildType[keyof ChildType]> : MapSchema<ChildType>) // TS ENUM
@@ -61,13 +62,11 @@ export type InferValueType<T extends DefinitionType> =
61
62
  : never;
62
63
 
63
64
  export type InferSchemaInstanceType<T extends Definition> = {
64
- [K in keyof T]: InferValueType<T[K]>
65
+ [K in keyof T]: T[K] extends (...args: any[]) => any
66
+ ? (T[K] extends new (...args: any[]) => any ? InferValueType<T[K]> : T[K])
67
+ : InferValueType<T[K]>
65
68
  } & Schema;
66
69
 
67
- export type DefinedSchemaType<T extends Definition, P extends typeof Schema> = {
68
- new (): InferSchemaInstanceType<T> & InstanceType<P>;
69
- } & typeof Schema;
70
-
71
70
  export type NonFunctionProps<T> = Omit<T, {
72
71
  [K in keyof T]: T[K] extends Function ? K : never;
73
72
  }[keyof T]>;
@@ -92,4 +91,27 @@ export type ToJSON<T> = NonFunctionProps<{
92
91
  : T[K] extends ArraySchema<infer U>
93
92
  ? U[]
94
93
  : T[K]
95
- }>;
94
+ }>;
95
+
96
+ // Helper type to check if T is exactly 'never' (meaning no InitProps was provided)
97
+ export type IsNever<T> = [T] extends [never] ? true : false;
98
+
99
+ /**
100
+ * Type helper for .assign() method - allows assigning values in a flexible way
101
+ * - Primitives can be assigned directly
102
+ * - Schema instances can be assigned from plain objects or Schema instances
103
+ * - Collections can be assigned from their JSON representations
104
+ */
105
+ export type AssignableProps<T> = {
106
+ [K in NonFunctionPropNames<T>]?: T[K] extends MapSchema<infer U>
107
+ ? MapSchema<U> | Record<string, U extends Schema ? (U | AssignableProps<U>) : U>
108
+ : T[K] extends ArraySchema<infer U>
109
+ ? ArraySchema<U> | (U extends Schema ? (U | AssignableProps<U>)[] : U[])
110
+ : T[K] extends SetSchema<infer U>
111
+ ? SetSchema<U> | Set<U> | (U extends Schema ? (U | AssignableProps<U>)[] : U[])
112
+ : T[K] extends CollectionSchema<infer U>
113
+ ? CollectionSchema<U> | (U extends Schema ? (U | AssignableProps<U>)[] : U[])
114
+ : T[K] extends Schema
115
+ ? T[K] | AssignableProps<T[K]>
116
+ : T[K]
117
+ };
@@ -97,7 +97,7 @@ export class TypeContext {
97
97
  this.discoverTypes(parent);
98
98
  }
99
99
 
100
- const metadata: Metadata = (klass[Symbol.metadata] ??= {});
100
+ const metadata: Metadata = (klass[Symbol.metadata] ??= {} as Metadata);
101
101
 
102
102
  // if any schema/field has filters, mark "context" as having filters.
103
103
  if (metadata[$viewFieldIndexes]) {
@@ -1,6 +1,6 @@
1
1
  import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $onDecodeEnd } from "../symbols";
2
2
  import type { Schema } from "../../Schema";
3
- import { ChangeTree, setOperationAtIndex } from "../../encoder/ChangeTree";
3
+ import { type IRef, ChangeTree, setOperationAtIndex } from "../../encoder/ChangeTree";
4
4
  import { OPERATION } from "../../encoding/spec";
5
5
  import { registerType } from "../registry";
6
6
  import { Collection } from "../HelperTypes";
@@ -18,18 +18,20 @@ const DEFAULT_SORT = (a: any, b: any) => {
18
18
  else return 0
19
19
  }
20
20
 
21
- export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
21
+ export class ArraySchema<V = any> implements Array<V>, Collection<number, V>, IRef {
22
22
  [n: number]: V;
23
+ [$changes]: ChangeTree;
24
+
25
+ protected [$childType]: string | typeof Schema;
23
26
 
24
27
  protected items: V[] = [];
25
28
  protected tmpItems: V[] = [];
26
29
  protected deletedIndexes: {[index: number]: boolean} = {};
30
+ protected isMovingItems = false;
27
31
 
28
32
  static [$encoder] = encodeArray;
29
33
  static [$decoder] = decodeArray;
30
34
 
31
- protected isMovingItems = false;
32
-
33
35
  /**
34
36
  * Determine if a property must be filtered.
35
37
  * - If returns false, the property is NOT going to be encoded.
@@ -76,7 +78,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
76
78
  // FIXME: d8 accuses this as low performance
77
79
  !isNaN(prop as any) // https://stackoverflow.com/a/175787/892698
78
80
  ) {
79
- return this.items[prop];
81
+ return this.items[prop as unknown as number];
80
82
 
81
83
  } else {
82
84
  return Reflect.get(obj, prop);
@@ -142,7 +144,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
142
144
  obj.$deleteAt(prop);
143
145
 
144
146
  } else {
145
- delete obj[prop];
147
+ delete obj[prop as unknown as number];
146
148
  }
147
149
 
148
150
  return true;
@@ -759,7 +761,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
759
761
  return this.items.findLast.apply(this.items, arguments);
760
762
  }
761
763
 
762
- findLastIndex(...args) {
764
+ findLastIndex(...args: any[]) {
763
765
  // @ts-ignore
764
766
  return this.items.findLastIndex.apply(this.items, arguments);
765
767
  }
@@ -821,7 +823,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
821
823
  return this;
822
824
  }
823
825
 
824
- protected [$getByIndex](index: number, isEncodeAll: boolean = false) {
826
+ [$getByIndex](index: number, isEncodeAll: boolean = false): any {
825
827
  //
826
828
  // TODO: avoid unecessary `this.tmpItems` check during decoding.
827
829
  //
@@ -836,7 +838,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
836
838
  : this.tmpItems[index] || this.items[index];
837
839
  }
838
840
 
839
- protected [$deleteByIndex](index: number) {
841
+ [$deleteByIndex](index: number): void {
840
842
  this.items[index] = undefined;
841
843
  this.tmpItems[index] = undefined; // TODO: do not try to get "tmpItems" at decoding time.
842
844
  }
@@ -856,7 +858,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
856
858
  }
857
859
 
858
860
  toJSON() {
859
- return this.toArray().map((value) => {
861
+ return this.toArray().map((value: any) => {
860
862
  return (typeof (value['toJSON']) === "function")
861
863
  ? value['toJSON']()
862
864
  : value;
@@ -1,15 +1,18 @@
1
1
  import { $changes, $childType, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $onEncodeEnd } from "../symbols";
2
- import { ChangeTree } from "../../encoder/ChangeTree";
2
+ import { ChangeTree, type IRef } from "../../encoder/ChangeTree";
3
3
  import { OPERATION } from "../../encoding/spec";
4
4
  import { registerType } from "../registry";
5
5
  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";
9
10
 
10
11
  type K = number; // TODO: allow to specify K generic on MapSchema.
11
12
 
12
- export class CollectionSchema<V=any> implements Collection<K, V>{
13
+ export class CollectionSchema<V=any> implements Collection<K, V>, IRef {
14
+ public [$changes]: ChangeTree;
15
+ protected [$childType]: string | typeof Schema;
13
16
 
14
17
  protected $items: Map<number, V> = new Map<number, V>();
15
18
  protected $indexes: Map<number, number> = new Map<number, number>();
@@ -159,11 +162,11 @@ export class CollectionSchema<V=any> implements Collection<K, V>{
159
162
  return this.$indexes.get(index);
160
163
  }
161
164
 
162
- protected [$getByIndex](index: number) {
165
+ [$getByIndex](index: number): any {
163
166
  return this.$items.get(this.$indexes.get(index));
164
167
  }
165
168
 
166
- protected [$deleteByIndex](index: number) {
169
+ [$deleteByIndex](index: number): void {
167
170
  const key = this.$indexes.get(index);
168
171
  this.$items.delete(key);
169
172
  this.$indexes.delete(index);
@@ -180,7 +183,7 @@ export class CollectionSchema<V=any> implements Collection<K, V>{
180
183
  toJSON() {
181
184
  const values: V[] = [];
182
185
 
183
- this.forEach((value, key) => {
186
+ this.forEach((value: any, key: K) => {
184
187
  values.push(
185
188
  (typeof (value['toJSON']) === "function")
186
189
  ? value['toJSON']()
@@ -204,7 +207,7 @@ export class CollectionSchema<V=any> implements Collection<K, V>{
204
207
  } else {
205
208
  // server-side
206
209
  cloned = new CollectionSchema();
207
- this.forEach((value) => {
210
+ this.forEach((value: any) => {
208
211
  if (value[$changes]) {
209
212
  cloned.add(value['clone']());
210
213
  } else {
@@ -1,5 +1,5 @@
1
1
  import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $numFields } from "../symbols";
2
- import { ChangeTree } from "../../encoder/ChangeTree";
2
+ import { ChangeTree, IRef } from "../../encoder/ChangeTree";
3
3
  import { OPERATION } from "../../encoding/spec";
4
4
  import { registerType } from "../registry";
5
5
  import { Collection } from "../HelperTypes";
@@ -9,15 +9,15 @@ import type { StateView } from "../../encoder/StateView";
9
9
  import type { Schema } from "../../Schema";
10
10
  import { assertInstanceType } from "../../encoding/assert";
11
11
 
12
- export class MapSchema<V=any, K extends string = string> implements Map<K, V>, Collection<K, V, [K, V]> {
12
+ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, Collection<K, V, [K, V]>, IRef {
13
13
  protected childType: new () => V;
14
+ [$changes]: ChangeTree;
15
+ protected [$childType]: string | typeof Schema;
14
16
 
15
17
  protected $items: Map<K, V> = new Map<K, V>();
16
18
  protected $indexes: Map<number, K> = new Map<number, K>();
17
19
  protected deletedItems: { [index: string]: V } = {};
18
20
 
19
- protected [$changes]: ChangeTree;
20
-
21
21
  static [$encoder] = encodeKeyValueOperation;
22
22
  static [$decoder] = decodeKeyValueOperation;
23
23
 
@@ -215,11 +215,11 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
215
215
  return this.$indexes.get(index);
216
216
  }
217
217
 
218
- protected [$getByIndex](index: number) {
218
+ [$getByIndex](index: number): V | undefined {
219
219
  return this.$items.get(this.$indexes.get(index));
220
220
  }
221
221
 
222
- protected [$deleteByIndex](index: number) {
222
+ [$deleteByIndex](index: number): void {
223
223
  const key = this.$indexes.get(index);
224
224
  this.$items.delete(key);
225
225
  this.$indexes.delete(index);
@@ -245,7 +245,7 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
245
245
  toJSON() {
246
246
  const map: any = {};
247
247
 
248
- this.forEach((value, key) => {
248
+ this.forEach((value: any, key) => {
249
249
  map[key] = (typeof (value['toJSON']) === "function")
250
250
  ? value['toJSON']()
251
251
  : value;
@@ -269,7 +269,7 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
269
269
  // server-side
270
270
  cloned = new MapSchema();
271
271
 
272
- this.forEach((value, key) => {
272
+ this.forEach((value: any, key) => {
273
273
  if (value[$changes]) {
274
274
  cloned.set(key, value['clone']());
275
275
  } else {
@@ -2,12 +2,15 @@ import { OPERATION } from "../../encoding/spec";
2
2
  import { registerType } from "../registry";
3
3
  import { $changes, $childType, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $onEncodeEnd } from "../symbols";
4
4
  import { Collection } from "../HelperTypes";
5
- import { ChangeTree } from "../../encoder/ChangeTree";
5
+ import { ChangeTree, type IRef } from "../../encoder/ChangeTree";
6
6
  import { encodeKeyValueOperation } from "../../encoder/EncodeOperation";
7
7
  import { decodeKeyValueOperation } from "../../decoder/DecodeOperation";
8
8
  import type { StateView } from "../../encoder/StateView";
9
+ import type { Schema } from "../../Schema";
9
10
 
10
- export class SetSchema<V=any> implements Collection<number, V> {
11
+ export class SetSchema<V=any> implements Collection<number, V>, IRef {
12
+ [$changes]: ChangeTree;
13
+ protected [$childType]: string | typeof Schema;
11
14
 
12
15
  protected $items: Map<number, V> = new Map<number, V>();
13
16
  protected $indexes: Map<number, number> = new Map<number, number>();
@@ -163,11 +166,11 @@ export class SetSchema<V=any> implements Collection<number, V> {
163
166
  return this.$indexes.get(index);
164
167
  }
165
168
 
166
- protected [$getByIndex](index: number) {
169
+ [$getByIndex](index: number): any {
167
170
  return this.$items.get(this.$indexes.get(index));
168
171
  }
169
172
 
170
- protected [$deleteByIndex](index: number) {
173
+ [$deleteByIndex](index: number): void {
171
174
  const key = this.$indexes.get(index);
172
175
  this.$items.delete(key);
173
176
  this.$indexes.delete(index);
@@ -184,7 +187,7 @@ export class SetSchema<V=any> implements Collection<number, V> {
184
187
  toJSON() {
185
188
  const values: V[] = [];
186
189
 
187
- this.forEach((value, key) => {
190
+ this.forEach((value: any, key: number) => {
188
191
  values.push(
189
192
  (typeof (value['toJSON']) === "function")
190
193
  ? value['toJSON']()
@@ -208,7 +211,7 @@ export class SetSchema<V=any> implements Collection<number, V> {
208
211
  } else {
209
212
  // server-side
210
213
  cloned = new SetSchema();
211
- this.forEach((value) => {
214
+ this.forEach((value: any) => {
212
215
  if (value[$changes]) {
213
216
  cloned.add(value['clone']());
214
217
  } else {
@@ -18,8 +18,8 @@ export function registerType(identifier: string, definition: TypeDefinition) {
18
18
  registeredTypes[identifier] = definition;
19
19
  }
20
20
 
21
- if (definition.encode) { encode[identifier] = definition.encode; }
22
- if (definition.decode) { decode[identifier] = definition.decode; }
21
+ if (definition.encode) { (encode as any)[identifier] = definition.encode; }
22
+ if (definition.decode) { (decode as any)[identifier] = definition.decode; }
23
23
  }
24
24
 
25
25
  export function getIdentifier(klass: any): string {
package/src/utils.ts CHANGED
@@ -2,8 +2,6 @@ import type { Schema } from "./Schema";
2
2
  import { OPERATION } from "./encoding/spec";
3
3
  import { $changes } from "./types/symbols";
4
4
 
5
- type ChangeItem = [string, number | string, any?];
6
-
7
5
  interface ChangeDump {
8
6
  ops: {
9
7
  ADD?: number;
@@ -43,8 +41,8 @@ export function dumpChanges(schema: Schema) {
43
41
  for (const index in changes) {
44
42
  const op = changes[index];
45
43
  const opName = OPERATION[op];
46
- if (!dump.ops[opName]) { dump.ops[opName] = 0; }
47
- dump.ops[OPERATION[op]]++;
44
+ if (!dump.ops[opName as keyof ChangeDump['ops']]) { dump.ops[opName as keyof ChangeDump['ops']] = 0; }
45
+ dump.ops[OPERATION[op] as keyof ChangeDump['ops']]++;
48
46
  }
49
47
  current = current.next;
50
48
  }
package/src/v3_bench.ts CHANGED
@@ -58,7 +58,7 @@ const encoder = new Encoder(state);
58
58
  let encoded = encoder.encode();
59
59
  console.log(`(${encoded.length})`, [...encoded]);
60
60
 
61
- globalThis.perform = function() {
61
+ (globalThis as any).perform = function(): void {
62
62
  for (let i = 0; i < 500000; i++) {
63
63
  encoder.encodeAll();
64
64
  }