@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.
- package/README.md +148 -62
- package/bin/schema-debug +94 -0
- package/build/cjs/index.js +2227 -1519
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +2228 -1522
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +2230 -1522
- package/lib/Metadata.d.ts +21 -9
- package/lib/Metadata.js +169 -32
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.d.ts +19 -4
- package/lib/Reflection.js +66 -31
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +12 -5
- package/lib/Schema.js +57 -56
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +31 -34
- package/lib/annotations.js +110 -160
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.d.ts +1 -0
- package/lib/bench_encode.js +130 -0
- package/lib/bench_encode.js.map +1 -0
- package/lib/codegen/api.js +1 -2
- package/lib/codegen/api.js.map +1 -1
- package/lib/codegen/languages/cpp.js +1 -2
- package/lib/codegen/languages/cpp.js.map +1 -1
- package/lib/codegen/languages/csharp.js +9 -46
- package/lib/codegen/languages/csharp.js.map +1 -1
- package/lib/codegen/languages/haxe.js +4 -2
- package/lib/codegen/languages/haxe.js.map +1 -1
- package/lib/codegen/languages/java.js +1 -2
- package/lib/codegen/languages/java.js.map +1 -1
- package/lib/codegen/languages/js.js +1 -2
- package/lib/codegen/languages/js.js.map +1 -1
- package/lib/codegen/languages/lua.js +23 -25
- package/lib/codegen/languages/lua.js.map +1 -1
- package/lib/codegen/languages/ts.js +1 -2
- package/lib/codegen/languages/ts.js.map +1 -1
- package/lib/codegen/parser.js +85 -3
- package/lib/codegen/parser.js.map +1 -1
- package/lib/codegen/types.js +6 -3
- package/lib/codegen/types.js.map +1 -1
- package/lib/debug.d.ts +1 -0
- package/lib/debug.js +51 -0
- package/lib/debug.js.map +1 -0
- package/lib/decoder/DecodeOperation.d.ts +3 -4
- package/lib/decoder/DecodeOperation.js +35 -17
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/Decoder.d.ts +5 -6
- package/lib/decoder/Decoder.js +10 -10
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/decoder/ReferenceTracker.js +4 -2
- package/lib/decoder/ReferenceTracker.js.map +1 -1
- package/lib/decoder/strategy/RawChanges.js +1 -2
- package/lib/decoder/strategy/RawChanges.js.map +1 -1
- package/lib/decoder/strategy/StateCallbacks.d.ts +44 -11
- package/lib/decoder/strategy/StateCallbacks.js +74 -64
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +28 -20
- package/lib/encoder/ChangeTree.js +242 -188
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +3 -6
- package/lib/encoder/EncodeOperation.js +51 -65
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +8 -7
- package/lib/encoder/Encoder.js +133 -85
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +22 -0
- package/lib/encoder/Root.js +81 -0
- package/lib/encoder/Root.js.map +1 -0
- package/lib/encoder/StateView.d.ts +7 -7
- package/lib/encoder/StateView.js +72 -74
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/assert.d.ts +7 -6
- package/lib/encoding/assert.js +13 -5
- package/lib/encoding/assert.js.map +1 -1
- package/lib/encoding/decode.d.ts +36 -19
- package/lib/encoding/decode.js +54 -84
- package/lib/encoding/decode.js.map +1 -1
- package/lib/encoding/encode.d.ts +36 -18
- package/lib/encoding/encode.js +61 -48
- package/lib/encoding/encode.js.map +1 -1
- package/lib/encoding/spec.d.ts +4 -5
- package/lib/encoding/spec.js +1 -2
- package/lib/encoding/spec.js.map +1 -1
- package/lib/index.d.ts +10 -9
- package/lib/index.js +24 -17
- package/lib/index.js.map +1 -1
- package/lib/types/HelperTypes.d.ts +34 -2
- package/lib/types/HelperTypes.js.map +1 -1
- package/lib/types/TypeContext.d.ts +29 -0
- package/lib/types/TypeContext.js +151 -0
- package/lib/types/TypeContext.js.map +1 -0
- package/lib/types/custom/ArraySchema.d.ts +2 -2
- package/lib/types/custom/ArraySchema.js +33 -22
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.d.ts +2 -2
- package/lib/types/custom/CollectionSchema.js +1 -0
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.d.ts +18 -16
- package/lib/types/custom/MapSchema.js +12 -4
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/lib/types/custom/SetSchema.d.ts +2 -2
- package/lib/types/custom/SetSchema.js +1 -0
- package/lib/types/custom/SetSchema.js.map +1 -1
- package/lib/types/registry.d.ts +8 -1
- package/lib/types/registry.js +23 -6
- package/lib/types/registry.js.map +1 -1
- package/lib/types/symbols.d.ts +8 -5
- package/lib/types/symbols.js +9 -6
- package/lib/types/symbols.js.map +1 -1
- package/lib/types/utils.js +1 -2
- package/lib/types/utils.js.map +1 -1
- package/lib/utils.js +9 -7
- package/lib/utils.js.map +1 -1
- package/package.json +19 -18
- package/src/Metadata.ts +190 -42
- package/src/Reflection.ts +76 -38
- package/src/Schema.ts +72 -70
- package/src/annotations.ts +156 -202
- package/src/bench_encode.ts +108 -0
- package/src/codegen/languages/csharp.ts +8 -47
- package/src/codegen/languages/haxe.ts +4 -0
- package/src/codegen/languages/lua.ts +19 -27
- package/src/codegen/parser.ts +107 -0
- package/src/codegen/types.ts +1 -0
- package/src/debug.ts +55 -0
- package/src/decoder/DecodeOperation.ts +43 -15
- package/src/decoder/Decoder.ts +12 -10
- package/src/decoder/ReferenceTracker.ts +5 -3
- package/src/decoder/strategy/StateCallbacks.ts +152 -81
- package/src/encoder/ChangeTree.ts +282 -209
- package/src/encoder/EncodeOperation.ts +78 -78
- package/src/encoder/Encoder.ts +157 -93
- package/src/encoder/Root.ts +93 -0
- package/src/encoder/StateView.ts +80 -88
- package/src/encoding/assert.ts +17 -8
- package/src/encoding/decode.ts +73 -93
- package/src/encoding/encode.ts +76 -45
- package/src/encoding/spec.ts +3 -5
- package/src/index.ts +12 -20
- package/src/types/HelperTypes.ts +54 -2
- package/src/types/TypeContext.ts +175 -0
- package/src/types/custom/ArraySchema.ts +49 -19
- package/src/types/custom/CollectionSchema.ts +1 -0
- package/src/types/custom/MapSchema.ts +30 -17
- package/src/types/custom/SetSchema.ts +1 -0
- package/src/types/registry.ts +22 -3
- package/src/types/symbols.ts +10 -7
- package/src/utils.ts +7 -3
package/src/Metadata.ts
CHANGED
|
@@ -1,134 +1,282 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DefinitionType, getPropertyDescriptor } from "./annotations";
|
|
2
|
+
import { Schema } from "./Schema";
|
|
2
3
|
import { getType } from "./types/registry";
|
|
4
|
+
import { $decoder, $descriptors, $encoder, $fieldIndexesByViewTag, $numFields, $refTypeFieldIndexes, $track, $viewFieldIndexes } from "./types/symbols";
|
|
5
|
+
import { TypeContext } from "./types/TypeContext";
|
|
3
6
|
|
|
4
7
|
export type MetadataField = {
|
|
5
8
|
type: DefinitionType,
|
|
9
|
+
name: string,
|
|
6
10
|
index: number,
|
|
7
11
|
tag?: number,
|
|
8
12
|
unreliable?: boolean,
|
|
9
13
|
deprecated?: boolean,
|
|
10
|
-
descriptor?: PropertyDescriptor,
|
|
11
14
|
};
|
|
12
15
|
|
|
13
16
|
export type Metadata =
|
|
14
|
-
{ [
|
|
15
|
-
{ [
|
|
16
|
-
{ [
|
|
17
|
-
{ [
|
|
18
|
-
{ [field:
|
|
17
|
+
{ [$numFields]: number; } & // number of fields
|
|
18
|
+
{ [$viewFieldIndexes]: number[]; } & // all field indexes with "view" tag
|
|
19
|
+
{ [$fieldIndexesByViewTag]: {[tag: number]: number[]}; } & // field indexes by "view" tag
|
|
20
|
+
{ [$refTypeFieldIndexes]: number[]; } & // all field indexes containing Ref types (Schema, ArraySchema, MapSchema, etc)
|
|
21
|
+
{ [field: number]: MetadataField; } & // index => field name
|
|
22
|
+
{ [field: string]: number; } & // field name => field metadata
|
|
23
|
+
{ [$descriptors]: { [field: string]: PropertyDescriptor } } // property descriptors
|
|
24
|
+
|
|
25
|
+
export function getNormalizedType(type: DefinitionType): DefinitionType {
|
|
26
|
+
return (Array.isArray(type))
|
|
27
|
+
? { array: type[0] }
|
|
28
|
+
: (typeof(type['type']) !== "undefined")
|
|
29
|
+
? type['type']
|
|
30
|
+
: type;
|
|
31
|
+
}
|
|
19
32
|
|
|
20
33
|
export const Metadata = {
|
|
21
34
|
|
|
22
|
-
addField(metadata: any, index: number,
|
|
35
|
+
addField(metadata: any, index: number, name: string, type: DefinitionType, descriptor?: PropertyDescriptor) {
|
|
23
36
|
if (index > 64) {
|
|
24
|
-
throw new Error(`Can't define field '${
|
|
37
|
+
throw new Error(`Can't define field '${name}'.\nSchema instances may only have up to 64 fields.`);
|
|
25
38
|
}
|
|
26
39
|
|
|
27
|
-
metadata[
|
|
28
|
-
metadata[
|
|
40
|
+
metadata[index] = Object.assign(
|
|
41
|
+
metadata[index] || {}, // avoid overwriting previous field metadata (@owned / @deprecated)
|
|
29
42
|
{
|
|
30
|
-
type: (
|
|
31
|
-
? { array: type[0] }
|
|
32
|
-
: type,
|
|
43
|
+
type: getNormalizedType(type),
|
|
33
44
|
index,
|
|
34
|
-
|
|
45
|
+
name,
|
|
35
46
|
}
|
|
36
47
|
);
|
|
37
48
|
|
|
49
|
+
// create "descriptors" map
|
|
50
|
+
Object.defineProperty(metadata, $descriptors, {
|
|
51
|
+
value: metadata[$descriptors] || {},
|
|
52
|
+
enumerable: false,
|
|
53
|
+
configurable: true,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (descriptor) {
|
|
57
|
+
// for encoder
|
|
58
|
+
metadata[$descriptors][name] = descriptor;
|
|
59
|
+
metadata[$descriptors][`_${name}`] = {
|
|
60
|
+
value: undefined,
|
|
61
|
+
writable: true,
|
|
62
|
+
enumerable: false,
|
|
63
|
+
configurable: true,
|
|
64
|
+
};
|
|
65
|
+
} else {
|
|
66
|
+
// for decoder
|
|
67
|
+
metadata[$descriptors][name] = {
|
|
68
|
+
value: undefined,
|
|
69
|
+
writable: true,
|
|
70
|
+
enumerable: true,
|
|
71
|
+
configurable: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
38
75
|
// map -1 as last field index
|
|
39
|
-
Object.defineProperty(metadata,
|
|
76
|
+
Object.defineProperty(metadata, $numFields, {
|
|
40
77
|
value: index,
|
|
41
78
|
enumerable: false,
|
|
42
79
|
configurable: true
|
|
43
80
|
});
|
|
44
81
|
|
|
45
|
-
// map
|
|
46
|
-
Object.defineProperty(metadata,
|
|
47
|
-
value:
|
|
82
|
+
// map field name => index (non enumerable)
|
|
83
|
+
Object.defineProperty(metadata, name, {
|
|
84
|
+
value: index,
|
|
48
85
|
enumerable: false,
|
|
49
86
|
configurable: true,
|
|
50
87
|
});
|
|
88
|
+
|
|
89
|
+
// if child Ref/complex type, add to -4
|
|
90
|
+
if (typeof (metadata[index].type) !== "string") {
|
|
91
|
+
if (metadata[$refTypeFieldIndexes] === undefined) {
|
|
92
|
+
Object.defineProperty(metadata, $refTypeFieldIndexes, {
|
|
93
|
+
value: [],
|
|
94
|
+
enumerable: false,
|
|
95
|
+
configurable: true,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
metadata[$refTypeFieldIndexes].push(index);
|
|
99
|
+
}
|
|
51
100
|
},
|
|
52
101
|
|
|
53
102
|
setTag(metadata: Metadata, fieldName: string, tag: number) {
|
|
103
|
+
const index = metadata[fieldName];
|
|
104
|
+
const field = metadata[index];
|
|
105
|
+
|
|
54
106
|
// add 'tag' to the field
|
|
55
|
-
const field = metadata[fieldName];
|
|
56
107
|
field.tag = tag;
|
|
57
108
|
|
|
58
|
-
if (!metadata[
|
|
109
|
+
if (!metadata[$viewFieldIndexes]) {
|
|
59
110
|
// -2: all field indexes with "view" tag
|
|
60
|
-
Object.defineProperty(metadata,
|
|
111
|
+
Object.defineProperty(metadata, $viewFieldIndexes, {
|
|
61
112
|
value: [],
|
|
62
113
|
enumerable: false,
|
|
63
114
|
configurable: true
|
|
64
115
|
});
|
|
65
116
|
|
|
66
117
|
// -3: field indexes by "view" tag
|
|
67
|
-
Object.defineProperty(metadata,
|
|
118
|
+
Object.defineProperty(metadata, $fieldIndexesByViewTag, {
|
|
68
119
|
value: {},
|
|
69
120
|
enumerable: false,
|
|
70
121
|
configurable: true
|
|
71
122
|
});
|
|
72
123
|
}
|
|
73
124
|
|
|
74
|
-
metadata[
|
|
125
|
+
metadata[$viewFieldIndexes].push(index);
|
|
75
126
|
|
|
76
|
-
if (!metadata[
|
|
77
|
-
metadata[
|
|
127
|
+
if (!metadata[$fieldIndexesByViewTag][tag]) {
|
|
128
|
+
metadata[$fieldIndexesByViewTag][tag] = [];
|
|
78
129
|
}
|
|
79
130
|
|
|
80
|
-
metadata[
|
|
131
|
+
metadata[$fieldIndexesByViewTag][tag].push(index);
|
|
81
132
|
},
|
|
82
133
|
|
|
83
134
|
setFields(target: any, fields: { [field: string]: DefinitionType }) {
|
|
84
|
-
|
|
135
|
+
// for inheritance support
|
|
136
|
+
const constructor = target.prototype.constructor;
|
|
137
|
+
TypeContext.register(constructor);
|
|
138
|
+
|
|
139
|
+
const parentClass = Object.getPrototypeOf(constructor);
|
|
140
|
+
const parentMetadata = parentClass && parentClass[Symbol.metadata];
|
|
141
|
+
const metadata = Metadata.initialize(constructor);
|
|
85
142
|
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
143
|
+
// Use Schema's methods if not defined in the class
|
|
144
|
+
if (!constructor[$track]) { constructor[$track] = Schema[$track]; }
|
|
145
|
+
if (!constructor[$encoder]) { constructor[$encoder] = Schema[$encoder]; }
|
|
146
|
+
if (!constructor[$decoder]) { constructor[$decoder] = Schema[$decoder]; }
|
|
147
|
+
if (!constructor.prototype.toJSON) { constructor.prototype.toJSON = Schema.prototype.toJSON; }
|
|
89
148
|
|
|
90
|
-
//
|
|
91
|
-
//
|
|
149
|
+
//
|
|
150
|
+
// detect index for this field, considering inheritance
|
|
151
|
+
//
|
|
152
|
+
let fieldIndex = metadata[$numFields] // current structure already has fields defined
|
|
153
|
+
?? (parentMetadata && parentMetadata[$numFields]) // parent structure has fields defined
|
|
154
|
+
?? -1; // no fields defined
|
|
92
155
|
|
|
93
|
-
|
|
156
|
+
fieldIndex++;
|
|
94
157
|
|
|
95
|
-
let index = 0;
|
|
96
158
|
for (const field in fields) {
|
|
97
159
|
const type = fields[field];
|
|
160
|
+
const normalizedType = getNormalizedType(type);
|
|
98
161
|
|
|
99
162
|
// FIXME: this code is duplicated from @type() annotation
|
|
100
163
|
const complexTypeKlass = (Array.isArray(type))
|
|
101
164
|
? getType("array")
|
|
102
165
|
: (typeof(Object.keys(type)[0]) === "string") && getType(Object.keys(type)[0]);
|
|
103
166
|
|
|
167
|
+
const childType = (complexTypeKlass)
|
|
168
|
+
? Object.values(type)[0]
|
|
169
|
+
: normalizedType;
|
|
170
|
+
|
|
104
171
|
Metadata.addField(
|
|
105
172
|
metadata,
|
|
106
|
-
|
|
173
|
+
fieldIndex,
|
|
107
174
|
field,
|
|
108
175
|
type,
|
|
109
|
-
getPropertyDescriptor(`_${field}`,
|
|
176
|
+
getPropertyDescriptor(`_${field}`, fieldIndex, childType, complexTypeKlass)
|
|
110
177
|
);
|
|
111
178
|
|
|
112
|
-
|
|
179
|
+
fieldIndex++;
|
|
113
180
|
}
|
|
181
|
+
|
|
182
|
+
return target;
|
|
114
183
|
},
|
|
115
184
|
|
|
116
185
|
isDeprecated(metadata: any, field: string) {
|
|
117
186
|
return metadata[field].deprecated === true;
|
|
118
187
|
},
|
|
119
188
|
|
|
189
|
+
init(klass: any) {
|
|
190
|
+
//
|
|
191
|
+
// Used only to initialize an empty Schema (Encoder#constructor)
|
|
192
|
+
// TODO: remove/refactor this...
|
|
193
|
+
//
|
|
194
|
+
const metadata = {};
|
|
195
|
+
klass[Symbol.metadata] = metadata;
|
|
196
|
+
Object.defineProperty(metadata, $numFields, {
|
|
197
|
+
value: 0,
|
|
198
|
+
enumerable: false,
|
|
199
|
+
configurable: true,
|
|
200
|
+
});
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
initialize(constructor: any) {
|
|
204
|
+
const parentClass = Object.getPrototypeOf(constructor);
|
|
205
|
+
const parentMetadata: Metadata = parentClass[Symbol.metadata];
|
|
206
|
+
|
|
207
|
+
let metadata: Metadata = constructor[Symbol.metadata] ?? Object.create(null);
|
|
208
|
+
|
|
209
|
+
// make sure inherited classes have their own metadata object.
|
|
210
|
+
if (parentClass !== Schema && metadata === parentMetadata) {
|
|
211
|
+
metadata = Object.create(null);
|
|
212
|
+
|
|
213
|
+
if (parentMetadata) {
|
|
214
|
+
//
|
|
215
|
+
// assign parent metadata to current
|
|
216
|
+
//
|
|
217
|
+
Object.setPrototypeOf(metadata, parentMetadata);
|
|
218
|
+
|
|
219
|
+
// $numFields
|
|
220
|
+
Object.defineProperty(metadata, $numFields, {
|
|
221
|
+
value: parentMetadata[$numFields],
|
|
222
|
+
enumerable: false,
|
|
223
|
+
configurable: true,
|
|
224
|
+
writable: true,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// $viewFieldIndexes / $fieldIndexesByViewTag
|
|
228
|
+
if (parentMetadata[$viewFieldIndexes] !== undefined) {
|
|
229
|
+
Object.defineProperty(metadata, $viewFieldIndexes, {
|
|
230
|
+
value: [...parentMetadata[$viewFieldIndexes]],
|
|
231
|
+
enumerable: false,
|
|
232
|
+
configurable: true,
|
|
233
|
+
writable: true,
|
|
234
|
+
});
|
|
235
|
+
Object.defineProperty(metadata, $fieldIndexesByViewTag, {
|
|
236
|
+
value: { ...parentMetadata[$fieldIndexesByViewTag] },
|
|
237
|
+
enumerable: false,
|
|
238
|
+
configurable: true,
|
|
239
|
+
writable: true,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// $refTypeFieldIndexes
|
|
244
|
+
if (parentMetadata[$refTypeFieldIndexes] !== undefined) {
|
|
245
|
+
Object.defineProperty(metadata, $refTypeFieldIndexes, {
|
|
246
|
+
value: [...parentMetadata[$refTypeFieldIndexes]],
|
|
247
|
+
enumerable: false,
|
|
248
|
+
configurable: true,
|
|
249
|
+
writable: true,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// $descriptors
|
|
254
|
+
Object.defineProperty(metadata, $descriptors, {
|
|
255
|
+
value: { ...parentMetadata[$descriptors] },
|
|
256
|
+
enumerable: false,
|
|
257
|
+
configurable: true,
|
|
258
|
+
writable: true,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
constructor[Symbol.metadata] = metadata;
|
|
264
|
+
|
|
265
|
+
return metadata;
|
|
266
|
+
},
|
|
267
|
+
|
|
120
268
|
isValidInstance(klass: any) {
|
|
121
269
|
return (
|
|
122
270
|
klass.constructor[Symbol.metadata] &&
|
|
123
|
-
Object.prototype.hasOwnProperty.call(klass.constructor[Symbol.metadata],
|
|
271
|
+
Object.prototype.hasOwnProperty.call(klass.constructor[Symbol.metadata], $numFields) as boolean
|
|
124
272
|
);
|
|
125
273
|
},
|
|
126
274
|
|
|
127
275
|
getFields(klass: any) {
|
|
128
|
-
const metadata = klass[Symbol.metadata];
|
|
276
|
+
const metadata: Metadata = klass[Symbol.metadata];
|
|
129
277
|
const fields = {};
|
|
130
|
-
for (let i = 0; i <= metadata[
|
|
131
|
-
fields[metadata[i]] = metadata[
|
|
278
|
+
for (let i = 0; i <= metadata[$numFields]; i++) {
|
|
279
|
+
fields[metadata[i].name] = metadata[i].type;
|
|
132
280
|
}
|
|
133
281
|
return fields;
|
|
134
282
|
}
|
package/src/Reflection.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type, PrimitiveType
|
|
1
|
+
import { type, PrimitiveType } from "./annotations";
|
|
2
|
+
import { TypeContext } from "./types/TypeContext";
|
|
2
3
|
import { Metadata } from "./Metadata";
|
|
3
4
|
import { ArraySchema } from "./types/custom/ArraySchema";
|
|
4
5
|
import { Iterator } from "./encoding/decode";
|
|
@@ -22,18 +23,32 @@ export class ReflectionType extends Schema {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export class Reflection extends Schema {
|
|
25
|
-
@type([
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
@type([ReflectionType]) types: ArraySchema<ReflectionType> = new ArraySchema<ReflectionType>();
|
|
27
|
+
@type("number") rootType: number;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Encodes the TypeContext of an Encoder into a buffer.
|
|
31
|
+
*
|
|
32
|
+
* @param encoder Encoder instance
|
|
33
|
+
* @param it
|
|
34
|
+
* @returns
|
|
35
|
+
*/
|
|
36
|
+
static encode(encoder: Encoder, it: Iterator = { offset: 0 }) {
|
|
37
|
+
const context = encoder.context;
|
|
31
38
|
|
|
32
39
|
const reflection = new Reflection();
|
|
33
|
-
const
|
|
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; }
|
|
34
46
|
|
|
35
47
|
const buildType = (currentType: ReflectionType, metadata: Metadata) => {
|
|
36
|
-
for (const
|
|
48
|
+
for (const fieldIndex in metadata) {
|
|
49
|
+
const index = Number(fieldIndex);
|
|
50
|
+
const fieldName = metadata[index].name;
|
|
51
|
+
|
|
37
52
|
// skip fields from parent classes
|
|
38
53
|
if (!Object.prototype.hasOwnProperty.call(metadata, fieldName)) {
|
|
39
54
|
continue;
|
|
@@ -44,7 +59,7 @@ export class Reflection extends Schema {
|
|
|
44
59
|
|
|
45
60
|
let fieldType: string;
|
|
46
61
|
|
|
47
|
-
const type = metadata[
|
|
62
|
+
const type = metadata[index].type;
|
|
48
63
|
|
|
49
64
|
if (typeof (type) === "string") {
|
|
50
65
|
fieldType = type;
|
|
@@ -96,72 +111,95 @@ export class Reflection extends Schema {
|
|
|
96
111
|
buildType(type, klass[Symbol.metadata]);
|
|
97
112
|
}
|
|
98
113
|
|
|
99
|
-
const buf =
|
|
114
|
+
const buf = reflectionEncoder.encodeAll(it);
|
|
100
115
|
return Buffer.from(buf, 0, it.offset);
|
|
101
116
|
}
|
|
102
117
|
|
|
103
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Decodes the TypeContext from a buffer into a Decoder instance.
|
|
120
|
+
*
|
|
121
|
+
* @param bytes Reflection.encode() output
|
|
122
|
+
* @param it
|
|
123
|
+
* @returns Decoder instance
|
|
124
|
+
*/
|
|
125
|
+
static decode<T extends Schema = Schema>(bytes: Buffer, it?: Iterator): Decoder<T> {
|
|
104
126
|
const reflection = new Reflection();
|
|
105
127
|
|
|
106
128
|
const reflectionDecoder = new Decoder(reflection);
|
|
107
129
|
reflectionDecoder.decode(bytes, it);
|
|
108
130
|
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
const schemaTypes = reflection.types.reduce((types, reflectionType) => {
|
|
112
|
-
const parentKlass: typeof Schema = types[reflectionType.extendsId] || Schema;
|
|
113
|
-
const schema: typeof Schema = class _ extends parentKlass {};
|
|
131
|
+
const typeContext = new TypeContext();
|
|
114
132
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
133
|
+
// 1st pass, initialize metadata + inheritance
|
|
134
|
+
reflection.types.forEach((reflectionType) => {
|
|
135
|
+
const parentClass: typeof Schema = typeContext.get(reflectionType.extendsId) ?? Schema;
|
|
136
|
+
const schema: typeof Schema = class _ extends parentClass {};
|
|
118
137
|
|
|
119
138
|
// register for inheritance support
|
|
120
139
|
TypeContext.register(schema);
|
|
121
140
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
context.add(schema, typeid);
|
|
125
|
-
return types;
|
|
126
|
-
}, {});
|
|
141
|
+
// // for inheritance support
|
|
142
|
+
// Metadata.initialize(schema);
|
|
127
143
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const metadata = schemaType[Symbol.metadata];
|
|
131
|
-
|
|
132
|
-
const parentKlass = reflection.types[reflectionType.extendsId];
|
|
133
|
-
const parentFieldIndex = parentKlass && parentKlass.fields.length || 0;
|
|
144
|
+
typeContext.add(schema, reflectionType.id);
|
|
145
|
+
}, {});
|
|
134
146
|
|
|
147
|
+
// define fields
|
|
148
|
+
const addFields = (metadata: Metadata, reflectionType: ReflectionType, parentFieldIndex: number) => {
|
|
135
149
|
reflectionType.fields.forEach((field, i) => {
|
|
136
150
|
const fieldIndex = parentFieldIndex + i;
|
|
137
151
|
|
|
138
152
|
if (field.referencedType !== undefined) {
|
|
139
153
|
let fieldType = field.type;
|
|
140
|
-
let refType =
|
|
154
|
+
let refType: PrimitiveType = typeContext.get(field.referencedType);
|
|
141
155
|
|
|
142
156
|
// map or array of primitive type (-1)
|
|
143
157
|
if (!refType) {
|
|
144
158
|
const typeInfo = field.type.split(":");
|
|
145
159
|
fieldType = typeInfo[0];
|
|
146
|
-
refType = typeInfo[1];
|
|
160
|
+
refType = typeInfo[1] as PrimitiveType; // string
|
|
147
161
|
}
|
|
148
162
|
|
|
149
163
|
if (fieldType === "ref") {
|
|
150
|
-
// type(refType)(schemaType.prototype, field.name);
|
|
151
164
|
Metadata.addField(metadata, fieldIndex, field.name, refType);
|
|
152
165
|
|
|
153
166
|
} else {
|
|
154
|
-
|
|
155
|
-
Metadata.addField(metadata, fieldIndex, field.name, { [fieldType]: refType } as DefinitionType);
|
|
167
|
+
Metadata.addField(metadata, fieldIndex, field.name, { [fieldType]: refType });
|
|
156
168
|
}
|
|
157
169
|
|
|
158
170
|
} else {
|
|
159
|
-
// type(field.type as PrimitiveType)(schemaType.prototype, field.name);
|
|
160
171
|
Metadata.addField(metadata, fieldIndex, field.name, field.type as PrimitiveType);
|
|
161
172
|
}
|
|
162
173
|
});
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// 2nd pass, set fields
|
|
177
|
+
reflection.types.forEach((reflectionType) => {
|
|
178
|
+
const schema = typeContext.get(reflectionType.id);
|
|
179
|
+
|
|
180
|
+
// for inheritance support
|
|
181
|
+
const metadata = Metadata.initialize(schema);
|
|
182
|
+
|
|
183
|
+
const inheritedTypes: ReflectionType[] = [];
|
|
184
|
+
|
|
185
|
+
let parentType: ReflectionType = reflectionType;
|
|
186
|
+
do {
|
|
187
|
+
inheritedTypes.push(parentType);
|
|
188
|
+
parentType = reflection.types.find((t) => t.id === parentType.extendsId);
|
|
189
|
+
} while (parentType);
|
|
190
|
+
|
|
191
|
+
let parentFieldIndex = 0;
|
|
192
|
+
|
|
193
|
+
inheritedTypes.reverse().forEach((reflectionType) => {
|
|
194
|
+
// add fields from all inherited classes
|
|
195
|
+
// TODO: refactor this to avoid adding fields from parent classes
|
|
196
|
+
addFields(metadata, reflectionType, parentFieldIndex);
|
|
197
|
+
parentFieldIndex += reflectionType.fields.length;
|
|
198
|
+
});
|
|
163
199
|
});
|
|
164
200
|
|
|
165
|
-
|
|
201
|
+
const state: T = new (typeContext.get(reflection.rootType || 0) as unknown as any)();
|
|
202
|
+
|
|
203
|
+
return new Decoder<T>(state, typeContext);
|
|
166
204
|
}
|
|
167
205
|
}
|