@colyseus/schema 3.0.0-alpha.4 → 3.0.0-alpha.41

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 (146) hide show
  1. package/README.md +148 -62
  2. package/bin/schema-debug +94 -0
  3. package/build/cjs/index.js +2201 -1507
  4. package/build/cjs/index.js.map +1 -1
  5. package/build/esm/index.mjs +2198 -1506
  6. package/build/esm/index.mjs.map +1 -1
  7. package/build/umd/index.js +2208 -1514
  8. package/lib/Metadata.d.ts +21 -9
  9. package/lib/Metadata.js +169 -32
  10. package/lib/Metadata.js.map +1 -1
  11. package/lib/Reflection.d.ts +19 -4
  12. package/lib/Reflection.js +66 -32
  13. package/lib/Reflection.js.map +1 -1
  14. package/lib/Schema.d.ts +4 -4
  15. package/lib/Schema.js +44 -50
  16. package/lib/Schema.js.map +1 -1
  17. package/lib/annotations.d.ts +31 -34
  18. package/lib/annotations.js +110 -160
  19. package/lib/annotations.js.map +1 -1
  20. package/lib/bench_encode.d.ts +1 -0
  21. package/lib/bench_encode.js +130 -0
  22. package/lib/bench_encode.js.map +1 -0
  23. package/lib/codegen/api.js +1 -2
  24. package/lib/codegen/api.js.map +1 -1
  25. package/lib/codegen/languages/cpp.js +1 -2
  26. package/lib/codegen/languages/cpp.js.map +1 -1
  27. package/lib/codegen/languages/csharp.js +2 -46
  28. package/lib/codegen/languages/csharp.js.map +1 -1
  29. package/lib/codegen/languages/haxe.js +1 -2
  30. package/lib/codegen/languages/haxe.js.map +1 -1
  31. package/lib/codegen/languages/java.js +1 -2
  32. package/lib/codegen/languages/java.js.map +1 -1
  33. package/lib/codegen/languages/js.js +1 -2
  34. package/lib/codegen/languages/js.js.map +1 -1
  35. package/lib/codegen/languages/lua.js +1 -2
  36. package/lib/codegen/languages/lua.js.map +1 -1
  37. package/lib/codegen/languages/ts.js +1 -2
  38. package/lib/codegen/languages/ts.js.map +1 -1
  39. package/lib/codegen/parser.js +85 -3
  40. package/lib/codegen/parser.js.map +1 -1
  41. package/lib/codegen/types.js +6 -3
  42. package/lib/codegen/types.js.map +1 -1
  43. package/lib/debug.d.ts +1 -0
  44. package/lib/debug.js +51 -0
  45. package/lib/debug.js.map +1 -0
  46. package/lib/decoder/DecodeOperation.d.ts +3 -4
  47. package/lib/decoder/DecodeOperation.js +37 -19
  48. package/lib/decoder/DecodeOperation.js.map +1 -1
  49. package/lib/decoder/Decoder.d.ts +6 -7
  50. package/lib/decoder/Decoder.js +14 -14
  51. package/lib/decoder/Decoder.js.map +1 -1
  52. package/lib/decoder/ReferenceTracker.js +3 -2
  53. package/lib/decoder/ReferenceTracker.js.map +1 -1
  54. package/lib/decoder/strategy/RawChanges.js +1 -2
  55. package/lib/decoder/strategy/RawChanges.js.map +1 -1
  56. package/lib/decoder/strategy/StateCallbacks.d.ts +44 -11
  57. package/lib/decoder/strategy/StateCallbacks.js +75 -65
  58. package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
  59. package/lib/encoder/ChangeTree.d.ts +27 -21
  60. package/lib/encoder/ChangeTree.js +246 -186
  61. package/lib/encoder/ChangeTree.js.map +1 -1
  62. package/lib/encoder/EncodeOperation.d.ts +3 -6
  63. package/lib/encoder/EncodeOperation.js +51 -65
  64. package/lib/encoder/EncodeOperation.js.map +1 -1
  65. package/lib/encoder/Encoder.d.ts +9 -8
  66. package/lib/encoder/Encoder.js +168 -91
  67. package/lib/encoder/Encoder.js.map +1 -1
  68. package/lib/encoder/Root.d.ts +22 -0
  69. package/lib/encoder/Root.js +81 -0
  70. package/lib/encoder/Root.js.map +1 -0
  71. package/lib/encoder/StateView.d.ts +7 -7
  72. package/lib/encoder/StateView.js +70 -74
  73. package/lib/encoder/StateView.js.map +1 -1
  74. package/lib/encoding/assert.d.ts +7 -6
  75. package/lib/encoding/assert.js +13 -5
  76. package/lib/encoding/assert.js.map +1 -1
  77. package/lib/encoding/decode.d.ts +35 -20
  78. package/lib/encoding/decode.js +43 -87
  79. package/lib/encoding/decode.js.map +1 -1
  80. package/lib/encoding/encode.d.ts +36 -17
  81. package/lib/encoding/encode.js +82 -68
  82. package/lib/encoding/encode.js.map +1 -1
  83. package/lib/encoding/spec.d.ts +4 -5
  84. package/lib/encoding/spec.js +1 -2
  85. package/lib/encoding/spec.js.map +1 -1
  86. package/lib/index.d.ts +10 -9
  87. package/lib/index.js +24 -17
  88. package/lib/index.js.map +1 -1
  89. package/lib/types/HelperTypes.d.ts +34 -2
  90. package/lib/types/HelperTypes.js.map +1 -1
  91. package/lib/types/TypeContext.d.ts +23 -0
  92. package/lib/types/TypeContext.js +111 -0
  93. package/lib/types/TypeContext.js.map +1 -0
  94. package/lib/types/custom/ArraySchema.d.ts +2 -2
  95. package/lib/types/custom/ArraySchema.js +33 -22
  96. package/lib/types/custom/ArraySchema.js.map +1 -1
  97. package/lib/types/custom/CollectionSchema.js +1 -0
  98. package/lib/types/custom/CollectionSchema.js.map +1 -1
  99. package/lib/types/custom/MapSchema.d.ts +3 -1
  100. package/lib/types/custom/MapSchema.js +12 -4
  101. package/lib/types/custom/MapSchema.js.map +1 -1
  102. package/lib/types/custom/SetSchema.js +1 -0
  103. package/lib/types/custom/SetSchema.js.map +1 -1
  104. package/lib/types/registry.d.ts +8 -1
  105. package/lib/types/registry.js +23 -6
  106. package/lib/types/registry.js.map +1 -1
  107. package/lib/types/symbols.d.ts +8 -5
  108. package/lib/types/symbols.js +9 -6
  109. package/lib/types/symbols.js.map +1 -1
  110. package/lib/types/utils.js +1 -2
  111. package/lib/types/utils.js.map +1 -1
  112. package/lib/utils.js +9 -7
  113. package/lib/utils.js.map +1 -1
  114. package/package.json +7 -6
  115. package/src/Metadata.ts +190 -42
  116. package/src/Reflection.ts +77 -39
  117. package/src/Schema.ts +59 -64
  118. package/src/annotations.ts +156 -202
  119. package/src/bench_encode.ts +108 -0
  120. package/src/codegen/languages/csharp.ts +1 -47
  121. package/src/codegen/parser.ts +107 -0
  122. package/src/codegen/types.ts +1 -0
  123. package/src/debug.ts +55 -0
  124. package/src/decoder/DecodeOperation.ts +46 -18
  125. package/src/decoder/Decoder.ts +17 -15
  126. package/src/decoder/ReferenceTracker.ts +3 -2
  127. package/src/decoder/strategy/StateCallbacks.ts +153 -82
  128. package/src/encoder/ChangeTree.ts +286 -202
  129. package/src/encoder/EncodeOperation.ts +78 -78
  130. package/src/encoder/Encoder.ts +202 -97
  131. package/src/encoder/Root.ts +93 -0
  132. package/src/encoder/StateView.ts +76 -88
  133. package/src/encoding/assert.ts +17 -8
  134. package/src/encoding/decode.ts +62 -97
  135. package/src/encoding/encode.ts +99 -65
  136. package/src/encoding/spec.ts +3 -5
  137. package/src/index.ts +12 -20
  138. package/src/types/HelperTypes.ts +54 -2
  139. package/src/types/TypeContext.ts +133 -0
  140. package/src/types/custom/ArraySchema.ts +49 -19
  141. package/src/types/custom/CollectionSchema.ts +1 -0
  142. package/src/types/custom/MapSchema.ts +18 -5
  143. package/src/types/custom/SetSchema.ts +1 -0
  144. package/src/types/registry.ts +22 -3
  145. package/src/types/symbols.ts +10 -7
  146. package/src/utils.ts +7 -3
