@colyseus/schema 3.0.0-alpha.13 → 3.0.0-alpha.15

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.
@@ -3994,29 +3994,26 @@
3994
3994
  // Handle schema instance
3995
3995
  //
3996
3996
  if (!uniqueRefIds.has(refId)) {
3997
- try {
3998
- // trigger onChange
3999
- const replaceCallbacks = $callbacks?.[exports.OPERATION.REPLACE];
4000
- for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {
4001
- replaceCallbacks[i]();
4002
- }
4003
- }
4004
- catch (e) {
4005
- console.error(e);
3997
+ // trigger onChange
3998
+ const replaceCallbacks = $callbacks?.[exports.OPERATION.REPLACE];
3999
+ for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {
4000
+ replaceCallbacks[i]();
4001
+ // try {
4002
+ // } catch (e) {
4003
+ // console.error(e);
4004
+ // }
4006
4005
  }
4007
4006
  }
4008
- try {
4009
- if ($callbacks.hasOwnProperty(change.field)) {
4010
- const fieldCallbacks = $callbacks[change.field];
4011
- for (let i = fieldCallbacks?.length - 1; i >= 0; i--) {
4012
- fieldCallbacks[i](change.value, change.previousValue);
4013
- }
4007
+ if ($callbacks.hasOwnProperty(change.field)) {
4008
+ const fieldCallbacks = $callbacks[change.field];
4009
+ for (let i = fieldCallbacks?.length - 1; i >= 0; i--) {
4010
+ fieldCallbacks[i](change.value, change.previousValue);
4011
+ // try {
4012
+ // } catch (e) {
4013
+ // console.error(e);
4014
+ // }
4014
4015
  }
4015
4016
  }
4016
- catch (e) {
4017
- //
4018
- console.error(e);
4019
- }
4020
4017
  }
4021
4018
  else {
4022
4019
  //
@@ -4094,12 +4091,15 @@
4094
4091
  return $root.addCallback($root.refIds.get(context.instance), exports.OPERATION.REPLACE, callback);
4095
4092
  },
4096
4093
  bindTo: function bindTo(targetObject, properties) {
4097
- // return $root.addCallback(
4098
- // $root.refIds.get(context.instance),
4099
- // OPERATION.BIND,
4100
- // callback
4101
- // );
4102
- console.log("bindTo", targetObject, properties);
4094
+ //
4095
+ // TODO: refactor this implementation. There is room for improvement here.
4096
+ //
4097
+ if (!properties) {
4098
+ properties = Object.keys(metadata);
4099
+ }
4100
+ return $root.addCallback($root.refIds.get(context.instance), exports.OPERATION.REPLACE, () => {
4101
+ properties.forEach((prop) => targetObject[prop] = context.instance[prop]);
4102
+ });
4103
4103
  }
4104
4104
  }, {
4105
4105
  get(target, prop) {
@@ -4190,7 +4190,7 @@
4190
4190
  function $(instance) {
4191
4191
  return getProxy(undefined, { instance });
4192
4192
  }
4193
- return $(decoder.state);
4193
+ return $;
4194
4194
  }
4195
4195
 
4196
4196
  function getRawChangesCallback(decoder, callback) {
@@ -1,17 +1,49 @@
1
1
  import { Collection, NonFunctionNonPrimitivePropNames, NonFunctionPropNames } from "../../types/HelperTypes";
2
2
  import { Decoder } from "../Decoder";
3
3
  import { Schema } from "../../Schema";
4
+ export type GetCallbackProxy = (<T extends Schema>(instance: T) => CallbackProxy<T>);
4
5
  export type CallbackProxy<T> = unknown extends T ? InstanceCallback<T> & CollectionCallback<any, any> : T extends Collection<infer K, infer V, infer _> ? CollectionCallback<K, V> : InstanceCallback<T>;
5
6
  type InstanceCallback<T> = {
7
+ /**
8
+ * Trigger callback when value of a property changes.
9
+ *
10
+ * @param prop name of the property
11
+ * @param callback callback to be triggered on property change
12
+ * @param immediate trigger immediatelly if property has been already set.
13
+ */
6
14
  listen<K extends NonFunctionPropNames<T>>(prop: K, callback: (value: T[K], previousValue: T[K]) => void, immediate?: boolean): any;
15
+ /**
16
+ * Trigger callback whenever any property changed within this instance.
17
+ *
18
+ * @param prop name of the property
19
+ * @param callback callback to be triggered on property change
20
+ * @param immediate trigger immediatelly if property has been already set.
21
+ */
7
22
  onChange(callback: () => void): void;
23
+ /**
24
+ * Bind properties to another object. Changes on the properties will be reflected on the target object.
25
+ *
26
+ * @param targetObject object to bind properties to
27
+ * @param properties list of properties to bind. If not provided, all properties will be bound.
28
+ */
8
29
  bindTo(targetObject: any, properties?: Array<NonFunctionPropNames<T>>): void;
9
30
  } & {
10
31
  [K in NonFunctionNonPrimitivePropNames<T>]: CallbackProxy<T[K]>;
11
32
  };
12
33
  type CollectionCallback<K, V> = {
34
+ /**
35
+ * Trigger callback when an item has been added to the collection.
36
+ *
37
+ * @param callback
38
+ * @param immediate
39
+ */
13
40
  onAdd(callback: (item: V, index: K) => void, immediate?: boolean): void;
41
+ /**
42
+ * Trigger callback when an item has been removed to the collection.
43
+ *
44
+ * @param callback
45
+ */
14
46
  onRemove(callback: (item: V, index: K) => void): void;
15
47
  };
16
- export declare function getStateCallbacks<T extends Schema>(decoder: Decoder<T>): CallbackProxy<T>;
48
+ export declare function getStateCallbacks<T extends Schema>(decoder: Decoder<T>): GetCallbackProxy;
17
49
  export {};
@@ -32,29 +32,26 @@ function getStateCallbacks(decoder) {
32
32
  // Handle schema instance
33
33
  //
34
34
  if (!uniqueRefIds.has(refId)) {
35
- try {
36
- // trigger onChange
37
- const replaceCallbacks = $callbacks?.[spec_1.OPERATION.REPLACE];
38
- for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {
39
- replaceCallbacks[i]();
40
- }
41
- }
42
- catch (e) {
43
- console.error(e);
35
+ // trigger onChange
36
+ const replaceCallbacks = $callbacks?.[spec_1.OPERATION.REPLACE];
37
+ for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {
38
+ replaceCallbacks[i]();
39
+ // try {
40
+ // } catch (e) {
41
+ // console.error(e);
42
+ // }
44
43
  }
45
44
  }
46
- try {
47
- if ($callbacks.hasOwnProperty(change.field)) {
48
- const fieldCallbacks = $callbacks[change.field];
49
- for (let i = fieldCallbacks?.length - 1; i >= 0; i--) {
50
- fieldCallbacks[i](change.value, change.previousValue);
51
- }
45
+ if ($callbacks.hasOwnProperty(change.field)) {
46
+ const fieldCallbacks = $callbacks[change.field];
47
+ for (let i = fieldCallbacks?.length - 1; i >= 0; i--) {
48
+ fieldCallbacks[i](change.value, change.previousValue);
49
+ // try {
50
+ // } catch (e) {
51
+ // console.error(e);
52
+ // }
52
53
  }
53
54
  }
54
- catch (e) {
55
- //
56
- console.error(e);
57
- }
58
55
  }
59
56
  else {
60
57
  //
@@ -132,12 +129,15 @@ function getStateCallbacks(decoder) {
132
129
  return $root.addCallback($root.refIds.get(context.instance), spec_1.OPERATION.REPLACE, callback);
133
130
  },
134
131
  bindTo: function bindTo(targetObject, properties) {
135
- // return $root.addCallback(
136
- // $root.refIds.get(context.instance),
137
- // OPERATION.BIND,
138
- // callback
139
- // );
140
- console.log("bindTo", targetObject, properties);
132
+ //
133
+ // TODO: refactor this implementation. There is room for improvement here.
134
+ //
135
+ if (!properties) {
136
+ properties = Object.keys(metadata);
137
+ }
138
+ return $root.addCallback($root.refIds.get(context.instance), spec_1.OPERATION.REPLACE, () => {
139
+ properties.forEach((prop) => targetObject[prop] = context.instance[prop]);
140
+ });
141
141
  }
142
142
  }, {
143
143
  get(target, prop) {
@@ -228,7 +228,7 @@ function getStateCallbacks(decoder) {
228
228
  function $(instance) {
229
229
  return getProxy(undefined, { instance });
230
230
  }
231
- return $(decoder.state);
231
+ return $;
232
232
  }
233
233
  exports.getStateCallbacks = getStateCallbacks;
234
234
  //# sourceMappingURL=StateCallbacks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StateCallbacks.js","sourceRoot":"","sources":["../../../src/decoder/strategy/StateCallbacks.ts"],"names":[],"mappings":"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","sourcesContent":["import { Metadata } from \"../../Metadata\";\nimport { Collection, NonFunctionNonPrimitivePropNames, NonFunctionPropNames } from \"../../types/HelperTypes\";\nimport { Ref } from \"../../encoder/ChangeTree\";\nimport { Decoder } from \"../Decoder\";\nimport { DataChange } from \"../DecodeOperation\";\nimport { OPERATION } from \"../../encoding/spec\";\nimport { DefinitionType } from \"../../annotations\";\nimport { Schema } from \"../../Schema\";\nimport type { ArraySchema } from \"../../types/custom/ArraySchema\";\n\n//\n// Discussion: https://github.com/colyseus/schema/issues/155\n//\n// Main points:\n// - Decouple structures from their callbacks.\n// - Registering deep callbacks can be confusing.\n// - Avoid closures by allowing to pass a context. (https://github.com/colyseus/schema/issues/155#issuecomment-1804694081)\n//\n\nexport type CallbackProxy<T> = unknown extends T // is \"any\"?\n ? InstanceCallback<T> & CollectionCallback<any, any>\n : T extends Collection<infer K, infer V, infer _>\n ? CollectionCallback<K, V>\n : InstanceCallback<T>\n\ntype InstanceCallback<T> = {\n listen<K extends NonFunctionPropNames<T>>(\n prop: K,\n callback: (value: T[K], previousValue: T[K]) => void,\n immediate?: boolean,\n )\n onChange(callback: () => void): void;\n bindTo(targetObject: any, properties?: Array<NonFunctionPropNames<T>>): void;\n} & {\n [K in NonFunctionNonPrimitivePropNames<T>]: CallbackProxy<T[K]>;\n}\n\ntype CollectionCallback<K, V> = {\n onAdd(callback: (item: V, index: K) => void, immediate?: boolean): void;\n onRemove(callback: (item: V, index: K) => void): void;\n};\n\ntype OnInstanceAvailableCallback = (callback: (ref: Ref, existing: boolean) => void) => void;\n\ntype CallContext = {\n instance?: any,\n parentInstance?: any,\n onInstanceAvailable?: OnInstanceAvailableCallback,\n}\n\nexport function getStateCallbacks<T extends Schema>(decoder: Decoder<T>): CallbackProxy<T> {\n const $root = decoder.root;\n const callbacks = $root.callbacks;\n\n let isTriggeringOnAdd = false;\n\n decoder.triggerChanges = function (allChanges: DataChange[]) {\n const uniqueRefIds = new Set<number>();\n\n for (let i = 0, l = allChanges.length; i < l; i++) {\n const change = allChanges[i];\n const refId = change.refId;\n const ref = change.ref;\n const $callbacks = callbacks[refId];\n\n if (!$callbacks) { continue; }\n\n //\n // trigger onRemove on child structure.\n //\n if (\n (change.op & OPERATION.DELETE) === OPERATION.DELETE &&\n change.previousValue instanceof Schema\n ) {\n const deleteCallbacks = callbacks[$root.refIds.get(change.previousValue)]?.[OPERATION.DELETE];\n for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {\n deleteCallbacks[i]();\n }\n }\n\n if (ref instanceof Schema) {\n //\n // Handle schema instance\n //\n\n if (!uniqueRefIds.has(refId)) {\n try {\n // trigger onChange\n const replaceCallbacks = $callbacks?.[OPERATION.REPLACE];\n for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {\n replaceCallbacks[i]();\n }\n\n } catch (e) {\n console.error(e);\n }\n }\n\n try {\n if ($callbacks.hasOwnProperty(change.field)) {\n const fieldCallbacks = $callbacks[change.field];\n for (let i = fieldCallbacks?.length - 1; i >= 0; i--) {\n fieldCallbacks[i](change.value, change.previousValue);\n }\n }\n\n } catch (e) {\n //\n console.error(e);\n }\n\n } else {\n //\n // Handle collection of items\n //\n\n if (change.op === OPERATION.ADD && change.previousValue === undefined) {\n // triger onAdd\n\n isTriggeringOnAdd = true;\n const addCallbacks = $callbacks[OPERATION.ADD];\n for (let i = addCallbacks?.length - 1; i >= 0; i--) {\n addCallbacks[i](change.value, change.dynamicIndex ?? change.field);\n }\n isTriggeringOnAdd = false;\n\n } else if ((change.op & OPERATION.DELETE) === OPERATION.DELETE) {\n //\n // FIXME: `previousValue` should always be available.\n //\n if (change.previousValue !== undefined) {\n // triger onRemove\n const deleteCallbacks = $callbacks[OPERATION.DELETE];\n for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {\n deleteCallbacks[i](change.previousValue, change.dynamicIndex ?? change.field);\n }\n }\n\n // Handle DELETE_AND_ADD operations\n // FIXME: should we set \"isTriggeringOnAdd\" here?\n if ((change.op & OPERATION.ADD) === OPERATION.ADD) {\n const addCallbacks = $callbacks[OPERATION.ADD];\n for (let i = addCallbacks?.length - 1; i >= 0; i--) {\n addCallbacks[i](change.value, change.dynamicIndex ?? change.field);\n }\n }\n }\n\n // trigger onChange\n if (change.value !== change.previousValue) {\n const replaceCallbacks = $callbacks[OPERATION.REPLACE];\n for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {\n replaceCallbacks[i](change.value, change.dynamicIndex ?? change.field);\n }\n }\n }\n\n uniqueRefIds.add(refId);\n }\n };\n\n function getProxy(metadataOrType: Metadata | DefinitionType, context: CallContext) {\n let metadata: Metadata = context.instance?.constructor[Symbol.metadata] || metadataOrType;\n let isCollection = (\n (context.instance && typeof (context.instance['forEach']) === \"function\") ||\n (metadataOrType && typeof (metadataOrType[Symbol.metadata]) === \"undefined\")\n );\n\n if (metadata && !isCollection) {\n\n const onAdd = function (\n ref: Ref,\n prop: string,\n callback: (value: any, previousValue: any) => void, immediate: boolean\n ) {\n // immediate trigger\n if (\n immediate &&\n context.instance[prop] !== undefined &&\n !isTriggeringOnAdd // FIXME: This is a workaround (https://github.com/colyseus/schema/issues/147)\n ) {\n callback(context.instance[prop], undefined);\n }\n return $root.addCallback($root.refIds.get(ref), prop, callback);\n }\n\n /**\n * Schema instances\n */\n return new Proxy({\n listen: function listen(prop: string, callback: (value: any, previousValue: any) => void, immediate: boolean = true) {\n if (context.instance) {\n return onAdd(context.instance, prop, callback, immediate);\n\n } else {\n // collection instance not received yet\n context.onInstanceAvailable((ref: Ref, existing: boolean) =>\n onAdd(ref, prop, callback, immediate && existing));\n }\n },\n onChange: function onChange(callback: () => void) {\n return $root.addCallback(\n $root.refIds.get(context.instance),\n OPERATION.REPLACE,\n callback\n );\n },\n bindTo: function bindTo(targetObject: any, properties?: string[]) {\n // return $root.addCallback(\n // $root.refIds.get(context.instance),\n // OPERATION.BIND,\n // callback\n // );\n console.log(\"bindTo\", targetObject, properties);\n }\n }, {\n get(target, prop: string) {\n if (metadata[prop]) {\n const instance = context.instance?.[prop];\n const onInstanceAvailable: OnInstanceAvailableCallback = (\n (callback: (ref: Ref, existing: boolean) => void) => {\n const unbind = $(context.instance).listen(prop, (value, _) => {\n callback(value, false);\n\n // FIXME: by \"unbinding\" the callback here,\n // it will not support when the server\n // re-instantiates the instance.\n //\n unbind?.();\n }, false);\n\n // has existing value\n if ($root.refIds.get(instance) !== undefined) {\n callback(instance, true);\n }\n }\n );\n return getProxy(metadata[prop].type, {\n instance,\n parentInstance: context.instance,\n onInstanceAvailable,\n });\n\n } else {\n // accessing the function\n return target[prop];\n }\n },\n has(target, prop: string) { return metadata[prop] !== undefined; },\n set(_, _1, _2) { throw new Error(\"not allowed\"); },\n deleteProperty(_, _1) { throw new Error(\"not allowed\"); },\n });\n\n } else {\n /**\n * Collection instances\n */\n\n const onAdd = function (ref: Ref, callback: (value: any, key: any) => void, immediate: boolean) {\n // Trigger callback on existing items\n if (immediate) {\n (ref as ArraySchema).forEach((v, k) => callback(v, k));\n }\n return $root.addCallback($root.refIds.get(ref), OPERATION.ADD, callback);\n };\n\n const onRemove = function (ref: Ref, callback: (value: any, key: any) => void) {\n return $root.addCallback($root.refIds.get(ref), OPERATION.DELETE, callback);\n };\n\n return new Proxy({\n onAdd: function(callback: (value, key) => void, immediate: boolean = true) {\n //\n // https://github.com/colyseus/schema/issues/147\n // If parent instance has \"onAdd\" registered, avoid triggering immediate callback.\n //\n // FIXME: \"isTriggeringOnAdd\" is a workaround. We should find a better way to handle this.\n //\n if (context.onInstanceAvailable) {\n // collection instance not received yet\n context.onInstanceAvailable((ref: Ref, existing: boolean) =>\n onAdd(ref, callback, immediate && existing && !isTriggeringOnAdd));\n\n } else if (context.instance) {\n onAdd(context.instance, callback, immediate && !isTriggeringOnAdd);\n }\n },\n onRemove: function(callback: (value, key) => void) {\n if (context.onInstanceAvailable) {\n // collection instance not received yet\n context.onInstanceAvailable((ref: Ref) =>\n onRemove(ref, callback));\n\n } else if (context.instance) {\n onRemove(context.instance, callback);\n }\n },\n }, {\n get(target, prop: string) {\n if (!target[prop]) {\n throw new Error(`Can't access '${prop}' through callback proxy. access the instance directly.`);\n }\n return target[prop];\n },\n has(target, prop) { return target[prop] !== undefined; },\n set(_, _1, _2) { throw new Error(\"not allowed\"); },\n deleteProperty(_, _1) { throw new Error(\"not allowed\"); },\n });\n }\n }\n\n function $<T>(instance: T): CallbackProxy<T> {\n return getProxy(undefined, { instance }) as CallbackProxy<T>;\n }\n\n return $(decoder.state);\n}"]}
1
+ {"version":3,"file":"StateCallbacks.js","sourceRoot":"","sources":["../../../src/decoder/strategy/StateCallbacks.ts"],"names":[],"mappings":"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","sourcesContent":["import { Metadata } from \"../../Metadata\";\nimport { Collection, NonFunctionNonPrimitivePropNames, NonFunctionPropNames } from \"../../types/HelperTypes\";\nimport { Ref } from \"../../encoder/ChangeTree\";\nimport { Decoder } from \"../Decoder\";\nimport { DataChange } from \"../DecodeOperation\";\nimport { OPERATION } from \"../../encoding/spec\";\nimport { DefinitionType } from \"../../annotations\";\nimport { Schema } from \"../../Schema\";\nimport type { ArraySchema } from \"../../types/custom/ArraySchema\";\n\n//\n// Discussion: https://github.com/colyseus/schema/issues/155\n//\n// Main points:\n// - Decouple structures from their callbacks.\n// - Registering deep callbacks can be confusing.\n// - Avoid closures by allowing to pass a context. (https://github.com/colyseus/schema/issues/155#issuecomment-1804694081)\n//\n\nexport type GetCallbackProxy = (<T extends Schema>(instance: T) => CallbackProxy<T>);\n\nexport type CallbackProxy<T> = unknown extends T // is \"any\"?\n ? InstanceCallback<T> & CollectionCallback<any, any>\n : T extends Collection<infer K, infer V, infer _>\n ? CollectionCallback<K, V>\n : InstanceCallback<T>;\n\ntype InstanceCallback<T> = {\n /**\n * Trigger callback when value of a property changes.\n *\n * @param prop name of the property\n * @param callback callback to be triggered on property change\n * @param immediate trigger immediatelly if property has been already set.\n */\n listen<K extends NonFunctionPropNames<T>>(\n prop: K,\n callback: (value: T[K], previousValue: T[K]) => void,\n immediate?: boolean,\n )\n /**\n * Trigger callback whenever any property changed within this instance.\n *\n * @param prop name of the property\n * @param callback callback to be triggered on property change\n * @param immediate trigger immediatelly if property has been already set.\n */\n onChange(callback: () => void): void;\n\n /**\n * Bind properties to another object. Changes on the properties will be reflected on the target object.\n *\n * @param targetObject object to bind properties to\n * @param properties list of properties to bind. If not provided, all properties will be bound.\n */\n bindTo(targetObject: any, properties?: Array<NonFunctionPropNames<T>>): void;\n} & {\n [K in NonFunctionNonPrimitivePropNames<T>]: CallbackProxy<T[K]>;\n}\n\ntype CollectionCallback<K, V> = {\n /**\n * Trigger callback when an item has been added to the collection.\n *\n * @param callback\n * @param immediate\n */\n onAdd(callback: (item: V, index: K) => void, immediate?: boolean): void;\n\n /**\n * Trigger callback when an item has been removed to the collection.\n *\n * @param callback\n */\n onRemove(callback: (item: V, index: K) => void): void;\n\n // /**\n // * Trigger callback when an item has been removed to the collection.\n // *\n // * @param callback\n // */\n // onChange(callback: (item: V, index: K) => void): void;\n};\n\ntype OnInstanceAvailableCallback = (callback: (ref: Ref, existing: boolean) => void) => void;\n\ntype CallContext = {\n instance?: any,\n parentInstance?: any,\n onInstanceAvailable?: OnInstanceAvailableCallback,\n}\n\n\nexport function getStateCallbacks<T extends Schema>(decoder: Decoder<T>): GetCallbackProxy {\n const $root = decoder.root;\n const callbacks = $root.callbacks;\n\n let isTriggeringOnAdd = false;\n\n decoder.triggerChanges = function (allChanges: DataChange[]) {\n const uniqueRefIds = new Set<number>();\n\n for (let i = 0, l = allChanges.length; i < l; i++) {\n const change = allChanges[i];\n const refId = change.refId;\n const ref = change.ref;\n const $callbacks = callbacks[refId];\n\n if (!$callbacks) { continue; }\n\n //\n // trigger onRemove on child structure.\n //\n if (\n (change.op & OPERATION.DELETE) === OPERATION.DELETE &&\n change.previousValue instanceof Schema\n ) {\n const deleteCallbacks = callbacks[$root.refIds.get(change.previousValue)]?.[OPERATION.DELETE];\n for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {\n deleteCallbacks[i]();\n }\n }\n\n if (ref instanceof Schema) {\n //\n // Handle schema instance\n //\n\n if (!uniqueRefIds.has(refId)) {\n // trigger onChange\n const replaceCallbacks = $callbacks?.[OPERATION.REPLACE];\n for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {\n replaceCallbacks[i]();\n // try {\n // } catch (e) {\n // console.error(e);\n // }\n }\n }\n\n if ($callbacks.hasOwnProperty(change.field)) {\n const fieldCallbacks = $callbacks[change.field];\n for (let i = fieldCallbacks?.length - 1; i >= 0; i--) {\n fieldCallbacks[i](change.value, change.previousValue);\n // try {\n // } catch (e) {\n // console.error(e);\n // }\n }\n }\n\n\n } else {\n //\n // Handle collection of items\n //\n\n if (change.op === OPERATION.ADD && change.previousValue === undefined) {\n // triger onAdd\n\n isTriggeringOnAdd = true;\n const addCallbacks = $callbacks[OPERATION.ADD];\n for (let i = addCallbacks?.length - 1; i >= 0; i--) {\n addCallbacks[i](change.value, change.dynamicIndex ?? change.field);\n }\n isTriggeringOnAdd = false;\n\n } else if ((change.op & OPERATION.DELETE) === OPERATION.DELETE) {\n //\n // FIXME: `previousValue` should always be available.\n //\n if (change.previousValue !== undefined) {\n // triger onRemove\n const deleteCallbacks = $callbacks[OPERATION.DELETE];\n for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {\n deleteCallbacks[i](change.previousValue, change.dynamicIndex ?? change.field);\n }\n }\n\n // Handle DELETE_AND_ADD operations\n // FIXME: should we set \"isTriggeringOnAdd\" here?\n if ((change.op & OPERATION.ADD) === OPERATION.ADD) {\n const addCallbacks = $callbacks[OPERATION.ADD];\n for (let i = addCallbacks?.length - 1; i >= 0; i--) {\n addCallbacks[i](change.value, change.dynamicIndex ?? change.field);\n }\n }\n }\n\n // trigger onChange\n if (change.value !== change.previousValue) {\n const replaceCallbacks = $callbacks[OPERATION.REPLACE];\n for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {\n replaceCallbacks[i](change.value, change.dynamicIndex ?? change.field);\n }\n }\n }\n\n uniqueRefIds.add(refId);\n }\n };\n\n function getProxy(metadataOrType: Metadata | DefinitionType, context: CallContext) {\n let metadata: Metadata = context.instance?.constructor[Symbol.metadata] || metadataOrType;\n let isCollection = (\n (context.instance && typeof (context.instance['forEach']) === \"function\") ||\n (metadataOrType && typeof (metadataOrType[Symbol.metadata]) === \"undefined\")\n );\n\n if (metadata && !isCollection) {\n\n const onAdd = function (\n ref: Ref,\n prop: string,\n callback: (value: any, previousValue: any) => void, immediate: boolean\n ) {\n // immediate trigger\n if (\n immediate &&\n context.instance[prop] !== undefined &&\n !isTriggeringOnAdd // FIXME: This is a workaround (https://github.com/colyseus/schema/issues/147)\n ) {\n callback(context.instance[prop], undefined);\n }\n return $root.addCallback($root.refIds.get(ref), prop, callback);\n }\n\n /**\n * Schema instances\n */\n return new Proxy({\n listen: function listen(prop: string, callback: (value: any, previousValue: any) => void, immediate: boolean = true) {\n if (context.instance) {\n return onAdd(context.instance, prop, callback, immediate);\n\n } else {\n // collection instance not received yet\n context.onInstanceAvailable((ref: Ref, existing: boolean) =>\n onAdd(ref, prop, callback, immediate && existing));\n }\n },\n onChange: function onChange(callback: () => void) {\n return $root.addCallback(\n $root.refIds.get(context.instance),\n OPERATION.REPLACE,\n callback\n );\n },\n bindTo: function bindTo(targetObject: any, properties?: string[]) {\n //\n // TODO: refactor this implementation. There is room for improvement here.\n //\n if (!properties) {\n properties = Object.keys(metadata);\n }\n return $root.addCallback(\n $root.refIds.get(context.instance),\n OPERATION.REPLACE,\n () => {\n properties.forEach((prop) =>\n targetObject[prop] = context.instance[prop])\n }\n );\n }\n }, {\n get(target, prop: string) {\n if (metadata[prop]) {\n const instance = context.instance?.[prop];\n const onInstanceAvailable: OnInstanceAvailableCallback = (\n (callback: (ref: Ref, existing: boolean) => void) => {\n const unbind = $(context.instance).listen(prop, (value, _) => {\n callback(value, false);\n\n // FIXME: by \"unbinding\" the callback here,\n // it will not support when the server\n // re-instantiates the instance.\n //\n unbind?.();\n }, false);\n\n // has existing value\n if ($root.refIds.get(instance) !== undefined) {\n callback(instance, true);\n }\n }\n );\n return getProxy(metadata[prop].type, {\n instance,\n parentInstance: context.instance,\n onInstanceAvailable,\n });\n\n } else {\n // accessing the function\n return target[prop];\n }\n },\n has(target, prop: string) { return metadata[prop] !== undefined; },\n set(_, _1, _2) { throw new Error(\"not allowed\"); },\n deleteProperty(_, _1) { throw new Error(\"not allowed\"); },\n });\n\n } else {\n /**\n * Collection instances\n */\n\n const onAdd = function (ref: Ref, callback: (value: any, key: any) => void, immediate: boolean) {\n // Trigger callback on existing items\n if (immediate) {\n (ref as ArraySchema).forEach((v, k) => callback(v, k));\n }\n return $root.addCallback($root.refIds.get(ref), OPERATION.ADD, callback);\n };\n\n const onRemove = function (ref: Ref, callback: (value: any, key: any) => void) {\n return $root.addCallback($root.refIds.get(ref), OPERATION.DELETE, callback);\n };\n\n return new Proxy({\n onAdd: function(callback: (value, key) => void, immediate: boolean = true) {\n //\n // https://github.com/colyseus/schema/issues/147\n // If parent instance has \"onAdd\" registered, avoid triggering immediate callback.\n //\n // FIXME: \"isTriggeringOnAdd\" is a workaround. We should find a better way to handle this.\n //\n if (context.onInstanceAvailable) {\n // collection instance not received yet\n context.onInstanceAvailable((ref: Ref, existing: boolean) =>\n onAdd(ref, callback, immediate && existing && !isTriggeringOnAdd));\n\n } else if (context.instance) {\n onAdd(context.instance, callback, immediate && !isTriggeringOnAdd);\n }\n },\n onRemove: function(callback: (value, key) => void) {\n if (context.onInstanceAvailable) {\n // collection instance not received yet\n context.onInstanceAvailable((ref: Ref) =>\n onRemove(ref, callback));\n\n } else if (context.instance) {\n onRemove(context.instance, callback);\n }\n },\n }, {\n get(target, prop: string) {\n if (!target[prop]) {\n throw new Error(`Can't access '${prop}' through callback proxy. access the instance directly.`);\n }\n return target[prop];\n },\n has(target, prop) { return target[prop] !== undefined; },\n set(_, _1, _2) { throw new Error(\"not allowed\"); },\n deleteProperty(_, _1) { throw new Error(\"not allowed\"); },\n });\n }\n }\n\n function $<T>(instance: T): CallbackProxy<T> {\n return getProxy(undefined, { instance }) as CallbackProxy<T>;\n }\n\n return $;\n}"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colyseus/schema",
3
- "version": "3.0.0-alpha.13",
3
+ "version": "3.0.0-alpha.15",
4
4
  "description": "Binary state serializer with delta encoding for games",
5
5
  "bin": {
6
6
  "schema-codegen": "./bin/schema-codegen"
@@ -17,27 +17,69 @@ import type { ArraySchema } from "../../types/custom/ArraySchema";
17
17
  // - Avoid closures by allowing to pass a context. (https://github.com/colyseus/schema/issues/155#issuecomment-1804694081)
18
18
  //
19
19
 
20
+ export type GetCallbackProxy = (<T extends Schema>(instance: T) => CallbackProxy<T>);
21
+
20
22
  export type CallbackProxy<T> = unknown extends T // is "any"?
21
23
  ? InstanceCallback<T> & CollectionCallback<any, any>
22
24
  : T extends Collection<infer K, infer V, infer _>
23
25
  ? CollectionCallback<K, V>
24
- : InstanceCallback<T>
26
+ : InstanceCallback<T>;
25
27
 
26
28
  type InstanceCallback<T> = {
29
+ /**
30
+ * Trigger callback when value of a property changes.
31
+ *
32
+ * @param prop name of the property
33
+ * @param callback callback to be triggered on property change
34
+ * @param immediate trigger immediatelly if property has been already set.
35
+ */
27
36
  listen<K extends NonFunctionPropNames<T>>(
28
37
  prop: K,
29
38
  callback: (value: T[K], previousValue: T[K]) => void,
30
39
  immediate?: boolean,
31
40
  )
41
+ /**
42
+ * Trigger callback whenever any property changed within this instance.
43
+ *
44
+ * @param prop name of the property
45
+ * @param callback callback to be triggered on property change
46
+ * @param immediate trigger immediatelly if property has been already set.
47
+ */
32
48
  onChange(callback: () => void): void;
49
+
50
+ /**
51
+ * Bind properties to another object. Changes on the properties will be reflected on the target object.
52
+ *
53
+ * @param targetObject object to bind properties to
54
+ * @param properties list of properties to bind. If not provided, all properties will be bound.
55
+ */
33
56
  bindTo(targetObject: any, properties?: Array<NonFunctionPropNames<T>>): void;
34
57
  } & {
35
58
  [K in NonFunctionNonPrimitivePropNames<T>]: CallbackProxy<T[K]>;
36
59
  }
37
60
 
38
61
  type CollectionCallback<K, V> = {
62
+ /**
63
+ * Trigger callback when an item has been added to the collection.
64
+ *
65
+ * @param callback
66
+ * @param immediate
67
+ */
39
68
  onAdd(callback: (item: V, index: K) => void, immediate?: boolean): void;
69
+
70
+ /**
71
+ * Trigger callback when an item has been removed to the collection.
72
+ *
73
+ * @param callback
74
+ */
40
75
  onRemove(callback: (item: V, index: K) => void): void;
76
+
77
+ // /**
78
+ // * Trigger callback when an item has been removed to the collection.
79
+ // *
80
+ // * @param callback
81
+ // */
82
+ // onChange(callback: (item: V, index: K) => void): void;
41
83
  };
42
84
 
43
85
  type OnInstanceAvailableCallback = (callback: (ref: Ref, existing: boolean) => void) => void;
@@ -48,7 +90,8 @@ type CallContext = {
48
90
  onInstanceAvailable?: OnInstanceAvailableCallback,
49
91
  }
50
92
 
51
- export function getStateCallbacks<T extends Schema>(decoder: Decoder<T>): CallbackProxy<T> {
93
+
94
+ export function getStateCallbacks<T extends Schema>(decoder: Decoder<T>): GetCallbackProxy {
52
95
  const $root = decoder.root;
53
96
  const callbacks = $root.callbacks;
54
97
 
@@ -84,31 +127,29 @@ export function getStateCallbacks<T extends Schema>(decoder: Decoder<T>): Callba
84
127
  //
85
128
 
86
129
  if (!uniqueRefIds.has(refId)) {
87
- try {
88
- // trigger onChange
89
- const replaceCallbacks = $callbacks?.[OPERATION.REPLACE];
90
- for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {
91
- replaceCallbacks[i]();
92
- }
93
-
94
- } catch (e) {
95
- console.error(e);
130
+ // trigger onChange
131
+ const replaceCallbacks = $callbacks?.[OPERATION.REPLACE];
132
+ for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {
133
+ replaceCallbacks[i]();
134
+ // try {
135
+ // } catch (e) {
136
+ // console.error(e);
137
+ // }
96
138
  }
97
139
  }
98
140
 
99
- try {
100
- if ($callbacks.hasOwnProperty(change.field)) {
101
- const fieldCallbacks = $callbacks[change.field];
102
- for (let i = fieldCallbacks?.length - 1; i >= 0; i--) {
103
- fieldCallbacks[i](change.value, change.previousValue);
104
- }
141
+ if ($callbacks.hasOwnProperty(change.field)) {
142
+ const fieldCallbacks = $callbacks[change.field];
143
+ for (let i = fieldCallbacks?.length - 1; i >= 0; i--) {
144
+ fieldCallbacks[i](change.value, change.previousValue);
145
+ // try {
146
+ // } catch (e) {
147
+ // console.error(e);
148
+ // }
105
149
  }
106
-
107
- } catch (e) {
108
- //
109
- console.error(e);
110
150
  }
111
151
 
152
+
112
153
  } else {
113
154
  //
114
155
  // Handle collection of items
@@ -206,12 +247,20 @@ export function getStateCallbacks<T extends Schema>(decoder: Decoder<T>): Callba
206
247
  );
207
248
  },
208
249
  bindTo: function bindTo(targetObject: any, properties?: string[]) {
209
- // return $root.addCallback(
210
- // $root.refIds.get(context.instance),
211
- // OPERATION.BIND,
212
- // callback
213
- // );
214
- console.log("bindTo", targetObject, properties);
250
+ //
251
+ // TODO: refactor this implementation. There is room for improvement here.
252
+ //
253
+ if (!properties) {
254
+ properties = Object.keys(metadata);
255
+ }
256
+ return $root.addCallback(
257
+ $root.refIds.get(context.instance),
258
+ OPERATION.REPLACE,
259
+ () => {
260
+ properties.forEach((prop) =>
261
+ targetObject[prop] = context.instance[prop])
262
+ }
263
+ );
215
264
  }
216
265
  }, {
217
266
  get(target, prop: string) {
@@ -313,5 +362,5 @@ export function getStateCallbacks<T extends Schema>(decoder: Decoder<T>): Callba
313
362
  return getProxy(undefined, { instance }) as CallbackProxy<T>;
314
363
  }
315
364
 
316
- return $(decoder.state);
365
+ return $;
317
366
  }