@colyseus/schema 3.0.75 → 4.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 (157) hide show
  1. package/build/cjs/index.js +780 -429
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/esm/index.mjs +778 -430
  4. package/build/esm/index.mjs.map +1 -1
  5. package/build/umd/index.js +780 -429
  6. package/lib/Reflection.d.ts +50 -17
  7. package/lib/Reflection.js +151 -202
  8. package/lib/Reflection.js.map +1 -1
  9. package/lib/Schema.d.ts +13 -1
  10. package/lib/Schema.js +73 -9
  11. package/lib/Schema.js.map +1 -1
  12. package/lib/annotations.d.ts +6 -1
  13. package/lib/annotations.js +8 -34
  14. package/lib/annotations.js.map +1 -1
  15. package/lib/bench_encode.js +34 -1
  16. package/lib/bench_encode.js.map +1 -1
  17. package/lib/codegen/api.js +35 -2
  18. package/lib/codegen/api.js.map +1 -1
  19. package/lib/codegen/cli.js +4 -1
  20. package/lib/codegen/cli.js.map +1 -1
  21. package/lib/codegen/parser.js +35 -2
  22. package/lib/codegen/parser.js.map +1 -1
  23. package/lib/codegen/types.js +34 -1
  24. package/lib/codegen/types.js.map +1 -1
  25. package/lib/decoder/DecodeOperation.d.ts +2 -2
  26. package/lib/decoder/DecodeOperation.js +3 -3
  27. package/lib/decoder/DecodeOperation.js.map +1 -1
  28. package/lib/decoder/Decoder.d.ts +3 -3
  29. package/lib/decoder/Decoder.js +2 -2
  30. package/lib/decoder/Decoder.js.map +1 -1
  31. package/lib/decoder/ReferenceTracker.d.ts +0 -1
  32. package/lib/decoder/ReferenceTracker.js +9 -7
  33. package/lib/decoder/ReferenceTracker.js.map +1 -1
  34. package/lib/decoder/strategy/Callbacks.d.ts +154 -0
  35. package/lib/decoder/strategy/Callbacks.js +340 -0
  36. package/lib/decoder/strategy/Callbacks.js.map +1 -0
  37. package/lib/decoder/strategy/{StateCallbacks.d.ts → getDecoderStateCallbacks.d.ts} +6 -0
  38. package/lib/decoder/strategy/{StateCallbacks.js → getDecoderStateCallbacks.js} +17 -10
  39. package/lib/decoder/strategy/getDecoderStateCallbacks.js.map +1 -0
  40. package/lib/encoder/ChangeTree.d.ts +2 -2
  41. package/lib/encoder/ChangeTree.js.map +1 -1
  42. package/lib/encoder/EncodeOperation.d.ts +2 -2
  43. package/lib/encoder/EncodeOperation.js +3 -3
  44. package/lib/encoder/EncodeOperation.js.map +1 -1
  45. package/lib/encoder/Encoder.d.ts +6 -6
  46. package/lib/encoder/Encoder.js +19 -18
  47. package/lib/encoder/Encoder.js.map +1 -1
  48. package/lib/encoder/Root.js +17 -14
  49. package/lib/encoder/Root.js.map +1 -1
  50. package/lib/encoder/StateView.js +13 -12
  51. package/lib/encoder/StateView.js.map +1 -1
  52. package/lib/encoding/decode.d.ts +2 -2
  53. package/lib/encoding/encode.d.ts +3 -1
  54. package/lib/encoding/encode.js.map +1 -1
  55. package/lib/index.d.ts +3 -2
  56. package/lib/index.js +7 -3
  57. package/lib/index.js.map +1 -1
  58. package/lib/types/HelperTypes.d.ts +7 -14
  59. package/lib/types/HelperTypes.js.map +1 -1
  60. package/lib/types/custom/ArraySchema.d.ts +2 -1
  61. package/lib/types/custom/ArraySchema.js.map +1 -1
  62. package/lib/types/custom/CollectionSchema.d.ts +2 -1
  63. package/lib/types/custom/CollectionSchema.js.map +1 -1
  64. package/lib/types/custom/MapSchema.d.ts +3 -2
  65. package/lib/types/custom/MapSchema.js.map +1 -1
  66. package/lib/types/custom/SetSchema.d.ts +2 -1
  67. package/lib/types/custom/SetSchema.js.map +1 -1
  68. package/lib/types/symbols.d.ts +1 -0
  69. package/lib/types/symbols.js +2 -1
  70. package/lib/types/symbols.js.map +1 -1
  71. package/lib/utils.js +1 -1
  72. package/lib/utils.js.map +1 -1
  73. package/package.json +12 -16
  74. package/src/Reflection.ts +185 -174
  75. package/src/Schema.ts +81 -13
  76. package/src/annotations.ts +14 -40
  77. package/src/codegen/parser.ts +1 -1
  78. package/src/decoder/DecodeOperation.ts +9 -9
  79. package/src/decoder/Decoder.ts +6 -6
  80. package/src/decoder/ReferenceTracker.ts +10 -8
  81. package/src/decoder/strategy/Callbacks.ts +547 -0
  82. package/src/decoder/strategy/{StateCallbacks.ts → getDecoderStateCallbacks.ts} +17 -11
  83. package/src/encoder/ChangeTree.ts +4 -7
  84. package/src/encoder/EncodeOperation.ts +9 -9
  85. package/src/encoder/Encoder.ts +26 -18
  86. package/src/encoder/Root.ts +20 -15
  87. package/src/encoder/StateView.ts +15 -13
  88. package/src/encoding/encode.ts +1 -1
  89. package/src/index.ts +3 -2
  90. package/src/types/HelperTypes.ts +13 -11
  91. package/src/types/custom/ArraySchema.ts +2 -1
  92. package/src/types/custom/CollectionSchema.ts +4 -2
  93. package/src/types/custom/MapSchema.ts +4 -2
  94. package/src/types/custom/SetSchema.ts +3 -1
  95. package/src/types/symbols.ts +1 -0
  96. package/src/utils.ts +2 -2
  97. package/lib/Decoder.d.ts +0 -16
  98. package/lib/Decoder.js +0 -182
  99. package/lib/Decoder.js.map +0 -1
  100. package/lib/Encoder.d.ts +0 -13
  101. package/lib/Encoder.js +0 -79
  102. package/lib/Encoder.js.map +0 -1
  103. package/lib/changes/ChangeSet.d.ts +0 -12
  104. package/lib/changes/ChangeSet.js +0 -35
  105. package/lib/changes/ChangeSet.js.map +0 -1
  106. package/lib/changes/ChangeTree.d.ts +0 -53
  107. package/lib/changes/ChangeTree.js +0 -202
  108. package/lib/changes/ChangeTree.js.map +0 -1
  109. package/lib/changes/DecodeOperation.d.ts +0 -15
  110. package/lib/changes/DecodeOperation.js +0 -186
  111. package/lib/changes/DecodeOperation.js.map +0 -1
  112. package/lib/changes/EncodeOperation.d.ts +0 -18
  113. package/lib/changes/EncodeOperation.js +0 -130
  114. package/lib/changes/EncodeOperation.js.map +0 -1
  115. package/lib/changes/ReferenceTracker.d.ts +0 -14
  116. package/lib/changes/ReferenceTracker.js +0 -83
  117. package/lib/changes/ReferenceTracker.js.map +0 -1
  118. package/lib/changes/consts.d.ts +0 -14
  119. package/lib/changes/consts.js +0 -18
  120. package/lib/changes/consts.js.map +0 -1
  121. package/lib/decoder/strategy/StateCallbacks.js.map +0 -1
  122. package/lib/decoding/decode.d.ts +0 -48
  123. package/lib/decoding/decode.js +0 -267
  124. package/lib/decoding/decode.js.map +0 -1
  125. package/lib/ecs.d.ts +0 -11
  126. package/lib/ecs.js +0 -160
  127. package/lib/ecs.js.map +0 -1
  128. package/lib/filters/index.d.ts +0 -8
  129. package/lib/filters/index.js +0 -24
  130. package/lib/filters/index.js.map +0 -1
  131. package/lib/spec.d.ts +0 -13
  132. package/lib/spec.js +0 -42
  133. package/lib/spec.js.map +0 -1
  134. package/lib/types/ArraySchema.d.ts +0 -238
  135. package/lib/types/ArraySchema.js +0 -555
  136. package/lib/types/ArraySchema.js.map +0 -1
  137. package/lib/types/CollectionSchema.d.ts +0 -35
  138. package/lib/types/CollectionSchema.js +0 -150
  139. package/lib/types/CollectionSchema.js.map +0 -1
  140. package/lib/types/MapSchema.d.ts +0 -38
  141. package/lib/types/MapSchema.js +0 -215
  142. package/lib/types/MapSchema.js.map +0 -1
  143. package/lib/types/SetSchema.d.ts +0 -32
  144. package/lib/types/SetSchema.js +0 -162
  145. package/lib/types/SetSchema.js.map +0 -1
  146. package/lib/types/typeRegistry.d.ts +0 -5
  147. package/lib/types/typeRegistry.js +0 -13
  148. package/lib/types/typeRegistry.js.map +0 -1
  149. package/lib/usage.d.ts +0 -1
  150. package/lib/usage.js +0 -22
  151. package/lib/usage.js.map +0 -1
  152. package/lib/v3.d.ts +0 -1
  153. package/lib/v3.js +0 -427
  154. package/lib/v3.js.map +0 -1
  155. package/lib/v3_experiment.d.ts +0 -1
  156. package/lib/v3_experiment.js +0 -407
  157. package/lib/v3_experiment.js.map +0 -1