@@ -35,28 +35,40 @@ let textEncoder: TextEncoder;
35
35
  // @ts-ignore
36
36
  try { textEncoder = new TextEncoder(); } catch (e) { }
37
37
 
38
- export function utf8Length(str) {
39
- var c = 0, length = 0;
40
- for (var i = 0, l = str.length; i < l; i++) {
41
- c = str.charCodeAt(i);
42
- if (c < 0x80) {
43
- length += 1;
44
- }
45
- else if (c < 0x800) {
46
- length += 2;
47
- }
48
- else if (c < 0xd800 || c >= 0xe000) {
49
- length += 3;
50
- }
51
- else {
52
- i++;
53
- length += 4;
38
+ // force little endian to facilitate decoding on multiple implementations
39
+ const _isLittleEndian = true; // new Uint16Array(new Uint8Array([1, 0]).buffer)[0] === 1;
40
+ const _convoBuffer = new ArrayBuffer(8);
41
+ const _int32 = new Int32Array(_convoBuffer);
42
+ const _float32 = new Float32Array(_convoBuffer);
43
+ const _float64 = new Float64Array(_convoBuffer);
44
+ const _int64 = new BigInt64Array(_convoBuffer);
45
+
46
+ const hasBufferByteLength = (typeof Buffer !== 'undefined' && Buffer.byteLength);
47
+
48
+ const utf8Length: (str: string, _?: any) => number = (hasBufferByteLength)
49
+ ? Buffer.byteLength // node
50
+ : function (str: string, _?: any) {
51
+ var c = 0, length = 0;
52
+ for (var i = 0, l = str.length; i < l; i++) {
53
+ c = str.charCodeAt(i);
54
+ if (c < 0x80) {
55
+ length += 1;
56
+ }
57
+ else if (c < 0x800) {
58
+ length += 2;
59
+ }
60
+ else if (c < 0xd800 || c >= 0xe000) {
61
+ length += 3;
62
+ }
63
+ else {
64
+ i++;
65
+ length += 4;
66
+ }
67
+ }
68
+ return length;
54
69
  }
55
- }
56
- return length;
57
- }
58
70
 
59
- export function utf8Write(view, str, it) {
71
+ function utf8Write(view: BufferLike, str: string, it: Iterator) {
60
72
  var c = 0;
61
73
  for (var i = 0, l = str.length; i < l; i++) {
62
74
  c = str.charCodeAt(i);
@@ -64,51 +76,54 @@ export function utf8Write(view, str, it) {
64
76
  view[it.offset++] = c;
65
77
  }
66
78
  else if (c < 0x800) {
67
- view[it.offset++] = 0xc0 | (c >> 6);
68
- view[it.offset++] = 0x80 | (c & 0x3f);
79
+ view[it.offset] = 0xc0 | (c >> 6);
80
+ view[it.offset + 1] = 0x80 | (c & 0x3f);
81
+ it.offset += 2;
69
82
  }
70
83
  else if (c < 0xd800 || c >= 0xe000) {
71
- view[it.offset++] = 0xe0 | (c >> 12);
72
- view[it.offset++] = 0x80 | (c >> 6 & 0x3f);
73
- view[it.offset++] = 0x80 | (c & 0x3f);
84
+ view[it.offset] = 0xe0 | (c >> 12);
85
+ view[it.offset+1] = 0x80 | (c >> 6 & 0x3f);
86
+ view[it.offset+2] = 0x80 | (c & 0x3f);
87
+ it.offset += 3;
74
88
  }
75
89
  else {
76
90
  i++;
77
91
  c = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));
78
- view[it.offset++] = 0xf0 | (c >> 18);
79
- view[it.offset++] = 0x80 | (c >> 12 & 0x3f);
80
- view[it.offset++] = 0x80 | (c >> 6 & 0x3f);
81
- view[it.offset++] = 0x80 | (c & 0x3f);
92
+ view[it.offset] = 0xf0 | (c >> 18);
93
+ view[it.offset+1] = 0x80 | (c >> 12 & 0x3f);
94
+ view[it.offset+2] = 0x80 | (c >> 6 & 0x3f);
95
+ view[it.offset+3] = 0x80 | (c & 0x3f);
96
+ it.offset += 4;
82
97
  }
83
98
  }
84
99
  }
