@colyseus/schema 2.0.31 → 3.0.0-alpha.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/build/cjs/index.js +3614 -2634
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +3324 -2445
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +3614 -2634
- package/lib/Decoder.d.ts +16 -0
- package/lib/Decoder.js +182 -0
- package/lib/Decoder.js.map +1 -0
- package/lib/Encoder.d.ts +13 -0
- package/lib/Encoder.js +79 -0
- package/lib/Encoder.js.map +1 -0
- package/lib/Metadata.d.ts +36 -0
- package/lib/Metadata.js +91 -0
- package/lib/Metadata.js.map +1 -0
- package/lib/Reflection.d.ts +7 -5
- package/lib/Reflection.js +62 -58
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +39 -51
- package/lib/Schema.js +189 -731
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +26 -45
- package/lib/annotations.js +363 -194
- package/lib/annotations.js.map +1 -1
- package/lib/changes/ChangeSet.d.ts +12 -0
- package/lib/changes/ChangeSet.js +35 -0
- package/lib/changes/ChangeSet.js.map +1 -0
- package/lib/changes/DecodeOperation.d.ts +15 -0
- package/lib/changes/DecodeOperation.js +186 -0
- package/lib/changes/DecodeOperation.js.map +1 -0
- package/lib/changes/EncodeOperation.d.ts +18 -0
- package/lib/changes/EncodeOperation.js +130 -0
- package/lib/changes/EncodeOperation.js.map +1 -0
- package/lib/changes/consts.d.ts +14 -0
- package/lib/changes/consts.js +18 -0
- package/lib/changes/consts.js.map +1 -0
- package/lib/decoder/DecodeOperation.d.ts +24 -0
- package/lib/decoder/DecodeOperation.js +256 -0
- package/lib/decoder/DecodeOperation.js.map +1 -0
- package/lib/decoder/Decoder.d.ts +21 -0
- package/lib/decoder/Decoder.js +114 -0
- package/lib/decoder/Decoder.js.map +1 -0
- package/lib/decoder/ReferenceTracker.d.ts +26 -0
- package/lib/decoder/ReferenceTracker.js +131 -0
- package/lib/decoder/ReferenceTracker.js.map +1 -0
- package/lib/decoder/strategy/RawChanges.d.ts +3 -0
- package/lib/decoder/strategy/RawChanges.js +8 -0
- package/lib/decoder/strategy/RawChanges.js.map +1 -0
- package/lib/decoder/strategy/StateCallbacks.d.ts +20 -0
- package/lib/decoder/strategy/StateCallbacks.js +240 -0
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -0
- package/lib/decoding/decode.d.ts +48 -0
- package/lib/decoding/decode.js +267 -0
- package/lib/decoding/decode.js.map +1 -0
- package/lib/ecs.d.ts +11 -0
- package/lib/ecs.js +160 -0
- package/lib/ecs.js.map +1 -0
- package/lib/encoder/ChangeTree.d.ts +72 -0
- package/lib/encoder/ChangeTree.js +384 -0
- package/lib/encoder/ChangeTree.js.map +1 -0
- package/lib/encoder/EncodeOperation.d.ts +25 -0
- package/lib/encoder/EncodeOperation.js +156 -0
- package/lib/encoder/EncodeOperation.js.map +1 -0
- package/lib/encoder/Encoder.d.ts +23 -0
- package/lib/encoder/Encoder.js +192 -0
- package/lib/encoder/Encoder.js.map +1 -0
- package/lib/encoder/StateView.d.ts +21 -0
- package/lib/encoder/StateView.js +196 -0
- package/lib/encoder/StateView.js.map +1 -0
- package/lib/encoding/assert.d.ts +9 -0
- package/lib/encoding/assert.js +47 -0
- package/lib/encoding/assert.js.map +1 -0
- package/lib/encoding/decode.js +1 -1
- package/lib/encoding/decode.js.map +1 -1
- package/lib/encoding/encode.d.ts +17 -16
- package/lib/encoding/encode.js +88 -81
- package/lib/encoding/encode.js.map +1 -1
- package/lib/encoding/spec.d.ts +25 -0
- package/lib/encoding/spec.js +30 -0
- package/lib/encoding/spec.js.map +1 -0
- package/lib/index.d.ts +18 -10
- package/lib/index.js +39 -17
- package/lib/index.js.map +1 -1
- package/lib/symbol.shim.d.ts +6 -0
- package/lib/symbol.shim.js +4 -0
- package/lib/symbol.shim.js.map +1 -0
- package/lib/types/ArraySchema.js +0 -7
- package/lib/types/ArraySchema.js.map +1 -1
- package/lib/types/HelperTypes.d.ts +10 -2
- package/lib/types/HelperTypes.js.map +1 -1
- package/lib/types/custom/ArraySchema.d.ts +245 -0
- package/lib/types/custom/ArraySchema.js +659 -0
- package/lib/types/custom/ArraySchema.js.map +1 -0
- package/lib/types/custom/CollectionSchema.d.ts +42 -0
- package/lib/types/custom/CollectionSchema.js +165 -0
- package/lib/types/custom/CollectionSchema.js.map +1 -0
- package/lib/types/custom/MapSchema.d.ts +43 -0
- package/lib/types/custom/MapSchema.js +200 -0
- package/lib/types/custom/MapSchema.js.map +1 -0
- package/lib/types/custom/SetSchema.d.ts +39 -0
- package/lib/types/custom/SetSchema.js +177 -0
- package/lib/types/custom/SetSchema.js.map +1 -0
- package/lib/types/registry.d.ts +6 -0
- package/lib/types/registry.js +19 -0
- package/lib/types/registry.js.map +1 -0
- package/lib/types/symbols.d.ts +29 -0
- package/lib/types/symbols.js +33 -0
- package/lib/types/symbols.js.map +1 -0
- package/lib/types/utils.d.ts +0 -8
- package/lib/types/utils.js +1 -33
- package/lib/types/utils.js.map +1 -1
- package/lib/usage.d.ts +1 -0
- package/lib/usage.js +22 -0
- package/lib/usage.js.map +1 -0
- package/lib/utils.d.ts +13 -2
- package/lib/utils.js +36 -15
- package/lib/utils.js.map +1 -1
- package/lib/v3.d.ts +1 -0
- package/lib/v3.js +427 -0
- package/lib/v3.js.map +1 -0
- package/lib/v3_bench.d.ts +1 -0
- package/lib/v3_bench.js +130 -0
- package/lib/v3_bench.js.map +1 -0
- package/lib/v3_experiment.d.ts +1 -0
- package/lib/v3_experiment.js +407 -0
- package/lib/v3_experiment.js.map +1 -0
- package/package.json +5 -5
- package/src/Metadata.ts +135 -0
- package/src/Reflection.ts +75 -66
- package/src/Schema.ts +213 -931
- package/src/annotations.ts +430 -243
- package/src/decoder/DecodeOperation.ts +372 -0
- package/src/decoder/Decoder.ts +155 -0
- package/src/decoder/ReferenceTracker.ts +151 -0
- package/src/decoder/strategy/RawChanges.ts +9 -0
- package/src/decoder/strategy/StateCallbacks.ts +326 -0
- package/src/encoder/ChangeTree.ts +492 -0
- package/src/encoder/EncodeOperation.ts +237 -0
- package/src/encoder/Encoder.ts +246 -0
- package/src/encoder/StateView.ts +229 -0
- package/src/encoding/assert.ts +58 -0
- package/src/encoding/decode.ts +1 -1
- package/src/encoding/encode.ts +88 -82
- package/src/encoding/spec.ts +29 -0
- package/src/index.ts +22 -19
- package/src/symbol.shim.ts +12 -0
- package/src/types/HelperTypes.ts +16 -2
- package/src/types/{ArraySchema.ts → custom/ArraySchema.ts} +345 -251
- package/src/types/{CollectionSchema.ts → custom/CollectionSchema.ts} +56 -46
- package/src/types/{MapSchema.ts → custom/MapSchema.ts} +88 -115
- package/src/types/{SetSchema.ts → custom/SetSchema.ts} +58 -47
- package/src/types/{typeRegistry.ts → registry.ts} +6 -6
- package/src/types/symbols.ts +36 -0
- package/src/types/utils.ts +0 -46
- package/src/utils.ts +50 -21
- package/src/v3_bench.ts +107 -0
- package/src/changes/ChangeTree.ts +0 -295
- package/src/changes/ReferenceTracker.ts +0 -91
- package/src/filters/index.ts +0 -23
- package/src/spec.ts +0 -49
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { Schema } from "../Schema";
|
|
3
|
+
import { TypeContext } from "../annotations";
|
|
4
|
+
import type { Iterator } from "../encoding/decode";
|
|
5
|
+
import { OPERATION } from '../encoding/spec';
|
|
6
|
+
import { Root } from "./ChangeTree";
|
|
7
|
+
import { StateView } from "./StateView";
|
|
8
|
+
export declare class Encoder<T extends Schema = any> {
|
|
9
|
+
static BUFFER_SIZE: number;
|
|
10
|
+
sharedBuffer: Buffer;
|
|
11
|
+
context: TypeContext;
|
|
12
|
+
state: T;
|
|
13
|
+
$root: Root;
|
|
14
|
+
constructor(root: T);
|
|
15
|
+
protected setRoot(state: T): void;
|
|
16
|
+
encode(it?: Iterator, view?: StateView, bytes?: Buffer, changeTrees?: Map<import("./ChangeTree").ChangeTree<any>, Map<number, OPERATION>>): Buffer;
|
|
17
|
+
encodeAll(it?: Iterator): Buffer;
|
|
18
|
+
encodeAllView(view: StateView, sharedOffset: number, it: Iterator, bytes?: Buffer): Buffer;
|
|
19
|
+
encodeView(view: StateView, sharedOffset: number, it: Iterator, bytes?: Buffer): Buffer;
|
|
20
|
+
onEndEncode(changeTrees?: Map<import("./ChangeTree").ChangeTree<any>, Map<number, OPERATION>>): void;
|
|
21
|
+
discardChanges(): void;
|
|
22
|
+
tryEncodeTypeId(bytes: Buffer, baseType: typeof Schema, targetType: typeof Schema, it: Iterator): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Encoder = void 0;
|
|
4
|
+
const annotations_1 = require("../annotations");
|
|
5
|
+
const symbols_1 = require("../types/symbols");
|
|
6
|
+
const encode = require("../encoding/encode");
|
|
7
|
+
const spec_1 = require("../encoding/spec");
|
|
8
|
+
const ChangeTree_1 = require("./ChangeTree");
|
|
9
|
+
const utils_1 = require("../utils");
|
|
10
|
+
class Encoder {
|
|
11
|
+
static { this.BUFFER_SIZE = 8 * 1024; } // 8KB
|
|
12
|
+
constructor(root) {
|
|
13
|
+
this.sharedBuffer = Buffer.allocUnsafeSlow(Encoder.BUFFER_SIZE);
|
|
14
|
+
this.setRoot(root);
|
|
15
|
+
//
|
|
16
|
+
// TODO: cache and restore "Context" based on root schema
|
|
17
|
+
// (to avoid creating a new context for every new room)
|
|
18
|
+
//
|
|
19
|
+
this.context = new annotations_1.TypeContext(root.constructor);
|
|
20
|
+
// console.log(">>>>>>>>>>>>>>>> Encoder types");
|
|
21
|
+
// this.context.schemas.forEach((id, schema) => {
|
|
22
|
+
// console.log("type:", id, schema.name, Object.keys(schema[Symbol.metadata]));
|
|
23
|
+
// });
|
|
24
|
+
}
|
|
25
|
+
setRoot(state) {
|
|
26
|
+
this.$root = new ChangeTree_1.Root();
|
|
27
|
+
this.state = state;
|
|
28
|
+
state[symbols_1.$changes].setRoot(this.$root);
|
|
29
|
+
}
|
|
30
|
+
encode(it = { offset: 0 }, view, bytes = this.sharedBuffer, changeTrees = this.$root.changes) {
|
|
31
|
+
const initialOffset = it.offset; // cache current offset in case we need to resize the buffer
|
|
32
|
+
const isEncodeAll = this.$root.allChanges === changeTrees;
|
|
33
|
+
const hasView = (view !== undefined);
|
|
34
|
+
const rootChangeTree = this.state[symbols_1.$changes];
|
|
35
|
+
const changeTreesIterator = changeTrees.entries();
|
|
36
|
+
for (const [changeTree, changes] of changeTreesIterator) {
|
|
37
|
+
const ref = changeTree.ref;
|
|
38
|
+
const ctor = ref['constructor'];
|
|
39
|
+
const encoder = ctor[symbols_1.$encoder];
|
|
40
|
+
const filter = ctor[symbols_1.$filter];
|
|
41
|
+
if (hasView) {
|
|
42
|
+
if (!view.items.has(changeTree)) {
|
|
43
|
+
view.invisible.add(changeTree);
|
|
44
|
+
continue; // skip this change tree
|
|
45
|
+
}
|
|
46
|
+
else if (view.invisible.has(changeTree)) {
|
|
47
|
+
view.invisible.delete(changeTree); // remove from invisible list
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// skip root `refId` if it's the first change tree
|
|
51
|
+
if (it.offset !== initialOffset || changeTree !== rootChangeTree) {
|
|
52
|
+
bytes[it.offset++] = spec_1.SWITCH_TO_STRUCTURE & 255;
|
|
53
|
+
encode.number(bytes, changeTree.refId, it);
|
|
54
|
+
}
|
|
55
|
+
const changesIterator = changes.entries();
|
|
56
|
+
for (const [fieldIndex, operation] of changesIterator) {
|
|
57
|
+
//
|
|
58
|
+
// first pass (encodeAll), identify "filtered" operations without encoding them
|
|
59
|
+
// they will be encoded per client, based on their view.
|
|
60
|
+
//
|
|
61
|
+
// TODO: how can we optimize filtering out "encode all" operations?
|
|
62
|
+
// TODO: avoid checking if no view tags were defined
|
|
63
|
+
//
|
|
64
|
+
if (filter && !filter(ref, fieldIndex, view)) {
|
|
65
|
+
// console.log("SKIP FIELD:", { ref: changeTree.ref.constructor.name, fieldIndex, })
|
|
66
|
+
// console.log("ADD AS INVISIBLE:", fieldIndex, changeTree.ref.constructor.name)
|
|
67
|
+
// view?.invisible.add(changeTree);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
// console.log("WILL ENCODE", {
|
|
71
|
+
// ref: changeTree.ref.constructor.name,
|
|
72
|
+
// fieldIndex,
|
|
73
|
+
// operation: OPERATION[operation],
|
|
74
|
+
// });
|
|
75
|
+
encoder(this, bytes, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (it.offset > bytes.byteLength) {
|
|
79
|
+
const newSize = (0, utils_1.getNextPowerOf2)(this.sharedBuffer.byteLength * 2);
|
|
80
|
+
console.warn("@colyseus/schema encode buffer overflow. Current buffer size: " + bytes.byteLength + ", encoding offset: " + it.offset + ", new size: " + newSize);
|
|
81
|
+
//
|
|
82
|
+
// resize buffer and re-encode (TODO: can we avoid re-encoding here?)
|
|
83
|
+
//
|
|
84
|
+
this.sharedBuffer = Buffer.allocUnsafeSlow(newSize);
|
|
85
|
+
return this.encode({ offset: initialOffset }, view);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
//
|
|
89
|
+
// only clear changes after making sure buffer resize is not required.
|
|
90
|
+
//
|
|
91
|
+
if (!isEncodeAll && !hasView) {
|
|
92
|
+
//
|
|
93
|
+
// FIXME: avoid iterating over change trees twice.
|
|
94
|
+
//
|
|
95
|
+
this.onEndEncode(changeTrees);
|
|
96
|
+
}
|
|
97
|
+
// return bytes;
|
|
98
|
+
return bytes.slice(0, it.offset);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
encodeAll(it = { offset: 0 }) {
|
|
102
|
+
// console.log(`encodeAll(), this.$root.allChanges (${this.$root.allChanges.size})`);
|
|
103
|
+
// Array.from(this.$root.allChanges.entries()).map((item) => {
|
|
104
|
+
// console.log("->", item[0].refId, item[0].ref.toJSON());
|
|
105
|
+
// });
|
|
106
|
+
return this.encode(it, undefined, this.sharedBuffer, this.$root.allChanges);
|
|
107
|
+
}
|
|
108
|
+
encodeAllView(view, sharedOffset, it, bytes = this.sharedBuffer) {
|
|
109
|
+
const viewOffset = it.offset;
|
|
110
|
+
// console.log(`encodeAllView(), this.$root.allFilteredChanges (${this.$root.allFilteredChanges.size})`);
|
|
111
|
+
// this.debugAllFilteredChanges();
|
|
112
|
+
// try to encode "filtered" changes
|
|
113
|
+
this.encode(it, view, bytes, this.$root.allFilteredChanges);
|
|
114
|
+
return Buffer.concat([
|
|
115
|
+
bytes.slice(0, sharedOffset),
|
|
116
|
+
bytes.slice(viewOffset, it.offset)
|
|
117
|
+
]);
|
|
118
|
+
}
|
|
119
|
+
// debugAllFilteredChanges() {
|
|
120
|
+
// Array.from(this.$root.allFilteredChanges.entries()).map((item) => {
|
|
121
|
+
// console.log("->", { refId: item[0].refId }, item[0].ref.toJSON());
|
|
122
|
+
// if (Array.isArray(item[0].ref.toJSON())) {
|
|
123
|
+
// item[1].forEach((op, key) => {
|
|
124
|
+
// console.log(" ->", { key, op: OPERATION[op] });
|
|
125
|
+
// })
|
|
126
|
+
// }
|
|
127
|
+
// });
|
|
128
|
+
// }
|
|
129
|
+
encodeView(view, sharedOffset, it, bytes = this.sharedBuffer) {
|
|
130
|
+
const viewOffset = it.offset;
|
|
131
|
+
// try to encode "filtered" changes
|
|
132
|
+
this.encode(it, view, bytes, this.$root.filteredChanges);
|
|
133
|
+
// encode visibility changes (add/remove for this view)
|
|
134
|
+
const viewChangesIterator = view.changes.entries();
|
|
135
|
+
for (const [changeTree, changes] of viewChangesIterator) {
|
|
136
|
+
if (changes.size === 0) {
|
|
137
|
+
// FIXME: avoid having empty changes if no changes were made
|
|
138
|
+
// console.log("changes.size === 0", changeTree.ref.constructor.name);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const ref = changeTree.ref;
|
|
142
|
+
const ctor = ref['constructor'];
|
|
143
|
+
const encoder = ctor[symbols_1.$encoder];
|
|
144
|
+
bytes[it.offset++] = spec_1.SWITCH_TO_STRUCTURE & 255;
|
|
145
|
+
encode.number(bytes, changeTree.refId, it);
|
|
146
|
+
const changesIterator = changes.entries();
|
|
147
|
+
for (const [fieldIndex, operation] of changesIterator) {
|
|
148
|
+
// isEncodeAll = false
|
|
149
|
+
// hasView = true
|
|
150
|
+
encoder(this, bytes, changeTree, fieldIndex, operation, it, false, true);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//
|
|
154
|
+
// TODO: only clear view changes after all views are encoded
|
|
155
|
+
// (to allow re-using StateView's for multiple clients)
|
|
156
|
+
//
|
|
157
|
+
// clear "view" changes after encoding
|
|
158
|
+
view.changes.clear();
|
|
159
|
+
return Buffer.concat([
|
|
160
|
+
bytes.slice(0, sharedOffset),
|
|
161
|
+
bytes.slice(viewOffset, it.offset)
|
|
162
|
+
]);
|
|
163
|
+
}
|
|
164
|
+
onEndEncode(changeTrees = this.$root.changes) {
|
|
165
|
+
const changeTreesIterator = changeTrees.entries();
|
|
166
|
+
for (const [changeTree, _] of changeTreesIterator) {
|
|
167
|
+
changeTree.endEncode();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
discardChanges() {
|
|
171
|
+
// discard shared changes
|
|
172
|
+
if (this.$root.changes.size > 0) {
|
|
173
|
+
this.onEndEncode(this.$root.changes);
|
|
174
|
+
this.$root.changes.clear();
|
|
175
|
+
}
|
|
176
|
+
// discard filtered changes
|
|
177
|
+
if (this.$root.filteredChanges.size > 0) {
|
|
178
|
+
this.onEndEncode(this.$root.filteredChanges);
|
|
179
|
+
this.$root.filteredChanges.clear();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
tryEncodeTypeId(bytes, baseType, targetType, it) {
|
|
183
|
+
const baseTypeId = this.context.getTypeId(baseType);
|
|
184
|
+
const targetTypeId = this.context.getTypeId(targetType);
|
|
185
|
+
if (baseTypeId !== targetTypeId) {
|
|
186
|
+
bytes[it.offset++] = spec_1.TYPE_ID & 255;
|
|
187
|
+
encode.number(bytes, targetTypeId, it);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
exports.Encoder = Encoder;
|
|
192
|
+
//# sourceMappingURL=Encoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Encoder.js","sourceRoot":"","sources":["../../src/encoder/Encoder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Schema } from \"../Schema\";\nimport { TypeContext } from \"../annotations\";\nimport { $changes, $encoder, $filter } from \"../types/symbols\";\n\nimport * as encode from \"../encoding/encode\";\nimport type { Iterator } from \"../encoding/decode\";\n\nimport { OPERATION, SWITCH_TO_STRUCTURE, TYPE_ID } from '../encoding/spec';\nimport { Root } from \"./ChangeTree\";\nimport { getNextPowerOf2 } from \"../utils\";\nimport { StateView } from \"./StateView\";\nimport { Metadata } from \"../Metadata\";\n\nexport class Encoder<T extends Schema = any> {\n static BUFFER_SIZE = 8 * 1024;// 8KB\n sharedBuffer = Buffer.allocUnsafeSlow(Encoder.BUFFER_SIZE);\n\n context: TypeContext;\n state: T;\n\n $root: Root;\n\n constructor(root: T) {\n this.setRoot(root);\n\n //\n // TODO: cache and restore \"Context\" based on root schema\n // (to avoid creating a new context for every new room)\n //\n this.context = new TypeContext(root.constructor as typeof Schema);\n\n // console.log(\">>>>>>>>>>>>>>>> Encoder types\");\n // this.context.schemas.forEach((id, schema) => {\n // console.log(\"type:\", id, schema.name, Object.keys(schema[Symbol.metadata]));\n // });\n }\n\n protected setRoot(state: T) {\n this.$root = new Root();\n this.state = state;\n state[$changes].setRoot(this.$root);\n }\n\n encode(\n it: Iterator = { offset: 0 },\n view?: StateView,\n bytes = this.sharedBuffer,\n changeTrees = this.$root.changes\n ): Buffer {\n const initialOffset = it.offset; // cache current offset in case we need to resize the buffer\n\n const isEncodeAll = this.$root.allChanges === changeTrees;\n const hasView = (view !== undefined);\n const rootChangeTree = this.state[$changes];\n\n const changeTreesIterator = changeTrees.entries();\n\n for (const [changeTree, changes] of changeTreesIterator) {\n const ref = changeTree.ref;\n\n const ctor = ref['constructor'];\n const encoder = ctor[$encoder];\n const filter = ctor[$filter];\n\n if (hasView) {\n if (!view.items.has(changeTree)) {\n view.invisible.add(changeTree);\n continue; // skip this change tree\n\n } else if (view.invisible.has(changeTree)) {\n view.invisible.delete(changeTree); // remove from invisible list\n }\n }\n\n // skip root `refId` if it's the first change tree\n if (it.offset !== initialOffset || changeTree !== rootChangeTree) {\n bytes[it.offset++] = SWITCH_TO_STRUCTURE & 255;\n encode.number(bytes, changeTree.refId, it);\n }\n\n const changesIterator = changes.entries();\n\n for (const [fieldIndex, operation] of changesIterator) {\n //\n // first pass (encodeAll), identify \"filtered\" operations without encoding them\n // they will be encoded per client, based on their view.\n //\n // TODO: how can we optimize filtering out \"encode all\" operations?\n // TODO: avoid checking if no view tags were defined\n //\n if (filter && !filter(ref, fieldIndex, view)) {\n // console.log(\"SKIP FIELD:\", { ref: changeTree.ref.constructor.name, fieldIndex, })\n\n // console.log(\"ADD AS INVISIBLE:\", fieldIndex, changeTree.ref.constructor.name)\n // view?.invisible.add(changeTree);\n continue;\n }\n\n // console.log(\"WILL ENCODE\", {\n // ref: changeTree.ref.constructor.name,\n // fieldIndex,\n // operation: OPERATION[operation],\n // });\n\n encoder(this, bytes, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);\n }\n }\n\n if (it.offset > bytes.byteLength) {\n const newSize = getNextPowerOf2(this.sharedBuffer.byteLength * 2);\n console.warn(\"@colyseus/schema encode buffer overflow. Current buffer size: \" + bytes.byteLength + \", encoding offset: \" + it.offset + \", new size: \" + newSize);\n\n //\n // resize buffer and re-encode (TODO: can we avoid re-encoding here?)\n //\n this.sharedBuffer = Buffer.allocUnsafeSlow(newSize);\n return this.encode({ offset: initialOffset }, view);\n\n } else {\n //\n // only clear changes after making sure buffer resize is not required.\n //\n if (!isEncodeAll && !hasView) {\n //\n // FIXME: avoid iterating over change trees twice.\n //\n this.onEndEncode(changeTrees);\n }\n\n // return bytes;\n return bytes.slice(0, it.offset);\n }\n }\n\n encodeAll(it: Iterator = { offset: 0 }) {\n // console.log(`encodeAll(), this.$root.allChanges (${this.$root.allChanges.size})`);\n\n // Array.from(this.$root.allChanges.entries()).map((item) => {\n // console.log(\"->\", item[0].refId, item[0].ref.toJSON());\n // });\n\n return this.encode(it, undefined, this.sharedBuffer, this.$root.allChanges);\n }\n\n encodeAllView(view: StateView, sharedOffset: number, it: Iterator, bytes = this.sharedBuffer) {\n const viewOffset = it.offset;\n\n // console.log(`encodeAllView(), this.$root.allFilteredChanges (${this.$root.allFilteredChanges.size})`);\n // this.debugAllFilteredChanges();\n\n // try to encode \"filtered\" changes\n this.encode(it, view, bytes, this.$root.allFilteredChanges);\n\n return Buffer.concat([\n bytes.slice(0, sharedOffset),\n bytes.slice(viewOffset, it.offset)\n ]);\n }\n\n\n // debugAllFilteredChanges() {\n // Array.from(this.$root.allFilteredChanges.entries()).map((item) => {\n // console.log(\"->\", { refId: item[0].refId }, item[0].ref.toJSON());\n // if (Array.isArray(item[0].ref.toJSON())) {\n // item[1].forEach((op, key) => {\n // console.log(\" ->\", { key, op: OPERATION[op] });\n // })\n // }\n // });\n // }\n\n encodeView(view: StateView, sharedOffset: number, it: Iterator, bytes = this.sharedBuffer) {\n const viewOffset = it.offset;\n\n // try to encode \"filtered\" changes\n this.encode(it, view, bytes, this.$root.filteredChanges);\n\n // encode visibility changes (add/remove for this view)\n const viewChangesIterator = view.changes.entries();\n for (const [changeTree, changes] of viewChangesIterator) {\n if (changes.size === 0) {\n // FIXME: avoid having empty changes if no changes were made\n // console.log(\"changes.size === 0\", changeTree.ref.constructor.name);\n continue;\n }\n\n const ref = changeTree.ref;\n\n const ctor = ref['constructor'];\n const encoder = ctor[$encoder];\n\n bytes[it.offset++] = SWITCH_TO_STRUCTURE & 255;\n encode.number(bytes, changeTree.refId, it);\n\n const changesIterator = changes.entries();\n\n for (const [fieldIndex, operation] of changesIterator) {\n // isEncodeAll = false\n // hasView = true\n encoder(this, bytes, changeTree, fieldIndex, operation, it, false, true);\n }\n }\n\n //\n // TODO: only clear view changes after all views are encoded\n // (to allow re-using StateView's for multiple clients)\n //\n // clear \"view\" changes after encoding\n view.changes.clear();\n\n return Buffer.concat([\n bytes.slice(0, sharedOffset),\n bytes.slice(viewOffset, it.offset)\n ]);\n }\n\n onEndEncode(changeTrees = this.$root.changes) {\n const changeTreesIterator = changeTrees.entries();\n for (const [changeTree, _] of changeTreesIterator) {\n changeTree.endEncode();\n }\n }\n\n discardChanges() {\n // discard shared changes\n if (this.$root.changes.size > 0) {\n this.onEndEncode(this.$root.changes);\n this.$root.changes.clear();\n }\n // discard filtered changes\n if (this.$root.filteredChanges.size > 0) {\n this.onEndEncode(this.$root.filteredChanges);\n this.$root.filteredChanges.clear();\n }\n }\n\n tryEncodeTypeId (bytes: Buffer, baseType: typeof Schema, targetType: typeof Schema, it: Iterator) {\n const baseTypeId = this.context.getTypeId(baseType);\n const targetTypeId = this.context.getTypeId(targetType);\n\n if (baseTypeId !== targetTypeId) {\n bytes[it.offset++] = TYPE_ID & 255;\n encode.number(bytes, targetTypeId, it);\n }\n }\n}"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ChangeTree, Ref } from "./ChangeTree";
|
|
2
|
+
import { OPERATION } from "../encoding/spec";
|
|
3
|
+
export declare class StateView {
|
|
4
|
+
/**
|
|
5
|
+
* List of ChangeTree's that are visible to this view
|
|
6
|
+
*/
|
|
7
|
+
items: WeakSet<ChangeTree>;
|
|
8
|
+
/**
|
|
9
|
+
* List of ChangeTree's that are invisible to this view
|
|
10
|
+
*/
|
|
11
|
+
invisible: WeakSet<ChangeTree>;
|
|
12
|
+
tags?: WeakMap<ChangeTree, Set<number>>;
|
|
13
|
+
/**
|
|
14
|
+
* Manual "ADD" operations for changes per ChangeTree, specific to this view.
|
|
15
|
+
* (This is used to force encoding a property, even if it was not changed)
|
|
16
|
+
*/
|
|
17
|
+
changes: Map<ChangeTree<any>, Map<number, OPERATION>>;
|
|
18
|
+
add(obj: Ref, tag?: number): this;
|
|
19
|
+
protected addParent(changeTree: ChangeTree, tag: number): void;
|
|
20
|
+
remove(obj: Ref, tag?: number): this;
|
|
21
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StateView = void 0;
|
|
4
|
+
const symbols_1 = require("../types/symbols");
|
|
5
|
+
const annotations_1 = require("../annotations");
|
|
6
|
+
const spec_1 = require("../encoding/spec");
|
|
7
|
+
const Metadata_1 = require("../Metadata");
|
|
8
|
+
class StateView {
|
|
9
|
+
constructor() {
|
|
10
|
+
/**
|
|
11
|
+
* List of ChangeTree's that are visible to this view
|
|
12
|
+
*/
|
|
13
|
+
this.items = new WeakSet();
|
|
14
|
+
/**
|
|
15
|
+
* List of ChangeTree's that are invisible to this view
|
|
16
|
+
*/
|
|
17
|
+
this.invisible = new WeakSet();
|
|
18
|
+
/**
|
|
19
|
+
* Manual "ADD" operations for changes per ChangeTree, specific to this view.
|
|
20
|
+
* (This is used to force encoding a property, even if it was not changed)
|
|
21
|
+
*/
|
|
22
|
+
this.changes = new Map();
|
|
23
|
+
}
|
|
24
|
+
// TODO: allow to set multiple tags at once
|
|
25
|
+
add(obj, tag = annotations_1.DEFAULT_VIEW_TAG) {
|
|
26
|
+
if (!obj[symbols_1.$changes]) {
|
|
27
|
+
console.warn("StateView#add(), invalid object:", obj);
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
let changeTree = obj[symbols_1.$changes];
|
|
31
|
+
this.items.add(changeTree);
|
|
32
|
+
// Add children of this ChangeTree to this view
|
|
33
|
+
changeTree.forEachChild((change, _) => this.add(change.ref, tag));
|
|
34
|
+
// FIXME: ArraySchema/MapSchema does not have metadata
|
|
35
|
+
const metadata = obj.constructor[Symbol.metadata];
|
|
36
|
+
// add parent ChangeTree's, if they are invisible to this view
|
|
37
|
+
// TODO: REFACTOR addParent()
|
|
38
|
+
this.addParent(changeTree, tag);
|
|
39
|
+
//
|
|
40
|
+
// TODO: when adding an item of a MapSchema, the changes may not
|
|
41
|
+
// be set (only the parent's changes are set)
|
|
42
|
+
//
|
|
43
|
+
let changes = this.changes.get(changeTree);
|
|
44
|
+
if (changes === undefined) {
|
|
45
|
+
changes = new Map();
|
|
46
|
+
this.changes.set(changeTree, changes);
|
|
47
|
+
}
|
|
48
|
+
// set tag
|
|
49
|
+
if (tag !== annotations_1.DEFAULT_VIEW_TAG) {
|
|
50
|
+
if (!this.tags) {
|
|
51
|
+
this.tags = new WeakMap();
|
|
52
|
+
}
|
|
53
|
+
let tags;
|
|
54
|
+
if (!this.tags.has(changeTree)) {
|
|
55
|
+
tags = new Set();
|
|
56
|
+
this.tags.set(changeTree, tags);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
tags = this.tags.get(changeTree);
|
|
60
|
+
}
|
|
61
|
+
tags.add(tag);
|
|
62
|
+
// console.log("BY TAG:", tag);
|
|
63
|
+
// Ref: add tagged properties
|
|
64
|
+
metadata?.[-3]?.[tag]?.forEach((index) => {
|
|
65
|
+
if (changeTree.getChange(index) !== spec_1.OPERATION.DELETE) {
|
|
66
|
+
changes.set(index, spec_1.OPERATION.ADD);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// console.log("DEFAULT TAG", changeTree.allChanges);
|
|
72
|
+
// // add default tag properties
|
|
73
|
+
// metadata?.[-3]?.[DEFAULT_VIEW_TAG]?.forEach((index) => {
|
|
74
|
+
// if (changeTree.getChange(index) !== OPERATION.DELETE) {
|
|
75
|
+
// changes.set(index, OPERATION.ADD);
|
|
76
|
+
// }
|
|
77
|
+
// });
|
|
78
|
+
const allChangesSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)
|
|
79
|
+
? changeTree.allFilteredChanges
|
|
80
|
+
: changeTree.allChanges;
|
|
81
|
+
const it = allChangesSet.keys();
|
|
82
|
+
const isInvisible = this.invisible.has(changeTree);
|
|
83
|
+
for (const index of it) {
|
|
84
|
+
if ((isInvisible || metadata?.[metadata?.[index]].tag === tag) &&
|
|
85
|
+
changeTree.getChange(index) !== spec_1.OPERATION.DELETE) {
|
|
86
|
+
changes.set(index, spec_1.OPERATION.ADD);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// TODO: avoid unnecessary iteration here
|
|
91
|
+
while (changeTree.parent &&
|
|
92
|
+
(changeTree = changeTree.parent[symbols_1.$changes]) &&
|
|
93
|
+
(changeTree.isFiltered || changeTree.isPartiallyFiltered)) {
|
|
94
|
+
this.items.add(changeTree);
|
|
95
|
+
}
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
98
|
+
addParent(changeTree, tag) {
|
|
99
|
+
const parentRef = changeTree.parent;
|
|
100
|
+
if (!parentRef) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const parentChangeTree = parentRef[symbols_1.$changes];
|
|
104
|
+
const parentIndex = changeTree.parentIndex;
|
|
105
|
+
if (!this.invisible.has(parentChangeTree)) {
|
|
106
|
+
// parent is already available, no need to add it!
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
this.addParent(parentChangeTree, tag);
|
|
110
|
+
// add parent's tag properties
|
|
111
|
+
if (parentChangeTree.getChange(parentIndex) !== spec_1.OPERATION.DELETE) {
|
|
112
|
+
let parentChanges = this.changes.get(parentChangeTree);
|
|
113
|
+
if (parentChanges === undefined) {
|
|
114
|
+
parentChanges = new Map();
|
|
115
|
+
this.changes.set(parentChangeTree, parentChanges);
|
|
116
|
+
}
|
|
117
|
+
// console.log("add parent change", {
|
|
118
|
+
// parentIndex,
|
|
119
|
+
// parentChanges,
|
|
120
|
+
// parentChange: (
|
|
121
|
+
// parentChangeTree.getChange(parentIndex) &&
|
|
122
|
+
// OPERATION[parentChangeTree.getChange(parentIndex)]
|
|
123
|
+
// ),
|
|
124
|
+
// })
|
|
125
|
+
if (!this.tags) {
|
|
126
|
+
this.tags = new WeakMap();
|
|
127
|
+
}
|
|
128
|
+
let tags;
|
|
129
|
+
if (!this.tags.has(parentChangeTree)) {
|
|
130
|
+
tags = new Set();
|
|
131
|
+
this.tags.set(parentChangeTree, tags);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
tags = this.tags.get(parentChangeTree);
|
|
135
|
+
}
|
|
136
|
+
tags.add(tag);
|
|
137
|
+
parentChanges.set(parentIndex, spec_1.OPERATION.ADD);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
remove(obj, tag = annotations_1.DEFAULT_VIEW_TAG) {
|
|
141
|
+
const changeTree = obj[symbols_1.$changes];
|
|
142
|
+
if (!changeTree) {
|
|
143
|
+
console.warn("StateView#remove(), invalid object:", obj);
|
|
144
|
+
return this;
|
|
145
|
+
}
|
|
146
|
+
this.items.delete(changeTree);
|
|
147
|
+
const ref = changeTree.ref;
|
|
148
|
+
const metadata = ref.constructor[Symbol.metadata];
|
|
149
|
+
let changes = this.changes.get(changeTree);
|
|
150
|
+
if (changes === undefined) {
|
|
151
|
+
changes = new Map();
|
|
152
|
+
this.changes.set(changeTree, changes);
|
|
153
|
+
}
|
|
154
|
+
if (tag === annotations_1.DEFAULT_VIEW_TAG) {
|
|
155
|
+
// parent is collection (Map/Array)
|
|
156
|
+
const parent = changeTree.parent;
|
|
157
|
+
if (!Metadata_1.Metadata.isValidInstance(parent)) {
|
|
158
|
+
const parentChangeTree = parent[symbols_1.$changes];
|
|
159
|
+
let changes = this.changes.get(parentChangeTree);
|
|
160
|
+
if (changes === undefined) {
|
|
161
|
+
changes = new Map();
|
|
162
|
+
this.changes.set(parentChangeTree, changes);
|
|
163
|
+
}
|
|
164
|
+
// DELETE / DELETE BY REF ID
|
|
165
|
+
changes.set(changeTree.parentIndex, spec_1.OPERATION.DELETE);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
// delete all "tagged" properties.
|
|
169
|
+
metadata[-2].forEach((index) => changes.set(index, spec_1.OPERATION.DELETE));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
// delete only tagged properties
|
|
174
|
+
metadata[-3][tag].forEach((index) => changes.set(index, spec_1.OPERATION.DELETE));
|
|
175
|
+
}
|
|
176
|
+
// remove tag
|
|
177
|
+
if (this.tags && this.tags.has(changeTree)) {
|
|
178
|
+
const tags = this.tags.get(changeTree);
|
|
179
|
+
if (tag === undefined) {
|
|
180
|
+
// delete all tags
|
|
181
|
+
this.tags.delete(changeTree);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// delete specific tag
|
|
185
|
+
tags.delete(tag);
|
|
186
|
+
// if tag set is empty, delete it entirely
|
|
187
|
+
if (tags.size === 0) {
|
|
188
|
+
this.tags.delete(changeTree);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return this;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
exports.StateView = StateView;
|
|
196
|
+
//# sourceMappingURL=StateView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StateView.js","sourceRoot":"","sources":["../../src/encoder/StateView.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeTree, Ref } from \"./ChangeTree\";\nimport { $changes } from \"../types/symbols\";\nimport { DEFAULT_VIEW_TAG } from \"../annotations\";\nimport { OPERATION } from \"../encoding/spec\";\nimport { Metadata } from \"../Metadata\";\n\nexport class StateView {\n /**\n * List of ChangeTree's that are visible to this view\n */\n items: WeakSet<ChangeTree> = new WeakSet<ChangeTree>();\n\n /**\n * List of ChangeTree's that are invisible to this view\n */\n invisible: WeakSet<ChangeTree> = new WeakSet<ChangeTree>();\n\n tags?: WeakMap<ChangeTree, Set<number>>; // TODO: use bit manipulation instead of Set<number> ()\n\n /**\n * Manual \"ADD\" operations for changes per ChangeTree, specific to this view.\n * (This is used to force encoding a property, even if it was not changed)\n */\n changes = new Map<ChangeTree, Map<number, OPERATION>>();\n\n // TODO: allow to set multiple tags at once\n add(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {\n if (!obj[$changes]) {\n console.warn(\"StateView#add(), invalid object:\", obj);\n return this;\n }\n\n let changeTree: ChangeTree = obj[$changes];\n this.items.add(changeTree);\n\n // Add children of this ChangeTree to this view\n changeTree.forEachChild((change, _) =>\n this.add(change.ref, tag));\n\n // FIXME: ArraySchema/MapSchema does not have metadata\n const metadata: Metadata = obj.constructor[Symbol.metadata];\n\n // add parent ChangeTree's, if they are invisible to this view\n // TODO: REFACTOR addParent()\n this.addParent(changeTree, tag);\n\n //\n // TODO: when adding an item of a MapSchema, the changes may not\n // be set (only the parent's changes are set)\n //\n let changes = this.changes.get(changeTree);\n if (changes === undefined) {\n changes = new Map<number, OPERATION>();\n this.changes.set(changeTree, changes)\n }\n\n // set tag\n if (tag !== DEFAULT_VIEW_TAG) {\n if (!this.tags) {\n this.tags = new WeakMap<ChangeTree, Set<number>>();\n }\n let tags: Set<number>;\n if (!this.tags.has(changeTree)) {\n tags = new Set<number>();\n this.tags.set(changeTree, tags);\n } else {\n tags = this.tags.get(changeTree);\n }\n tags.add(tag);\n\n // console.log(\"BY TAG:\", tag);\n\n // Ref: add tagged properties\n metadata?.[-3]?.[tag]?.forEach((index) => {\n if (changeTree.getChange(index) !== OPERATION.DELETE) {\n changes.set(index, OPERATION.ADD)\n }\n });\n\n } else {\n\n // console.log(\"DEFAULT TAG\", changeTree.allChanges);\n\n // // add default tag properties\n // metadata?.[-3]?.[DEFAULT_VIEW_TAG]?.forEach((index) => {\n // if (changeTree.getChange(index) !== OPERATION.DELETE) {\n // changes.set(index, OPERATION.ADD);\n // }\n // });\n\n const allChangesSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)\n ? changeTree.allFilteredChanges\n : changeTree.allChanges;\n const it = allChangesSet.keys();\n const isInvisible = this.invisible.has(changeTree);\n\n for (const index of it) {\n if (\n (isInvisible || metadata?.[metadata?.[index]].tag === tag) &&\n changeTree.getChange(index) !== OPERATION.DELETE\n ) {\n changes.set(index, OPERATION.ADD);\n }\n }\n }\n\n // TODO: avoid unnecessary iteration here\n while (\n changeTree.parent &&\n (changeTree = changeTree.parent[$changes]) &&\n (changeTree.isFiltered || changeTree.isPartiallyFiltered)\n ) {\n this.items.add(changeTree);\n }\n\n return this;\n }\n\n protected addParent(changeTree: ChangeTree, tag: number) {\n const parentRef = changeTree.parent;\n if (!parentRef) { return; }\n\n const parentChangeTree = parentRef[$changes];\n const parentIndex = changeTree.parentIndex;\n\n if (!this.invisible.has(parentChangeTree)) {\n // parent is already available, no need to add it!\n return;\n }\n\n this.addParent(parentChangeTree, tag);\n\n // add parent's tag properties\n if (parentChangeTree.getChange(parentIndex) !== OPERATION.DELETE) {\n\n let parentChanges = this.changes.get(parentChangeTree);\n if (parentChanges === undefined) {\n parentChanges = new Map<number, OPERATION>();\n this.changes.set(parentChangeTree, parentChanges);\n }\n\n // console.log(\"add parent change\", {\n // parentIndex,\n // parentChanges,\n // parentChange: (\n // parentChangeTree.getChange(parentIndex) &&\n // OPERATION[parentChangeTree.getChange(parentIndex)]\n // ),\n // })\n\n if (!this.tags) { this.tags = new WeakMap<ChangeTree, Set<number>>(); }\n let tags: Set<number>;\n if (!this.tags.has(parentChangeTree)) {\n tags = new Set<number>();\n this.tags.set(parentChangeTree, tags);\n } else {\n tags = this.tags.get(parentChangeTree);\n }\n tags.add(tag);\n\n parentChanges.set(parentIndex, OPERATION.ADD);\n }\n\n }\n\n remove(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {\n const changeTree = obj[$changes];\n if (!changeTree) {\n console.warn(\"StateView#remove(), invalid object:\", obj);\n return this;\n }\n\n this.items.delete(changeTree);\n\n const ref = changeTree.ref;\n const metadata: Metadata = ref.constructor[Symbol.metadata];\n\n let changes = this.changes.get(changeTree);\n if (changes === undefined) {\n changes = new Map<number, OPERATION>();\n this.changes.set(changeTree, changes)\n }\n\n if (tag === DEFAULT_VIEW_TAG) {\n // parent is collection (Map/Array)\n const parent = changeTree.parent;\n if (!Metadata.isValidInstance(parent)) {\n const parentChangeTree = parent[$changes];\n let changes = this.changes.get(parentChangeTree);\n if (changes === undefined) {\n changes = new Map<number, OPERATION>();\n this.changes.set(parentChangeTree, changes)\n }\n // DELETE / DELETE BY REF ID\n changes.set(changeTree.parentIndex, OPERATION.DELETE);\n\n } else {\n // delete all \"tagged\" properties.\n metadata[-2].forEach((index) =>\n changes.set(index, OPERATION.DELETE));\n }\n\n\n } else {\n // delete only tagged properties\n metadata[-3][tag].forEach((index) =>\n changes.set(index, OPERATION.DELETE));\n }\n\n // remove tag\n if (this.tags && this.tags.has(changeTree)) {\n const tags = this.tags.get(changeTree);\n if (tag === undefined) {\n // delete all tags\n this.tags.delete(changeTree);\n } else {\n // delete specific tag\n tags.delete(tag);\n\n // if tag set is empty, delete it entirely\n if (tags.size === 0) {\n this.tags.delete(changeTree);\n }\n }\n }\n\n return this;\n }\n}"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Schema } from "../Schema";
|
|
2
|
+
import { CollectionSchema } from "../types/custom/CollectionSchema";
|
|
3
|
+
import { MapSchema } from "../types/custom/MapSchema";
|
|
4
|
+
import { SetSchema } from "../types/custom/SetSchema";
|
|
5
|
+
import { ArraySchema } from "../types/custom/ArraySchema";
|
|
6
|
+
export declare class EncodeSchemaError extends Error {
|
|
7
|
+
}
|
|
8
|
+
export declare function assertType(value: any, type: string, klass: Schema, field: string | number): void;
|
|
9
|
+
export declare function assertInstanceType(value: Schema, type: typeof Schema | typeof ArraySchema | typeof MapSchema | typeof CollectionSchema | typeof SetSchema, klass: Schema, field: string | number): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertInstanceType = exports.assertType = exports.EncodeSchemaError = void 0;
|
|
4
|
+
class EncodeSchemaError extends Error {
|
|
5
|
+
}
|
|
6
|
+
exports.EncodeSchemaError = EncodeSchemaError;
|
|
7
|
+
function assertType(value, type, klass, field) {
|
|
8
|
+
let typeofTarget;
|
|
9
|
+
let allowNull = false;
|
|
10
|
+
switch (type) {
|
|
11
|
+
case "number":
|
|
12
|
+
case "int8":
|
|
13
|
+
case "uint8":
|
|
14
|
+
case "int16":
|
|
15
|
+
case "uint16":
|
|
16
|
+
case "int32":
|
|
17
|
+
case "uint32":
|
|
18
|
+
case "int64":
|
|
19
|
+
case "uint64":
|
|
20
|
+
case "float32":
|
|
21
|
+
case "float64":
|
|
22
|
+
typeofTarget = "number";
|
|
23
|
+
if (isNaN(value)) {
|
|
24
|
+
console.log(`trying to encode "NaN" in ${klass.constructor.name}#${field}`);
|
|
25
|
+
}
|
|
26
|
+
break;
|
|
27
|
+
case "string":
|
|
28
|
+
typeofTarget = "string";
|
|
29
|
+
allowNull = true;
|
|
30
|
+
break;
|
|
31
|
+
case "boolean":
|
|
32
|
+
// boolean is always encoded as true/false based on truthiness
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (typeof (value) !== typeofTarget && (!allowNull || (allowNull && value !== null))) {
|
|
36
|
+
let foundValue = `'${JSON.stringify(value)}'${(value && value.constructor && ` (${value.constructor.name})`) || ''}`;
|
|
37
|
+
throw new EncodeSchemaError(`a '${typeofTarget}' was expected, but ${foundValue} was provided in ${klass.constructor.name}#${field}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.assertType = assertType;
|
|
41
|
+
function assertInstanceType(value, type, klass, field) {
|
|
42
|
+
if (!(value instanceof type)) {
|
|
43
|
+
throw new EncodeSchemaError(`a '${type.name}' was expected, but '${value && value.constructor.name}' was provided in ${klass.constructor.name}#${field}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.assertInstanceType = assertInstanceType;
|
|
47
|
+
//# sourceMappingURL=assert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert.js","sourceRoot":"","sources":["../../src/encoding/assert.ts"],"names":[],"mappings":";;;AAMA,MAAa,iBAAkB,SAAQ,KAAK;CAAG;AAA/C,8CAA+C;AAE/C,SAAgB,UAAU,CAAC,KAAU,EAAE,IAAY,EAAE,KAAa,EAAE,KAAsB;IACtF,IAAI,YAAoB,CAAC;IACzB,IAAI,SAAS,GAAY,KAAK,CAAC;IAE/B,QAAQ,IAAI,EAAE,CAAC;QACX,KAAK,QAAQ,CAAC;QACd,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO,CAAC;QACb,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS,CAAC;QACf,KAAK,SAAS;YACV,YAAY,GAAG,QAAQ,CAAC;YACxB,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,6BAA6B,KAAK,CAAC,WAAW,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;YAChF,CAAC;YACD,MAAM;QACV,KAAK,QAAQ;YACT,YAAY,GAAG,QAAQ,CAAC;YACxB,SAAS,GAAG,IAAI,CAAC;YACjB,MAAM;QACV,KAAK,SAAS;YACV,8DAA8D;YAC9D,OAAO;IACf,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC;QACnF,IAAI,UAAU,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,KAAK,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;QACrH,MAAM,IAAI,iBAAiB,CAAC,MAAM,YAAY,uBAAuB,UAAU,oBAAoB,KAAK,CAAC,WAAW,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;IAC1I,CAAC;AACL,CAAC;AAlCD,gCAkCC;AAED,SAAgB,kBAAkB,CAC9B,KAAa,EACb,IAIsB,EACtB,KAAa,EACb,KAAsB;IAEtB,IAAI,CAAC,CAAC,KAAK,YAAY,IAAI,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,iBAAiB,CAAC,MAAM,IAAI,CAAC,IAAI,wBAAwB,KAAK,IAAK,KAAa,CAAC,WAAW,CAAC,IAAI,qBAAqB,KAAK,CAAC,WAAW,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;IACvK,CAAC;AACL,CAAC;AAbD,gDAaC","sourcesContent":["import { Schema } from \"../Schema\";\nimport { CollectionSchema } from \"../types/custom/CollectionSchema\";\nimport { MapSchema } from \"../types/custom/MapSchema\";\nimport { SetSchema } from \"../types/custom/SetSchema\";\nimport { ArraySchema } from \"../types/custom/ArraySchema\";\n\nexport class EncodeSchemaError extends Error {}\n\nexport function assertType(value: any, type: string, klass: Schema, field: string | number) {\n let typeofTarget: string;\n let allowNull: boolean = false;\n\n switch (type) {\n case \"number\":\n case \"int8\":\n case \"uint8\":\n case \"int16\":\n case \"uint16\":\n case \"int32\":\n case \"uint32\":\n case \"int64\":\n case \"uint64\":\n case \"float32\":\n case \"float64\":\n typeofTarget = \"number\";\n if (isNaN(value)) {\n console.log(`trying to encode \"NaN\" in ${klass.constructor.name}#${field}`);\n }\n break;\n case \"string\":\n typeofTarget = \"string\";\n allowNull = true;\n break;\n case \"boolean\":\n // boolean is always encoded as true/false based on truthiness\n return;\n }\n\n if (typeof (value) !== typeofTarget && (!allowNull || (allowNull && value !== null))) {\n let foundValue = `'${JSON.stringify(value)}'${(value && value.constructor && ` (${value.constructor.name})`) || ''}`;\n throw new EncodeSchemaError(`a '${typeofTarget}' was expected, but ${foundValue} was provided in ${klass.constructor.name}#${field}`);\n }\n}\n\nexport function assertInstanceType(\n value: Schema,\n type: typeof Schema\n | typeof ArraySchema\n | typeof MapSchema\n | typeof CollectionSchema\n | typeof SetSchema,\n klass: Schema,\n field: string | number,\n) {\n if (!(value instanceof type)) {\n throw new EncodeSchemaError(`a '${type.name}' was expected, but '${value && (value as any).constructor.name}' was provided in ${klass.constructor.name}#${field}`);\n }\n}"]}
|
package/lib/encoding/decode.js
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.switchStructureCheck = exports.arrayCheck = exports.numberCheck = exports.number = exports.stringCheck = exports.string = exports.boolean = exports.readFloat64 = exports.readFloat32 = exports.uint64 = exports.int64 = exports.float64 = exports.float32 = exports.uint32 = exports.int32 = exports.uint16 = exports.int16 = exports.uint8 = exports.int8 = void 0;
|
|
26
|
-
const spec_1 = require("
|
|
26
|
+
const spec_1 = require("./spec");
|
|
27
27
|
function utf8Read(bytes, offset, length) {
|
|
28
28
|
var string = '', chr = 0;
|
|
29
29
|
for (var i = offset, end = offset + length; i < end; i++) {
|