@simplysm/core-common 13.0.69 → 13.0.71

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 (151) hide show
  1. package/README.md +66 -267
  2. package/dist/common.types.d.ts +14 -14
  3. package/dist/errors/argument-error.d.ts +10 -10
  4. package/dist/errors/argument-error.d.ts.map +1 -1
  5. package/dist/errors/argument-error.js +2 -2
  6. package/dist/errors/argument-error.js.map +1 -1
  7. package/dist/errors/not-implemented-error.d.ts +8 -8
  8. package/dist/errors/not-implemented-error.js +2 -2
  9. package/dist/errors/not-implemented-error.js.map +1 -1
  10. package/dist/errors/sd-error.d.ts +10 -10
  11. package/dist/errors/sd-error.d.ts.map +1 -1
  12. package/dist/errors/timeout-error.d.ts +10 -10
  13. package/dist/errors/timeout-error.js +3 -3
  14. package/dist/errors/timeout-error.js.map +1 -1
  15. package/dist/extensions/arr-ext.d.ts +2 -2
  16. package/dist/extensions/arr-ext.helpers.d.ts +8 -8
  17. package/dist/extensions/arr-ext.helpers.js +1 -1
  18. package/dist/extensions/arr-ext.helpers.js.map +1 -1
  19. package/dist/extensions/arr-ext.js +13 -13
  20. package/dist/extensions/arr-ext.js.map +1 -1
  21. package/dist/extensions/arr-ext.types.d.ts +57 -57
  22. package/dist/extensions/arr-ext.types.d.ts.map +1 -1
  23. package/dist/extensions/map-ext.d.ts +16 -16
  24. package/dist/extensions/set-ext.d.ts +11 -11
  25. package/dist/features/debounce-queue.d.ts +17 -15
  26. package/dist/features/debounce-queue.d.ts.map +1 -1
  27. package/dist/features/debounce-queue.js +6 -6
  28. package/dist/features/debounce-queue.js.map +1 -1
  29. package/dist/features/event-emitter.d.ts +20 -20
  30. package/dist/features/event-emitter.js +17 -17
  31. package/dist/features/serial-queue.d.ts +11 -11
  32. package/dist/features/serial-queue.js +5 -5
  33. package/dist/features/serial-queue.js.map +1 -1
  34. package/dist/globals.d.ts +4 -4
  35. package/dist/types/date-only.d.ts +64 -64
  36. package/dist/types/date-only.d.ts.map +1 -1
  37. package/dist/types/date-only.js +63 -63
  38. package/dist/types/date-time.d.ts +37 -37
  39. package/dist/types/date-time.d.ts.map +1 -1
  40. package/dist/types/date-time.js +54 -37
  41. package/dist/types/date-time.js.map +1 -1
  42. package/dist/types/lazy-gc-map.d.ts +26 -26
  43. package/dist/types/lazy-gc-map.d.ts.map +1 -1
  44. package/dist/types/lazy-gc-map.js +26 -26
  45. package/dist/types/lazy-gc-map.js.map +1 -1
  46. package/dist/types/time.d.ts +25 -25
  47. package/dist/types/time.d.ts.map +1 -1
  48. package/dist/types/time.js +25 -25
  49. package/dist/types/time.js.map +1 -1
  50. package/dist/types/uuid.d.ts +11 -11
  51. package/dist/types/uuid.d.ts.map +1 -1
  52. package/dist/types/uuid.js +12 -12
  53. package/dist/types/uuid.js.map +1 -1
  54. package/dist/utils/bytes.d.ts +17 -17
  55. package/dist/utils/bytes.js +4 -4
  56. package/dist/utils/bytes.js.map +1 -1
  57. package/dist/utils/date-format.d.ts +45 -45
  58. package/dist/utils/date-format.js +1 -1
  59. package/dist/utils/date-format.js.map +1 -1
  60. package/dist/utils/error.d.ts +4 -4
  61. package/dist/utils/json.d.ts +17 -17
  62. package/dist/utils/json.js +3 -3
  63. package/dist/utils/json.js.map +1 -1
  64. package/dist/utils/num.d.ts +23 -23
  65. package/dist/utils/obj.d.ts +111 -111
  66. package/dist/utils/obj.d.ts.map +1 -1
  67. package/dist/utils/obj.js +3 -3
  68. package/dist/utils/obj.js.map +1 -1
  69. package/dist/utils/path.d.ts +10 -10
  70. package/dist/utils/primitive.d.ts +5 -5
  71. package/dist/utils/primitive.js +1 -1
  72. package/dist/utils/primitive.js.map +1 -1
  73. package/dist/utils/str.d.ts +46 -46
  74. package/dist/utils/str.d.ts.map +1 -1
  75. package/dist/utils/str.js +5 -5
  76. package/dist/utils/str.js.map +1 -1
  77. package/dist/utils/template-strings.d.ts +26 -26
  78. package/dist/utils/transferable.d.ts +18 -18
  79. package/dist/utils/transferable.js +1 -1
  80. package/dist/utils/transferable.js.map +1 -1
  81. package/dist/utils/wait.d.ts +9 -9
  82. package/dist/utils/xml.d.ts +13 -13
  83. package/dist/utils/xml.d.ts.map +1 -1
  84. package/dist/utils/xml.js +1 -0
  85. package/dist/utils/xml.js.map +1 -1
  86. package/dist/zip/sd-zip.d.ts +22 -22
  87. package/dist/zip/sd-zip.js +16 -16
  88. package/package.json +4 -4
  89. package/src/common.types.ts +17 -17
  90. package/src/errors/argument-error.ts +15 -15
  91. package/src/errors/not-implemented-error.ts +9 -9
  92. package/src/errors/sd-error.ts +12 -12
  93. package/src/errors/timeout-error.ts +12 -12
  94. package/src/extensions/arr-ext.helpers.ts +10 -10
  95. package/src/extensions/arr-ext.ts +57 -57
  96. package/src/extensions/arr-ext.types.ts +59 -59
  97. package/src/extensions/map-ext.ts +16 -16
  98. package/src/extensions/set-ext.ts +11 -11
  99. package/src/features/debounce-queue.ts +21 -19
  100. package/src/features/event-emitter.ts +25 -25
  101. package/src/features/serial-queue.ts +13 -13
  102. package/src/globals.ts +4 -4
  103. package/src/index.ts +1 -1
  104. package/src/types/date-only.ts +83 -83
  105. package/src/types/date-time.ts +64 -44
  106. package/src/types/lazy-gc-map.ts +45 -45
  107. package/src/types/time.ts +34 -34
  108. package/src/types/uuid.ts +17 -17
  109. package/src/utils/bytes.ts +35 -35
  110. package/src/utils/date-format.ts +65 -65
  111. package/src/utils/error.ts +4 -4
  112. package/src/utils/json.ts +39 -39
  113. package/src/utils/num.ts +23 -23
  114. package/src/utils/obj.ts +138 -138
  115. package/src/utils/path.ts +10 -10
  116. package/src/utils/primitive.ts +6 -6
  117. package/src/utils/str.ts +260 -261
  118. package/src/utils/template-strings.ts +29 -29
  119. package/src/utils/transferable.ts +284 -284
  120. package/src/utils/wait.ts +10 -10
  121. package/src/utils/xml.ts +20 -19
  122. package/src/zip/sd-zip.ts +25 -25
  123. package/tests/errors/errors.spec.ts +80 -0
  124. package/tests/extensions/array-extension.spec.ts +796 -0
  125. package/tests/extensions/map-extension.spec.ts +147 -0
  126. package/tests/extensions/set-extension.spec.ts +74 -0
  127. package/tests/types/date-only.spec.ts +638 -0
  128. package/tests/types/date-time.spec.ts +391 -0
  129. package/tests/types/lazy-gc-map.spec.ts +692 -0
  130. package/tests/types/time.spec.ts +559 -0
  131. package/tests/types/uuid.spec.ts +74 -0
  132. package/tests/utils/bytes-utils.spec.ts +230 -0
  133. package/tests/utils/date-format.spec.ts +373 -0
  134. package/tests/utils/debounce-queue.spec.ts +272 -0
  135. package/tests/utils/json.spec.ts +486 -0
  136. package/tests/utils/number.spec.ts +157 -0
  137. package/tests/utils/object.spec.ts +829 -0
  138. package/tests/utils/path.spec.ts +78 -0
  139. package/tests/utils/primitive.spec.ts +43 -0
  140. package/tests/utils/sd-event-emitter.spec.ts +216 -0
  141. package/tests/utils/serial-queue.spec.ts +365 -0
  142. package/tests/utils/string.spec.ts +281 -0
  143. package/tests/utils/template-strings.spec.ts +57 -0
  144. package/tests/utils/transferable.spec.ts +703 -0
  145. package/tests/utils/wait.spec.ts +145 -0
  146. package/tests/utils/xml.spec.ts +146 -0
  147. package/tests/zip/sd-zip.spec.ts +238 -0
  148. package/docs/extensions.md +0 -503
  149. package/docs/features.md +0 -109
  150. package/docs/types.md +0 -486
  151. package/docs/utils.md +0 -780
