@simplysm/core-common 13.0.99 → 14.0.1

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 (181) hide show
  1. package/dist/common.types.d.ts +14 -14
  2. package/dist/common.types.js +2 -1
  3. package/dist/common.types.js.map +1 -6
  4. package/dist/env.d.ts +5 -0
  5. package/dist/env.d.ts.map +1 -1
  6. package/dist/env.js +12 -8
  7. package/dist/env.js.map +1 -6
  8. package/dist/errors/argument-error.d.ts +10 -10
  9. package/dist/errors/argument-error.d.ts.map +1 -1
  10. package/dist/errors/argument-error.js +31 -14
  11. package/dist/errors/argument-error.js.map +1 -6
  12. package/dist/errors/not-implemented-error.d.ts +8 -8
  13. package/dist/errors/not-implemented-error.js +30 -12
  14. package/dist/errors/not-implemented-error.js.map +1 -6
  15. package/dist/errors/sd-error.d.ts +10 -10
  16. package/dist/errors/sd-error.d.ts.map +1 -1
  17. package/dist/errors/sd-error.js +45 -24
  18. package/dist/errors/sd-error.js.map +1 -6
  19. package/dist/errors/timeout-error.d.ts +10 -10
  20. package/dist/errors/timeout-error.js +34 -15
  21. package/dist/errors/timeout-error.js.map +1 -6
  22. package/dist/extensions/arr-ext.d.ts +2 -2
  23. package/dist/extensions/arr-ext.helpers.d.ts +10 -10
  24. package/dist/extensions/arr-ext.helpers.js +112 -89
  25. package/dist/extensions/arr-ext.helpers.js.map +1 -6
  26. package/dist/extensions/arr-ext.js +458 -422
  27. package/dist/extensions/arr-ext.js.map +1 -6
  28. package/dist/extensions/arr-ext.types.d.ts +57 -57
  29. package/dist/extensions/arr-ext.types.d.ts.map +1 -1
  30. package/dist/extensions/arr-ext.types.js +6 -1
  31. package/dist/extensions/arr-ext.types.js.map +1 -6
  32. package/dist/extensions/map-ext.d.ts +16 -16
  33. package/dist/extensions/map-ext.js +27 -22
  34. package/dist/extensions/map-ext.js.map +1 -6
  35. package/dist/extensions/set-ext.d.ts +11 -11
  36. package/dist/extensions/set-ext.js +32 -25
  37. package/dist/extensions/set-ext.js.map +1 -6
  38. package/dist/features/debounce-queue.d.ts +17 -17
  39. package/dist/features/debounce-queue.js +98 -70
  40. package/dist/features/debounce-queue.js.map +1 -6
  41. package/dist/features/event-emitter.d.ts +20 -20
  42. package/dist/features/event-emitter.js +101 -78
  43. package/dist/features/event-emitter.js.map +1 -6
  44. package/dist/features/serial-queue.d.ts +11 -11
  45. package/dist/features/serial-queue.js +78 -57
  46. package/dist/features/serial-queue.js.map +1 -6
  47. package/dist/globals.d.ts +4 -4
  48. package/dist/globals.js +9 -1
  49. package/dist/globals.js.map +1 -6
  50. package/dist/index.js +28 -27
  51. package/dist/index.js.map +1 -6
  52. package/dist/types/date-only.d.ts +64 -64
  53. package/dist/types/date-only.d.ts.map +1 -1
  54. package/dist/types/date-only.js +263 -252
  55. package/dist/types/date-only.js.map +1 -6
  56. package/dist/types/date-time.d.ts +36 -36
  57. package/dist/types/date-time.d.ts.map +1 -1
  58. package/dist/types/date-time.js +196 -288
  59. package/dist/types/date-time.js.map +1 -6
  60. package/dist/types/lazy-gc-map.d.ts +26 -26
  61. package/dist/types/lazy-gc-map.d.ts.map +1 -1
  62. package/dist/types/lazy-gc-map.js +202 -159
  63. package/dist/types/lazy-gc-map.js.map +1 -6
  64. package/dist/types/time.d.ts +23 -23
  65. package/dist/types/time.d.ts.map +1 -1
  66. package/dist/types/time.js +169 -158
  67. package/dist/types/time.js.map +1 -6
  68. package/dist/types/uuid.d.ts +11 -11
  69. package/dist/types/uuid.d.ts.map +1 -1
  70. package/dist/types/uuid.js +95 -70
  71. package/dist/types/uuid.js.map +1 -6
  72. package/dist/utils/bytes.d.ts +17 -17
  73. package/dist/utils/bytes.js +137 -81
  74. package/dist/utils/bytes.js.map +1 -6
  75. package/dist/utils/date-format.d.ts +40 -40
  76. package/dist/utils/date-format.js +187 -101
  77. package/dist/utils/date-format.js.map +1 -6
  78. package/dist/utils/error.d.ts +4 -4
  79. package/dist/utils/error.js +11 -6
  80. package/dist/utils/error.js.map +1 -6
  81. package/dist/utils/json.d.ts +19 -19
  82. package/dist/utils/json.js +187 -135
  83. package/dist/utils/json.js.map +1 -6
  84. package/dist/utils/num.d.ts +20 -20
  85. package/dist/utils/num.js +76 -34
  86. package/dist/utils/num.js.map +1 -6
  87. package/dist/utils/obj.d.ts +111 -111
  88. package/dist/utils/obj.d.ts.map +1 -1
  89. package/dist/utils/obj.js +706 -496
  90. package/dist/utils/obj.js.map +1 -6
  91. package/dist/utils/path.d.ts +10 -10
  92. package/dist/utils/path.js +35 -18
  93. package/dist/utils/path.js.map +1 -6
  94. package/dist/utils/primitive.d.ts +5 -5
  95. package/dist/utils/primitive.js +34 -14
  96. package/dist/utils/primitive.js.map +1 -6
  97. package/dist/utils/str.d.ts +38 -38
  98. package/dist/utils/str.js +217 -113
  99. package/dist/utils/str.js.map +1 -6
  100. package/dist/utils/template-strings.d.ts +26 -26
  101. package/dist/utils/template-strings.js +113 -40
  102. package/dist/utils/template-strings.js.map +1 -6
  103. package/dist/utils/transferable.d.ts +18 -18
  104. package/dist/utils/transferable.js +218 -151
  105. package/dist/utils/transferable.js.map +1 -6
  106. package/dist/utils/wait.d.ts +9 -9
  107. package/dist/utils/wait.js +30 -15
  108. package/dist/utils/wait.js.map +1 -6
  109. package/dist/utils/xml.d.ts +13 -13
  110. package/dist/utils/xml.js +84 -46
  111. package/dist/utils/xml.js.map +1 -6
  112. package/dist/utils/zip.d.ts +22 -22
  113. package/dist/utils/zip.js +172 -148
  114. package/dist/utils/zip.js.map +1 -6
  115. package/package.json +5 -7
  116. package/src/common.types.ts +14 -14
  117. package/src/env.ts +9 -1
  118. package/src/errors/argument-error.ts +15 -15
  119. package/src/errors/not-implemented-error.ts +9 -9
  120. package/src/errors/sd-error.ts +12 -12
  121. package/src/errors/timeout-error.ts +12 -12
  122. package/src/extensions/arr-ext.helpers.ts +16 -16
  123. package/src/extensions/arr-ext.ts +35 -35
  124. package/src/extensions/arr-ext.types.ts +57 -57
  125. package/src/extensions/map-ext.ts +16 -16
  126. package/src/extensions/set-ext.ts +11 -11
  127. package/src/features/debounce-queue.ts +23 -23
  128. package/src/features/event-emitter.ts +25 -25
  129. package/src/features/serial-queue.ts +13 -13
  130. package/src/globals.ts +4 -4
  131. package/src/index.ts +5 -5
  132. package/src/types/date-only.ts +84 -83
  133. package/src/types/date-time.ts +43 -42
  134. package/src/types/lazy-gc-map.ts +44 -44
  135. package/src/types/time.ts +29 -29
  136. package/src/types/uuid.ts +15 -15
  137. package/src/utils/bytes.ts +35 -35
  138. package/src/utils/date-format.ts +59 -59
  139. package/src/utils/error.ts +4 -4
  140. package/src/utils/json.ts +41 -41
  141. package/src/utils/num.ts +20 -20
  142. package/src/utils/obj.ts +138 -138
  143. package/src/utils/path.ts +10 -10
  144. package/src/utils/primitive.ts +6 -6
  145. package/src/utils/str.ts +48 -48
  146. package/src/utils/template-strings.ts +29 -29
  147. package/src/utils/transferable.ts +38 -38
  148. package/src/utils/wait.ts +10 -10
  149. package/src/utils/xml.ts +19 -19
  150. package/src/utils/zip.ts +25 -25
  151. package/README.md +0 -160
  152. package/docs/errors.md +0 -119
  153. package/docs/extensions.md +0 -387
  154. package/docs/features.md +0 -143
  155. package/docs/types.md +0 -287
  156. package/docs/utils.md +0 -757
  157. package/tests/errors/errors.spec.ts +0 -80
  158. package/tests/extensions/array-extension.spec.ts +0 -654
  159. package/tests/extensions/map-extension.spec.ts +0 -117
  160. package/tests/extensions/set-extension.spec.ts +0 -67
  161. package/tests/types/date-only.spec.ts +0 -533
  162. package/tests/types/date-time.spec.ts +0 -246
  163. package/tests/types/lazy-gc-map.spec.ts +0 -606
  164. package/tests/types/time.spec.ts +0 -428
  165. package/tests/types/uuid.spec.ts +0 -74
  166. package/tests/utils/bytes-utils.spec.ts +0 -197
  167. package/tests/utils/date-format.spec.ts +0 -350
  168. package/tests/utils/debounce-queue.spec.ts +0 -226
  169. package/tests/utils/json.spec.ts +0 -400
  170. package/tests/utils/number.spec.ts +0 -136
  171. package/tests/utils/object.spec.ts +0 -810
  172. package/tests/utils/path.spec.ts +0 -70
  173. package/tests/utils/primitive.spec.ts +0 -43
  174. package/tests/utils/sd-event-emitter.spec.ts +0 -189
  175. package/tests/utils/serial-queue.spec.ts +0 -305
  176. package/tests/utils/string.spec.ts +0 -265
  177. package/tests/utils/template-strings.spec.ts +0 -48
  178. package/tests/utils/transferable.spec.ts +0 -639
  179. package/tests/utils/wait.spec.ts +0 -123
  180. package/tests/utils/xml.spec.ts +0 -146
  181. package/tests/utils/zip.spec.ts +0 -221
