@simplysm/core-common 13.0.75 → 13.0.77

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 (135) hide show
  1. package/README.md +64 -21
  2. package/dist/extensions/arr-ext.d.ts +1 -1
  3. package/dist/extensions/arr-ext.d.ts.map +1 -1
  4. package/dist/extensions/arr-ext.helpers.d.ts +8 -0
  5. package/dist/extensions/arr-ext.helpers.d.ts.map +1 -1
  6. package/dist/extensions/arr-ext.helpers.js +65 -0
  7. package/dist/extensions/arr-ext.helpers.js.map +2 -2
  8. package/dist/extensions/arr-ext.js +16 -124
  9. package/dist/extensions/arr-ext.js.map +2 -2
  10. package/dist/extensions/arr-ext.types.d.ts +40 -32
  11. package/dist/extensions/arr-ext.types.d.ts.map +1 -1
  12. package/dist/extensions/map-ext.js.map +1 -1
  13. package/dist/extensions/set-ext.js.map +1 -1
  14. package/dist/features/event-emitter.d.ts +4 -4
  15. package/dist/features/event-emitter.d.ts.map +1 -1
  16. package/dist/features/event-emitter.js.map +1 -1
  17. package/dist/features/serial-queue.js +2 -2
  18. package/dist/features/serial-queue.js.map +1 -1
  19. package/dist/index.d.ts +13 -13
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +27 -13
  22. package/dist/index.js.map +1 -1
  23. package/dist/types/date-only.js +2 -2
  24. package/dist/types/date-only.js.map +1 -1
  25. package/dist/types/date-time.js +2 -2
  26. package/dist/types/date-time.js.map +1 -1
  27. package/dist/types/time.js +2 -2
  28. package/dist/types/time.js.map +1 -1
  29. package/dist/types/uuid.d.ts +2 -2
  30. package/dist/types/uuid.d.ts.map +1 -1
  31. package/dist/types/uuid.js +1 -1
  32. package/dist/types/uuid.js.map +1 -1
  33. package/dist/utils/bytes.d.ts +10 -10
  34. package/dist/utils/bytes.d.ts.map +1 -1
  35. package/dist/utils/bytes.js +10 -10
  36. package/dist/utils/bytes.js.map +1 -1
  37. package/dist/utils/date-format.d.ts +1 -1
  38. package/dist/utils/date-format.d.ts.map +1 -1
  39. package/dist/utils/date-format.js +2 -2
  40. package/dist/utils/date-format.js.map +1 -1
  41. package/dist/utils/error.d.ts +1 -1
  42. package/dist/utils/error.d.ts.map +1 -1
  43. package/dist/utils/error.js +2 -2
  44. package/dist/utils/error.js.map +1 -1
  45. package/dist/utils/json.d.ts +4 -2
  46. package/dist/utils/json.d.ts.map +1 -1
  47. package/dist/utils/json.js +9 -9
  48. package/dist/utils/json.js.map +1 -1
  49. package/dist/utils/num.d.ts +10 -10
  50. package/dist/utils/num.d.ts.map +1 -1
  51. package/dist/utils/num.js +11 -11
  52. package/dist/utils/num.js.map +1 -1
  53. package/dist/utils/obj.d.ts +40 -40
  54. package/dist/utils/obj.d.ts.map +1 -1
  55. package/dist/utils/obj.js +102 -99
  56. package/dist/utils/obj.js.map +1 -1
  57. package/dist/utils/path.d.ts +3 -3
  58. package/dist/utils/path.d.ts.map +1 -1
  59. package/dist/utils/path.js +6 -6
  60. package/dist/utils/path.js.map +1 -1
  61. package/dist/utils/primitive.d.ts +1 -1
  62. package/dist/utils/primitive.d.ts.map +1 -1
  63. package/dist/utils/primitive.js +2 -2
  64. package/dist/utils/primitive.js.map +1 -1
  65. package/dist/utils/str.d.ts +16 -16
  66. package/dist/utils/str.d.ts.map +1 -1
  67. package/dist/utils/str.js +16 -16
  68. package/dist/utils/str.js.map +1 -1
  69. package/dist/utils/transferable.d.ts +3 -3
  70. package/dist/utils/transferable.d.ts.map +1 -1
  71. package/dist/utils/transferable.js +10 -10
  72. package/dist/utils/transferable.js.map +1 -1
  73. package/dist/utils/wait.d.ts +2 -2
  74. package/dist/utils/wait.d.ts.map +1 -1
  75. package/dist/utils/wait.js +5 -5
  76. package/dist/utils/wait.js.map +1 -1
  77. package/dist/utils/xml.d.ts +2 -2
  78. package/dist/utils/xml.d.ts.map +1 -1
  79. package/dist/utils/xml.js +4 -4
  80. package/dist/utils/xml.js.map +1 -1
  81. package/dist/{zip/sd-zip.d.ts → utils/zip.d.ts} +1 -1
  82. package/dist/utils/zip.d.ts.map +1 -0
  83. package/dist/{zip/sd-zip.js → utils/zip.js} +1 -1
  84. package/dist/{zip/sd-zip.js.map → utils/zip.js.map} +1 -1
  85. package/package.json +3 -3
  86. package/src/extensions/arr-ext.helpers.ts +86 -0
  87. package/src/extensions/arr-ext.ts +22 -170
  88. package/src/extensions/arr-ext.types.ts +76 -48
  89. package/src/extensions/map-ext.ts +3 -3
  90. package/src/extensions/set-ext.ts +2 -2
  91. package/src/features/event-emitter.ts +6 -6
  92. package/src/features/serial-queue.ts +2 -2
  93. package/src/index.ts +16 -16
  94. package/src/types/date-only.ts +2 -2
  95. package/src/types/date-time.ts +2 -2
  96. package/src/types/time.ts +2 -2
  97. package/src/types/uuid.ts +2 -2
  98. package/src/utils/bytes.ts +15 -15
  99. package/src/utils/date-format.ts +1 -1
  100. package/src/utils/error.ts +1 -1
  101. package/src/utils/json.ts +9 -7
  102. package/src/utils/num.ts +15 -15
  103. package/src/utils/obj.ts +119 -116
  104. package/src/utils/path.ts +3 -3
  105. package/src/utils/primitive.ts +1 -1
  106. package/src/utils/str.ts +16 -16
  107. package/src/utils/transferable.ts +9 -9
  108. package/src/utils/wait.ts +3 -3
  109. package/src/utils/xml.ts +2 -2
  110. package/tests/extensions/array-extension.spec.ts +7 -149
  111. package/tests/extensions/map-extension.spec.ts +0 -30
  112. package/tests/extensions/set-extension.spec.ts +0 -7
  113. package/tests/types/date-only.spec.ts +0 -105
  114. package/tests/types/date-time.spec.ts +0 -145
  115. package/tests/types/lazy-gc-map.spec.ts +0 -86
  116. package/tests/types/time.spec.ts +0 -131
  117. package/tests/types/uuid.spec.ts +4 -4
  118. package/tests/utils/bytes-utils.spec.ts +42 -75
  119. package/tests/utils/date-format.spec.ts +89 -112
  120. package/tests/utils/debounce-queue.spec.ts +3 -49
  121. package/tests/utils/json.spec.ts +61 -147
  122. package/tests/utils/number.spec.ts +41 -62
  123. package/tests/utils/object.spec.ts +120 -139
  124. package/tests/utils/path.spec.ts +19 -27
  125. package/tests/utils/primitive.spec.ts +12 -12
  126. package/tests/utils/sd-event-emitter.spec.ts +0 -27
  127. package/tests/utils/serial-queue.spec.ts +0 -60
  128. package/tests/utils/string.spec.ts +66 -82
  129. package/tests/utils/template-strings.spec.ts +0 -9
  130. package/tests/utils/transferable.spec.ts +55 -119
  131. package/tests/utils/wait.spec.ts +10 -32
  132. package/tests/utils/xml.spec.ts +25 -25
  133. package/tests/{zip/sd-zip.spec.ts → utils/zip.spec.ts} +0 -17
  134. package/dist/zip/sd-zip.d.ts.map +0 -1
  135. /package/src/{zip/sd-zip.ts → utils/zip.ts} +0 -0
