@colyseus/schema 1.1.0-alpha.1 → 2.0.2

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 (55) hide show
  1. package/README.md +1 -4
  2. package/build/cjs/index.js +1197 -1001
  3. package/build/cjs/index.js.map +1 -1
  4. package/build/esm/index.mjs +353 -311
  5. package/build/esm/index.mjs.map +1 -1
  6. package/build/umd/index.js +374 -335
  7. package/lib/Reflection.js +23 -13
  8. package/lib/Reflection.js.map +1 -1
  9. package/lib/Schema.d.ts +26 -18
  10. package/lib/Schema.js +121 -165
  11. package/lib/Schema.js.map +1 -1
  12. package/lib/annotations.d.ts +26 -8
  13. package/lib/annotations.js +62 -14
  14. package/lib/annotations.js.map +1 -1
  15. package/lib/changes/ChangeTree.d.ts +4 -16
  16. package/lib/changes/ChangeTree.js +1 -72
  17. package/lib/changes/ChangeTree.js.map +1 -1
  18. package/lib/changes/ReferenceTracker.d.ts +14 -0
  19. package/lib/changes/ReferenceTracker.js +77 -0
  20. package/lib/changes/ReferenceTracker.js.map +1 -0
  21. package/lib/codegen/languages/csharp.js +39 -17
  22. package/lib/codegen/languages/csharp.js.map +1 -1
  23. package/lib/codegen/languages/ts.js +11 -2
  24. package/lib/codegen/languages/ts.js.map +1 -1
  25. package/lib/codegen/parser.js +3 -1
  26. package/lib/codegen/parser.js.map +1 -1
  27. package/lib/codegen/types.js +14 -1
  28. package/lib/codegen/types.js.map +1 -1
  29. package/lib/events/EventEmitter.d.ts +4 -4
  30. package/lib/events/EventEmitter.js +10 -10
  31. package/lib/events/EventEmitter.js.map +1 -1
  32. package/lib/filters/index.d.ts +2 -2
  33. package/lib/filters/index.js.map +1 -1
  34. package/lib/index.d.ts +1 -1
  35. package/lib/index.js +6 -6
  36. package/lib/index.js.map +1 -1
  37. package/lib/types/ArraySchema.d.ts +8 -5
  38. package/lib/types/ArraySchema.js +22 -19
  39. package/lib/types/ArraySchema.js.map +1 -1
  40. package/lib/types/CollectionSchema.d.ts +8 -5
  41. package/lib/types/CollectionSchema.js +17 -11
  42. package/lib/types/CollectionSchema.js.map +1 -1
  43. package/lib/types/MapSchema.d.ts +8 -5
  44. package/lib/types/MapSchema.js +20 -11
  45. package/lib/types/MapSchema.js.map +1 -1
  46. package/lib/types/SetSchema.d.ts +8 -5
  47. package/lib/types/SetSchema.js +22 -14
  48. package/lib/types/SetSchema.js.map +1 -1
  49. package/lib/types/typeRegistry.d.ts +5 -0
  50. package/lib/types/typeRegistry.js +13 -0
  51. package/lib/types/typeRegistry.js.map +1 -0
  52. package/lib/types/utils.d.ts +9 -0
  53. package/lib/types/utils.js +50 -0
  54. package/lib/types/utils.js.map +1 -0
  55. package/package.json +3 -8
package/lib/Schema.js CHANGED
@@ -41,9 +41,10 @@ var MapSchema_1 = require("./types/MapSchema");
41
41
  var CollectionSchema_1 = require("./types/CollectionSchema");
42
42
  var SetSchema_1 = require("./types/SetSchema");
43
43
  var ChangeTree_1 = require("./changes/ChangeTree");
44
- var EventEmitter_1 = require("./events/EventEmitter");
45
44
  var filters_1 = require("./filters");
