@colyseus/schema 3.0.0-alpha.37 → 3.0.0-alpha.39

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 (45) hide show
  1. package/build/cjs/index.js +142 -32
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/esm/index.mjs +142 -33
  4. package/build/esm/index.mjs.map +1 -1
  5. package/build/umd/index.js +142 -32
  6. package/lib/Metadata.d.ts +3 -2
  7. package/lib/Metadata.js +57 -15
  8. package/lib/Metadata.js.map +1 -1
  9. package/lib/Reflection.d.ts +4 -3
  10. package/lib/Reflection.js +36 -11
  11. package/lib/Reflection.js.map +1 -1
  12. package/lib/Schema.d.ts +2 -2
  13. package/lib/Schema.js.map +1 -1
  14. package/lib/annotations.d.ts +29 -12
  15. package/lib/annotations.js +36 -3
  16. package/lib/annotations.js.map +1 -1
  17. package/lib/codegen/parser.js +83 -0
  18. package/lib/codegen/parser.js.map +1 -1
  19. package/lib/codegen/types.js +3 -0
  20. package/lib/codegen/types.js.map +1 -1
  21. package/lib/decoder/DecodeOperation.js +4 -0
  22. package/lib/decoder/DecodeOperation.js.map +1 -1
  23. package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
  24. package/lib/encoder/EncodeOperation.js +2 -2
  25. package/lib/encoder/EncodeOperation.js.map +1 -1
  26. package/lib/index.d.ts +1 -1
  27. package/lib/index.js +2 -1
  28. package/lib/index.js.map +1 -1
  29. package/lib/types/HelperTypes.d.ts +34 -2
  30. package/lib/types/HelperTypes.js.map +1 -1
  31. package/lib/types/TypeContext.js +9 -1
  32. package/lib/types/TypeContext.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/Metadata.ts +62 -16
  35. package/src/Reflection.ts +43 -16
  36. package/src/Schema.ts +2 -3
  37. package/src/annotations.ts +68 -18
  38. package/src/codegen/parser.ts +107 -0
  39. package/src/codegen/types.ts +1 -0
  40. package/src/decoder/DecodeOperation.ts +4 -0
  41. package/src/decoder/strategy/StateCallbacks.ts +1 -1
  42. package/src/encoder/EncodeOperation.ts +4 -2
  43. package/src/index.ts +1 -1
  44. package/src/types/HelperTypes.ts +54 -2
  45. package/src/types/TypeContext.ts +11 -1