package/src/utils/obj.ts CHANGED
@@ -7,26 +7,26 @@ import { ArgumentError } from "../errors/argument-error";
7
7
  //#region objClone
8
8
 
9
9
  /**
10
- * 깊은 복사
11
- * - 순환 참조 지원
12
- * - 커스텀 타입(DateTime, DateOnly, Time, Uuid, Uint8Array) 복사 지원
10
+ * Deep clone
11
+ * - Supports circular references
12
+ * - Supports copying custom types (DateTime, DateOnly, Time, Uuid, Uint8Array)
13
13
  *
14
- * @note 함수, Symbol은 복사되지 않고 참조가 유지됨
15
- * @note WeakMap, WeakSet 지원되지 않음 (일반 객체로 복사되어 객체가 )
16
- * @note 프로토타입 체인은 유지됨 (Object.setPrototypeOf 사용)
17
- * @note getter/setter는 현재 값으로 평가되어 복사됨 (접근자 속성 자체는 복사되지 않음)
14
+ * @note Functions and Symbols are not cloned and references are maintained
15
+ * @note WeakMap and WeakSet are not supported (copied as generic objects, resulting in empty objects)
16
+ * @note Prototype chain is maintained (using Object.setPrototypeOf)
17
+ * @note Getters/setters are evaluated as current values and copied (accessor properties themselves are not copied)
18
18
  */
19
19
  export function objClone<TSource>(source: TSource): TSource {
20
20
  return objCloneImpl(source) as TSource;
21
21
  }
22
22
 
