@colyseus/schema 3.0.0-alpha.3 → 3.0.0-alpha.30
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 +131 -61
- package/build/cjs/index.js +644 -283
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +643 -282
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +644 -283
- package/lib/Metadata.d.ts +2 -0
- package/lib/Metadata.js +39 -0
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.d.ts +2 -3
- package/lib/Reflection.js +31 -26
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +2 -2
- package/lib/Schema.js +2 -2
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +0 -19
- package/lib/annotations.js +15 -101
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.d.ts +1 -0
- package/lib/bench_encode.js +120 -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 +1 -2
- package/lib/codegen/languages/csharp.js.map +1 -1
- package/lib/codegen/languages/haxe.js +1 -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 +1 -2
- 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 +2 -3
- package/lib/codegen/parser.js.map +1 -1
- package/lib/codegen/types.js +3 -3
- package/lib/codegen/types.js.map +1 -1
- package/lib/debug.d.ts +1 -0
- package/lib/debug.js +52 -0
- package/lib/debug.js.map +1 -0
- package/lib/decoder/DecodeOperation.d.ts +0 -1
- package/lib/decoder/DecodeOperation.js +23 -7
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/Decoder.d.ts +6 -7
- package/lib/decoder/Decoder.js +8 -8
- package/lib/decoder/Decoder.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 +72 -63
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +1 -12
- package/lib/encoder/ChangeTree.js +29 -58
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +0 -1
- package/lib/encoder/EncodeOperation.js +29 -13
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +10 -8
- package/lib/encoder/Encoder.js +78 -53
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +17 -0
- package/lib/encoder/Root.js +44 -0
- package/lib/encoder/Root.js.map +1 -0
- package/lib/encoder/StateView.d.ts +2 -2
- package/lib/encoder/StateView.js +48 -58
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/assert.js +3 -3
- package/lib/encoding/assert.js.map +1 -1
- package/lib/encoding/decode.js +21 -22
- package/lib/encoding/decode.js.map +1 -1
- package/lib/encoding/encode.d.ts +2 -2
- package/lib/encoding/encode.js +40 -39
- package/lib/encoding/encode.js.map +1 -1
- package/lib/encoding/spec.d.ts +2 -1
- package/lib/encoding/spec.js +1 -0
- package/lib/encoding/spec.js.map +1 -1
- package/lib/index.d.ts +5 -1
- package/lib/index.js +8 -4
- package/lib/index.js.map +1 -1
- package/lib/types/TypeContext.d.ts +23 -0
- package/lib/types/TypeContext.js +109 -0
- package/lib/types/TypeContext.js.map +1 -0
- package/lib/types/custom/ArraySchema.d.ts +2 -2
- package/lib/types/custom/ArraySchema.js +0 -9
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/registry.js +3 -4
- package/lib/types/registry.js.map +1 -1
- package/lib/types/utils.js +1 -2
- package/lib/types/utils.js.map +1 -1
- package/lib/utils.js +3 -4
- package/lib/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/Metadata.ts +47 -0
- package/src/Reflection.ts +34 -26
- package/src/Schema.ts +2 -2
- package/src/annotations.ts +7 -109
- package/src/bench_encode.ts +97 -0
- package/src/debug.ts +56 -0
- package/src/decoder/DecodeOperation.ts +30 -7
- package/src/decoder/Decoder.ts +13 -11
- package/src/decoder/strategy/StateCallbacks.ts +149 -79
- package/src/encoder/ChangeTree.ts +36 -66
- package/src/encoder/EncodeOperation.ts +29 -12
- package/src/encoder/Encoder.ts +95 -61
- package/src/encoder/Root.ts +51 -0
- package/src/encoder/StateView.ts +51 -67
- package/src/encoding/decode.ts +1 -2
- package/src/encoding/encode.ts +25 -22
- package/src/encoding/spec.ts +1 -0
- package/src/index.ts +8 -11
- package/src/types/TypeContext.ts +127 -0
- package/src/types/custom/ArraySchema.ts +2 -2
package/src/encoder/Encoder.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type { Schema } from "../Schema";
|
|
2
|
-
import { TypeContext } from "../
|
|
2
|
+
import { TypeContext } from "../types/TypeContext";
|
|
3
3
|
import { $changes, $encoder, $filter } from "../types/symbols";
|
|
4
4
|
|
|
5
5
|
import * as encode from "../encoding/encode";
|
|
6
6
|
import type { Iterator } from "../encoding/decode";
|
|
7
7
|
|
|
8
|
-
import { SWITCH_TO_STRUCTURE, TYPE_ID } from '../encoding/spec';
|
|
9
|
-
import { Root } from "./
|
|
8
|
+
import { OPERATION, SWITCH_TO_STRUCTURE, TYPE_ID } from '../encoding/spec';
|
|
9
|
+
import { Root } from "./Root";
|
|
10
10
|
import { getNextPowerOf2 } from "../utils";
|
|
11
|
+
|
|
11
12
|
import type { StateView } from "./StateView";
|
|
13
|
+
import type { Metadata } from "../Metadata";
|
|
14
|
+
import type { ChangeTree } from "./ChangeTree";
|
|
12
15
|
|
|
13
16
|
export class Encoder<T extends Schema = any> {
|
|
14
17
|
static BUFFER_SIZE = 8 * 1024;// 8KB
|
|
@@ -19,14 +22,16 @@ export class Encoder<T extends Schema = any> {
|
|
|
19
22
|
|
|
20
23
|
root: Root;
|
|
21
24
|
|
|
22
|
-
constructor(
|
|
23
|
-
this.setRoot(root);
|
|
25
|
+
constructor(state: T) {
|
|
24
26
|
|
|
25
27
|
//
|
|
26
28
|
// TODO: cache and restore "Context" based on root schema
|
|
27
29
|
// (to avoid creating a new context for every new room)
|
|
28
30
|
//
|
|
29
|
-
this.context = new TypeContext(
|
|
31
|
+
this.context = new TypeContext(state.constructor as typeof Schema);
|
|
32
|
+
this.root = new Root(this.context);
|
|
33
|
+
|
|
34
|
+
this.setState(state);
|
|
30
35
|
|
|
31
36
|
// console.log(">>>>>>>>>>>>>>>> Encoder types");
|
|
32
37
|
// this.context.schemas.forEach((id, schema) => {
|
|
@@ -34,21 +39,19 @@ export class Encoder<T extends Schema = any> {
|
|
|
34
39
|
// });
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
protected
|
|
38
|
-
this.root = new Root();
|
|
42
|
+
protected setState(state: T) {
|
|
39
43
|
this.state = state;
|
|
40
|
-
state[$changes].setRoot(this.root);
|
|
44
|
+
this.state[$changes].setRoot(this.root);
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
encode(
|
|
44
48
|
it: Iterator = { offset: 0 },
|
|
45
49
|
view?: StateView,
|
|
46
|
-
|
|
47
|
-
changeTrees = this.root.changes
|
|
50
|
+
buffer = this.sharedBuffer,
|
|
51
|
+
changeTrees = this.root.changes,
|
|
52
|
+
isEncodeAll = this.root.allChanges === changeTrees,
|
|
53
|
+
initialOffset = it.offset // cache current offset in case we need to resize the buffer
|
|
48
54
|
): Buffer {
|
|
49
|
-
const initialOffset = it.offset; // cache current offset in case we need to resize the buffer
|
|
50
|
-
|
|
51
|
-
const isEncodeAll = this.root.allChanges === changeTrees;
|
|
52
55
|
const hasView = (view !== undefined);
|
|
53
56
|
const rootChangeTree = this.state[$changes];
|
|
54
57
|
|
|
@@ -61,6 +64,13 @@ export class Encoder<T extends Schema = any> {
|
|
|
61
64
|
const encoder = ctor[$encoder];
|
|
62
65
|
const filter = ctor[$filter];
|
|
63
66
|
|
|
67
|
+
// try { throw new Error(); } catch (e) {
|
|
68
|
+
// // only print if not coming from Reflection.ts
|
|
69
|
+
// if (!e.stack.includes("src/Reflection.ts")) {
|
|
70
|
+
// console.log("ChangeTree:", { ref: ref.constructor.name, });
|
|
71
|
+
// }
|
|
72
|
+
// }
|
|
73
|
+
|
|
64
74
|
if (hasView) {
|
|
65
75
|
if (!view.items.has(changeTree)) {
|
|
66
76
|
view.invisible.add(changeTree);
|
|
@@ -72,9 +82,10 @@ export class Encoder<T extends Schema = any> {
|
|
|
72
82
|
}
|
|
73
83
|
|
|
74
84
|
// skip root `refId` if it's the first change tree
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
85
|
+
// (unless it "hasView", which will need to revisit the root)
|
|
86
|
+
if (hasView || it.offset > initialOffset || changeTree !== rootChangeTree) {
|
|
87
|
+
buffer[it.offset++] = SWITCH_TO_STRUCTURE & 255;
|
|
88
|
+
encode.number(buffer, changeTree.refId, it);
|
|
78
89
|
}
|
|
79
90
|
|
|
80
91
|
const changesIterator = changes.entries();
|
|
@@ -88,32 +99,45 @@ export class Encoder<T extends Schema = any> {
|
|
|
88
99
|
// TODO: avoid checking if no view tags were defined
|
|
89
100
|
//
|
|
90
101
|
if (filter && !filter(ref, fieldIndex, view)) {
|
|
91
|
-
// console.log("SKIP FIELD:", { ref: changeTree.ref.constructor.name, fieldIndex, })
|
|
92
|
-
|
|
93
102
|
// console.log("ADD AS INVISIBLE:", fieldIndex, changeTree.ref.constructor.name)
|
|
94
103
|
// view?.invisible.add(changeTree);
|
|
95
104
|
continue;
|
|
96
105
|
}
|
|
97
106
|
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
// try { throw new Error(); } catch (e) {
|
|
108
|
+
// // only print if not coming from Reflection.ts
|
|
109
|
+
// if (!e.stack.includes("src/Reflection.ts")) {
|
|
110
|
+
// console.log("WILL ENCODE", {
|
|
111
|
+
// ref: changeTree.ref.constructor.name,
|
|
112
|
+
// fieldIndex,
|
|
113
|
+
// operation: OPERATION[operation],
|
|
114
|
+
// });
|
|
115
|
+
// }
|
|
116
|
+
// }
|
|
117
|
+
|
|
118
|
+
encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
|
|
105
119
|
}
|
|
106
120
|
}
|
|
107
121
|
|
|
108
|
-
if (it.offset >
|
|
109
|
-
const newSize = getNextPowerOf2(
|
|
110
|
-
console.warn(
|
|
122
|
+
if (it.offset > buffer.byteLength) {
|
|
123
|
+
const newSize = getNextPowerOf2(buffer.byteLength * 2);
|
|
124
|
+
console.warn(`@colyseus/schema buffer overflow. Encoded state is higher than default BUFFER_SIZE. Use the following to increase default BUFFER_SIZE:
|
|
125
|
+
|
|
126
|
+
import { Encoder } from "@colyseus/schema";
|
|
127
|
+
Encoder.BUFFER_SIZE = ${Math.round(newSize / 1024)} * 1024; // ${Math.round(newSize / 1024)} KB
|
|
128
|
+
`);
|
|
111
129
|
|
|
112
130
|
//
|
|
113
131
|
// resize buffer and re-encode (TODO: can we avoid re-encoding here?)
|
|
114
132
|
//
|
|
115
|
-
|
|
116
|
-
|
|
133
|
+
buffer = Buffer.allocUnsafeSlow(newSize);
|
|
134
|
+
|
|
135
|
+
// assign resized buffer to local sharedBuffer
|
|
136
|
+
if (buffer === this.sharedBuffer) {
|
|
137
|
+
this.sharedBuffer = buffer;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return this.encode({ offset: initialOffset }, view, buffer, changeTrees, isEncodeAll);
|
|
117
141
|
|
|
118
142
|
} else {
|
|
119
143
|
//
|
|
@@ -126,53 +150,60 @@ export class Encoder<T extends Schema = any> {
|
|
|
126
150
|
this.onEndEncode(changeTrees);
|
|
127
151
|
}
|
|
128
152
|
|
|
129
|
-
|
|
130
|
-
return bytes.slice(0, it.offset);
|
|
153
|
+
return buffer.subarray(0, it.offset);
|
|
131
154
|
}
|
|
132
155
|
}
|
|
133
156
|
|
|
134
|
-
encodeAll(it: Iterator = { offset: 0 }) {
|
|
135
|
-
// console.log(
|
|
136
|
-
|
|
137
|
-
// Array.from(this.$root.allChanges.entries()).map((item) => {
|
|
138
|
-
// console.log("->", item[0].refId, item[0].ref.toJSON());
|
|
139
|
-
// });
|
|
157
|
+
encodeAll(it: Iterator = { offset: 0 }, buffer: Buffer = this.sharedBuffer) {
|
|
158
|
+
// console.log(`\nencodeAll(), this.root.allChanges (${this.root.allChanges.size})`);
|
|
159
|
+
// this.debugChanges("allChanges");
|
|
140
160
|
|
|
141
|
-
return this.encode(it, undefined,
|
|
161
|
+
return this.encode(it, undefined, buffer, this.root.allChanges, true);
|
|
142
162
|
}
|
|
143
163
|
|
|
144
164
|
encodeAllView(view: StateView, sharedOffset: number, it: Iterator, bytes = this.sharedBuffer) {
|
|
145
165
|
const viewOffset = it.offset;
|
|
146
166
|
|
|
147
|
-
// console.log(
|
|
148
|
-
// this.
|
|
167
|
+
// console.log(`\nencodeAllView(), this.root.allFilteredChanges (${this.root.allFilteredChanges.size})`);
|
|
168
|
+
// this.debugChanges("allFilteredChanges");
|
|
149
169
|
|
|
150
170
|
// try to encode "filtered" changes
|
|
151
|
-
this.encode(it, view, bytes, this.root.allFilteredChanges);
|
|
171
|
+
this.encode(it, view, bytes, this.root.allFilteredChanges, true, viewOffset);
|
|
152
172
|
|
|
153
173
|
return Buffer.concat([
|
|
154
|
-
bytes.
|
|
155
|
-
bytes.
|
|
174
|
+
bytes.subarray(0, sharedOffset),
|
|
175
|
+
bytes.subarray(viewOffset, it.offset)
|
|
156
176
|
]);
|
|
157
177
|
}
|
|
158
178
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
179
|
+
debugChanges(
|
|
180
|
+
field: "changes" | "allFilteredChanges" | "allChanges" | "filteredChanges" | Map<ChangeTree, Map<number, OPERATION>>
|
|
181
|
+
) {
|
|
182
|
+
const changeSet = (typeof (field) === "string")
|
|
183
|
+
? this.root[field]
|
|
184
|
+
: field;
|
|
185
|
+
|
|
186
|
+
Array.from(changeSet.entries()).map((item) => {
|
|
187
|
+
const metadata: Metadata = item[0].ref.constructor[Symbol.metadata];
|
|
188
|
+
console.log("->", { ref: item[0].ref.constructor.name, refId: item[0].refId, changes: item[1].size });
|
|
189
|
+
item[1].forEach((op, index) => {
|
|
190
|
+
console.log(" ->", {
|
|
191
|
+
index,
|
|
192
|
+
field: metadata?.[index],
|
|
193
|
+
op: OPERATION[op],
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
}
|
|
170
198
|
|
|
171
199
|
encodeView(view: StateView, sharedOffset: number, it: Iterator, bytes = this.sharedBuffer) {
|
|
172
200
|
const viewOffset = it.offset;
|
|
173
201
|
|
|
174
|
-
//
|
|
175
|
-
this.
|
|
202
|
+
// console.log(`\nencodeView(), view.changes (${view.changes.size})`);
|
|
203
|
+
// this.debugChanges(view.changes);
|
|
204
|
+
|
|
205
|
+
// console.log(`\nencodeView(), this.root.filteredChanges (${this.root.filteredChanges.size})`);
|
|
206
|
+
// this.debugChanges("filteredChanges");
|
|
176
207
|
|
|
177
208
|
// encode visibility changes (add/remove for this view)
|
|
178
209
|
const viewChangesIterator = view.changes.entries();
|
|
@@ -207,9 +238,12 @@ export class Encoder<T extends Schema = any> {
|
|
|
207
238
|
// clear "view" changes after encoding
|
|
208
239
|
view.changes.clear();
|
|
209
240
|
|
|
241
|
+
// try to encode "filtered" changes
|
|
242
|
+
this.encode(it, view, bytes, this.root.filteredChanges, false, viewOffset);
|
|
243
|
+
|
|
210
244
|
return Buffer.concat([
|
|
211
|
-
bytes.
|
|
212
|
-
bytes.
|
|
245
|
+
bytes.subarray(0, sharedOffset),
|
|
246
|
+
bytes.subarray(viewOffset, it.offset)
|
|
213
247
|
]);
|
|
214
248
|
}
|
|
215
249
|
|
|
@@ -242,4 +276,4 @@ export class Encoder<T extends Schema = any> {
|
|
|
242
276
|
encode.number(bytes, targetTypeId, it);
|
|
243
277
|
}
|
|
244
278
|
}
|
|
245
|
-
}
|
|
279
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { OPERATION } from "../encoding/spec";
|
|
2
|
+
import { TypeContext } from "../types/TypeContext";
|
|
3
|
+
import { ChangeTree } from "./ChangeTree";
|
|
4
|
+
|
|
5
|
+
export class Root {
|
|
6
|
+
protected nextUniqueId: number = 0;
|
|
7
|
+
refCount = new WeakMap<ChangeTree, number>();
|
|
8
|
+
|
|
9
|
+
// all changes
|
|
10
|
+
allChanges = new Map<ChangeTree, Map<number, OPERATION>>();
|
|
11
|
+
allFilteredChanges = new Map<ChangeTree, Map<number, OPERATION>>();
|
|
12
|
+
|
|
13
|
+
// pending changes to be encoded
|
|
14
|
+
changes = new Map<ChangeTree, Map<number, OPERATION>>();
|
|
15
|
+
filteredChanges = new Map<ChangeTree, Map<number, OPERATION>>();
|
|
16
|
+
|
|
17
|
+
constructor(public types: TypeContext) { }
|
|
18
|
+
|
|
19
|
+
getNextUniqueId() {
|
|
20
|
+
return this.nextUniqueId++;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
add(changeTree: ChangeTree) {
|
|
24
|
+
const refCount = this.refCount.get(changeTree) || 0;
|
|
25
|
+
this.refCount.set(changeTree, refCount + 1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
remove(changeTree: ChangeTree) {
|
|
29
|
+
const refCount = this.refCount.get(changeTree);
|
|
30
|
+
if (refCount <= 1) {
|
|
31
|
+
this.allChanges.delete(changeTree);
|
|
32
|
+
this.changes.delete(changeTree);
|
|
33
|
+
|
|
34
|
+
if (changeTree.isFiltered || changeTree.isPartiallyFiltered) {
|
|
35
|
+
this.allFilteredChanges.delete(changeTree);
|
|
36
|
+
this.filteredChanges.delete(changeTree);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
this.refCount.delete(changeTree);
|
|
40
|
+
|
|
41
|
+
} else {
|
|
42
|
+
this.refCount.set(changeTree, refCount - 1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
changeTree.forEachChild((child, _) => this.remove(child));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
clear() {
|
|
49
|
+
this.changes.clear();
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/encoder/StateView.ts
CHANGED
|
@@ -28,25 +28,23 @@ export class StateView {
|
|
|
28
28
|
changes = new Map<ChangeTree, Map<number, OPERATION>>();
|
|
29
29
|
|
|
30
30
|
// TODO: allow to set multiple tags at once
|
|
31
|
-
add(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {
|
|
31
|
+
add(obj: Ref, tag: number = DEFAULT_VIEW_TAG, checkIncludeParent: boolean = true) {
|
|
32
32
|
if (!obj[$changes]) {
|
|
33
33
|
console.warn("StateView#add(), invalid object:", obj);
|
|
34
34
|
return this;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
let changeTree: ChangeTree = obj[$changes];
|
|
38
|
-
this.items.add(changeTree);
|
|
39
|
-
|
|
40
|
-
// Add children of this ChangeTree to this view
|
|
41
|
-
changeTree.forEachChild((change, _) =>
|
|
42
|
-
this.add(change.ref, tag));
|
|
43
|
-
|
|
44
37
|
// FIXME: ArraySchema/MapSchema does not have metadata
|
|
45
38
|
const metadata: Metadata = obj.constructor[Symbol.metadata];
|
|
39
|
+
const changeTree: ChangeTree = obj[$changes];
|
|
40
|
+
this.items.add(changeTree);
|
|
46
41
|
|
|
47
|
-
// add parent ChangeTree's
|
|
48
|
-
//
|
|
49
|
-
|
|
42
|
+
// add parent ChangeTree's
|
|
43
|
+
// - if it was invisible to this view
|
|
44
|
+
// - if it were previously filtered out
|
|
45
|
+
if (checkIncludeParent && changeTree.parent) {
|
|
46
|
+
this.addParent(changeTree.parent[$changes], changeTree.parentIndex, tag);
|
|
47
|
+
}
|
|
50
48
|
|
|
51
49
|
//
|
|
52
50
|
// TODO: when adding an item of a MapSchema, the changes may not
|
|
@@ -72,8 +70,6 @@ export class StateView {
|
|
|
72
70
|
}
|
|
73
71
|
tags.add(tag);
|
|
74
72
|
|
|
75
|
-
// console.log("BY TAG:", tag);
|
|
76
|
-
|
|
77
73
|
// Ref: add tagged properties
|
|
78
74
|
metadata?.[-3]?.[tag]?.forEach((index) => {
|
|
79
75
|
if (changeTree.getChange(index) !== OPERATION.DELETE) {
|
|
@@ -82,89 +78,77 @@ export class StateView {
|
|
|
82
78
|
});
|
|
83
79
|
|
|
84
80
|
} else {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
// // add default tag properties
|
|
89
|
-
// metadata?.[-3]?.[DEFAULT_VIEW_TAG]?.forEach((index) => {
|
|
90
|
-
// if (changeTree.getChange(index) !== OPERATION.DELETE) {
|
|
91
|
-
// changes.set(index, OPERATION.ADD);
|
|
92
|
-
// }
|
|
93
|
-
// });
|
|
94
|
-
|
|
95
|
-
const allChangesSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)
|
|
81
|
+
const isInvisible = this.invisible.has(changeTree);
|
|
82
|
+
const changeSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)
|
|
96
83
|
? changeTree.allFilteredChanges
|
|
97
84
|
: changeTree.allChanges;
|
|
98
|
-
const it = allChangesSet.keys();
|
|
99
|
-
const isInvisible = this.invisible.has(changeTree);
|
|
100
85
|
|
|
101
|
-
|
|
86
|
+
changeSet.forEach((op, index) => {
|
|
87
|
+
const tagAtIndex = metadata?.[metadata?.[index]].tag;
|
|
102
88
|
if (
|
|
103
|
-
(
|
|
104
|
-
|
|
89
|
+
(
|
|
90
|
+
isInvisible || // if "invisible", include all
|
|
91
|
+
tagAtIndex === undefined || // "all change" with no tag
|
|
92
|
+
tagAtIndex === tag // tagged property
|
|
93
|
+
) &&
|
|
94
|
+
op !== OPERATION.DELETE
|
|
105
95
|
) {
|
|
106
|
-
changes.set(index,
|
|
96
|
+
changes.set(index, op);
|
|
107
97
|
}
|
|
108
|
-
}
|
|
98
|
+
});
|
|
109
99
|
}
|
|
110
100
|
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
this.
|
|
118
|
-
}
|
|
101
|
+
// Add children of this ChangeTree to this view
|
|
102
|
+
changeTree.forEachChild((change, index) => {
|
|
103
|
+
// Do not ADD children that don't have the same tag
|
|
104
|
+
if (metadata && metadata[metadata[index]].tag !== tag) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.add(change.ref, tag, false);
|
|
108
|
+
});
|
|
119
109
|
|
|
120
110
|
return this;
|
|
121
111
|
}
|
|
122
112
|
|
|
123
|
-
protected addParent(changeTree: ChangeTree, tag: number) {
|
|
124
|
-
|
|
125
|
-
|
|
113
|
+
protected addParent(changeTree: ChangeTree, parentIndex: number, tag: number) {
|
|
114
|
+
// view must have all "changeTree" parent tree
|
|
115
|
+
this.items.add(changeTree);
|
|
126
116
|
|
|
127
|
-
|
|
128
|
-
const
|
|
117
|
+
// add parent's parent
|
|
118
|
+
const parentChangeTree = changeTree.parent?.[$changes];
|
|
119
|
+
if (parentChangeTree && (parentChangeTree.isFiltered || parentChangeTree.isPartiallyFiltered)) {
|
|
120
|
+
this.addParent(parentChangeTree, changeTree.parentIndex, tag);
|
|
121
|
+
}
|
|
129
122
|
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
// parent is already available, no need to add it!
|
|
124
|
+
if (!this.invisible.has(changeTree)) {
|
|
132
125
|
return;
|
|
133
126
|
}
|
|
134
127
|
|
|
135
|
-
this.addParent(parentChangeTree, tag);
|
|
136
|
-
|
|
137
128
|
// add parent's tag properties
|
|
138
|
-
if (
|
|
129
|
+
if (changeTree.getChange(parentIndex) !== OPERATION.DELETE) {
|
|
139
130
|
|
|
140
|
-
let
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
this.changes.set(
|
|
131
|
+
let changes = this.changes.get(changeTree);
|
|
132
|
+
if (changes === undefined) {
|
|
133
|
+
changes = new Map<number, OPERATION>();
|
|
134
|
+
this.changes.set(changeTree, changes);
|
|
144
135
|
}
|
|
145
136
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
// parentChange: (
|
|
150
|
-
// parentChangeTree.getChange(parentIndex) &&
|
|
151
|
-
// OPERATION[parentChangeTree.getChange(parentIndex)]
|
|
152
|
-
// ),
|
|
153
|
-
// })
|
|
137
|
+
if (!this.tags) {
|
|
138
|
+
this.tags = new WeakMap<ChangeTree, Set<number>>();
|
|
139
|
+
}
|
|
154
140
|
|
|
155
|
-
if (!this.tags) { this.tags = new WeakMap<ChangeTree, Set<number>>(); }
|
|
156
141
|
let tags: Set<number>;
|
|
157
|
-
if (!this.tags.has(
|
|
142
|
+
if (!this.tags.has(changeTree)) {
|
|
158
143
|
tags = new Set<number>();
|
|
159
|
-
this.tags.set(
|
|
144
|
+
this.tags.set(changeTree, tags);
|
|
160
145
|
} else {
|
|
161
|
-
tags = this.tags.get(
|
|
146
|
+
tags = this.tags.get(changeTree);
|
|
162
147
|
}
|
|
163
148
|
tags.add(tag);
|
|
164
149
|
|
|
165
|
-
|
|
150
|
+
changes.set(parentIndex, OPERATION.ADD);
|
|
166
151
|
}
|
|
167
|
-
|
|
168
152
|
}
|
|
169
153
|
|
|
170
154
|
remove(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {
|
package/src/encoding/decode.ts
CHANGED
|
@@ -32,8 +32,6 @@ import type { BufferLike } from "./encode";
|
|
|
32
32
|
export interface Iterator { offset: number; }
|
|
33
33
|
|
|
34
34
|
export function utf8Read(bytes: BufferLike, it: Iterator, length: number) {
|
|
35
|
-
it.offset += length;
|
|
36
|
-
|
|
37
35
|
var string = '', chr = 0;
|
|
38
36
|
for (var i = it.offset, end = it.offset + length; i < end; i++) {
|
|
39
37
|
var byte = bytes[i];
|
|
@@ -74,6 +72,7 @@ export function utf8Read(bytes: BufferLike, it: Iterator, length: number) {
|
|
|
74
72
|
// (do not throw error to avoid server/client from crashing due to hack attemps)
|
|
75
73
|
// throw new Error('Invalid byte ' + byte.toString(16));
|
|
76
74
|
}
|
|
75
|
+
it.offset += length;
|
|
77
76
|
return string;
|
|
78
77
|
}
|
|
79
78
|
|
package/src/encoding/encode.ts
CHANGED
|
@@ -35,28 +35,32 @@ let textEncoder: TextEncoder;
|
|
|
35
35
|
// @ts-ignore
|
|
36
36
|
try { textEncoder = new TextEncoder(); } catch (e) { }
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
38
|
+
const hasBufferByteLength = (typeof Buffer !== 'undefined' && Buffer.byteLength);
|
|
39
|
+
|
|
40
|
+
export const utf8Length = (hasBufferByteLength)
|
|
41
|
+
? Buffer.byteLength // node
|
|
42
|
+
: function (str: string, _?: any) {
|
|
43
|
+
var c = 0, length = 0;
|
|
44
|
+
for (var i = 0, l = str.length; i < l; i++) {
|
|
45
|
+
c = str.charCodeAt(i);
|
|
46
|
+
if (c < 0x80) {
|
|
47
|
+
length += 1;
|
|
48
|
+
}
|
|
49
|
+
else if (c < 0x800) {
|
|
50
|
+
length += 2;
|
|
51
|
+
}
|
|
52
|
+
else if (c < 0xd800 || c >= 0xe000) {
|
|
53
|
+
length += 3;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
i++;
|
|
57
|
+
length += 4;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return length;
|
|
54
61
|
}
|
|
55
|
-
}
|
|
56
|
-
return length;
|
|
57
|
-
}
|
|
58
62
|
|
|
59
|
-
export function utf8Write(view, str, it) {
|
|
63
|
+
export function utf8Write(view: BufferLike, str: string, it: Iterator) {
|
|
60
64
|
var c = 0;
|
|
61
65
|
for (var i = 0, l = str.length; i < l; i++) {
|
|
62
66
|
c = str.charCodeAt(i);
|
|
@@ -166,8 +170,7 @@ export function string(bytes: BufferLike, value: string, it: Iterator) {
|
|
|
166
170
|
// encode `null` strings as empty.
|
|
167
171
|
if (!value) { value = ""; }
|
|
168
172
|
|
|
169
|
-
|
|
170
|
-
let length = Buffer.byteLength(value, "utf8");
|
|
173
|
+
let length = utf8Length(value, "utf8");
|
|
171
174
|
let size = 0;
|
|
172
175
|
|
|
173
176
|
// fixstr
|
package/src/encoding/spec.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -4,6 +4,8 @@ export type { DataChange } from "./decoder/DecodeOperation";
|
|
|
4
4
|
import { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType } from "./types/symbols";
|
|
5
5
|
export { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType };
|
|
6
6
|
|
|
7
|
+
export type { ToJSON } from "./types/HelperTypes";
|
|
8
|
+
|
|
7
9
|
import { MapSchema } from "./types/custom/MapSchema"
|
|
8
10
|
export { MapSchema };
|
|
9
11
|
|
|
@@ -40,22 +42,17 @@ export {
|
|
|
40
42
|
ReflectionField,
|
|
41
43
|
} from "./Reflection";
|
|
42
44
|
|
|
45
|
+
// Annotations, Metadata and TypeContext
|
|
43
46
|
export { Metadata } from "./Metadata";
|
|
44
|
-
|
|
45
|
-
export {
|
|
46
|
-
// Annotations
|
|
47
|
-
type,
|
|
48
|
-
deprecated,
|
|
49
|
-
defineTypes,
|
|
50
|
-
view,
|
|
51
|
-
|
|
52
|
-
// Internals
|
|
53
|
-
TypeContext,
|
|
54
|
-
} from "./annotations";
|
|
47
|
+
export { type, deprecated, defineTypes, view, } from "./annotations";
|
|
48
|
+
export { TypeContext } from "./types/TypeContext";
|
|
55
49
|
|
|
56
50
|
// Annotation types
|
|
57
51
|
export type { DefinitionType, PrimitiveType, Definition, } from "./annotations";
|
|
58
52
|
|
|
53
|
+
export { getDecoderStateCallbacks, CallbackProxy, GetCallbackProxy } from "./decoder/strategy/StateCallbacks";
|
|
54
|
+
export { getRawChangesCallback } from "./decoder/strategy/RawChanges";
|
|
55
|
+
|
|
59
56
|
export { Encoder } from "./encoder/Encoder";
|
|
60
57
|
export { encodeSchemaOperation, encodeArray as encodeKeyValueOperation } from "./encoder/EncodeOperation";
|
|
61
58
|
export { ChangeTree, Ref } from "./encoder/ChangeTree";
|