46
- var types_1 = require("./types");
45
+ var typeRegistry_1 = require("./types/typeRegistry");
46
+ var ReferenceTracker_1 = require("./changes/ReferenceTracker");
47
+ var utils_1 = require("./types/utils");
47
48
  var EncodeSchemaError = /** @class */ (function (_super) {
48
49
  __extends(EncodeSchemaError, _super);
49
50
  function EncodeSchemaError() {
@@ -115,12 +116,17 @@ var Schema = /** @class */ (function () {
115
116
  // fix enumerability of fields for end-user
116
117
  Object.defineProperties(this, {
117
118
  $changes: {
118
- value: new ChangeTree_1.ChangeTree(this, undefined, new ChangeTree_1.Root()),
119
+ value: new ChangeTree_1.ChangeTree(this, undefined, new ReferenceTracker_1.ReferenceTracker()),
119
120
  enumerable: false,
120
121
  writable: true
121
122
  },
122
- $listeners: {
123
- value: {},
123
+ // $listeners: {
124
+ // value: undefined,
125
+ // enumerable: false,
126
+ // writable: true
127
+ // },
128
+ $callbacks: {
129
+ value: undefined,
124
130
  enumerable: false,
125
131
  writable: true
126
132
  },
@@ -143,6 +149,12 @@ var Schema = /** @class */ (function () {
143
149
  return (type['_definition'] &&
144
150
  type['_definition'].schema !== undefined);
145
151
  };
152
+ Schema.prototype.onChange = function (callback) {
153
+ return utils_1.addCallback((this.$callbacks || (this.$callbacks = [])), spec_1.OPERATION.REPLACE, callback);
154
+ };
155
+ Schema.prototype.onRemove = function (callback) {
156
+ return utils_1.addCallback((this.$callbacks || (this.$callbacks = [])), spec_1.OPERATION.DELETE, callback);
157
+ };
146
158
  Schema.prototype.assign = function (props) {
147
159
  Object.assign(this, props);
148
160
  return this;
@@ -152,27 +164,35 @@ var Schema = /** @class */ (function () {
152
164
  enumerable: false,
153
165
  configurable: true
154
166
  });
167
+ /**
168
+ * (Server-side): Flag a property to be encoded for the next patch.
169
+ * @param instance Schema instance
170
+ * @param property string representing the property name, or number representing the index of the property.
171
+ * @param operation OPERATION to perform (detected automatically)
172
+ */
173
+ Schema.prototype.setDirty = function (property, operation) {
174
+ this.$changes.change(property, operation);
175
+ };
155
176
  Schema.prototype.listen = function (attr, callback) {
156
177
  var _this = this;
157
- if (!this.$listeners[attr]) {
158
- this.$listeners[attr] = new EventEmitter_1.EventEmitter();
178
+ if (!this.$callbacks) {
179
+ this.$callbacks = {};
180
+ }
181
+ if (!this.$callbacks[attr]) {
182
+ this.$callbacks[attr] = [];
159
183
  }
160
- this.$listeners[attr].register(callback);
184
+ this.$callbacks[attr].push(callback);
161
185
  // return un-register callback.
162
- return function () {
163
- return _this.$listeners[attr].remove(callback);
164
- };
186
+ return function () { return utils_1.spliceOne(_this.$callbacks[attr], _this.$callbacks[attr].indexOf(callback)); };
165
187
  };
166
- Schema.prototype.decode = function (bytes, it, ref, allChanges) {
188
+ Schema.prototype.decode = function (bytes, it, ref) {
167
189
  if (it === void 0) { it = { offset: 0 }; }
168
190
  if (ref === void 0) { ref = this; }
169
- if (allChanges === void 0) { allChanges = new Map(); }
191
+ var allChanges = [];
170
192
  var $root = this.$changes.root;
171
193
  var totalBytes = bytes.length;
172
194
  var refId = 0;
173
- var changes = [];
174
195
  $root.refs.set(refId, this);
175
- allChanges.set(refId, changes);
176
196
  while (it.offset < totalBytes) {
177
197
  var byte = bytes[it.offset++];
178
198
  if (byte == spec_1.SWITCH_TO_STRUCTURE) {
@@ -185,9 +205,6 @@ var Schema = /** @class */ (function () {
185
205
  throw new Error("\"refId\" not found: " + refId);
186
206
  }
187
207
  ref = nextRef;
188
- // create empty list of changes for this refId.
189
- changes = [];
190
- allChanges.set(refId, changes);
191
208
  continue;
192
209
  }
193
210
  var changeTree = ref['$changes'];
@@ -201,7 +218,7 @@ var Schema = /** @class */ (function () {
201
218
  // The `.clear()` method is calling `$root.removeRef(refId)` for
202
219
  // each item inside this collection
203
220
  //
204
- ref.clear(true);
221
+ ref.clear(allChanges);
205
222
  continue;
206
223
  }
207
224
  var fieldIndex = (isSchema)
@@ -276,9 +293,8 @@ var Schema = /** @class */ (function () {
276
293
  value = this.createTypeInstance(childType);
277
294
  value.$changes.refId = refId_1;
278
295
  if (previousValue) {
279
- value.onChange = previousValue.onChange;
280
- value.onRemove = previousValue.onRemove;
281
- value.$listeners = previousValue.$listeners;
296
+ value.$callbacks = previousValue.$callbacks;
297
+ // value.$listeners = previousValue.$listeners;
282
298
  if (previousValue['$changes'].refId &&
283
299
  refId_1 !== previousValue['$changes'].refId) {
284
300
  $root.removeRef(previousValue['$changes'].refId);
@@ -295,7 +311,7 @@ var Schema = /** @class */ (function () {
295
311
  value = decodePrimitiveType(type, bytes, it);
296
312
  }
297
313
  else {
298
- var typeDef = types_1.getType(Object.keys(type)[0]);
314
+ var typeDef = typeRegistry_1.getType(Object.keys(type)[0]);
299
315
  var refId_2 = decode.number(bytes, it);
300
316
  var valueRef = ($root.refs.has(refId_2))
301
317
  ? previousValue || $root.refs.get(refId_2)
@@ -304,40 +320,29 @@ var Schema = /** @class */ (function () {
304
320
  value.$changes.refId = refId_2;
305
321
  // preserve schema callbacks
306
322
  if (previousValue) {
307
- value.onAdd = previousValue.onAdd;
308
- value.onRemove = previousValue.onRemove;
309
- value.onChange = previousValue.onChange;
323
+ value['$callbacks'] = previousValue['$callbacks'];
310
324
  if (previousValue['$changes'].refId &&
311
325
  refId_2 !== previousValue['$changes'].refId) {
312
326
  $root.removeRef(previousValue['$changes'].refId);
313
327
  //
314
328
  // Trigger onRemove if structure has been replaced.
315
329
  //
316
- var deletes = [];
317
330
  var entries = previousValue.entries();
318
331
  var iter = void 0;
319
332
  while ((iter = entries.next()) && !iter.done) {
320
333
  var _a = __read(iter.value, 2), key = _a[0], value_1 = _a[1];
321
- deletes.push({
334
+ allChanges.push({
335
+ refId: refId_2,
322
336
  op: spec_1.OPERATION.DELETE,
323
337
  field: key,
324
338
  value: undefined,
325
339
  previousValue: value_1,
326
340
  });
327
341
  }
328
- allChanges.set(previousValue['$changes'].refId, deletes);
329
342
  }
330
343
  }
331
344
  $root.addRef(refId_2, value, (valueRef !== previousValue));
332
- //
333
- // TODO: deprecate proxies on next version.
334
- // get proxy to target value.
335
- //
336
- if (typeDef.getProxy) {
337
- value = typeDef.getProxy(value);
338
- }
339
345
  }
340
- var hasChange = (previousValue !== value);
341
346
  if (value !== null &&
342
347
  value !== undefined) {
343
348
  if (value['$changes']) {
@@ -345,14 +350,7 @@ var Schema = /** @class */ (function () {
345
350
  }
346
351
  if (ref instanceof Schema) {
347
352
  ref[fieldName] = value;
348
- //
349
- // FIXME: use `_field` instead of `field`.
350
- //
351
- // `field` is going to use the setter of the PropertyDescriptor
352
- // and create a proxy for array/map. This is only useful for
353
- // backwards-compatibility with @colyseus/schema@0.5.x
354
- //
355
- // // ref[_field] = value;
353
+ // ref[`_${fieldName}`] = value;
356
354
  }
357
355
  else if (ref instanceof MapSchema_1.MapSchema) {
358
356
  // const key = ref['$indexes'].get(field);
@@ -366,19 +364,20 @@ var Schema = /** @class */ (function () {
366
364
  // ref[key] = value;
367
365
  ref.setAt(fieldIndex, value);
368
366
  }
369
- else if (ref instanceof CollectionSchema_1.CollectionSchema ||
370
- ref instanceof SetSchema_1.SetSchema) {
367
+ else if (ref instanceof CollectionSchema_1.CollectionSchema) {
371
368
  var index = ref.add(value);
372
369
  ref['setIndex'](fieldIndex, index);
373
370
  }
371
+ else if (ref instanceof SetSchema_1.SetSchema) {
372
+ var index = ref.add(value);
373
+ if (index !== false) {
374
+ ref['setIndex'](fieldIndex, index);
375
+ }
376
+ }
374
377
  }
375
- if (hasChange
376
- // &&
377
- // (
378
- // this.onChange || ref.$listeners[field]
379
- // )
380
- ) {
381
- changes.push({
378
+ if (previousValue !== value) {
379
+ allChanges.push({
380
+ refId: refId,
382
381
  op: operation,
383
382
  field: fieldName,
384
383
  dynamicIndex: dynamicIndex,
@@ -506,7 +505,7 @@ var Schema = /** @class */ (function () {
506
505
  //
507
506
  // Custom type (MapSchema, ArraySchema, etc)
508
507
  //
509
- var definition = types_1.getType(Object.keys(type)[0]);
508
+ var definition = typeRegistry_1.getType(Object.keys(type)[0]);
510
509
  //
511
510
  // ensure a ArraySchema has been provided
512
511
  //
@@ -532,6 +531,7 @@ var Schema = /** @class */ (function () {
532
531
  return this.encode(true, [], useFilters);
533
532
  };
534
533
  Schema.prototype.applyFilters = function (client, encodeAll) {
534
+ var _a, _b;
535
535
  if (encodeAll === void 0) { encodeAll = false; }
536
536
  var root = this;
537
537
  var refIdsDissallowed = new Set();
@@ -651,7 +651,7 @@ var Schema = /** @class */ (function () {
651
651
  //
652
652
  // use cached bytes directly if is from Schema type.
653
653
  //
654
- filteredBytes = filteredBytes.concat(changeTree.caches[fieldIndex]);
654
+ filteredBytes.push.apply(filteredBytes, (_a = changeTree.caches[fieldIndex]) !== null && _a !== void 0 ? _a : []);
655
655
  containerIndexes.add(fieldIndex);
656
656
  }
657
657
  else {
@@ -659,7 +659,7 @@ var Schema = /** @class */ (function () {
659
659
  //
660
660
  // use cached bytes if already has the field
661
661
  //
662
- filteredBytes = filteredBytes.concat(changeTree.caches[fieldIndex]);
662
+ filteredBytes.push.apply(filteredBytes, (_b = changeTree.caches[fieldIndex]) !== null && _b !== void 0 ? _b : []);
663
663
  }
664
664
  else {
665
665
  //
@@ -728,20 +728,6 @@ var Schema = /** @class */ (function () {
728
728
  }
729
729
  return cloned;
730
730
  };
731
- Schema.prototype.triggerAll = function () {
732
- // skip if haven't received any remote refs yet.
733
- if (this.$changes.root.refs.size === 0) {
734
- return;
735
- }
736
- var allChanges = new Map();
737
- Schema.prototype._triggerAllFillChanges.call(this, this, allChanges);
738
- try {
739
- Schema.prototype._triggerChanges.call(this, allChanges);
740
- }
741
- catch (e) {
742
- Schema.onError(e);
743
- }
744
- };
745
731
  Schema.prototype.toJSON = function () {
746
732
  var schema = this._definition.schema;
747
733
  var deprecated = this._definition.deprecated;
@@ -784,111 +770,81 @@ var Schema = /** @class */ (function () {
784
770
  instance.$changes.root = this.$changes.root;
785
771
  return instance;
786
772
  };
787
- Schema.prototype._triggerAllFillChanges = function (ref, allChanges) {
788
- if (allChanges.has(ref['$changes'].refId)) {
789
- return;
790
- }
791
- var changes = [];
792
- allChanges.set(ref['$changes'].refId || 0, changes);
793
- if (ref instanceof Schema) {
794
- var schema = ref._definition.schema;
795
- for (var fieldName in schema) {
796
- var _field = "_" + fieldName;
797
- var value = ref[_field];
798
- if (value !== undefined) {
799
- changes.push({
800
- op: spec_1.OPERATION.ADD,
801
- field: fieldName,
802
- value: value,
803
- previousValue: undefined
804
- });
805
- if (value['$changes'] !== undefined) {
806
- Schema.prototype._triggerAllFillChanges.call(this, value, allChanges);
773
+ Schema.prototype._triggerChanges = function (changes) {
774
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
775
+ var uniqueRefIds = new Set();
776
+ var $refs = this.$changes.root.refs;
777
+ var _loop_2 = function (i) {
778
+ var change = changes[i];
779
+ var refId = change.refId;
780
+ var ref = $refs.get(refId);
781
+ var $callbacks = ref['$callbacks'];
782
+ //
783
+ // trigger onRemove on child structure.
784
+ //
785
+ if ((change.op & spec_1.OPERATION.DELETE) === spec_1.OPERATION.DELETE &&
786
+ change.previousValue instanceof Schema) {
787
+ (_b = (_a = change.previousValue['$callbacks']) === null || _a === void 0 ? void 0 : _a[spec_1.OPERATION.DELETE]) === null || _b === void 0 ? void 0 : _b.forEach(function (callback) { return callback(); });
788
+ }
789
+ // no callbacks defined, skip this structure!
790
+ if (!$callbacks) {
791
+ return "continue";
792
+ }
793
+ if (ref instanceof Schema) {
794
+ if (!uniqueRefIds.has(refId)) {
795
+ try {
796
+ // trigger onChange
797
+ (_d = (_c = $callbacks) === null || _c === void 0 ? void 0 : _c[spec_1.OPERATION.REPLACE]) === null || _d === void 0 ? void 0 : _d.forEach(function (callback) {
798
+ return callback(changes);
799
+ });
800
+ }
801
+ catch (e) {
802
+ Schema.onError(e);
807
803
  }
808
804
  }
809
- }
810
- }
811
- else {
812
- var entries = ref.entries();
813
- var iter = void 0;
814
- while ((iter = entries.next()) && !iter.done) {
815
- var _a = __read(iter.value, 2), key = _a[0], value = _a[1];
816
- changes.push({
817
- op: spec_1.OPERATION.ADD,
818
- field: key,
819
- dynamicIndex: key,
820
- value: value,
821
- previousValue: undefined,
822
- });
823
- if (value['$changes'] !== undefined) {
824
- Schema.prototype._triggerAllFillChanges.call(this, value, allChanges);
805
+ try {
806
+ (_e = $callbacks[change.op]) === null || _e === void 0 ? void 0 : _e.forEach(function (callback) {
807
+ return callback(change.value, change.previousValue);
808
+ });
809
+ }
810
+ catch (e) {
811
+ Schema.onError(e);
825
812
  }
826
813
  }
827
- }
828
- };
829
- Schema.prototype._triggerChanges = function (allChanges) {
830
- var _this = this;
831
- allChanges.forEach(function (changes, refId) {
832
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
833
- if (changes.length > 0) {
834
- var ref = _this.$changes.root.refs.get(refId);
835
- var isSchema = ref instanceof Schema;
836
- for (var i = 0; i < changes.length; i++) {
837
- var change = changes[i];
838
- var listener = ref['$listeners'] && ref['$listeners'][change.field];
839
- if (!isSchema) {
840
- if (change.op === spec_1.OPERATION.ADD && change.previousValue === undefined) {
841
- (_b = (_a = ref).onAdd) === null || _b === void 0 ? void 0 : _b.call(_a, change.value, (_c = change.dynamicIndex) !== null && _c !== void 0 ? _c : change.field);
842
- }
843
- else if (change.op === spec_1.OPERATION.DELETE) {
844
- //
845
- // FIXME: `previousValue` should always be avaiiable.
846
- // ADD + DELETE operations are still encoding DELETE operation.
847
- //
848
- if (change.previousValue !== undefined) {
849
- (_e = (_d = ref).onRemove) === null || _e === void 0 ? void 0 : _e.call(_d, change.previousValue, (_f = change.dynamicIndex) !== null && _f !== void 0 ? _f : change.field);
850
- }
851
- }
852
- else if (change.op === spec_1.OPERATION.DELETE_AND_ADD) {
853
- if (change.previousValue !== undefined) {
854
- (_h = (_g = ref).onRemove) === null || _h === void 0 ? void 0 : _h.call(_g, change.previousValue, change.dynamicIndex);
855
- }
856
- (_k = (_j = ref).onAdd) === null || _k === void 0 ? void 0 : _k.call(_j, change.value, change.dynamicIndex);
857
- }
858
- else if (change.op === spec_1.OPERATION.REPLACE ||
859
- change.value !== change.previousValue) {
860
- (_m = (_l = ref).onChange) === null || _m === void 0 ? void 0 : _m.call(_l, change.value, change.dynamicIndex);
861
- }
862
- }
814
+ else {
815
+ // is a collection of items
816
+ if (change.op === spec_1.OPERATION.ADD && change.previousValue === undefined) {
817
+ // triger onAdd
818
+ (_f = $callbacks[spec_1.OPERATION.ADD]) === null || _f === void 0 ? void 0 : _f.forEach(function (callback) { var _a; return callback(change.value, (_a = change.dynamicIndex) !== null && _a !== void 0 ? _a : change.field); });
819
+ }
820
+ else if (change.op === spec_1.OPERATION.DELETE) {
863
821
  //
864
- // trigger onRemove on child structure.
822
+ // FIXME: `previousValue` should always be available.
823
+ // ADD + DELETE operations are still encoding DELETE operation.
865
824
  //
866
- if ((change.op & spec_1.OPERATION.DELETE) === spec_1.OPERATION.DELETE &&
867
- change.previousValue instanceof Schema &&
868
- change.previousValue.onRemove) {
869
- change.previousValue.onRemove();
870
- }
871
- if (listener) {
872
- try {
873
- listener.invoke(change.value, change.previousValue);
874
- }
875
- catch (e) {
876
- Schema.onError(e);
877
- }
825
+ if (change.previousValue !== undefined) {
826
+ // triger onRemove
827
+ (_g = $callbacks[spec_1.OPERATION.DELETE]) === null || _g === void 0 ? void 0 : _g.forEach(function (callback) { var _a; return callback(change.previousValue, (_a = change.dynamicIndex) !== null && _a !== void 0 ? _a : change.field); });
878
828
  }
879
829
  }
880
- if (isSchema) {
881
- if (ref.onChange) {
882
- try {
883
- ref.onChange(changes);
884
- }
885
- catch (e) {
886
- Schema.onError(e);
887
- }
830
+ else if (change.op === spec_1.OPERATION.DELETE_AND_ADD) {
831
+ // triger onRemove
832
+ if (change.previousValue !== undefined) {
833
+ (_h = $callbacks[spec_1.OPERATION.DELETE]) === null || _h === void 0 ? void 0 : _h.forEach(function (callback) { var _a; return callback(change.previousValue, (_a = change.dynamicIndex) !== null && _a !== void 0 ? _a : change.field); });
888
834
  }
835
+ // triger onAdd
836
+ (_j = $callbacks[spec_1.OPERATION.ADD]) === null || _j === void 0 ? void 0 : _j.forEach(function (callback) { var _a; return callback(change.value, (_a = change.dynamicIndex) !== null && _a !== void 0 ? _a : change.field); });
837
+ }
838
+ // trigger onChange
839
+ if (change.value !== change.previousValue) {
840
+ (_k = $callbacks[spec_1.OPERATION.REPLACE]) === null || _k === void 0 ? void 0 : _k.forEach(function (callback) { var _a; return callback(change.value, (_a = change.dynamicIndex) !== null && _a !== void 0 ? _a : change.field); });
889
841
  }
890
842
  }
891
- });
843
+ uniqueRefIds.add(refId);
844
+ };
845
+ for (var i = 0; i < changes.length; i++) {
846
+ _loop_2(i);
847
+ }
892
848
  };
893
849
  Schema._definition = annotations_1.SchemaDefinition.create();
894
850
  return Schema;