@colyseus/schema 3.0.20 → 3.0.21
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/build/cjs/index.js +83 -49
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +83 -49
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +83 -49
- package/lib/Reflection.js +69 -41
- package/lib/Reflection.js.map +1 -1
- package/lib/encoder/Encoder.js +5 -3
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/types/TypeContext.d.ts +2 -0
- package/lib/types/TypeContext.js +9 -5
- package/lib/types/TypeContext.js.map +1 -1
- package/package.json +1 -1
- package/src/Reflection.ts +79 -46
- package/src/encoder/Encoder.ts +5 -3
- package/src/types/TypeContext.ts +10 -5
package/src/Reflection.ts
CHANGED
|
@@ -44,71 +44,104 @@ export class Reflection extends Schema {
|
|
|
44
44
|
const rootType = context.schemas.get(encoder.state.constructor);
|
|
45
45
|
if (rootType > 0) { reflection.rootType = rootType; }
|
|
46
46
|
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
47
|
+
const includedTypeIds = new Set<number>();
|
|
48
|
+
const pendingReflectionTypes: { [typeid: number]: ReflectionType[] } = {};
|
|
49
|
+
|
|
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);
|
|
55
|
+
|
|
56
|
+
reflection.types.push(type);
|
|
57
|
+
|
|
58
|
+
const deps = pendingReflectionTypes[type.id];
|
|
59
|
+
if (deps !== undefined) {
|
|
60
|
+
delete pendingReflectionTypes[type.id];
|
|
61
|
+
deps.forEach((childType) => addType(childType));
|
|
55
62
|
}
|
|
63
|
+
} else {
|
|
64
|
+
if (pendingReflectionTypes[type.extendsId] === undefined) {
|
|
65
|
+
pendingReflectionTypes[type.extendsId] = [];
|
|
66
|
+
}
|
|
67
|
+
pendingReflectionTypes[type.extendsId].push(type);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
56
70
|
|
|
57
|
-
|
|
58
|
-
|
|
71
|
+
context.schemas.forEach((typeid, klass) => {
|
|
72
|
+
const type = new ReflectionType();
|
|
73
|
+
type.id = Number(typeid);
|
|
59
74
|
|
|
60
|
-
|
|
75
|
+
// support inheritance
|
|
76
|
+
const inheritFrom = Object.getPrototypeOf(klass);
|
|
77
|
+
if (inheritFrom !== Schema) {
|
|
78
|
+
type.extendsId = context.schemas.get(inheritFrom);
|
|
79
|
+
}
|
|
61
80
|
|
|
62
|
-
|
|
81
|
+
const metadata = klass[Symbol.metadata];
|
|
63
82
|
|
|
64
|
-
|
|
65
|
-
|
|
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;
|
|
66
91
|
|
|
67
|
-
|
|
68
|
-
|
|
92
|
+
// skip fields from parent classes
|
|
93
|
+
if (!Object.prototype.hasOwnProperty.call(metadata, fieldName)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const reflectionField = new ReflectionField();
|
|
98
|
+
reflectionField.name = fieldName;
|
|
99
|
+
|
|
100
|
+
let fieldType: string;
|
|
69
101
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
fieldType = "ref";
|
|
75
|
-
childTypeSchema = type as typeof Schema;
|
|
102
|
+
const field = metadata[index];
|
|
103
|
+
|
|
104
|
+
if (typeof (field.type) === "string") {
|
|
105
|
+
fieldType = field.type;
|
|
76
106
|
|
|
77
107
|
} else {
|
|
78
|
-
|
|
108
|
+
let childTypeSchema: typeof Schema;
|
|
79
109
|
|
|
80
|
-
|
|
81
|
-
|
|
110
|
+
//
|
|
111
|
+
// TODO: refactor below.
|
|
112
|
+
//
|
|
113
|
+
if (Schema.is(field.type)) {
|
|
114
|
+
fieldType = "ref";
|
|
115
|
+
childTypeSchema = field.type as typeof Schema;
|
|
82
116
|
|
|
83
117
|
} else {
|
|
84
|
-
|
|
118
|
+
fieldType = Object.keys(field.type)[0];
|
|
119
|
+
|
|
120
|
+
if (typeof (field.type[fieldType]) === "string") {
|
|
121
|
+
fieldType += ":" + field.type[fieldType]; // array:string
|
|
122
|
+
|
|
123
|
+
} else {
|
|
124
|
+
childTypeSchema = field.type[fieldType];
|
|
125
|
+
}
|
|
85
126
|
}
|
|
127
|
+
|
|
128
|
+
reflectionField.referencedType = (childTypeSchema)
|
|
129
|
+
? context.getTypeId(childTypeSchema)
|
|
130
|
+
: -1;
|
|
86
131
|
}
|
|
87
132
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
: -1;
|
|
133
|
+
reflectionField.type = fieldType;
|
|
134
|
+
type.fields.push(reflectionField);
|
|
91
135
|
}
|
|
92
|
-
|
|
93
|
-
field.type = fieldType;
|
|
94
|
-
currentType.fields.push(field);
|
|
95
136
|
}
|
|
96
137
|
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
for (let typeid in context.types) {
|
|
101
|
-
const klass = context.types[typeid];
|
|
102
|
-
const type = new ReflectionType();
|
|
103
|
-
type.id = Number(typeid);
|
|
104
|
-
|
|
105
|
-
// support inheritance
|
|
106
|
-
const inheritFrom = Object.getPrototypeOf(klass);
|
|
107
|
-
if (inheritFrom !== Schema) {
|
|
108
|
-
type.extendsId = context.schemas.get(inheritFrom);
|
|
109
|
-
}
|
|
138
|
+
addType(type);
|
|
139
|
+
});
|
|
110
140
|
|
|
111
|
-
|
|
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))
|
|
112
145
|
}
|
|
113
146
|
|
|
114
147
|
const buf = reflectionEncoder.encodeAll(it);
|
package/src/encoder/Encoder.ts
CHANGED
|
@@ -23,10 +23,12 @@ export class Encoder<T extends Schema = any> {
|
|
|
23
23
|
|
|
24
24
|
constructor(state: T) {
|
|
25
25
|
//
|
|
26
|
-
//
|
|
27
|
-
// (to avoid creating a new context for every new room)
|
|
26
|
+
// Use .cache() here to avoid re-creating a new context for every new room instance.
|
|
28
27
|
//
|
|
29
|
-
this
|
|
28
|
+
// We may need to make this optional in case of dynamically created
|
|
29
|
+
// schemas - which would lead to memory leaks
|
|
30
|
+
//
|
|
31
|
+
this.context = TypeContext.cache(state.constructor as typeof Schema);
|
|
30
32
|
this.root = new Root(this.context);
|
|
31
33
|
|
|
32
34
|
this.setState(state);
|
package/src/types/TypeContext.ts
CHANGED
|
@@ -14,6 +14,7 @@ export class TypeContext {
|
|
|
14
14
|
* Keeps track of which classes extends which. (parent -> children)
|
|
15
15
|
*/
|
|
16
16
|
static inheritedTypes = new Map<typeof Schema, Set<typeof Schema>>();
|
|
17
|
+
static cachedContexts = new Map<typeof Schema, TypeContext>();
|
|
17
18
|
|
|
18
19
|
static register(target: typeof Schema) {
|
|
19
20
|
const parent = Object.getPrototypeOf(target);
|
|
@@ -27,13 +28,17 @@ export class TypeContext {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
static cache (rootClass: typeof Schema) {
|
|
32
|
+
let context = TypeContext.cachedContexts.get(rootClass);
|
|
33
|
+
if (!context) {
|
|
34
|
+
context = new TypeContext(rootClass);
|
|
35
|
+
TypeContext.cachedContexts.set(rootClass, context);
|
|
36
|
+
}
|
|
37
|
+
return context;
|
|
38
|
+
}
|
|
39
|
+
|
|
30
40
|
constructor(rootClass?: typeof Schema) {
|
|
31
41
|
if (rootClass) {
|
|
32
|
-
//
|
|
33
|
-
// TODO:
|
|
34
|
-
// cache "discoverTypes" results for each rootClass
|
|
35
|
-
// to avoid re-discovering types for each new context/room
|
|
36
|
-
//
|
|
37
42
|
this.discoverTypes(rootClass);
|
|
38
43
|
}
|
|
39
44
|
}
|