85
100
 
86
- export function int8(bytes: BufferLike, value: number, it: Iterator) {
101
+ function int8(bytes: BufferLike, value: number, it: Iterator) {
87
102
  bytes[it.offset++] = value & 255;
88
103
  };
89
104
 
90
- export function uint8(bytes: BufferLike, value: number, it: Iterator) {
105
+ function uint8(bytes: BufferLike, value: number, it: Iterator) {
91
106
  bytes[it.offset++] = value & 255;
92
107
  };
93
108
 
94
- export function int16(bytes: BufferLike, value: number, it: Iterator) {
109
+ function int16(bytes: BufferLike, value: number, it: Iterator) {
95
110
  bytes[it.offset++] = value & 255;
96
111
  bytes[it.offset++] = (value >> 8) & 255;
97
112
  };
98
113
 
99
- export function uint16(bytes: BufferLike, value: number, it: Iterator) {
114
+ function uint16(bytes: BufferLike, value: number, it: Iterator) {
100
115
  bytes[it.offset++] = value & 255;
101
116
  bytes[it.offset++] = (value >> 8) & 255;
102
117
  };
103
118
 
104
- export function int32(bytes: BufferLike, value: number, it: Iterator) {
119
+ function int32(bytes: BufferLike, value: number, it: Iterator) {
105
120
  bytes[it.offset++] = value & 255;
106
121
  bytes[it.offset++] = (value >> 8) & 255;
107
122
  bytes[it.offset++] = (value >> 16) & 255;
108
123
  bytes[it.offset++] = (value >> 24) & 255;
109
124
  };
110
125
 
111
- export function uint32(bytes: BufferLike, value: number, it: Iterator) {
126
+ function uint32(bytes: BufferLike, value: number, it: Iterator) {
112
127
  const b4 = value >> 24;
113
128
  const b3 = value >> 16;
114
129
  const b2 = value >> 8;
@@ -119,55 +134,52 @@ export function uint32(bytes: BufferLike, value: number, it: Iterator) {
119
134
  bytes[it.offset++] = b4 & 255;
120
135
  };
121
136
 
122
- export function int64(bytes: BufferLike, value: number, it: Iterator) {
137
+ function int64(bytes: BufferLike, value: number, it: Iterator) {
123
138
  const high = Math.floor(value / Math.pow(2, 32));
124
139
  const low = value >>> 0;
125
140
  uint32(bytes, low, it);
126
141
  uint32(bytes, high, it);
127
142
  };
128
143
 
129
- export function uint64(bytes: BufferLike, value: number, it: Iterator) {
144
+ function uint64(bytes: BufferLike, value: number, it: Iterator) {
130
145
  const high = (value / Math.pow(2, 32)) >> 0;
131
146
  const low = value >>> 0;
132
147
  uint32(bytes, low, it);
133
148
  uint32(bytes, high, it);
134
149
  };
135
150
 
136
- export function float32(bytes: BufferLike, value: number, it: Iterator) {
137
- writeFloat32(bytes, value, it);
151
+ function bigint64(bytes: BufferLike, value: bigint, it: Iterator) {
152
+ _int64[0] = BigInt.asIntN(64, value);
153
+ int32(bytes, _int32[0], it);
154
+ int32(bytes, _int32[1], it);
138
155
  }
139
156
 
140
- export function float64(bytes: BufferLike, value: number, it: Iterator) {
141
- writeFloat64(bytes, value, it);
157
+ function biguint64(bytes: BufferLike, value: bigint, it: Iterator) {
158
+ _int64[0] = BigInt.asIntN(64, value);
159
+ int32(bytes, _int32[0], it);
160
+ int32(bytes, _int32[1], it);
142
161
  }
143
162
 
144
- // force little endian to facilitate decoding on multiple implementations
145
- const _isLittleEndian = true; // new Uint16Array(new Uint8Array([1, 0]).buffer)[0] === 1;
146
- const _int32 = new Int32Array(2);
147
- const _float32 = new Float32Array(_int32.buffer);
148
- const _float64 = new Float64Array(_int32.buffer);
149
-
150
- export function writeFloat32(bytes: BufferLike, value: number, it: Iterator) {
163
+ function float32(bytes: BufferLike, value: number, it: Iterator) {
151
164
  _float32[0] = value;
152
165
  int32(bytes, _int32[0], it);
153
- };
166
+ }
154
167
 
155
- export function writeFloat64(bytes: BufferLike, value: number, it: Iterator) {
168
+ function float64(bytes: BufferLike, value: number, it: Iterator) {
156
169
  _float64[0] = value;
157
170
  int32(bytes, _int32[_isLittleEndian ? 0 : 1], it);
158
171
  int32(bytes, _int32[_isLittleEndian ? 1 : 0], it);
159
- };
172
+ }
160
173
 
161
- export function boolean(bytes: BufferLike, value: number, it: Iterator) {
174
+ function boolean(bytes: BufferLike, value: number, it: Iterator) {
162
175
  bytes[it.offset++] = value ? 1 : 0; // uint8
163
176
  };
164
177
 
165
- export function string(bytes: BufferLike, value: string, it: Iterator) {
178
+ function string(bytes: BufferLike, value: string, it: Iterator) {
166
179
  // encode `null` strings as empty.
167
180
  if (!value) { value = ""; }
168
181
 
169
- // let length = utf8Length(value);
170
- let length = Buffer.byteLength(value, "utf8");
182
+ let length = utf8Length(value, "utf8");
171
183
  let size = 0;
172
184
 
173
185
  // fixstr
@@ -201,7 +213,7 @@ export function string(bytes: BufferLike, value: string, it: Iterator) {
201
213
  return size + length;
202
214
  }
203
215
 
204
- export function number(bytes: BufferLike, value: number, it: Iterator) {
216
+ function number(bytes: BufferLike, value: number, it: Iterator) {
205
217
  if (isNaN(value)) {
206
218
  return number(bytes, 0, it);
207
219
 
@@ -209,17 +221,19 @@ export function number(bytes: BufferLike, value: number, it: Iterator) {
209
221
  return number(bytes, (value > 0) ? Number.MAX_SAFE_INTEGER : -Number.MAX_SAFE_INTEGER, it);
210
222
 
211
223
  } else if (value !== (value|0)) {
224
+ if (Math.abs(value) <= 3.4028235e+38) { // range check
225
+ _float32[0] = value;
226
+ if (Math.abs(Math.abs(_float32[0]) - Math.abs(value)) < 1e-4) { // precision check; adjust 1e-n (n = precision) to in-/decrease acceptable precision loss
227
+ // now we know value is in range for f32 and has acceptable precision for f32
228
+ bytes[it.offset++] = 0xca;
229
+ float32(bytes, value, it);
230
+ return 5;
231
+ }
232
+ }
233
+
212
234
  bytes[it.offset++] = 0xcb;
213
- writeFloat64(bytes, value, it);
235
+ float64(bytes, value, it);
214
236
  return 9;
215
-
216
- // TODO: encode float 32?
217
- // is it possible to differentiate between float32 / float64 here?
218
-
219
- // // float 32
220
- // bytes.push(0xca);
221
- // writeFloat32(bytes, value);
222
- // return 5;
223
237
  }
224
238
 
225
239
  if (value >= 0) {
@@ -290,3 +304,23 @@ export function number(bytes: BufferLike, value: number, it: Iterator) {
290
304
  return 9;
291
305
  }
292
306
  }
307
+
308
+ export const encode = {
309
+ int8,
310
+ uint8,
311
+ int16,
312
+ uint16,
313
+ int32,
314
+ uint32,
315
+ int64,
316
+ uint64,
317
+ bigint64,
318
+ biguint64,
319
+ float32,
320
+ float64,
321
+ boolean,
322
+ string,
323
+ number,
324
+ utf8Write,
325
+ utf8Length,
326
+ }
@@ -8,8 +8,8 @@ export enum OPERATION {
8
8
  ADD = 128, // (10000000) add new structure/primitive
9
9
  REPLACE = 0, // (00000001) replace structure/primitive
10
10
  DELETE = 64, // (01000000) delete field
11
- DELETE_AND_MOVE = 96, // () add new structure/primitive
12
- MOVE_AND_ADD = 160, // () add new structure/primitive
11
+ DELETE_AND_MOVE = 96, // () ArraySchema only
12
+ MOVE_AND_ADD = 160, // () ArraySchema only
13
13
  DELETE_AND_ADD = 192, // (11000000) DELETE field, followed by an ADD
14
14
 
15
15
  /**
@@ -20,10 +20,8 @@ export enum OPERATION {
20
20
  /**
21
21
  * ArraySchema operations
22
22
  */
23
- PUSH = 11,
24
- UNSHIFT = 12,
25
23
  REVERSE = 15,
26
24
  MOVE = 32,
27
25
  DELETE_BY_REFID = 33, // This operation is only used at ENCODING time. During DECODING, DELETE_BY_REFID is converted to DELETE
28
-
26
+ ADD_BY_REFID = 129,
29
27
  }
package/src/index.ts CHANGED
@@ -1,8 +1,6 @@
1
1
  export { Schema } from "./Schema";
2
2
  export type { DataChange } from "./decoder/DecodeOperation";
3
-
4
- import { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType } from "./types/symbols";
5
- export { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType };
3
+ export type { ToJSON } from "./types/HelperTypes";
6
4
 
7
5
  import { MapSchema } from "./types/custom/MapSchema"
8
6
  export { MapSchema };
@@ -16,8 +14,8 @@ export { CollectionSchema };
16
14
  import { SetSchema } from "./types/custom/SetSchema";
17
15
  export { SetSchema };
18
16
 
19
- import { registerType } from "./types/registry";
20
- export { registerType };
17
+ import { registerType, defineCustomTypes } from "./types/registry";
18
+ export { registerType, defineCustomTypes };
21
19
 
22
20
  registerType("map", { constructor: MapSchema });
23
21
  registerType("array", { constructor: ArraySchema });
@@ -28,10 +26,9 @@ registerType("collection", { constructor: CollectionSchema, });
28
26
  export { dumpChanges } from "./utils";
29
27
 
30
28
  // Encoder / Decoder
31
- export type { Iterator } from "./encoding/decode";
32
- import * as encode from "./encoding/encode";
33
- import * as decode from "./encoding/decode";
34
- export { encode, decode };
29
+ export { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType } from "./types/symbols";
30
+ export { encode } from "./encoding/encode";
31
+ export { decode, type Iterator } from "./encoding/decode";
35
32
 
36
33
  // Reflection
37
34
  export {
@@ -40,22 +37,17 @@ export {
40
37
  ReflectionField,
41
38
  } from "./Reflection";
42
39
 
40
+ // Annotations, Metadata and TypeContext
43
41
  export { Metadata } from "./Metadata";
44
-
45
- export {
46
- // Annotations
47
- type,
48
- deprecated,
49
- defineTypes,
50
- view,
51
-
52
- // Internals
53
- TypeContext,
54
- } from "./annotations";
42
+ export { type, deprecated, defineTypes, view, schema, type SchemaWithExtends, } from "./annotations";
43
+ export { TypeContext } from "./types/TypeContext";
55
44
 
56
45
  // Annotation types
57
46
  export type { DefinitionType, PrimitiveType, Definition, } from "./annotations";
58
47
 
48
+ export { getDecoderStateCallbacks, CallbackProxy, GetCallbackProxy } from "./decoder/strategy/StateCallbacks";
49
+ export { getRawChangesCallback } from "./decoder/strategy/RawChanges";
50
+
59
51
  export { Encoder } from "./encoder/Encoder";
60
52
  export { encodeSchemaOperation, encodeArray as encodeKeyValueOperation } from "./encoder/EncodeOperation";
61
53
  export { ChangeTree, Ref } from "./encoder/ChangeTree";
@@ -1,5 +1,11 @@
1
- import { ArraySchema } from "./custom/ArraySchema";
2
- import { MapSchema } from "./custom/MapSchema";
1
+ import type { Definition, DefinitionType, PrimitiveType, RawPrimitiveType } from "../annotations";
2
+ import type { Schema } from "../Schema";
3
+ import type { ArraySchema } from "./custom/ArraySchema";
4
+ import type { CollectionSchema } from "./custom/CollectionSchema";
5
+ import type { MapSchema } from "./custom/MapSchema";
6
+ import type { SetSchema } from "./custom/SetSchema";
7
+
8
+ export type Constructor<T = {}> = new (...args: any[]) => T;
3
9
 
4
10
  export interface Collection<K = any, V = any, IT = V> {
5
11
  [Symbol.iterator](): IterableIterator<IT>;
@@ -7,6 +13,52 @@ export interface Collection<K = any, V = any, IT = V> {
7
13
  entries(): IterableIterator<[K, V]>;
8
14
  }
9
15
 
16
+ export type InferValueType<T extends DefinitionType> =
17
+ T extends "string" ? string
18
+ : T extends "number" ? number
19
+ : T extends "int8" ? number
20
+ : T extends "uint8" ? number
21
+ : T extends "int16" ? number
22
+ : T extends "uint16" ? number
23
+ : T extends "int32" ? number
24
+ : T extends "uint32" ? number
25
+ : T extends "int64" ? number
26
+ : T extends "uint64" ? number
27
+ : T extends "float32" ? number
28
+ : T extends "float64" ? number
29
+ : T extends "boolean" ? boolean
30
+
31
+ : T extends { type: infer ChildType extends Constructor } ? InstanceType<ChildType>
32
+ : T extends { type: infer ChildType extends PrimitiveType } ? ChildType
33
+
34
+ : T extends Array<infer ChildType extends Constructor> ? InstanceType<ChildType>[]
35
+ : T extends Array<infer ChildType extends RawPrimitiveType> ? ChildType[]
36
+
37
+ : T extends { array: infer ChildType extends Constructor } ? InstanceType<ChildType>[]
38
+ : T extends { array: infer ChildType extends PrimitiveType } ? ChildType[]
39
+
40
+ : T extends { map: infer ChildType extends Constructor } ? MapSchema<InstanceType<ChildType>>
41
+ : T extends { map: infer ChildType extends PrimitiveType } ? MapSchema<ChildType>
42
+
43
+ : T extends { set: infer ChildType extends Constructor } ? SetSchema<InstanceType<ChildType>>
44
+ : T extends { set: infer ChildType extends PrimitiveType } ? SetSchema<ChildType>
45
+
46
+ : T extends { collection: infer ChildType extends Constructor } ? CollectionSchema<InstanceType<ChildType>>
47
+ : T extends { collection: infer ChildType extends PrimitiveType } ? CollectionSchema<ChildType>
48
+
49
+ : T extends Constructor ? InstanceType<T>
50
+ : T extends PrimitiveType ? T
51
+
52
+ : never;
53
+
54
+ export type InferSchemaInstanceType<T extends Definition> = {
55
+ [K in keyof T]: InferValueType<T[K]>
56
+ } & Schema;
57
+
58
+ export type DefinedSchemaType<T extends Definition, P extends typeof Schema> = {
59
+ new (): InferSchemaInstanceType<T> & InstanceType<P>;
60
+ } & typeof Schema;
61
+
10
62
  export type NonFunctionProps<T> = Omit<T, {
11
63
  [K in keyof T]: T[K] extends Function ? K : never;
12
64
  }[keyof T]>;
@@ -0,0 +1,133 @@
1
+ import { Metadata } from "../Metadata";
2
+ import { Schema } from "../Schema";
3
+ import { $viewFieldIndexes } from "./symbols";
4
+
5
+ export class TypeContext {
6
+ types: { [id: number]: typeof Schema; } = {};
7
+ schemas = new Map<typeof Schema, number>();
8
+
9
+ hasFilters: boolean = false;
10
+ parentFiltered: {[typeIdAndParentIndex: string]: boolean} = {};
11
+
12
+ /**
13
+ * For inheritance support
14
+ * Keeps track of which classes extends which. (parent -> children)
15
+ */
16
+ static inheritedTypes = new Map<typeof Schema, Set<typeof Schema>>();
17
+
18
+ static register(target: typeof Schema) {
19
+ const parent = Object.getPrototypeOf(target);
20
+ if (parent !== Schema) {
21
+ let inherits = TypeContext.inheritedTypes.get(parent);
22
+ if (!inherits) {
23
+ inherits = new Set<typeof Schema>();
24
+ TypeContext.inheritedTypes.set(parent, inherits);
25
+ }
26
+ inherits.add(target);
27
+ }
28
+ }
29
+
30
+ constructor(rootClass?: typeof Schema) {
31
+ if (rootClass) {
32
+ this.discoverTypes(rootClass);
33
+ }
34
+ }
35
+
36
+ has(schema: typeof Schema) {
37
+ return this.schemas.has(schema);
38
+ }
39
+
40
+ get(typeid: number) {
41
+ return this.types[typeid];
42
+ }
43
+
44
+ add(schema: typeof Schema, typeid: number = this.schemas.size) {
45
+ // skip if already registered
46
+ if (this.schemas.has(schema)) {
47
+ return false;
48
+ }
49
+
50
+ this.types[typeid] = schema;
51
+
52
+ //
53
+ // Workaround to allow using an empty Schema (with no `@type()` fields)
54
+ //
55
+ if (schema[Symbol.metadata] === undefined) {
56
+ Metadata.initialize(schema);
57
+ }
58
+
59
+ this.schemas.set(schema, typeid);
60
+ return true;
61
+ }
62
+
63
+ getTypeId(klass: typeof Schema) {
64
+ return this.schemas.get(klass);
65
+ }
66
+
67
+ private discoverTypes(klass: typeof Schema, parentIndex?: number, parentFieldViewTag?: number) {
68
+ if (!this.add(klass)) {
69
+ return;
70
+ }
71
+
72
+ // add classes inherited from this base class
73
+ TypeContext.inheritedTypes.get(klass)?.forEach((child) => {
74
+ this.discoverTypes(child, parentIndex, parentFieldViewTag);
75
+ });
76
+
77
+ // add parent classes
78
+ let parent: any = klass;
79
+ while (
80
+ (parent = Object.getPrototypeOf(parent)) &&
81
+ parent !== Schema && // stop at root (Schema)
82
+ parent !== Function.prototype // stop at root (non-Schema)
83
+ ) {
84
+ this.discoverTypes(parent);
85
+ }
86
+
87
+ const metadata: Metadata = (klass[Symbol.metadata] ??= {});
88
+
89
+ // if any schema/field has filters, mark "context" as having filters.
90
+ if (metadata[$viewFieldIndexes]) {
91
+ this.hasFilters = true;
92
+ }
93
+
94
+ if (parentFieldViewTag !== undefined) {
95
+ this.parentFiltered[`${this.schemas.get(klass)}-${parentIndex}`] = true;
96
+ }
97
+
98
+ for (const fieldIndex in metadata) {
99
+ const index = fieldIndex as any as number;
100
+
101
+ const fieldType = metadata[index].type;
102
+ const viewTag = metadata[index].tag;
103
+
104
+ if (typeof (fieldType) === "string") {
105
+ continue;
106
+ }
107
+
108
+ if (Array.isArray(fieldType)) {
109
+ const type = fieldType[0];
110
+
111
+ // skip primitive types
112
+ if (type === "string") {
113
+ continue;
114
+ }
115
+
116
+ this.discoverTypes(type as typeof Schema, index, viewTag);
117
+
118
+ } else if (typeof (fieldType) === "function") {
119
+ this.discoverTypes(fieldType as typeof Schema, viewTag);
120
+
121
+ } else {
122
+ const type = Object.values(fieldType)[0];
123
+
124
+ // skip primitive types
125
+ if (typeof (type) === "string") {
126
+ continue;
127
+ }
128
+
129
+ this.discoverTypes(type as typeof Schema, index, viewTag);
130
+ }
131
+ }
132
+ }
133
+ }