@colyseus/schema 5.0.6 → 5.0.8
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/Reflection.d.ts +53 -0
- package/build/Schema.d.ts +26 -1
- package/build/annotations.d.ts +8 -1
- package/build/codegen/cli.cjs +74 -64
- package/build/codegen/cli.cjs.map +1 -1
- package/build/codegen/types.d.ts +0 -1
- package/build/decoder/Decoder.d.ts +28 -0
- package/build/decoder/Resync.d.ts +61 -0
- package/build/encoder/ChangeTree.d.ts +15 -0
- package/build/encoder/Encoder.d.ts +13 -0
- package/build/encoder/Pool.d.ts +62 -0
- package/build/encoder/Root.d.ts +5 -4
- package/build/encoder/StateView.d.ts +12 -3
- package/build/index.cjs +1192 -284
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +3 -0
- package/build/index.js +1192 -284
- package/build/index.mjs +1189 -285
- package/build/index.mjs.map +1 -1
- package/build/input/InputDecoder.d.ts +9 -4
- package/build/input/InputEncoder.d.ts +44 -53
- package/build/input/index.cjs +102 -7321
- package/build/input/index.cjs.map +1 -1
- package/build/input/index.mjs +97 -7316
- package/build/input/index.mjs.map +1 -1
- package/build/types/HelperTypes.d.ts +3 -0
- package/build/types/builder.d.ts +57 -4
- package/build/types/custom/ArraySchema.d.ts +11 -1
- package/build/types/custom/CollectionSchema.d.ts +9 -1
- package/build/types/custom/MapSchema.d.ts +9 -1
- package/build/types/custom/SetSchema.d.ts +9 -1
- package/build/types/custom/StreamSchema.d.ts +2 -1
- package/build/types/quantize.d.ts +102 -0
- package/build/types/symbols.d.ts +15 -0
- package/package.json +8 -1
- package/src/Metadata.ts +34 -9
- package/src/Reflection.ts +49 -11
- package/src/Schema.ts +64 -2
- package/src/annotations.ts +133 -51
- package/src/bench_churn.ts +121 -0
- package/src/codegen/languages/haxe.ts +0 -16
- package/src/codegen/parser.ts +29 -11
- package/src/codegen/types.ts +45 -63
- package/src/decoder/DecodeOperation.ts +46 -4
- package/src/decoder/Decoder.ts +48 -0
- package/src/decoder/ReferenceTracker.ts +9 -5
- package/src/decoder/Resync.ts +170 -0
- package/src/encoder/ChangeTree.ts +59 -0
- package/src/encoder/Encoder.ts +53 -12
- package/src/encoder/Pool.ts +90 -0
- package/src/encoder/Root.ts +22 -32
- package/src/encoder/StateView.ts +101 -50
- package/src/encoder/changeTree/liveIteration.ts +4 -0
- package/src/encoder/changeTree/treeAttachment.ts +28 -24
- package/src/index.ts +11 -1
- package/src/input/InputDecoder.ts +11 -5
- package/src/input/InputEncoder.ts +85 -126
- package/src/types/HelperTypes.ts +7 -0
- package/src/types/TypeContext.ts +7 -0
- package/src/types/builder.ts +62 -5
- package/src/types/custom/ArraySchema.ts +70 -12
- package/src/types/custom/CollectionSchema.ts +36 -1
- package/src/types/custom/MapSchema.ts +50 -1
- package/src/types/custom/SetSchema.ts +36 -1
- package/src/types/custom/StreamSchema.ts +7 -0
- package/src/types/quantize.ts +173 -0
- package/src/types/symbols.ts +16 -0
- package/build/encoder/RefIdAllocator.d.ts +0 -35
- package/src/encoder/RefIdAllocator.ts +0 -68
package/build/Reflection.d.ts
CHANGED
|
@@ -45,14 +45,53 @@ interface ReflectionStatic {
|
|
|
45
45
|
/**
|
|
46
46
|
* Reflection
|
|
47
47
|
*/
|
|
48
|
+
/**
|
|
49
|
+
* `t.quantized()` field descriptor as it rides the reflection handshake —
|
|
50
|
+
* schema-typed (bit-exact float64 bounds), NOT a string grammar, so every
|
|
51
|
+
* language port decodes it with the schema decoder it already has.
|
|
52
|
+
*/
|
|
53
|
+
export declare const QuantizedDescriptor: import("./annotations.js").SchemaWithExtendsConstructor<{
|
|
54
|
+
min: FieldBuilder<number, false, false>;
|
|
55
|
+
max: FieldBuilder<number, false, false>;
|
|
56
|
+
bits: FieldBuilder<number, false, false>;
|
|
57
|
+
mode: FieldBuilder<number, false, false>;
|
|
58
|
+
}, import("./index.js").BuilderInitProps<{
|
|
59
|
+
min: FieldBuilder<number, false, false>;
|
|
60
|
+
max: FieldBuilder<number, false, false>;
|
|
61
|
+
bits: FieldBuilder<number, false, false>;
|
|
62
|
+
mode: FieldBuilder<number, false, false>;
|
|
63
|
+
}>, typeof Schema>;
|
|
64
|
+
export type QuantizedDescriptor = SchemaType<typeof QuantizedDescriptor>;
|
|
48
65
|
export declare const ReflectionField: import("./annotations.js").SchemaWithExtendsConstructor<{
|
|
49
66
|
name: FieldBuilder<string, false, false>;
|
|
50
67
|
type: FieldBuilder<string, false, false>;
|
|
51
68
|
referencedType: FieldBuilder<number, false, false>;
|
|
69
|
+
/** Primitive child of a collection (`array`/`map`/... of "string" etc.) —
|
|
70
|
+
* its own slot, replacing the legacy `"array:string"` colon packing. */
|
|
71
|
+
childPrimitive: FieldBuilder<string, false, false>;
|
|
72
|
+
/** Set only on `t.quantized()` fields (`.optional()` — no auto-instantiated
|
|
73
|
+
* default; its absence is the "not quantized" signal on decode). */
|
|
74
|
+
quantized: FieldBuilder<{} & {
|
|
75
|
+
min?: number;
|
|
76
|
+
max?: number;
|
|
77
|
+
bits?: number;
|
|
78
|
+
mode?: number;
|
|
79
|
+
} & Schema<any> & Schema<unknown>, false, true>;
|
|
52
80
|
}, import("./index.js").BuilderInitProps<{
|
|
53
81
|
name: FieldBuilder<string, false, false>;
|
|
54
82
|
type: FieldBuilder<string, false, false>;
|
|
55
83
|
referencedType: FieldBuilder<number, false, false>;
|
|
84
|
+
/** Primitive child of a collection (`array`/`map`/... of "string" etc.) —
|
|
85
|
+
* its own slot, replacing the legacy `"array:string"` colon packing. */
|
|
86
|
+
childPrimitive: FieldBuilder<string, false, false>;
|
|
87
|
+
/** Set only on `t.quantized()` fields (`.optional()` — no auto-instantiated
|
|
88
|
+
* default; its absence is the "not quantized" signal on decode). */
|
|
89
|
+
quantized: FieldBuilder<{} & {
|
|
90
|
+
min?: number;
|
|
91
|
+
max?: number;
|
|
92
|
+
bits?: number;
|
|
93
|
+
mode?: number;
|
|
94
|
+
} & Schema<any> & Schema<unknown>, false, true>;
|
|
56
95
|
}>, typeof Schema>;
|
|
57
96
|
export type ReflectionField = SchemaType<typeof ReflectionField>;
|
|
58
97
|
export declare const ReflectionType: import("./annotations.js").SchemaWithExtendsConstructor<{
|
|
@@ -61,7 +100,14 @@ export declare const ReflectionType: import("./annotations.js").SchemaWithExtend
|
|
|
61
100
|
fields: FieldBuilder<ArraySchema<{} & {
|
|
62
101
|
name?: string;
|
|
63
102
|
type?: string;
|
|
103
|
+
quantized?: {} & {
|
|
104
|
+
min?: number;
|
|
105
|
+
max?: number;
|
|
106
|
+
bits?: number;
|
|
107
|
+
mode?: number;
|
|
108
|
+
} & Schema<any> & Schema<unknown>;
|
|
64
109
|
referencedType?: number;
|
|
110
|
+
childPrimitive?: string;
|
|
65
111
|
} & Schema<any> & Schema<unknown>>, true, false>;
|
|
66
112
|
}, import("./index.js").BuilderInitProps<{
|
|
67
113
|
id: FieldBuilder<number, false, false>;
|
|
@@ -69,7 +115,14 @@ export declare const ReflectionType: import("./annotations.js").SchemaWithExtend
|
|
|
69
115
|
fields: FieldBuilder<ArraySchema<{} & {
|
|
70
116
|
name?: string;
|
|
71
117
|
type?: string;
|
|
118
|
+
quantized?: {} & {
|
|
119
|
+
min?: number;
|
|
120
|
+
max?: number;
|
|
121
|
+
bits?: number;
|
|
122
|
+
mode?: number;
|
|
123
|
+
} & Schema<any> & Schema<unknown>;
|
|
72
124
|
referencedType?: number;
|
|
125
|
+
childPrimitive?: string;
|
|
73
126
|
} & Schema<any> & Schema<unknown>>, true, false>;
|
|
74
127
|
}>, typeof Schema>;
|
|
75
128
|
export type ReflectionType = SchemaType<typeof ReflectionType>;
|
package/build/Schema.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { OPERATION } from './encoding/spec.js';
|
|
|
2
2
|
import { type DefinitionType } from "./annotations.js";
|
|
3
3
|
import { AssignableProps, NonFunctionPropNames, ToJSON } from './types/HelperTypes.js';
|
|
4
4
|
import { ChangeTree, IRef, Ref } from './encoder/ChangeTree.js';
|
|
5
|
-
import { $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $refId, $track, $values } from './types/symbols.js';
|
|
5
|
+
import { $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $refId, $reset, $track, $values } from './types/symbols.js';
|
|
6
6
|
import { StateView } from './encoder/StateView.js';
|
|
7
7
|
import type { Decoder } from './decoder/Decoder.js';
|
|
8
8
|
import type { Metadata } from './Metadata.js';
|
|
@@ -37,6 +37,31 @@ export declare class Schema<C = any> implements IRef {
|
|
|
37
37
|
static initializeForDecoder<T extends Schema = Schema>(this: {
|
|
38
38
|
prototype: T;
|
|
39
39
|
} & typeof Schema): T;
|
|
40
|
+
/**
|
|
41
|
+
* Reset a DETACHED instance to construction defaults so it can be returned
|
|
42
|
+
* to a {@link SchemaPool} and reused, avoiding the cost of `new`. Recurses
|
|
43
|
+
* into ref-type fields (child Schemas / collections).
|
|
44
|
+
*
|
|
45
|
+
* Preconditions (enforced):
|
|
46
|
+
* - The instance must be tracked (encoder-side), not a decoder mirror.
|
|
47
|
+
* - The instance must NOT be shared across multiple parents.
|
|
48
|
+
* - The instance must already be removed from its parent collection/field
|
|
49
|
+
* (so the encoder detached it: `root === undefined`).
|
|
50
|
+
*
|
|
51
|
+
* NOTE: primitive field values are NOT reset to class defaults — re-assign
|
|
52
|
+
* the fields you care about when you reuse the instance (standard
|
|
53
|
+
* object-pool discipline).
|
|
54
|
+
*/
|
|
55
|
+
static reset(instance: Schema): void;
|
|
56
|
+
/**
|
|
57
|
+
* Per-instance reset primitive (the recursive worker behind
|
|
58
|
+
* {@link Schema.reset}). Resets ref-type children first (depth-first),
|
|
59
|
+
* then recycles this instance's ChangeTree and drops its `$refId` so a
|
|
60
|
+
* re-add is assigned a fresh refId exactly like a freshly constructed
|
|
61
|
+
* instance. Dropping `$refId` is what makes instance reuse
|
|
62
|
+
* wire-format-identical to `new T()`.
|
|
63
|
+
*/
|
|
64
|
+
[$reset](): void;
|
|
40
65
|
/**
|
|
41
66
|
* Check whether `type` describes a Schema *class* (a subclass
|
|
42
67
|
* constructor carrying `Symbol.metadata`, as installed by `@type`).
|
package/build/annotations.d.ts
CHANGED
|
@@ -55,7 +55,14 @@ export interface TypeOptions {
|
|
|
55
55
|
manual?: boolean;
|
|
56
56
|
}
|
|
57
57
|
export declare const DEFAULT_VIEW_TAG = -1;
|
|
58
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Class decorator that registers a `@type`-style Schema class with the
|
|
60
|
+
* TypeContext (required for reflection / cross-language codegen).
|
|
61
|
+
*
|
|
62
|
+
* @entity
|
|
63
|
+
* class Player extends Schema { ... }
|
|
64
|
+
*/
|
|
65
|
+
export declare function entity<T extends Function>(constructor: T): T;
|
|
59
66
|
/**
|
|
60
67
|
* [See documentation](https://docs.colyseus.io/state/schema/)
|
|
61
68
|
*
|
package/build/codegen/cli.cjs
CHANGED
|
@@ -84,21 +84,11 @@ class Context {
|
|
|
84
84
|
interfaces = [];
|
|
85
85
|
enums = [];
|
|
86
86
|
getStructures() {
|
|
87
|
+
// `isSchemaClass` already walks the full ancestor chain, so a class is
|
|
88
|
+
// emitted iff it (or any ancestor) descends from Schema — no need to
|
|
89
|
+
// re-walk parents here.
|
|
87
90
|
return {
|
|
88
|
-
classes: this.classes.filter(klass =>
|
|
89
|
-
if (this.isSchemaClass(klass)) {
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
let parentClass = klass;
|
|
94
|
-
while (parentClass = this.getParentClass(parentClass)) {
|
|
95
|
-
if (this.isSchemaClass(parentClass)) {
|
|
96
|
-
return true;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return false;
|
|
101
|
-
}),
|
|
91
|
+
classes: this.classes.filter(klass => this.isSchemaClass(klass)),
|
|
102
92
|
interfaces: this.interfaces,
|
|
103
93
|
enums: this.enums,
|
|
104
94
|
};
|
|
@@ -118,30 +108,25 @@ class Context {
|
|
|
118
108
|
this.enums.push(structure);
|
|
119
109
|
}
|
|
120
110
|
}
|
|
121
|
-
getParentClass(klass) {
|
|
122
|
-
return this.classes.find(c => c.name === klass.extends);
|
|
123
|
-
}
|
|
124
111
|
isSchemaClass(klass) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
klass.extends = "Schema";
|
|
112
|
+
// True if `klass` or any ancestor extends Schema (directly or via the
|
|
113
|
+
// `schema.Schema` / `Schema.Schema` aliases).
|
|
114
|
+
//
|
|
115
|
+
// TODO: ideally we should check for the actual @colyseus/schema module
|
|
116
|
+
// reference rather than arbitrary strings.
|
|
117
|
+
for (const current of [klass, ...eachAncestor(klass, this.classes)]) {
|
|
118
|
+
const isSchema = (current.extends === "Schema" ||
|
|
119
|
+
current.extends === "schema.Schema" ||
|
|
120
|
+
current.extends === "Schema.Schema");
|
|
121
|
+
if (isSchema) {
|
|
122
|
+
// Normalize a `schema.Schema`-style base on the queried class itself.
|
|
123
|
+
if (current === klass) {
|
|
124
|
+
klass.extends = "Schema";
|
|
125
|
+
}
|
|
126
|
+
return true;
|
|
141
127
|
}
|
|
142
|
-
currentClass = this.getParentClass(currentClass);
|
|
143
128
|
}
|
|
144
|
-
return
|
|
129
|
+
return false;
|
|
145
130
|
}
|
|
146
131
|
}
|
|
147
132
|
class Interface {
|
|
@@ -170,14 +155,11 @@ class Class {
|
|
|
170
155
|
this.properties.push(property);
|
|
171
156
|
}
|
|
172
157
|
postProcessing() {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
let parentKlass = this;
|
|
177
|
-
while (parentKlass &&
|
|
178
|
-
(parentKlass = this.context.classes.find(k => k.name === parentKlass.extends))) {
|
|
158
|
+
// Offset each property's `index` by the field count of every ancestor,
|
|
159
|
+
// so indexes stay correct across inheritance.
|
|
160
|
+
for (const parent of eachAncestor(this, this.context.classes)) {
|
|
179
161
|
this.properties.forEach(prop => {
|
|
180
|
-
prop.index +=
|
|
162
|
+
prop.index += parent.properties.length;
|
|
181
163
|
});
|
|
182
164
|
}
|
|
183
165
|
}
|
|
@@ -197,17 +179,31 @@ class Property {
|
|
|
197
179
|
childType;
|
|
198
180
|
deprecated;
|
|
199
181
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Walk `klass`'s `extends` chain, parent-first, yielding each ancestor class
|
|
184
|
+
* (not `klass` itself). The single safe ancestor traversal every inheritance
|
|
185
|
+
* query is built on: it stops at the Schema root, an unresolved base, or a
|
|
186
|
+
* cycle — so a malformed class graph can never spin forever. This is why the
|
|
187
|
+
* `seen` cycle-guard lives here and nowhere else.
|
|
188
|
+
*/
|
|
189
|
+
function* eachAncestor(klass, allClasses) {
|
|
190
|
+
const seen = new Set([klass]);
|
|
191
|
+
let current = klass;
|
|
192
|
+
while (current.extends && current.extends !== "Schema") {
|
|
193
|
+
const parent = allClasses.find(c => c.name === current.extends);
|
|
194
|
+
if (!parent || seen.has(parent)) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
seen.add(parent);
|
|
198
|
+
yield parent;
|
|
199
|
+
current = parent;
|
|
209
200
|
}
|
|
210
|
-
|
|
201
|
+
}
|
|
202
|
+
function getInheritanceTree(klass, allClasses, includeSelf = true) {
|
|
203
|
+
return [
|
|
204
|
+
...(includeSelf ? [klass] : []),
|
|
205
|
+
...eachAncestor(klass, allClasses),
|
|
206
|
+
];
|
|
211
207
|
}
|
|
212
208
|
|
|
213
209
|
let currentStructure;
|
|
@@ -442,7 +438,7 @@ function inspectNode(node, context, decoratorName) {
|
|
|
442
438
|
if (!callee)
|
|
443
439
|
break;
|
|
444
440
|
const isSchemaCall = callee === "schema" || callee === "schema.schema";
|
|
445
|
-
const isExtendCall = callee.
|
|
441
|
+
const isExtendCall = callee.endsWith(".extend");
|
|
446
442
|
if (!isSchemaCall && !isExtendCall)
|
|
447
443
|
break;
|
|
448
444
|
// Signature: (fields, name?)
|
|
@@ -460,24 +456,38 @@ function inspectNode(node, context, decoratorName) {
|
|
|
460
456
|
className = nameArg.getText();
|
|
461
457
|
}
|
|
462
458
|
}
|
|
463
|
-
if (!className
|
|
464
|
-
|
|
459
|
+
if (!className) {
|
|
460
|
+
// No explicit name arg — infer it from the variable the
|
|
461
|
+
// result is assigned to (`const Foo = schema({...})`).
|
|
462
|
+
let p = callExpression.parent;
|
|
463
|
+
while (p !== undefined && (p.kind === ts__namespace.SyntaxKind.PropertyAccessExpression ||
|
|
464
|
+
p.kind === ts__namespace.SyntaxKind.CallExpression)) {
|
|
465
|
+
p = p.parent;
|
|
466
|
+
}
|
|
467
|
+
if (p?.kind === ts__namespace.SyntaxKind.VariableDeclaration) {
|
|
468
|
+
className = p.name?.getText();
|
|
469
|
+
}
|
|
465
470
|
}
|
|
466
471
|
if (!className)
|
|
467
472
|
break;
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
473
|
+
// Resolve the base class BEFORE registering a structure. A
|
|
474
|
+
// chained `schema({...}).extend({...})` has a call expression
|
|
475
|
+
// (not an identifier) as its `.extend` base, which can't be
|
|
476
|
+
// statically named — bail here rather than leave a half-formed,
|
|
477
|
+
// nameless Class in the context (which corrupts inheritance walks).
|
|
478
|
+
let extendsClass = "Schema";
|
|
472
479
|
if (isExtendCall) {
|
|
473
|
-
|
|
474
|
-
if (!extendsClass)
|
|
480
|
+
extendsClass = node.expression?.expression?.escapedText;
|
|
481
|
+
if (!extendsClass) {
|
|
482
|
+
console.warn(`schema-codegen: cannot resolve the base class of a chained .extend() for '${className}' — fields from that .extend({...}) are omitted.`);
|
|
475
483
|
break;
|
|
476
|
-
|
|
484
|
+
}
|
|
477
485
|
}
|
|
478
|
-
|
|
479
|
-
currentStructure
|
|
486
|
+
if (currentStructure?.name !== className) {
|
|
487
|
+
currentStructure = new Class();
|
|
488
|
+
context.addStructure(currentStructure);
|
|
480
489
|
}
|
|
490
|
+
currentStructure.extends = extendsClass;
|
|
481
491
|
currentStructure.name = className;
|
|
482
492
|
const types = fieldsArg;
|
|
483
493
|
for (let i = 0; i < types.properties.length; i++) {
|