23
23
  function objCloneImpl(source: unknown, prevClones?: WeakMap<object, unknown>): unknown {
24
- // primitive는 그대로 반환
24
+ // Primitives are returned as-is
25
25
  if (typeof source !== "object" || source === null) {
26
26
  return source;
27
27
  }
28
28
 
29
- // Immutable-like 타입들 (내부에 object 참조 없음)
29
+ // Immutable-like types (no internal object references)
30
30
  if (source instanceof Date) {
31
31
  return new Date(source.getTime());
32
32
  }
@@ -52,14 +52,14 @@ function objCloneImpl(source: unknown, prevClones?: WeakMap<object, unknown>): u
52
52
  return new RegExp(source.source, source.flags);
53
53
  }
54
54
 
55
- // 순환 참조 체크 (Error 포함 모든 object 타입에 적용)
55
+ // Circular reference check (applies to all object types including Error)
56
56
  const currPrevClones = prevClones ?? new WeakMap<object, unknown>();
57
57
  if (currPrevClones.has(source)) {
58
58
  return currPrevClones.get(source);
59
59
  }
60
60
 
61
- // Error (cause 포함)
62
- // 생성자 호출 대신 프로토타입 기반 복사 - 커스텀 Error 클래스 호환성 보장
61
+ // Error (including cause)
62
+ // Prototype-based copying instead of constructor call - ensures custom Error class compatibility
63
63
  if (source instanceof Error) {
64
64
  const cloned = Object.create(Object.getPrototypeOf(source)) as Error;
65
65
  currPrevClones.set(source, cloned);
@@ -69,7 +69,7 @@ function objCloneImpl(source: unknown, prevClones?: WeakMap<object, unknown>): u
69
69
  if (source.cause !== undefined) {
70
70
  cloned.cause = objCloneImpl(source.cause, currPrevClones);
71
71
  }
72
- // 커스텀 Error 속성 복사
72
+ // Copy custom Error properties
73
73
  for (const key of Object.keys(source)) {
74
74
  if (!["message", "name", "stack", "cause"].includes(key)) {
75
75
  (cloned as unknown as Record<string, unknown>)[key] = objCloneImpl(
@@ -114,7 +114,7 @@ function objCloneImpl(source: unknown, prevClones?: WeakMap<object, unknown>): u
114
114
  return result;
115
115
  }
116
116
 
117
- // 기타 Object
117
+ // Other Object types
118
118
  const result: Record<string, unknown> = {};
119
119
  Object.setPrototypeOf(result, Object.getPrototypeOf(source));
120
120
  currPrevClones.set(source, result);
@@ -131,40 +131,40 @@ function objCloneImpl(source: unknown, prevClones?: WeakMap<object, unknown>): u
131
131
 
132
132
  //#region objEqual
133
133
 
134
- /** objEqual 옵션 타입 */
134
+ /** objEqual options type */
135
135
  export interface EqualOptions {
136
- /** 비교할 목록. 지정 해당 키만 비교 (최상위 레벨에만 적용) */
136
+ /** List of keys to compare. When specified, only those keys are compared (applies only to top level) */
137
137
  topLevelIncludes?: string[];
138
- /** 비교에서 제외할 목록 (최상위 레벨에만 적용) */
138
+ /** List of keys to exclude from comparison (applies only to top level) */
139
139
  topLevelExcludes?: string[];
140
- /** 배열 순서 무시 여부. true O(n²) 복잡도 */
140
+ /** Whether to ignore array order. O(n²) complexity when true */
141
141
  ignoreArrayIndex?: boolean;
142
- /** 얕은 비교 여부. true 1단계만 비교 (참조 비교) */
142
+ /** Whether to do shallow comparison. Only compare 1 level (reference comparison) when true */
143
143
  onlyOneDepth?: boolean;
144
144
  }
145
145
 
146
146
  /**
147
- * 깊은 비교
147
+ * Deep equality comparison
148
148
  *
149
- * @param source 비교 대상 1
150
- * @param target 비교 대상 2
151
- * @param options 비교 옵션
152
- * @param options.topLevelIncludes 비교할 목록. 지정 해당 키만 비교 (최상위 레벨에만 적용)
153
- * @example `{ topLevelIncludes: ["id", "name"] }` - id, name 키만 비교
154
- * @param options.topLevelExcludes 비교에서 제외할 목록 (최상위 레벨에만 적용)
155
- * @example `{ topLevelExcludes: ["updatedAt"] }` - updatedAt 키를 제외하고 비교
156
- * @param options.ignoreArrayIndex 배열 순서 무시 여부. true O(n²) 복잡도
157
- * @param options.onlyOneDepth 얕은 비교 여부. true 1단계만 비교 (참조 비교)
149
+ * @param source Comparison target 1
150
+ * @param target Comparison target 2
151
+ * @param options Comparison options
152
+ * @param options.topLevelIncludes List of keys to compare. When specified, only those keys are compared (applies only to top level)
153
+ * @example `{ topLevelIncludes: ["id", "name"] }` - Compare only id and name keys
154
+ * @param options.topLevelExcludes List of keys to exclude from comparison (applies only to top level)
155
+ * @example `{ topLevelExcludes: ["updatedAt"] }` - Compare excluding updatedAt key
156
+ * @param options.ignoreArrayIndex Whether to ignore array order. O(n²) complexity when true
157
+ * @param options.onlyOneDepth Whether to do shallow comparison. Only compare 1 level (reference comparison) when true
158
158
  *
159
- * @note topLevelIncludes/topLevelExcludes 옵션은 object 속성 키에만 적용됨.
160
- * Map 모든 키는 항상 비교에 포함됨.
161
- * @note 성능 고려사항:
162
- * - 기본 배열 비교: O(n) 시간 복잡도
163
- * - `ignoreArrayIndex: true` 사용 시: O(n²) 시간 복잡도
164
- * (대용량 배열에서 성능 저하 가능)
165
- * @note `ignoreArrayIndex: true` 동작 특성:
166
- * - 배열 순서를 무시하고 동일한 요소들의 순열인지 비교
167
- * - 예: `[1,2,3]`과 `[3,2,1]` → true, `[1,1,1]`과 `[1,2,3]` → false
159
+ * @note topLevelIncludes/topLevelExcludes options apply only to object property keys.
160
+ * All keys in Map are always included in comparison.
161
+ * @note Performance considerations:
162
+ * - Basic array comparison: O(n) time complexity
163
+ * - When using `ignoreArrayIndex: true`: O(n²) time complexity
164
+ * (possible performance degradation on large arrays)
165
+ * @note `ignoreArrayIndex: true` behavior characteristics:
166
+ * - Ignore array order and check if elements are permutations of the same set
167
+ * - Example: `[1,2,3]` and `[3,2,1]` → true, `[1,1,1]` and `[1,2,3]` → false
168
168
  */
169
169
  export function objEqual(source: unknown, target: unknown, options?: EqualOptions): boolean {
170
170
  if (source === target) return true;
@@ -232,7 +232,7 @@ function objEqualArray(source: unknown[], target: unknown[], options?: EqualOpti
232
232
  return false;
233
233
  });
234
234
  } else {
235
- // 재귀 호출 topLevelIncludes/topLevelExcludes 옵션은 최상위 레벨에만 적용되므로 제외
235
+ // On recursive calls, topLevelIncludes/topLevelExcludes options apply only to top level, so exclude them
236
236
  const recursiveOptions = {
237
237
  ignoreArrayIndex: options.ignoreArrayIndex,
238
238
  onlyOneDepth: options.onlyOneDepth,
@@ -256,7 +256,7 @@ function objEqualArray(source: unknown[], target: unknown[], options?: EqualOpti
256
256
  }
257
257
  }
258
258
  } else {
259
- // 재귀 호출 topLevelIncludes/topLevelExcludes 옵션은 최상위 레벨에만 적용되므로 제외
259
+ // On recursive calls, topLevelIncludes/topLevelExcludes options apply only to top level, so exclude them
260
260
  for (let i = 0; i < source.length; i++) {
261
261
  if (
262
262
  !objEqual(source[i], target[i], {
@@ -274,16 +274,16 @@ function objEqualArray(source: unknown[], target: unknown[], options?: EqualOpti
274
274
  }
275
275
 
276
276
  /**
277
- * Map 객체 비교
278
- * @note 비문자열 키(객체, 배열 등) 처리 O(n²) 복잡도 발생
279
- * @note 대량 데이터의 경우 onlyOneDepth: true 옵션 사용 권장 (참조 비교로 O(n)으로 개선)
277
+ * Map object comparison
278
+ * @note O(n²) complexity when handling non-string keys (objects, arrays, etc.)
279
+ * @note Recommended to use onlyOneDepth: true option for large datasets (improves to O(n) with reference comparison)
280
280
  */
281
281
  function objEqualMap(
282
282
  source: Map<unknown, unknown>,
283
283
  target: Map<unknown, unknown>,
284
284
  options?: EqualOptions,
285
285
  ): boolean {
286
- // Map 비교 topLevelIncludes/topLevelExcludes 옵션은 무시됨 (object 속성 키에만 적용)
286
+ // When comparing Maps, topLevelIncludes/topLevelExcludes options are ignored (apply only to object property keys)
287
287
  const sourceKeys = Array.from(source.keys()).filter((key) => source.get(key) != null);
288
288
  const targetKeys = Array.from(target.keys()).filter((key) => target.get(key) != null);
289
289
 
@@ -293,7 +293,7 @@ function objEqualMap(
293
293
 
294
294
  const usedTargetKeys = new Set<number>();
295
295
  for (const sourceKey of sourceKeys) {
296
- // 문자열 키: 직접 비교
296
+ // String keys: compare directly
297
297
  if (typeof sourceKey === "string") {
298
298
  const sourceValue = source.get(sourceKey);
299
299
  const targetValue = target.get(sourceKey);
@@ -310,7 +310,7 @@ function objEqualMap(
310
310
  }
311
311
  }
312
312
  } else {
313
- // 비문자열 키: targetKeys에서 동등한 찾기
313
+ // Non-string keys: find equivalent key in targetKeys
314
314
  let found = false;
315
315
  for (let i = 0; i < targetKeys.length; i++) {
316
316
  const targetKey = targetKeys[i];
@@ -384,9 +384,9 @@ function objEqualObject(
384
384
  }
385
385
 
386
386
  /**
387
- * Set 깊은 비교
388
- * @note deep equal 비교(`onlyOneDepth: false`) O(n²) 시간 복잡도를 가짐.
389
- * primitive Set이나 성능이 중요한 경우 `onlyOneDepth: true` 사용 권장
387
+ * Set deep equality comparison
388
+ * @note Deep equal comparison (`onlyOneDepth: false`) has O(n²) time complexity.
389
+ * Recommended to use `onlyOneDepth: true` for primitive Sets or when performance is critical
390
390
  */
391
391
  function objEqualSet(source: Set<unknown>, target: Set<unknown>, options?: EqualOptions): boolean {
392
392
  if (source.size !== target.size) {
@@ -400,8 +400,8 @@ function objEqualSet(source: Set<unknown>, target: Set<unknown>, options?: Equal
400
400
  }
401
401
  }
402
402
  } else {
403
- // deep equal: target 배열을 루프 외부에서 1회만 생성
404
- // 매칭된 인덱스를 추적하여 중복 매칭 방지
403
+ // Deep equal: create target array only once outside loop
404
+ // Track matched indices to prevent duplicate matching
405
405
  const targetArr = [...target];
406
406
  const matchedIndices = new Set<number>();
407
407
  for (const sourceItem of source) {
@@ -422,31 +422,31 @@ function objEqualSet(source: Set<unknown>, target: Set<unknown>, options?: Equal
422
422
 
423
423
  //#region objMerge
424
424
 
425
- /** objMerge 옵션 타입 */
425
+ /** objMerge options type */
426
426
  export interface ObjMergeOptions {
427
- /** 배열 처리 방식. "replace": target으로 대체(기본), "concat": 합침(중복 제거) */
427
+ /** Array processing method. "replace": replace with target (default), "concat": merge (deduplicate) */
428
428
  arrayProcess?: "replace" | "concat";
429
- /** target이 null일 해당 삭제 여부 */
429
+ /** Whether to delete the key when target is null */
430
430
  useDelTargetNull?: boolean;
431
431
  }
432
432
 
433
433
  /**
434
- * 깊은 병합 (source base로 target을 병합)
434
+ * Deep merge (merge target into source as base)
435
435
  *
436
- * @param source 기준 객체
437
- * @param target 병합할 객체
438
- * @param opt 병합 옵션
439
- * @param opt.arrayProcess 배열 처리 방식
440
- * - `"replace"`: target 배열로 대체 (기본값)
441
- * - `"concat"`: source target 배열을 합침 (Set으로 중복 제거)
442
- * @param opt.useDelTargetNull target 값이 null일 해당 삭제 여부
443
- * - `true`: target이 null이면 결과에서 해당 삭제
444
- * - `false` 또는 미지정: source 값 유지
436
+ * @param source Base object
437
+ * @param target Object to merge
438
+ * @param opt Merge options
439
+ * @param opt.arrayProcess Array processing method
440
+ * - `"replace"`: Replace with target array (default)
441
+ * - `"concat"`: Merge source and target arrays (deduplicate with Set)
442
+ * @param opt.useDelTargetNull Whether to delete the key when target value is null
443
+ * - `true`: Delete the key from result if target is null
444
+ * - `false` or not specified: Keep source value
445
445
  *
446
- * @note 원본 객체를 수정하지 않고 객체를 반환함 (불변성 보장)
447
- * @note arrayProcess="concat" 사용 Set을 통해 중복을 제거하며,
448
- * 객체 배열의 경우 참조(주소) 비교로 중복을 판단함
449
- * @note 타입이 다른 경우 target 값으로 덮어씀
446
+ * @note Returns a new object without modifying original objects (guarantees immutability)
447
+ * @note When using arrayProcess="concat", deduplication is done with Set,
448
+ * and for object arrays, deduplication is determined by reference (address) comparison
449
+ * @note If types are different, overwrite with target value
450
450
  */
451
451
  export function objMerge<TSource, TMergeTarget>(
452
452
  source: TSource,
@@ -483,7 +483,7 @@ export function objMerge<TSource, TMergeTarget>(
483
483
  return objClone(target) as TSource & TMergeTarget;
484
484
  }
485
485
 
486
- // source object 아니거나, source target 다른 종류의 object면 target으로 덮어씀
486
+ // If source is not an object or source and target are different types of objects, overwrite with target
487
487
  if (typeof source !== "object" || source.constructor !== target.constructor) {
488
488
  return objClone(target) as TSource & TMergeTarget;
489
489
  }
@@ -521,33 +521,33 @@ export function objMerge<TSource, TMergeTarget>(
521
521
  return resultRec as TSource & TMergeTarget;
522
522
  }
523
523
 
524
- /** merge3 옵션 타입 */
524
+ /** merge3 options type */
525
525
  export interface ObjMerge3KeyOptions {
526
- /** 비교할 하위 목록 (equal topLevelIncludes와 동일) */
526
+ /** List of sub-keys to compare (same as equal's topLevelIncludes) */
527
527
  keys?: string[];
528
- /** 비교에서 제외할 하위 목록 */
528
+ /** List of sub-keys to exclude from comparison */
529
529
  excludes?: string[];
530
- /** 배열 순서 무시 여부 */
530
+ /** Whether to ignore array order */
531
531
  ignoreArrayIndex?: boolean;
532
532
  }
533
533
 
534
534
  /**
535
- * 3-way 병합
535
+ * 3-way merge
536
536
  *
537
- * source, origin, target 세 객체를 비교하여 병합합니다.
538
- * - source origin 같고 target 다르면 → target 값 사용
539
- * - target origin 같고 source 다르면 → source 값 사용
540
- * - source target 같으면해당 사용
541
- * - 값이 모두 다르면충돌 발생 (origin 값 유지)
537
+ * Merge by comparing three objects: source, origin, and target.
538
+ * - If source and origin are equal and target differsuse target value
539
+ * - If target and origin are equal and source differsuse source value
540
+ * - If source and target are equal use that value
541
+ * - If all three values differ conflict occurs (maintain origin value)
542
542
  *
543
- * @param source 변경된 버전 1
544
- * @param origin 기준 버전 (공통 조상)
545
- * @param target 변경된 버전 2
546
- * @param optionsObj 키별 비교 옵션. 키에 대해 equal() 비교 옵션을 개별 지정
547
- * - `keys`: 비교할 하위 목록 (equal topLevelIncludes와 동일)
548
- * - `excludes`: 비교에서 제외할 하위 목록
549
- * - `ignoreArrayIndex`: 배열 순서 무시 여부
550
- * @returns conflict: 충돌 발생 여부, result: 병합 결과
543
+ * @param source Changed version 1
544
+ * @param origin Base version (common ancestor)
545
+ * @param target Changed version 2
546
+ * @param optionsObj Comparison options per key. Specify equal() comparison options individually for each key
547
+ * - `keys`: List of sub-keys to compare (same as equal's topLevelIncludes)
548
+ * - `excludes`: List of sub-keys to exclude from comparison
549
+ * - `ignoreArrayIndex`: Whether to ignore array order
550
+ * @returns conflict: Whether conflict occurred, result: Merge result
551
551
  *
552
552
  * @example
553
553
  * const { conflict, result } = merge3(
@@ -596,10 +596,10 @@ export function objMerge3<
596
596
  //#region objOmit / objPick
597
597
 
598
598
  /**
599
- * 객체에서 특정 키들을 제외
600
- * @param item 원본 객체
601
- * @param omitKeys 제외할 배열
602
- * @returns 지정된 키가 제외된 객체
599
+ * Exclude specific keys from object
600
+ * @param item Source object
601
+ * @param omitKeys Array of keys to exclude
602
+ * @returns New object with specified keys excluded
603
603
  * @example
604
604
  * const user = { name: "Alice", age: 30, email: "alice@example.com" };
605
605
  * objOmit(user, ["email"]);
@@ -619,11 +619,11 @@ export function objOmit<T extends Record<string, unknown>, K extends keyof T>(
619
619
  }
620
620
 
621
621
  /**
622
- * 조건에 맞는 키들을 제외
622
+ * Exclude keys matching condition
623
623
  * @internal
624
- * @param item 원본 객체
625
- * @param omitKeyFn 키를 받아 제외 여부를 반환하는 함수 (true 제외)
626
- * @returns 조건에 맞는 키가 제외된 객체
624
+ * @param item Source object
625
+ * @param omitKeyFn Function that receives key and returns whether to exclude (true to exclude)
626
+ * @returns New object with keys matching condition excluded
627
627
  * @example
628
628
  * const data = { name: "Alice", _internal: "secret", age: 30 };
629
629
  * objOmitByFilter(data, (key) => key.startsWith("_"));
@@ -643,10 +643,10 @@ export function objOmitByFilter<T extends Record<string, unknown>>(
643
643
  }
644
644
 
645
645
  /**
646
- * 객체에서 특정 키들만 선택
647
- * @param item 원본 객체
648
- * @param keys 선택할 배열
649
- * @returns 지정된 키만 포함된 객체
646
+ * Select specific keys from object
647
+ * @param item Source object
648
+ * @param keys Array of keys to select
649
+ * @returns New object containing only specified keys
650
650
  * @example
651
651
  * const user = { name: "Alice", age: 30, email: "alice@example.com" };
652
652
  * objPick(user, ["name", "age"]);
@@ -667,7 +667,7 @@ export function objPick<T extends Record<string, unknown>, K extends keyof T>(
667
667
 
668
668
  //#region objGetChainValue / objSetChainValue / objDeleteChainValue
669
669
 
670
- // 정규식 캐싱 (모듈 로드 1회만 생성)
670
+ // Regex caching (created once at module load)
671
671
  const chainSplitRegex = /[.[\]]/g;
672
672
  const chainCleanRegex = /[?!'"]/g;
673
673
  const chainNumericRegex = /^[0-9]*$/;
@@ -690,7 +690,7 @@ function getChainSplits(chain: string): (string | number)[] {
690
690
  }
691
691
 
692
692
  /**
693
- * 체인 경로로 가져오기
693
+ * Get value by chain path
694
694
  * @example objGetChainValue(obj, "a.b[0].c")
695
695
  */
696
696
  export function objGetChainValue(obj: unknown, chain: string, optional: true): unknown | undefined;
@@ -713,13 +713,13 @@ export function objGetChainValue(
713
713
  }
714
714
 
715
715
  /**
716
- * depth만큼 같은 키로 내려가기
716
+ * Descend by the same key for depth levels
717
717
  * @internal
718
- * @param obj 대상 객체
719
- * @param key 내려갈
720
- * @param depth 내려갈 깊이 (1 이상)
721
- * @param optional true 중간에 null/undefined 있어도 에러 없이 undefined 반환
722
- * @throws ArgumentError depth 1 미만일 경우
718
+ * @param obj Target object
719
+ * @param key Key to descend by
720
+ * @param depth Depth to descend (1 or more)
721
+ * @param optional If true, return undefined without error if null/undefined found in the middle
722
+ * @throws ArgumentError If depth is less than 1
723
723
  * @example objGetChainValueByDepth({ parent: { parent: { name: 'a' } } }, 'parent', 2) => { name: 'a' }
724
724
  */
725
725
  export function objGetChainValueByDepth<TObject, TKey extends keyof TObject>(
@@ -740,7 +740,7 @@ export function objGetChainValueByDepth<TObject, TKey extends keyof TObject>(
740
740
  optional?: true,
741
741
  ): TObject[TKey] | undefined {
742
742
  if (depth < 1) {
743
- throw new ArgumentError("depth 1 이상이어야 합니다.", { depth });
743
+ throw new ArgumentError("depth must be 1 or greater", { depth });
744
744
  }
745
745
  let result: unknown = obj;
746
746
  for (let i = 0; i < depth; i++) {
@@ -754,13 +754,13 @@ export function objGetChainValueByDepth<TObject, TKey extends keyof TObject>(
754
754
  }
755
755
 
756
756
  /**
757
- * 체인 경로로 설정
757
+ * Set value by chain path
758
758
  * @example objSetChainValue(obj, "a.b[0].c", value)
759
759
  */
760
760
  export function objSetChainValue(obj: unknown, chain: string, value: unknown): void {
761
761
  const splits = getChainSplits(chain);
762
762
  if (splits.length === 0) {
763
- throw new ArgumentError("체인이 비어있습니다.", { chain });
763
+ throw new ArgumentError("Chain is empty", { chain });
764
764
  }
765
765
 
766
766
  let curr: Record<string | number, unknown> = obj as Record<string | number, unknown>;
@@ -774,19 +774,19 @@ export function objSetChainValue(obj: unknown, chain: string, value: unknown): v
774
774
  }
775
775
 
776
776
  /**
777
- * 체인 경로의 삭제
777
+ * Delete value by chain path
778
778
  * @example objDeleteChainValue(obj, "a.b[0].c")
779
779
  */
780
780
  export function objDeleteChainValue(obj: unknown, chain: string): void {
781
781
  const splits = getChainSplits(chain);
782
782
  if (splits.length === 0) {
783
- throw new ArgumentError("체인이 비어있습니다.", { chain });
783
+ throw new ArgumentError("Chain is empty", { chain });
784
784
  }
785
785
 
786
786
  let curr: Record<string | number, unknown> = obj as Record<string | number, unknown>;
787
787
  for (const splitItem of splits.slice(0, -1)) {
788
788
  const next = curr[splitItem];
789
- // 중간 경로가 없으면 조용히 리턴 (삭제할 것이 없음)
789
+ // Silently return if middle path doesn't exist (nothing to delete)
790
790
  if (next == null || typeof next !== "object") {
791
791
  return;
792
792
  }
@@ -802,10 +802,10 @@ export function objDeleteChainValue(obj: unknown, chain: string): void {
802
802
  //#region objClearUndefined / objClear / objNullToUndefined / objUnflatten
803
803
 
804
804
  /**
805
- * 객체에서 undefined 값을 가진 키 삭제
805
+ * Delete keys with undefined values from object
806
806
  * @internal
807
807
  *
808
- * @mutates 원본 객체를 직접 수정함
808
+ * @mutates Modifies the original object directly
809
809
  */
810
810
  export function objClearUndefined<T extends object>(obj: T): T {
811
811
  const record = obj as Record<string, unknown>;
@@ -818,10 +818,10 @@ export function objClearUndefined<T extends object>(obj: T): T {
818
818
  }
819
819
 
820
820
  /**
821
- * 객체의 모든 삭제
821
+ * Delete all keys from object
822
822
  * @internal
823
823
  *
824
- * @mutates 원본 객체를 직접 수정함
824
+ * @mutates Modifies the original object directly
825
825
  */
826
826
  export function objClear<T extends Record<string, unknown>>(obj: T): Record<string, never> {
827
827
  for (const key of Object.keys(obj)) {
@@ -831,10 +831,10 @@ export function objClear<T extends Record<string, unknown>>(obj: T): Record<stri
831
831
  }
832
832
 
833
833
  /**
834
- * null undefined 변환 (재귀적)
834
+ * Convert null to undefined (recursive)
835
835
  * @internal
836
836
  *
837
- * @mutates 원본 배열/객체를 직접 수정함
837
+ * @mutates Modifies the original array/object directly
838
838
  */
839
839
  export function objNullToUndefined<TObject>(obj: TObject): TObject | undefined {
840
840
  return objNullToUndefinedImpl(obj, new WeakSet());
@@ -879,7 +879,7 @@ function objNullToUndefinedImpl<TObject>(obj: TObject, seen: WeakSet<object>): T
879
879
  }
880
880
 
881
881
  /**
882
- * flat된 객체를 nested 객체로 변환
882
+ * Convert flattened object to nested object
883
883
  * @internal
884
884
  * @example objUnflatten({ "a.b.c": 1 }) => { a: { b: { c: 1 } } }
885
885
  */
@@ -909,10 +909,10 @@ export function objUnflatten(flatObj: Record<string, unknown>): Record<string, u
909
909
 
910
910
  //#endregion
911
911
 
912
- //#region 타입 유틸리티
912
+ //#region Type utilities
913
913
 
914
914
  /**
915
- * undefined 가진 프로퍼티를 optional로 변환
915
+ * Convert properties with undefined to optional
916
916
  * @example { a: string; b: string | undefined } → { a: string; b?: string | undefined }
917
917
  */
918
918
  export type ObjUndefToOptional<TObject> = {
@@ -920,7 +920,7 @@ export type ObjUndefToOptional<TObject> = {
920
920
  } & { [K in keyof TObject as undefined extends TObject[K] ? never : K]: TObject[K] };
921
921
 
922
922
  /**
923
- * optional 프로퍼티를 required + undefined 유니온으로 변환
923
+ * Convert optional properties to required + undefined union
924
924
  * @example { a: string; b?: string } → { a: string; b: string | undefined }
925
925
  */
926
926
  export type ObjOptionalToUndef<TObject> = {
@@ -930,27 +930,27 @@ export type ObjOptionalToUndef<TObject> = {
930
930
  //#endregion
931
931
 
932
932
  /**
933
- * Object.keys의 타입 안전한 버전
934
- * @param obj 키를 추출할 객체
935
- * @returns 객체의 배열
933
+ * Type-safe version of Object.keys
934
+ * @param obj Object to extract keys from
935
+ * @returns Array of object keys
936
936
  */
937
937
  export function objKeys<T extends object>(obj: T): (keyof T)[] {
938
938
  return Object.keys(obj) as (keyof T)[];
939
939
  }
940
940
 
941
941
  /**
942
- * Object.entries의 타입 안전한 버전
943
- * @param obj 엔트리를 추출할 객체
944
- * @returns [키, ] 튜플 배열
942
+ * Type-safe version of Object.entries
943
+ * @param obj Object to extract entries from
944
+ * @returns Array of [key, value] tuples
945
945
  */
946
946
  export function objEntries<T extends object>(obj: T): ObjEntries<T> {
947
947
  return Object.entries(obj) as ObjEntries<T>;
948
948
  }
949
949
 
950
950
  /**
951
- * Object.fromEntries의 타입 안전한 버전
952
- * @param entries [키, ] 튜플 배열
953
- * @returns 생성된 객체
951
+ * Type-safe version of Object.fromEntries
952
+ * @param entries Array of [key, value] tuples
953
+ * @returns Created object
954
954
  */
955
955
  export function objFromEntries<T extends [string, unknown]>(entries: T[]): { [K in T[0]]: T[1] } {
956
956
  return Object.fromEntries(entries) as { [K in T[0]]: T[1] };
@@ -959,18 +959,18 @@ export function objFromEntries<T extends [string, unknown]>(entries: T[]): { [K
959
959
  type ObjEntries<TObject> = { [K in keyof TObject]: [K, TObject[K]] }[keyof TObject][];
960
960
 
961
961
  /**
962
- * 객체의 엔트리를 변환하여 객체 반환
963
- * @param obj 변환할 객체
964
- * @param fn 변환 함수 (key, value) => [newKey, newValue]
965
- * @returns 변환된 키와 값을 가진 객체
962
+ * Transform each entry of object and return new object
963
+ * @param obj Object to transform
964
+ * @param fn Transform function (key, value) => [newKey, newValue]
965
+ * @returns New object with transformed keys and values
966
966
  * @example
967
967
  * const colors = { primary: "255, 0, 0", secondary: "0, 255, 0" };
968
968
  *
969
- * // 값만 변환
969
+ * // Transform only values
970
970
  * objMap(colors, (key, rgb) => [null, `rgb(${rgb})`]);
971
971
  * // { primary: "rgb(255, 0, 0)", secondary: "rgb(0, 255, 0)" }
972
972
  *
973
- * // 키와 모두 변환
973
+ * // Transform both keys and values
974
974
  * objMap(colors, (key, rgb) => [`${key}Light`, `rgb(${rgb})`]);
975
975
  * // { primaryLight: "rgb(255, 0, 0)", secondaryLight: "rgb(0, 255, 0)" }
976
976
  */
package/src/utils/path.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  /**
2
- * 경로 유틸리티 함수
3
- * Node.js path 모듈 대체용 (브라우저 환경 지원)
2
+ * Path utility functions
3
+ * Replacement for Node.js path module (supports browser environments)
4
4
  *
5
- * @note 유틸리티는 POSIX 스타일 경로(슬래시 `/`) 지원합니다.
6
- * Windows 백슬래시(`\`) 경로는 지원하지 않습니다.
7
- * 브라우저 환경 Capacitor 플러그인용으로 설계되었습니다.
5
+ * @note This utility supports POSIX style paths (slash `/`) only.
6
+ * Windows backslash (`\`) paths are not supported.
7
+ * Designed for browser environments and Capacitor plugins.
8
8
  */
9
9
 
10
10
  /**
11
- * 경로 조합 (path.join 대체)
12
- * @note POSIX 스타일 경로만 지원 (슬래시 `/`)
11
+ * Combine paths (path.join replacement)
12
+ * @note Supports POSIX style paths only (slash `/`)
13
13
  */
14
14
  export function pathJoin(...segments: string[]): string {
15
15
  return segments
@@ -19,7 +19,7 @@ export function pathJoin(...segments: string[]): string {
19
19
  }
20
20
 
21
21
  /**
22
- * 파일명 추출 (path.basename 대체)
22
+ * Extract filename (path.basename replacement)
23
23
  */
24
24
  export function pathBasename(filePath: string, ext?: string): string {
25
25
  const name = filePath.split("/").pop() ?? "";
@@ -30,8 +30,8 @@ export function pathBasename(filePath: string, ext?: string): string {
30
30
  }
31
31
 
32
32
  /**
33
- * 확장자 추출 (path.extname 대체)
34
- * @note 숨김 파일(예: `.gitignore`) 문자열을 반환합니다 (Node.js path.extname과 동일)
33
+ * Extract file extension (path.extname replacement)
34
+ * @note Hidden files (e.g., `.gitignore`) return empty string (same as Node.js path.extname)
35
35
  */
36
36
  export function pathExtname(filePath: string): string {
37
37
  const name = filePath.split("/").pop() ?? "";