@colyseus/schema 3.0.27 → 3.0.29

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.
Files changed (39) hide show
  1. package/build/cjs/index.js +51 -29
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/esm/index.mjs +51 -29
  4. package/build/esm/index.mjs.map +1 -1
  5. package/build/umd/index.js +51 -29
  6. package/lib/Metadata.d.ts +1 -0
  7. package/lib/Metadata.js +3 -0
  8. package/lib/Metadata.js.map +1 -1
  9. package/lib/Schema.js +1 -1
  10. package/lib/Schema.js.map +1 -1
  11. package/lib/decoder/DecodeOperation.js +8 -4
  12. package/lib/decoder/DecodeOperation.js.map +1 -1
  13. package/lib/encoder/ChangeTree.d.ts +1 -0
  14. package/lib/encoder/ChangeTree.js +13 -15
  15. package/lib/encoder/ChangeTree.js.map +1 -1
  16. package/lib/encoder/EncodeOperation.js +1 -1
  17. package/lib/encoder/EncodeOperation.js.map +1 -1
  18. package/lib/encoder/Encoder.js +3 -4
  19. package/lib/encoder/Encoder.js.map +1 -1
  20. package/lib/encoder/StateView.d.ts +1 -0
  21. package/lib/encoder/StateView.js +19 -0
  22. package/lib/encoder/StateView.js.map +1 -1
  23. package/lib/types/custom/ArraySchema.js +1 -2
  24. package/lib/types/custom/ArraySchema.js.map +1 -1
  25. package/lib/types/custom/CollectionSchema.js +1 -1
  26. package/lib/types/custom/CollectionSchema.js.map +1 -1
  27. package/lib/types/custom/MapSchema.js +1 -1
  28. package/lib/types/custom/MapSchema.js.map +1 -1
  29. package/package.json +1 -1
  30. package/src/Metadata.ts +4 -0
  31. package/src/Schema.ts +1 -1
  32. package/src/decoder/DecodeOperation.ts +9 -4
  33. package/src/encoder/ChangeTree.ts +20 -17
  34. package/src/encoder/EncodeOperation.ts +1 -1
  35. package/src/encoder/Encoder.ts +3 -4
  36. package/src/encoder/StateView.ts +24 -0
  37. package/src/types/custom/ArraySchema.ts +1 -2
  38. package/src/types/custom/CollectionSchema.ts +1 -1
  39. package/src/types/custom/MapSchema.ts +1 -1
@@ -959,6 +959,9 @@ const Metadata = {
959
959
  fields[metadata[i].name] = metadata[i].type;
960
960
  }
961
961
  return fields;
962
+ },
963
+ hasViewTagAtIndex(metadata, index) {
964
+ return metadata?.[$viewFieldIndexes]?.includes(index);
962
965
  }
963
966
  };
964
967
 
