@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
|
@@ -32,66 +32,80 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
32
32
|
refId: number;
|
|
33
33
|
|
|
34
34
|
root?: Root;
|
|
35
|
-
|
|
36
|
-
isFiltered?: boolean;
|
|
37
|
-
isPartiallyFiltered?: boolean;
|
|
38
|
-
|
|
39
35
|
parent?: Ref;
|
|
40
36
|
parentIndex?: number;
|
|
41
37
|
|
|
42
|
-
|
|
38
|
+
isFiltered: boolean = false;
|
|
39
|
+
isPartiallyFiltered: boolean = false;
|
|
40
|
+
|
|
43
41
|
currentOperationIndex: number = 0;
|
|
44
42
|
|
|
43
|
+
changes = new Map<number, OPERATION>();
|
|
45
44
|
allChanges = new Map<number, OPERATION>();
|
|
46
|
-
allFilteredChanges = new Map<number, OPERATION>();
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
filteredChanges
|
|
46
|
+
allFilteredChanges: Map<number, OPERATION>;
|
|
47
|
+
filteredChanges: Map<number, OPERATION>;
|
|
48
|
+
|
|
49
|
+
indexes: {[index: string]: any}; // TODO: remove this, only used by MapSchema/SetSchema/CollectionSchema (`encodeKeyValueOperation`)
|
|
50
50
|
|
|
51
51
|
[$isNew] = true;
|
|
52
52
|
|
|
53
53
|
constructor(ref: T) {
|
|
54
54
|
this.ref = ref;
|
|
55
|
+
|
|
56
|
+
//
|
|
57
|
+
// Does this structure have "filters" declared?
|
|
58
|
+
//
|
|
59
|
+
if (ref.constructor[Symbol.metadata]?.[-2]) {
|
|
60
|
+
this.allFilteredChanges = new Map<number, OPERATION>();
|
|
61
|
+
this.filteredChanges = new Map<number, OPERATION>();
|
|
62
|
+
}
|
|
55
63
|
}
|
|
56
64
|
|
|
57
65
|
setRoot(root: Root) {
|
|
58
66
|
this.root = root;
|
|
59
67
|
this.root.add(this);
|
|
60
68
|
|
|
61
|
-
|
|
62
|
-
// At Schema initialization, the "root" structure might not be available
|
|
63
|
-
// yet, as it only does once the "Encoder" has been set up.
|
|
64
|
-
//
|
|
65
|
-
// So the "parent" may be already set without a "root".
|
|
66
|
-
//
|
|
67
|
-
this.checkIsFiltered(this.parent, this.parentIndex);
|
|
69
|
+
const metadata: Metadata = this.ref.constructor[Symbol.metadata];
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
if (this.root.types.hasFilters) {
|
|
72
|
+
//
|
|
73
|
+
// At Schema initialization, the "root" structure might not be available
|
|
74
|
+
// yet, as it only does once the "Encoder" has been set up.
|
|
75
|
+
//
|
|
76
|
+
// So the "parent" may be already set without a "root".
|
|
77
|
+
//
|
|
78
|
+
this.checkIsFiltered(metadata, this.parent, this.parentIndex);
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
if (this.isFiltered || this.isPartiallyFiltered) {
|
|
81
|
+
this.root.allFilteredChanges.set(this, this.allFilteredChanges);
|
|
82
|
+
this.root.filteredChanges.set(this, this.filteredChanges);
|
|
83
|
+
}
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
if (!this.isFiltered) {
|
|
87
|
+
this.root.changes.set(this, this.changes);
|
|
82
88
|
this.root.allChanges.set(this, this.allChanges);
|
|
83
89
|
}
|
|
84
90
|
|
|
85
|
-
this.
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
this.ensureRefId();
|
|
92
|
+
|
|
93
|
+
if (metadata) {
|
|
94
|
+
metadata[-4]?.forEach((index) => {
|
|
95
|
+
const field = metadata[index as any as number];
|
|
96
|
+
const value = this.ref[field.name];
|
|
97
|
+
if (value) {
|
|
98
|
+
value[$changes].setRoot(root);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
} else if (this.ref[$childType] && typeof(this.ref[$childType]) !== "string") {
|
|
103
|
+
// MapSchema / ArraySchema, etc.
|
|
104
|
+
(this.ref as MapSchema).forEach((value, key) => {
|
|
105
|
+
value[$changes].setRoot(root);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
88
108
|
|
|
89
|
-
// this.allChanges.forEach((_, index) => {
|
|
90
|
-
// const childRef = this.ref[$getByIndex](index);
|
|
91
|
-
// if (childRef && childRef[$changes]) {
|
|
92
|
-
// childRef[$changes].setRoot(root);
|
|
93
|
-
// }
|
|
94
|
-
// });
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
setParent(
|
|
@@ -107,56 +121,71 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
107
121
|
|
|
108
122
|
root.add(this);
|
|
109
123
|
|
|
124
|
+
const metadata: Metadata = this.ref.constructor[Symbol.metadata];
|
|
125
|
+
|
|
110
126
|
// skip if parent is already set
|
|
111
|
-
if (root
|
|
112
|
-
this.
|
|
113
|
-
changeTree.setParent(this.ref, root, atIndex);
|
|
114
|
-
});
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
127
|
+
if (root !== this.root) {
|
|
128
|
+
this.root = root;
|
|
117
129
|
|
|
118
|
-
|
|
119
|
-
|
|
130
|
+
if (root.types.hasFilters) {
|
|
131
|
+
this.checkIsFiltered(metadata, parent, parentIndex);
|
|
120
132
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
133
|
+
if (this.isFiltered || this.isPartiallyFiltered) {
|
|
134
|
+
this.root.filteredChanges.set(this, this.filteredChanges);
|
|
135
|
+
this.root.allFilteredChanges.set(this, this.filteredChanges);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
125
138
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
139
|
+
if (!this.isFiltered) {
|
|
140
|
+
this.root.changes.set(this, this.changes);
|
|
141
|
+
this.root.allChanges.set(this, this.allChanges);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
this.ensureRefId();
|
|
129
145
|
}
|
|
130
146
|
|
|
131
|
-
|
|
147
|
+
// assign same parent on child structures
|
|
148
|
+
if (metadata) {
|
|
149
|
+
metadata[-4]?.forEach((index) => {
|
|
150
|
+
const field = metadata[index as any as number];
|
|
151
|
+
const value = this.ref[field.name];
|
|
152
|
+
value?.[$changes].setParent(this.ref, root, index);
|
|
153
|
+
|
|
154
|
+
// console.log(this.ref.constructor.name, field.name, value);
|
|
155
|
+
|
|
156
|
+
// try { throw new Error(); } catch (e) {
|
|
157
|
+
// console.log(e.stack);
|
|
158
|
+
// }
|
|
159
|
+
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
} else if (this.ref[$childType] && typeof(this.ref[$childType]) !== "string") {
|
|
163
|
+
// MapSchema / ArraySchema, etc.
|
|
164
|
+
(this.ref as MapSchema).forEach((value, key) => {
|
|
165
|
+
value[$changes].setParent(this.ref, root, this.indexes[key] ?? key);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
132
168
|
|
|
133
|
-
this.forEachChild((changeTree, atIndex) => {
|
|
134
|
-
changeTree.setParent(this.ref, root, atIndex);
|
|
135
|
-
});
|
|
136
169
|
}
|
|
137
170
|
|
|
138
171
|
forEachChild(callback: (change: ChangeTree, atIndex: number) => void) {
|
|
139
172
|
//
|
|
140
173
|
// assign same parent on child structures
|
|
141
174
|
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (value && value[$changes]) {
|
|
150
|
-
callback(value[$changes], metadata[field].index);
|
|
175
|
+
const metadata: Metadata = this.ref.constructor[Symbol.metadata];
|
|
176
|
+
if (metadata) {
|
|
177
|
+
metadata[-4]?.forEach((index) => {
|
|
178
|
+
const field = metadata[index as any as number];
|
|
179
|
+
const value = this.ref[field.name];
|
|
180
|
+
if (value) {
|
|
181
|
+
callback(value[$changes], index);
|
|
151
182
|
}
|
|
152
|
-
}
|
|
183
|
+
});
|
|
153
184
|
|
|
154
|
-
} else if (typeof
|
|
185
|
+
} else if (this.ref[$childType] && typeof(this.ref[$childType]) !== "string") {
|
|
155
186
|
// MapSchema / ArraySchema, etc.
|
|
156
187
|
(this.ref as MapSchema).forEach((value, key) => {
|
|
157
|
-
|
|
158
|
-
callback(value[$changes], this.ref[$changes].indexes[key] ?? key);
|
|
159
|
-
}
|
|
188
|
+
callback(value[$changes], this.indexes[key] ?? key);
|
|
160
189
|
});
|
|
161
190
|
}
|
|
162
191
|
}
|
|
@@ -167,9 +196,9 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
167
196
|
}
|
|
168
197
|
|
|
169
198
|
change(index: number, operation: OPERATION = OPERATION.ADD) {
|
|
170
|
-
const metadata = this.ref
|
|
199
|
+
const metadata = this.ref.constructor[Symbol.metadata] as Metadata;
|
|
171
200
|
|
|
172
|
-
const isFiltered = this.isFiltered || (metadata
|
|
201
|
+
const isFiltered = this.isFiltered || (metadata?.[index]?.tag !== undefined);
|
|
173
202
|
const changeSet = (isFiltered)
|
|
174
203
|
? this.filteredChanges
|
|
175
204
|
: this.changes;
|
|
@@ -181,17 +210,15 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
181
210
|
: (previousOperation === OPERATION.DELETE)
|
|
182
211
|
? OPERATION.DELETE_AND_ADD
|
|
183
212
|
: operation
|
|
213
|
+
//
|
|
214
|
+
// TODO: are DELETE operations being encoded as ADD here ??
|
|
215
|
+
//
|
|
184
216
|
changeSet.set(index, op);
|
|
185
217
|
}
|
|
186
218
|
|
|
187
|
-
//
|
|
188
|
-
// TODO: are DELETE operations being encoded as ADD here ??
|
|
189
|
-
//
|
|
190
|
-
|
|
191
219
|
if (isFiltered) {
|
|
192
|
-
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
193
|
-
|
|
194
220
|
this.allFilteredChanges.set(index, OPERATION.ADD);
|
|
221
|
+
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
195
222
|
this.root?.allFilteredChanges.set(this, this.allFilteredChanges);
|
|
196
223
|
|
|
197
224
|
} else {
|
|
@@ -244,10 +271,7 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
244
271
|
}
|
|
245
272
|
|
|
246
273
|
indexedOperation(index: number, operation: OPERATION, allChangesIndex = index) {
|
|
247
|
-
|
|
248
|
-
const isFiltered = this.isFiltered || (metadata && metadata[metadata[index]].tag !== undefined);
|
|
249
|
-
|
|
250
|
-
if (isFiltered) {
|
|
274
|
+
if (this.filteredChanges !== undefined) {
|
|
251
275
|
this.allFilteredChanges.set(allChangesIndex, OPERATION.ADD);
|
|
252
276
|
this.filteredChanges.set(index, operation);
|
|
253
277
|
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
@@ -261,8 +285,8 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
261
285
|
|
|
262
286
|
getType(index?: number) {
|
|
263
287
|
if (Metadata.isValidInstance(this.ref)) {
|
|
264
|
-
const metadata = this.ref
|
|
265
|
-
return metadata[
|
|
288
|
+
const metadata = this.ref.constructor[Symbol.metadata] as Metadata;
|
|
289
|
+
return metadata[index].type;
|
|
266
290
|
|
|
267
291
|
} else {
|
|
268
292
|
//
|
|
@@ -277,7 +301,7 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
277
301
|
|
|
278
302
|
getChange(index: number) {
|
|
279
303
|
// TODO: optimize this. avoid checking against multiple instances
|
|
280
|
-
return this.changes.get(index) ?? this.filteredChanges
|
|
304
|
+
return this.changes.get(index) ?? this.filteredChanges?.get(index);
|
|
281
305
|
}
|
|
282
306
|
|
|
283
307
|
//
|
|
@@ -300,9 +324,7 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
300
324
|
return;
|
|
301
325
|
}
|
|
302
326
|
|
|
303
|
-
const
|
|
304
|
-
const isFiltered = this.isFiltered || (metadata && metadata[metadata[index]].tag !== undefined);
|
|
305
|
-
const changeSet = (isFiltered)
|
|
327
|
+
const changeSet = (this.filteredChanges)
|
|
306
328
|
? this.filteredChanges
|
|
307
329
|
: this.changes;
|
|
308
330
|
|
|
@@ -312,8 +334,6 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
312
334
|
|
|
313
335
|
// remove `root` reference
|
|
314
336
|
if (previousValue && previousValue[$changes]) {
|
|
315
|
-
previousValue[$changes].root = undefined;
|
|
316
|
-
|
|
317
337
|
//
|
|
318
338
|
// FIXME: this.root is "undefined"
|
|
319
339
|
//
|
|
@@ -324,13 +344,20 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
324
344
|
//
|
|
325
345
|
// (the property descriptors should NOT be used at decoding time. only at encoding time.)
|
|
326
346
|
//
|
|
327
|
-
this.root?.remove(previousValue[$changes]);
|
|
347
|
+
const refCount = this.root?.remove(previousValue[$changes]);
|
|
348
|
+
|
|
349
|
+
//
|
|
350
|
+
// Only remove "root" reference if it's the last reference
|
|
351
|
+
//
|
|
352
|
+
if (refCount <= 0) {
|
|
353
|
+
previousValue[$changes].root = undefined;
|
|
354
|
+
}
|
|
328
355
|
}
|
|
329
356
|
|
|
330
357
|
//
|
|
331
358
|
// FIXME: this is looking a bit ugly (and repeated from `.change()`)
|
|
332
359
|
//
|
|
333
|
-
if (
|
|
360
|
+
if (this.filteredChanges) {
|
|
334
361
|
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
335
362
|
this.allFilteredChanges.delete(allChangesIndex);
|
|
336
363
|
|
|
@@ -342,6 +369,8 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
342
369
|
|
|
343
370
|
endEncode() {
|
|
344
371
|
this.changes.clear();
|
|
372
|
+
|
|
373
|
+
// ArraySchema and MapSchema have a custom "encode end" method
|
|
345
374
|
this.ref[$onEncodeEnd]?.();
|
|
346
375
|
|
|
347
376
|
// Not a new instance anymore
|
|
@@ -357,14 +386,14 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
357
386
|
this.ref[$onEncodeEnd]?.();
|
|
358
387
|
|
|
359
388
|
this.changes.clear();
|
|
360
|
-
this.filteredChanges
|
|
389
|
+
this.filteredChanges?.clear();
|
|
361
390
|
|
|
362
391
|
// reset operation index
|
|
363
392
|
this.currentOperationIndex = 0;
|
|
364
393
|
|
|
365
394
|
if (discardAll) {
|
|
366
395
|
this.allChanges.clear();
|
|
367
|
-
this.allFilteredChanges
|
|
396
|
+
this.allFilteredChanges?.clear();
|
|
368
397
|
|
|
369
398
|
// remove children references
|
|
370
399
|
this.forEachChild((changeTree, _) =>
|
|
@@ -400,60 +429,47 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
400
429
|
return this.changes.size > 0;
|
|
401
430
|
}
|
|
402
431
|
|
|
403
|
-
protected checkIsFiltered(parent: Ref, parentIndex: number) {
|
|
432
|
+
protected checkIsFiltered(metadata: Metadata, parent: Ref, parentIndex: number) {
|
|
404
433
|
// Detect if current structure has "filters" declared
|
|
405
|
-
this.isPartiallyFiltered =
|
|
434
|
+
this.isPartiallyFiltered = metadata?.[-2] !== undefined;
|
|
406
435
|
|
|
407
|
-
if (
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
parentIndex = parentChangeTree.parentIndex;
|
|
436
|
+
if (this.isPartiallyFiltered) {
|
|
437
|
+
this.filteredChanges = this.filteredChanges || new Map<number, OPERATION>();
|
|
438
|
+
this.allFilteredChanges = this.allFilteredChanges || new Map<number, OPERATION>();
|
|
411
439
|
}
|
|
412
440
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
// this.isFiltered = this.ref['constructor']?.[Symbol.metadata]?.[-4];
|
|
421
|
-
|
|
422
|
-
// // Detect if parent has "filters" declared
|
|
423
|
-
// while (parent && !this.isFiltered) {
|
|
424
|
-
// const metadata: Metadata = parent['constructor'][Symbol.metadata];
|
|
425
|
-
// // this.isFiltered = metadata?.[-4];
|
|
426
|
-
|
|
427
|
-
// const fieldName = metadata?.[parentIndex];
|
|
428
|
-
// const isParentOwned = metadata?.[fieldName]?.tag !== undefined;
|
|
429
|
-
// this.isFiltered = isParentOwned || parent[$changes].isFiltered; // metadata?.[-2]
|
|
430
|
-
|
|
431
|
-
// parent = parent[$changes].parent;
|
|
432
|
-
// };
|
|
441
|
+
if (parent) {
|
|
442
|
+
if (!Metadata.isValidInstance(parent)) {
|
|
443
|
+
const parentChangeTree = parent[$changes];
|
|
444
|
+
parent = parentChangeTree.parent;
|
|
445
|
+
parentIndex = parentChangeTree.parentIndex;
|
|
446
|
+
}
|
|
433
447
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
// ref: this.ref.constructor.name,
|
|
437
|
-
// isFiltered: this.isFiltered,
|
|
438
|
-
// isPartiallyFiltered: this.isPartiallyFiltered,
|
|
439
|
-
// });
|
|
448
|
+
const parentMetadata = parent?.constructor?.[Symbol.metadata];
|
|
449
|
+
this.isFiltered = (parent && parentMetadata?.[-2]?.includes(parentIndex));
|
|
440
450
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
451
|
+
//
|
|
452
|
+
// TODO: refactor this!
|
|
453
|
+
//
|
|
454
|
+
// swapping `changes` and `filteredChanges` is required here
|
|
455
|
+
// because "isFiltered" may not be imedialely available on `change()`
|
|
456
|
+
//
|
|
457
|
+
if (this.isFiltered) {
|
|
458
|
+
this.filteredChanges = new Map<number, OPERATION>();
|
|
459
|
+
this.allFilteredChanges = new Map<number, OPERATION>();
|
|
460
|
+
|
|
461
|
+
if (this.changes.size > 0) {
|
|
462
|
+
// swap changes reference
|
|
463
|
+
const changes = this.changes;
|
|
464
|
+
this.changes = this.filteredChanges;
|
|
465
|
+
this.filteredChanges = changes;
|
|
466
|
+
|
|
467
|
+
// swap "all changes" reference
|
|
468
|
+
const allFilteredChanges = this.allFilteredChanges;
|
|
469
|
+
this.allFilteredChanges = this.allChanges;
|
|
470
|
+
this.allChanges = allFilteredChanges;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
457
473
|
}
|
|
458
474
|
}
|
|
459
475
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { OPERATION } from "../encoding/spec";
|
|
2
|
-
import { $changes } from "../types/symbols";
|
|
2
|
+
import { $changes, $childType, $getByIndex } from "../types/symbols";
|
|
3
3
|
import { getType } from "../types/registry";
|
|
4
4
|
|
|
5
5
|
import * as encode from "../encoding/encode";
|
|
6
|
-
import { EncodeSchemaError, assertInstanceType, assertType } from "../encoding/assert";
|
|
6
|
+
// import { EncodeSchemaError, assertInstanceType, assertType } from "../encoding/assert";
|
|
7
7
|
|
|
8
8
|
import type { ChangeTree, Ref } from "./ChangeTree";
|
|
9
9
|
import type { Encoder } from "./Encoder";
|
|
@@ -12,6 +12,7 @@ import type { PrimitiveType } from "../annotations";
|
|
|
12
12
|
|
|
13
13
|
import type { Iterator } from "../encoding/decode";
|
|
14
14
|
import type { ArraySchema } from "../types/custom/ArraySchema";
|
|
15
|
+
import type { Metadata } from "../Metadata";
|
|
15
16
|
|
|
16
17
|
export type EncodeOperation<T extends Ref = any> = (
|
|
17
18
|
encoder: Encoder,
|
|
@@ -24,41 +25,18 @@ export type EncodeOperation<T extends Ref = any> = (
|
|
|
24
25
|
hasView: boolean,
|
|
25
26
|
) => void;
|
|
26
27
|
|
|
27
|
-
export function encodePrimitiveType(
|
|
28
|
-
type: PrimitiveType,
|
|
29
|
-
bytes: Buffer,
|
|
30
|
-
value: any,
|
|
31
|
-
klass: Schema,
|
|
32
|
-
field: string | number,
|
|
33
|
-
it: Iterator,
|
|
34
|
-
) {
|
|
35
|
-
assertType(value, type as string, klass, field);
|
|
36
|
-
|
|
37
|
-
const encodeFunc = encode[type as string];
|
|
38
|
-
|
|
39
|
-
if (encodeFunc) {
|
|
40
|
-
encodeFunc(bytes, value, it);
|
|
41
|
-
// encodeFunc(bytes, value);
|
|
42
|
-
|
|
43
|
-
} else {
|
|
44
|
-
throw new EncodeSchemaError(`a '${type}' was expected, but ${value} was provided in ${klass.constructor.name}#${field}`);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
28
|
export function encodeValue(
|
|
49
29
|
encoder: Encoder,
|
|
50
30
|
bytes: Buffer,
|
|
51
|
-
ref: Ref,
|
|
52
31
|
type: any,
|
|
53
32
|
value: any,
|
|
54
|
-
field: string | number,
|
|
55
33
|
operation: OPERATION,
|
|
56
34
|
it: Iterator,
|
|
57
35
|
) {
|
|
58
|
-
if (type
|
|
59
|
-
|
|
60
|
-
assertInstanceType(value, type as typeof Schema, ref as Schema, field);
|
|
36
|
+
if (typeof (type) === "string") {
|
|
37
|
+
encode[type]?.(bytes, value, it);
|
|
61
38
|
|
|
39
|
+
} else if (type[Symbol.metadata] !== undefined) {
|
|
62
40
|
//
|
|
63
41
|
// Encode refId for this instance.
|
|
64
42
|
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
@@ -70,23 +48,7 @@ export function encodeValue(
|
|
|
70
48
|
encoder.tryEncodeTypeId(bytes, type as typeof Schema, value.constructor as typeof Schema, it);
|
|
71
49
|
}
|
|
72
50
|
|
|
73
|
-
} else if (typeof (type) === "string") {
|
|
74
|
-
//
|
|
75
|
-
// Primitive values
|
|
76
|
-
//
|
|
77
|
-
encodePrimitiveType(type as PrimitiveType, bytes, value, ref as Schema, field, it);
|
|
78
|
-
|
|
79
51
|
} else {
|
|
80
|
-
//
|
|
81
|
-
// Custom type (MapSchema, ArraySchema, etc)
|
|
82
|
-
//
|
|
83
|
-
const definition = getType(Object.keys(type)[0]);
|
|
84
|
-
|
|
85
|
-
//
|
|
86
|
-
// ensure a ArraySchema has been provided
|
|
87
|
-
//
|
|
88
|
-
assertInstanceType(ref[field], definition.constructor, ref as Schema, field);
|
|
89
|
-
|
|
90
52
|
//
|
|
91
53
|
// Encode refId for this instance.
|
|
92
54
|
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
@@ -107,13 +69,6 @@ export const encodeSchemaOperation: EncodeOperation = function (
|
|
|
107
69
|
operation: OPERATION,
|
|
108
70
|
it: Iterator,
|
|
109
71
|
) {
|
|
110
|
-
const ref = changeTree.ref;
|
|
111
|
-
const metadata = ref['constructor'][Symbol.metadata];
|
|
112
|
-
|
|
113
|
-
const field = metadata[index];
|
|
114
|
-
const type = metadata[field].type;
|
|
115
|
-
const value = ref[field];
|
|
116
|
-
|
|
117
72
|
// "compress" field index + operation
|
|
118
73
|
bytes[it.offset++] = (index | operation) & 255;
|
|
119
74
|
|
|
@@ -122,8 +77,19 @@ export const encodeSchemaOperation: EncodeOperation = function (
|
|
|
122
77
|
return;
|
|
123
78
|
}
|
|
124
79
|
|
|
80
|
+
const ref = changeTree.ref;
|
|
81
|
+
const metadata: Metadata = ref.constructor[Symbol.metadata];
|
|
82
|
+
const field = metadata[index];
|
|
83
|
+
|
|
125
84
|
// TODO: inline this function call small performance gain
|
|
126
|
-
encodeValue(
|
|
85
|
+
encodeValue(
|
|
86
|
+
encoder,
|
|
87
|
+
bytes,
|
|
88
|
+
metadata[index].type,
|
|
89
|
+
ref[field.name],
|
|
90
|
+
operation,
|
|
91
|
+
it
|
|
92
|
+
);
|
|
127
93
|
}
|
|
128
94
|
|
|
129
95
|
/**
|
|
@@ -134,12 +100,10 @@ export const encodeKeyValueOperation: EncodeOperation = function (
|
|
|
134
100
|
encoder: Encoder,
|
|
135
101
|
bytes: Buffer,
|
|
136
102
|
changeTree: ChangeTree,
|
|
137
|
-
|
|
103
|
+
index: number,
|
|
138
104
|
operation: OPERATION,
|
|
139
105
|
it: Iterator,
|
|
140
106
|
) {
|
|
141
|
-
const ref = changeTree.ref;
|
|
142
|
-
|
|
143
107
|
// encode operation
|
|
144
108
|
bytes[it.offset++] = operation & 255;
|
|
145
109
|
|
|
@@ -149,28 +113,30 @@ export const encodeKeyValueOperation: EncodeOperation = function (
|
|
|
149
113
|
}
|
|
150
114
|
|
|
151
115
|
// encode index
|
|
152
|
-
encode.number(bytes,
|
|
116
|
+
encode.number(bytes, index, it);
|
|
153
117
|
|
|
154
118
|
// Do not encode value for DELETE operations
|
|
155
119
|
if (operation === OPERATION.DELETE) {
|
|
156
120
|
return;
|
|
157
121
|
}
|
|
158
122
|
|
|
123
|
+
const ref = changeTree.ref;
|
|
124
|
+
|
|
159
125
|
//
|
|
160
126
|
// encode "alias" for dynamic fields (maps)
|
|
161
127
|
//
|
|
162
|
-
if ((operation & OPERATION.ADD)
|
|
128
|
+
if ((operation & OPERATION.ADD) === OPERATION.ADD) { // ADD or DELETE_AND_ADD
|
|
163
129
|
if (typeof(ref['set']) === "function") {
|
|
164
130
|
//
|
|
165
131
|
// MapSchema dynamic key
|
|
166
132
|
//
|
|
167
|
-
const dynamicIndex = changeTree.ref['$indexes'].get(
|
|
133
|
+
const dynamicIndex = changeTree.ref['$indexes'].get(index);
|
|
168
134
|
encode.string(bytes, dynamicIndex, it);
|
|
169
135
|
}
|
|
170
136
|
}
|
|
171
137
|
|
|
172
|
-
const type =
|
|
173
|
-
const value =
|
|
138
|
+
const type = ref[$childType];
|
|
139
|
+
const value = ref[$getByIndex](index);
|
|
174
140
|
|
|
175
141
|
// try { throw new Error(); } catch (e) {
|
|
176
142
|
// // only print if not coming from Reflection.ts
|
|
@@ -186,7 +152,14 @@ export const encodeKeyValueOperation: EncodeOperation = function (
|
|
|
186
152
|
// }
|
|
187
153
|
|
|
188
154
|
// TODO: inline this function call small performance gain
|
|
189
|
-
encodeValue(
|
|
155
|
+
encodeValue(
|
|
156
|
+
encoder,
|
|
157
|
+
bytes,
|
|
158
|
+
type,
|
|
159
|
+
value,
|
|
160
|
+
operation,
|
|
161
|
+
it
|
|
162
|
+
);
|
|
190
163
|
}
|
|
191
164
|
|
|
192
165
|
/**
|
|
@@ -250,5 +223,12 @@ export const encodeArray: EncodeOperation = function (
|
|
|
250
223
|
// });
|
|
251
224
|
|
|
252
225
|
// TODO: inline this function call small performance gain
|
|
253
|
-
encodeValue(
|
|
226
|
+
encodeValue(
|
|
227
|
+
encoder,
|
|
228
|
+
bytes,
|
|
229
|
+
type,
|
|
230
|
+
value,
|
|
231
|
+
operation,
|
|
232
|
+
it
|
|
233
|
+
);
|
|
254
234
|
}
|