package/src/Reflection.ts CHANGED
@@ -1,31 +1,15 @@
1
- import { type, PrimitiveType } from "./annotations";
1
+ import { PrimitiveType, schema, SchemaType } from "./annotations";
2
2
  import { TypeContext } from "./types/TypeContext";
3
3
  import { Metadata } from "./Metadata";
4
- import { ArraySchema } from "./types/custom/ArraySchema";
5
4
  import { Iterator } from "./encoding/decode";
6
5
  import { Encoder } from "./encoder/Encoder";
7
6
  import { Decoder } from "./decoder/Decoder";
8
7
  import { Schema } from "./Schema";
9
8
 
10
9
  /**
11
- * Reflection
10
+ * Static methods available on Reflection
12
11
  */
13
- export class ReflectionField extends Schema {
14
- @type("string") name: string;
15
- @type("string") type: string;
16
- @type("number") referencedType: number;
17
- }
18
-
19
- export class ReflectionType extends Schema {
20
- @type("number") id: number;
21
- @type("number") extendsId: number;
22
- @type([ ReflectionField ]) fields = new ArraySchema<ReflectionField>();
23
- }
24
-
25
- export class Reflection extends Schema {
26
- @type([ReflectionType]) types: ArraySchema<ReflectionType> = new ArraySchema<ReflectionType>();
27
- @type("number") rootType: number;
28
-
12
+ interface ReflectionStatic {
29
13
  /**
30
14
  * Encodes the TypeContext of an Encoder into a buffer.
31
15
  *
@@ -33,207 +17,234 @@ export class Reflection extends Schema {
33
17
  * @param it
34
18
  * @returns
35
19
  */
36
- static encode(encoder: Encoder, it: Iterator = { offset: 0 }) {
37
- const context = encoder.context;
20
+ encode: (encoder: Encoder, it?: Iterator) => Uint8Array;
38
21
 
39
- const reflection = new Reflection();
40
- const reflectionEncoder = new Encoder(reflection);
41
-
42
- // rootType is usually the first schema passed to the Encoder
43
- // (unless it inherits from another schema)
44
- const rootType = context.schemas.get(encoder.state.constructor);
45
- if (rootType > 0) { reflection.rootType = rootType; }
22
+ /**
23
+ * Decodes the TypeContext from a buffer into a Decoder instance.
24
+ *
25
+ * @param bytes Reflection.encode() output
26
+ * @param it
27
+ * @returns Decoder instance
28
+ */
29
+ decode: <T extends Schema = Schema>(bytes: Uint8Array, it?: Iterator) => Decoder<T>;
30
+ }
46
31
 
47
- const includedTypeIds = new Set<number>();
48
- const pendingReflectionTypes: { [typeid: number]: ReflectionType[] } = {};
32
+ /**
33
+ * Reflection
34
+ */
35
+ export const ReflectionField = schema({
36
+ name: "string",
37
+ type: "string",
38
+ referencedType: "number",
39
+ })
40
+ export type ReflectionField = SchemaType<typeof ReflectionField>;
41
+
42
+ export const ReflectionType = schema({
43
+ id: "number",
44
+ extendsId: "number",
45
+ fields: [ ReflectionField ],
46
+ })
47
+ export type ReflectionType = SchemaType<typeof ReflectionType>;
48
+
49
+ export const Reflection = schema({
50
+ types: [ ReflectionType ],
51
+ rootType: "number",
52
+ }) as ReturnType<typeof schema<{
53
+ types: [typeof ReflectionType];
54
+ rootType: "number";
55
+ }>> & ReflectionStatic;
56
+
57
+ export type Reflection = SchemaType<typeof Reflection>;
58
+
59
+ Reflection.encode = function (encoder: Encoder, it: Iterator = { offset: 0 }) {
60
+ const context = encoder.context;
61
+
62
+ const reflection = new Reflection();
63
+ const reflectionEncoder = new Encoder(reflection);
64
+
65
+ // rootType is usually the first schema passed to the Encoder
66
+ // (unless it inherits from another schema)
67
+ const rootType = context.schemas.get(encoder.state.constructor);
68
+ if (rootType > 0) { reflection.rootType = rootType; }
69
+
70
+ const includedTypeIds = new Set<number>();
71
+ const pendingReflectionTypes: { [typeid: number]: ReflectionType[] } = {};
72
+
73
+ // add type to reflection in a way that respects inheritance
74
+ // (parent types should be added before their children)
75
+ const addType = (type: ReflectionType) => {
76
+ if (type.extendsId === undefined || includedTypeIds.has(type.extendsId)) {
77
+ includedTypeIds.add(type.id);
78
+
79
+ reflection.types.push(type);
80
+
81
+ const deps = pendingReflectionTypes[type.id];
82
+ if (deps !== undefined) {
83
+ delete pendingReflectionTypes[type.id];
84
+ deps.forEach((childType) => addType(childType));
85
+ }
86
+ } else {
87
+ if (pendingReflectionTypes[type.extendsId] === undefined) {
88
+ pendingReflectionTypes[type.extendsId] = [];
89
+ }
90
+ pendingReflectionTypes[type.extendsId].push(type);
91
+ }
92
+ };
49
93
 
50
- // add type to reflection in a way that respects inheritance
51
- // (parent types should be added before their children)
52
- const addType = (type: ReflectionType) => {
53
- if (type.extendsId === undefined || includedTypeIds.has(type.extendsId)) {
54
- includedTypeIds.add(type.id);
94
+ context.schemas.forEach((typeid, klass) => {
95
+ const type = new ReflectionType();
96
+ type.id = Number(typeid);
55
97
 
56
- reflection.types.push(type);
98
+ // support inheritance
99
+ const inheritFrom = Object.getPrototypeOf(klass);
100
+ if (inheritFrom !== Schema) {
101
+ type.extendsId = context.schemas.get(inheritFrom);
102
+ }
57
103
 
58
- const deps = pendingReflectionTypes[type.id];
59
- if (deps !== undefined) {
60
- delete pendingReflectionTypes[type.id];
61
- deps.forEach((childType) => addType(childType));
62
- }
63
- } else {
64
- if (pendingReflectionTypes[type.extendsId] === undefined) {
65
- pendingReflectionTypes[type.extendsId] = [];
66
- }
67
- pendingReflectionTypes[type.extendsId].push(type);
68
- }
69
- };
104
+ const metadata = klass[Symbol.metadata];
70
105
 
71
- context.schemas.forEach((typeid, klass) => {
72
- const type = new ReflectionType();
73
- type.id = Number(typeid);
106
+ //
107
+ // FIXME: this is a workaround for inherited types without additional fields
108
+ // if metadata is the same reference as the parent class - it means the class has no own metadata
109
+ //
110
+ if (metadata !== inheritFrom[Symbol.metadata]) {
111
+ for (const fieldIndex in metadata) {
112
+ const index = Number(fieldIndex);
113
+ const fieldName = metadata[index].name;
74
114
 
75
- // support inheritance
76
- const inheritFrom = Object.getPrototypeOf(klass);
77
- if (inheritFrom !== Schema) {
78
- type.extendsId = context.schemas.get(inheritFrom);
79
- }
115
+ // skip fields from parent classes
116
+ if (!Object.prototype.hasOwnProperty.call(metadata, fieldName)) {
117
+ continue;
118
+ }
80
119
 
81
- const metadata = klass[Symbol.metadata];
120
+ const reflectionField = new ReflectionField();
121
+ reflectionField.name = fieldName;
82
122
 
83
- //
84
- // FIXME: this is a workaround for inherited types without additional fields
85
- // if metadata is the same reference as the parent class - it means the class has no own metadata
86
- //
87
- if (metadata !== inheritFrom[Symbol.metadata]) {
88
- for (const fieldIndex in metadata) {
89
- const index = Number(fieldIndex);
90
- const fieldName = metadata[index].name;
123
+ let fieldType: string;
91
124
 
92
- // skip fields from parent classes
93
- if (!Object.prototype.hasOwnProperty.call(metadata, fieldName)) {
94
- continue;
95
- }
125
+ const field = metadata[index];
96
126
 
97
- const reflectionField = new ReflectionField();
98
- reflectionField.name = fieldName;
127
+ if (typeof (field.type) === "string") {
128
+ fieldType = field.type;
99
129
 
100
- let fieldType: string;
101
-
102
- const field = metadata[index];
130
+ } else {
131
+ let childTypeSchema: typeof Schema;
103
132
 
104
- if (typeof (field.type) === "string") {
105
- fieldType = field.type;
133
+ //
134
+ // TODO: refactor below.
135
+ //
136
+ if (Schema.is(field.type)) {
137
+ fieldType = "ref";
138
+ childTypeSchema = field.type as typeof Schema;
106
139
 
107
140
  } else {
108
- let childTypeSchema: typeof Schema;
141
+ fieldType = Object.keys(field.type)[0];
109
142
 
110
- //
111
- // TODO: refactor below.
112
- //
113
- if (Schema.is(field.type)) {
114
- fieldType = "ref";
115
- childTypeSchema = field.type as typeof Schema;
143
+ if (typeof (field.type[fieldType as keyof typeof field.type]) === "string") {
144
+ fieldType += ":" + field.type[fieldType as keyof typeof field.type]; // array:string
116
145
 
117
146
  } else {
118
- fieldType = Object.keys(field.type)[0];
119
-
120
- if (typeof (field.type[fieldType as keyof typeof field.type]) === "string") {
121
- fieldType += ":" + field.type[fieldType as keyof typeof field.type]; // array:string
122
-
123
- } else {
124
- childTypeSchema = field.type[fieldType as keyof typeof field.type];
125
- }
147
+ childTypeSchema = field.type[fieldType as keyof typeof field.type];
126
148
  }
127
-
128
- reflectionField.referencedType = (childTypeSchema)
129
- ? context.getTypeId(childTypeSchema)
130
- : -1;
131
149
  }
132
150
 
133
- reflectionField.type = fieldType;
134
- type.fields.push(reflectionField);
151
+ reflectionField.referencedType = (childTypeSchema)
152
+ ? context.getTypeId(childTypeSchema)
153
+ : -1;
135
154
  }
136
- }
137
-
138
- addType(type);
139
- });
140
155
 
141
- // in case there are types that were not added due to inheritance
142
- for (const typeid in pendingReflectionTypes) {
143
- pendingReflectionTypes[typeid].forEach((type) =>
144
- reflection.types.push(type))
156
+ reflectionField.type = fieldType;
157
+ type.fields.push(reflectionField);
158
+ }
145
159
  }
146
160
 
147
- const buf = reflectionEncoder.encodeAll(it);
148
- return buf.slice(0, it.offset)
149
- // return Buffer.from(buf, 0, it.offset);
150
- }
161
+ addType(type);
162
+ });
151
163
 
152
- /**
153
- * Decodes the TypeContext from a buffer into a Decoder instance.
154
- *
155
- * @param bytes Reflection.encode() output
156
- * @param it
157
- * @returns Decoder instance
158
- */
159
- static decode<T extends Schema = Schema>(bytes: Buffer, it?: Iterator): Decoder<T> {
160
- const reflection = new Reflection();
164
+ // in case there are types that were not added due to inheritance
165
+ for (const typeid in pendingReflectionTypes) {
166
+ pendingReflectionTypes[typeid].forEach((type) =>
167
+ reflection.types.push(type))
168
+ }
161
169
 
162
- const reflectionDecoder = new Decoder(reflection);
163
- reflectionDecoder.decode(bytes, it);
170
+ const buf = reflectionEncoder.encodeAll(it);
171
+ return buf.slice(0, it.offset);
172
+ };
164
173
 
165
- const typeContext = new TypeContext();
174
+ Reflection.decode = function <T extends Schema = Schema>(bytes: Uint8Array, it?: Iterator): Decoder<T> {
175
+ const reflection = new Reflection();
166
176
 
167
- // 1st pass, initialize metadata + inheritance
168
- reflection.types.forEach((reflectionType) => {
169
- const parentClass: typeof Schema = typeContext.get(reflectionType.extendsId) ?? Schema;
170
- const schema: typeof Schema = class _ extends parentClass {};
177
+ const reflectionDecoder = new Decoder(reflection);
178
+ reflectionDecoder.decode(bytes, it);
171
179
 
172
- // register for inheritance support
173
- TypeContext.register(schema);
180
+ const typeContext = new TypeContext();
174
181
 
175
- // // for inheritance support
176
- // Metadata.initialize(schema);
182
+ // 1st pass, initialize metadata + inheritance
183
+ reflection.types.forEach((reflectionType) => {
184
+ const parentClass: typeof Schema = typeContext.get(reflectionType.extendsId) ?? Schema;
185
+ const schema: typeof Schema = class _ extends parentClass { };
177
186
 
178
- typeContext.add(schema, reflectionType.id);
179
- }, {});
187
+ // register for inheritance support
188
+ TypeContext.register(schema);
180
189
 
181
- // define fields
182
- const addFields = (metadata: Metadata, reflectionType: ReflectionType, parentFieldIndex: number) => {
183
- reflectionType.fields.forEach((field, i) => {
184
- const fieldIndex = parentFieldIndex + i;
190
+ typeContext.add(schema, reflectionType.id);
191
+ }, {});
185
192
 
186
- if (field.referencedType !== undefined) {
187
- let fieldType = field.type;
188
- let refType: PrimitiveType = typeContext.get(field.referencedType);
193
+ // define fields
194
+ const addFields = (metadata: Metadata, reflectionType: ReflectionType, parentFieldIndex: number) => {
195
+ reflectionType.fields.forEach((field, i) => {
196
+ const fieldIndex = parentFieldIndex + i;
189
197
 
190
- // map or array of primitive type (-1)
191
- if (!refType) {
192
- const typeInfo = field.type.split(":");
193
- fieldType = typeInfo[0];
194
- refType = typeInfo[1] as PrimitiveType; // string
195
- }
198
+ if (field.referencedType !== undefined) {
199
+ let fieldType = field.type;
200
+ let refType: PrimitiveType = typeContext.get(field.referencedType);
196
201
 
197
- if (fieldType === "ref") {
198
- Metadata.addField(metadata, fieldIndex, field.name, refType);
202
+ // map or array of primitive type (-1)
203
+ if (!refType) {
204
+ const typeInfo = field.type.split(":");
205
+ fieldType = typeInfo[0];
206
+ refType = typeInfo[1] as PrimitiveType; // string
207
+ }
199
208
 
200
- } else {
201
- Metadata.addField(metadata, fieldIndex, field.name, { [fieldType]: refType });
202
- }
209
+ if (fieldType === "ref") {
210
+ Metadata.addField(metadata, fieldIndex, field.name, refType);
203
211
 
204
212
  } else {
205
- Metadata.addField(metadata, fieldIndex, field.name, field.type as PrimitiveType);
213
+ Metadata.addField(metadata, fieldIndex, field.name, { [fieldType]: refType });
206
214
  }
207
- });
208
- };
209
215
 
210
- // 2nd pass, set fields
211
- reflection.types.forEach((reflectionType) => {
212
- const schema = typeContext.get(reflectionType.id);
216
+ } else {
217
+ Metadata.addField(metadata, fieldIndex, field.name, field.type as PrimitiveType);
218
+ }
219
+ });
220
+ };
213
221
 
214
- // for inheritance support
215
- const metadata = Metadata.initialize(schema);
222
+ // 2nd pass, set fields
223
+ reflection.types.forEach((reflectionType) => {
224
+ const schema = typeContext.get(reflectionType.id);
216
225
 
217
- const inheritedTypes: ReflectionType[] = [];
226
+ // for inheritance support
227
+ const metadata = Metadata.initialize(schema);
218
228
 
219
- let parentType: ReflectionType = reflectionType;
220
- do {
221
- inheritedTypes.push(parentType);
222
- parentType = reflection.types.find((t) => t.id === parentType.extendsId);
223
- } while (parentType);
229
+ const inheritedTypes: ReflectionType[] = [];
224
230
 
225
- let parentFieldIndex = 0;
231
+ let parentType: ReflectionType = reflectionType;
232
+ do {
233
+ inheritedTypes.push(parentType);
234
+ parentType = reflection.types.find((t) => t.id === parentType.extendsId);
235
+ } while (parentType);
226
236
 
227
- inheritedTypes.reverse().forEach((reflectionType) => {
228
- // add fields from all inherited classes
229
- // TODO: refactor this to avoid adding fields from parent classes
230
- addFields(metadata, reflectionType, parentFieldIndex);
231
- parentFieldIndex += reflectionType.fields.length;
232
- });
237
+ let parentFieldIndex = 0;
238
+
239
+ inheritedTypes.reverse().forEach((reflectionType) => {
240
+ // add fields from all inherited classes
241
+ // TODO: refactor this to avoid adding fields from parent classes
242
+ addFields(metadata, reflectionType, parentFieldIndex);
243
+ parentFieldIndex += reflectionType.fields.length;
233
244
  });
245
+ });
234
246
 
235
- const state: T = new (typeContext.get(reflection.rootType || 0) as unknown as any)();
247
+ const state: T = new (typeContext.get(reflection.rootType || 0) as unknown as any)();
236
248
 
237
- return new Decoder<T>(state, typeContext);
238
- }
239
- }
249
+ return new Decoder<T>(state, typeContext);
250
+ }
package/src/Schema.ts CHANGED
@@ -4,7 +4,7 @@ import { DEFAULT_VIEW_TAG, type DefinitionType } from "./annotations";
4
4
  import { AssignableProps, NonFunctionPropNames, ToJSON } from './types/HelperTypes';
5
5
 
6
6
  import { ChangeSet, ChangeSetName, ChangeTree, IRef, Ref } from './encoder/ChangeTree';
7
- import { $changes, $decoder, $deleteByIndex, $descriptors, $encoder, $filter, $getByIndex, $track } from './types/symbols';
7
+ import { $changes, $decoder, $deleteByIndex, $descriptors, $encoder, $filter, $getByIndex, $refId, $track } from './types/symbols';
8
8
  import { StateView } from './encoder/StateView';
9
9
 
10
10
  import { encodeSchemaOperation } from './encoder/EncodeOperation';
@@ -22,6 +22,8 @@ export class Schema<C = any> implements IRef {
22
22
  static [$encoder] = encodeSchemaOperation;
23
23
  static [$decoder] = decodeSchemaOperation;
24
24
 
25
+ [$refId]?: number;
26
+
25
27
  /**
26
28
  * Assign the property descriptors required to track changes on this instance.
27
29
  * @param instance
@@ -95,13 +97,79 @@ export class Schema<C = any> implements IRef {
95
97
  }
96
98
  }
97
99
 
98
- public assign<T extends Partial<this>>(
99
- props: AssignableProps<T>,
100
- ): this {
100
+ /**
101
+ * Assign properties to the instance.
102
+ * @param props Properties to assign to the instance
103
+ * @returns
104
+ */
105
+ public assign<T extends Partial<this>>(props: AssignableProps<T>,): this {
101
106
  Object.assign(this, props);
102
107
  return this;
103
108
  }
104
109
 
110
+ /**
111
+ * Restore the instance from JSON data.
112
+ * @param jsonData JSON data to restore the instance from
113
+ * @returns
114
+ */
115
+ public restore(jsonData: ToJSON<this>): this {
116
+ const metadata: Metadata = (this.constructor as typeof Schema)[Symbol.metadata];
117
+
118
+ for (const fieldIndex in metadata) {
119
+ const field = metadata[fieldIndex as any as number];
120
+ const fieldName = field.name as keyof this;
121
+ const fieldType = field.type;
122
+ const value = (jsonData as any)[fieldName];
123
+
124
+ if (value === undefined || value === null) {
125
+ continue;
126
+ }
127
+
128
+ if (typeof fieldType === "string") {
129
+ // Primitive type: assign directly
130
+ this[fieldName] = value;
131
+
132
+ } else if (Schema.is(fieldType)) {
133
+ // Schema type: create instance and restore
134
+ const instance = new (fieldType as typeof Schema)();
135
+ instance.restore(value);
136
+ this[fieldName] = instance as any;
137
+
138
+ } else if (typeof fieldType === "object") {
139
+ // Collection types: { map: ... }, { array: ... }, etc.
140
+ const collectionType = Object.keys(fieldType)[0] as string;
141
+ const childType = (fieldType as any)[collectionType];
142
+
143
+ if (collectionType === "map") {
144
+ const mapSchema = this[fieldName] as any;
145
+ for (const key in value) {
146
+ if (Schema.is(childType)) {
147
+ const childInstance = new (childType as typeof Schema)();
148
+ childInstance.restore(value[key]);
149
+ mapSchema.set(key, childInstance);
150
+ } else {
151
+ mapSchema.set(key, value[key]);
152
+ }
153
+ }
154
+
155
+ } else if (collectionType === "array") {
156
+ const arraySchema = this[fieldName] as any;
157
+ for (let i = 0; i < value.length; i++) {
158
+ if (Schema.is(childType)) {
159
+ const childInstance = new (childType as typeof Schema)();
160
+ childInstance.restore(value[i]);
161
+ arraySchema.push(childInstance);
162
+ } else {
163
+ arraySchema.push(value[i]);
164
+ }
165
+ }
166
+ }
167
+ }
168
+ }
169
+
170
+ return this;
171
+ }
172
+
105
173
  /**
106
174
  * (Server-side): Flag a property to be encoded for the next patch.
107
175
  * @param instance Schema instance
@@ -190,7 +258,7 @@ export class Schema<C = any> implements IRef {
190
258
  const contents = (showContents) ? ` - ${JSON.stringify(ref.toJSON())}` : "";
191
259
  const changeTree: ChangeTree = ref[$changes];
192
260
 
193
- const refId = (decoder) ? decoder.root.refIds.get(ref) : changeTree.refId;
261
+ const refId = (ref as IRef)[$refId];
194
262
  const root = (decoder) ? decoder.root : changeTree.root;
195
263
 
196
264
  // log reference count if > 1
@@ -218,7 +286,7 @@ export class Schema<C = any> implements IRef {
218
286
  let current = ref[$changes].root[changeSet].next;
219
287
  while (current) {
220
288
  if (current.changeTree) {
221
- encodeOrder.push(current.changeTree.refId);
289
+ encodeOrder.push(current.changeTree.ref[$refId]);
222
290
  }
223
291
  current = current.next;
224
292
  }
@@ -243,7 +311,7 @@ export class Schema<C = any> implements IRef {
243
311
  const changeSet = (isEncodeAll) ? changeTree.allChanges : changeTree.changes;
244
312
  const changeSetName = (isEncodeAll) ? "allChanges" : "changes";
245
313
 
246
- let output = `${instance.constructor.name} (${changeTree.refId}) -> .${changeSetName}:\n`;
314
+ let output = `${instance.constructor.name} (${instance[$refId]}) -> .${changeSetName}:\n`;
247
315
 
248
316
  function dumpChangeSet(changeSet: ChangeSet) {
249
317
  changeSet.operations
@@ -262,7 +330,7 @@ export class Schema<C = any> implements IRef {
262
330
  changeTree.filteredChanges &&
263
331
  (changeTree.filteredChanges.operations).filter(op => op).length > 0
264
332
  ) {
265
- output += `${instance.constructor.name} (${changeTree.refId}) -> .filteredChanges:\n`;
333
+ output += `${instance.constructor.name} (${instance[$refId]}) -> .filteredChanges:\n`;
266
334
  dumpChangeSet(changeTree.filteredChanges);
267
335
  }
268
336
 
@@ -272,7 +340,7 @@ export class Schema<C = any> implements IRef {
272
340
  changeTree.allFilteredChanges &&
273
341
  (changeTree.allFilteredChanges.operations).filter(op => op).length > 0
274
342
  ) {
275
- output += `${instance.constructor.name} (${changeTree.refId}) -> .allFilteredChanges:\n`;
343
+ output += `${instance.constructor.name} (${instance[$refId]}) -> .allFilteredChanges:\n`;
276
344
  dumpChangeSet(changeTree.allFilteredChanges);
277
345
  }
278
346
 
@@ -313,14 +381,14 @@ export class Schema<C = any> implements IRef {
313
381
  }
314
382
 
315
383
  if (includeChangeTree) {
316
- instanceRefIds.push(changeTree.refId);
384
+ instanceRefIds.push(changeTree.ref[$refId]);
317
385
  totalOperations += Object.keys(changes).length;
318
386
  changeTrees.set(changeTree, parentChangeTrees.reverse());
319
387
  }
320
388
  }
321
389
 
322
390
  output += "---\n"
323
- output += `root refId: ${rootChangeTree.refId}\n`;
391
+ output += `root refId: ${rootChangeTree.ref[$refId]}\n`;
324
392
  output += `Total instances: ${instanceRefIds.length} (refIds: ${instanceRefIds.join(", ")})\n`;
325
393
  output += `Total changes: ${totalOperations}\n`;
326
394
  output += "---\n"
@@ -330,7 +398,7 @@ export class Schema<C = any> implements IRef {
330
398
  for (const [changeTree, parentChangeTrees] of changeTrees.entries()) {
331
399
  parentChangeTrees.forEach((parentChangeTree, level) => {
332
400
  if (!visitedParents.has(parentChangeTree)) {
333
- output += `${getIndent(level)}${parentChangeTree.ref.constructor.name} (refId: ${parentChangeTree.refId})\n`;
401
+ output += `${getIndent(level)}${parentChangeTree.ref.constructor.name} (refId: ${parentChangeTree.ref[$refId]})\n`;
334
402
  visitedParents.add(parentChangeTree);
335
403
  }
336
404
  });
@@ -340,7 +408,7 @@ export class Schema<C = any> implements IRef {
340
408
  const indent = getIndent(level);
341
409
 
342
410
  const parentIndex = (level > 0) ? `(${changeTree.parentIndex}) ` : "";
343
- output += `${indent}${parentIndex}${changeTree.ref.constructor.name} (refId: ${changeTree.refId}) - changes: ${Object.keys(changes).length}\n`;
411
+ output += `${indent}${parentIndex}${changeTree.ref.constructor.name} (refId: ${changeTree.ref[$refId]}) - changes: ${Object.keys(changes).length}\n`;
344
412
 
345
413
  for (const index in changes) {
346
414
  const operation = changes[index];