@colyseus/schema 3.0.0-alpha.30 → 3.0.0-alpha.31
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 +383 -341
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +383 -341
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +383 -341
- 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 +33 -11
- package/lib/bench_encode.js.map +1 -1
- package/lib/decoder/DecodeOperation.js +4 -8
- 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 +128 -115
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +1 -4
- package/lib/encoder/EncodeOperation.js +46 -46
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.js +11 -3
- package/lib/encoder/Encoder.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 +37 -13
- package/src/decoder/DecodeOperation.ts +4 -10
- package/src/decoder/ReferenceTracker.ts +3 -2
- package/src/decoder/strategy/StateCallbacks.ts +4 -3
- package/src/encoder/ChangeTree.ts +146 -135
- package/src/encoder/EncodeOperation.ts +64 -58
- package/src/encoder/Encoder.ts +16 -4
- package/src/encoder/StateView.ts +4 -4
- package/src/encoding/assert.ts +4 -3
- package/src/index.ts +1 -4
- package/src/types/TypeContext.ts +10 -15
- package/src/types/custom/ArraySchema.ts +8 -0
- package/src/types/custom/CollectionSchema.ts +1 -0
- package/src/types/custom/MapSchema.ts +6 -0
- package/src/types/custom/SetSchema.ts +1 -0
- package/src/types/symbols.ts +2 -0
package/build/esm/index.mjs
CHANGED
|
@@ -34,6 +34,7 @@ const $decoder = Symbol("$decoder");
|
|
|
34
34
|
const $filter = Symbol("$filter");
|
|
35
35
|
const $getByIndex = Symbol("$getByIndex");
|
|
36
36
|
const $deleteByIndex = Symbol("$deleteByIndex");
|
|
37
|
+
const $descriptors = Symbol("$descriptors");
|
|
37
38
|
/**
|
|
38
39
|
* Used to hold ChangeTree instances whitin the structures
|
|
39
40
|
*/
|
|
@@ -69,34 +70,67 @@ function getType(identifier) {
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
const Metadata = {
|
|
72
|
-
addField(metadata, index,
|
|
73
|
+
addField(metadata, index, name, type, descriptor) {
|
|
73
74
|
if (index > 64) {
|
|
74
|
-
throw new Error(`Can't define field '${
|
|
75
|
+
throw new Error(`Can't define field '${name}'.\nSchema instances may only have up to 64 fields.`);
|
|
75
76
|
}
|
|
76
|
-
metadata[
|
|
77
|
+
metadata[index] = Object.assign(metadata[index] || {}, // avoid overwriting previous field metadata (@owned / @deprecated)
|
|
77
78
|
{
|
|
78
79
|
type: (Array.isArray(type))
|
|
79
80
|
? { array: type[0] }
|
|
80
81
|
: type,
|
|
81
82
|
index,
|
|
82
|
-
|
|
83
|
+
name,
|
|
83
84
|
});
|
|
85
|
+
// create "descriptors" map
|
|
86
|
+
metadata[$descriptors] ??= {};
|
|
87
|
+
if (descriptor) {
|
|
88
|
+
// for encoder
|
|
89
|
+
metadata[$descriptors][name] = descriptor;
|
|
90
|
+
metadata[$descriptors][`_${name}`] = {
|
|
91
|
+
value: undefined,
|
|
92
|
+
writable: true,
|
|
93
|
+
enumerable: false,
|
|
94
|
+
configurable: true,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
// for decoder
|
|
99
|
+
metadata[$descriptors][name] = {
|
|
100
|
+
value: undefined,
|
|
101
|
+
writable: true,
|
|
102
|
+
enumerable: true,
|
|
103
|
+
configurable: true,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
84
106
|
// map -1 as last field index
|
|
85
107
|
Object.defineProperty(metadata, -1, {
|
|
86
108
|
value: index,
|
|
87
109
|
enumerable: false,
|
|
88
110
|
configurable: true
|
|
89
111
|
});
|
|
90
|
-
// map
|
|
91
|
-
Object.defineProperty(metadata,
|
|
92
|
-
value:
|
|
112
|
+
// map field name => index (non enumerable)
|
|
113
|
+
Object.defineProperty(metadata, name, {
|
|
114
|
+
value: index,
|
|
93
115
|
enumerable: false,
|
|
94
116
|
configurable: true,
|
|
95
117
|
});
|
|
118
|
+
// if child Ref/complex type, add to -4
|
|
119
|
+
if (typeof (metadata[index].type) !== "string") {
|
|
120
|
+
if (metadata[-4] === undefined) {
|
|
121
|
+
Object.defineProperty(metadata, -4, {
|
|
122
|
+
value: [],
|
|
123
|
+
enumerable: false,
|
|
124
|
+
configurable: true,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
metadata[-4].push(index);
|
|
128
|
+
}
|
|
96
129
|
},
|
|
97
130
|
setTag(metadata, fieldName, tag) {
|
|
131
|
+
const index = metadata[fieldName];
|
|
132
|
+
const field = metadata[index];
|
|
98
133
|
// add 'tag' to the field
|
|
99
|
-
const field = metadata[fieldName];
|
|
100
134
|
field.tag = tag;
|
|
101
135
|
if (!metadata[-2]) {
|
|
102
136
|
// -2: all field indexes with "view" tag
|
|
@@ -112,20 +146,14 @@ const Metadata = {
|
|
|
112
146
|
configurable: true
|
|
113
147
|
});
|
|
114
148
|
}
|
|
115
|
-
metadata[-2].push(
|
|
149
|
+
metadata[-2].push(index);
|
|
116
150
|
if (!metadata[-3][tag]) {
|
|
117
151
|
metadata[-3][tag] = [];
|
|
118
152
|
}
|
|
119
|
-
metadata[-3][tag].push(
|
|
153
|
+
metadata[-3][tag].push(index);
|
|
120
154
|
},
|
|
121
155
|
setFields(target, fields) {
|
|
122
156
|
const metadata = (target.prototype.constructor[Symbol.metadata] ??= {});
|
|
123
|
-
// target[$track] = function (changeTree, index: number, operation: OPERATION = OPERATION.ADD) {
|
|
124
|
-
// changeTree.change(index, operation, encodeSchemaOperation);
|
|
125
|
-
// };
|
|
126
|
-
// target[$encoder] = encodeSchemaOperation;
|
|
127
|
-
// target[$decoder] = decodeSchemaOperation;
|
|
128
|
-
// if (!target.prototype.toJSON) { target.prototype.toJSON = Schema.prototype.toJSON; }
|
|
129
157
|
let index = 0;
|
|
130
158
|
for (const field in fields) {
|
|
131
159
|
const type = fields[field];
|
|
@@ -133,7 +161,7 @@ const Metadata = {
|
|
|
133
161
|
const complexTypeKlass = (Array.isArray(type))
|
|
134
162
|
? getType("array")
|
|
135
163
|
: (typeof (Object.keys(type)[0]) === "string") && getType(Object.keys(type)[0]);
|
|
136
|
-
Metadata.addField(metadata, index, field, type, getPropertyDescriptor(`_${field}`, index, type, complexTypeKlass
|
|
164
|
+
Metadata.addField(metadata, index, field, type, getPropertyDescriptor(`_${field}`, index, type, complexTypeKlass));
|
|
137
165
|
index++;
|
|
138
166
|
}
|
|
139
167
|
},
|
|
@@ -162,8 +190,9 @@ const Metadata = {
|
|
|
162
190
|
// assign parent metadata to current
|
|
163
191
|
Object.assign(metadata, parentMetadata);
|
|
164
192
|
for (let i = 0; i <= parentMetadata[-1]; i++) {
|
|
165
|
-
|
|
166
|
-
|
|
193
|
+
const fieldName = parentMetadata[i].name;
|
|
194
|
+
Object.defineProperty(metadata, fieldName, {
|
|
195
|
+
value: parentMetadata[fieldName],
|
|
167
196
|
enumerable: false,
|
|
168
197
|
configurable: true,
|
|
169
198
|
});
|
|
@@ -187,7 +216,7 @@ const Metadata = {
|
|
|
187
216
|
const metadata = klass[Symbol.metadata];
|
|
188
217
|
const fields = {};
|
|
189
218
|
for (let i = 0; i <= metadata[-1]; i++) {
|
|
190
|
-
fields[metadata[i]] = metadata[
|
|
219
|
+
fields[metadata[i].name] = metadata[i].type;
|
|
191
220
|
}
|
|
192
221
|
return fields;
|
|
193
222
|
}
|
|
@@ -196,48 +225,59 @@ const Metadata = {
|
|
|
196
225
|
var _a$5;
|
|
197
226
|
class ChangeTree {
|
|
198
227
|
static { _a$5 = $isNew; }
|
|
199
|
-
;
|
|
200
228
|
constructor(ref) {
|
|
201
|
-
this.
|
|
229
|
+
this.isFiltered = false;
|
|
230
|
+
this.isPartiallyFiltered = false;
|
|
202
231
|
this.currentOperationIndex = 0;
|
|
203
|
-
this.allChanges = new Map();
|
|
204
|
-
this.allFilteredChanges = new Map();
|
|
205
232
|
this.changes = new Map();
|
|
206
|
-
this.
|
|
233
|
+
this.allChanges = new Map();
|
|
207
234
|
this[_a$5] = true;
|
|
208
235
|
this.ref = ref;
|
|
236
|
+
//
|
|
237
|
+
// Does this structure have "filters" declared?
|
|
238
|
+
//
|
|
239
|
+
if (ref.constructor[Symbol.metadata]?.[-2]) {
|
|
240
|
+
this.allFilteredChanges = new Map();
|
|
241
|
+
this.filteredChanges = new Map();
|
|
242
|
+
}
|
|
209
243
|
}
|
|
210
244
|
setRoot(root) {
|
|
211
245
|
this.root = root;
|
|
212
246
|
this.root.add(this);
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
247
|
+
const metadata = this.ref.constructor[Symbol.metadata];
|
|
248
|
+
if (this.root.types.hasFilters) {
|
|
249
|
+
//
|
|
250
|
+
// At Schema initialization, the "root" structure might not be available
|
|
251
|
+
// yet, as it only does once the "Encoder" has been set up.
|
|
252
|
+
//
|
|
253
|
+
// So the "parent" may be already set without a "root".
|
|
254
|
+
//
|
|
255
|
+
this.checkIsFiltered(metadata, this.parent, this.parentIndex);
|
|
256
|
+
if (this.isFiltered || this.isPartiallyFiltered) {
|
|
257
|
+
this.root.allFilteredChanges.set(this, this.allFilteredChanges);
|
|
258
|
+
this.root.filteredChanges.set(this, this.filteredChanges);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
222
261
|
if (!this.isFiltered) {
|
|
223
262
|
this.root.changes.set(this, this.changes);
|
|
263
|
+
this.root.allChanges.set(this, this.allChanges);
|
|
224
264
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
265
|
+
this.ensureRefId();
|
|
266
|
+
if (metadata) {
|
|
267
|
+
metadata[-4]?.forEach((index) => {
|
|
268
|
+
const field = metadata[index];
|
|
269
|
+
const value = this.ref[field.name];
|
|
270
|
+
if (value) {
|
|
271
|
+
value[$changes].setRoot(root);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
228
274
|
}
|
|
229
|
-
if (
|
|
230
|
-
|
|
275
|
+
else if (this.ref[$childType] && typeof (this.ref[$childType]) !== "string") {
|
|
276
|
+
// MapSchema / ArraySchema, etc.
|
|
277
|
+
this.ref.forEach((value, key) => {
|
|
278
|
+
value[$changes].setRoot(root);
|
|
279
|
+
});
|
|
231
280
|
}
|
|
232
|
-
this.forEachChild((changeTree, _) => {
|
|
233
|
-
changeTree.setRoot(root);
|
|
234
|
-
});
|
|
235
|
-
// this.allChanges.forEach((_, index) => {
|
|
236
|
-
// const childRef = this.ref[$getByIndex](index);
|
|
237
|
-
// if (childRef && childRef[$changes]) {
|
|
238
|
-
// childRef[$changes].setRoot(root);
|
|
239
|
-
// }
|
|
240
|
-
// });
|
|
241
281
|
}
|
|
242
282
|
setParent(parent, root, parentIndex) {
|
|
243
283
|
this.parent = parent;
|
|
@@ -247,48 +287,60 @@ class ChangeTree {
|
|
|
247
287
|
return;
|
|
248
288
|
}
|
|
249
289
|
root.add(this);
|
|
290
|
+
const metadata = this.ref.constructor[Symbol.metadata];
|
|
250
291
|
// skip if parent is already set
|
|
251
|
-
if (root
|
|
252
|
-
this.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
292
|
+
if (root !== this.root) {
|
|
293
|
+
this.root = root;
|
|
294
|
+
if (root.types.hasFilters) {
|
|
295
|
+
this.checkIsFiltered(metadata, parent, parentIndex);
|
|
296
|
+
if (this.isFiltered || this.isPartiallyFiltered) {
|
|
297
|
+
this.root.filteredChanges.set(this, this.filteredChanges);
|
|
298
|
+
this.root.allFilteredChanges.set(this, this.filteredChanges);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (!this.isFiltered) {
|
|
302
|
+
this.root.changes.set(this, this.changes);
|
|
303
|
+
this.root.allChanges.set(this, this.allChanges);
|
|
304
|
+
}
|
|
305
|
+
this.ensureRefId();
|
|
256
306
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
307
|
+
// assign same parent on child structures
|
|
308
|
+
if (metadata) {
|
|
309
|
+
metadata[-4]?.forEach((index) => {
|
|
310
|
+
const field = metadata[index];
|
|
311
|
+
const value = this.ref[field.name];
|
|
312
|
+
value?.[$changes].setParent(this.ref, root, index);
|
|
313
|
+
// console.log(this.ref.constructor.name, field.name, value);
|
|
314
|
+
// try { throw new Error(); } catch (e) {
|
|
315
|
+
// console.log(e.stack);
|
|
316
|
+
// }
|
|
317
|
+
});
|
|
262
318
|
}
|
|
263
|
-
if (this.
|
|
264
|
-
|
|
265
|
-
this.
|
|
319
|
+
else if (this.ref[$childType] && typeof (this.ref[$childType]) !== "string") {
|
|
320
|
+
// MapSchema / ArraySchema, etc.
|
|
321
|
+
this.ref.forEach((value, key) => {
|
|
322
|
+
value[$changes].setParent(this.ref, root, this.indexes[key] ?? key);
|
|
323
|
+
});
|
|
266
324
|
}
|
|
267
|
-
this.ensureRefId();
|
|
268
|
-
this.forEachChild((changeTree, atIndex) => {
|
|
269
|
-
changeTree.setParent(this.ref, root, atIndex);
|
|
270
|
-
});
|
|
271
325
|
}
|
|
272
326
|
forEachChild(callback) {
|
|
273
327
|
//
|
|
274
328
|
// assign same parent on child structures
|
|
275
329
|
//
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const value = this.ref[field];
|
|
281
|
-
if (value
|
|
282
|
-
callback(value[$changes],
|
|
330
|
+
const metadata = this.ref.constructor[Symbol.metadata];
|
|
331
|
+
if (metadata) {
|
|
332
|
+
metadata[-4]?.forEach((index) => {
|
|
333
|
+
const field = metadata[index];
|
|
334
|
+
const value = this.ref[field.name];
|
|
335
|
+
if (value) {
|
|
336
|
+
callback(value[$changes], index);
|
|
283
337
|
}
|
|
284
|
-
}
|
|
338
|
+
});
|
|
285
339
|
}
|
|
286
|
-
else if (typeof (this.ref)
|
|
340
|
+
else if (this.ref[$childType] && typeof (this.ref[$childType]) !== "string") {
|
|
287
341
|
// MapSchema / ArraySchema, etc.
|
|
288
342
|
this.ref.forEach((value, key) => {
|
|
289
|
-
|
|
290
|
-
callback(value[$changes], this.ref[$changes].indexes[key] ?? key);
|
|
291
|
-
}
|
|
343
|
+
callback(value[$changes], this.indexes[key] ?? key);
|
|
292
344
|
});
|
|
293
345
|
}
|
|
294
346
|
}
|
|
@@ -297,8 +349,8 @@ class ChangeTree {
|
|
|
297
349
|
this.root?.changes.set(this, this.changes);
|
|
298
350
|
}
|
|
299
351
|
change(index, operation = OPERATION.ADD) {
|
|
300
|
-
const metadata = this.ref
|
|
301
|
-
const isFiltered = this.isFiltered || (metadata
|
|
352
|
+
const metadata = this.ref.constructor[Symbol.metadata];
|
|
353
|
+
const isFiltered = this.isFiltered || (metadata?.[index]?.tag !== undefined);
|
|
302
354
|
const changeSet = (isFiltered)
|
|
303
355
|
? this.filteredChanges
|
|
304
356
|
: this.changes;
|
|
@@ -309,14 +361,14 @@ class ChangeTree {
|
|
|
309
361
|
: (previousOperation === OPERATION.DELETE)
|
|
310
362
|
? OPERATION.DELETE_AND_ADD
|
|
311
363
|
: operation;
|
|
364
|
+
//
|
|
365
|
+
// TODO: are DELETE operations being encoded as ADD here ??
|
|
366
|
+
//
|
|
312
367
|
changeSet.set(index, op);
|
|
313
368
|
}
|
|
314
|
-
//
|
|
315
|
-
// TODO: are DELETE operations being encoded as ADD here ??
|
|
316
|
-
//
|
|
317
369
|
if (isFiltered) {
|
|
318
|
-
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
319
370
|
this.allFilteredChanges.set(index, OPERATION.ADD);
|
|
371
|
+
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
320
372
|
this.root?.allFilteredChanges.set(this, this.allFilteredChanges);
|
|
321
373
|
}
|
|
322
374
|
else {
|
|
@@ -363,9 +415,7 @@ class ChangeTree {
|
|
|
363
415
|
});
|
|
364
416
|
}
|
|
365
417
|
indexedOperation(index, operation, allChangesIndex = index) {
|
|
366
|
-
|
|
367
|
-
const isFiltered = this.isFiltered || (metadata && metadata[metadata[index]].tag !== undefined);
|
|
368
|
-
if (isFiltered) {
|
|
418
|
+
if (this.filteredChanges !== undefined) {
|
|
369
419
|
this.allFilteredChanges.set(allChangesIndex, OPERATION.ADD);
|
|
370
420
|
this.filteredChanges.set(index, operation);
|
|
371
421
|
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
@@ -378,8 +428,8 @@ class ChangeTree {
|
|
|
378
428
|
}
|
|
379
429
|
getType(index) {
|
|
380
430
|
if (Metadata.isValidInstance(this.ref)) {
|
|
381
|
-
const metadata = this.ref
|
|
382
|
-
return metadata[
|
|
431
|
+
const metadata = this.ref.constructor[Symbol.metadata];
|
|
432
|
+
return metadata[index].type;
|
|
383
433
|
}
|
|
384
434
|
else {
|
|
385
435
|
//
|
|
@@ -393,7 +443,7 @@ class ChangeTree {
|
|
|
393
443
|
}
|
|
394
444
|
getChange(index) {
|
|
395
445
|
// TODO: optimize this. avoid checking against multiple instances
|
|
396
|
-
return this.changes.get(index) ?? this.filteredChanges
|
|
446
|
+
return this.changes.get(index) ?? this.filteredChanges?.get(index);
|
|
397
447
|
}
|
|
398
448
|
//
|
|
399
449
|
// used during `.encode()`
|
|
@@ -414,9 +464,7 @@ class ChangeTree {
|
|
|
414
464
|
}
|
|
415
465
|
return;
|
|
416
466
|
}
|
|
417
|
-
const
|
|
418
|
-
const isFiltered = this.isFiltered || (metadata && metadata[metadata[index]].tag !== undefined);
|
|
419
|
-
const changeSet = (isFiltered)
|
|
467
|
+
const changeSet = (this.filteredChanges)
|
|
420
468
|
? this.filteredChanges
|
|
421
469
|
: this.changes;
|
|
422
470
|
const previousValue = this.getValue(index);
|
|
@@ -439,7 +487,7 @@ class ChangeTree {
|
|
|
439
487
|
//
|
|
440
488
|
// FIXME: this is looking a bit ugly (and repeated from `.change()`)
|
|
441
489
|
//
|
|
442
|
-
if (
|
|
490
|
+
if (this.filteredChanges) {
|
|
443
491
|
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
444
492
|
this.allFilteredChanges.delete(allChangesIndex);
|
|
445
493
|
}
|
|
@@ -450,6 +498,7 @@ class ChangeTree {
|
|
|
450
498
|
}
|
|
451
499
|
endEncode() {
|
|
452
500
|
this.changes.clear();
|
|
501
|
+
// ArraySchema and MapSchema have a custom "encode end" method
|
|
453
502
|
this.ref[$onEncodeEnd]?.();
|
|
454
503
|
// Not a new instance anymore
|
|
455
504
|
delete this[$isNew];
|
|
@@ -462,12 +511,12 @@ class ChangeTree {
|
|
|
462
511
|
//
|
|
463
512
|
this.ref[$onEncodeEnd]?.();
|
|
464
513
|
this.changes.clear();
|
|
465
|
-
this.filteredChanges
|
|
514
|
+
this.filteredChanges?.clear();
|
|
466
515
|
// reset operation index
|
|
467
516
|
this.currentOperationIndex = 0;
|
|
468
517
|
if (discardAll) {
|
|
469
518
|
this.allChanges.clear();
|
|
470
|
-
this.allFilteredChanges
|
|
519
|
+
this.allFilteredChanges?.clear();
|
|
471
520
|
// remove children references
|
|
472
521
|
this.forEachChild((changeTree, _) => this.root?.remove(changeTree));
|
|
473
522
|
}
|
|
@@ -494,48 +543,41 @@ class ChangeTree {
|
|
|
494
543
|
get changed() {
|
|
495
544
|
return this.changes.size > 0;
|
|
496
545
|
}
|
|
497
|
-
checkIsFiltered(parent, parentIndex) {
|
|
546
|
+
checkIsFiltered(metadata, parent, parentIndex) {
|
|
498
547
|
// Detect if current structure has "filters" declared
|
|
499
|
-
this.isPartiallyFiltered =
|
|
500
|
-
if (
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
const changes = this.changes;
|
|
533
|
-
this.changes = this.filteredChanges;
|
|
534
|
-
this.filteredChanges = changes;
|
|
535
|
-
// swap "all changes" reference
|
|
536
|
-
const allFilteredChanges = this.allFilteredChanges;
|
|
537
|
-
this.allFilteredChanges = this.allChanges;
|
|
538
|
-
this.allChanges = allFilteredChanges;
|
|
548
|
+
this.isPartiallyFiltered = metadata?.[-2] !== undefined;
|
|
549
|
+
if (this.isPartiallyFiltered) {
|
|
550
|
+
this.filteredChanges = this.filteredChanges || new Map();
|
|
551
|
+
this.allFilteredChanges = this.allFilteredChanges || new Map();
|
|
552
|
+
}
|
|
553
|
+
if (parent) {
|
|
554
|
+
if (!Metadata.isValidInstance(parent)) {
|
|
555
|
+
const parentChangeTree = parent[$changes];
|
|
556
|
+
parent = parentChangeTree.parent;
|
|
557
|
+
parentIndex = parentChangeTree.parentIndex;
|
|
558
|
+
}
|
|
559
|
+
const parentMetadata = parent?.constructor?.[Symbol.metadata];
|
|
560
|
+
this.isFiltered = (parent && parentMetadata?.[-2]?.includes(parentIndex));
|
|
561
|
+
//
|
|
562
|
+
// TODO: refactor this!
|
|
563
|
+
//
|
|
564
|
+
// swapping `changes` and `filteredChanges` is required here
|
|
565
|
+
// because "isFiltered" may not be imedialely available on `change()`
|
|
566
|
+
//
|
|
567
|
+
if (this.isFiltered) {
|
|
568
|
+
this.filteredChanges = new Map();
|
|
569
|
+
this.allFilteredChanges = new Map();
|
|
570
|
+
if (this.changes.size > 0) {
|
|
571
|
+
// swap changes reference
|
|
572
|
+
const changes = this.changes;
|
|
573
|
+
this.changes = this.filteredChanges;
|
|
574
|
+
this.filteredChanges = changes;
|
|
575
|
+
// swap "all changes" reference
|
|
576
|
+
const allFilteredChanges = this.allFilteredChanges;
|
|
577
|
+
this.allFilteredChanges = this.allChanges;
|
|
578
|
+
this.allChanges = allFilteredChanges;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
539
581
|
}
|
|
540
582
|
}
|
|
541
583
|
}
|
|
@@ -819,62 +861,21 @@ var encode = /*#__PURE__*/Object.freeze({
|
|
|
819
861
|
writeFloat64: writeFloat64
|
|
820
862
|
});
|
|
821
863
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
case "int32":
|
|
834
|
-
case "uint32":
|
|
835
|
-
case "int64":
|
|
836
|
-
case "uint64":
|
|
837
|
-
case "float32":
|
|
838
|
-
case "float64":
|
|
839
|
-
typeofTarget = "number";
|
|
840
|
-
if (isNaN(value)) {
|
|
841
|
-
console.log(`trying to encode "NaN" in ${klass.constructor.name}#${field}`);
|
|
842
|
-
}
|
|
843
|
-
break;
|
|
844
|
-
case "string":
|
|
845
|
-
typeofTarget = "string";
|
|
846
|
-
allowNull = true;
|
|
847
|
-
break;
|
|
848
|
-
case "boolean":
|
|
849
|
-
// boolean is always encoded as true/false based on truthiness
|
|
850
|
-
return;
|
|
851
|
-
}
|
|
852
|
-
if (typeof (value) !== typeofTarget && (!allowNull || (allowNull && value !== null))) {
|
|
853
|
-
let foundValue = `'${JSON.stringify(value)}'${(value && value.constructor && ` (${value.constructor.name})`) || ''}`;
|
|
854
|
-
throw new EncodeSchemaError(`a '${typeofTarget}' was expected, but ${foundValue} was provided in ${klass.constructor.name}#${field}`);
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
function assertInstanceType(value, type, klass, field) {
|
|
858
|
-
if (!(value instanceof type)) {
|
|
859
|
-
throw new EncodeSchemaError(`a '${type.name}' was expected, but '${value && value.constructor.name}' was provided in ${klass.constructor.name}#${field}`);
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
function encodePrimitiveType(type, bytes, value, klass, field, it) {
|
|
864
|
-
assertType(value, type, klass, field);
|
|
865
|
-
const encodeFunc = encode[type];
|
|
866
|
-
if (encodeFunc) {
|
|
867
|
-
encodeFunc(bytes, value, it);
|
|
868
|
-
// encodeFunc(bytes, value);
|
|
869
|
-
}
|
|
870
|
-
else {
|
|
871
|
-
throw new EncodeSchemaError(`a '${type}' was expected, but ${value} was provided in ${klass.constructor.name}#${field}`);
|
|
864
|
+
function encodeValue(encoder, bytes,
|
|
865
|
+
// ref: Ref,
|
|
866
|
+
type, value,
|
|
867
|
+
// field: string | number,
|
|
868
|
+
operation, it) {
|
|
869
|
+
if (typeof (type) === "string") {
|
|
870
|
+
//
|
|
871
|
+
// Primitive values
|
|
872
|
+
//
|
|
873
|
+
// assertType(value, type as string, ref as Schema, field);
|
|
874
|
+
encode[type]?.(bytes, value, it);
|
|
872
875
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
// TODO: move this to the `@type()` annotation
|
|
877
|
-
assertInstanceType(value, type, ref, field);
|
|
876
|
+
else if (type[Symbol.metadata] !== undefined) {
|
|
877
|
+
// // TODO: move this to the `@type()` annotation
|
|
878
|
+
// assertInstanceType(value, type as typeof Schema, ref as Schema, field);
|
|
878
879
|
//
|
|
879
880
|
// Encode refId for this instance.
|
|
880
881
|
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
@@ -885,21 +886,15 @@ function encodeValue(encoder, bytes, ref, type, value, field, operation, it) {
|
|
|
885
886
|
encoder.tryEncodeTypeId(bytes, type, value.constructor, it);
|
|
886
887
|
}
|
|
887
888
|
}
|
|
888
|
-
else if (typeof (type) === "string") {
|
|
889
|
-
//
|
|
890
|
-
// Primitive values
|
|
891
|
-
//
|
|
892
|
-
encodePrimitiveType(type, bytes, value, ref, field, it);
|
|
893
|
-
}
|
|
894
889
|
else {
|
|
895
|
-
//
|
|
896
|
-
// Custom type (MapSchema, ArraySchema, etc)
|
|
897
|
-
//
|
|
898
|
-
const definition = getType(Object.keys(type)[0]);
|
|
899
|
-
//
|
|
900
|
-
// ensure a ArraySchema has been provided
|
|
901
|
-
//
|
|
902
|
-
assertInstanceType(ref[field], definition.constructor, ref, field);
|
|
890
|
+
// //
|
|
891
|
+
// // Custom type (MapSchema, ArraySchema, etc)
|
|
892
|
+
// //
|
|
893
|
+
// const definition = getType(Object.keys(type)[0]);
|
|
894
|
+
// //
|
|
895
|
+
// // ensure a ArraySchema has been provided
|
|
896
|
+
// //
|
|
897
|
+
// assertInstanceType(ref[field], definition.constructor, ref as Schema, field);
|
|
903
898
|
//
|
|
904
899
|
// Encode refId for this instance.
|
|
905
900
|
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
@@ -912,26 +907,27 @@ function encodeValue(encoder, bytes, ref, type, value, field, operation, it) {
|
|
|
912
907
|
* @private
|
|
913
908
|
*/
|
|
914
909
|
const encodeSchemaOperation = function (encoder, bytes, changeTree, index, operation, it) {
|
|
915
|
-
const ref = changeTree.ref;
|
|
916
|
-
const metadata = ref['constructor'][Symbol.metadata];
|
|
917
|
-
const field = metadata[index];
|
|
918
|
-
const type = metadata[field].type;
|
|
919
|
-
const value = ref[field];
|
|
920
910
|
// "compress" field index + operation
|
|
921
911
|
bytes[it.offset++] = (index | operation) & 255;
|
|
922
912
|
// Do not encode value for DELETE operations
|
|
923
913
|
if (operation === OPERATION.DELETE) {
|
|
924
914
|
return;
|
|
925
915
|
}
|
|
916
|
+
const ref = changeTree.ref;
|
|
917
|
+
const metadata = ref['constructor'][Symbol.metadata];
|
|
918
|
+
const field = metadata[index];
|
|
926
919
|
// TODO: inline this function call small performance gain
|
|
927
|
-
encodeValue(encoder, bytes,
|
|
920
|
+
encodeValue(encoder, bytes,
|
|
921
|
+
// ref,
|
|
922
|
+
metadata[index].type, ref[field.name],
|
|
923
|
+
// index,
|
|
924
|
+
operation, it);
|
|
928
925
|
};
|
|
929
926
|
/**
|
|
930
927
|
* Used for collections (MapSchema, CollectionSchema, SetSchema)
|
|
931
928
|
* @private
|
|
932
929
|
*/
|
|
933
|
-
const encodeKeyValueOperation = function (encoder, bytes, changeTree,
|
|
934
|
-
const ref = changeTree.ref;
|
|
930
|
+
const encodeKeyValueOperation = function (encoder, bytes, changeTree, index, operation, it) {
|
|
935
931
|
// encode operation
|
|
936
932
|
bytes[it.offset++] = operation & 255;
|
|
937
933
|
// custom operations
|
|
@@ -939,11 +935,12 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, field, ope
|
|
|
939
935
|
return;
|
|
940
936
|
}
|
|
941
937
|
// encode index
|
|
942
|
-
number$1(bytes,
|
|
938
|
+
number$1(bytes, index, it);
|
|
943
939
|
// Do not encode value for DELETE operations
|
|
944
940
|
if (operation === OPERATION.DELETE) {
|
|
945
941
|
return;
|
|
946
942
|
}
|
|
943
|
+
const ref = changeTree.ref;
|
|
947
944
|
//
|
|
948
945
|
// encode "alias" for dynamic fields (maps)
|
|
949
946
|
//
|
|
@@ -952,12 +949,12 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, field, ope
|
|
|
952
949
|
//
|
|
953
950
|
// MapSchema dynamic key
|
|
954
951
|
//
|
|
955
|
-
const dynamicIndex = changeTree.ref['$indexes'].get(
|
|
952
|
+
const dynamicIndex = changeTree.ref['$indexes'].get(index);
|
|
956
953
|
string$1(bytes, dynamicIndex, it);
|
|
957
954
|
}
|
|
958
955
|
}
|
|
959
|
-
const type = changeTree.getType(
|
|
960
|
-
const value = changeTree.getValue(
|
|
956
|
+
const type = changeTree.getType(index);
|
|
957
|
+
const value = changeTree.getValue(index);
|
|
961
958
|
// try { throw new Error(); } catch (e) {
|
|
962
959
|
// // only print if not coming from Reflection.ts
|
|
963
960
|
// if (!e.stack.includes("src/Reflection.ts")) {
|
|
@@ -971,7 +968,11 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, field, ope
|
|
|
971
968
|
// }
|
|
972
969
|
// }
|
|
973
970
|
// TODO: inline this function call small performance gain
|
|
974
|
-
encodeValue(encoder, bytes,
|
|
971
|
+
encodeValue(encoder, bytes,
|
|
972
|
+
// ref,
|
|
973
|
+
type, value,
|
|
974
|
+
// index,
|
|
975
|
+
operation, it);
|
|
975
976
|
};
|
|
976
977
|
/**
|
|
977
978
|
* Used for collections (MapSchema, ArraySchema, etc.)
|
|
@@ -1015,7 +1016,11 @@ const encodeArray = function (encoder, bytes, changeTree, field, operation, it,
|
|
|
1015
1016
|
// items: ref.toJSON(),
|
|
1016
1017
|
// });
|
|
1017
1018
|
// TODO: inline this function call small performance gain
|
|
1018
|
-
encodeValue(encoder, bytes,
|
|
1019
|
+
encodeValue(encoder, bytes,
|
|
1020
|
+
// ref,
|
|
1021
|
+
type, value,
|
|
1022
|
+
// field,
|
|
1023
|
+
operation, it);
|
|
1019
1024
|
};
|
|
1020
1025
|
|
|
1021
1026
|
/**
|
|
@@ -1372,7 +1377,7 @@ function decodeValue(decoder, operation, ref, index, type, bytes, it, allChanges
|
|
|
1372
1377
|
}
|
|
1373
1378
|
const decodeSchemaOperation = function (decoder, bytes, it, ref, allChanges) {
|
|
1374
1379
|
const first_byte = bytes[it.offset++];
|
|
1375
|
-
const metadata = ref
|
|
1380
|
+
const metadata = ref.constructor[Symbol.metadata];
|
|
1376
1381
|
// "compressed" index + operation
|
|
1377
1382
|
const operation = (first_byte >> 6) << 6;
|
|
1378
1383
|
const index = first_byte % (operation || 255);
|
|
@@ -1382,9 +1387,9 @@ const decodeSchemaOperation = function (decoder, bytes, it, ref, allChanges) {
|
|
|
1382
1387
|
console.warn("@colyseus/schema: field not defined at", { index, ref: ref.constructor.name, metadata });
|
|
1383
1388
|
return DEFINITION_MISMATCH;
|
|
1384
1389
|
}
|
|
1385
|
-
const { value, previousValue } = decodeValue(decoder, operation, ref, index,
|
|
1390
|
+
const { value, previousValue } = decodeValue(decoder, operation, ref, index, field.type, bytes, it, allChanges);
|
|
1386
1391
|
if (value !== null && value !== undefined) {
|
|
1387
|
-
ref[field] = value;
|
|
1392
|
+
ref[field.name] = value;
|
|
1388
1393
|
}
|
|
1389
1394
|
// add change
|
|
1390
1395
|
if (previousValue !== value) {
|
|
@@ -1392,7 +1397,7 @@ const decodeSchemaOperation = function (decoder, bytes, it, ref, allChanges) {
|
|
|
1392
1397
|
ref,
|
|
1393
1398
|
refId: decoder.currentRefId,
|
|
1394
1399
|
op: operation,
|
|
1395
|
-
field: field,
|
|
1400
|
+
field: field.name,
|
|
1396
1401
|
value,
|
|
1397
1402
|
previousValue,
|
|
1398
1403
|
});
|
|
@@ -1490,7 +1495,6 @@ const decodeArray = function (decoder, bytes, it, ref, allChanges) {
|
|
|
1490
1495
|
return;
|
|
1491
1496
|
}
|
|
1492
1497
|
else if (operation === OPERATION.ADD_BY_REFID) {
|
|
1493
|
-
// operation = OPERATION.ADD;
|
|
1494
1498
|
const refId = number(bytes, it);
|
|
1495
1499
|
const itemByRefId = decoder.root.refs.get(refId);
|
|
1496
1500
|
// use existing index, or push new value
|
|
@@ -1524,6 +1528,47 @@ const decodeArray = function (decoder, bytes, it, ref, allChanges) {
|
|
|
1524
1528
|
}
|
|
1525
1529
|
};
|
|
1526
1530
|
|
|
1531
|
+
class EncodeSchemaError extends Error {
|
|
1532
|
+
}
|
|
1533
|
+
function assertType(value, type, klass, field) {
|
|
1534
|
+
let typeofTarget;
|
|
1535
|
+
let allowNull = false;
|
|
1536
|
+
switch (type) {
|
|
1537
|
+
case "number":
|
|
1538
|
+
case "int8":
|
|
1539
|
+
case "uint8":
|
|
1540
|
+
case "int16":
|
|
1541
|
+
case "uint16":
|
|
1542
|
+
case "int32":
|
|
1543
|
+
case "uint32":
|
|
1544
|
+
case "int64":
|
|
1545
|
+
case "uint64":
|
|
1546
|
+
case "float32":
|
|
1547
|
+
case "float64":
|
|
1548
|
+
typeofTarget = "number";
|
|
1549
|
+
if (isNaN(value)) {
|
|
1550
|
+
console.log(`trying to encode "NaN" in ${klass.constructor.name}#${field}`);
|
|
1551
|
+
}
|
|
1552
|
+
break;
|
|
1553
|
+
case "string":
|
|
1554
|
+
typeofTarget = "string";
|
|
1555
|
+
allowNull = true;
|
|
1556
|
+
break;
|
|
1557
|
+
case "boolean":
|
|
1558
|
+
// boolean is always encoded as true/false based on truthiness
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
if (typeof (value) !== typeofTarget && (!allowNull || (allowNull && value !== null))) {
|
|
1562
|
+
let foundValue = `'${JSON.stringify(value)}'${(value && value.constructor && ` (${value.constructor.name})`) || ''}`;
|
|
1563
|
+
throw new EncodeSchemaError(`a '${typeofTarget}' was expected, but ${foundValue} was provided in ${klass.constructor.name}#${field}`);
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
function assertInstanceType(value, type, instance, field) {
|
|
1567
|
+
if (!(value instanceof type)) {
|
|
1568
|
+
throw new EncodeSchemaError(`a '${type.name}' was expected, but '${value && value.constructor.name}' was provided in ${instance.constructor.name}#${field}`);
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1527
1572
|
var _a$4, _b$4;
|
|
1528
1573
|
const DEFAULT_SORT = (a, b) => {
|
|
1529
1574
|
const A = a.toString();
|
|
@@ -1589,6 +1634,7 @@ class ArraySchema {
|
|
|
1589
1634
|
}
|
|
1590
1635
|
else {
|
|
1591
1636
|
if (setValue[$changes]) {
|
|
1637
|
+
assertInstanceType(setValue, obj[$childType], obj, key);
|
|
1592
1638
|
if (obj.items[key] !== undefined) {
|
|
1593
1639
|
if (setValue[$changes][$isNew]) {
|
|
1594
1640
|
this[$changes].indexedOperation(Number(key), OPERATION.MOVE_AND_ADD);
|
|
@@ -1635,6 +1681,7 @@ class ArraySchema {
|
|
|
1635
1681
|
}
|
|
1636
1682
|
});
|
|
1637
1683
|
this[$changes] = new ChangeTree(proxy);
|
|
1684
|
+
this[$changes].indexes = {};
|
|
1638
1685
|
this.push.apply(this, items);
|
|
1639
1686
|
return proxy;
|
|
1640
1687
|
}
|
|
@@ -1659,6 +1706,9 @@ class ArraySchema {
|
|
|
1659
1706
|
if (value === undefined || value === null) {
|
|
1660
1707
|
return;
|
|
1661
1708
|
}
|
|
1709
|
+
else if (typeof (value) === "object" && this[$childType]) {
|
|
1710
|
+
assertInstanceType(value, this[$childType], this, i);
|
|
1711
|
+
}
|
|
1662
1712
|
const changeTree = this[$changes];
|
|
1663
1713
|
changeTree.indexedOperation(length, OPERATION.ADD, this.items.length);
|
|
1664
1714
|
this.items.push(value);
|
|
@@ -2186,6 +2236,7 @@ class MapSchema {
|
|
|
2186
2236
|
this.$items = new Map();
|
|
2187
2237
|
this.$indexes = new Map();
|
|
2188
2238
|
this[$changes] = new ChangeTree(this);
|
|
2239
|
+
this[$changes].indexes = {};
|
|
2189
2240
|
if (initialValues) {
|
|
2190
2241
|
if (initialValues instanceof Map ||
|
|
2191
2242
|
initialValues instanceof MapSchema) {
|
|
@@ -2212,6 +2263,9 @@ class MapSchema {
|
|
|
2212
2263
|
if (value === undefined || value === null) {
|
|
2213
2264
|
throw new Error(`MapSchema#set('${key}', ${value}): trying to set ${value} value on '${key}'.`);
|
|
2214
2265
|
}
|
|
2266
|
+
else if (typeof (value) === "object" && this[$childType]) {
|
|
2267
|
+
assertInstanceType(value, this[$childType], this, key);
|
|
2268
|
+
}
|
|
2215
2269
|
// Force "key" as string
|
|
2216
2270
|
// See: https://github.com/colyseus/colyseus/issues/561#issuecomment-1646733468
|
|
2217
2271
|
key = key.toString();
|
|
@@ -2417,27 +2471,20 @@ class TypeContext {
|
|
|
2417
2471
|
if (parentFieldViewTag !== undefined) {
|
|
2418
2472
|
this.parentFiltered[`${this.schemas.get(klass)}-${parentIndex}`] = true;
|
|
2419
2473
|
}
|
|
2420
|
-
for (const
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
// if (
|
|
2425
|
-
// parentFieldViewTag !== undefined &&
|
|
2426
|
-
// metadata[field].tag === undefined
|
|
2427
|
-
// ) {
|
|
2428
|
-
// metadata[field].tag = parentFieldViewTag;
|
|
2429
|
-
// }
|
|
2430
|
-
const fieldType = metadata[field].type;
|
|
2431
|
-
const viewTag = metadata[field].tag;
|
|
2474
|
+
for (const fieldIndex in metadata) {
|
|
2475
|
+
const index = fieldIndex;
|
|
2476
|
+
const fieldType = metadata[index].type;
|
|
2477
|
+
const viewTag = metadata[index].tag;
|
|
2432
2478
|
if (typeof (fieldType) === "string") {
|
|
2433
2479
|
continue;
|
|
2434
2480
|
}
|
|
2435
2481
|
if (Array.isArray(fieldType)) {
|
|
2436
2482
|
const type = fieldType[0];
|
|
2483
|
+
// skip primitive types
|
|
2437
2484
|
if (type === "string") {
|
|
2438
2485
|
continue;
|
|
2439
2486
|
}
|
|
2440
|
-
this.discoverTypes(type,
|
|
2487
|
+
this.discoverTypes(type, index, viewTag);
|
|
2441
2488
|
}
|
|
2442
2489
|
else if (typeof (fieldType) === "function") {
|
|
2443
2490
|
this.discoverTypes(fieldType, viewTag);
|
|
@@ -2448,7 +2495,7 @@ class TypeContext {
|
|
|
2448
2495
|
if (typeof (type) === "string") {
|
|
2449
2496
|
continue;
|
|
2450
2497
|
}
|
|
2451
|
-
this.discoverTypes(type,
|
|
2498
|
+
this.discoverTypes(type, index, viewTag);
|
|
2452
2499
|
}
|
|
2453
2500
|
}
|
|
2454
2501
|
}
|
|
@@ -2604,17 +2651,18 @@ function view(tag = DEFAULT_VIEW_TAG) {
|
|
|
2604
2651
|
const parentMetadata = parentClass[Symbol.metadata];
|
|
2605
2652
|
// TODO: use Metadata.initialize()
|
|
2606
2653
|
const metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
}
|
|
2654
|
+
// const fieldIndex = metadata[fieldName];
|
|
2655
|
+
// if (!metadata[fieldIndex]) {
|
|
2656
|
+
// //
|
|
2657
|
+
// // detect index for this field, considering inheritance
|
|
2658
|
+
// //
|
|
2659
|
+
// metadata[fieldIndex] = {
|
|
2660
|
+
// type: undefined,
|
|
2661
|
+
// index: (metadata[-1] // current structure already has fields defined
|
|
2662
|
+
// ?? (parentMetadata && parentMetadata[-1]) // parent structure has fields defined
|
|
2663
|
+
// ?? -1) + 1 // no fields defined
|
|
2664
|
+
// }
|
|
2665
|
+
// }
|
|
2618
2666
|
Metadata.setTag(metadata, fieldName, tag);
|
|
2619
2667
|
};
|
|
2620
2668
|
}
|
|
@@ -2629,16 +2677,16 @@ function type(type, options) {
|
|
|
2629
2677
|
const parentClass = Object.getPrototypeOf(constructor);
|
|
2630
2678
|
const parentMetadata = parentClass && parentClass[Symbol.metadata];
|
|
2631
2679
|
const metadata = Metadata.initialize(constructor, parentMetadata);
|
|
2632
|
-
let fieldIndex;
|
|
2680
|
+
let fieldIndex = metadata[field];
|
|
2633
2681
|
/**
|
|
2634
2682
|
* skip if descriptor already exists for this field (`@deprecated()`)
|
|
2635
2683
|
*/
|
|
2636
|
-
if (metadata[
|
|
2637
|
-
if (metadata[
|
|
2684
|
+
if (metadata[fieldIndex]) {
|
|
2685
|
+
if (metadata[fieldIndex].deprecated) {
|
|
2638
2686
|
// do not create accessors for deprecated properties.
|
|
2639
2687
|
return;
|
|
2640
2688
|
}
|
|
2641
|
-
else if (metadata[
|
|
2689
|
+
else if (metadata[fieldIndex].type !== undefined) {
|
|
2642
2690
|
// trying to define same property multiple times across inheritance.
|
|
2643
2691
|
// https://github.com/colyseus/colyseus-unity3d/issues/131#issuecomment-814308572
|
|
2644
2692
|
try {
|
|
@@ -2649,9 +2697,6 @@ function type(type, options) {
|
|
|
2649
2697
|
throw new Error(`${e.message} ${definitionAtLine}`);
|
|
2650
2698
|
}
|
|
2651
2699
|
}
|
|
2652
|
-
else {
|
|
2653
|
-
fieldIndex = metadata[field].index;
|
|
2654
|
-
}
|
|
2655
2700
|
}
|
|
2656
2701
|
else {
|
|
2657
2702
|
//
|
|
@@ -2677,11 +2722,11 @@ function type(type, options) {
|
|
|
2677
2722
|
const childType = (complexTypeKlass)
|
|
2678
2723
|
? Object.values(type)[0]
|
|
2679
2724
|
: type;
|
|
2680
|
-
Metadata.addField(metadata, fieldIndex, field, type, getPropertyDescriptor(`_${field}`, fieldIndex, childType, complexTypeKlass
|
|
2725
|
+
Metadata.addField(metadata, fieldIndex, field, type, getPropertyDescriptor(`_${field}`, fieldIndex, childType, complexTypeKlass));
|
|
2681
2726
|
}
|
|
2682
2727
|
};
|
|
2683
2728
|
}
|
|
2684
|
-
function getPropertyDescriptor(fieldCached, fieldIndex, type, complexTypeKlass
|
|
2729
|
+
function getPropertyDescriptor(fieldCached, fieldIndex, type, complexTypeKlass) {
|
|
2685
2730
|
return {
|
|
2686
2731
|
get: function () { return this[fieldCached]; },
|
|
2687
2732
|
set: function (value) {
|
|
@@ -2703,22 +2748,27 @@ function getPropertyDescriptor(fieldCached, fieldIndex, type, complexTypeKlass,
|
|
|
2703
2748
|
}
|
|
2704
2749
|
value[$childType] = type;
|
|
2705
2750
|
}
|
|
2751
|
+
else if (typeof (type) !== "string") {
|
|
2752
|
+
assertInstanceType(value, type, this, fieldCached.substring(1));
|
|
2753
|
+
}
|
|
2754
|
+
else {
|
|
2755
|
+
assertType(value, type, this, fieldCached.substring(1));
|
|
2756
|
+
}
|
|
2757
|
+
const changeTree = this[$changes];
|
|
2706
2758
|
//
|
|
2707
2759
|
// Replacing existing "ref", remove it from root.
|
|
2708
2760
|
// TODO: if there are other references to this instance, we should not remove it from root.
|
|
2709
2761
|
//
|
|
2710
2762
|
if (previousValue !== undefined && previousValue[$changes]) {
|
|
2711
|
-
|
|
2763
|
+
changeTree.root?.remove(previousValue[$changes]);
|
|
2712
2764
|
}
|
|
2713
2765
|
// flag the change for encoding.
|
|
2714
|
-
this.constructor[$track](
|
|
2766
|
+
this.constructor[$track](changeTree, fieldIndex, OPERATION.ADD);
|
|
2715
2767
|
//
|
|
2716
2768
|
// call setParent() recursively for this and its child
|
|
2717
2769
|
// structures.
|
|
2718
2770
|
//
|
|
2719
|
-
|
|
2720
|
-
value[$changes].setParent(this, this[$changes].root, metadata[field].index);
|
|
2721
|
-
}
|
|
2771
|
+
value[$changes]?.setParent(this, changeTree.root, fieldIndex);
|
|
2722
2772
|
}
|
|
2723
2773
|
else if (previousValue !== undefined) {
|
|
2724
2774
|
//
|
|
@@ -2745,20 +2795,22 @@ function deprecated(throws = true) {
|
|
|
2745
2795
|
const parentClass = Object.getPrototypeOf(constructor);
|
|
2746
2796
|
const parentMetadata = parentClass[Symbol.metadata];
|
|
2747
2797
|
const metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
}
|
|
2759
|
-
|
|
2798
|
+
const fieldIndex = metadata[field];
|
|
2799
|
+
// if (!metadata[field]) {
|
|
2800
|
+
// //
|
|
2801
|
+
// // detect index for this field, considering inheritance
|
|
2802
|
+
// //
|
|
2803
|
+
// metadata[field] = {
|
|
2804
|
+
// type: undefined,
|
|
2805
|
+
// index: (metadata[-1] // current structure already has fields defined
|
|
2806
|
+
// ?? (parentMetadata && parentMetadata[-1]) // parent structure has fields defined
|
|
2807
|
+
// ?? -1) + 1 // no fields defined
|
|
2808
|
+
// }
|
|
2809
|
+
// }
|
|
2810
|
+
metadata[fieldIndex].deprecated = true;
|
|
2760
2811
|
if (throws) {
|
|
2761
|
-
metadata[
|
|
2812
|
+
metadata[$descriptors] ??= {};
|
|
2813
|
+
metadata[$descriptors][field] = {
|
|
2762
2814
|
get: function () { throw new Error(`${field} is deprecated.`); },
|
|
2763
2815
|
set: function (value) { },
|
|
2764
2816
|
enumerable: false,
|
|
@@ -2766,8 +2818,8 @@ function deprecated(throws = true) {
|
|
|
2766
2818
|
};
|
|
2767
2819
|
}
|
|
2768
2820
|
// flag metadata[field] as non-enumerable
|
|
2769
|
-
Object.defineProperty(metadata,
|
|
2770
|
-
value: metadata[
|
|
2821
|
+
Object.defineProperty(metadata, fieldIndex, {
|
|
2822
|
+
value: metadata[fieldIndex],
|
|
2771
2823
|
enumerable: false,
|
|
2772
2824
|
configurable: true
|
|
2773
2825
|
});
|
|
@@ -2833,35 +2885,7 @@ class Schema {
|
|
|
2833
2885
|
enumerable: false,
|
|
2834
2886
|
writable: true
|
|
2835
2887
|
});
|
|
2836
|
-
|
|
2837
|
-
// Define property descriptors
|
|
2838
|
-
for (const field in metadata) {
|
|
2839
|
-
if (metadata[field].descriptor) {
|
|
2840
|
-
// for encoder
|
|
2841
|
-
Object.defineProperty(instance, `_${field}`, {
|
|
2842
|
-
value: undefined,
|
|
2843
|
-
writable: true,
|
|
2844
|
-
enumerable: false,
|
|
2845
|
-
configurable: true,
|
|
2846
|
-
});
|
|
2847
|
-
Object.defineProperty(instance, field, metadata[field].descriptor);
|
|
2848
|
-
}
|
|
2849
|
-
else {
|
|
2850
|
-
// for decoder
|
|
2851
|
-
Object.defineProperty(instance, field, {
|
|
2852
|
-
value: undefined,
|
|
2853
|
-
writable: true,
|
|
2854
|
-
enumerable: true,
|
|
2855
|
-
configurable: true,
|
|
2856
|
-
});
|
|
2857
|
-
}
|
|
2858
|
-
// Object.defineProperty(instance, field, {
|
|
2859
|
-
// ...instance.constructor[Symbol.metadata][field].descriptor
|
|
2860
|
-
// });
|
|
2861
|
-
// if (args[0]?.hasOwnProperty(field)) {
|
|
2862
|
-
// instance[field] = args[0][field];
|
|
2863
|
-
// }
|
|
2864
|
-
}
|
|
2888
|
+
Object.defineProperties(instance, instance.constructor[Symbol.metadata]?.[$descriptors] || {});
|
|
2865
2889
|
}
|
|
2866
2890
|
static is(type) {
|
|
2867
2891
|
return typeof (type[Symbol.metadata]) === "object";
|
|
@@ -2885,7 +2909,7 @@ class Schema {
|
|
|
2885
2909
|
*/
|
|
2886
2910
|
static [$filter](ref, index, view) {
|
|
2887
2911
|
const metadata = ref.constructor[Symbol.metadata];
|
|
2888
|
-
const tag = metadata[
|
|
2912
|
+
const tag = metadata[index]?.tag;
|
|
2889
2913
|
if (view === undefined) {
|
|
2890
2914
|
// shared pass/encode: encode if doesn't have a tag
|
|
2891
2915
|
return tag === undefined;
|
|
@@ -2906,12 +2930,21 @@ class Schema {
|
|
|
2906
2930
|
}
|
|
2907
2931
|
// allow inherited classes to have a constructor
|
|
2908
2932
|
constructor(...args) {
|
|
2909
|
-
|
|
2933
|
+
//
|
|
2934
|
+
// inline
|
|
2935
|
+
// Schema.initialize(this);
|
|
2936
|
+
//
|
|
2937
|
+
Object.defineProperty(this, $changes, {
|
|
2938
|
+
value: new ChangeTree(this),
|
|
2939
|
+
enumerable: false,
|
|
2940
|
+
writable: true
|
|
2941
|
+
});
|
|
2942
|
+
Object.defineProperties(this, this.constructor[Symbol.metadata]?.[$descriptors] || {});
|
|
2910
2943
|
//
|
|
2911
2944
|
// Assign initial values
|
|
2912
2945
|
//
|
|
2913
2946
|
if (args[0]) {
|
|
2914
|
-
|
|
2947
|
+
Object.assign(this, args[0]);
|
|
2915
2948
|
}
|
|
2916
2949
|
}
|
|
2917
2950
|
assign(props) {
|
|
@@ -2925,7 +2958,8 @@ class Schema {
|
|
|
2925
2958
|
* @param operation OPERATION to perform (detected automatically)
|
|
2926
2959
|
*/
|
|
2927
2960
|
setDirty(property, operation) {
|
|
2928
|
-
this
|
|
2961
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
2962
|
+
this[$changes].change(metadata[metadata[property]].index, operation);
|
|
2929
2963
|
}
|
|
2930
2964
|
clone() {
|
|
2931
2965
|
const cloned = new (this.constructor);
|
|
@@ -2934,7 +2968,9 @@ class Schema {
|
|
|
2934
2968
|
// TODO: clone all properties, not only annotated ones
|
|
2935
2969
|
//
|
|
2936
2970
|
// for (const field in this) {
|
|
2937
|
-
for (const
|
|
2971
|
+
for (const fieldIndex in metadata) {
|
|
2972
|
+
// const field = metadata[metadata[fieldIndex]].name;
|
|
2973
|
+
const field = metadata[fieldIndex].name;
|
|
2938
2974
|
if (typeof (this[field]) === "object" &&
|
|
2939
2975
|
typeof (this[field]?.clone) === "function") {
|
|
2940
2976
|
// deep clone
|
|
@@ -2948,10 +2984,11 @@ class Schema {
|
|
|
2948
2984
|
return cloned;
|
|
2949
2985
|
}
|
|
2950
2986
|
toJSON() {
|
|
2951
|
-
const metadata = this.constructor[Symbol.metadata];
|
|
2952
2987
|
const obj = {};
|
|
2953
|
-
|
|
2954
|
-
|
|
2988
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
2989
|
+
for (const index in metadata) {
|
|
2990
|
+
const field = metadata[index];
|
|
2991
|
+
const fieldName = field.name;
|
|
2955
2992
|
if (!field.deprecated && this[fieldName] !== null && typeof (this[fieldName]) !== "undefined") {
|
|
2956
2993
|
obj[fieldName] = (typeof (this[fieldName]['toJSON']) === "function")
|
|
2957
2994
|
? this[fieldName]['toJSON']()
|
|
@@ -2964,10 +3001,12 @@ class Schema {
|
|
|
2964
3001
|
this[$changes].discardAll();
|
|
2965
3002
|
}
|
|
2966
3003
|
[$getByIndex](index) {
|
|
2967
|
-
|
|
3004
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
3005
|
+
return this[metadata[index].name];
|
|
2968
3006
|
}
|
|
2969
3007
|
[$deleteByIndex](index) {
|
|
2970
|
-
this
|
|
3008
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
3009
|
+
this[metadata[index].name] = undefined;
|
|
2971
3010
|
}
|
|
2972
3011
|
static debugRefIds(instance, jsonContents = true, level = 0) {
|
|
2973
3012
|
const ref = instance;
|
|
@@ -3091,6 +3130,7 @@ class CollectionSchema {
|
|
|
3091
3130
|
this.$indexes = new Map();
|
|
3092
3131
|
this.$refId = 0;
|
|
3093
3132
|
this[$changes] = new ChangeTree(this);
|
|
3133
|
+
this[$changes].indexes = {};
|
|
3094
3134
|
if (initialValues) {
|
|
3095
3135
|
initialValues.forEach((v) => this.add(v));
|
|
3096
3136
|
}
|
|
@@ -3246,6 +3286,7 @@ class SetSchema {
|
|
|
3246
3286
|
this.$indexes = new Map();
|
|
3247
3287
|
this.$refId = 0;
|
|
3248
3288
|
this[$changes] = new ChangeTree(this);
|
|
3289
|
+
this[$changes].indexes = {};
|
|
3249
3290
|
if (initialValues) {
|
|
3250
3291
|
initialValues.forEach((v) => this.add(v));
|
|
3251
3292
|
}
|
|
@@ -3480,8 +3521,8 @@ class Encoder {
|
|
|
3480
3521
|
) {
|
|
3481
3522
|
const hasView = (view !== undefined);
|
|
3482
3523
|
const rootChangeTree = this.state[$changes];
|
|
3483
|
-
const
|
|
3484
|
-
for (const [changeTree, changes] of
|
|
3524
|
+
const shouldClearChanges = !isEncodeAll && !hasView;
|
|
3525
|
+
for (const [changeTree, changes] of changeTrees.entries()) {
|
|
3485
3526
|
const ref = changeTree.ref;
|
|
3486
3527
|
const ctor = ref['constructor'];
|
|
3487
3528
|
const encoder = ctor[$encoder];
|
|
@@ -3533,6 +3574,9 @@ class Encoder {
|
|
|
3533
3574
|
// }
|
|
3534
3575
|
encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
|
|
3535
3576
|
}
|
|
3577
|
+
// if (shouldClearChanges) {
|
|
3578
|
+
// changeTree.endEncode();
|
|
3579
|
+
// }
|
|
3536
3580
|
}
|
|
3537
3581
|
if (it.offset > buffer.byteLength) {
|
|
3538
3582
|
const newSize = getNextPowerOf2(buffer.byteLength * 2);
|
|
@@ -3555,7 +3599,7 @@ class Encoder {
|
|
|
3555
3599
|
//
|
|
3556
3600
|
// only clear changes after making sure buffer resize is not required.
|
|
3557
3601
|
//
|
|
3558
|
-
if (
|
|
3602
|
+
if (shouldClearChanges) {
|
|
3559
3603
|
//
|
|
3560
3604
|
// FIXME: avoid iterating over change trees twice.
|
|
3561
3605
|
//
|
|
@@ -3639,6 +3683,11 @@ class Encoder {
|
|
|
3639
3683
|
const changeTreesIterator = changeTrees.entries();
|
|
3640
3684
|
for (const [changeTree, _] of changeTreesIterator) {
|
|
3641
3685
|
changeTree.endEncode();
|
|
3686
|
+
// changeTree.changes.clear();
|
|
3687
|
+
// // ArraySchema and MapSchema have a custom "encode end" method
|
|
3688
|
+
// changeTree.ref[$onEncodeEnd]?.();
|
|
3689
|
+
// // Not a new instance anymore
|
|
3690
|
+
// delete changeTree[$isNew];
|
|
3642
3691
|
}
|
|
3643
3692
|
}
|
|
3644
3693
|
discardChanges() {
|
|
@@ -3754,8 +3803,9 @@ class ReferenceTracker {
|
|
|
3754
3803
|
// Ensure child schema instances have their references removed as well.
|
|
3755
3804
|
//
|
|
3756
3805
|
if (Metadata.isValidInstance(ref)) {
|
|
3757
|
-
const metadata = ref
|
|
3758
|
-
for (const
|
|
3806
|
+
const metadata = ref.constructor[Symbol.metadata];
|
|
3807
|
+
for (const index in metadata) {
|
|
3808
|
+
const field = metadata[index].name;
|
|
3759
3809
|
const childRefId = typeof (ref[field]) === "object" && this.refIds.get(ref[field]);
|
|
3760
3810
|
if (childRefId) {
|
|
3761
3811
|
this.removeRef(childRefId);
|
|
@@ -3942,7 +3992,9 @@ class Reflection extends Schema {
|
|
|
3942
3992
|
const reflection = new Reflection();
|
|
3943
3993
|
const encoder = new Encoder(reflection);
|
|
3944
3994
|
const buildType = (currentType, metadata) => {
|
|
3945
|
-
for (const
|
|
3995
|
+
for (const fieldIndex in metadata) {
|
|
3996
|
+
const index = Number(fieldIndex);
|
|
3997
|
+
const fieldName = metadata[index].name;
|
|
3946
3998
|
// skip fields from parent classes
|
|
3947
3999
|
if (!Object.prototype.hasOwnProperty.call(metadata, fieldName)) {
|
|
3948
4000
|
continue;
|
|
@@ -3950,7 +4002,7 @@ class Reflection extends Schema {
|
|
|
3950
4002
|
const field = new ReflectionField();
|
|
3951
4003
|
field.name = fieldName;
|
|
3952
4004
|
let fieldType;
|
|
3953
|
-
const type = metadata[
|
|
4005
|
+
const type = metadata[index].type;
|
|
3954
4006
|
if (typeof (type) === "string") {
|
|
3955
4007
|
fieldType = type;
|
|
3956
4008
|
}
|
|
@@ -4016,18 +4068,7 @@ class Reflection extends Schema {
|
|
|
4016
4068
|
reflection.types.forEach((reflectionType) => {
|
|
4017
4069
|
const schemaType = typeContext.get(reflectionType.id);
|
|
4018
4070
|
const metadata = schemaType[Symbol.metadata];
|
|
4019
|
-
// FIXME: use metadata[-1] to get field count
|
|
4020
4071
|
const parentFieldIndex = 0;
|
|
4021
|
-
// console.log("--------------------");
|
|
4022
|
-
// // console.log("reflectionType", reflectionType.toJSON());
|
|
4023
|
-
// console.log("reflectionType.fields", reflectionType.fields.toJSON());
|
|
4024
|
-
// console.log("parentFieldIndex", parentFieldIndex);
|
|
4025
|
-
//
|
|
4026
|
-
// FIXME: set fields using parentKlass as well
|
|
4027
|
-
// currently the fields are duplicated on inherited classes
|
|
4028
|
-
//
|
|
4029
|
-
// // const parentKlass = reflection.types[reflectionType.extendsId];
|
|
4030
|
-
// // parentKlass.fields
|
|
4031
4072
|
reflectionType.fields.forEach((field, i) => {
|
|
4032
4073
|
const fieldIndex = parentFieldIndex + i;
|
|
4033
4074
|
if (field.referencedType !== undefined) {
|
|
@@ -4192,7 +4233,7 @@ function getDecoderStateCallbacks(decoder) {
|
|
|
4192
4233
|
//
|
|
4193
4234
|
bindTo: function bindTo(targetObject, properties) {
|
|
4194
4235
|
if (!properties) {
|
|
4195
|
-
properties = Object.keys(metadata);
|
|
4236
|
+
properties = Object.keys(metadata).map((index) => metadata[index].name);
|
|
4196
4237
|
}
|
|
4197
4238
|
return $root.addCallback($root.refIds.get(context.instance), OPERATION.REPLACE, () => {
|
|
4198
4239
|
properties.forEach((prop) => targetObject[prop] = context.instance[prop]);
|
|
@@ -4200,7 +4241,8 @@ function getDecoderStateCallbacks(decoder) {
|
|
|
4200
4241
|
}
|
|
4201
4242
|
}, {
|
|
4202
4243
|
get(target, prop) {
|
|
4203
|
-
|
|
4244
|
+
const metadataField = metadata[metadata[prop]];
|
|
4245
|
+
if (metadataField) {
|
|
4204
4246
|
const instance = context.instance?.[prop];
|
|
4205
4247
|
const onInstanceAvailable = ((callback) => {
|
|
4206
4248
|
const unbind = $(context.instance).listen(prop, (value, _) => {
|
|
@@ -4216,7 +4258,7 @@ function getDecoderStateCallbacks(decoder) {
|
|
|
4216
4258
|
callback(instance, true);
|
|
4217
4259
|
}
|
|
4218
4260
|
});
|
|
4219
|
-
return getProxy(
|
|
4261
|
+
return getProxy(metadataField.type, {
|
|
4220
4262
|
// make sure refId is available, otherwise need to wait for the instance to be available.
|
|
4221
4263
|
instance: ($root.refIds.get(instance) && instance),
|
|
4222
4264
|
parentInstance: context.instance,
|
|
@@ -4329,7 +4371,7 @@ class StateView {
|
|
|
4329
4371
|
console.warn("StateView#add(), invalid object:", obj);
|
|
4330
4372
|
return this;
|
|
4331
4373
|
}
|
|
4332
|
-
// FIXME: ArraySchema/MapSchema
|
|
4374
|
+
// FIXME: ArraySchema/MapSchema do not have metadata
|
|
4333
4375
|
const metadata = obj.constructor[Symbol.metadata];
|
|
4334
4376
|
const changeTree = obj[$changes];
|
|
4335
4377
|
this.items.add(changeTree);
|
|
@@ -4375,7 +4417,7 @@ class StateView {
|
|
|
4375
4417
|
? changeTree.allFilteredChanges
|
|
4376
4418
|
: changeTree.allChanges;
|
|
4377
4419
|
changeSet.forEach((op, index) => {
|
|
4378
|
-
const tagAtIndex = metadata?.[
|
|
4420
|
+
const tagAtIndex = metadata?.[index].tag;
|
|
4379
4421
|
if ((isInvisible || // if "invisible", include all
|
|
4380
4422
|
tagAtIndex === undefined || // "all change" with no tag
|
|
4381
4423
|
tagAtIndex === tag // tagged property
|
|
@@ -4388,7 +4430,7 @@ class StateView {
|
|
|
4388
4430
|
// Add children of this ChangeTree to this view
|
|
4389
4431
|
changeTree.forEachChild((change, index) => {
|
|
4390
4432
|
// Do not ADD children that don't have the same tag
|
|
4391
|
-
if (metadata && metadata[
|
|
4433
|
+
if (metadata && metadata[index].tag !== tag) {
|
|
4392
4434
|
return;
|
|
4393
4435
|
}
|
|
4394
4436
|
this.add(change.ref, tag, false);
|