@simplysm/core-common 13.0.100 → 14.0.4

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 (184) hide show
  1. package/README.md +86 -92
  2. package/dist/common.types.d.ts +14 -14
  3. package/dist/common.types.js +2 -1
  4. package/dist/common.types.js.map +1 -6
  5. package/dist/env.d.ts +8 -1
  6. package/dist/env.d.ts.map +1 -1
  7. package/dist/env.js +13 -9
  8. package/dist/env.js.map +1 -6
  9. package/dist/errors/argument-error.d.ts +10 -10
  10. package/dist/errors/argument-error.d.ts.map +1 -1
  11. package/dist/errors/argument-error.js +31 -14
  12. package/dist/errors/argument-error.js.map +1 -6
  13. package/dist/errors/not-implemented-error.d.ts +8 -8
  14. package/dist/errors/not-implemented-error.js +30 -12
  15. package/dist/errors/not-implemented-error.js.map +1 -6
  16. package/dist/errors/sd-error.d.ts +10 -10
  17. package/dist/errors/sd-error.d.ts.map +1 -1
  18. package/dist/errors/sd-error.js +45 -24
  19. package/dist/errors/sd-error.js.map +1 -6
  20. package/dist/errors/timeout-error.d.ts +10 -10
  21. package/dist/errors/timeout-error.js +34 -15
  22. package/dist/errors/timeout-error.js.map +1 -6
  23. package/dist/extensions/arr-ext.d.ts +2 -2
  24. package/dist/extensions/arr-ext.helpers.d.ts +10 -10
  25. package/dist/extensions/arr-ext.helpers.js +112 -89
  26. package/dist/extensions/arr-ext.helpers.js.map +1 -6
  27. package/dist/extensions/arr-ext.js +458 -422
  28. package/dist/extensions/arr-ext.js.map +1 -6
  29. package/dist/extensions/arr-ext.types.d.ts +57 -57
  30. package/dist/extensions/arr-ext.types.d.ts.map +1 -1
  31. package/dist/extensions/arr-ext.types.js +6 -1
  32. package/dist/extensions/arr-ext.types.js.map +1 -6
  33. package/dist/extensions/map-ext.d.ts +16 -16
  34. package/dist/extensions/map-ext.js +27 -22
  35. package/dist/extensions/map-ext.js.map +1 -6
  36. package/dist/extensions/set-ext.d.ts +11 -11
  37. package/dist/extensions/set-ext.js +32 -25
  38. package/dist/extensions/set-ext.js.map +1 -6
  39. package/dist/features/debounce-queue.d.ts +17 -17
  40. package/dist/features/debounce-queue.js +98 -70
  41. package/dist/features/debounce-queue.js.map +1 -6
  42. package/dist/features/event-emitter.d.ts +20 -20
  43. package/dist/features/event-emitter.js +101 -78
  44. package/dist/features/event-emitter.js.map +1 -6
  45. package/dist/features/serial-queue.d.ts +11 -11
  46. package/dist/features/serial-queue.js +78 -57
  47. package/dist/features/serial-queue.js.map +1 -6
  48. package/dist/globals.d.ts +4 -4
  49. package/dist/globals.js +9 -1
  50. package/dist/globals.js.map +1 -6
  51. package/dist/index.js +28 -27
  52. package/dist/index.js.map +1 -6
  53. package/dist/types/date-only.d.ts +64 -64
  54. package/dist/types/date-only.d.ts.map +1 -1
  55. package/dist/types/date-only.js +263 -252
  56. package/dist/types/date-only.js.map +1 -6
  57. package/dist/types/date-time.d.ts +36 -36
  58. package/dist/types/date-time.d.ts.map +1 -1
  59. package/dist/types/date-time.js +196 -288
  60. package/dist/types/date-time.js.map +1 -6
  61. package/dist/types/lazy-gc-map.d.ts +26 -26
  62. package/dist/types/lazy-gc-map.d.ts.map +1 -1
  63. package/dist/types/lazy-gc-map.js +202 -159
  64. package/dist/types/lazy-gc-map.js.map +1 -6
  65. package/dist/types/time.d.ts +23 -23
  66. package/dist/types/time.d.ts.map +1 -1
  67. package/dist/types/time.js +169 -158
  68. package/dist/types/time.js.map +1 -6
  69. package/dist/types/uuid.d.ts +11 -11
  70. package/dist/types/uuid.d.ts.map +1 -1
  71. package/dist/types/uuid.js +95 -70
  72. package/dist/types/uuid.js.map +1 -6
  73. package/dist/utils/bytes.d.ts +17 -17
  74. package/dist/utils/bytes.js +137 -81
  75. package/dist/utils/bytes.js.map +1 -6
  76. package/dist/utils/date-format.d.ts +40 -40
  77. package/dist/utils/date-format.js +187 -101
  78. package/dist/utils/date-format.js.map +1 -6
  79. package/dist/utils/error.d.ts +4 -4
  80. package/dist/utils/error.js +11 -6
  81. package/dist/utils/error.js.map +1 -6
  82. package/dist/utils/json.d.ts +19 -19
  83. package/dist/utils/json.js +187 -135
  84. package/dist/utils/json.js.map +1 -6
  85. package/dist/utils/num.d.ts +20 -20
  86. package/dist/utils/num.js +76 -34
  87. package/dist/utils/num.js.map +1 -6
  88. package/dist/utils/obj.d.ts +111 -111
  89. package/dist/utils/obj.d.ts.map +1 -1
  90. package/dist/utils/obj.js +706 -496
  91. package/dist/utils/obj.js.map +1 -6
  92. package/dist/utils/path.d.ts +10 -10
  93. package/dist/utils/path.js +35 -18
  94. package/dist/utils/path.js.map +1 -6
  95. package/dist/utils/primitive.d.ts +5 -5
  96. package/dist/utils/primitive.js +34 -14
  97. package/dist/utils/primitive.js.map +1 -6
  98. package/dist/utils/str.d.ts +38 -38
  99. package/dist/utils/str.js +217 -113
  100. package/dist/utils/str.js.map +1 -6
  101. package/dist/utils/template-strings.d.ts +26 -26
  102. package/dist/utils/template-strings.js +113 -40
  103. package/dist/utils/template-strings.js.map +1 -6
  104. package/dist/utils/transferable.d.ts +18 -18
  105. package/dist/utils/transferable.js +218 -151
  106. package/dist/utils/transferable.js.map +1 -6
  107. package/dist/utils/wait.d.ts +9 -9
  108. package/dist/utils/wait.js +30 -15
  109. package/dist/utils/wait.js.map +1 -6
  110. package/dist/utils/xml.d.ts +13 -13
  111. package/dist/utils/xml.js +84 -46
  112. package/dist/utils/xml.js.map +1 -6
  113. package/dist/utils/zip.d.ts +22 -22
  114. package/dist/utils/zip.js +172 -148
  115. package/dist/utils/zip.js.map +1 -6
  116. package/docs/array-extensions.md +430 -0
  117. package/docs/env.md +52 -0
  118. package/docs/errors.md +41 -56
  119. package/docs/features.md +82 -97
  120. package/docs/type-utilities.md +91 -0
  121. package/docs/types.md +221 -201
  122. package/docs/utils.md +319 -435
  123. package/package.json +7 -5
  124. package/src/common.types.ts +14 -14
  125. package/src/env.ts +12 -3
  126. package/src/errors/argument-error.ts +15 -15
  127. package/src/errors/not-implemented-error.ts +9 -9
  128. package/src/errors/sd-error.ts +12 -12
  129. package/src/errors/timeout-error.ts +12 -12
  130. package/src/extensions/arr-ext.helpers.ts +16 -16
  131. package/src/extensions/arr-ext.ts +35 -35
  132. package/src/extensions/arr-ext.types.ts +57 -57
  133. package/src/extensions/map-ext.ts +16 -16
  134. package/src/extensions/set-ext.ts +11 -11
  135. package/src/features/debounce-queue.ts +23 -23
  136. package/src/features/event-emitter.ts +25 -25
  137. package/src/features/serial-queue.ts +13 -13
  138. package/src/globals.ts +4 -4
  139. package/src/index.ts +5 -5
  140. package/src/types/date-only.ts +84 -83
  141. package/src/types/date-time.ts +43 -42
  142. package/src/types/lazy-gc-map.ts +44 -44
  143. package/src/types/time.ts +29 -29
  144. package/src/types/uuid.ts +15 -15
  145. package/src/utils/bytes.ts +35 -35
  146. package/src/utils/date-format.ts +59 -59
  147. package/src/utils/error.ts +4 -4
  148. package/src/utils/json.ts +41 -41
  149. package/src/utils/num.ts +20 -20
  150. package/src/utils/obj.ts +138 -138
  151. package/src/utils/path.ts +10 -10
  152. package/src/utils/primitive.ts +6 -6
  153. package/src/utils/str.ts +48 -48
  154. package/src/utils/template-strings.ts +29 -29
  155. package/src/utils/transferable.ts +38 -38
  156. package/src/utils/wait.ts +10 -10
  157. package/src/utils/xml.ts +19 -19
  158. package/src/utils/zip.ts +25 -25
  159. package/docs/extensions.md +0 -387
  160. package/tests/errors/errors.spec.ts +0 -80
  161. package/tests/extensions/array-extension.spec.ts +0 -654
  162. package/tests/extensions/map-extension.spec.ts +0 -117
  163. package/tests/extensions/set-extension.spec.ts +0 -67
  164. package/tests/types/date-only.spec.ts +0 -533
  165. package/tests/types/date-time.spec.ts +0 -246
  166. package/tests/types/lazy-gc-map.spec.ts +0 -606
  167. package/tests/types/time.spec.ts +0 -428
  168. package/tests/types/uuid.spec.ts +0 -74
  169. package/tests/utils/bytes-utils.spec.ts +0 -197
  170. package/tests/utils/date-format.spec.ts +0 -350
  171. package/tests/utils/debounce-queue.spec.ts +0 -226
  172. package/tests/utils/json.spec.ts +0 -400
  173. package/tests/utils/number.spec.ts +0 -136
  174. package/tests/utils/object.spec.ts +0 -810
  175. package/tests/utils/path.spec.ts +0 -70
  176. package/tests/utils/primitive.spec.ts +0 -43
  177. package/tests/utils/sd-event-emitter.spec.ts +0 -189
  178. package/tests/utils/serial-queue.spec.ts +0 -305
  179. package/tests/utils/string.spec.ts +0 -265
  180. package/tests/utils/template-strings.spec.ts +0 -48
  181. package/tests/utils/transferable.spec.ts +0 -639
  182. package/tests/utils/wait.spec.ts +0 -123
  183. package/tests/utils/xml.spec.ts +0 -146
  184. package/tests/utils/zip.spec.ts +0 -221