@@ -1175,18 +1178,6 @@ class ChangeTree {
1175
1178
  for (const key in changeSet.indexes) {
1176
1179
  newIndexes[newKey++] = changeSet.indexes[key];
1177
1180
  }
1178
- // const newIndexes = {};
1179
- // let newKey = 0;
1180
- // for (const key in changeSet.indexes) {
1181
- // const index = changeSet.indexes[key];
1182
- // newIndexes[newKey++] = changeSet.indexes[key];
1183
- // console.log("...shiftAllChangeIndexes", { index: key, targetIndex: index, startIndex, shiftIndex });
1184
- // if (index > startIndex) {
1185
- // newIndexes[Number(key) + shiftIndex] = index;
1186
- // } else {
1187
- // newIndexes[Number(key)] = index;
1188
- // }
1189
- // }
1190
1181
  changeSet.indexes = newIndexes;
1191
1182
  for (let i = 0; i < changeSet.operations.length; i++) {
1192
1183
  const index = changeSet.operations[i];
@@ -1375,25 +1366,35 @@ class ChangeTree {
1375
1366
  const refType = Metadata.isValidInstance(this.ref)
1376
1367
  ? this.ref.constructor
1377
1368
  : this.ref[$childType];
1378
- if (!Metadata.isValidInstance(parent)) {
1379
- const parentChangeTree = parent[$changes];
1369
+ let parentChangeTree;
1370
+ let parentIsCollection = !Metadata.isValidInstance(parent);
1371
+ if (parentIsCollection) {
1372
+ parentChangeTree = parent[$changes];
1380
1373
  parent = parentChangeTree.parent;
1381
1374
  parentIndex = parentChangeTree.parentIndex;
1382
1375
  }
1376
+ else {
1377
+ parentChangeTree = parent[$changes];
1378
+ }
1383
1379
  const parentConstructor = parent.constructor;
1384
1380
  let key = `${this.root.types.getTypeId(refType)}`;
1385
1381
  if (parentConstructor) {
1386
1382
  key += `-${this.root.types.schemas.get(parentConstructor)}`;
1387
1383
  }
1388
1384
  key += `-${parentIndex}`;
1385
+ const fieldHasViewTag = Metadata.hasViewTagAtIndex(parentConstructor?.[Symbol.metadata], parentIndex);
1389
1386
  this.isFiltered = parent[$changes].isFiltered // in case parent is already filtered
1390
1387
  || this.root.types.parentFiltered[key]
1391
- || parentConstructor?.[Symbol.metadata]?.[$viewFieldIndexes]?.includes(parentIndex);
1388
+ || fieldHasViewTag;
1392
1389
  //
1393
1390
  // "isFiltered" may not be imedialely available during `change()` due to the instance not being attached to the root yet.
1394
1391
  // when it's available, we need to enqueue the "changes" changeset into the "filteredChanges" changeset.
1395
1392
  //
1396
1393
  if (this.isFiltered) {
1394
+ this.isVisibilitySharedWithParent = (parentChangeTree.isFiltered &&
1395
+ typeof (refType) !== "string" &&
1396
+ !fieldHasViewTag &&
1397
+ parentIsCollection);
1397
1398
  if (!this.filteredChanges) {
1398
1399
  this.filteredChanges = createChangeSet();
1399
1400
  this.allFilteredChanges = createChangeSet();
@@ -1524,7 +1525,7 @@ const encodeArray = function (encoder, bytes, changeTree, field, operation, it,
1524
1525
  // encode index
1525
1526
  encode.number(bytes, refOrIndex, it);
1526
1527
  // Do not encode value for DELETE operations
1527
- if (operation === exports.OPERATION.DELETE) {
1528
+ if (operation === exports.OPERATION.DELETE || operation === exports.OPERATION.DELETE_BY_REFID) {
1528
1529
  return;
1529
1530
  }
1530
1531
  const type = changeTree.getType(field);
@@ -1745,10 +1746,14 @@ const decodeArray = function (decoder, bytes, it, ref, allChanges) {
1745
1746
  else if (operation === exports.OPERATION.ADD_BY_REFID) {
1746
1747
  const refId = decode.number(bytes, it);
1747
1748
  const itemByRefId = decoder.root.refs.get(refId);
1748
- // use existing index, or push new value
1749
- index = (itemByRefId)
1750
- ? ref.findIndex((value) => value === itemByRefId)
1751
- : ref.length;
1749
+ // if item already exists, use existing index
1750
+ if (itemByRefId) {
1751
+ index = ref.findIndex((value) => value === itemByRefId);
1752
+ }
1753
+ // fallback to use last index
1754
+ if (index === -1 || index === undefined) {
1755
+ index = ref.length;
1756
+ }
1752
1757
  }
1753
1758
  else {
1754
1759
  index = decode.number(bytes, it);
@@ -1851,8 +1856,7 @@ class ArraySchema {
1851
1856
  static [(_a$4 = $encoder, _b$4 = $decoder, $filter)](ref, index, view) {
1852
1857
  return (!view ||
1853
1858
  typeof (ref[$childType]) === "string" ||
1854
- // view.items.has(ref[$getByIndex](index)[$changes])
1855
- view.visible.has(ref['tmpItems'][index]?.[$changes]));
1859
+ view.isChangeTreeVisible(ref['tmpItems'][index]?.[$changes]));
1856
1860
  }
1857
1861
  static is(type) {
1858
1862
  return (
@@ -2533,7 +2537,7 @@ class MapSchema {
2533
2537
  static [(_a$3 = $encoder, _b$3 = $decoder, $filter)](ref, index, view) {
2534
2538
  return (!view ||
2535
2539
  typeof (ref[$childType]) === "string" ||
2536
- view.visible.has((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
2540
+ view.isChangeTreeVisible((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
2537
2541
  }
2538
2542
  static is(type) {
2539
2543
  return type['map'] !== undefined;
@@ -3150,7 +3154,7 @@ class Schema {
3150
3154
  }
3151
3155
  else if (tag === DEFAULT_VIEW_TAG) {
3152
3156
  // view pass: default tag
3153
- return view.visible.has(ref[$changes]);
3157
+ return view.isChangeTreeVisible(ref[$changes]);
3154
3158
  }
3155
3159
  else {
3156
3160
  // view pass: custom tag
@@ -3363,7 +3367,7 @@ class CollectionSchema {
3363
3367
  static [(_a$1 = $encoder, _b$1 = $decoder, $filter)](ref, index, view) {
3364
3368
  return (!view ||
3365
3369
  typeof (ref[$childType]) === "string" ||
3366
- view.visible.has((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
3370
+ view.isChangeTreeVisible((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
3367
3371
  }
3368
3372
  static is(type) {
3369
3373
  return type['collection'] !== undefined;
@@ -3837,13 +3841,12 @@ class Encoder {
3837
3841
  continue;
3838
3842
  }
3839
3843
  if (hasView) {
3840
- if (!view.visible.has(changeTree)) {
3844
+ if (!view.isChangeTreeVisible(changeTree)) {
3845
+ // console.log("MARK AS INVISIBLE:", { ref: changeTree.ref.constructor.name, refId: changeTree.refId, raw: changeTree.ref.toJSON() });
3841
3846
  view.invisible.add(changeTree);
3842
3847
  continue; // skip this change tree
3843
3848
  }
3844
- else {
3845
- view.invisible.delete(changeTree); // remove from invisible list
3846
- }
3849
+ view.invisible.delete(changeTree); // remove from invisible list
3847
3850
  }
3848
3851
  const changeSet = changeTree[changeSetName];
3849
3852
  const ref = changeTree.ref;
@@ -4977,6 +4980,25 @@ class StateView {
4977
4980
  // clear items array
4978
4981
  this.items.length = 0;
4979
4982
  }
4983
+ isChangeTreeVisible(changeTree) {
4984
+ let isVisible = this.visible.has(changeTree);
4985
+ //
4986
+ // TODO: avoid checking for parent visibility, most of the time it's not needed
4987
+ // See test case: 'should not be required to manually call view.add() items to child arrays without @view() tag'
4988
+ //
4989
+ if (!isVisible && changeTree.isVisibilitySharedWithParent) {
4990
+ // console.log("CHECK AGAINST PARENT...", {
4991
+ // ref: changeTree.ref.constructor.name,
4992
+ // refId: changeTree.refId,
4993
+ // parent: changeTree.parent.constructor.name,
4994
+ // });
4995
+ if (this.visible.has(changeTree.parent[$changes])) {
4996
+ this.visible.add(changeTree);
4997
+ isVisible = true;
4998
+ }
4999
+ }
5000
+ return isVisible;
5001
+ }
4980
5002
  }
4981
5003
 
4982
5004
  registerType("map", { constructor: MapSchema });