@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
package/src/utils/xml.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * XML conversion utility
2
+ * XML 변환 유틸리티
3
3
  */
4
4
  import type { XmlBuilderOptions } from "fast-xml-parser";
5
5
  import { XMLBuilder, XMLParser } from "fast-xml-parser";
@@ -7,14 +7,14 @@ import { XMLBuilder, XMLParser } from "fast-xml-parser";
7
7
  //#region parse
8
8
 
9
9
  /**
10
- * Parse XML string into an object
11
- * @param str XML string
12
- * @param options Options
13
- * @param options.stripTagPrefix Whether to remove tag prefix (namespace)
14
- * @returns Parsed object. Structure:
15
- * - Attributes: grouped in `$` object
16
- * - Text nodes: stored in `_` key
17
- * - Child elements: converted to array (except root element)
10
+ * XML 문자열을 객체로 파싱
11
+ * @param str XML 문자열
12
+ * @param options 옵션
13
+ * @param options.stripTagPrefix 태그 접두사(네임스페이스) 제거 여부
14
+ * @returns 파싱된 객체. 구조:
15
+ * - 속성: `$` 객체에 그룹화
16
+ * - 텍스트 노드: `_` key에 저장
17
+ * - 자식 요소: array로 변환 (루트 요소 제외)
18
18
  * @example
19
19
  * xmlParse('<root id="1"><item>hello</item></root>');
20
20
  * // { root: { $: { id: "1" }, item: [{ _: "hello" }] } }
@@ -40,10 +40,10 @@ export function parse(str: string, options?: { stripTagPrefix?: boolean }): unkn
40
40
  //#region stringify
41
41
 
42
42
  /**
43
- * Serialize object to XML string
44
- * @param obj Object to serialize
45
- * @param options fast-xml-parser XmlBuilderOptions (optional)
46
- * @returns XML string
43
+ * 객체를 XML 문자열로 직렬화
44
+ * @param obj 직렬화할 객체
45
+ * @param options fast-xml-parser XmlBuilderOptions (선택사항)
46
+ * @returns XML 문자열
47
47
  * @example
48
48
  * xmlStringify({
49
49
  * root: {
@@ -69,10 +69,10 @@ export function stringify(obj: unknown, options?: XmlBuilderOptions): string {
69
69
  //#region private
70
70
 
71
71
  /**
72
- * Remove namespace prefix from tag name
73
- * @note Removes the namespace prefix in the format "ns:tag" from XML parsing results, leaving only the tag name.
74
- * This allows consistent access to XML data without considering namespace.
75
- * However, attributes are kept with their prefix.
72
+ * 태그 이름에서 네임스페이스 접두사 제거
73
+ * @note XML 파싱 결과에서 "ns:tag" 형식의 네임스페이스 접두사를 제거하여 태그 이름만 남김.
74
+ * 네임스페이스를 고려하지 않고 XML 데이터에 일관되게 접근 가능.
75
+ * 단, 속성은 접두사가 유지됨.
76
76
  */
