@colyseus/schema 3.0.0-alpha.30 → 3.0.0-alpha.32
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 +389 -354
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +389 -354
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +389 -354
- package/lib/Metadata.d.ts +14 -5
- package/lib/Metadata.js +49 -20
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.js +4 -13
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.js +26 -39
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +1 -2
- package/lib/annotations.js +58 -52
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.js +25 -22
- package/lib/bench_encode.js.map +1 -1
- package/lib/decoder/DecodeOperation.js +7 -9
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/ReferenceTracker.js +3 -2
- package/lib/decoder/ReferenceTracker.js.map +1 -1
- package/lib/decoder/strategy/StateCallbacks.js +4 -3
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +8 -7
- package/lib/encoder/ChangeTree.js +135 -117
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +1 -4
- package/lib/encoder/EncodeOperation.js +17 -47
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.js +18 -6
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +2 -2
- package/lib/encoder/Root.js +18 -6
- package/lib/encoder/Root.js.map +1 -1
- package/lib/encoder/StateView.js +3 -3
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/assert.d.ts +2 -1
- package/lib/encoding/assert.js +2 -2
- package/lib/encoding/assert.js.map +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.js +11 -10
- package/lib/index.js.map +1 -1
- package/lib/types/TypeContext.js +7 -14
- package/lib/types/TypeContext.js.map +1 -1
- package/lib/types/custom/ArraySchema.js +6 -0
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.js +1 -0
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.js +5 -0
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/lib/types/custom/SetSchema.js +1 -0
- package/lib/types/custom/SetSchema.js.map +1 -1
- package/lib/types/symbols.d.ts +1 -0
- package/lib/types/symbols.js +2 -1
- package/lib/types/symbols.js.map +1 -1
- package/package.json +1 -1
- package/src/Metadata.ts +60 -29
- package/src/Reflection.ts +5 -15
- package/src/Schema.ts +33 -45
- package/src/annotations.ts +75 -67
- package/src/bench_encode.ts +29 -27
- package/src/decoder/DecodeOperation.ts +12 -11
- package/src/decoder/ReferenceTracker.ts +3 -2
- package/src/decoder/strategy/StateCallbacks.ts +4 -3
- package/src/encoder/ChangeTree.ts +154 -138
- package/src/encoder/EncodeOperation.ts +42 -62
- package/src/encoder/Encoder.ts +25 -8
- package/src/encoder/Root.ts +23 -6
- package/src/encoder/StateView.ts +4 -4
- package/src/encoding/assert.ts +4 -3
- package/src/index.ts +1 -4
- package/src/types/TypeContext.ts +10 -15
- package/src/types/custom/ArraySchema.ts +8 -0
- package/src/types/custom/CollectionSchema.ts +1 -0
- package/src/types/custom/MapSchema.ts +6 -0
- package/src/types/custom/SetSchema.ts +1 -0
- package/src/types/symbols.ts +2 -0
package/src/encoder/Encoder.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Schema } from "../Schema";
|
|
2
2
|
import { TypeContext } from "../types/TypeContext";
|
|
3
|
-
import { $changes, $encoder, $filter } from "../types/symbols";
|
|
3
|
+
import { $changes, $encoder, $filter, $isNew, $onEncodeEnd } from "../types/symbols";
|
|
4
4
|
|
|
5
5
|
import * as encode from "../encoding/encode";
|
|
6
6
|
import type { Iterator } from "../encoding/decode";
|
|
@@ -55,12 +55,12 @@ export class Encoder<T extends Schema = any> {
|
|
|
55
55
|
const hasView = (view !== undefined);
|
|
56
56
|
const rootChangeTree = this.state[$changes];
|
|
57
57
|
|
|
58
|
-
const
|
|
58
|
+
const shouldClearChanges = !isEncodeAll && !hasView;
|
|
59
59
|
|
|
60
|
-
for (const [changeTree, changes] of
|
|
60
|
+
for (const [changeTree, changes] of changeTrees.entries()) {
|
|
61
61
|
const ref = changeTree.ref;
|
|
62
62
|
|
|
63
|
-
const ctor = ref
|
|
63
|
+
const ctor = ref.constructor;
|
|
64
64
|
const encoder = ctor[$encoder];
|
|
65
65
|
const filter = ctor[$filter];
|
|
66
66
|
|
|
@@ -88,9 +88,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
88
88
|
encode.number(buffer, changeTree.refId, it);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
for (const [fieldIndex, operation] of changesIterator) {
|
|
91
|
+
for (const [fieldIndex, operation] of changes.entries()) {
|
|
94
92
|
//
|
|
95
93
|
// first pass (encodeAll), identify "filtered" operations without encoding them
|
|
96
94
|
// they will be encoded per client, based on their view.
|
|
@@ -117,6 +115,17 @@ export class Encoder<T extends Schema = any> {
|
|
|
117
115
|
|
|
118
116
|
encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
|
|
119
117
|
}
|
|
118
|
+
|
|
119
|
+
// if (shouldClearChanges) {
|
|
120
|
+
// // changeTree.endEncode();
|
|
121
|
+
// changeTree.changes.clear();
|
|
122
|
+
|
|
123
|
+
// // ArraySchema and MapSchema have a custom "encode end" method
|
|
124
|
+
// changeTree.ref[$onEncodeEnd]?.();
|
|
125
|
+
|
|
126
|
+
// // Not a new instance anymore
|
|
127
|
+
// delete changeTree[$isNew];
|
|
128
|
+
// }
|
|
120
129
|
}
|
|
121
130
|
|
|
122
131
|
if (it.offset > buffer.byteLength) {
|
|
@@ -143,7 +152,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
143
152
|
//
|
|
144
153
|
// only clear changes after making sure buffer resize is not required.
|
|
145
154
|
//
|
|
146
|
-
if (
|
|
155
|
+
if (shouldClearChanges) {
|
|
147
156
|
//
|
|
148
157
|
// FIXME: avoid iterating over change trees twice.
|
|
149
158
|
//
|
|
@@ -251,6 +260,14 @@ export class Encoder<T extends Schema = any> {
|
|
|
251
260
|
const changeTreesIterator = changeTrees.entries();
|
|
252
261
|
for (const [changeTree, _] of changeTreesIterator) {
|
|
253
262
|
changeTree.endEncode();
|
|
263
|
+
// changeTree.changes.clear();
|
|
264
|
+
|
|
265
|
+
// // ArraySchema and MapSchema have a custom "encode end" method
|
|
266
|
+
// changeTree.ref[$onEncodeEnd]?.();
|
|
267
|
+
|
|
268
|
+
// // Not a new instance anymore
|
|
269
|
+
// delete changeTree[$isNew];
|
|
270
|
+
|
|
254
271
|
}
|
|
255
272
|
}
|
|
256
273
|
|
package/src/encoder/Root.ts
CHANGED
|
@@ -21,13 +21,28 @@ export class Root {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
add(changeTree: ChangeTree) {
|
|
24
|
-
const
|
|
25
|
-
|
|
24
|
+
const previousRefCount = this.refCount.get(changeTree);
|
|
25
|
+
|
|
26
|
+
if (previousRefCount === 0) {
|
|
27
|
+
//
|
|
28
|
+
// When a ChangeTree is re-added, it means that it was previously removed.
|
|
29
|
+
// We need to re-add all changes to the `changes` map.
|
|
30
|
+
//
|
|
31
|
+
changeTree.allChanges.forEach((operation, index) => {
|
|
32
|
+
changeTree.changes.set(index, operation);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const refCount = (previousRefCount || 0) + 1;
|
|
37
|
+
this.refCount.set(changeTree, refCount);
|
|
38
|
+
|
|
39
|
+
return refCount;
|
|
26
40
|
}
|
|
27
41
|
|
|
28
42
|
remove(changeTree: ChangeTree) {
|
|
29
|
-
const refCount = this.refCount.get(changeTree);
|
|
30
|
-
|
|
43
|
+
const refCount = (this.refCount.get(changeTree)) - 1;
|
|
44
|
+
|
|
45
|
+
if (refCount <= 0) {
|
|
31
46
|
this.allChanges.delete(changeTree);
|
|
32
47
|
this.changes.delete(changeTree);
|
|
33
48
|
|
|
@@ -36,13 +51,15 @@ export class Root {
|
|
|
36
51
|
this.filteredChanges.delete(changeTree);
|
|
37
52
|
}
|
|
38
53
|
|
|
39
|
-
this.refCount.
|
|
54
|
+
this.refCount.set(changeTree, 0);
|
|
40
55
|
|
|
41
56
|
} else {
|
|
42
|
-
this.refCount.set(changeTree, refCount
|
|
57
|
+
this.refCount.set(changeTree, refCount);
|
|
43
58
|
}
|
|
44
59
|
|
|
45
60
|
changeTree.forEachChild((child, _) => this.remove(child));
|
|
61
|
+
|
|
62
|
+
return refCount;
|
|
46
63
|
}
|
|
47
64
|
|
|
48
65
|
clear() {
|
package/src/encoder/StateView.ts
CHANGED
|
@@ -34,7 +34,7 @@ export class StateView {
|
|
|
34
34
|
return this;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
// FIXME: ArraySchema/MapSchema
|
|
37
|
+
// FIXME: ArraySchema/MapSchema do not have metadata
|
|
38
38
|
const metadata: Metadata = obj.constructor[Symbol.metadata];
|
|
39
39
|
const changeTree: ChangeTree = obj[$changes];
|
|
40
40
|
this.items.add(changeTree);
|
|
@@ -84,7 +84,7 @@ export class StateView {
|
|
|
84
84
|
: changeTree.allChanges;
|
|
85
85
|
|
|
86
86
|
changeSet.forEach((op, index) => {
|
|
87
|
-
const tagAtIndex = metadata?.[
|
|
87
|
+
const tagAtIndex = metadata?.[index].tag;
|
|
88
88
|
if (
|
|
89
89
|
(
|
|
90
90
|
isInvisible || // if "invisible", include all
|
|
@@ -101,7 +101,7 @@ export class StateView {
|
|
|
101
101
|
// Add children of this ChangeTree to this view
|
|
102
102
|
changeTree.forEachChild((change, index) => {
|
|
103
103
|
// Do not ADD children that don't have the same tag
|
|
104
|
-
if (metadata && metadata[
|
|
104
|
+
if (metadata && metadata[index].tag !== tag) {
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
107
|
this.add(change.ref, tag, false);
|
|
@@ -166,7 +166,7 @@ export class StateView {
|
|
|
166
166
|
let changes = this.changes.get(changeTree);
|
|
167
167
|
if (changes === undefined) {
|
|
168
168
|
changes = new Map<number, OPERATION>();
|
|
169
|
-
this.changes.set(changeTree, changes)
|
|
169
|
+
this.changes.set(changeTree, changes);
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
if (tag === DEFAULT_VIEW_TAG) {
|
package/src/encoding/assert.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { CollectionSchema } from "../types/custom/CollectionSchema";
|
|
|
3
3
|
import { MapSchema } from "../types/custom/MapSchema";
|
|
4
4
|
import { SetSchema } from "../types/custom/SetSchema";
|
|
5
5
|
import { ArraySchema } from "../types/custom/ArraySchema";
|
|
6
|
+
import type { Ref } from "../encoder/ChangeTree";
|
|
6
7
|
|
|
7
8
|
export class EncodeSchemaError extends Error {}
|
|
8
9
|
|
|
@@ -43,16 +44,16 @@ export function assertType(value: any, type: string, klass: Schema, field: strin
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export function assertInstanceType(
|
|
46
|
-
value:
|
|
47
|
+
value: Ref,
|
|
47
48
|
type: typeof Schema
|
|
48
49
|
| typeof ArraySchema
|
|
49
50
|
| typeof MapSchema
|
|
50
51
|
| typeof CollectionSchema
|
|
51
52
|
| typeof SetSchema,
|
|
52
|
-
|
|
53
|
+
instance: Ref,
|
|
53
54
|
field: string | number,
|
|
54
55
|
) {
|
|
55
56
|
if (!(value instanceof type)) {
|
|
56
|
-
throw new EncodeSchemaError(`a '${type.name}' was expected, but '${value && (value as any).constructor.name}' was provided in ${
|
|
57
|
+
throw new EncodeSchemaError(`a '${type.name}' was expected, but '${value && (value as any).constructor.name}' was provided in ${instance.constructor.name}#${field}`);
|
|
57
58
|
}
|
|
58
59
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
export { Schema } from "./Schema";
|
|
2
2
|
export type { DataChange } from "./decoder/DecodeOperation";
|
|
3
|
-
|
|
4
|
-
import { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType } from "./types/symbols";
|
|
5
|
-
export { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType };
|
|
6
|
-
|
|
7
3
|
export type { ToJSON } from "./types/HelperTypes";
|
|
8
4
|
|
|
9
5
|
import { MapSchema } from "./types/custom/MapSchema"
|
|
@@ -30,6 +26,7 @@ registerType("collection", { constructor: CollectionSchema, });
|
|
|
30
26
|
export { dumpChanges } from "./utils";
|
|
31
27
|
|
|
32
28
|
// Encoder / Decoder
|
|
29
|
+
export { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType } from "./types/symbols";
|
|
33
30
|
export type { Iterator } from "./encoding/decode";
|
|
34
31
|
import * as encode from "./encoding/encode";
|
|
35
32
|
import * as decode from "./encoding/decode";
|
package/src/types/TypeContext.ts
CHANGED
|
@@ -84,19 +84,11 @@ export class TypeContext {
|
|
|
84
84
|
this.parentFiltered[`${this.schemas.get(klass)}-${parentIndex}`] = true;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
for (const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// parentFieldViewTag !== undefined &&
|
|
93
|
-
// metadata[field].tag === undefined
|
|
94
|
-
// ) {
|
|
95
|
-
// metadata[field].tag = parentFieldViewTag;
|
|
96
|
-
// }
|
|
97
|
-
|
|
98
|
-
const fieldType = metadata[field].type;
|
|
99
|
-
const viewTag = metadata[field].tag;
|
|
87
|
+
for (const fieldIndex in metadata) {
|
|
88
|
+
const index = fieldIndex as any as number;
|
|
89
|
+
|
|
90
|
+
const fieldType = metadata[index].type;
|
|
91
|
+
const viewTag = metadata[index].tag;
|
|
100
92
|
|
|
101
93
|
if (typeof (fieldType) === "string") {
|
|
102
94
|
continue;
|
|
@@ -104,10 +96,13 @@ export class TypeContext {
|
|
|
104
96
|
|
|
105
97
|
if (Array.isArray(fieldType)) {
|
|
106
98
|
const type = fieldType[0];
|
|
99
|
+
|
|
100
|
+
// skip primitive types
|
|
107
101
|
if (type === "string") {
|
|
108
102
|
continue;
|
|
109
103
|
}
|
|
110
|
-
|
|
104
|
+
|
|
105
|
+
this.discoverTypes(type as typeof Schema, index, viewTag);
|
|
111
106
|
|
|
112
107
|
} else if (typeof (fieldType) === "function") {
|
|
113
108
|
this.discoverTypes(fieldType as typeof Schema, viewTag);
|
|
@@ -120,7 +115,7 @@ export class TypeContext {
|
|
|
120
115
|
continue;
|
|
121
116
|
}
|
|
122
117
|
|
|
123
|
-
this.discoverTypes(type as typeof Schema,
|
|
118
|
+
this.discoverTypes(type as typeof Schema, index, viewTag);
|
|
124
119
|
}
|
|
125
120
|
}
|
|
126
121
|
}
|
|
@@ -8,6 +8,7 @@ import { Collection } from "../HelperTypes";
|
|
|
8
8
|
import { encodeArray } from "../../encoder/EncodeOperation";
|
|
9
9
|
import { decodeArray } from "../../decoder/DecodeOperation";
|
|
10
10
|
import type { StateView } from "../../encoder/StateView";
|
|
11
|
+
import { assertInstanceType } from "../../encoding/assert";
|
|
11
12
|
|
|
12
13
|
const DEFAULT_SORT = (a: any, b: any) => {
|
|
13
14
|
const A = a.toString();
|
|
@@ -85,6 +86,8 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
85
86
|
|
|
86
87
|
} else {
|
|
87
88
|
if (setValue[$changes]) {
|
|
89
|
+
assertInstanceType(setValue, obj[$childType] as typeof Schema, obj, key);
|
|
90
|
+
|
|
88
91
|
if (obj.items[key as unknown as number] !== undefined) {
|
|
89
92
|
if (setValue[$changes][$isNew]) {
|
|
90
93
|
this[$changes].indexedOperation(Number(key), OPERATION.MOVE_AND_ADD);
|
|
@@ -99,6 +102,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
99
102
|
} else if (setValue[$changes][$isNew]) {
|
|
100
103
|
this[$changes].indexedOperation(Number(key), OPERATION.ADD);
|
|
101
104
|
}
|
|
105
|
+
|
|
102
106
|
} else {
|
|
103
107
|
obj.$changeAt(Number(key), setValue);
|
|
104
108
|
}
|
|
@@ -133,6 +137,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
133
137
|
});
|
|
134
138
|
|
|
135
139
|
this[$changes] = new ChangeTree(proxy);
|
|
140
|
+
this[$changes].indexes = {};
|
|
136
141
|
this.push.apply(this, items);
|
|
137
142
|
|
|
138
143
|
return proxy;
|
|
@@ -159,6 +164,9 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
159
164
|
// skip null values
|
|
160
165
|
if (value === undefined || value === null) {
|
|
161
166
|
return;
|
|
167
|
+
|
|
168
|
+
} else if (typeof (value) === "object" && this[$childType]) {
|
|
169
|
+
assertInstanceType(value as any, this[$childType] as typeof Schema, this, i);
|
|
162
170
|
}
|
|
163
171
|
|
|
164
172
|
const changeTree = this[$changes];
|
|
@@ -6,6 +6,8 @@ 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";
|
|
10
|
+
import { assertInstanceType } from "../../encoding/assert";
|
|
9
11
|
|
|
10
12
|
export class MapSchema<V=any, K extends string = string> implements Map<K, V>, Collection<K, V, [K, V]> {
|
|
11
13
|
protected childType: new () => V;
|
|
@@ -39,6 +41,7 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
|
|
|
39
41
|
|
|
40
42
|
constructor (initialValues?: Map<K, V> | Record<K, V>) {
|
|
41
43
|
this[$changes] = new ChangeTree(this);
|
|
44
|
+
this[$changes].indexes = {};
|
|
42
45
|
|
|
43
46
|
if (initialValues) {
|
|
44
47
|
if (
|
|
@@ -71,6 +74,9 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
|
|
|
71
74
|
set(key: K, value: V) {
|
|
72
75
|
if (value === undefined || value === null) {
|
|
73
76
|
throw new Error(`MapSchema#set('${key}', ${value}): trying to set ${value} value on '${key}'.`);
|
|
77
|
+
|
|
78
|
+
} else if (typeof(value) === "object" && this[$childType]) {
|
|
79
|
+
assertInstanceType(value as any, this[$childType] as typeof Schema, this, key);
|
|
74
80
|
}
|
|
75
81
|
|
|
76
82
|
// Force "key" as string
|
package/src/types/symbols.ts
CHANGED
|
@@ -7,6 +7,8 @@ export const $filter = Symbol("$filter");
|
|
|
7
7
|
export const $getByIndex = Symbol("$getByIndex");
|
|
8
8
|
export const $deleteByIndex = Symbol("$deleteByIndex");
|
|
9
9
|
|
|
10
|
+
export const $descriptors = Symbol("$descriptors");
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* Used to hold ChangeTree instances whitin the structures
|
|
12
14
|
*/
|