@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,654 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import "@simplysm/core-common"; // Enable $ extension
3
-
4
- describe("Array prototype extensions", () => {
5
- //#region single
6
-
7
- describe("single()", () => {
8
- it("Returns single matching element", () => {
9
- const result = [1, 2, 3].single((x) => x === 2);
10
-
11
- expect(result).toBe(2);
12
- });
13
-
14
- it("Returns undefined if no matching element", () => {
15
- const result = [1, 2, 3].single((x) => x === 4);
16
-
17
- expect(result).toBe(undefined);
18
- });
19
-
20
- it("Throws error if multiple matching elements", () => {
21
- expect(() => [1, 1, 2].single((x) => x === 1)).toThrow();
22
- });
23
-
24
- it("Without condition, targets entire array", () => {
25
- expect([1].single()).toBe(1);
26
- expect(([] as number[]).single()).toBe(undefined);
27
- expect(() => [1, 2].single()).toThrow();
28
- });
29
- });
30
-
31
- //#endregion
32
-
33
- //#region Async methods
34
-
35
- describe("parallelAsync()", () => {
36
- it("Performs parallel async execution", async () => {
37
- const result = await [1, 2, 3].parallelAsync(async (x) => Promise.resolve(x * 2));
38
-
39
- expect(result).toEqual([2, 4, 6]);
40
- });
41
- });
42
-
43
- describe("mapAsync()", () => {
44
- it("Performs sequential async mapping", async () => {
45
- const result = await [1, 2, 3].mapAsync(async (x) => Promise.resolve(x * 2));
46
-
47
- expect(result).toEqual([2, 4, 6]);
48
- });
49
- });
50
-
51
- describe("filterAsync()", () => {
52
- it("Performs async filtering", async () => {
53
- const result = await [1, 2, 3, 4, 5].filterAsync(async (x) => Promise.resolve(x > 2));
54
-
55
- expect(result).toEqual([3, 4, 5]);
56
- });
57
- });
58
-
59
- //#endregion
60
-
61
- //#region Map conversion
62
-
63
- describe("toMap()", () => {
64
- it("Creates Map with key function", () => {
65
- const result = [
66
- { id: 1, name: "a" },
67
- { id: 2, name: "b" },
68
- ].toMap((x) => x.id);
69
-
70
- expect(result.get(1)).toEqual({ id: 1, name: "a" });
71
- expect(result.get(2)).toEqual({ id: 2, name: "b" });
72
- });
73
-
74
- it("Transforms values with value function", () => {
75
- const result = [
76
- { id: 1, name: "a" },
77
- { id: 2, name: "b" },
78
- ].toMap(
79
- (x) => x.id,
80
- (x) => x.name,
81
- );
82
-
83
- expect(result.get(1)).toBe("a");
84
- expect(result.get(2)).toBe("b");
85
- });
86
-
87
- it("Throws error on duplicate keys", () => {
88
- expect(() =>
89
- [
90
- { id: 1, name: "a" },
91
- { id: 1, name: "b" },
92
- ].toMap((x) => x.id),
93
- ).toThrow("Duplicated key");
94
- });
95
- });
96
-
97
- describe("toMapAsync()", () => {
98
- it("Creates Map with async key/value functions", async () => {
99
- const result = await [
100
- { id: 1, name: "a" },
101
- { id: 2, name: "b" },
102
- ].toMapAsync(async (x) => Promise.resolve(x.id));
103
-
104
- expect(result.get(1)).toEqual({ id: 1, name: "a" });
105
- expect(result.get(2)).toEqual({ id: 2, name: "b" });
106
- });
107
- });
108
-
109
- describe("toArrayMap()", () => {
110
- it("Creates Map with array values", () => {
111
- const result = [
112
- { type: "a", v: 1 },
113
- { type: "b", v: 2 },
114
- { type: "a", v: 3 },
115
- ].toArrayMap((x) => x.type);
116
-
117
- expect(result.get("a")).toHaveLength(2);
118
- expect(result.get("b")).toHaveLength(1);
119
- });
120
-
121
- it("Transforms values with value function", () => {
122
- const result = [
123
- { type: "a", v: 1 },
124
- { type: "a", v: 2 },
125
- ].toArrayMap(
126
- (x) => x.type,
127
- (x) => x.v,
128
- );
129
-
130
- expect(result.get("a")).toEqual([1, 2]);
131
- });
132
- });
133
-
134
- describe("toSetMap()", () => {
135
- it("Creates Map with Set values", () => {
136
- const result = [
137
- { type: "a", v: 1 },
138
- { type: "a", v: 1 }, // duplicate
139
- { type: "a", v: 2 },
140
- ].toSetMap(
141
- (x) => x.type,
142
- (x) => x.v,
143
- );
144
-
145
- expect(result.get("a")?.size).toBe(2); // duplicates removed
146
- });
147
- });
148
-
149
- describe("toMapValues()", () => {
150
- it("Creates Map with aggregated results per group", () => {
151
- const result = [
152
- { type: "a", v: 10 },
153
- { type: "b", v: 20 },
154
- { type: "a", v: 30 },
155
- ].toMapValues(
156
- (x) => x.type,
157
- (items) => items.reduce((sum, x) => sum + x.v, 0),
158
- );
159
-
160
- expect(result.get("a")).toBe(40);
161
- expect(result.get("b")).toBe(20);
162
- });
163
- });
164
-
165
- //#endregion
166
-
167
- //#region Tree conversion
168
-
169
- describe("toTree()", () => {
170
- it("Converts to tree structure", () => {
171
- interface Item {
172
- id: number;
173
- parentId?: number;
174
- name: string;
175
- }
176
-
177
- const items: Item[] = [
178
- { id: 1, name: "root" },
179
- { id: 2, parentId: 1, name: "child1" },
180
- { id: 3, parentId: 1, name: "child2" },
181
- { id: 4, parentId: 2, name: "grandchild" },
182
- ];
183
-
184
- const result = items.toTree("id", "parentId");
185
-
186
- expect(result).toHaveLength(1);
187
- expect(result[0].children).toHaveLength(2);
188
- expect(result[0].children[0].children).toHaveLength(1);
189
- });
190
- });
191
-
192
- //#endregion
193
-
194
- //#region Array comparison
195
-
196
- describe("diffs()", () => {
197
- it("Analyzes differences between arrays", () => {
198
- interface Item {
199
- [key: string]: unknown;
200
- id: number;
201
- value: string;
202
- }
203
-
204
- const source: Item[] = [
205
- { id: 1, value: "a" },
206
- { id: 2, value: "b" },
207
- { id: 3, value: "c" },
208
- ];
209
-
210
- const target: Item[] = [
211
- { id: 2, value: "b" },
212
- { id: 3, value: "changed" },
213
- { id: 4, value: "d" },
214
- ];
215
-
216
- const result = source.diffs(target, { keys: ["id"] });
217
-
218
- const deleted = result.find((d) => d.source?.["id"] === 1);
219
- expect(deleted?.target).toBe(undefined);
220
-
221
- const updated = result.find((d) => d.source?.["id"] === 3);
222
- expect(updated?.target?.["value"]).toBe("changed");
223
-
224
- const inserted = result.find((d) => d.target?.["id"] === 4);
225
- expect(inserted?.source).toBe(undefined);
226
- });
227
- });
228
-
229
- describe("oneWayDiffs()", () => {
230
- it("Analyzes one-way differences", () => {
231
- interface Item {
232
- id: number;
233
- value: string;
234
- }
235
-
236
- const orgItems: Item[] = [
237
- { id: 1, value: "a" },
238
- { id: 2, value: "b" },
239
- ];
240
-
241
- const items: Item[] = [
242
- { id: 2, value: "changed" },
243
- { id: 3, value: "c" },
244
- ];
245
-
246
- const result = items.oneWayDiffs(orgItems, "id");
247
-
248
- const updated = result.find((d) => d.item.id === 2);
249
- expect(updated?.type).toBe("update");
250
-
251
- const created = result.find((d) => d.item.id === 3);
252
- expect(created?.type).toBe("create");
253
- });
254
-
255
- it("Includes unchanged items when includeSame=true", () => {
256
- interface Item {
257
- id: number;
258
- value: string;
259
- }
260
-
261
- const orgItems: Item[] = [
262
- { id: 1, value: "a" },
263
- { id: 2, value: "b" },
264
- ];
265
-
266
- const items: Item[] = [
267
- { id: 1, value: "a" }, // unchanged
268
- { id: 2, value: "changed" },
269
- ];
270
-
271
- const result = items.oneWayDiffs(orgItems, "id", { includeSame: true });
272
-
273
- const same = result.find((d) => d.item.id === 1);
274
- expect(same?.type).toBe("same");
275
-
276
- const updated = result.find((d) => d.item.id === 2);
277
- expect(updated?.type).toBe("update");
278
- });
279
- });
280
-
281
- describe("merge()", () => {
282
- it("Merges modified items", () => {
283
- interface Item {
284
- [key: string]: unknown;
285
- id: number;
286
- value: string;
287
- }
288
-
289
- const source: Item[] = [
290
- { id: 1, value: "a" },
291
- { id: 2, value: "b" },
292
- ];
293
- const target: Item[] = [
294
- { id: 1, value: "a" },
295
- { id: 2, value: "changed" },
296
- ];
297
-
298
- const result = source.merge(target, { keys: ["id"] });
299
-
300
- expect(result).toHaveLength(2);
301
- expect(result.find((r) => r["id"] === 2)?.["value"]).toBe("changed");
302
- });
303
- });
304
-
305
- //#endregion
306
-
307
- //#region first, last
308
-
309
- describe("first()", () => {
310
- it("Returns first element", () => {
311
- expect([1, 2, 3].first()).toBe(1);
312
- });
313
-
314
- it("Returns first matching element", () => {
315
- expect([1, 2, 3, 4, 5].first((x) => x > 3)).toBe(4);
316
- });
317
-
318
- it("Returns undefined for empty array", () => {
319
- expect(([] as number[]).first()).toBe(undefined);
320
- });
321
- });
322
-
323
- describe("last()", () => {
324
- it("Returns last element", () => {
325
- expect([1, 2, 3].last()).toBe(3);
326
- });
327
-
328
- it("Returns last matching element", () => {
329
- expect([1, 2, 3, 4, 5].last((x) => x < 4)).toBe(3);
330
- });
331
-
332
- it("Returns undefined for empty array", () => {
333
- expect(([] as number[]).last()).toBe(undefined);
334
- });
335
- });
336
-
337
- //#endregion
338
-
339
- //#region filterExists, ofType
340
-
341
- describe("filterExists()", () => {
342
- it("Removes null/undefined", () => {
343
- const arr = [1, null, 2, undefined, 3];
344
- const result = arr.filterExists();
345
- expect(result).toEqual([1, 2, 3]);
346
- });
347
- });
348
-
349
- describe("ofType()", () => {
350
- it("Filters string type elements only", () => {
351
- const arr = [1, "a", 2, "b", true];
352
- const result = arr.ofType("string");
353
- expect(result).toEqual(["a", "b"]);
354
- });
355
-
356
- it("Filters number type elements only", () => {
357
- const arr = [1, "a", 2, "b", 3];
358
- const result = arr.ofType("number");
359
- expect(result).toEqual([1, 2, 3]);
360
- });
361
-
362
- it("Filters boolean type elements only", () => {
363
- const arr = [1, "a", true, false, 2];
364
- const result = arr.ofType("boolean");
365
- expect(result).toEqual([true, false]);
366
- });
367
- });
368
-
369
- //#endregion
370
-
371
- //#region mapMany
372
-
373
- describe("mapMany()", () => {
374
- it("Maps then flattens", () => {
375
- const result = [1, 2, 3].mapMany((x) => [x, x * 10]);
376
- expect(result).toEqual([1, 10, 2, 20, 3, 30]);
377
- });
378
- });
379
-
380
- describe("mapManyAsync()", () => {
381
- it("Async maps then flattens", async () => {
382
- const result = await [1, 2, 3].mapManyAsync(async (x) => Promise.resolve([x, x * 10]));
383
- expect(result).toEqual([1, 10, 2, 20, 3, 30]);
384
- });
385
-
386
- it("Async maps nested Promise array then flattens", async () => {
387
- const result = await [1, 2].mapManyAsync(async (x) => Promise.resolve([x, x + 1, x + 2]));
388
- expect(result).toEqual([1, 2, 3, 2, 3, 4]);
389
- });
390
- });
391
-
392
- //#endregion
393
-
394
- //#region groupBy
395
-
396
- describe("groupBy()", () => {
397
- it("Groups by key", () => {
398
- const items = [
399
- { type: "a", value: 1 },
400
- { type: "b", value: 2 },
401
- { type: "a", value: 3 },
402
- ];
403
- const result = items.groupBy((x) => x.type);
404
-
405
- expect(result).toHaveLength(2);
406
- expect(result.find((g) => g.key === "a")?.values).toHaveLength(2);
407
- expect(result.find((g) => g.key === "b")?.values).toHaveLength(1);
408
- });
409
- });
410
-
411
- //#endregion
412
-
413
- //#region toObject
414
-
415
- describe("toObject()", () => {
416
- it("Converts array to object", () => {
417
- const items = [
418
- { key: "a", value: 1 },
419
- { key: "b", value: 2 },
420
- ];
421
- const result = items.toObject(
422
- (x) => x.key,
423
- (x) => x.value,
424
- );
425
-
426
- expect(result).toEqual({ a: 1, b: 2 });
427
- });
428
-
429
- it("Throws error on duplicate keys", () => {
430
- const items = [
431
- { key: "a", value: 1 },
432
- { key: "a", value: 2 },
433
- ];
434
- expect(() => items.toObject((x) => x.key)).toThrow();
435
- });
436
- });
437
-
438
- //#endregion
439
-
440
- //#region distinct
441
-
442
- describe("distinct()", () => {
443
- it("Removes duplicates", () => {
444
- expect([1, 2, 2, 3, 3, 3].distinct()).toEqual([1, 2, 3]);
445
- });
446
-
447
- it("Removes duplicates from object array", () => {
448
- const arr = [{ a: 1 }, { a: 2 }, { a: 1 }];
449
- const result = arr.distinct();
450
- expect(result).toHaveLength(2);
451
- });
452
-
453
- it("Can use custom key with keyFn", () => {
454
- const arr = [
455
- { id: 1, name: "a" },
456
- { id: 2, name: "b" },
457
- { id: 1, name: "c" },
458
- ];
459
- const result = arr.distinct({ keyFn: (x) => x.id });
460
- expect(result).toHaveLength(2);
461
- });
462
-
463
- it("Removes duplicates by reference with matchAddress=true", () => {
464
- const obj1 = { a: 1 };
465
- const obj2 = { a: 1 }; // same value but different reference
466
- const arr = [obj1, obj1, obj2];
467
- const result = arr.distinct({ matchAddress: true });
468
- expect(result).toHaveLength(2);
469
- expect(result).toContain(obj1);
470
- expect(result).toContain(obj2);
471
- });
472
- });
473
-
474
- //#endregion
475
-
476
- //#region orderBy, orderByDesc
477
-
478
- describe("orderBy()", () => {
479
- it("Sorts in ascending order", () => {
480
- expect([3, 1, 2].orderBy()).toEqual([1, 2, 3]);
481
- });
482
-
483
- it("Can specify sort criteria with selector", () => {
484
- const items = [
485
- { name: "b", age: 30 },
486
- { name: "a", age: 20 },
487
- { name: "c", age: 25 },
488
- ];
489
- const result = items.orderBy((x) => x.age);
490
- expect(result.map((x) => x.age)).toEqual([20, 25, 30]);
491
- });
492
- });
493
-
494
- describe("orderByDesc()", () => {
495
- it("Sorts in descending order", () => {
496
- expect([1, 3, 2].orderByDesc()).toEqual([3, 2, 1]);
497
- });
498
- });
499
-
500
- //#endregion
501
-
502
- //#region sum, min, max
503
-
504
- describe("sum()", () => {
505
- it("Returns sum", () => {
506
- expect([1, 2, 3, 4, 5].sum()).toBe(15);
507
- });
508
-
509
- it("Can extract values with selector", () => {
510
- const items = [{ value: 10 }, { value: 20 }, { value: 30 }];
511
- expect(items.sum((x) => x.value)).toBe(60);
512
- });
513
-
514
- it("Returns 0 for empty array", () => {
515
- expect(([] as number[]).sum()).toBe(0);
516
- });
517
-
518
- it("Throws error for non-number type", () => {
519
- expect(() => (["a", "b"] as unknown as number[]).sum()).toThrow("sum can only be used with numbers");
520
- });
521
- });
522
-
523
- describe("min()", () => {
524
- it("Returns minimum value", () => {
525
- expect([3, 1, 2].min()).toBe(1);
526
- });
527
-
528
- it("Returns undefined for empty array", () => {
529
- expect(([] as number[]).min()).toBe(undefined);
530
- });
531
-
532
- it("Throws error for non-number/string type", () => {
533
- expect(() => ([true, false] as unknown as number[]).min()).toThrow(
534
- "min can only be used with numbers/strings",
535
- );
536
- });
537
- });
538
-
539
- describe("max()", () => {
540
- it("Returns maximum value", () => {
541
- expect([1, 3, 2].max()).toBe(3);
542
- });
543
-
544
- it("Returns undefined for empty array", () => {
545
- expect(([] as number[]).max()).toBe(undefined);
546
- });
547
-
548
- it("Throws error for non-number/string type", () => {
549
- expect(() => ([{}, {}] as unknown as number[]).max()).toThrow(
550
- "max can only be used with numbers/strings",
551
- );
552
- });
553
- });
554
-
555
- //#endregion
556
-
557
- //#region shuffle
558
-
559
- describe("shuffle()", () => {
560
- it("Shuffles array (preserves original)", () => {
561
- const original = [1, 2, 3, 4, 5];
562
- const shuffled = original.shuffle();
563
-
564
- // original unchanged
565
- expect(original).toEqual([1, 2, 3, 4, 5]);
566
- // has same elements
567
- expect(shuffled.sort()).toEqual([1, 2, 3, 4, 5]);
568
- });
569
- });
570
-
571
- //#endregion
572
-
573
- //#region Mutating methods
574
-
575
- describe("distinctThis()", () => {
576
- it("Removes duplicates from original array", () => {
577
- const arr = [1, 2, 2, 3, 3, 3];
578
- const result = arr.distinctThis();
579
-
580
- expect(arr).toEqual([1, 2, 3]);
581
- expect(result).toEqual([1, 2, 3]);
582
- });
583
- });
584
-
585
- describe("orderByThis()", () => {
586
- it("Sorts original array in ascending order", () => {
587
- const arr = [3, 1, 2];
588
- arr.orderByThis();
589
-
590
- expect(arr).toEqual([1, 2, 3]);
591
- });
592
- });
593
-
594
- describe("orderByDescThis()", () => {
595
- it("Sorts original array in descending order", () => {
596
- const arr = [1, 3, 2];
597
- arr.orderByDescThis();
598
-
599
- expect(arr).toEqual([3, 2, 1]);
600
- });
601
- });
602
-
603
- describe("insert()", () => {
604
- it("Inserts item to original array", () => {
605
- const arr = [1, 3];
606
- arr.insert(1, 2);
607
-
608
- expect(arr).toEqual([1, 2, 3]);
609
- });
610
- });
611
-
612
- describe("remove()", () => {
613
- it("Removes item from original array", () => {
614
- const arr = [1, 2, 3];
615
- arr.remove(2);
616
-
617
- expect(arr).toEqual([1, 3]);
618
- });
619
-
620
- it("Removes item with condition function", () => {
621
- const arr = [1, 2, 3, 4];
622
- arr.remove((x) => x % 2 === 0);
623
-
624
- expect(arr).toEqual([1, 3]);
625
- });
626
- });
627
-
628
- describe("toggle()", () => {
629
- it("Removes item if exists", () => {
630
- const arr = [1, 2, 3];
631
- arr.toggle(2);
632
-
633
- expect(arr).toEqual([1, 3]);
634
- });
635
-
636
- it("Adds item if not exists", () => {
637
- const arr = [1, 3];
638
- arr.toggle(2);
639
-
640
- expect(arr).toEqual([1, 3, 2]);
641
- });
642
- });
643
-
644
- describe("clear()", () => {
645
- it("Clears original array", () => {
646
- const arr = [1, 2, 3];
647
- arr.clear();
648
-
649
- expect(arr).toEqual([]);
650
- });
651
- });
652
-
653
- //#endregion
654
- });