package/src/utils/path.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  * Combine paths (path.join replacement)
12
12
  * @note Supports POSIX style paths only (slash `/`)
13
13
  */
14
- export function pathJoin(...segments: string[]): string {
14
+ export function join(...segments: string[]): string {
15
15
  return segments
16
16
  .map((s, i) => (i === 0 ? s.replace(/\/+$/, "") : s.replace(/^\/+|\/+$/g, "")))
17
17
  .filter(Boolean)
@@ -21,7 +21,7 @@ export function pathJoin(...segments: string[]): string {
21
21
  /**
22
22
  * Extract filename (path.basename replacement)
23
23
  */
24
- export function pathBasename(filePath: string, ext?: string): string {
24
+ export function basename(filePath: string, ext?: string): string {
25
25
  const name = filePath.split("/").pop() ?? "";
26
26
  if (ext != null && ext !== "" && name.endsWith(ext)) {
27
27
  return name.slice(0, -ext.length);
@@ -33,7 +33,7 @@ export function pathBasename(filePath: string, ext?: string): string {
33
33
  * Extract file extension (path.extname replacement)
34
34
  * @note Hidden files (e.g., `.gitignore`) return empty string (same as Node.js path.extname)
35
35
  */
36
- export function pathExtname(filePath: string): string {
36
+ export function extname(filePath: string): string {
37
37
  const name = filePath.split("/").pop() ?? "";
38
38
  const dotIndex = name.lastIndexOf(".");
39
39
  return dotIndex > 0 ? name.slice(dotIndex) : "";
@@ -20,7 +20,7 @@ import type { PrimitiveTypeMap, PrimitiveTypeStr } from "../common.types";
20
20
  * getPrimitiveTypeStr(new DateTime()) // "DateTime"
21
21
  * getPrimitiveTypeStr(new Uint8Array()) // "Bytes"
22
22
  */
23
- export function getPrimitiveTypeStr(value: PrimitiveTypeMap[PrimitiveTypeStr]): PrimitiveTypeStr {
23
+ export function typeStr(value: PrimitiveTypeMap[PrimitiveTypeStr]): PrimitiveTypeStr {
24
24
  if (typeof value === "string") return "string";
25
25
  if (typeof value === "number") return "number";
26
26
  if (typeof value === "boolean") return "boolean";
package/src/utils/str.ts CHANGED
@@ -28,10 +28,10 @@ const suffixTable = {
28
28
  * - `"라"`: 이라/라 (ira/ra - copula particle)
29
29
  *
30
30
  * @example
31
- * koreanGetSuffix("Apple", "을") // "를"
32
- * koreanGetSuffix("책", "이") // "이"
31
+ * getKoreanSuffix("Apple", "을") // "를"
32
+ * getKoreanSuffix("책", "이") // "이"
33
33
  */
34
- export function koreanGetSuffix(
34
+ export function getKoreanSuffix(
35
35
  text: string,
36
36
  type: "을" | "은" | "이" | "와" | "랑" | "로" | "라",
37
37
  ): string {
@@ -147,10 +147,10 @@ const fullWidthCharRegex = new RegExp(`[${Object.keys(fullWidthCharMap).join("")
147
147
  * - Full-width parentheses (() → ())
148
148
  *
149
149
  * @example
150
- * strReplaceFullWidth("A123") // "A123"
151
- * strReplaceFullWidth("(株)") // "(株)"
150
+ * replaceFullWidth("A123") // "A123"
151
+ * replaceFullWidth("(株)") // "(株)"
152
152
  */
153
- export function strReplaceFullWidth(str: string): string {
153
+ export function replaceFullWidth(str: string): string {
154
154
  return str.replace(fullWidthCharRegex, (char) => fullWidthCharMap[char] ?? char);
155
155
  }
156
156
 
@@ -164,7 +164,7 @@ export function strReplaceFullWidth(str: string): string {
164
164
  * @example "hello_world" → "HelloWorld"
165
165
  * @example "hello.world" → "HelloWorld"
166
166
  */
167
- export function strToPascalCase(str: string): string {
167
+ export function toPascalCase(str: string): string {
168
168
  return str
169
169
  .replace(/[-._][a-z]/g, (m) => m[1].toUpperCase())
170
170
  .replace(/^[a-z]/, (m) => m.toUpperCase());
@@ -176,7 +176,7 @@ export function strToPascalCase(str: string): string {
176
176
  * @example "hello_world" → "helloWorld"
177
177
  * @example "HelloWorld" → "helloWorld"
178
178
  */
179
- export function strToCamelCase(str: string): string {
179
+ export function toCamelCase(str: string): string {
180
180
  return str
181
181
  .replace(/[-._][a-z]/g, (m) => m[1].toUpperCase())
182
182
  .replace(/^[A-Z]/, (m) => m.toLowerCase());
@@ -192,7 +192,7 @@ export function strToCamelCase(str: string): string {
192
192
  * @example "Hello-World" → "hello--world" (existing separators are preserved)
193
193
  * @example "XMLParser" → "x-m-l-parser" (consecutive uppercase letters are separated)
194
194
  */
195
- export function strToKebabCase(str: string): string {
195
+ export function toKebabCase(str: string): string {
196
196
  return toCaseWithSeparator(str, "-");
197
197
  }
198
198
 
@@ -206,7 +206,7 @@ export function strToKebabCase(str: string): string {
206
206
  * @example "Hello_World" → "hello__world" (existing separators are preserved)
207
207
  * @example "XMLParser" → "x_m_l_parser" (consecutive uppercase letters are separated)
208
208
  */
209
- export function strToSnakeCase(str: string): string {
209
+ export function toSnakeCase(str: string): string {
210
210
  return toCaseWithSeparator(str, "_");
211
211
  }
212
212
 
@@ -228,7 +228,7 @@ function toCaseWithSeparator(str: string, separator: string): string {
228
228
  *
229
229
  * @example
230
230
  * const name: string | undefined = getValue();
231
- * if (strIsNullOrEmpty(name)) {
231
+ * if (isNullOrEmpty(name)) {
232
232
  * // name: "" | undefined
233
233
  * console.log("Name is empty");
234
234
  * } else {
@@ -236,7 +236,7 @@ function toCaseWithSeparator(str: string, separator: string): string {
236
236
  * console.log(`Name: ${name}`);
237
237
  * }
238
238
  */
239
- export function strIsNullOrEmpty(str: string | undefined): str is "" | undefined {
239
+ export function isNullOrEmpty(str: string | undefined): str is "" | undefined {
240
240
  return str == null || str === "";
241
241
  }
242
242
 
@@ -249,11 +249,11 @@ export function strIsNullOrEmpty(str: string | undefined): str is "" | undefined
249
249
  * @returns A new string with the insertion applied
250
250
  *
251
251
  * @example
252
- * strInsert("Hello World", 5, ","); // "Hello, World"
253
- * strInsert("abc", 0, "X"); // "Xabc"
254
- * strInsert("abc", 3, "X"); // "abcX"
252
+ * insert("Hello World", 5, ","); // "Hello, World"
253
+ * insert("abc", 0, "X"); // "Xabc"
254
+ * insert("abc", 3, "X"); // "abcX"
255
255
  */
256
- export function strInsert(str: string, index: number, insertString: string): string {
256
+ export function insert(str: string, index: number, insertString: string): string {
257
257
  return str.substring(0, index) + insertString + str.substring(index);
258
258
  }
259
259
 
@@ -32,7 +32,7 @@ type Transferable = ArrayBuffer;
32
32
  * worker.postMessage(result, transferList);
33
33
  *
34
34
  * // Receive data from Worker
35
- * const decoded = transferableDecode(event.data);
35
+ * const decoded = decode(event.data);
36
36
  */
37
37
 
38
38
  //#region encode
@@ -43,7 +43,7 @@ type Transferable = ArrayBuffer;
43
43
  *
44
44
  * @throws TypeError if circular reference is detected
45
45
  */
46
- export function transferableEncode(obj: unknown): {
46
+ export function encode(obj: unknown): {
47
47
  result: unknown;
48
48
  transferList: Transferable[];
49
49
  } {
@@ -204,7 +204,7 @@ function encodeImpl(
204
204
  * Convert serialized objects to objects using Simplysm types
205
205
  * Deserialize data received from a Worker
206
206
  */
207
- export function transferableDecode(obj: unknown): unknown {
207
+ export function decode(obj: unknown): unknown {
208
208
  if (obj == null) return obj;
209
209
 
210
210
  // 1. Restore special types from tagged objects
@@ -239,22 +239,22 @@ export function transferableDecode(obj: unknown): unknown {
239
239
  err.stack = errorData.stack;
240
240
 
241
241
  if (errorData.code !== undefined) err.code = errorData.code;
242
- if (errorData.cause !== undefined) (err as Error).cause = transferableDecode(errorData.cause);
243
- if (errorData.detail !== undefined) err.detail = transferableDecode(errorData.detail);
242
+ if (errorData.cause !== undefined) (err as Error).cause = decode(errorData.cause);
243
+ if (errorData.detail !== undefined) err.detail = decode(errorData.detail);
244
244
  return err;
245
245
  }
246
246
  }
247
247
 
248
248
  // 2. Array recursion
249
249
  if (Array.isArray(obj)) {
250
- return obj.map((item) => transferableDecode(item));
250
+ return obj.map((item) => decode(item));
251
251
  }
252
252
 
253
253
  // 3. Map recursion
254
254
  if (obj instanceof Map) {
255
255
  const newMap = new Map<unknown, unknown>();
256
256
  for (const [k, v] of obj) {
257
- newMap.set(transferableDecode(k), transferableDecode(v));
257
+ newMap.set(decode(k), decode(v));
258
258
  }
259
259
  return newMap;
260
260
  }
@@ -263,7 +263,7 @@ export function transferableDecode(obj: unknown): unknown {
263
263
  if (obj instanceof Set) {
264
264
  const newSet = new Set<unknown>();
265
265
  for (const v of obj) {
266
- newSet.add(transferableDecode(v));
266
+ newSet.add(decode(v));
267
267
  }
268
268
  return newSet;
269
269
  }
@@ -273,7 +273,7 @@ export function transferableDecode(obj: unknown): unknown {
273
273
  const record = obj as Record<string, unknown>;
274
274
  const result: Record<string, unknown> = {};
275
275
  for (const key of Object.keys(record)) {
276
- result[key] = transferableDecode(record[key]);
276
+ result[key] = decode(record[key]);
277
277
  }
278
278
  return result;
279
279
  }
package/src/utils/wait.ts CHANGED
@@ -15,7 +15,7 @@ import { TimeoutError } from "../errors/timeout-error";
15
15
  * await waitUntil(() => someCondition, 100, 3);
16
16
  * @throws TimeoutError when maximum number of attempts is exceeded
17
17
  */
18
- export async function waitUntil(
18
+ export async function until(
19
19
  forwarder: () => boolean | Promise<boolean>,
20
20
  milliseconds?: number,
21
21
  maxCount?: number,
@@ -27,7 +27,7 @@ export async function waitUntil(
27
27
  throw new TimeoutError(count);
28
28
  }
29
29
 
30
- await waitTime(milliseconds ?? 100);
30
+ await time(milliseconds ?? 100);
31
31
  }
32
32
  }
33
33
 
@@ -35,6 +35,6 @@ export async function waitUntil(
35
35
  * Wait for a specified amount of time
36
36
  * @param millisecond Wait time (ms)
37
37
  */
38
- export async function waitTime(millisecond: number): Promise<void> {
38
+ export async function time(millisecond: number): Promise<void> {
39
39
  return new Promise<void>((resolve) => setTimeout(resolve, millisecond));
40
40
  }
package/src/utils/xml.ts CHANGED
@@ -19,7 +19,7 @@ import { XMLBuilder, XMLParser } from "fast-xml-parser";
19
19
  * xmlParse('<root id="1"><item>hello</item></root>');
20
20
  * // { root: { $: { id: "1" }, item: [{ _: "hello" }] } }
21
21
  */
22
- export function xmlParse(str: string, options?: { stripTagPrefix?: boolean }): unknown {
22
+ export function parse(str: string, options?: { stripTagPrefix?: boolean }): unknown {
23
23
  const result = new XMLParser({
24
24
  ignoreAttributes: false,
25
25
  attributeNamePrefix: "",
@@ -53,7 +53,7 @@ export function xmlParse(str: string, options?: { stripTagPrefix?: boolean }): u
53
53
  * });
54
54
  * // '<root id="1"><item>hello</item><item>world</item></root>'
55
55
  */
56
- export function xmlStringify(obj: unknown, options?: XmlBuilderOptions): string {
56
+ export function stringify(obj: unknown, options?: XmlBuilderOptions): string {
57
57
  return new XMLBuilder({
58
58
  ignoreAttributes: false,
59
59
  attributeNamePrefix: "",
@@ -2,65 +2,6 @@ import { describe, it, expect } from "vitest";
2
2
  import "@simplysm/core-common"; // Enable $ extension
3
3
 
4
4
  describe("Array prototype extensions", () => {
5
- //#region Basic chaining
6
-
7
- describe("Basic chaining", () => {
8
- it("Can chain existing array methods", () => {
9
- const result = [1, 2, 3, 4, 5].filter((x) => x > 2).map((x) => x * 10);
10
-
11
- expect(result).toEqual([30, 40, 50]);
12
- });
13
-
14
- it("Can chain extension methods", () => {
15
- const result = [
16
- { id: 1, name: "a" },
17
- { id: 2, name: "b" },
18
- ].toMap((x) => x.id);
19
-
20
- expect(result.get(1)).toEqual({ id: 1, name: "a" });
21
- expect(result.get(2)).toEqual({ id: 2, name: "b" });
22
- });
23
-
24
- it("Can mix array and extension methods chaining", () => {
25
- const users = [
26
- { id: 1, name: "Kim", active: true },
27
- { id: 2, name: "Lee", active: false },
28
- { id: 3, name: "Park", active: true },
29
- ];
30
-
31
- const result = users.filter((u) => u.active).toMap((u) => u.id);
32
-
33
- expect(result.size).toBe(2);
34
- expect(result.has(1)).toBe(true);
35
- expect(result.has(3)).toBe(true);
36
- expect(result.has(2)).toBe(false);
37
- });
38
-
39
- it("Can chain multiple steps", () => {
40
- const result = [1, 2, 3, 4, 5]
41
- .filter((x) => x > 1)
42
- .map((x) => x * 2)
43
- .filter((x) => x < 10)
44
- .toMap((x) => x);
45
-
46
- expect(result.size).toBe(3);
47
- expect(result.has(4)).toBe(true);
48
- expect(result.has(6)).toBe(true);
49
- expect(result.has(8)).toBe(true);
50
- });
51
-
52
- it("Can access array properties", () => {
53
- const arr = [1, 2, 3];
54
-
55
- expect(arr.length).toBe(3);
56
- expect(arr[0]).toBe(1);
57
- expect(arr[1]).toBe(2);
58
- expect(arr[2]).toBe(3);
59
- });
60
- });
61
-
62
- //#endregion
63
-
64
5
  //#region single
65
6
 
66
7
  describe("single()", () => {
@@ -85,12 +26,6 @@ describe("Array prototype extensions", () => {
85
26
  expect(([] as number[]).single()).toBe(undefined);
86
27
  expect(() => [1, 2].single()).toThrow();
87
28
  });
88
-
89
- it("Can use single after chaining", () => {
90
- const result = [1, 2, 3, 4, 5].filter((x) => x > 3).single((x) => x === 4);
91
-
92
- expect(result).toBe(4);
93
- });
94
29
  });
95
30
 
96
31
  //#endregion
@@ -111,14 +46,6 @@ describe("Array prototype extensions", () => {
111
46
 
112
47
  expect(result).toEqual([2, 4, 6]);
113
48
  });
114
-
115
- it("Can use mapAsync after chaining", async () => {
116
- const result = await [1, 2, 3, 4, 5]
117
- .filter((x) => x > 2)
118
- .mapAsync(async (x) => Promise.resolve(x * 10));
119
-
120
- expect(result).toEqual([30, 40, 50]);
121
- });
122
49
  });
123
50
 
124
51
  describe("filterAsync()", () => {
@@ -269,6 +196,7 @@ describe("Array prototype extensions", () => {
269
196
  describe("diffs()", () => {
270
197
  it("Analyzes differences between arrays", () => {
271
198
  interface Item {
199
+ [key: string]: unknown;
272
200
  id: number;
273
201
  value: string;
274
202
  }
@@ -287,13 +215,13 @@ describe("Array prototype extensions", () => {
287
215
 
288
216
  const result = source.diffs(target, { keys: ["id"] });
289
217
 
290
- const deleted = result.find((d) => d.source?.id === 1);
218
+ const deleted = result.find((d) => d.source?.["id"] === 1);
291
219
  expect(deleted?.target).toBe(undefined);
292
220
 
293
- const updated = result.find((d) => d.source?.id === 3);
294
- expect(updated?.target?.value).toBe("changed");
221
+ const updated = result.find((d) => d.source?.["id"] === 3);
222
+ expect(updated?.target?.["value"]).toBe("changed");
295
223
 
296
- const inserted = result.find((d) => d.target?.id === 4);
224
+ const inserted = result.find((d) => d.target?.["id"] === 4);
297
225
  expect(inserted?.source).toBe(undefined);
298
226
  });
299
227
  });
@@ -353,6 +281,7 @@ describe("Array prototype extensions", () => {
353
281
  describe("merge()", () => {
354
282
  it("Merges modified items", () => {
355
283
  interface Item {
284
+ [key: string]: unknown;
356
285
  id: number;
357
286
  value: string;
358
287
  }
@@ -369,62 +298,7 @@ describe("Array prototype extensions", () => {
369
298
  const result = source.merge(target, { keys: ["id"] });
370
299
 
371
300
  expect(result).toHaveLength(2);
372
- expect(result.find((r) => r.id === 2)?.value).toBe("changed");
373
- });
374
- });
375
-
376
- //#endregion
377
-
378
- //#region ReadonlyArray support
379
-
380
- describe("ReadonlyArray support", () => {
381
- it("$ can be used with readonly array", () => {
382
- const arr: readonly number[] = [1, 2, 3];
383
- const result = arr.filter((x) => x > 1).toMap((x) => x);
384
-
385
- expect(result.size).toBe(2);
386
- expect(result.has(2)).toBe(true);
387
- expect(result.has(3)).toBe(true);
388
- });
389
- });
390
-
391
- //#endregion
392
-
393
- //#region Various array method chaining
394
-
395
- describe("Various array method chaining", () => {
396
- it("flatMap can be chained", () => {
397
- const result = [
398
- [1, 2],
399
- [3, 4],
400
- ]
401
- .flatMap((x) => x)
402
- .toMap((x) => x);
403
-
404
- expect(result.size).toBe(4);
405
- });
406
-
407
- it("slice can be chained", () => {
408
- const result = [1, 2, 3, 4, 5].slice(1, 4).toMap((x) => x);
409
-
410
- expect(result.size).toBe(3);
411
- expect(result.has(2)).toBe(true);
412
- expect(result.has(3)).toBe(true);
413
- expect(result.has(4)).toBe(true);
414
- });
415
-
416
- it("concat can be chained", () => {
417
- const result = [1, 2].concat([3, 4]).toMap((x) => x);
418
-
419
- expect(result.size).toBe(4);
420
- });
421
-
422
- it("sort can be chained", () => {
423
- const result = [3, 1, 2].sort((a, b) => a - b).toMap((x, i) => i);
424
-
425
- expect(result.get(0)).toBe(1);
426
- expect(result.get(1)).toBe(2);
427
- expect(result.get(2)).toBe(3);
301
+ expect(result.find((r) => r["id"] === 2)?.["value"]).toBe("changed");
428
302
  });
429
303
  });
430
304
 
@@ -470,12 +344,6 @@ describe("Array prototype extensions", () => {
470
344
  const result = arr.filterExists();
471
345
  expect(result).toEqual([1, 2, 3]);
472
346
  });
473
-
474
- it("Can be chained", () => {
475
- const arr = [1, null, 2, undefined, 3];
476
- const result = arr.filterExists().map((x) => x * 2);
477
- expect(result).toEqual([2, 4, 6]);
478
- });
479
347
  });
480
348
 
481
349
  describe("ofType()", () => {
@@ -582,11 +450,6 @@ describe("Array prototype extensions", () => {
582
450
  expect(result).toHaveLength(2);
583
451
  });
584
452
 
585
- it("Can be chained", () => {
586
- const result = [1, 2, 2, 3].distinct().map((x) => x * 2);
587
- expect(result).toEqual([2, 4, 6]);
588
- });
589
-
590
453
  it("Can use custom key with keyFn", () => {
591
454
  const arr = [
592
455
  { id: 1, name: "a" },
@@ -626,11 +489,6 @@ describe("Array prototype extensions", () => {
626
489
  const result = items.orderBy((x) => x.age);
627
490
  expect(result.map((x) => x.age)).toEqual([20, 25, 30]);
628
491
  });
629
-
630
- it("Can be chained", () => {
631
- const result = [3, 1, 2].orderBy().map((x) => x * 2);
632
- expect(result).toEqual([2, 4, 6]);
633
- });
634
492
  });
635
493
 
636
494
  describe("orderByDesc()", () => {
@@ -44,16 +44,6 @@ describe("Map prototype extensions", () => {
44
44
  expect(map.get("key")).toBe(50);
45
45
  });
46
46
 
47
- it("Returns existing value if key exists (direct value)", () => {
48
- const map = new Map<string, number>();
49
- map.set("key", 50);
50
-
51
- const result = map.getOrCreate("key", 100);
52
-
53
- expect(result).toBe(50);
54
- expect(map.size).toBe(1);
55
- });
56
-
57
47
  it("Can set empty array as default value", () => {
58
48
  const map = new Map<string, number[]>();
59
49
 
@@ -121,26 +111,6 @@ describe("Map prototype extensions", () => {
121
111
 
122
112
  expect(map.get("key")).toBe("hello world");
123
113
  });
124
-
125
- it("Can update object value", () => {
126
- const map = new Map<string, { count: number }>();
127
- map.set("key", { count: 5 });
128
-
129
- map.update("key", (v) => ({ count: (v?.count ?? 0) + 1 }));
130
-
131
- expect(map.get("key")).toEqual({ count: 6 });
132
- });
133
-
134
- it("Can update multiple times sequentially", () => {
135
- const map = new Map<string, number>();
136
- map.set("counter", 0);
137
-
138
- map.update("counter", (v) => (v ?? 0) + 1);
139
- map.update("counter", (v) => (v ?? 0) + 1);
140
- map.update("counter", (v) => (v ?? 0) + 1);
141
-
142
- expect(map.get("counter")).toBe(3);
143
- });
144
114
  });
145
115
 
146
116
  //#endregion
@@ -22,13 +22,6 @@ describe("Set prototype extensions", () => {
22
22
 
23
23
  expect(set.size).toBe(4); // 1, 2, 3, 4
24
24
  });
25
-
26
- it("Adds multiple items to empty Set", () => {
27
- const set = new Set<number>();
28
- set.adds(1, 2, 3);
29
-
30
- expect(set.size).toBe(3);
31
- });
32
25
  });
33
26
 
34
27
  //#endregion
@@ -109,22 +109,6 @@ describe("DateOnly", () => {
109
109
  expect(() => DateOnly.parse("invalid-date")).toThrow("Failed to parse date format");
110
110
  });
111
111
 
112
- it("Parses year-end boundary (December 31)", () => {
113
- const dateOnly = DateOnly.parse("2024-12-31");
114
-
115
- expect(dateOnly.year).toBe(2024);
116
- expect(dateOnly.month).toBe(12);
117
- expect(dateOnly.day).toBe(31);
118
- });
119
-
120
- it("Parses year-start boundary (January 1)", () => {
121
- const dateOnly = DateOnly.parse("2025-01-01");
122
-
123
- expect(dateOnly.year).toBe(2025);
124
- expect(dateOnly.month).toBe(1);
125
- expect(dateOnly.day).toBe(1);
126
- });
127
-
128
112
  it("Parses February 29 in leap year", () => {
129
113
  const dateOnly = DateOnly.parse("2024-02-29");
130
114
 
@@ -132,14 +116,6 @@ describe("DateOnly", () => {
132
116
  expect(dateOnly.month).toBe(2);
133
117
  expect(dateOnly.day).toBe(29);
134
118
  });
135
-
136
- it("Parses February 28 in leap year", () => {
137
- const dateOnly = DateOnly.parse("2024-02-28");
138
-
139
- expect(dateOnly.year).toBe(2024);
140
- expect(dateOnly.month).toBe(2);
141
- expect(dateOnly.day).toBe(28);
142
- });
143
119
  });
144
120
 
145
121
  //#endregion
@@ -147,37 +123,6 @@ describe("DateOnly", () => {
147
123
  //#region Getters
148
124
 
149
125
  describe("Getters", () => {
150
- it("Returns year", () => {
151
- const dateOnly = new DateOnly(2025, 1, 6);
152
- expect(dateOnly.year).toBe(2025);
153
- });
154
-
155
- it("Returns month (1-12)", () => {
156
- const dateOnly = new DateOnly(2025, 1, 6);
157
- expect(dateOnly.month).toBe(1);
158
- });
159
-
160
- it("Returns day", () => {
161
- const dateOnly = new DateOnly(2025, 1, 6);
162
- expect(dateOnly.day).toBe(6);
163
- });
164
-
165
- it("Returns tick", () => {
166
- const dateOnly = new DateOnly(2025, 1, 6);
167
- expect(dateOnly.tick).toBe(new Date(2025, 0, 6).getTime());
168
- });
169
-
170
- it("Returns dayOfWeek (Sunday-Saturday: 0-6)", () => {
171
- // 2025-01-06 is Monday (1)
172
- const dateOnly = new DateOnly(2025, 1, 6);
173
- expect(dateOnly.dayOfWeek).toBe(1);
174
- });
175
-
176
- it("Returns isValid", () => {
177
- const dateOnly = new DateOnly(2025, 1, 6);
178
- expect(dateOnly.isValid).toBe(true);
179
- });
180
-
181
126
  it("Invalid date returns isValid as false", () => {
182
127
  const dateOnly = new DateOnly(NaN);
183
128
  expect(dateOnly.isValid).toBe(false);
@@ -257,18 +202,6 @@ describe("DateOnly", () => {
257
202
  });
258
203
  });
259
204
 
260
- describe("setDay()", () => {
261
- it("Returns new instance with day changed", () => {
262
- const dateOnly = new DateOnly(2025, 1, 6);
263
- const newDateOnly = dateOnly.setDay(15);
264
-
265
- expect(newDateOnly.year).toBe(2025);
266
- expect(newDateOnly.month).toBe(1);
267
- expect(newDateOnly.day).toBe(15);
268
- expect(dateOnly.day).toBe(6); // original immutable
269
- });
270
- });
271
-
272
205
  //#endregion
273
206
 
274
207
  //#region addX methods (immutable)
@@ -379,44 +312,6 @@ describe("DateOnly", () => {
379
312
 
380
313
  //#endregion
381
314
 
382
- //#region tick comparison
383
-
384
- describe("tick comparison", () => {
385
- it("Same dates have same tick", () => {
386
- const d1 = new DateOnly(2025, 3, 15);
387
- const d2 = new DateOnly(2025, 3, 15);
388
-
389
- expect(d1.tick).toBe(d2.tick);
390
- });
391
-
392
- it("Different dates have different ticks", () => {
393
- const d1 = new DateOnly(2025, 3, 15);
394
- const d2 = new DateOnly(2025, 3, 16);
395
-
396
- expect(d1.tick).not.toBe(d2.tick);
397
- });
398
-
399
- it("Can compare date order by tick", () => {
400
- const d1 = new DateOnly(2025, 1, 1);
401
- const d2 = new DateOnly(2025, 6, 15);
402
- const d3 = new DateOnly(2025, 12, 31);
403
-
404
- expect(d1.tick).toBeLessThan(d2.tick);
405
- expect(d2.tick).toBeLessThan(d3.tick);
406
- });
407
-
408
- it("Can compare dates with different years by tick", () => {
409
- const d2024 = new DateOnly(2024, 12, 31);
410
- const d2025 = new DateOnly(2025, 1, 1);
411
-
412
- expect(d2024.tick).toBeLessThan(d2025.tick);
413
- });
414
- });
415
-
416
- //#endregion
417
-
418
- //#endregion
419
-
420
315
  //#region Week calculation
421
316
 
422
317
  describe("getWeekSeqOfYear()", () => {