77
77
  function stripTagPrefix(obj: unknown): unknown {
78
78
  if (Array.isArray(obj)) {
@@ -86,11 +86,11 @@ function stripTagPrefix(obj: unknown): unknown {
86
86
  for (const key of Object.keys(record)) {
87
87
  const value = record[key];
88
88
 
89
- // Attributes must not have prefix removed
89
+ // 속성은 접두사를 제거하면
90
90
  if (key === "$") {
91
91
  newObj[key] = value;
92
92
  } else {
93
- // Remove prefix from tag names only, based on first ":"
93
+ // 번째 ":"를 기준으로 태그 이름에서만 접두사 제거
94
94
  const colonIndex = key.indexOf(":");
95
95
  const cleanKey = colonIndex !== -1 ? key.slice(colonIndex + 1) : key;
96
96
  newObj[cleanKey] = stripTagPrefix(value);
package/src/utils/zip.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * ZIP file processing utility
2
+ * ZIP 파일 처리 유틸리티
3
3
  */
4
4
  import type { FileEntry } from "@zip.js/zip.js";
5
5
  import {
@@ -18,25 +18,25 @@ export interface ZipArchiveProgress {
18
18
  }
19
19
 
20
20
  /**
21
- * ZIP archive processing class
21
+ * ZIP 아카이브 처리 클래스
22
22
  *
23
- * Handles reading, writing, compression, and decompression of ZIP files.
24
- * Uses internal caching to prevent duplicate decompression of the same file.
23
+ * ZIP 파일의 읽기, 쓰기, 압축, 해제를 처리.
24
+ * 동일 파일의 중복 해제를 방지하기 위해 내부 캐싱 사용.
25
25
  *
26
26
  * @example
27
- * // Read ZIP file
27
+ * // ZIP 파일 읽기
28
28
  * await using archive = new ZipArchive(zipBytes);
29
29
  * const content = await archive.get("file.txt");
30
30
  *
31
31
  * @example
32
- * // Create ZIP file
32
+ * // ZIP 파일 생성
33
33
  * await using archive = new ZipArchive();
34
34
  * archive.write("file.txt", textBytes);
35
35
  * archive.write("data.json", jsonBytes);
36
36
  * const zipBytes = await archive.compress();
37
37
  *
38
38
  * @example
39
- * // Extract all files (with progress reporting)
39
+ * // 모든 파일 추출 (진행률 보고 포함)
40
40
  * await using archive = new ZipArchive(zipBytes);
41
41
  * const files = await archive.extractAll((progress) => {
42
42
  * console.log(`${progress.fileName}: ${progress.extractedSize}/${progress.totalSize}`);
@@ -48,8 +48,8 @@ export class ZipArchive {
48
48
  private _entries?: Awaited<ReturnType<ZipReader<Blob | Bytes>["getEntries"]>>;
49
49
 
50
50
  /**
51
- * Create ZipArchive
52
- * @param data ZIP data (omit to create a new archive)
51
+ * ZipArchive 생성
52
+ * @param data ZIP 데이터 (생략하면 아카이브 생성)
53
53
  */
54
54
  constructor(data?: Blob | Bytes) {
55
55
  if (!data) return;
@@ -70,8 +70,8 @@ export class ZipArchive {
70
70
 
71
71
  //#region extractAll
72
72
  /**
73
- * Extract all files
74
- * @param progressCallback Progress callback
73
+ * 모든 파일 추출
74
+ * @param progressCallback 진행률 콜백
75
75
  */
76
76
  async extractAll(
77
77
  progressCallback?: (progress: ZipArchiveProgress) => void,
@@ -79,7 +79,7 @@ export class ZipArchive {
79
79
  const entries = await this._getEntries();
80
80
  if (entries == null) return this._cache;
81
81
 
82
- // Calculate total size to extract
82
+ // 추출할 전체 크기 계산
83
83
  const totalSize = entries
84
84
  .filter((e) => !e.directory)
85
85
  .reduce((acc, e) => acc + e.uncompressedSize, 0);
@@ -112,7 +112,7 @@ export class ZipArchive {
112
112
 
113
113
  this._cache.set(entry.filename, entryBytes);
114
114
 
115
- // Accumulate when individual file completes
115
+ // 개별 파일 완료 누적
116
116
  totalExtracted += entry.uncompressedSize;
117
117
 
118
118
  progressCallback?.({
@@ -128,8 +128,8 @@ export class ZipArchive {
128
128
 
129
129
  //#region get
130
130
  /**
131
- * Extract specific file
132
- * @param fileName File name
131
+ * 특정 파일 추출
132
+ * @param fileName 파일 이름
133
133
  */
134
134
  async get(fileName: string): Promise<Bytes | undefined> {
135
135
  if (this._cache.has(fileName)) {
@@ -156,8 +156,8 @@ export class ZipArchive {
156
156
 
157
157
  //#region exists
158
158
  /**
159
- * Check if file exists
160
- * @param fileName File name
159
+ * 파일 존재 여부 확인
160
+ * @param fileName 파일 이름
161
161
  */
162
162
  async exists(fileName: string): Promise<boolean> {
163
163
  if (this._cache.has(fileName)) {
@@ -176,9 +176,9 @@ export class ZipArchive {
176
176
 
177
177
  //#region write
178
178
  /**
179
- * Write file (store in cache)
180
- * @param fileName File name
181
- * @param bytes File content
179
+ * 파일 쓰기 (캐시에 저장)
180
+ * @param fileName 파일 이름
181
+ * @param bytes 파일 내용
182
182
  */
183
183
  write(fileName: string, bytes: Bytes): void {
184
184
  this._cache.set(fileName, bytes);
@@ -187,11 +187,11 @@ export class ZipArchive {
187
187
 
188
188
  //#region compress
189
189
  /**
190
- * Compress cached files to ZIP
190
+ * 캐시된 파일을 ZIP으로 압축
191
191
  *
192
192
  * @remarks
193
- * Internally calls `extractAll()` to load all files into memory before compressing.
194
- * Be mindful of memory usage when dealing with large ZIP files.
193
+ * 내부적으로 `extractAll()`을 호출하여 모든 파일을 메모리에 로드한 압축.
194
+ * 대용량 ZIP 파일 처리 메모리 사용량에 주의.
195
195
  */
196
196
  async compress(): Promise<Bytes> {
197
197
  const fileMap = await this.extractAll();
@@ -211,7 +211,7 @@ export class ZipArchive {
211
211
 
212
212
  //#region close
213
213
  /**
214
- * Close reader and clear cache
214
+ * 리더 닫기 캐시 비우기
215
215
  */
216
216
  async close(): Promise<void> {
217
217
  await this._reader?.close();
@@ -219,7 +219,7 @@ export class ZipArchive {
219
219
  }
220
220
 
221
221
  /**
222
- * Support for await using
222
+ * await using 지원
223
223
  */
224
224
  async [Symbol.asyncDispose](): Promise<void> {
225
225
  await this.close();
@@ -1,387 +0,0 @@
1
- # Prototype Extensions (side-effect)
2
-
3
- Prototype extensions for `Array`, `Map`, and `Set`. These are applied as side effects when importing `@simplysm/core-common`.
4
-
5
- **Important:** Importing the package entry point automatically patches these prototypes. If you import only specific sub-modules, you must also import the extension modules or the entry point to get these methods.
6
-
7
- Source: `src/extensions/*.ts`
8
-
9
- ---
10
-
11
- ## Array Extensions
12
-
13
- ### Readonly methods (return new array or value, do not mutate)
14
-
15
- #### `single`
16
-
17
- Return single element matching condition. Throws `ArgumentError` if 2+ elements match.
18
-
19
- ```typescript
20
- single(predicate?: (item: T, index: number) => boolean): T | undefined;
21
- ```
22
-
23
- #### `first`
24
-
25
- Return first element.
26
-
27
- ```typescript
28
- first(predicate?: (item: T, index: number) => boolean): T | undefined;
29
- ```
30
-
31
- #### `last`
32
-
33
- Return last element.
34
-
35
- ```typescript
36
- last(predicate?: (item: T, index: number) => boolean): T | undefined;
37
- ```
38
-
39
- #### `filterAsync`
40
-
41
- Async filter (sequential execution).
42
-
43
- ```typescript
44
- filterAsync(predicate: (item: T, index: number) => Promise<boolean>): Promise<T[]>;
45
- ```
46
-
47
- #### `filterExists`
48
-
49
- Remove `null` and `undefined` values.
50
-
51
- ```typescript
52
- filterExists(): NonNullable<T>[];
53
- ```
54
-
55
- #### `ofType`
56
-
57
- Filter only elements of specific type (`PrimitiveTypeStr` or constructor type).
58
-
59
- ```typescript
60
- ofType<TKey extends PrimitiveTypeStr>(type: TKey): Extract<T, PrimitiveTypeMap[TKey]>[];
61
- ofType<TNarrow extends T>(type: Type<TNarrow>): TNarrow[];
62
- ```
63
-
64
- #### `mapAsync`
65
-
66
- Async mapping (sequential execution).
67
-
68
- ```typescript
69
- mapAsync<R>(selector: (item: T, index: number) => Promise<R>): Promise<R[]>;
70
- ```
71
-
72
- #### `mapMany`
73
-
74
- Flatten nested array, or map then flatten.
75
-
76
- ```typescript
77
- mapMany(): T extends readonly (infer U)[] ? U[] : T;
78
- mapMany<R>(selector: (item: T, index: number) => R[]): R[];
79
- ```
80
-
81
- #### `mapManyAsync`
82
-
83
- Async mapping and then flatten (sequential execution).
84
-
85
- ```typescript
86
- mapManyAsync<R>(selector: (item: T, index: number) => Promise<R[]>): Promise<R[]>;
87
- ```
88
-
89
- #### `parallelAsync`
90
-
91
- Async parallel processing using `Promise.all`.
92
-
93
- ```typescript
94
- parallelAsync<R>(fn: (item: T, index: number) => Promise<R>): Promise<R[]>;
95
- ```
96
-
97
- #### `groupBy`
98
-
99
- Group by key. O(n) for primitive keys, O(n^2) for object keys (deep comparison).
100
-
101
- ```typescript
102
- groupBy<K>(keySelector: (item: T, index: number) => K): { key: K; values: T[] }[];
103
- groupBy<K, V>(
104
- keySelector: (item: T, index: number) => K,
105
- valueSelector: (item: T, index: number) => V,
106
- ): { key: K; values: V[] }[];
107
- ```
108
-
109
- #### `toMap`
110
-
111
- Convert to `Map`. Throws `ArgumentError` on duplicate keys.
112
-
113
- ```typescript
114
- toMap<K>(keySelector: (item: T, index: number) => K): Map<K, T>;
115
- toMap<K, V>(keySelector: (item: T, index: number) => K, valueSelector: (item: T, index: number) => V): Map<K, V>;
116
- ```
117
-
118
- #### `toMapAsync`
119
-
120
- Async version of `toMap`.
121
-
122
- ```typescript
123
- toMapAsync<K>(keySelector: (item: T, index: number) => Promise<K>): Promise<Map<K, T>>;
124
- toMapAsync<K, V>(
125
- keySelector: (item: T, index: number) => Promise<K> | K,
126
- valueSelector: (item: T, index: number) => Promise<V> | V,
127
- ): Promise<Map<K, V>>;
128
- ```
129
-
130
- #### `toArrayMap`
131
-
132
- Convert to `Map<K, T[]>` (groups values by key).
133
-
134
- ```typescript
135
- toArrayMap<K>(keySelector: (item: T, index: number) => K): Map<K, T[]>;
136
- toArrayMap<K, V>(keySelector: (item: T, index: number) => K, valueSelector: (item: T, index: number) => V): Map<K, V[]>;
137
- ```
138
-
139
- #### `toSetMap`
140
-
141
- Convert to `Map<K, Set<T>>`.
142
-
143
- ```typescript
144
- toSetMap<K>(keySelector: (item: T, index: number) => K): Map<K, Set<T>>;
145
- toSetMap<K, V>(keySelector: (item: T, index: number) => K, valueSelector: (item: T, index: number) => V): Map<K, Set<V>>;
146
- ```
147
-
148
- #### `toMapValues`
149
-
150
- Group by key, then reduce each group's values.
151
-
152
- ```typescript
153
- toMapValues<K, V>(
154
- keySelector: (item: T, index: number) => K,
155
- valueSelector: (items: T[]) => V,
156
- ): Map<K, V>;
157
- ```
158
-
159
- #### `toObject`
160
-
161
- Convert to plain object. Throws `ArgumentError` on duplicate keys.
162
-
163
- ```typescript
164
- toObject(keySelector: (item: T, index: number) => string): Record<string, T>;
165
- toObject<V>(keySelector: (item: T, index: number) => string, valueSelector: (item: T, index: number) => V): Record<string, V>;
166
- ```
167
-
168
- #### `toTree`
169
-
170
- Convert flat array to tree structure. Items with `null`/`undefined` parent key become roots. Uses `toArrayMap` for O(n) complexity.
171
-
172
- ```typescript
173
- toTree<K extends keyof T, P extends keyof T>(keyProp: K, parentKey: P): TreeArray<T>[];
174
- ```
175
-
176
- #### `distinct`
177
-
178
- Remove duplicates. Options: `matchAddress` for reference comparison, `keyFn` for custom key (O(n)). Without `keyFn` on objects: O(n^2).
179
-
180
- ```typescript
181
- distinct(options?: boolean | { matchAddress?: boolean; keyFn?: (item: T) => string | number }): T[];
182
- ```
183
-
184
- #### `orderBy` / `orderByDesc`
185
-
186
- Sort in ascending or descending order. Supports `string`, `number`, `DateTime`, `DateOnly`, `Time`.
187
-
188
- ```typescript
189
- orderBy(selector?: (item: T) => string | number | DateTime | DateOnly | Time | undefined): T[];
190
- orderByDesc(selector?: (item: T) => string | number | DateTime | DateOnly | Time | undefined): T[];
191
- ```
192
-
193
- #### `diffs`
194
-
195
- Compare two arrays and return INSERT / DELETE / UPDATE results.
196
-
197
- ```typescript
198
- diffs<P>(target: P[]): ArrayDiffsResult<T, P>[];
199
- diffs<P>(target: P[], options: { keys: string[]; excludes?: string[] }): ArrayDiffsResult<T, P>[];
200
- diffs<P>(target: P[], options: { excludes: string[] }): ArrayDiffsResult<T, P>[];
201
- ```
202
-
203
- #### `oneWayDiffs`
204
-
205
- One-way diff against original items. Returns `"create"`, `"update"`, or `"same"` for each item.
206
-
207
- ```typescript
208
- oneWayDiffs<K extends keyof T>(
209
- orgItems: T[] | Map<T[K], T>,
210
- keyPropNameOrGetValFn: K | ((item: T) => string | number | undefined),
211
- options?: { includeSame?: boolean; excludes?: string[]; includes?: string[] },
212
- ): ArrayOneWayDiffResult<T>[];
213
- ```
214
-
215
- #### `merge`
216
-
217
- Merge source and target arrays based on diff results.
218
-
219
- ```typescript
220
- merge<P>(target: P[]): (T | P | (T & P))[];
221
- merge<P>(target: P[], options: { keys: string[]; excludes?: string[] }): (T | P | (T & P))[];
222
- ```
223
-
224
- #### `sum`
225
-
226
- Return sum of elements. Returns `0` for empty arrays.
227
-
228
- ```typescript
229
- sum(selector?: (item: T, index: number) => number): number;
230
- ```
231
-
232
- #### `min` / `max`
233
-
234
- Return minimum or maximum value.
235
-
236
- ```typescript
237
- min(): T extends number | string ? T | undefined : never;
238
- min<P extends number | string>(selector?: (item: T, index: number) => P): P | undefined;
239
- max(): T extends number | string ? T | undefined : never;
240
- max<P extends number | string>(selector?: (item: T, index: number) => P): P | undefined;
241
- ```
242
-
243
- #### `shuffle`
244
-
245
- Return a shuffled copy (Fisher-Yates algorithm).
246
-
247
- ```typescript
248
- shuffle(): T[];
249
- ```
250
-
251
- ---
252
-
253
- ### Mutable methods (modify original array, marked `@mutates`)
254
-
255
- #### `distinctThis`
256
-
257
- Remove duplicates from original array.
258
-
259
- ```typescript
260
- distinctThis(options?: boolean | { matchAddress?: boolean; keyFn?: (item: T) => string | number }): T[];
261
- ```
262
-
263
- #### `orderByThis` / `orderByDescThis`
264
-
265
- Sort original array in ascending or descending order.
266
-
267
- ```typescript
268
- orderByThis(selector?: (item: T) => string | number | DateTime | DateOnly | Time | undefined): T[];
269
- orderByDescThis(selector?: (item: T) => string | number | DateTime | DateOnly | Time | undefined): T[];
270
- ```
271
-
272
- #### `insert`
273
-
274
- Insert items at index.
275
-
276
- ```typescript
277
- insert(index: number, ...items: T[]): this;
278
- ```
279
-
280
- #### `remove`
281
-
282
- Remove item or items matching condition.
283
-
284
- ```typescript
285
- remove(item: T): this;
286
- remove(selector: (item: T, index: number) => boolean): this;
287
- ```
288
-
289
- #### `toggle`
290
-
291
- Toggle item in array (remove if exists, add if not).
292
-
293
- ```typescript
294
- toggle(item: T): this;
295
- ```
296
-
297
- #### `clear`
298
-
299
- Clear all items from array.
300
-
301
- ```typescript
302
- clear(): this;
303
- ```
304
-
305
- ---
306
-
307
- ## Exported Types
308
-
309
- ```typescript
310
- export type ArrayDiffsResult<TOriginal, TOther> =
311
- | { source: undefined; target: TOther } // INSERT
312
- | { source: TOriginal; target: undefined } // DELETE
313
- | { source: TOriginal; target: TOther }; // UPDATE
314
-
315
- export type ArrayOneWayDiffResult<TItem> =
316
- | { type: "create"; item: TItem; orgItem: undefined }
317
- | { type: "update"; item: TItem; orgItem: TItem }
318
- | { type: "same"; item: TItem; orgItem: TItem };
319
-
320
- export type TreeArray<TNode> = TNode & { children: TreeArray<TNode>[] };
321
-
322
- /** Type that can be sorted/compared */
323
- export type ComparableType = string | number | boolean | DateTime | DateOnly | Time | undefined;
324
- ```
325
-
326
- ---
327
-
328
- ## Map Extensions
329
-
330
- #### `getOrCreate`
331
-
332
- If no value exists for key, set new value and return it. If the second argument is a function, it is called as a factory.
333
-
334
- ```typescript
335
- getOrCreate(key: K, newValue: V): V;
336
- getOrCreate(key: K, newValueFn: () => V): V;
337
- ```
338
-
339
- **Caution:** If `V` is a function type, passing the function directly will be recognized as a factory and called. Wrap it in a factory to store the function itself.
340
-
341
- #### `update`
342
-
343
- Update value for key using function. Called even if key does not exist.
344
-
345
- ```typescript
346
- update(key: K, updateFn: (v: V | undefined) => V): void;
347
- ```
348
-
349
- **Example:**
350
-
351
- ```typescript
352
- const countMap = new Map<string, number>();
353
- countMap.update("key", (v) => (v ?? 0) + 1);
354
-
355
- map.getOrCreate("users", []).push(newUser);
356
- ```
357
-
358
- ---
359
-
360
- ## Set Extensions
361
-
362
- #### `adds`
363
-
364
- Add multiple values at once.
365
-
366
- ```typescript
367
- adds(...values: T[]): this;
368
- ```
369
-
370
- #### `toggle`
371
-
372
- Toggle value (remove if exists, add if not). Optional `addOrDel` parameter to force add or remove.
373
-
374
- ```typescript
375
- toggle(value: T, addOrDel?: "add" | "del"): this;
376
- ```
377
-
378
- **Example:**
379
-
380
- ```typescript
381
- const set = new Set<number>([1, 2, 3]);
382
- set.toggle(2); // 2 exists, so remove -> {1, 3}
383
- set.toggle(4); // 4 doesn't exist, so add -> {1, 3, 4}
384
-
385
- const isAdmin = true;
386
- set.toggle(5, isAdmin ? "add" : "del"); // Force add
387
- ```
@@ -1,80 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { SdError, ArgumentError } from "@simplysm/core-common";
3
-
4
- describe("Errors", () => {
5
- //#region SdError
6
-
7
- describe("SdError", () => {
8
- it("Creates with cause", () => {
9
- const cause = new Error("original error");
10
- const error = new SdError(cause, "wrapped message");
11
-
12
- // Message combined as "wrapped message => original error" format
13
- expect(error.message).toContain("wrapped message");
14
- expect(error.message).toContain("original error");
15
- });
16
-
17
- it("Integrates cause message", () => {
18
- const cause = new Error("cause message");
19
- const error = new SdError(cause, "main message");
20
-
21
- expect(error.message).toContain("main message");
22
- });
23
-
24
- it("Handles multi-level cause chain", () => {
25
- const root = new Error("root error");
26
- const middle = new SdError(root, "middle error");
27
- const top = new SdError(middle, "top error");
28
-
29
- expect(top.message).toContain("top error");
30
- expect(top.message).toContain("middle error");
31
- expect(top.message).toContain("root error");
32
- });
33
-
34
- it("Integrates cause stack to current stack", () => {
35
- const cause = new Error("cause error");
36
- const error = new SdError(cause, "main error");
37
-
38
- expect(error.stack).toContain("---- cause stack ----");
39
- expect(error.stack).toContain(cause.stack);
40
- });
41
-
42
- it("Converts non-Error object passed as cause using String()", () => {
43
- // number
44
- const errorFromNumber = new SdError(42, "number cause");
45
- expect(errorFromNumber.message).toContain("42");
46
-
47
- // object
48
- const errorFromObject = new SdError({ code: 500, reason: "server error" }, "object cause");
49
- expect(errorFromObject.message).toContain("object cause");
50
-
51
- // null/undefined
52
- const errorFromNull = new SdError(null, "null cause");
53
- expect(errorFromNull.message).toContain("null cause");
54
- });
55
- });
56
-
57
- //#endregion
58
-
59
- //#region ArgumentError
60
-
61
- describe("ArgumentError", () => {
62
- it("Creates with argObj", () => {
63
- const error = new ArgumentError("invalid argument", { param: "value", expected: "string" });
64
-
65
- // argObj included in message as YAML format
66
- expect(error.message).toContain("invalid argument");
67
- expect(error.message).toContain("param");
68
- expect(error.message).toContain("value");
69
- });
70
-
71
- it("Creates with only argObj without message", () => {
72
- const error = new ArgumentError({ key: "value" });
73
-
74
- expect(error.message).toContain("Invalid arguments");
75
- expect(error.message).toContain("key");
76
- });
77
- });
78
-
79
- //#endregion
80
- });