@colyseus/schema 3.0.0-alpha.30 → 3.0.0-alpha.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/index.js +389 -354
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +389 -354
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +389 -354
- package/lib/Metadata.d.ts +14 -5
- package/lib/Metadata.js +49 -20
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.js +4 -13
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.js +26 -39
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +1 -2
- package/lib/annotations.js +58 -52
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.js +25 -22
- package/lib/bench_encode.js.map +1 -1
- package/lib/decoder/DecodeOperation.js +7 -9
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/ReferenceTracker.js +3 -2
- package/lib/decoder/ReferenceTracker.js.map +1 -1
- package/lib/decoder/strategy/StateCallbacks.js +4 -3
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +8 -7
- package/lib/encoder/ChangeTree.js +135 -117
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +1 -4
- package/lib/encoder/EncodeOperation.js +17 -47
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.js +18 -6
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +2 -2
- package/lib/encoder/Root.js +18 -6
- package/lib/encoder/Root.js.map +1 -1
- package/lib/encoder/StateView.js +3 -3
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/assert.d.ts +2 -1
- package/lib/encoding/assert.js +2 -2
- package/lib/encoding/assert.js.map +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.js +11 -10
- package/lib/index.js.map +1 -1
- package/lib/types/TypeContext.js +7 -14
- package/lib/types/TypeContext.js.map +1 -1
- package/lib/types/custom/ArraySchema.js +6 -0
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.js +1 -0
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.js +5 -0
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/lib/types/custom/SetSchema.js +1 -0
- package/lib/types/custom/SetSchema.js.map +1 -1
- package/lib/types/symbols.d.ts +1 -0
- package/lib/types/symbols.js +2 -1
- package/lib/types/symbols.js.map +1 -1
- package/package.json +1 -1
- package/src/Metadata.ts +60 -29
- package/src/Reflection.ts +5 -15
- package/src/Schema.ts +33 -45
- package/src/annotations.ts +75 -67
- package/src/bench_encode.ts +29 -27
- package/src/decoder/DecodeOperation.ts +12 -11
- package/src/decoder/ReferenceTracker.ts +3 -2
- package/src/decoder/strategy/StateCallbacks.ts +4 -3
- package/src/encoder/ChangeTree.ts +154 -138
- package/src/encoder/EncodeOperation.ts +42 -62
- package/src/encoder/Encoder.ts +25 -8
- package/src/encoder/Root.ts +23 -6
- package/src/encoder/StateView.ts +4 -4
- package/src/encoding/assert.ts +4 -3
- package/src/index.ts +1 -4
- package/src/types/TypeContext.ts +10 -15
- package/src/types/custom/ArraySchema.ts +8 -0
- package/src/types/custom/CollectionSchema.ts +1 -0
- package/src/types/custom/MapSchema.ts +6 -0
- package/src/types/custom/SetSchema.ts +1 -0
- package/src/types/symbols.ts +2 -0
package/build/umd/index.js
CHANGED
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
const $filter = Symbol("$filter");
|
|
41
41
|
const $getByIndex = Symbol("$getByIndex");
|
|
42
42
|
const $deleteByIndex = Symbol("$deleteByIndex");
|
|
43
|
+
const $descriptors = Symbol("$descriptors");
|
|
43
44
|
/**
|
|
44
45
|
* Used to hold ChangeTree instances whitin the structures
|
|
45
46
|
*/
|
|
@@ -75,34 +76,67 @@
|
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
const Metadata = {
|
|
78
|
-
addField(metadata, index,
|
|
79
|
+
addField(metadata, index, name, type, descriptor) {
|
|
79
80
|
if (index > 64) {
|
|
80
|
-
throw new Error(`Can't define field '${
|
|
81
|
+
throw new Error(`Can't define field '${name}'.\nSchema instances may only have up to 64 fields.`);
|
|
81
82
|
}
|
|
82
|
-
metadata[
|
|
83
|
+
metadata[index] = Object.assign(metadata[index] || {}, // avoid overwriting previous field metadata (@owned / @deprecated)
|
|
83
84
|
{
|
|
84
85
|
type: (Array.isArray(type))
|
|
85
86
|
? { array: type[0] }
|
|
86
87
|
: type,
|
|
87
88
|
index,
|
|
88
|
-
|
|
89
|
+
name,
|
|
89
90
|
});
|
|
91
|
+
// create "descriptors" map
|
|
92
|
+
metadata[$descriptors] ??= {};
|
|
93
|
+
if (descriptor) {
|
|
94
|
+
// for encoder
|
|
95
|
+
metadata[$descriptors][name] = descriptor;
|
|
96
|
+
metadata[$descriptors][`_${name}`] = {
|
|
97
|
+
value: undefined,
|
|
98
|
+
writable: true,
|
|
99
|
+
enumerable: false,
|
|
100
|
+
configurable: true,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
// for decoder
|
|
105
|
+
metadata[$descriptors][name] = {
|
|
106
|
+
value: undefined,
|
|
107
|
+
writable: true,
|
|
108
|
+
enumerable: true,
|
|
109
|
+
configurable: true,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
90
112
|
// map -1 as last field index
|
|
91
113
|
Object.defineProperty(metadata, -1, {
|
|
92
114
|
value: index,
|
|
93
115
|
enumerable: false,
|
|
94
116
|
configurable: true
|
|
95
117
|
});
|
|
96
|
-
// map
|
|
97
|
-
Object.defineProperty(metadata,
|
|
98
|
-
value:
|
|
118
|
+
// map field name => index (non enumerable)
|
|
119
|
+
Object.defineProperty(metadata, name, {
|
|
120
|
+
value: index,
|
|
99
121
|
enumerable: false,
|
|
100
122
|
configurable: true,
|
|
101
123
|
});
|
|
124
|
+
// if child Ref/complex type, add to -4
|
|
125
|
+
if (typeof (metadata[index].type) !== "string") {
|
|
126
|
+
if (metadata[-4] === undefined) {
|
|
127
|
+
Object.defineProperty(metadata, -4, {
|
|
128
|
+
value: [],
|
|
129
|
+
enumerable: false,
|
|
130
|
+
configurable: true,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
metadata[-4].push(index);
|
|
134
|
+
}
|
|
102
135
|
},
|
|
103
136
|
setTag(metadata, fieldName, tag) {
|
|
137
|
+
const index = metadata[fieldName];
|
|
138
|
+
const field = metadata[index];
|
|
104
139
|
// add 'tag' to the field
|
|
105
|
-
const field = metadata[fieldName];
|
|
106
140
|
field.tag = tag;
|
|
107
141
|
if (!metadata[-2]) {
|
|
108
142
|
// -2: all field indexes with "view" tag
|
|
@@ -118,20 +152,14 @@
|
|
|
118
152
|
configurable: true
|
|
119
153
|
});
|
|
120
154
|
}
|
|
121
|
-
metadata[-2].push(
|
|
155
|
+
metadata[-2].push(index);
|
|
122
156
|
if (!metadata[-3][tag]) {
|
|
123
157
|
metadata[-3][tag] = [];
|
|
124
158
|
}
|
|
125
|
-
metadata[-3][tag].push(
|
|
159
|
+
metadata[-3][tag].push(index);
|
|
126
160
|
},
|
|
127
161
|
setFields(target, fields) {
|
|
128
162
|
const metadata = (target.prototype.constructor[Symbol.metadata] ??= {});
|
|
129
|
-
// target[$track] = function (changeTree, index: number, operation: OPERATION = OPERATION.ADD) {
|
|
130
|
-
// changeTree.change(index, operation, encodeSchemaOperation);
|
|
131
|
-
// };
|
|
132
|
-
// target[$encoder] = encodeSchemaOperation;
|
|
133
|
-
// target[$decoder] = decodeSchemaOperation;
|
|
134
|
-
// if (!target.prototype.toJSON) { target.prototype.toJSON = Schema.prototype.toJSON; }
|
|
135
163
|
let index = 0;
|
|
136
164
|
for (const field in fields) {
|
|
137
165
|
const type = fields[field];
|
|
@@ -139,7 +167,7 @@
|
|
|
139
167
|
const complexTypeKlass = (Array.isArray(type))
|
|
140
168
|
? getType("array")
|
|
141
169
|
: (typeof (Object.keys(type)[0]) === "string") && getType(Object.keys(type)[0]);
|
|
142
|
-
Metadata.addField(metadata, index, field, type, getPropertyDescriptor(`_${field}`, index, type, complexTypeKlass
|
|
170
|
+
Metadata.addField(metadata, index, field, type, getPropertyDescriptor(`_${field}`, index, type, complexTypeKlass));
|
|
143
171
|
index++;
|
|
144
172
|
}
|
|
145
173
|
},
|
|
@@ -168,8 +196,9 @@
|
|
|
168
196
|
// assign parent metadata to current
|
|
169
197
|
Object.assign(metadata, parentMetadata);
|
|
170
198
|
for (let i = 0; i <= parentMetadata[-1]; i++) {
|
|
171
|
-
|
|
172
|
-
|
|
199
|
+
const fieldName = parentMetadata[i].name;
|
|
200
|
+
Object.defineProperty(metadata, fieldName, {
|
|
201
|
+
value: parentMetadata[fieldName],
|
|
173
202
|
enumerable: false,
|
|
174
203
|
configurable: true,
|
|
175
204
|
});
|
|
@@ -193,7 +222,7 @@
|
|
|
193
222
|
const metadata = klass[Symbol.metadata];
|
|
194
223
|
const fields = {};
|
|
195
224
|
for (let i = 0; i <= metadata[-1]; i++) {
|
|
196
|
-
fields[metadata[i]] = metadata[
|
|
225
|
+
fields[metadata[i].name] = metadata[i].type;
|
|
197
226
|
}
|
|
198
227
|
return fields;
|
|
199
228
|
}
|
|
@@ -202,48 +231,59 @@
|
|
|
202
231
|
var _a$5;
|
|
203
232
|
class ChangeTree {
|
|
204
233
|
static { _a$5 = $isNew; }
|
|
205
|
-
;
|
|
206
234
|
constructor(ref) {
|
|
207
|
-
this.
|
|
235
|
+
this.isFiltered = false;
|
|
236
|
+
this.isPartiallyFiltered = false;
|
|
208
237
|
this.currentOperationIndex = 0;
|
|
209
|
-
this.allChanges = new Map();
|
|
210
|
-
this.allFilteredChanges = new Map();
|
|
211
238
|
this.changes = new Map();
|
|
212
|
-
this.
|
|
239
|
+
this.allChanges = new Map();
|
|
213
240
|
this[_a$5] = true;
|
|
214
241
|
this.ref = ref;
|
|
242
|
+
//
|
|
243
|
+
// Does this structure have "filters" declared?
|
|
244
|
+
//
|
|
245
|
+
if (ref.constructor[Symbol.metadata]?.[-2]) {
|
|
246
|
+
this.allFilteredChanges = new Map();
|
|
247
|
+
this.filteredChanges = new Map();
|
|
248
|
+
}
|
|
215
249
|
}
|
|
216
250
|
setRoot(root) {
|
|
217
251
|
this.root = root;
|
|
218
252
|
this.root.add(this);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
253
|
+
const metadata = this.ref.constructor[Symbol.metadata];
|
|
254
|
+
if (this.root.types.hasFilters) {
|
|
255
|
+
//
|
|
256
|
+
// At Schema initialization, the "root" structure might not be available
|
|
257
|
+
// yet, as it only does once the "Encoder" has been set up.
|
|
258
|
+
//
|
|
259
|
+
// So the "parent" may be already set without a "root".
|
|
260
|
+
//
|
|
261
|
+
this.checkIsFiltered(metadata, this.parent, this.parentIndex);
|
|
262
|
+
if (this.isFiltered || this.isPartiallyFiltered) {
|
|
263
|
+
this.root.allFilteredChanges.set(this, this.allFilteredChanges);
|
|
264
|
+
this.root.filteredChanges.set(this, this.filteredChanges);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
228
267
|
if (!this.isFiltered) {
|
|
229
268
|
this.root.changes.set(this, this.changes);
|
|
269
|
+
this.root.allChanges.set(this, this.allChanges);
|
|
230
270
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
271
|
+
this.ensureRefId();
|
|
272
|
+
if (metadata) {
|
|
273
|
+
metadata[-4]?.forEach((index) => {
|
|
274
|
+
const field = metadata[index];
|
|
275
|
+
const value = this.ref[field.name];
|
|
276
|
+
if (value) {
|
|
277
|
+
value[$changes].setRoot(root);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
234
280
|
}
|
|
235
|
-
if (
|
|
236
|
-
|
|
281
|
+
else if (this.ref[$childType] && typeof (this.ref[$childType]) !== "string") {
|
|
282
|
+
// MapSchema / ArraySchema, etc.
|
|
283
|
+
this.ref.forEach((value, key) => {
|
|
284
|
+
value[$changes].setRoot(root);
|
|
285
|
+
});
|
|
237
286
|
}
|
|
238
|
-
this.forEachChild((changeTree, _) => {
|
|
239
|
-
changeTree.setRoot(root);
|
|
240
|
-
});
|
|
241
|
-
// this.allChanges.forEach((_, index) => {
|
|
242
|
-
// const childRef = this.ref[$getByIndex](index);
|
|
243
|
-
// if (childRef && childRef[$changes]) {
|
|
244
|
-
// childRef[$changes].setRoot(root);
|
|
245
|
-
// }
|
|
246
|
-
// });
|
|
247
287
|
}
|
|
248
288
|
setParent(parent, root, parentIndex) {
|
|
249
289
|
this.parent = parent;
|
|
@@ -253,48 +293,60 @@
|
|
|
253
293
|
return;
|
|
254
294
|
}
|
|
255
295
|
root.add(this);
|
|
296
|
+
const metadata = this.ref.constructor[Symbol.metadata];
|
|
256
297
|
// skip if parent is already set
|
|
257
|
-
if (root
|
|
258
|
-
this.
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
298
|
+
if (root !== this.root) {
|
|
299
|
+
this.root = root;
|
|
300
|
+
if (root.types.hasFilters) {
|
|
301
|
+
this.checkIsFiltered(metadata, parent, parentIndex);
|
|
302
|
+
if (this.isFiltered || this.isPartiallyFiltered) {
|
|
303
|
+
this.root.filteredChanges.set(this, this.filteredChanges);
|
|
304
|
+
this.root.allFilteredChanges.set(this, this.filteredChanges);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (!this.isFiltered) {
|
|
308
|
+
this.root.changes.set(this, this.changes);
|
|
309
|
+
this.root.allChanges.set(this, this.allChanges);
|
|
310
|
+
}
|
|
311
|
+
this.ensureRefId();
|
|
262
312
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
313
|
+
// assign same parent on child structures
|
|
314
|
+
if (metadata) {
|
|
315
|
+
metadata[-4]?.forEach((index) => {
|
|
316
|
+
const field = metadata[index];
|
|
317
|
+
const value = this.ref[field.name];
|
|
318
|
+
value?.[$changes].setParent(this.ref, root, index);
|
|
319
|
+
// console.log(this.ref.constructor.name, field.name, value);
|
|
320
|
+
// try { throw new Error(); } catch (e) {
|
|
321
|
+
// console.log(e.stack);
|
|
322
|
+
// }
|
|
323
|
+
});
|
|
268
324
|
}
|
|
269
|
-
if (this.
|
|
270
|
-
|
|
271
|
-
this.
|
|
325
|
+
else if (this.ref[$childType] && typeof (this.ref[$childType]) !== "string") {
|
|
326
|
+
// MapSchema / ArraySchema, etc.
|
|
327
|
+
this.ref.forEach((value, key) => {
|
|
328
|
+
value[$changes].setParent(this.ref, root, this.indexes[key] ?? key);
|
|
329
|
+
});
|
|
272
330
|
}
|
|
273
|
-
this.ensureRefId();
|
|
274
|
-
this.forEachChild((changeTree, atIndex) => {
|
|
275
|
-
changeTree.setParent(this.ref, root, atIndex);
|
|
276
|
-
});
|
|
277
331
|
}
|
|
278
332
|
forEachChild(callback) {
|
|
279
333
|
//
|
|
280
334
|
// assign same parent on child structures
|
|
281
335
|
//
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const value = this.ref[field];
|
|
287
|
-
if (value
|
|
288
|
-
callback(value[$changes],
|
|
336
|
+
const metadata = this.ref.constructor[Symbol.metadata];
|
|
337
|
+
if (metadata) {
|
|
338
|
+
metadata[-4]?.forEach((index) => {
|
|
339
|
+
const field = metadata[index];
|
|
340
|
+
const value = this.ref[field.name];
|
|
341
|
+
if (value) {
|
|
342
|
+
callback(value[$changes], index);
|
|
289
343
|
}
|
|
290
|
-
}
|
|
344
|
+
});
|
|
291
345
|
}
|
|
292
|
-
else if (typeof (this.ref)
|
|
346
|
+
else if (this.ref[$childType] && typeof (this.ref[$childType]) !== "string") {
|
|
293
347
|
// MapSchema / ArraySchema, etc.
|
|
294
348
|
this.ref.forEach((value, key) => {
|
|
295
|
-
|
|
296
|
-
callback(value[$changes], this.ref[$changes].indexes[key] ?? key);
|
|
297
|
-
}
|
|
349
|
+
callback(value[$changes], this.indexes[key] ?? key);
|
|
298
350
|
});
|
|
299
351
|
}
|
|
300
352
|
}
|
|
@@ -303,8 +355,8 @@
|
|
|
303
355
|
this.root?.changes.set(this, this.changes);
|
|
304
356
|
}
|
|
305
357
|
change(index, operation = exports.OPERATION.ADD) {
|
|
306
|
-
const metadata = this.ref
|
|
307
|
-
const isFiltered = this.isFiltered || (metadata
|
|
358
|
+
const metadata = this.ref.constructor[Symbol.metadata];
|
|
359
|
+
const isFiltered = this.isFiltered || (metadata?.[index]?.tag !== undefined);
|
|
308
360
|
const changeSet = (isFiltered)
|
|
309
361
|
? this.filteredChanges
|
|
310
362
|
: this.changes;
|
|
@@ -315,14 +367,14 @@
|
|
|
315
367
|
: (previousOperation === exports.OPERATION.DELETE)
|
|
316
368
|
? exports.OPERATION.DELETE_AND_ADD
|
|
317
369
|
: operation;
|
|
370
|
+
//
|
|
371
|
+
// TODO: are DELETE operations being encoded as ADD here ??
|
|
372
|
+
//
|
|
318
373
|
changeSet.set(index, op);
|
|
319
374
|
}
|
|
320
|
-
//
|
|
321
|
-
// TODO: are DELETE operations being encoded as ADD here ??
|
|
322
|
-
//
|
|
323
375
|
if (isFiltered) {
|
|
324
|
-
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
325
376
|
this.allFilteredChanges.set(index, exports.OPERATION.ADD);
|
|
377
|
+
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
326
378
|
this.root?.allFilteredChanges.set(this, this.allFilteredChanges);
|
|
327
379
|
}
|
|
328
380
|
else {
|
|
@@ -369,9 +421,7 @@
|
|
|
369
421
|
});
|
|
370
422
|
}
|
|
371
423
|
indexedOperation(index, operation, allChangesIndex = index) {
|
|
372
|
-
|
|
373
|
-
const isFiltered = this.isFiltered || (metadata && metadata[metadata[index]].tag !== undefined);
|
|
374
|
-
if (isFiltered) {
|
|
424
|
+
if (this.filteredChanges !== undefined) {
|
|
375
425
|
this.allFilteredChanges.set(allChangesIndex, exports.OPERATION.ADD);
|
|
376
426
|
this.filteredChanges.set(index, operation);
|
|
377
427
|
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
@@ -384,8 +434,8 @@
|
|
|
384
434
|
}
|
|
385
435
|
getType(index) {
|
|
386
436
|
if (Metadata.isValidInstance(this.ref)) {
|
|
387
|
-
const metadata = this.ref
|
|
388
|
-
return metadata[
|
|
437
|
+
const metadata = this.ref.constructor[Symbol.metadata];
|
|
438
|
+
return metadata[index].type;
|
|
389
439
|
}
|
|
390
440
|
else {
|
|
391
441
|
//
|
|
@@ -399,7 +449,7 @@
|
|
|
399
449
|
}
|
|
400
450
|
getChange(index) {
|
|
401
451
|
// TODO: optimize this. avoid checking against multiple instances
|
|
402
|
-
return this.changes.get(index) ?? this.filteredChanges
|
|
452
|
+
return this.changes.get(index) ?? this.filteredChanges?.get(index);
|
|
403
453
|
}
|
|
404
454
|
//
|
|
405
455
|
// used during `.encode()`
|
|
@@ -420,16 +470,13 @@
|
|
|
420
470
|
}
|
|
421
471
|
return;
|
|
422
472
|
}
|
|
423
|
-
const
|
|
424
|
-
const isFiltered = this.isFiltered || (metadata && metadata[metadata[index]].tag !== undefined);
|
|
425
|
-
const changeSet = (isFiltered)
|
|
473
|
+
const changeSet = (this.filteredChanges)
|
|
426
474
|
? this.filteredChanges
|
|
427
475
|
: this.changes;
|
|
428
476
|
const previousValue = this.getValue(index);
|
|
429
477
|
changeSet.set(index, operation ?? exports.OPERATION.DELETE);
|
|
430
478
|
// remove `root` reference
|
|
431
479
|
if (previousValue && previousValue[$changes]) {
|
|
432
|
-
previousValue[$changes].root = undefined;
|
|
433
480
|
//
|
|
434
481
|
// FIXME: this.root is "undefined"
|
|
435
482
|
//
|
|
@@ -440,12 +487,18 @@
|
|
|
440
487
|
//
|
|
441
488
|
// (the property descriptors should NOT be used at decoding time. only at encoding time.)
|
|
442
489
|
//
|
|
443
|
-
this.root?.remove(previousValue[$changes]);
|
|
490
|
+
const refCount = this.root?.remove(previousValue[$changes]);
|
|
491
|
+
//
|
|
492
|
+
// Only remove "root" reference if it's the last reference
|
|
493
|
+
//
|
|
494
|
+
if (refCount <= 0) {
|
|
495
|
+
previousValue[$changes].root = undefined;
|
|
496
|
+
}
|
|
444
497
|
}
|
|
445
498
|
//
|
|
446
499
|
// FIXME: this is looking a bit ugly (and repeated from `.change()`)
|
|
447
500
|
//
|
|
448
|
-
if (
|
|
501
|
+
if (this.filteredChanges) {
|
|
449
502
|
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
450
503
|
this.allFilteredChanges.delete(allChangesIndex);
|
|
451
504
|
}
|
|
@@ -456,6 +509,7 @@
|
|
|
456
509
|
}
|
|
457
510
|
endEncode() {
|
|
458
511
|
this.changes.clear();
|
|
512
|
+
// ArraySchema and MapSchema have a custom "encode end" method
|
|
459
513
|
this.ref[$onEncodeEnd]?.();
|
|
460
514
|
// Not a new instance anymore
|
|
461
515
|
delete this[$isNew];
|
|
@@ -468,12 +522,12 @@
|
|
|
468
522
|
//
|
|
469
523
|
this.ref[$onEncodeEnd]?.();
|
|
470
524
|
this.changes.clear();
|
|
471
|
-
this.filteredChanges
|
|
525
|
+
this.filteredChanges?.clear();
|
|
472
526
|
// reset operation index
|
|
473
527
|
this.currentOperationIndex = 0;
|
|
474
528
|
if (discardAll) {
|
|
475
529
|
this.allChanges.clear();
|
|
476
|
-
this.allFilteredChanges
|
|
530
|
+
this.allFilteredChanges?.clear();
|
|
477
531
|
// remove children references
|
|
478
532
|
this.forEachChild((changeTree, _) => this.root?.remove(changeTree));
|
|
479
533
|
}
|
|
@@ -500,48 +554,41 @@
|
|
|
500
554
|
get changed() {
|
|
501
555
|
return this.changes.size > 0;
|
|
502
556
|
}
|
|
503
|
-
checkIsFiltered(parent, parentIndex) {
|
|
557
|
+
checkIsFiltered(metadata, parent, parentIndex) {
|
|
504
558
|
// Detect if current structure has "filters" declared
|
|
505
|
-
this.isPartiallyFiltered =
|
|
506
|
-
if (
|
|
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
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const changes = this.changes;
|
|
539
|
-
this.changes = this.filteredChanges;
|
|
540
|
-
this.filteredChanges = changes;
|
|
541
|
-
// swap "all changes" reference
|
|
542
|
-
const allFilteredChanges = this.allFilteredChanges;
|
|
543
|
-
this.allFilteredChanges = this.allChanges;
|
|
544
|
-
this.allChanges = allFilteredChanges;
|
|
559
|
+
this.isPartiallyFiltered = metadata?.[-2] !== undefined;
|
|
560
|
+
if (this.isPartiallyFiltered) {
|
|
561
|
+
this.filteredChanges = this.filteredChanges || new Map();
|
|
562
|
+
this.allFilteredChanges = this.allFilteredChanges || new Map();
|
|
563
|
+
}
|
|
564
|
+
if (parent) {
|
|
565
|
+
if (!Metadata.isValidInstance(parent)) {
|
|
566
|
+
const parentChangeTree = parent[$changes];
|
|
567
|
+
parent = parentChangeTree.parent;
|
|
568
|
+
parentIndex = parentChangeTree.parentIndex;
|
|
569
|
+
}
|
|
570
|
+
const parentMetadata = parent?.constructor?.[Symbol.metadata];
|
|
571
|
+
this.isFiltered = (parent && parentMetadata?.[-2]?.includes(parentIndex));
|
|
572
|
+
//
|
|
573
|
+
// TODO: refactor this!
|
|
574
|
+
//
|
|
575
|
+
// swapping `changes` and `filteredChanges` is required here
|
|
576
|
+
// because "isFiltered" may not be imedialely available on `change()`
|
|
577
|
+
//
|
|
578
|
+
if (this.isFiltered) {
|
|
579
|
+
this.filteredChanges = new Map();
|
|
580
|
+
this.allFilteredChanges = new Map();
|
|
581
|
+
if (this.changes.size > 0) {
|
|
582
|
+
// swap changes reference
|
|
583
|
+
const changes = this.changes;
|
|
584
|
+
this.changes = this.filteredChanges;
|
|
585
|
+
this.filteredChanges = changes;
|
|
586
|
+
// swap "all changes" reference
|
|
587
|
+
const allFilteredChanges = this.allFilteredChanges;
|
|
588
|
+
this.allFilteredChanges = this.allChanges;
|
|
589
|
+
this.allChanges = allFilteredChanges;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
545
592
|
}
|
|
546
593
|
}
|
|
547
594
|
}
|
|
@@ -825,62 +872,11 @@
|
|
|
825
872
|
writeFloat64: writeFloat64
|
|
826
873
|
});
|
|
827
874
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
let typeofTarget;
|
|
832
|
-
let allowNull = false;
|
|
833
|
-
switch (type) {
|
|
834
|
-
case "number":
|
|
835
|
-
case "int8":
|
|
836
|
-
case "uint8":
|
|
837
|
-
case "int16":
|
|
838
|
-
case "uint16":
|
|
839
|
-
case "int32":
|
|
840
|
-
case "uint32":
|
|
841
|
-
case "int64":
|
|
842
|
-
case "uint64":
|
|
843
|
-
case "float32":
|
|
844
|
-
case "float64":
|
|
845
|
-
typeofTarget = "number";
|
|
846
|
-
if (isNaN(value)) {
|
|
847
|
-
console.log(`trying to encode "NaN" in ${klass.constructor.name}#${field}`);
|
|
848
|
-
}
|
|
849
|
-
break;
|
|
850
|
-
case "string":
|
|
851
|
-
typeofTarget = "string";
|
|
852
|
-
allowNull = true;
|
|
853
|
-
break;
|
|
854
|
-
case "boolean":
|
|
855
|
-
// boolean is always encoded as true/false based on truthiness
|
|
856
|
-
return;
|
|
857
|
-
}
|
|
858
|
-
if (typeof (value) !== typeofTarget && (!allowNull || (allowNull && value !== null))) {
|
|
859
|
-
let foundValue = `'${JSON.stringify(value)}'${(value && value.constructor && ` (${value.constructor.name})`) || ''}`;
|
|
860
|
-
throw new EncodeSchemaError(`a '${typeofTarget}' was expected, but ${foundValue} was provided in ${klass.constructor.name}#${field}`);
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
function assertInstanceType(value, type, klass, field) {
|
|
864
|
-
if (!(value instanceof type)) {
|
|
865
|
-
throw new EncodeSchemaError(`a '${type.name}' was expected, but '${value && value.constructor.name}' was provided in ${klass.constructor.name}#${field}`);
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
function encodePrimitiveType(type, bytes, value, klass, field, it) {
|
|
870
|
-
assertType(value, type, klass, field);
|
|
871
|
-
const encodeFunc = encode[type];
|
|
872
|
-
if (encodeFunc) {
|
|
873
|
-
encodeFunc(bytes, value, it);
|
|
874
|
-
// encodeFunc(bytes, value);
|
|
875
|
-
}
|
|
876
|
-
else {
|
|
877
|
-
throw new EncodeSchemaError(`a '${type}' was expected, but ${value} was provided in ${klass.constructor.name}#${field}`);
|
|
875
|
+
function encodeValue(encoder, bytes, type, value, operation, it) {
|
|
876
|
+
if (typeof (type) === "string") {
|
|
877
|
+
encode[type]?.(bytes, value, it);
|
|
878
878
|
}
|
|
879
|
-
|
|
880
|
-
function encodeValue(encoder, bytes, ref, type, value, field, operation, it) {
|
|
881
|
-
if (type[Symbol.metadata] !== undefined) {
|
|
882
|
-
// TODO: move this to the `@type()` annotation
|
|
883
|
-
assertInstanceType(value, type, ref, field);
|
|
879
|
+
else if (type[Symbol.metadata] !== undefined) {
|
|
884
880
|
//
|
|
885
881
|
// Encode refId for this instance.
|
|
886
882
|
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
@@ -891,21 +887,7 @@
|
|
|
891
887
|
encoder.tryEncodeTypeId(bytes, type, value.constructor, it);
|
|
892
888
|
}
|
|
893
889
|
}
|
|
894
|
-
else if (typeof (type) === "string") {
|
|
895
|
-
//
|
|
896
|
-
// Primitive values
|
|
897
|
-
//
|
|
898
|
-
encodePrimitiveType(type, bytes, value, ref, field, it);
|
|
899
|
-
}
|
|
900
890
|
else {
|
|
901
|
-
//
|
|
902
|
-
// Custom type (MapSchema, ArraySchema, etc)
|
|
903
|
-
//
|
|
904
|
-
const definition = getType(Object.keys(type)[0]);
|
|
905
|
-
//
|
|
906
|
-
// ensure a ArraySchema has been provided
|
|
907
|
-
//
|
|
908
|
-
assertInstanceType(ref[field], definition.constructor, ref, field);
|
|
909
891
|
//
|
|
910
892
|
// Encode refId for this instance.
|
|
911
893
|
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
@@ -918,26 +900,23 @@
|
|
|
918
900
|
* @private
|
|
919
901
|
*/
|
|
920
902
|
const encodeSchemaOperation = function (encoder, bytes, changeTree, index, operation, it) {
|
|
921
|
-
const ref = changeTree.ref;
|
|
922
|
-
const metadata = ref['constructor'][Symbol.metadata];
|
|
923
|
-
const field = metadata[index];
|
|
924
|
-
const type = metadata[field].type;
|
|
925
|
-
const value = ref[field];
|
|
926
903
|
// "compress" field index + operation
|
|
927
904
|
bytes[it.offset++] = (index | operation) & 255;
|
|
928
905
|
// Do not encode value for DELETE operations
|
|
929
906
|
if (operation === exports.OPERATION.DELETE) {
|
|
930
907
|
return;
|
|
931
908
|
}
|
|
909
|
+
const ref = changeTree.ref;
|
|
910
|
+
const metadata = ref.constructor[Symbol.metadata];
|
|
911
|
+
const field = metadata[index];
|
|
932
912
|
// TODO: inline this function call small performance gain
|
|
933
|
-
encodeValue(encoder, bytes,
|
|
913
|
+
encodeValue(encoder, bytes, metadata[index].type, ref[field.name], operation, it);
|
|
934
914
|
};
|
|
935
915
|
/**
|
|
936
916
|
* Used for collections (MapSchema, CollectionSchema, SetSchema)
|
|
937
917
|
* @private
|
|
938
918
|
*/
|
|
939
|
-
const encodeKeyValueOperation = function (encoder, bytes, changeTree,
|
|
940
|
-
const ref = changeTree.ref;
|
|
919
|
+
const encodeKeyValueOperation = function (encoder, bytes, changeTree, index, operation, it) {
|
|
941
920
|
// encode operation
|
|
942
921
|
bytes[it.offset++] = operation & 255;
|
|
943
922
|
// custom operations
|
|
@@ -945,25 +924,26 @@
|
|
|
945
924
|
return;
|
|
946
925
|
}
|
|
947
926
|
// encode index
|
|
948
|
-
number$1(bytes,
|
|
927
|
+
number$1(bytes, index, it);
|
|
949
928
|
// Do not encode value for DELETE operations
|
|
950
929
|
if (operation === exports.OPERATION.DELETE) {
|
|
951
930
|
return;
|
|
952
931
|
}
|
|
932
|
+
const ref = changeTree.ref;
|
|
953
933
|
//
|
|
954
934
|
// encode "alias" for dynamic fields (maps)
|
|
955
935
|
//
|
|
956
|
-
if ((operation & exports.OPERATION.ADD)
|
|
936
|
+
if ((operation & exports.OPERATION.ADD) === exports.OPERATION.ADD) { // ADD or DELETE_AND_ADD
|
|
957
937
|
if (typeof (ref['set']) === "function") {
|
|
958
938
|
//
|
|
959
939
|
// MapSchema dynamic key
|
|
960
940
|
//
|
|
961
|
-
const dynamicIndex = changeTree.ref['$indexes'].get(
|
|
941
|
+
const dynamicIndex = changeTree.ref['$indexes'].get(index);
|
|
962
942
|
string$1(bytes, dynamicIndex, it);
|
|
963
943
|
}
|
|
964
944
|
}
|
|
965
|
-
const type =
|
|
966
|
-
const value =
|
|
945
|
+
const type = ref[$childType];
|
|
946
|
+
const value = ref[$getByIndex](index);
|
|
967
947
|
// try { throw new Error(); } catch (e) {
|
|
968
948
|
// // only print if not coming from Reflection.ts
|
|
969
949
|
// if (!e.stack.includes("src/Reflection.ts")) {
|
|
@@ -977,7 +957,7 @@
|
|
|
977
957
|
// }
|
|
978
958
|
// }
|
|
979
959
|
// TODO: inline this function call small performance gain
|
|
980
|
-
encodeValue(encoder, bytes,
|
|
960
|
+
encodeValue(encoder, bytes, type, value, operation, it);
|
|
981
961
|
};
|
|
982
962
|
/**
|
|
983
963
|
* Used for collections (MapSchema, ArraySchema, etc.)
|
|
@@ -1021,7 +1001,7 @@
|
|
|
1021
1001
|
// items: ref.toJSON(),
|
|
1022
1002
|
// });
|
|
1023
1003
|
// TODO: inline this function call small performance gain
|
|
1024
|
-
encodeValue(encoder, bytes,
|
|
1004
|
+
encodeValue(encoder, bytes, type, value, operation, it);
|
|
1025
1005
|
};
|
|
1026
1006
|
|
|
1027
1007
|
/**
|
|
@@ -1327,7 +1307,9 @@
|
|
|
1327
1307
|
if (!value) {
|
|
1328
1308
|
value = decoder.createInstanceOfType(childType);
|
|
1329
1309
|
}
|
|
1330
|
-
$root.addRef(refId, value, (value !== previousValue
|
|
1310
|
+
$root.addRef(refId, value, (value !== previousValue || // increment ref count if value has changed
|
|
1311
|
+
(operation === exports.OPERATION.DELETE_AND_ADD && value === previousValue) // increment ref count if the same instance is being added again
|
|
1312
|
+
));
|
|
1331
1313
|
}
|
|
1332
1314
|
}
|
|
1333
1315
|
else if (typeof (type) === "string") {
|
|
@@ -1378,7 +1360,7 @@
|
|
|
1378
1360
|
}
|
|
1379
1361
|
const decodeSchemaOperation = function (decoder, bytes, it, ref, allChanges) {
|
|
1380
1362
|
const first_byte = bytes[it.offset++];
|
|
1381
|
-
const metadata = ref
|
|
1363
|
+
const metadata = ref.constructor[Symbol.metadata];
|
|
1382
1364
|
// "compressed" index + operation
|
|
1383
1365
|
const operation = (first_byte >> 6) << 6;
|
|
1384
1366
|
const index = first_byte % (operation || 255);
|
|
@@ -1388,9 +1370,9 @@
|
|
|
1388
1370
|
console.warn("@colyseus/schema: field not defined at", { index, ref: ref.constructor.name, metadata });
|
|
1389
1371
|
return DEFINITION_MISMATCH;
|
|
1390
1372
|
}
|
|
1391
|
-
const { value, previousValue } = decodeValue(decoder, operation, ref, index,
|
|
1373
|
+
const { value, previousValue } = decodeValue(decoder, operation, ref, index, field.type, bytes, it, allChanges);
|
|
1392
1374
|
if (value !== null && value !== undefined) {
|
|
1393
|
-
ref[field] = value;
|
|
1375
|
+
ref[field.name] = value;
|
|
1394
1376
|
}
|
|
1395
1377
|
// add change
|
|
1396
1378
|
if (previousValue !== value) {
|
|
@@ -1398,7 +1380,7 @@
|
|
|
1398
1380
|
ref,
|
|
1399
1381
|
refId: decoder.currentRefId,
|
|
1400
1382
|
op: operation,
|
|
1401
|
-
field: field,
|
|
1383
|
+
field: field.name,
|
|
1402
1384
|
value,
|
|
1403
1385
|
previousValue,
|
|
1404
1386
|
});
|
|
@@ -1496,7 +1478,6 @@
|
|
|
1496
1478
|
return;
|
|
1497
1479
|
}
|
|
1498
1480
|
else if (operation === exports.OPERATION.ADD_BY_REFID) {
|
|
1499
|
-
// operation = OPERATION.ADD;
|
|
1500
1481
|
const refId = number(bytes, it);
|
|
1501
1482
|
const itemByRefId = decoder.root.refs.get(refId);
|
|
1502
1483
|
// use existing index, or push new value
|
|
@@ -1530,6 +1511,47 @@
|
|
|
1530
1511
|
}
|
|
1531
1512
|
};
|
|
1532
1513
|
|
|
1514
|
+
class EncodeSchemaError extends Error {
|
|
1515
|
+
}
|
|
1516
|
+
function assertType(value, type, klass, field) {
|
|
1517
|
+
let typeofTarget;
|
|
1518
|
+
let allowNull = false;
|
|
1519
|
+
switch (type) {
|
|
1520
|
+
case "number":
|
|
1521
|
+
case "int8":
|
|
1522
|
+
case "uint8":
|
|
1523
|
+
case "int16":
|
|
1524
|
+
case "uint16":
|
|
1525
|
+
case "int32":
|
|
1526
|
+
case "uint32":
|
|
1527
|
+
case "int64":
|
|
1528
|
+
case "uint64":
|
|
1529
|
+
case "float32":
|
|
1530
|
+
case "float64":
|
|
1531
|
+
typeofTarget = "number";
|
|
1532
|
+
if (isNaN(value)) {
|
|
1533
|
+
console.log(`trying to encode "NaN" in ${klass.constructor.name}#${field}`);
|
|
1534
|
+
}
|
|
1535
|
+
break;
|
|
1536
|
+
case "string":
|
|
1537
|
+
typeofTarget = "string";
|
|
1538
|
+
allowNull = true;
|
|
1539
|
+
break;
|
|
1540
|
+
case "boolean":
|
|
1541
|
+
// boolean is always encoded as true/false based on truthiness
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
if (typeof (value) !== typeofTarget && (!allowNull || (allowNull && value !== null))) {
|
|
1545
|
+
let foundValue = `'${JSON.stringify(value)}'${(value && value.constructor && ` (${value.constructor.name})`) || ''}`;
|
|
1546
|
+
throw new EncodeSchemaError(`a '${typeofTarget}' was expected, but ${foundValue} was provided in ${klass.constructor.name}#${field}`);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
function assertInstanceType(value, type, instance, field) {
|
|
1550
|
+
if (!(value instanceof type)) {
|
|
1551
|
+
throw new EncodeSchemaError(`a '${type.name}' was expected, but '${value && value.constructor.name}' was provided in ${instance.constructor.name}#${field}`);
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1533
1555
|
var _a$4, _b$4;
|
|
1534
1556
|
const DEFAULT_SORT = (a, b) => {
|
|
1535
1557
|
const A = a.toString();
|
|
@@ -1595,6 +1617,7 @@
|
|
|
1595
1617
|
}
|
|
1596
1618
|
else {
|
|
1597
1619
|
if (setValue[$changes]) {
|
|
1620
|
+
assertInstanceType(setValue, obj[$childType], obj, key);
|
|
1598
1621
|
if (obj.items[key] !== undefined) {
|
|
1599
1622
|
if (setValue[$changes][$isNew]) {
|
|
1600
1623
|
this[$changes].indexedOperation(Number(key), exports.OPERATION.MOVE_AND_ADD);
|
|
@@ -1641,6 +1664,7 @@
|
|
|
1641
1664
|
}
|
|
1642
1665
|
});
|
|
1643
1666
|
this[$changes] = new ChangeTree(proxy);
|
|
1667
|
+
this[$changes].indexes = {};
|
|
1644
1668
|
this.push.apply(this, items);
|
|
1645
1669
|
return proxy;
|
|
1646
1670
|
}
|
|
@@ -1665,6 +1689,9 @@
|
|
|
1665
1689
|
if (value === undefined || value === null) {
|
|
1666
1690
|
return;
|
|
1667
1691
|
}
|
|
1692
|
+
else if (typeof (value) === "object" && this[$childType]) {
|
|
1693
|
+
assertInstanceType(value, this[$childType], this, i);
|
|
1694
|
+
}
|
|
1668
1695
|
const changeTree = this[$changes];
|
|
1669
1696
|
changeTree.indexedOperation(length, exports.OPERATION.ADD, this.items.length);
|
|
1670
1697
|
this.items.push(value);
|
|
@@ -2192,6 +2219,7 @@
|
|
|
2192
2219
|
this.$items = new Map();
|
|
2193
2220
|
this.$indexes = new Map();
|
|
2194
2221
|
this[$changes] = new ChangeTree(this);
|
|
2222
|
+
this[$changes].indexes = {};
|
|
2195
2223
|
if (initialValues) {
|
|
2196
2224
|
if (initialValues instanceof Map ||
|
|
2197
2225
|
initialValues instanceof MapSchema) {
|
|
@@ -2218,6 +2246,9 @@
|
|
|
2218
2246
|
if (value === undefined || value === null) {
|
|
2219
2247
|
throw new Error(`MapSchema#set('${key}', ${value}): trying to set ${value} value on '${key}'.`);
|
|
2220
2248
|
}
|
|
2249
|
+
else if (typeof (value) === "object" && this[$childType]) {
|
|
2250
|
+
assertInstanceType(value, this[$childType], this, key);
|
|
2251
|
+
}
|
|
2221
2252
|
// Force "key" as string
|
|
2222
2253
|
// See: https://github.com/colyseus/colyseus/issues/561#issuecomment-1646733468
|
|
2223
2254
|
key = key.toString();
|
|
@@ -2423,27 +2454,20 @@
|
|
|
2423
2454
|
if (parentFieldViewTag !== undefined) {
|
|
2424
2455
|
this.parentFiltered[`${this.schemas.get(klass)}-${parentIndex}`] = true;
|
|
2425
2456
|
}
|
|
2426
|
-
for (const
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
// if (
|
|
2431
|
-
// parentFieldViewTag !== undefined &&
|
|
2432
|
-
// metadata[field].tag === undefined
|
|
2433
|
-
// ) {
|
|
2434
|
-
// metadata[field].tag = parentFieldViewTag;
|
|
2435
|
-
// }
|
|
2436
|
-
const fieldType = metadata[field].type;
|
|
2437
|
-
const viewTag = metadata[field].tag;
|
|
2457
|
+
for (const fieldIndex in metadata) {
|
|
2458
|
+
const index = fieldIndex;
|
|
2459
|
+
const fieldType = metadata[index].type;
|
|
2460
|
+
const viewTag = metadata[index].tag;
|
|
2438
2461
|
if (typeof (fieldType) === "string") {
|
|
2439
2462
|
continue;
|
|
2440
2463
|
}
|
|
2441
2464
|
if (Array.isArray(fieldType)) {
|
|
2442
2465
|
const type = fieldType[0];
|
|
2466
|
+
// skip primitive types
|
|
2443
2467
|
if (type === "string") {
|
|
2444
2468
|
continue;
|
|
2445
2469
|
}
|
|
2446
|
-
this.discoverTypes(type,
|
|
2470
|
+
this.discoverTypes(type, index, viewTag);
|
|
2447
2471
|
}
|
|
2448
2472
|
else if (typeof (fieldType) === "function") {
|
|
2449
2473
|
this.discoverTypes(fieldType, viewTag);
|
|
@@ -2454,7 +2478,7 @@
|
|
|
2454
2478
|
if (typeof (type) === "string") {
|
|
2455
2479
|
continue;
|
|
2456
2480
|
}
|
|
2457
|
-
this.discoverTypes(type,
|
|
2481
|
+
this.discoverTypes(type, index, viewTag);
|
|
2458
2482
|
}
|
|
2459
2483
|
}
|
|
2460
2484
|
}
|
|
@@ -2610,17 +2634,18 @@
|
|
|
2610
2634
|
const parentMetadata = parentClass[Symbol.metadata];
|
|
2611
2635
|
// TODO: use Metadata.initialize()
|
|
2612
2636
|
const metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
}
|
|
2637
|
+
// const fieldIndex = metadata[fieldName];
|
|
2638
|
+
// if (!metadata[fieldIndex]) {
|
|
2639
|
+
// //
|
|
2640
|
+
// // detect index for this field, considering inheritance
|
|
2641
|
+
// //
|
|
2642
|
+
// metadata[fieldIndex] = {
|
|
2643
|
+
// type: undefined,
|
|
2644
|
+
// index: (metadata[-1] // current structure already has fields defined
|
|
2645
|
+
// ?? (parentMetadata && parentMetadata[-1]) // parent structure has fields defined
|
|
2646
|
+
// ?? -1) + 1 // no fields defined
|
|
2647
|
+
// }
|
|
2648
|
+
// }
|
|
2624
2649
|
Metadata.setTag(metadata, fieldName, tag);
|
|
2625
2650
|
};
|
|
2626
2651
|
}
|
|
@@ -2635,16 +2660,16 @@
|
|
|
2635
2660
|
const parentClass = Object.getPrototypeOf(constructor);
|
|
2636
2661
|
const parentMetadata = parentClass && parentClass[Symbol.metadata];
|
|
2637
2662
|
const metadata = Metadata.initialize(constructor, parentMetadata);
|
|
2638
|
-
let fieldIndex;
|
|
2663
|
+
let fieldIndex = metadata[field];
|
|
2639
2664
|
/**
|
|
2640
2665
|
* skip if descriptor already exists for this field (`@deprecated()`)
|
|
2641
2666
|
*/
|
|
2642
|
-
if (metadata[
|
|
2643
|
-
if (metadata[
|
|
2667
|
+
if (metadata[fieldIndex]) {
|
|
2668
|
+
if (metadata[fieldIndex].deprecated) {
|
|
2644
2669
|
// do not create accessors for deprecated properties.
|
|
2645
2670
|
return;
|
|
2646
2671
|
}
|
|
2647
|
-
else if (metadata[
|
|
2672
|
+
else if (metadata[fieldIndex].type !== undefined) {
|
|
2648
2673
|
// trying to define same property multiple times across inheritance.
|
|
2649
2674
|
// https://github.com/colyseus/colyseus-unity3d/issues/131#issuecomment-814308572
|
|
2650
2675
|
try {
|
|
@@ -2655,9 +2680,6 @@
|
|
|
2655
2680
|
throw new Error(`${e.message} ${definitionAtLine}`);
|
|
2656
2681
|
}
|
|
2657
2682
|
}
|
|
2658
|
-
else {
|
|
2659
|
-
fieldIndex = metadata[field].index;
|
|
2660
|
-
}
|
|
2661
2683
|
}
|
|
2662
2684
|
else {
|
|
2663
2685
|
//
|
|
@@ -2683,11 +2705,11 @@
|
|
|
2683
2705
|
const childType = (complexTypeKlass)
|
|
2684
2706
|
? Object.values(type)[0]
|
|
2685
2707
|
: type;
|
|
2686
|
-
Metadata.addField(metadata, fieldIndex, field, type, getPropertyDescriptor(`_${field}`, fieldIndex, childType, complexTypeKlass
|
|
2708
|
+
Metadata.addField(metadata, fieldIndex, field, type, getPropertyDescriptor(`_${field}`, fieldIndex, childType, complexTypeKlass));
|
|
2687
2709
|
}
|
|
2688
2710
|
};
|
|
2689
2711
|
}
|
|
2690
|
-
function getPropertyDescriptor(fieldCached, fieldIndex, type, complexTypeKlass
|
|
2712
|
+
function getPropertyDescriptor(fieldCached, fieldIndex, type, complexTypeKlass) {
|
|
2691
2713
|
return {
|
|
2692
2714
|
get: function () { return this[fieldCached]; },
|
|
2693
2715
|
set: function (value) {
|
|
@@ -2709,22 +2731,27 @@
|
|
|
2709
2731
|
}
|
|
2710
2732
|
value[$childType] = type;
|
|
2711
2733
|
}
|
|
2734
|
+
else if (typeof (type) !== "string") {
|
|
2735
|
+
assertInstanceType(value, type, this, fieldCached.substring(1));
|
|
2736
|
+
}
|
|
2737
|
+
else {
|
|
2738
|
+
assertType(value, type, this, fieldCached.substring(1));
|
|
2739
|
+
}
|
|
2740
|
+
const changeTree = this[$changes];
|
|
2712
2741
|
//
|
|
2713
2742
|
// Replacing existing "ref", remove it from root.
|
|
2714
2743
|
// TODO: if there are other references to this instance, we should not remove it from root.
|
|
2715
2744
|
//
|
|
2716
2745
|
if (previousValue !== undefined && previousValue[$changes]) {
|
|
2717
|
-
|
|
2746
|
+
changeTree.root?.remove(previousValue[$changes]);
|
|
2718
2747
|
}
|
|
2719
2748
|
// flag the change for encoding.
|
|
2720
|
-
this.constructor[$track](
|
|
2749
|
+
this.constructor[$track](changeTree, fieldIndex, exports.OPERATION.ADD);
|
|
2721
2750
|
//
|
|
2722
2751
|
// call setParent() recursively for this and its child
|
|
2723
2752
|
// structures.
|
|
2724
2753
|
//
|
|
2725
|
-
|
|
2726
|
-
value[$changes].setParent(this, this[$changes].root, metadata[field].index);
|
|
2727
|
-
}
|
|
2754
|
+
value[$changes]?.setParent(this, changeTree.root, fieldIndex);
|
|
2728
2755
|
}
|
|
2729
2756
|
else if (previousValue !== undefined) {
|
|
2730
2757
|
//
|
|
@@ -2751,20 +2778,22 @@
|
|
|
2751
2778
|
const parentClass = Object.getPrototypeOf(constructor);
|
|
2752
2779
|
const parentMetadata = parentClass[Symbol.metadata];
|
|
2753
2780
|
const metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
}
|
|
2765
|
-
|
|
2781
|
+
const fieldIndex = metadata[field];
|
|
2782
|
+
// if (!metadata[field]) {
|
|
2783
|
+
// //
|
|
2784
|
+
// // detect index for this field, considering inheritance
|
|
2785
|
+
// //
|
|
2786
|
+
// metadata[field] = {
|
|
2787
|
+
// type: undefined,
|
|
2788
|
+
// index: (metadata[-1] // current structure already has fields defined
|
|
2789
|
+
// ?? (parentMetadata && parentMetadata[-1]) // parent structure has fields defined
|
|
2790
|
+
// ?? -1) + 1 // no fields defined
|
|
2791
|
+
// }
|
|
2792
|
+
// }
|
|
2793
|
+
metadata[fieldIndex].deprecated = true;
|
|
2766
2794
|
if (throws) {
|
|
2767
|
-
metadata[
|
|
2795
|
+
metadata[$descriptors] ??= {};
|
|
2796
|
+
metadata[$descriptors][field] = {
|
|
2768
2797
|
get: function () { throw new Error(`${field} is deprecated.`); },
|
|
2769
2798
|
set: function (value) { },
|
|
2770
2799
|
enumerable: false,
|
|
@@ -2772,8 +2801,8 @@
|
|
|
2772
2801
|
};
|
|
2773
2802
|
}
|
|
2774
2803
|
// flag metadata[field] as non-enumerable
|
|
2775
|
-
Object.defineProperty(metadata,
|
|
2776
|
-
value: metadata[
|
|
2804
|
+
Object.defineProperty(metadata, fieldIndex, {
|
|
2805
|
+
value: metadata[fieldIndex],
|
|
2777
2806
|
enumerable: false,
|
|
2778
2807
|
configurable: true
|
|
2779
2808
|
});
|
|
@@ -2839,35 +2868,7 @@
|
|
|
2839
2868
|
enumerable: false,
|
|
2840
2869
|
writable: true
|
|
2841
2870
|
});
|
|
2842
|
-
|
|
2843
|
-
// Define property descriptors
|
|
2844
|
-
for (const field in metadata) {
|
|
2845
|
-
if (metadata[field].descriptor) {
|
|
2846
|
-
// for encoder
|
|
2847
|
-
Object.defineProperty(instance, `_${field}`, {
|
|
2848
|
-
value: undefined,
|
|
2849
|
-
writable: true,
|
|
2850
|
-
enumerable: false,
|
|
2851
|
-
configurable: true,
|
|
2852
|
-
});
|
|
2853
|
-
Object.defineProperty(instance, field, metadata[field].descriptor);
|
|
2854
|
-
}
|
|
2855
|
-
else {
|
|
2856
|
-
// for decoder
|
|
2857
|
-
Object.defineProperty(instance, field, {
|
|
2858
|
-
value: undefined,
|
|
2859
|
-
writable: true,
|
|
2860
|
-
enumerable: true,
|
|
2861
|
-
configurable: true,
|
|
2862
|
-
});
|
|
2863
|
-
}
|
|
2864
|
-
// Object.defineProperty(instance, field, {
|
|
2865
|
-
// ...instance.constructor[Symbol.metadata][field].descriptor
|
|
2866
|
-
// });
|
|
2867
|
-
// if (args[0]?.hasOwnProperty(field)) {
|
|
2868
|
-
// instance[field] = args[0][field];
|
|
2869
|
-
// }
|
|
2870
|
-
}
|
|
2871
|
+
Object.defineProperties(instance, instance.constructor[Symbol.metadata]?.[$descriptors] || {});
|
|
2871
2872
|
}
|
|
2872
2873
|
static is(type) {
|
|
2873
2874
|
return typeof (type[Symbol.metadata]) === "object";
|
|
@@ -2891,7 +2892,7 @@
|
|
|
2891
2892
|
*/
|
|
2892
2893
|
static [$filter](ref, index, view) {
|
|
2893
2894
|
const metadata = ref.constructor[Symbol.metadata];
|
|
2894
|
-
const tag = metadata[
|
|
2895
|
+
const tag = metadata[index]?.tag;
|
|
2895
2896
|
if (view === undefined) {
|
|
2896
2897
|
// shared pass/encode: encode if doesn't have a tag
|
|
2897
2898
|
return tag === undefined;
|
|
@@ -2912,12 +2913,21 @@
|
|
|
2912
2913
|
}
|
|
2913
2914
|
// allow inherited classes to have a constructor
|
|
2914
2915
|
constructor(...args) {
|
|
2915
|
-
|
|
2916
|
+
//
|
|
2917
|
+
// inline
|
|
2918
|
+
// Schema.initialize(this);
|
|
2919
|
+
//
|
|
2920
|
+
Object.defineProperty(this, $changes, {
|
|
2921
|
+
value: new ChangeTree(this),
|
|
2922
|
+
enumerable: false,
|
|
2923
|
+
writable: true
|
|
2924
|
+
});
|
|
2925
|
+
Object.defineProperties(this, this.constructor[Symbol.metadata]?.[$descriptors] || {});
|
|
2916
2926
|
//
|
|
2917
2927
|
// Assign initial values
|
|
2918
2928
|
//
|
|
2919
2929
|
if (args[0]) {
|
|
2920
|
-
|
|
2930
|
+
Object.assign(this, args[0]);
|
|
2921
2931
|
}
|
|
2922
2932
|
}
|
|
2923
2933
|
assign(props) {
|
|
@@ -2931,7 +2941,8 @@
|
|
|
2931
2941
|
* @param operation OPERATION to perform (detected automatically)
|
|
2932
2942
|
*/
|
|
2933
2943
|
setDirty(property, operation) {
|
|
2934
|
-
this
|
|
2944
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
2945
|
+
this[$changes].change(metadata[metadata[property]].index, operation);
|
|
2935
2946
|
}
|
|
2936
2947
|
clone() {
|
|
2937
2948
|
const cloned = new (this.constructor);
|
|
@@ -2940,7 +2951,9 @@
|
|
|
2940
2951
|
// TODO: clone all properties, not only annotated ones
|
|
2941
2952
|
//
|
|
2942
2953
|
// for (const field in this) {
|
|
2943
|
-
for (const
|
|
2954
|
+
for (const fieldIndex in metadata) {
|
|
2955
|
+
// const field = metadata[metadata[fieldIndex]].name;
|
|
2956
|
+
const field = metadata[fieldIndex].name;
|
|
2944
2957
|
if (typeof (this[field]) === "object" &&
|
|
2945
2958
|
typeof (this[field]?.clone) === "function") {
|
|
2946
2959
|
// deep clone
|
|
@@ -2954,10 +2967,11 @@
|
|
|
2954
2967
|
return cloned;
|
|
2955
2968
|
}
|
|
2956
2969
|
toJSON() {
|
|
2957
|
-
const metadata = this.constructor[Symbol.metadata];
|
|
2958
2970
|
const obj = {};
|
|
2959
|
-
|
|
2960
|
-
|
|
2971
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
2972
|
+
for (const index in metadata) {
|
|
2973
|
+
const field = metadata[index];
|
|
2974
|
+
const fieldName = field.name;
|
|
2961
2975
|
if (!field.deprecated && this[fieldName] !== null && typeof (this[fieldName]) !== "undefined") {
|
|
2962
2976
|
obj[fieldName] = (typeof (this[fieldName]['toJSON']) === "function")
|
|
2963
2977
|
? this[fieldName]['toJSON']()
|
|
@@ -2970,10 +2984,12 @@
|
|
|
2970
2984
|
this[$changes].discardAll();
|
|
2971
2985
|
}
|
|
2972
2986
|
[$getByIndex](index) {
|
|
2973
|
-
|
|
2987
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
2988
|
+
return this[metadata[index].name];
|
|
2974
2989
|
}
|
|
2975
2990
|
[$deleteByIndex](index) {
|
|
2976
|
-
this
|
|
2991
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
2992
|
+
this[metadata[index].name] = undefined;
|
|
2977
2993
|
}
|
|
2978
2994
|
static debugRefIds(instance, jsonContents = true, level = 0) {
|
|
2979
2995
|
const ref = instance;
|
|
@@ -3097,6 +3113,7 @@
|
|
|
3097
3113
|
this.$indexes = new Map();
|
|
3098
3114
|
this.$refId = 0;
|
|
3099
3115
|
this[$changes] = new ChangeTree(this);
|
|
3116
|
+
this[$changes].indexes = {};
|
|
3100
3117
|
if (initialValues) {
|
|
3101
3118
|
initialValues.forEach((v) => this.add(v));
|
|
3102
3119
|
}
|
|
@@ -3252,6 +3269,7 @@
|
|
|
3252
3269
|
this.$indexes = new Map();
|
|
3253
3270
|
this.$refId = 0;
|
|
3254
3271
|
this[$changes] = new ChangeTree(this);
|
|
3272
|
+
this[$changes].indexes = {};
|
|
3255
3273
|
if (initialValues) {
|
|
3256
3274
|
initialValues.forEach((v) => this.add(v));
|
|
3257
3275
|
}
|
|
@@ -3438,24 +3456,36 @@
|
|
|
3438
3456
|
return this.nextUniqueId++;
|
|
3439
3457
|
}
|
|
3440
3458
|
add(changeTree) {
|
|
3441
|
-
const
|
|
3442
|
-
|
|
3459
|
+
const previousRefCount = this.refCount.get(changeTree);
|
|
3460
|
+
if (previousRefCount === 0) {
|
|
3461
|
+
//
|
|
3462
|
+
// When a ChangeTree is re-added, it means that it was previously removed.
|
|
3463
|
+
// We need to re-add all changes to the `changes` map.
|
|
3464
|
+
//
|
|
3465
|
+
changeTree.allChanges.forEach((operation, index) => {
|
|
3466
|
+
changeTree.changes.set(index, operation);
|
|
3467
|
+
});
|
|
3468
|
+
}
|
|
3469
|
+
const refCount = (previousRefCount || 0) + 1;
|
|
3470
|
+
this.refCount.set(changeTree, refCount);
|
|
3471
|
+
return refCount;
|
|
3443
3472
|
}
|
|
3444
3473
|
remove(changeTree) {
|
|
3445
|
-
const refCount = this.refCount.get(changeTree);
|
|
3446
|
-
if (refCount <=
|
|
3474
|
+
const refCount = (this.refCount.get(changeTree)) - 1;
|
|
3475
|
+
if (refCount <= 0) {
|
|
3447
3476
|
this.allChanges.delete(changeTree);
|
|
3448
3477
|
this.changes.delete(changeTree);
|
|
3449
3478
|
if (changeTree.isFiltered || changeTree.isPartiallyFiltered) {
|
|
3450
3479
|
this.allFilteredChanges.delete(changeTree);
|
|
3451
3480
|
this.filteredChanges.delete(changeTree);
|
|
3452
3481
|
}
|
|
3453
|
-
this.refCount.
|
|
3482
|
+
this.refCount.set(changeTree, 0);
|
|
3454
3483
|
}
|
|
3455
3484
|
else {
|
|
3456
|
-
this.refCount.set(changeTree, refCount
|
|
3485
|
+
this.refCount.set(changeTree, refCount);
|
|
3457
3486
|
}
|
|
3458
3487
|
changeTree.forEachChild((child, _) => this.remove(child));
|
|
3488
|
+
return refCount;
|
|
3459
3489
|
}
|
|
3460
3490
|
clear() {
|
|
3461
3491
|
this.changes.clear();
|
|
@@ -3486,10 +3516,10 @@
|
|
|
3486
3516
|
) {
|
|
3487
3517
|
const hasView = (view !== undefined);
|
|
3488
3518
|
const rootChangeTree = this.state[$changes];
|
|
3489
|
-
const
|
|
3490
|
-
for (const [changeTree, changes] of
|
|
3519
|
+
const shouldClearChanges = !isEncodeAll && !hasView;
|
|
3520
|
+
for (const [changeTree, changes] of changeTrees.entries()) {
|
|
3491
3521
|
const ref = changeTree.ref;
|
|
3492
|
-
const ctor = ref
|
|
3522
|
+
const ctor = ref.constructor;
|
|
3493
3523
|
const encoder = ctor[$encoder];
|
|
3494
3524
|
const filter = ctor[$filter];
|
|
3495
3525
|
// try { throw new Error(); } catch (e) {
|
|
@@ -3513,8 +3543,7 @@
|
|
|
3513
3543
|
buffer[it.offset++] = SWITCH_TO_STRUCTURE & 255;
|
|
3514
3544
|
number$1(buffer, changeTree.refId, it);
|
|
3515
3545
|
}
|
|
3516
|
-
const
|
|
3517
|
-
for (const [fieldIndex, operation] of changesIterator) {
|
|
3546
|
+
for (const [fieldIndex, operation] of changes.entries()) {
|
|
3518
3547
|
//
|
|
3519
3548
|
// first pass (encodeAll), identify "filtered" operations without encoding them
|
|
3520
3549
|
// they will be encoded per client, based on their view.
|
|
@@ -3539,6 +3568,14 @@
|
|
|
3539
3568
|
// }
|
|
3540
3569
|
encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
|
|
3541
3570
|
}
|
|
3571
|
+
// if (shouldClearChanges) {
|
|
3572
|
+
// // changeTree.endEncode();
|
|
3573
|
+
// changeTree.changes.clear();
|
|
3574
|
+
// // ArraySchema and MapSchema have a custom "encode end" method
|
|
3575
|
+
// changeTree.ref[$onEncodeEnd]?.();
|
|
3576
|
+
// // Not a new instance anymore
|
|
3577
|
+
// delete changeTree[$isNew];
|
|
3578
|
+
// }
|
|
3542
3579
|
}
|
|
3543
3580
|
if (it.offset > buffer.byteLength) {
|
|
3544
3581
|
const newSize = getNextPowerOf2(buffer.byteLength * 2);
|
|
@@ -3561,7 +3598,7 @@
|
|
|
3561
3598
|
//
|
|
3562
3599
|
// only clear changes after making sure buffer resize is not required.
|
|
3563
3600
|
//
|
|
3564
|
-
if (
|
|
3601
|
+
if (shouldClearChanges) {
|
|
3565
3602
|
//
|
|
3566
3603
|
// FIXME: avoid iterating over change trees twice.
|
|
3567
3604
|
//
|
|
@@ -3645,6 +3682,11 @@
|
|
|
3645
3682
|
const changeTreesIterator = changeTrees.entries();
|
|
3646
3683
|
for (const [changeTree, _] of changeTreesIterator) {
|
|
3647
3684
|
changeTree.endEncode();
|
|
3685
|
+
// changeTree.changes.clear();
|
|
3686
|
+
// // ArraySchema and MapSchema have a custom "encode end" method
|
|
3687
|
+
// changeTree.ref[$onEncodeEnd]?.();
|
|
3688
|
+
// // Not a new instance anymore
|
|
3689
|
+
// delete changeTree[$isNew];
|
|
3648
3690
|
}
|
|
3649
3691
|
}
|
|
3650
3692
|
discardChanges() {
|
|
@@ -3760,8 +3802,9 @@
|
|
|
3760
3802
|
// Ensure child schema instances have their references removed as well.
|
|
3761
3803
|
//
|
|
3762
3804
|
if (Metadata.isValidInstance(ref)) {
|
|
3763
|
-
const metadata = ref
|
|
3764
|
-
for (const
|
|
3805
|
+
const metadata = ref.constructor[Symbol.metadata];
|
|
3806
|
+
for (const index in metadata) {
|
|
3807
|
+
const field = metadata[index].name;
|
|
3765
3808
|
const childRefId = typeof (ref[field]) === "object" && this.refIds.get(ref[field]);
|
|
3766
3809
|
if (childRefId) {
|
|
3767
3810
|
this.removeRef(childRefId);
|
|
@@ -3948,7 +3991,9 @@
|
|
|
3948
3991
|
const reflection = new Reflection();
|
|
3949
3992
|
const encoder = new Encoder(reflection);
|
|
3950
3993
|
const buildType = (currentType, metadata) => {
|
|
3951
|
-
for (const
|
|
3994
|
+
for (const fieldIndex in metadata) {
|
|
3995
|
+
const index = Number(fieldIndex);
|
|
3996
|
+
const fieldName = metadata[index].name;
|
|
3952
3997
|
// skip fields from parent classes
|
|
3953
3998
|
if (!Object.prototype.hasOwnProperty.call(metadata, fieldName)) {
|
|
3954
3999
|
continue;
|
|
@@ -3956,7 +4001,7 @@
|
|
|
3956
4001
|
const field = new ReflectionField();
|
|
3957
4002
|
field.name = fieldName;
|
|
3958
4003
|
let fieldType;
|
|
3959
|
-
const type = metadata[
|
|
4004
|
+
const type = metadata[index].type;
|
|
3960
4005
|
if (typeof (type) === "string") {
|
|
3961
4006
|
fieldType = type;
|
|
3962
4007
|
}
|
|
@@ -4022,18 +4067,7 @@
|
|
|
4022
4067
|
reflection.types.forEach((reflectionType) => {
|
|
4023
4068
|
const schemaType = typeContext.get(reflectionType.id);
|
|
4024
4069
|
const metadata = schemaType[Symbol.metadata];
|
|
4025
|
-
// FIXME: use metadata[-1] to get field count
|
|
4026
4070
|
const parentFieldIndex = 0;
|
|
4027
|
-
// console.log("--------------------");
|
|
4028
|
-
// // console.log("reflectionType", reflectionType.toJSON());
|
|
4029
|
-
// console.log("reflectionType.fields", reflectionType.fields.toJSON());
|
|
4030
|
-
// console.log("parentFieldIndex", parentFieldIndex);
|
|
4031
|
-
//
|
|
4032
|
-
// FIXME: set fields using parentKlass as well
|
|
4033
|
-
// currently the fields are duplicated on inherited classes
|
|
4034
|
-
//
|
|
4035
|
-
// // const parentKlass = reflection.types[reflectionType.extendsId];
|
|
4036
|
-
// // parentKlass.fields
|
|
4037
4071
|
reflectionType.fields.forEach((field, i) => {
|
|
4038
4072
|
const fieldIndex = parentFieldIndex + i;
|
|
4039
4073
|
if (field.referencedType !== undefined) {
|
|
@@ -4198,7 +4232,7 @@
|
|
|
4198
4232
|
//
|
|
4199
4233
|
bindTo: function bindTo(targetObject, properties) {
|
|
4200
4234
|
if (!properties) {
|
|
4201
|
-
properties = Object.keys(metadata);
|
|
4235
|
+
properties = Object.keys(metadata).map((index) => metadata[index].name);
|
|
4202
4236
|
}
|
|
4203
4237
|
return $root.addCallback($root.refIds.get(context.instance), exports.OPERATION.REPLACE, () => {
|
|
4204
4238
|
properties.forEach((prop) => targetObject[prop] = context.instance[prop]);
|
|
@@ -4206,7 +4240,8 @@
|
|
|
4206
4240
|
}
|
|
4207
4241
|
}, {
|
|
4208
4242
|
get(target, prop) {
|
|
4209
|
-
|
|
4243
|
+
const metadataField = metadata[metadata[prop]];
|
|
4244
|
+
if (metadataField) {
|
|
4210
4245
|
const instance = context.instance?.[prop];
|
|
4211
4246
|
const onInstanceAvailable = ((callback) => {
|
|
4212
4247
|
const unbind = $(context.instance).listen(prop, (value, _) => {
|
|
@@ -4222,7 +4257,7 @@
|
|
|
4222
4257
|
callback(instance, true);
|
|
4223
4258
|
}
|
|
4224
4259
|
});
|
|
4225
|
-
return getProxy(
|
|
4260
|
+
return getProxy(metadataField.type, {
|
|
4226
4261
|
// make sure refId is available, otherwise need to wait for the instance to be available.
|
|
4227
4262
|
instance: ($root.refIds.get(instance) && instance),
|
|
4228
4263
|
parentInstance: context.instance,
|
|
@@ -4335,7 +4370,7 @@
|
|
|
4335
4370
|
console.warn("StateView#add(), invalid object:", obj);
|
|
4336
4371
|
return this;
|
|
4337
4372
|
}
|
|
4338
|
-
// FIXME: ArraySchema/MapSchema
|
|
4373
|
+
// FIXME: ArraySchema/MapSchema do not have metadata
|
|
4339
4374
|
const metadata = obj.constructor[Symbol.metadata];
|
|
4340
4375
|
const changeTree = obj[$changes];
|
|
4341
4376
|
this.items.add(changeTree);
|
|
@@ -4381,7 +4416,7 @@
|
|
|
4381
4416
|
? changeTree.allFilteredChanges
|
|
4382
4417
|
: changeTree.allChanges;
|
|
4383
4418
|
changeSet.forEach((op, index) => {
|
|
4384
|
-
const tagAtIndex = metadata?.[
|
|
4419
|
+
const tagAtIndex = metadata?.[index].tag;
|
|
4385
4420
|
if ((isInvisible || // if "invisible", include all
|
|
4386
4421
|
tagAtIndex === undefined || // "all change" with no tag
|
|
4387
4422
|
tagAtIndex === tag // tagged property
|
|
@@ -4394,7 +4429,7 @@
|
|
|
4394
4429
|
// Add children of this ChangeTree to this view
|
|
4395
4430
|
changeTree.forEachChild((change, index) => {
|
|
4396
4431
|
// Do not ADD children that don't have the same tag
|
|
4397
|
-
if (metadata && metadata[
|
|
4432
|
+
if (metadata && metadata[index].tag !== tag) {
|
|
4398
4433
|
return;
|
|
4399
4434
|
}
|
|
4400
4435
|
this.add(change.ref, tag, false);
|