@@ -1,639 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { transfer, DateTime, DateOnly, Time, Uuid } from "@simplysm/core-common";
3
-
4
- describe("TransferableConvert", () => {
5
- //#region encode - Special types
6
-
7
- describe("encode() - Special types", () => {
8
- it("Encodes DateTime", () => {
9
- const dt = new DateTime(2025, 1, 6, 15, 30, 45, 123);
10
- const { result } = transfer.encode(dt);
11
-
12
- expect(result).toEqual({
13
- __type__: "DateTime",
14
- data: dt.tick,
15
- });
16
- });
17
-
18
- it("Encodes DateOnly", () => {
19
- const d = new DateOnly(2025, 1, 6);
20
- const { result } = transfer.encode(d);
21
-
22
- expect(result).toEqual({
23
- __type__: "DateOnly",
24
- data: d.tick,
25
- });
26
- });
27
-
28
- it("Encodes Time", () => {
29
- const t = new Time(15, 30, 45, 123);
30
- const { result } = transfer.encode(t);
31
-
32
- expect(result).toEqual({
33
- __type__: "Time",
34
- data: t.tick,
35
- });
36
- });
37
-
38
- it("Encodes Uuid", () => {
39
- const uuid = Uuid.generate();
40
- const { result } = transfer.encode(uuid);
41
-
42
- expect(result).toEqual({
43
- __type__: "Uuid",
44
- data: uuid.toString(),
45
- });
46
- });
47
-
48
- it("Encodes Error", () => {
49
- const err = new Error("test error");
50
- err.stack = "test stack";
51
- const { result } = transfer.encode(err);
52
-
53
- expect(result).toEqual({
54
- __type__: "Error",
55
- data: {
56
- name: "Error",
57
- message: "test error",
58
- stack: "test stack",
59
- },
60
- });
61
- });
62
-
63
- it("Recursively encodes Error cause", () => {
64
- const cause = new Error("cause error");
65
- const err = new Error("main error", { cause });
66
- const { result } = transfer.encode(err);
67
-
68
- const typedResult = result as {
69
- __type__: string;
70
- data: {
71
- name: string;
72
- message: string;
73
- cause?: {
74
- __type__: string;
75
- data: {
76
- name: string;
77
- message: string;
78
- };
79
- };
80
- };
81
- };
82
-
83
- expect(typedResult.data.cause).toEqual({
84
- __type__: "Error",
85
- data: {
86
- name: "Error",
87
- message: "cause error",
88
- stack: cause.stack,
89
- },
90
- });
91
- });
92
-
93
- it("Encodes Error code property", () => {
94
- const err = new Error("test error") as Error & { code: string };
95
- err.code = "ERR_CUSTOM";
96
- const { result } = transfer.encode(err);
97
-
98
- const typedResult = result as {
99
- __type__: string;
100
- data: {
101
- name: string;
102
- message: string;
103
- code?: string;
104
- };
105
- };
106
-
107
- expect(typedResult.data.code).toBe("ERR_CUSTOM");
108
- });
109
-
110
- it("Encodes Error detail property", () => {
111
- const err = new Error("test error") as Error & { detail: unknown };
112
- err.detail = { userId: 123, action: "delete" };
113
- const { result } = transfer.encode(err);
114
-
115
- const typedResult = result as {
116
- __type__: string;
117
- data: {
118
- name: string;
119
- message: string;
120
- detail?: unknown;
121
- };
122
- };
123
-
124
- expect(typedResult.data.detail).toEqual({ userId: 123, action: "delete" });
125
- });
126
-
127
- it("Encodes special types in Error detail", () => {
128
- const err = new Error("test error") as Error & { detail: unknown };
129
- const dt = new DateTime(2025, 1, 6);
130
- err.detail = { timestamp: dt };
131
- const { result } = transfer.encode(err);
132
-
133
- const typedResult = result as {
134
- __type__: string;
135
- data: {
136
- name: string;
137
- message: string;
138
- detail?: { timestamp: { __type__: string; data: number } };
139
- };
140
- };
141
-
142
- expect(typedResult.data.detail?.timestamp).toEqual({
143
- __type__: "DateTime",
144
- data: dt.tick,
145
- });
146
- });
147
-
148
- it("Encodes Uint8Array and adds to transferList", () => {
149
- const bytes = new TextEncoder().encode("hello");
150
- const { result, transferList } = transfer.encode(bytes);
151
-
152
- expect(result).toBe(bytes);
153
- expect(transferList).toContain(bytes.buffer);
154
- });
155
-
156
- it("Encodes Date", () => {
157
- const date = new Date(2025, 0, 6, 15, 30, 45, 123);
158
- const { result } = transfer.encode(date);
159
-
160
- expect(result).toEqual({
161
- __type__: "Date",
162
- data: date.getTime(),
163
- });
164
- });
165
-
166
- it("Encodes RegExp", () => {
167
- const regex = /test\d+/gi;
168
- const { result } = transfer.encode(regex);
169
-
170
- expect(result).toEqual({
171
- __type__: "RegExp",
172
- data: { source: "test\\d+", flags: "gi" },
173
- });
174
- });
175
- });
176
-
177
- //#endregion
178
-
179
- //#region encode - Collections
180
-
181
- describe("encode() - Collections", () => {
182
- it("Recursively encodes array", () => {
183
- const arr = [new DateTime(2025, 1, 6), Uuid.generate(), "string", 123] as const;
184
- const { result } = transfer.encode(arr);
185
-
186
- expect(Array.isArray(result)).toBe(true);
187
- const resultArr = result as unknown[];
188
- expect(resultArr).toHaveLength(4);
189
- expect(resultArr[0]).toMatchObject({ __type__: "DateTime" });
190
- expect(resultArr[1]).toMatchObject({ __type__: "Uuid" });
191
- expect(resultArr[2]).toBe("string");
192
- expect(resultArr[3]).toBe(123);
193
- });
194
-
195
- it("Recursively encodes Map", () => {
196
- const map = new Map<string, DateTime | Uuid>([
197
- ["key1", new DateTime(2025, 1, 6)],
198
- ["key2", Uuid.generate()],
199
- ]);
200
- const { result } = transfer.encode(map);
201
-
202
- expect(result instanceof Map).toBe(true);
203
- const resultMap = result as Map<string, unknown>;
204
- expect(resultMap.size).toBe(2);
205
- expect(resultMap.get("key1")).toMatchObject({ __type__: "DateTime" });
206
- expect(resultMap.get("key2")).toMatchObject({ __type__: "Uuid" });
207
- });
208
-
209
- it("Recursively encodes Set", () => {
210
- const set = new Set([new DateTime(2025, 1, 6), Uuid.generate()]);
211
- const { result } = transfer.encode(set);
212
-
213
- expect(result instanceof Set).toBe(true);
214
- const resultSet = result as Set<unknown>;
215
- expect(resultSet.size).toBe(2);
216
- const arr = Array.from(resultSet);
217
- expect(arr[0]).toMatchObject({ __type__: "DateTime" });
218
- expect(arr[1]).toMatchObject({ __type__: "Uuid" });
219
- });
220
-
221
- it("Recursively encodes nested object", () => {
222
- const obj = {
223
- dt: new DateTime(2025, 1, 6),
224
- nested: {
225
- uuid: Uuid.generate(),
226
- arr: [new DateOnly(2025, 1, 6)],
227
- },
228
- };
229
- const { result } = transfer.encode(obj);
230
-
231
- const typedResult = result as {
232
- dt: { __type__: string };
233
- nested: {
234
- uuid: { __type__: string };
235
- arr: { __type__: string }[];
236
- };
237
- };
238
-
239
- expect(typedResult.dt).toMatchObject({ __type__: "DateTime" });
240
- expect(typedResult.nested.uuid).toMatchObject({ __type__: "Uuid" });
241
- expect(typedResult.nested.arr[0]).toMatchObject({ __type__: "DateOnly" });
242
- });
243
- });
244
-
245
- //#endregion
246
-
247
- //#region encode - Circular reference detection
248
-
249
- describe("encode() - Circular reference detection", () => {
250
- it("Throws TypeError when encoding self-referencing object", () => {
251
- const obj: Record<string, unknown> = { a: 1 };
252
- obj["self"] = obj;
253
-
254
- expect(() => transfer.encode(obj)).toThrow(TypeError);
255
- expect(() => transfer.encode(obj)).toThrow("Circular reference detected");
256
- });
257
-
258
- it("Detects nested circular references", () => {
259
- const a: Record<string, unknown> = { name: "a" };
260
- const b: Record<string, unknown> = { name: "b", ref: a };
261
- a["ref"] = b;
262
-
263
- expect(() => transfer.encode(a)).toThrow("Circular reference detected");
264
- });
265
-
266
- it("Detects circular references in array", () => {
267
- const arr: unknown[] = [1, 2, 3];
268
- arr.push(arr);
269
-
270
- expect(() => transfer.encode(arr)).toThrow("Circular reference detected");
271
- });
272
- });
273
-
274
- //#endregion
275
-
276
- //#region encode - DAG (Shared objects)
277
-
278
- describe("encode() - DAG (Shared objects)", () => {
279
- it("Encodes without error when same object is referenced from multiple places", () => {
280
- const shared = { name: "shared" };
281
- const data = { a: shared, b: shared };
282
- const { result } = transfer.encode(data);
283
- const decoded = result as Record<string, Record<string, string>>;
284
- expect(decoded["a"]["name"]).toBe("shared");
285
- expect(decoded["b"]["name"]).toBe("shared");
286
- });
287
-
288
- it("Encodes without error when same array is referenced from multiple places", () => {
289
- const sharedArr = [1, 2, 3];
290
- const data = { x: sharedArr, y: sharedArr };
291
- const { result } = transfer.encode(data);
292
- const decoded = result as Record<string, number[]>;
293
- expect(decoded["x"]).toEqual([1, 2, 3]);
294
- expect(decoded["y"]).toEqual([1, 2, 3]);
295
- });
296
- });
297
-
298
- //#endregion
299
-
300
- //#region decode - Special types
301
-
302
- describe("decode() - Special types", () => {
303
- it("Decodes DateTime", () => {
304
- const tick = new DateTime(2025, 1, 6, 15, 30, 45, 123).tick;
305
- const encoded = { __type__: "DateTime", data: tick };
306
- const decoded = transfer.decode(encoded);
307
-
308
- expect(decoded instanceof DateTime).toBe(true);
309
- const dt = decoded as DateTime;
310
- expect(dt.year).toBe(2025);
311
- expect(dt.month).toBe(1);
312
- expect(dt.day).toBe(6);
313
- expect(dt.hour).toBe(15);
314
- expect(dt.minute).toBe(30);
315
- expect(dt.second).toBe(45);
316
- expect(dt.millisecond).toBe(123);
317
- });
318
-
319
- it("Decodes DateOnly", () => {
320
- const tick = new DateOnly(2025, 1, 6).tick;
321
- const encoded = { __type__: "DateOnly", data: tick };
322
- const decoded = transfer.decode(encoded);
323
-
324
- expect(decoded instanceof DateOnly).toBe(true);
325
- const d = decoded as DateOnly;
326
- expect(d.year).toBe(2025);
327
- expect(d.month).toBe(1);
328
- expect(d.day).toBe(6);
329
- });
330
-
331
- it("Decodes Time", () => {
332
- const tick = new Time(15, 30, 45, 123).tick;
333
- const encoded = { __type__: "Time", data: tick };
334
- const decoded = transfer.decode(encoded);
335
-
336
- expect(decoded instanceof Time).toBe(true);
337
- const t = decoded as Time;
338
- expect(t.hour).toBe(15);
339
- expect(t.minute).toBe(30);
340
- expect(t.second).toBe(45);
341
- expect(t.millisecond).toBe(123);
342
- });
343
-
344
- it("Decodes Uuid", () => {
345
- const uuid = Uuid.generate();
346
- const encoded = { __type__: "Uuid", data: uuid.toString() };
347
- const decoded = transfer.decode(encoded);
348
-
349
- expect(decoded instanceof Uuid).toBe(true);
350
- expect((decoded as Uuid).toString()).toBe(uuid.toString());
351
- });
352
-
353
- it("Decodes Error", () => {
354
- const encoded = {
355
- __type__: "Error",
356
- data: {
357
- name: "CustomError",
358
- message: "test error",
359
- stack: "test stack",
360
- },
361
- };
362
- const decoded = transfer.decode(encoded);
363
-
364
- expect(decoded instanceof Error).toBe(true);
365
- const err = decoded as Error;
366
- expect(err.name).toBe("CustomError");
367
- expect(err.message).toBe("test error");
368
- expect(err.stack).toBe("test stack");
369
- });
370
-
371
- it("Recursively decodes Error cause", () => {
372
- const encoded = {
373
- __type__: "Error",
374
- data: {
375
- name: "Error",
376
- message: "main error",
377
- cause: {
378
- __type__: "Error",
379
- data: {
380
- name: "Error",
381
- message: "cause error",
382
- },
383
- },
384
- },
385
- };
386
- const decoded = transfer.decode(encoded);
387
-
388
- expect(decoded instanceof Error).toBe(true);
389
- const err = decoded as Error;
390
- expect(err.message).toBe("main error");
391
- expect(err.cause instanceof Error).toBe(true);
392
- expect((err.cause as Error).message).toBe("cause error");
393
- });
394
-
395
- it("Decodes Error code property", () => {
396
- const encoded = {
397
- __type__: "Error",
398
- data: {
399
- name: "Error",
400
- message: "test error",
401
- code: "ERR_CUSTOM",
402
- },
403
- };
404
- const decoded = transfer.decode(encoded);
405
-
406
- expect(decoded instanceof Error).toBe(true);
407
- const err = decoded as Error & { code?: string };
408
- expect(err.code).toBe("ERR_CUSTOM");
409
- });
410
-
411
- it("Decodes Error detail property", () => {
412
- const encoded = {
413
- __type__: "Error",
414
- data: {
415
- name: "Error",
416
- message: "test error",
417
- detail: { userId: 123, action: "delete" },
418
- },
419
- };
420
- const decoded = transfer.decode(encoded);
421
-
422
- expect(decoded instanceof Error).toBe(true);
423
- const err = decoded as Error & { detail?: unknown };
424
- expect(err.detail).toEqual({ userId: 123, action: "delete" });
425
- });
426
-
427
- it("Decodes special types in Error detail", () => {
428
- const tick = new DateTime(2025, 1, 6).tick;
429
- const encoded = {
430
- __type__: "Error",
431
- data: {
432
- name: "Error",
433
- message: "test error",
434
- detail: { timestamp: { __type__: "DateTime", data: tick } },
435
- },
436
- };
437
- const decoded = transfer.decode(encoded);
438
-
439
- expect(decoded instanceof Error).toBe(true);
440
- const err = decoded as Error & { detail?: { timestamp: DateTime } };
441
- expect(err.detail?.timestamp instanceof DateTime).toBe(true);
442
- expect(err.detail?.timestamp.tick).toBe(tick);
443
- });
444
-
445
- it("Decodes Date", () => {
446
- const tick = new Date(2025, 0, 6, 15, 30, 45, 123).getTime();
447
- const encoded = { __type__: "Date", data: tick };
448
- const decoded = transfer.decode(encoded);
449
-
450
- expect(decoded instanceof Date).toBe(true);
451
- const date = decoded as Date;
452
- expect(date.getFullYear()).toBe(2025);
453
- expect(date.getMonth()).toBe(0);
454
- expect(date.getDate()).toBe(6);
455
- expect(date.getHours()).toBe(15);
456
- expect(date.getMinutes()).toBe(30);
457
- expect(date.getSeconds()).toBe(45);
458
- expect(date.getMilliseconds()).toBe(123);
459
- });
460
-
461
- it("Decodes RegExp", () => {
462
- const encoded = {
463
- __type__: "RegExp",
464
- data: { source: "test\\d+", flags: "gi" },
465
- };
466
- const decoded = transfer.decode(encoded);
467
-
468
- expect(decoded instanceof RegExp).toBe(true);
469
- const regex = decoded as RegExp;
470
- expect(regex.source).toBe("test\\d+");
471
- expect(regex.flags).toBe("gi");
472
- // RegExp with g flag is stateful, so reset lastIndex before testing
473
- expect(regex.test("test123")).toBe(true);
474
- regex.lastIndex = 0;
475
- expect(regex.test("TEST456")).toBe(true);
476
- });
477
- });
478
-
479
- //#endregion
480
-
481
- //#region decode - Collections
482
-
483
- describe("decode() - Collections", () => {
484
- it("Recursively decodes array", () => {
485
- const tick = new DateTime(2025, 1, 6).tick;
486
- const uuidStr = Uuid.generate().toString();
487
- const encoded = [
488
- { __type__: "DateTime", data: tick },
489
- { __type__: "Uuid", data: uuidStr },
490
- "string",
491
- 123,
492
- ];
493
- const decoded = transfer.decode(encoded);
494
-
495
- expect(Array.isArray(decoded)).toBe(true);
496
- const arr = decoded as unknown[];
497
- expect(arr[0] instanceof DateTime).toBe(true);
498
- expect(arr[1] instanceof Uuid).toBe(true);
499
- expect(arr[2]).toBe("string");
500
- expect(arr[3]).toBe(123);
501
- });
502
-
503
- it("Recursively decodes Map", () => {
504
- const tick = new DateTime(2025, 1, 6).tick;
505
- const encoded = new Map<string, unknown>([
506
- ["key1", { __type__: "DateTime", data: tick }],
507
- ["key2", "value"],
508
- ]);
509
- const decoded = transfer.decode(encoded);
510
-
511
- expect(decoded instanceof Map).toBe(true);
512
- const map = decoded as Map<string, unknown>;
513
- expect(map.get("key1") instanceof DateTime).toBe(true);
514
- expect(map.get("key2")).toBe("value");
515
- });
516
-
517
- it("Recursively decodes Set", () => {
518
- const tick = new DateTime(2025, 1, 6).tick;
519
- const encoded = new Set([{ __type__: "DateTime", data: tick }, "string"]);
520
- const decoded = transfer.decode(encoded);
521
-
522
- expect(decoded instanceof Set).toBe(true);
523
- const set = decoded as Set<unknown>;
524
- const arr = Array.from(set);
525
- expect(arr[0] instanceof DateTime).toBe(true);
526
- expect(arr[1]).toBe("string");
527
- });
528
-
529
- it("Recursively decodes nested object", () => {
530
- const dtTick = new DateTime(2025, 1, 6).tick;
531
- const uuidStr = Uuid.generate().toString();
532
- const dTick = new DateOnly(2025, 1, 6).tick;
533
- const encoded = {
534
- dt: { __type__: "DateTime", data: dtTick },
535
- nested: {
536
- uuid: { __type__: "Uuid", data: uuidStr },
537
- arr: [{ __type__: "DateOnly", data: dTick }],
538
- },
539
- };
540
- const decoded = transfer.decode(encoded);
541
-
542
- const obj = decoded as {
543
- dt: DateTime;
544
- nested: {
545
- uuid: Uuid;
546
- arr: DateOnly[];
547
- };
548
- };
549
-
550
- expect(obj.dt instanceof DateTime).toBe(true);
551
- expect(obj.nested.uuid instanceof Uuid).toBe(true);
552
- expect(obj.nested.arr[0] instanceof DateOnly).toBe(true);
553
- });
554
- });
555
-
556
- //#endregion
557
-
558
- //#region decode - Preserve original
559
-
560
- describe("decode() - Preserve original", () => {
561
- it("Original object is not modified", () => {
562
- const tick = new DateTime(2025, 1, 6).tick;
563
- const original = {
564
- dt: { __type__: "DateTime", data: tick },
565
- value: 123,
566
- };
567
- const originalCopy = JSON.stringify(original);
568
-
569
- transfer.decode(original);
570
-
571
- // Verify original is not modified
572
- expect(JSON.stringify(original)).toBe(originalCopy);
573
- expect(original.dt).toEqual({ __type__: "DateTime", data: tick });
574
- expect(original.value).toBe(123);
575
- });
576
-
577
- it("Decode result is a new instance (different from original)", () => {
578
- const tick = new DateTime(2025, 1, 6).tick;
579
- const original = [{ __type__: "DateTime", data: tick }];
580
-
581
- const decoded = transfer.decode(original);
582
-
583
- // Result is a new array
584
- expect(decoded).not.toBe(original);
585
- // Array contents are converted
586
- expect(Array.isArray(decoded)).toBe(true);
587
- expect((decoded as unknown[])[0] instanceof DateTime).toBe(true);
588
- });
589
- });
590
-
591
- //#endregion
592
-
593
- //#region Round-trip conversion (encode → decode)
594
-
595
- describe("Round-trip conversion (encode → decode)", () => {
596
- it("Round-trips DateTime", () => {
597
- const original = new DateTime(2025, 1, 6, 15, 30, 45, 123);
598
- const { result } = transfer.encode(original);
599
- const decoded = transfer.decode(result) as DateTime;
600
-
601
- expect(decoded.tick).toBe(original.tick);
602
- });
603
-
604
- it("Round-trips complex object", () => {
605
- const original = {
606
- dt: new DateTime(2025, 1, 6),
607
- d: new DateOnly(2025, 1, 6),
608
- t: new Time(15, 30, 45),
609
- uuid: Uuid.generate(),
610
- arr: [new DateTime(2024, 12, 31)],
611
- map: new Map([["key", new DateOnly(2025, 1, 1)]]),
612
- set: new Set([new Time(12, 0, 0)]),
613
- };
614
-
615
- const { result } = transfer.encode(original);
616
- const decoded = transfer.decode(result) as typeof original;
617
-
618
- expect(decoded.dt instanceof DateTime).toBe(true);
619
- expect(decoded.d instanceof DateOnly).toBe(true);
620
- expect(decoded.t instanceof Time).toBe(true);
621
- expect(decoded.uuid instanceof Uuid).toBe(true);
622
- expect(decoded.arr[0] instanceof DateTime).toBe(true);
623
- expect(decoded.map.get("key") instanceof DateOnly).toBe(true);
624
- expect(Array.from(decoded.set)[0] instanceof Time).toBe(true);
625
- });
626
-
627
- it("Round-trips RegExp", () => {
628
- const original = /test\d+/gi;
629
- const { result } = transfer.encode(original);
630
- const decoded = transfer.decode(result) as RegExp;
631
-
632
- expect(decoded instanceof RegExp).toBe(true);
633
- expect(decoded.source).toBe(original.source);
634
- expect(decoded.flags).toBe(original.flags);
635
- });
636
- });
637
-
638
- //#endregion
639
- });