@@ -1,810 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { obj as objU, DateTime, DateOnly, Uuid } from "@simplysm/core-common";
3
-
4
- describe("object utils", () => {
5
- //#region clone
6
-
7
- describe("objClone()", () => {
8
- it("Clones primitive values", () => {
9
- expect(objU.clone(42)).toBe(42);
10
- expect(objU.clone("hello")).toBe("hello");
11
- expect(objU.clone(true)).toBe(true);
12
- expect(objU.clone(null)).toBe(null);
13
- expect(objU.clone(undefined)).toBe(undefined);
14
- });
15
-
16
- it("Deep clones array", () => {
17
- const arr = [1, [2, 3], { a: 4 }];
18
- const cloned = objU.clone(arr);
19
-
20
- expect(cloned).toEqual(arr);
21
- expect(cloned).not.toBe(arr);
22
- expect(cloned[1]).not.toBe(arr[1]);
23
- expect(cloned[2]).not.toBe(arr[2]);
24
- });
25
-
26
- it("Deep clones object", () => {
27
- const obj = { a: 1, b: { c: 2 }, d: [3, 4] };
28
- const cloned = objU.clone(obj);
29
-
30
- expect(cloned).toEqual(obj);
31
- expect(cloned).not.toBe(obj);
32
- expect(cloned.b).not.toBe(obj.b);
33
- expect(cloned.d).not.toBe(obj.d);
34
- });
35
-
36
- it("Clones Date", () => {
37
- const date = new Date(2024, 2, 15);
38
- const cloned = objU.clone(date);
39
-
40
- expect(cloned).toEqual(date);
41
- expect(cloned).not.toBe(date);
42
- });
43
-
44
- it("Clones DateTime", () => {
45
- const dt = new DateTime(2024, 3, 15, 10, 30);
46
- const cloned = objU.clone(dt);
47
-
48
- expect(cloned.tick).toBe(dt.tick);
49
- expect(cloned).not.toBe(dt);
50
- });
51
-
52
- it("Clones DateOnly", () => {
53
- const d = new DateOnly(2024, 3, 15);
54
- const cloned = objU.clone(d);
55
-
56
- expect(cloned.tick).toBe(d.tick);
57
- expect(cloned).not.toBe(d);
58
- });
59
-
60
- it("Clones Uuid", () => {
61
- const uuid = Uuid.generate();
62
- const cloned = objU.clone(uuid);
63
-
64
- expect(cloned.toString()).toBe(uuid.toString());
65
- expect(cloned).not.toBe(uuid);
66
- });
67
-
68
- it("Clones Map", () => {
69
- const map = new Map<string, number | { c: number }>([
70
- ["a", 1],
71
- ["b", { c: 2 }],
72
- ]);
73
- const cloned = objU.clone(map);
74
-
75
- expect(cloned.get("a")).toBe(1);
76
- expect(cloned.get("b")).toEqual({ c: 2 });
77
- expect(cloned.get("b")).not.toBe(map.get("b"));
78
- });
79
-
80
- it("Clones Set", () => {
81
- const obj = { a: 1 };
82
- const set = new Set([1, 2, obj]);
83
- const cloned = objU.clone(set);
84
-
85
- expect(cloned.has(1)).toBe(true);
86
- expect(cloned.has(2)).toBe(true);
87
- // Object in Set is cloned
88
- const clonedObj = Array.from(cloned).find((item) => typeof item === "object");
89
- expect(clonedObj).toEqual(obj);
90
- expect(clonedObj).not.toBe(obj);
91
- });
92
-
93
- it("Handles circular references", () => {
94
- const obj: Record<string, unknown> = { a: 1 };
95
- obj["self"] = obj;
96
-
97
- const cloned = objU.clone(obj);
98
-
99
- expect(cloned["a"]).toBe(1);
100
- expect(cloned["self"]).toBe(cloned);
101
- expect(cloned).not.toBe(obj);
102
- });
103
-
104
- it("Clones RegExp", () => {
105
- const regex = /test/gi;
106
- const cloned = objU.clone(regex);
107
-
108
- expect(cloned).toEqual(regex);
109
- expect(cloned).not.toBe(regex);
110
- expect(cloned.source).toBe("test");
111
- expect(cloned.flags).toBe("gi");
112
- });
113
-
114
- it("Clones Error", () => {
115
- const error = new Error("test error");
116
- const cloned = objU.clone(error);
117
-
118
- expect(cloned.message).toBe("test error");
119
- expect(cloned).not.toBe(error);
120
- });
121
-
122
- it("Clones Error cause", () => {
123
- const cause = new Error("cause error");
124
- const error = new Error("test error", { cause });
125
- const cloned = objU.clone(error);
126
-
127
- expect(cloned.message).toBe("test error");
128
- expect(cloned.cause).toBeInstanceOf(Error);
129
- expect((cloned.cause as Error).message).toBe("cause error");
130
- });
131
-
132
- it("Clones Error custom properties", () => {
133
- const error = new Error("test") as Error & { code: string; detail: object };
134
- error.code = "ERR_CODE";
135
- error.detail = { key: "value" };
136
- const cloned = objU.clone(error);
137
-
138
- expect(cloned.code).toBe("ERR_CODE");
139
- expect(cloned.detail).toEqual({ key: "value" });
140
- expect(cloned.detail).not.toBe(error.detail);
141
- });
142
-
143
- it("Clones Uint8Array", () => {
144
- const arr = new Uint8Array([1, 2, 3, 4, 5]);
145
- const cloned = objU.clone(arr);
146
-
147
- expect(cloned).toEqual(arr);
148
- expect(cloned).not.toBe(arr);
149
- expect(cloned.buffer).not.toBe(arr.buffer);
150
- });
151
-
152
- it("Symbol keys are not cloned", () => {
153
- // Object.keys() does not enumerate Symbol keys, so they are not cloned
154
- const sym = Symbol("test");
155
- const obj = { a: 1, [sym]: "symbol value" };
156
- const cloned = objU.clone(obj);
157
-
158
- expect(cloned.a).toBe(1);
159
- expect(cloned[sym]).toBeUndefined();
160
- });
161
- });
162
-
163
- //#endregion
164
-
165
- //#region equal
166
-
167
- describe("objU.equal()", () => {
168
- it("Compares primitive values", () => {
169
- expect(objU.equal(1, 1)).toBe(true);
170
- expect(objU.equal(1, 2)).toBe(false);
171
- expect(objU.equal("a", "a")).toBe(true);
172
- expect(objU.equal(null, null)).toBe(true);
173
- expect(objU.equal(undefined, undefined)).toBe(true);
174
- expect(objU.equal(null, undefined)).toBe(false);
175
- });
176
-
177
- it("Compares arrays", () => {
178
- expect(objU.equal([1, 2, 3], [1, 2, 3])).toBe(true);
179
- expect(objU.equal([1, 2, 3], [1, 2])).toBe(false);
180
- expect(objU.equal([1, 2, 3], [1, 3, 2])).toBe(false);
181
- });
182
-
183
- it("Compares objects", () => {
184
- expect(objU.equal({ a: 1, b: 2 }, { a: 1, b: 2 })).toBe(true);
185
- expect(objU.equal({ a: 1, b: 2 }, { a: 1, b: 3 })).toBe(false);
186
- expect(objU.equal({ a: 1 }, { a: 1, b: 2 })).toBe(false);
187
- });
188
-
189
- it("Compares nested objects", () => {
190
- expect(objU.equal({ a: { b: { c: 1 } } }, { a: { b: { c: 1 } } })).toBe(true);
191
- expect(objU.equal({ a: { b: { c: 1 } } }, { a: { b: { c: 2 } } })).toBe(false);
192
- });
193
-
194
- it("Compares DateTime", () => {
195
- const dt1 = new DateTime(2024, 3, 15);
196
- const dt2 = new DateTime(2024, 3, 15);
197
- const dt3 = new DateTime(2024, 3, 16);
198
-
199
- expect(objU.equal(dt1, dt2)).toBe(true);
200
- expect(objU.equal(dt1, dt3)).toBe(false);
201
- });
202
-
203
- it("Compares Uuid", () => {
204
- const uuid1 = new Uuid("12345678-9abc-def0-1234-56789abcdef0");
205
- const uuid2 = new Uuid("12345678-9abc-def0-1234-56789abcdef0");
206
- const uuid3 = new Uuid("12345678-9abc-def0-1234-56789abcdef1");
207
-
208
- expect(objU.equal(uuid1, uuid2)).toBe(true);
209
- expect(objU.equal(uuid1, uuid3)).toBe(false);
210
- });
211
-
212
- it("Compares RegExp", () => {
213
- const regex1 = /test/gi;
214
- const regex2 = /test/gi;
215
- const regex3 = /test/g;
216
- const regex4 = /other/gi;
217
-
218
- expect(objU.equal(regex1, regex2)).toBe(true);
219
- expect(objU.equal(regex1, regex3)).toBe(false); // Different flags
220
- expect(objU.equal(regex1, regex4)).toBe(false); // Different source
221
- });
222
-
223
- it("Compares Map", () => {
224
- const map1 = new Map([
225
- ["a", 1],
226
- ["b", 2],
227
- ]);
228
- const map2 = new Map([
229
- ["a", 1],
230
- ["b", 2],
231
- ]);
232
- const map3 = new Map([
233
- ["a", 1],
234
- ["b", 3],
235
- ]);
236
-
237
- expect(objU.equal(map1, map2)).toBe(true);
238
- expect(objU.equal(map1, map3)).toBe(false);
239
- });
240
-
241
- it("Compares Set", () => {
242
- const set1 = new Set([1, 2, 3]);
243
- const set2 = new Set([1, 2, 3]);
244
- const set3 = new Set([1, 2, 4]);
245
-
246
- expect(objU.equal(set1, set2)).toBe(true);
247
- expect(objU.equal(set1, set3)).toBe(false);
248
- });
249
-
250
- it("Compares only specific keys with topLevelIncludes option", () => {
251
- const obj1 = { a: 1, b: 2, c: 3 };
252
- const obj2 = { a: 1, b: 99, c: 99 };
253
-
254
- expect(objU.equal(obj1, obj2, { topLevelIncludes: ["a"] })).toBe(true);
255
- expect(objU.equal(obj1, obj2, { topLevelIncludes: ["a", "b"] })).toBe(false);
256
- });
257
-
258
- it("Excludes specific keys with topLevelExcludes option", () => {
259
- const obj1 = { a: 1, b: 2, c: 3 };
260
- const obj2 = { a: 1, b: 99, c: 99 };
261
-
262
- expect(objU.equal(obj1, obj2, { topLevelExcludes: ["b", "c"] })).toBe(true);
263
- });
264
-
265
- it("Ignores array order with ignoreArrayIndex option", () => {
266
- expect(objU.equal([1, 2, 3], [3, 2, 1], { ignoreArrayIndex: true })).toBe(true);
267
- });
268
-
269
- it("Performs shallow comparison with shallow option", () => {
270
- const inner = { c: 1 };
271
- const obj1 = { a: 1, b: inner };
272
- const obj2 = { a: 1, b: inner };
273
- const obj3 = { a: 1, b: { c: 1 } };
274
-
275
- expect(objU.equal(obj1, obj2, { shallow: true })).toBe(true);
276
- expect(objU.equal(obj1, obj3, { shallow: true })).toBe(false);
277
- });
278
- });
279
-
280
- //#endregion
281
-
282
- //#region merge
283
-
284
- describe("objU.merge()", () => {
285
- it("Copies target when source is null", () => {
286
- const target = { a: 1 };
287
- const result = objU.merge(null, target);
288
-
289
- expect(result).toEqual({ a: 1 });
290
- expect(result).not.toBe(target);
291
- });
292
-
293
- it("Copies source when target is undefined", () => {
294
- const source = { a: 1 };
295
- const result = objU.merge(source, undefined);
296
-
297
- expect(result).toEqual({ a: 1 });
298
- });
299
-
300
- it("Merges objects", () => {
301
- const source = { a: 1, b: 2 };
302
- const target = { b: 3, c: 4 };
303
- const result = objU.merge(source, target);
304
-
305
- expect(result).toEqual({ a: 1, b: 3, c: 4 });
306
- });
307
-
308
- it("Merges nested objects", () => {
309
- const source = { a: { b: 1, c: 2 } };
310
- const target = { a: { c: 3, d: 4 } };
311
- const result = objU.merge(source, target);
312
-
313
- expect(result).toEqual({ a: { b: 1, c: 3, d: 4 } });
314
- });
315
-
316
- it("Replaces array with arrayProcess: replace", () => {
317
- const source = { arr: [1, 2, 3] };
318
- const target = { arr: [4, 5] };
319
- const result = objU.merge(source, target, { arrayProcess: "replace" });
320
-
321
- expect(result.arr).toEqual([4, 5]);
322
- });
323
-
324
- it("Concatenates arrays with arrayProcess: concat", () => {
325
- const source = { arr: [1, 2, 3] };
326
- const target = { arr: [3, 4, 5] };
327
- const result = objU.merge(source, target, { arrayProcess: "concat" });
328
-
329
- // Duplicates removed via Set
330
- expect(result.arr).toEqual([1, 2, 3, 4, 5]);
331
- });
332
-
333
- it("Deletes when null with useDelTargetNull option", () => {
334
- const source = { a: 1, b: 2 };
335
- const target = { b: null };
336
- const result = objU.merge(source, target, { useDelTargetNull: true });
337
-
338
- expect(result).toEqual({ a: 1 });
339
- });
340
-
341
- it("Returns target when source is object and target is primitive", () => {
342
- const source = { a: 1 };
343
- const target = "string";
344
-
345
- const result = objU.merge(source, target as any);
346
-
347
- expect(result).toBe("string");
348
- });
349
-
350
- it("Returns target when source is primitive and target is object", () => {
351
- const source = "string";
352
- const target = { a: 1 };
353
-
354
- const result = objU.merge(source as any, target);
355
-
356
- expect(result).toEqual({ a: 1 });
357
- });
358
-
359
- it("Returns target when source is array and target is plain object", () => {
360
- const source = [1, 2, 3];
361
- const target = { a: 1 };
362
-
363
- const result = objU.merge(source as any, target);
364
-
365
- expect(result).toEqual({ a: 1 });
366
- });
367
-
368
- it("Returns target when source is plain object and target is array", () => {
369
- const source = { a: 1 };
370
- const target = [1, 2, 3];
371
-
372
- const result = objU.merge(source as any, target);
373
-
374
- expect(result).toEqual([1, 2, 3]);
375
- });
376
-
377
- it("Merges deeply nested objects (3+ levels)", () => {
378
- const source = {
379
- level1: {
380
- level2: {
381
- level3: {
382
- a: 1,
383
- b: 2,
384
- },
385
- x: 10,
386
- },
387
- y: 20,
388
- },
389
- z: 30,
390
- };
391
- const target = {
392
- level1: {
393
- level2: {
394
- level3: {
395
- b: 3,
396
- c: 4,
397
- },
398
- },
399
- },
400
- };
401
-
402
- const result = objU.merge(source, target);
403
-
404
- expect(result).toEqual({
405
- level1: {
406
- level2: {
407
- level3: {
408
- a: 1,
409
- b: 3,
410
- c: 4,
411
- },
412
- x: 10,
413
- },
414
- y: 20,
415
- },
416
- z: 30,
417
- });
418
- });
419
-
420
- it("Modifies only deep value in 4-level nesting", () => {
421
- const source = {
422
- a: {
423
- b: {
424
- c: {
425
- d: { value: 1 },
426
- },
427
- },
428
- },
429
- };
430
- const target = {
431
- a: {
432
- b: {
433
- c: {
434
- d: { value: 2 },
435
- },
436
- },
437
- },
438
- };
439
-
440
- const result = objU.merge(source, target);
441
-
442
- expect(result.a.b.c.d.value).toBe(2);
443
- });
444
-
445
- it("Clones new key-value in Map merge", () => {
446
- const sourceMap = new Map<string, { value: number }>([["key1", { value: 1 }]]);
447
- const targetObj = { value: 2 };
448
- const targetMap = new Map<string, { value: number }>([["key2", targetObj]]);
449
-
450
- const result = objU.merge(sourceMap, targetMap);
451
-
452
- // key2 value is cloned, should be different reference
453
- expect(result.get("key2")).toEqual({ value: 2 });
454
- expect(result.get("key2")).not.toBe(targetObj);
455
- });
456
- });
457
-
458
- describe("objU.merge3()", () => {
459
- it("Uses source value when only source changes", () => {
460
- const origin = { a: 1, b: 2 };
461
- const source = { a: 1, b: 3 };
462
- const target = { a: 1, b: 2 };
463
- const { conflict, result } = objU.merge3(source, origin, target);
464
-
465
- expect(conflict).toBe(false);
466
- expect(result).toEqual({ a: 1, b: 3 });
467
- });
468
-
469
- it("Uses target value when only target changes", () => {
470
- const origin = { a: 1, b: 2 };
471
- const source = { a: 1, b: 2 };
472
- const target = { a: 1, b: 4 };
473
- const { conflict, result } = objU.merge3(source, origin, target);
474
-
475
- expect(conflict).toBe(false);
476
- expect(result).toEqual({ a: 1, b: 4 });
477
- });
478
-
479
- it("Uses value without conflict when both change to same value", () => {
480
- const origin = { a: 1, b: 2 };
481
- const source = { a: 1, b: 5 };
482
- const target = { a: 1, b: 5 };
483
- const { conflict, result } = objU.merge3(source, origin, target);
484
-
485
- expect(conflict).toBe(false);
486
- expect(result).toEqual({ a: 1, b: 5 });
487
- });
488
-
489
- it("Returns conflict when both change to different values", () => {
490
- const origin = { a: 1, b: 2 };
491
- const source = { a: 1, b: 3 };
492
- const target = { a: 1, b: 4 };
493
- const { conflict, result } = objU.merge3(source, origin, target);
494
-
495
- expect(conflict).toBe(true);
496
- // Origin value preserved
497
- expect(result.b).toBe(2);
498
- });
499
-
500
- it("Returns conflict when only some keys conflict", () => {
501
- const origin = { a: 1, b: 2, c: 3 };
502
- const source = { a: 10, b: 20, c: 3 };
503
- const target = { a: 1, b: 30, c: 4 };
504
- const { conflict, result } = objU.merge3(source, origin, target);
505
-
506
- expect(conflict).toBe(true);
507
- expect(result.a).toBe(10); // Only source changed
508
- expect(result.b).toBe(2); // Both changed differently → conflict → origin preserved
509
- expect(result.c).toBe(4); // Only target changed
510
- });
511
-
512
- it("Detects conflict in nested objects", () => {
513
- const origin = { a: { b: 1, c: 2 } };
514
- const source = { a: { b: 10, c: 2 } };
515
- const target = { a: { b: 20, c: 2 } };
516
- const { conflict, result } = objU.merge3(source, origin, target);
517
-
518
- expect(conflict).toBe(true);
519
- expect(result.a.b).toBe(1); // Both changed differently → conflict → origin preserved
520
- expect(result.a.c).toBe(2);
521
- });
522
-
523
- it("Detects conflict in nested object when different internal keys change", () => {
524
- // merge3 compares at key level, so entire { a: {...} } is compared
525
- // If source.a differs from origin.a and target.a differs from origin.a, conflict
526
- const origin = { a: { b: 1, c: 2 } };
527
- const source = { a: { b: 10, c: 2 } };
528
- const target = { a: { b: 1, c: 20 } };
529
- const { conflict, result } = objU.merge3(source, origin, target);
530
-
531
- expect(conflict).toBe(true);
532
- expect(result.a.b).toBe(1); // Conflict → origin preserved
533
- expect(result.a.c).toBe(2);
534
- });
535
-
536
- it("Detects conflict in array", () => {
537
- const origin = { arr: [1, 2, 3] };
538
- const source = { arr: [1, 2, 4] };
539
- const target = { arr: [1, 2, 5] };
540
- const { conflict, result } = objU.merge3(source, origin, target);
541
-
542
- expect(conflict).toBe(true);
543
- expect(result.arr).toEqual([1, 2, 3]); // Conflict → origin preserved
544
- });
545
-
546
- it("Detects conflict in primitive value", () => {
547
- const origin = { value: "original" };
548
- const source = { value: "from source" };
549
- const target = { value: "from target" };
550
- const { conflict, result } = objU.merge3(source, origin, target);
551
-
552
- expect(conflict).toBe(true);
553
- expect(result.value).toBe("original"); // Conflict → origin preserved
554
- });
555
- });
556
-
557
- //#endregion
558
-
559
- //#region omit / pick
560
-
561
- describe("objU.omit()", () => {
562
- it("Excludes specific keys", () => {
563
- const obj = { a: 1, b: 2, c: 3 };
564
- const result = objU.omit(obj, ["b"]);
565
-
566
- expect(result).toEqual({ a: 1, c: 3 });
567
- });
568
-
569
- it("Excludes multiple keys", () => {
570
- const obj = { a: 1, b: 2, c: 3, d: 4 };
571
- const result = objU.omit(obj, ["a", "c"]);
572
-
573
- expect(result).toEqual({ b: 2, d: 4 });
574
- });
575
- });
576
-
577
- describe("objU.omitByFilter()", () => {
578
- it("Excludes keys matching condition", () => {
579
- const obj = { a: 1, b: 2, c: 3 };
580
- const result = objU.omitByFilter(obj, (key) => key === "b");
581
-
582
- expect(result).toEqual({ a: 1, c: 3 });
583
- });
584
- });
585
-
586
- describe("objU.pick()", () => {
587
- it("Selects only specific keys", () => {
588
- const obj = { a: 1, b: 2, c: 3 };
589
- const result = objU.pick(obj, ["a", "c"]);
590
-
591
- expect(result).toEqual({ a: 1, c: 3 });
592
- });
593
- });
594
-
595
- //#endregion
596
-
597
- //#region chain value
598
-
599
- describe("objU.getChainValue()", () => {
600
- it("Gets value using dot notation", () => {
601
- const obj = { a: { b: { c: 1 } } };
602
-
603
- expect(objU.getChainValue(obj, "a.b.c")).toBe(1);
604
- });
605
-
606
- it("Gets value using array notation", () => {
607
- const obj = { arr: [{ name: "first" }, { name: "second" }] };
608
-
609
- expect(objU.getChainValue(obj, "arr[1].name")).toBe("second");
610
- });
611
-
612
- it("Returns undefined for non-existent path with optional: true", () => {
613
- const obj = { a: 1 };
614
-
615
- expect(objU.getChainValue(obj, "b.c.d", true)).toBe(undefined);
616
- });
617
- });
618
-
619
- describe("objU.getChainValueByDepth()", () => {
620
- it("Descends by depth using same key", () => {
621
- const obj = {
622
- parent: {
623
- parent: {
624
- parent: {
625
- name: "leaf",
626
- },
627
- },
628
- },
629
- };
630
-
631
- const result = objU.getChainValueByDepth(obj, "parent", 2);
632
-
633
- expect(result).toEqual({ parent: { name: "leaf" } });
634
- });
635
-
636
- it("Throws error when depth is 0", () => {
637
- const obj = { parent: { name: "child" } };
638
-
639
- expect(() => objU.getChainValueByDepth(obj, "parent", 0)).toThrow(
640
- "depth must be 1 or greater",
641
- );
642
- });
643
-
644
- it("Descends one level when depth is 1", () => {
645
- const obj = { parent: { name: "child" } };
646
-
647
- const result = objU.getChainValueByDepth(obj, "parent", 1);
648
-
649
- expect(result).toEqual({ name: "child" });
650
- });
651
-
652
- it("Returns undefined when intermediate path missing with optional: true", () => {
653
- const obj = { parent: { name: "child" } };
654
-
655
- const result = objU.getChainValueByDepth(obj, "parent", 5, true);
656
-
657
- expect(result).toBe(undefined);
658
- });
659
-
660
- it("Throws error when intermediate path missing without optional", () => {
661
- const obj = { parent: undefined as unknown };
662
-
663
- // Without optional, trying to access property on undefined throws error
664
- // Current implementation only checks result == null inside optional condition
665
- // So without optional, error is possible
666
- expect(() => objU.getChainValueByDepth(obj as any, "parent", 2)).toThrow();
667
- });
668
- });
669
-
670
- describe("objU.setChainValue()", () => {
671
- it("Sets value using dot notation", () => {
672
- const obj: Record<string, unknown> = {};
673
- objU.setChainValue(obj, "a.b.c", 1);
674
-
675
- expect(obj).toEqual({ a: { b: { c: 1 } } });
676
- });
677
-
678
- it("Overwrites existing value", () => {
679
- const obj = { a: { b: { c: 1 } } };
680
- objU.setChainValue(obj, "a.b.c", 2);
681
-
682
- expect(obj.a.b.c).toBe(2);
683
- });
684
-
685
- it("Throws error for empty chain", () => {
686
- const obj: Record<string, unknown> = {};
687
-
688
- expect(() => objU.setChainValue(obj, "", 1)).toThrow();
689
- });
690
- });
691
-
692
- describe("objU.deleteChainValue()", () => {
693
- it("Deletes value at chain path", () => {
694
- const obj = { a: { b: { c: 1, d: 2 } } };
695
- objU.deleteChainValue(obj, "a.b.c");
696
-
697
- expect(obj.a.b).toEqual({ d: 2 });
698
- });
699
-
700
- it("Silently ignores non-existent path", () => {
701
- const obj = { a: 1 };
702
-
703
- // No error when intermediate path missing
704
- expect(() => objU.deleteChainValue(obj, "b.c.d")).not.toThrow();
705
- expect(obj).toEqual({ a: 1 });
706
- });
707
-
708
- it("Silently ignores undefined intermediate path", () => {
709
- const obj: Record<string, unknown> = { a: undefined };
710
-
711
- expect(() => objU.deleteChainValue(obj, "a.b.c")).not.toThrow();
712
- expect(obj).toEqual({ a: undefined });
713
- });
714
-
715
- it("Silently ignores null intermediate path", () => {
716
- const obj: Record<string, unknown> = { a: null };
717
-
718
- expect(() => objU.deleteChainValue(obj, "a.b.c")).not.toThrow();
719
- expect(obj).toEqual({ a: null });
720
- });
721
-
722
- it("Deletes using array index path", () => {
723
- const obj = { arr: [{ name: "first" }, { name: "second" }] };
724
- objU.deleteChainValue(obj, "arr[0].name");
725
-
726
- expect(obj.arr[0]).toEqual({});
727
- expect(obj.arr[1]).toEqual({ name: "second" });
728
- });
729
-
730
- it("Throws error for empty chain", () => {
731
- const obj = { a: 1 };
732
-
733
- expect(() => objU.deleteChainValue(obj, "")).toThrow();
734
- });
735
- });
736
-
737
- //#endregion
738
-
739
- //#region clear / transform
740
-
741
- describe("objU.clearUndefined()", () => {
742
- it("Deletes keys with undefined value", () => {
743
- const obj = { a: 1, b: undefined, c: 3 };
744
- const result = objU.clearUndefined(obj);
745
-
746
- expect(result).toEqual({ a: 1, c: 3 });
747
- expect("b" in result).toBe(false);
748
- });
749
- });
750
-
751
- describe("objU.clear()", () => {
752
- it("Deletes all keys", () => {
753
- const obj = { a: 1, b: 2, c: 3 };
754
- const result = objU.clear(obj);
755
-
756
- expect(Object.keys(result)).toHaveLength(0);
757
- });
758
- });
759
-
760
- describe("objU.nullToUndefined()", () => {
761
- it("Converts null to undefined", () => {
762
- expect(objU.nullToUndefined(null)).toBe(undefined);
763
- });
764
-
765
- it("Converts nested null to undefined", () => {
766
- const obj = { a: 1, b: null, c: { d: null } };
767
- const result = objU.nullToUndefined(obj);
768
-
769
- expect(result).toEqual({ a: 1, b: undefined, c: { d: undefined } });
770
- });
771
-
772
- it("Converts null in array to undefined", () => {
773
- const arr = [1, null, { a: null }];
774
- const result = objU.nullToUndefined(arr);
775
-
776
- expect(result).toEqual([1, undefined, { a: undefined }]);
777
- });
778
-
779
- it("Safely handles object with circular references", () => {
780
- const obj: Record<string, unknown> = { a: null };
781
- obj["self"] = obj;
782
- const result = objU.nullToUndefined(obj);
783
- expect(result).toBeDefined();
784
- expect((result as Record<string, unknown>)["a"]).toBeUndefined();
785
- });
786
-
787
- it("Safely handles array with circular references", () => {
788
- const arr: unknown[] = [null, 1];
789
- arr.push(arr);
790
- const result = objU.nullToUndefined(arr);
791
- expect(result).toBeDefined();
792
- expect((result as unknown[])[0]).toBeUndefined();
793
- expect((result as unknown[])[1]).toBe(1);
794
- });
795
- });
796
-
797
- describe("objU.unflatten()", () => {
798
- it("Converts flattened object to nested", () => {
799
- const flat = { "a.b.c": 1, "a.b.d": 2, "e": 3 };
800
- const result = objU.unflatten(flat);
801
-
802
- expect(result).toEqual({
803
- a: { b: { c: 1, d: 2 } },
804
- e: 3,
805
- });
806
- });
807
- });
808
-
809
- //#endregion
810
- });