@@ -115,7 +115,7 @@ class TypeContext {
115
115
  // Workaround to allow using an empty Schema (with no `@type()` fields)
116
116
  //
117
117
  if (schema[Symbol.metadata] === undefined) {
118
- Metadata.init(schema);
118
+ Metadata.initialize(schema);
119
119
  }
120
120
  this.schemas.set(schema, typeid);
121
121
  return true;
@@ -131,6 +131,14 @@ class TypeContext {
131
131
  TypeContext.inheritedTypes.get(klass)?.forEach((child) => {
132
132
  this.discoverTypes(child, parentIndex, parentFieldViewTag);
133
133
  });
134
+ // add parent classes
135
+ let parent = klass;
136
+ while ((parent = Object.getPrototypeOf(parent)) &&
137
+ parent !== Schema && // stop at root (Schema)
138
+ parent !== Function.prototype // stop at root (non-Schema)
139
+ ) {
140
+ this.discoverTypes(parent);
141
+ }
134
142
  const metadata = (klass[Symbol.metadata] ??= {});
135
143
  // if any schema/field has filters, mark "context" as having filters.
136
144
  if (metadata[$viewFieldIndexes]) {
@@ -169,6 +177,13 @@ class TypeContext {
169
177
  }
170
178
  }
171
179
 
180
+ function getNormalizedType(type) {
181
+ return (Array.isArray(type))
182
+ ? { array: type[0] }
183
+ : (typeof (type['type']) !== "undefined")
184
+ ? type['type']
185
+ : type;
186
+ }
172
187
  const Metadata = {
173
188
  addField(metadata, index, name, type, descriptor) {
174
189
  if (index > 64) {
@@ -176,14 +191,16 @@ const Metadata = {
176
191
  }
177
192
  metadata[index] = Object.assign(metadata[index] || {}, // avoid overwriting previous field metadata (@owned / @deprecated)
178
193
  {
179
- type: (Array.isArray(type))
180
- ? { array: type[0] }
181
- : type,
194
+ type: getNormalizedType(type),
182
195
  index,
183
196
  name,
184
197
  });
185
198
  // create "descriptors" map
186
- metadata[$descriptors] ??= {};
199
+ Object.defineProperty(metadata, $descriptors, {
200
+ value: metadata[$descriptors] || {},
201
+ enumerable: false,
202
+ configurable: true,
203
+ });
187
204
  if (descriptor) {
188
205
  // for encoder
189
206
  metadata[$descriptors][name] = descriptor;
@@ -258,7 +275,7 @@ const Metadata = {
258
275
  TypeContext.register(constructor);
259
276
  const parentClass = Object.getPrototypeOf(constructor);
260
277
  const parentMetadata = parentClass && parentClass[Symbol.metadata];
261
- const metadata = Metadata.initialize(constructor, parentMetadata);
278
+ const metadata = Metadata.initialize(constructor);
262
279
  // Use Schema's methods if not defined in the class
263
280
  if (!constructor[$track]) {
264
281
  constructor[$track] = Schema[$track];
@@ -281,11 +298,15 @@ const Metadata = {
281
298
  fieldIndex++;
282
299
  for (const field in fields) {
283
300
  const type = fields[field];
301
+ const normalizedType = getNormalizedType(type);
284
302
  // FIXME: this code is duplicated from @type() annotation
285
303
  const complexTypeKlass = (Array.isArray(type))
286
304
  ? getType("array")
287
305
  : (typeof (Object.keys(type)[0]) === "string") && getType(Object.keys(type)[0]);
288
- Metadata.addField(metadata, fieldIndex, field, type, getPropertyDescriptor(`_${field}`, fieldIndex, type, complexTypeKlass));
306
+ const childType = (complexTypeKlass)
307
+ ? Object.values(type)[0]
308
+ : normalizedType;
309
+ Metadata.addField(metadata, fieldIndex, field, type, getPropertyDescriptor(`_${field}`, fieldIndex, childType, complexTypeKlass));
289
310
  fieldIndex++;
290
311
  }
291
312
  return target;
@@ -306,24 +327,52 @@ const Metadata = {
306
327
  configurable: true,
307
328
  });
308
329
  },
309
- initialize(constructor, parentMetadata) {
330
+ initialize(constructor) {
331
+ const parentClass = Object.getPrototypeOf(constructor);
332
+ const parentMetadata = parentClass[Symbol.metadata];
310
333
  let metadata = constructor[Symbol.metadata] ?? Object.create(null);
311
334
  // make sure inherited classes have their own metadata object.
312
- if (constructor[Symbol.metadata] === parentMetadata) {
335
+ if (parentClass !== Schema && metadata === parentMetadata) {
313
336
  metadata = Object.create(null);
314
337
  if (parentMetadata) {
338
+ //
315
339
  // assign parent metadata to current
316
- Object.assign(metadata, parentMetadata);
317
- for (let i = 0; i <= parentMetadata[$numFields]; i++) {
318
- const fieldName = parentMetadata[i].name;
319
- Object.defineProperty(metadata, fieldName, {
320
- value: parentMetadata[fieldName],
340
+ //
341
+ Object.setPrototypeOf(metadata, parentMetadata);
342
+ // $numFields
343
+ Object.defineProperty(metadata, $numFields, {
344
+ value: parentMetadata[$numFields],
345
+ enumerable: false,
346
+ configurable: true,
347
+ writable: true,
348
+ });
349
+ // $viewFieldIndexes / $fieldIndexesByViewTag
350
+ if (parentMetadata[$viewFieldIndexes] !== undefined) {
351
+ Object.defineProperty(metadata, $viewFieldIndexes, {
352
+ value: [...parentMetadata[$viewFieldIndexes]],
321
353
  enumerable: false,
322
354
  configurable: true,
355
+ writable: true,
356
+ });
357
+ Object.defineProperty(metadata, $fieldIndexesByViewTag, {
358
+ value: { ...parentMetadata[$fieldIndexesByViewTag] },
359
+ enumerable: false,
360
+ configurable: true,
361
+ writable: true,
323
362
  });
324
363
  }
325
- Object.defineProperty(metadata, $numFields, {
326
- value: parentMetadata[$numFields],
364
+ // $refTypeFieldIndexes
365
+ if (parentMetadata[$refTypeFieldIndexes] !== undefined) {
366
+ Object.defineProperty(metadata, $refTypeFieldIndexes, {
367
+ value: [...parentMetadata[$refTypeFieldIndexes]],
368
+ enumerable: false,
369
+ configurable: true,
370
+ writable: true,
371
+ });
372
+ }
373
+ // $descriptors
374
+ Object.defineProperty(metadata, $descriptors, {
375
+ value: { ...parentMetadata[$descriptors] },
327
376
  enumerable: false,
328
377
  configurable: true,
329
378
  writable: true,
@@ -1098,7 +1147,6 @@ const encodeSchemaOperation = function (encoder, bytes, changeTree, index, opera
1098
1147
  return;
1099
1148
  }
1100
1149
  const ref = changeTree.ref;
1101
- // const metadata: Metadata = ref.constructor[Symbol.metadata];
1102
1150
  const field = metadata[index];
1103
1151
  // TODO: inline this function call small performance gain
1104
1152
  encodeValue(encoder, bytes, metadata[index].type, ref[field.name], operation, it);
@@ -1173,7 +1221,8 @@ const encodeArray = function (encoder, bytes, changeTree, field, operation, it,
1173
1221
  // encode operation
1174
1222
  bytes[it.offset++] = operation & 255;
1175
1223
  // custom operations
1176
- if (operation === exports.OPERATION.CLEAR) {
1224
+ if (operation === exports.OPERATION.CLEAR ||
1225
+ operation === exports.OPERATION.REVERSE) {
1177
1226
  return;
1178
1227
  }
1179
1228
  // encode index
@@ -1651,6 +1700,10 @@ const decodeArray = function (decoder, bytes, it, ref, allChanges) {
1651
1700
  ref.clear();
1652
1701
  return;
1653
1702
  }
1703
+ else if (operation === exports.OPERATION.REVERSE) {
1704
+ ref.reverse();
1705
+ return;
1706
+ }
1654
1707
  else if (operation === exports.OPERATION.DELETE_BY_REFID) {
1655
1708
  // TODO: refactor here, try to follow same flow as below
1656
1709
  const refId = number(bytes, it);
@@ -2770,13 +2823,13 @@ function type(type, options) {
2770
2823
  // for inheritance support
2771
2824
  TypeContext.register(constructor);
2772
2825
  const parentClass = Object.getPrototypeOf(constructor);
2773
- const parentMetadata = parentClass && parentClass[Symbol.metadata];
2774
- const metadata = Metadata.initialize(constructor, parentMetadata);
2826
+ const parentMetadata = parentClass[Symbol.metadata];
2827
+ const metadata = Metadata.initialize(constructor);
2775
2828
  let fieldIndex = metadata[field];
2776
2829
  /**
2777
2830
  * skip if descriptor already exists for this field (`@deprecated()`)
2778
2831
  */
2779
- if (metadata[fieldIndex]) {
2832
+ if (metadata[fieldIndex] !== undefined) {
2780
2833
  if (metadata[fieldIndex].deprecated) {
2781
2834
  // do not create accessors for deprecated properties.
2782
2835
  return;
@@ -2926,6 +2979,37 @@ function defineTypes(target, fields, options) {
2926
2979
  }
2927
2980
  return target;
2928
2981
  }
2982
+ function schema(fields, name, inherits = Schema) {
2983
+ const defaultValues = {};
2984
+ const viewTagFields = {};
2985
+ for (let fieldName in fields) {
2986
+ const field = fields[fieldName];
2987
+ if (typeof (field) === "object") {
2988
+ if (field['default'] !== undefined) {
2989
+ defaultValues[fieldName] = field['default'];
2990
+ }
2991
+ if (field['view'] !== undefined) {
2992
+ viewTagFields[fieldName] = (typeof (field['view']) === "boolean")
2993
+ ? DEFAULT_VIEW_TAG
2994
+ : field['view'];
2995
+ }
2996
+ }
2997
+ }
2998
+ const klass = Metadata.setFields(class extends inherits {
2999
+ constructor(...args) {
3000
+ args[0] = Object.assign({}, defaultValues, args[0]);
3001
+ super(...args);
3002
+ }
3003
+ }, fields);
3004
+ for (let fieldName in viewTagFields) {
3005
+ view(viewTagFields[fieldName])(klass.prototype, fieldName);
3006
+ }
3007
+ if (name) {
3008
+ Object.defineProperty(klass, "name", { value: name });
3009
+ }
3010
+ klass.extends = (fields, name) => schema(fields, name, klass);
3011
+ return klass;
3012
+ }
2929
3013
 
2930
3014
  function getIndent(level) {
2931
3015
  return (new Array(level).fill(0)).map((_, i) => (i === level - 1) ? `└─ ` : ` `).join("");
@@ -4173,13 +4257,20 @@ class Reflection extends Schema {
4173
4257
  /**
4174
4258
  * Encodes the TypeContext of an Encoder into a buffer.
4175
4259
  *
4176
- * @param context TypeContext instance
4260
+ * @param encoder Encoder instance
4177
4261
  * @param it
4178
4262
  * @returns
4179
4263
  */
4180
- static encode(context, it = { offset: 0 }) {
4264
+ static encode(encoder, it = { offset: 0 }) {
4265
+ const context = encoder.context;
4181
4266
  const reflection = new Reflection();
4182
4267
  const reflectionEncoder = new Encoder(reflection);
4268
+ // rootType is usually the first schema passed to the Encoder
4269
+ // (unless it inherits from another schema)
4270
+ const rootType = context.schemas.get(encoder.state.constructor);
4271
+ if (rootType > 0) {
4272
+ reflection.rootType = rootType;
4273
+ }
4183
4274
  const buildType = (currentType, metadata) => {
4184
4275
  for (const fieldIndex in metadata) {
4185
4276
  const index = Number(fieldIndex);
@@ -4253,18 +4344,14 @@ class Reflection extends Schema {
4253
4344
  const parentClass = typeContext.get(reflectionType.extendsId) ?? Schema;
4254
4345
  const schema = class _ extends parentClass {
4255
4346
  };
4256
- const parentMetadata = parentClass[Symbol.metadata];
4257
4347
  // register for inheritance support
4258
4348
  TypeContext.register(schema);
4259
- // for inheritance support
4260
- Metadata.initialize(schema, parentMetadata);
4349
+ // // for inheritance support
4350
+ // Metadata.initialize(schema);
4261
4351
  typeContext.add(schema, reflectionType.id);
4262
4352
  }, {});
4263
- // 2nd pass, set fields
4264
- reflection.types.forEach((reflectionType) => {
4265
- const schemaType = typeContext.get(reflectionType.id);
4266
- const metadata = schemaType[Symbol.metadata];
4267
- const parentFieldIndex = 0;
4353
+ // define fields
4354
+ const addFields = (metadata, reflectionType, parentFieldIndex) => {
4268
4355
  reflectionType.fields.forEach((field, i) => {
4269
4356
  const fieldIndex = parentFieldIndex + i;
4270
4357
  if (field.referencedType !== undefined) {
@@ -4287,14 +4374,36 @@ class Reflection extends Schema {
4287
4374
  Metadata.addField(metadata, fieldIndex, field.name, field.type);
4288
4375
  }
4289
4376
  });
4377
+ };
4378
+ // 2nd pass, set fields
4379
+ reflection.types.forEach((reflectionType) => {
4380
+ const schema = typeContext.get(reflectionType.id);
4381
+ // for inheritance support
4382
+ const metadata = Metadata.initialize(schema);
4383
+ const inheritedTypes = [];
4384
+ let parentType = reflectionType;
4385
+ do {
4386
+ inheritedTypes.push(parentType);
4387
+ parentType = reflection.types.find((t) => t.id === parentType.extendsId);
4388
+ } while (parentType);
4389
+ let parentFieldIndex = 0;
4390
+ inheritedTypes.reverse().forEach((reflectionType) => {
4391
+ // add fields from all inherited classes
4392
+ // TODO: refactor this to avoid adding fields from parent classes
4393
+ addFields(metadata, reflectionType, parentFieldIndex);
4394
+ parentFieldIndex += reflectionType.fields.length;
4395
+ });
4290
4396
  });
4291
- const state = new (typeContext.get(0))();
4397
+ const state = new (typeContext.get(reflection.rootType || 0))();
4292
4398
  return new Decoder(state, typeContext);
4293
4399
  }
4294
4400
  }
4295
4401
  __decorate([
4296
4402
  type([ReflectionType])
4297
4403
  ], Reflection.prototype, "types", void 0);
4404
+ __decorate([
4405
+ type("number")
4406
+ ], Reflection.prototype, "rootType", void 0);
4298
4407
 
4299
4408
  function getDecoderStateCallbacks(decoder) {
4300
4409
  const $root = decoder.root;
@@ -4767,6 +4876,7 @@ exports.encodeSchemaOperation = encodeSchemaOperation;
4767
4876
  exports.getDecoderStateCallbacks = getDecoderStateCallbacks;
4768
4877
  exports.getRawChangesCallback = getRawChangesCallback;
4769
4878
  exports.registerType = registerType;
4879
+ exports.schema = schema;
4770
4880
  exports.type = type;
4771
4881
  exports.view = view;
4772
4882
  //# sourceMappingURL=index.js.map