@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
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Array 확장 메서드
2
+ * Array extension methods
3
3
  *
4
- * @remarks 메서드의 TSDoc은 타입 정의 파일(arr-ext.types.ts) 참조
4
+ * @remarks See type definition file (arr-ext.types.ts) for TSDoc of each method
5
5
  */
6
6
 
7
7
  import "./map-ext";
@@ -22,13 +22,13 @@ import type {
22
22
  TreeArray,
23
23
  } from "./arr-ext.types";
24
24
 
25
- //#region 구현
25
+ //#region Implementation
26
26
 
27
27
  const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
28
28
  single<T>(predicate?: (item: T, index: number) => boolean): T | undefined {
29
29
  const arr = predicate !== undefined ? this.filter(predicate) : this;
30
30
  if (arr.length > 1) {
31
- throw new ArgumentError("복수의 결과물이 있습니다.", { count: arr.length });
31
+ throw new ArgumentError("Multiple results found.", { count: arr.length });
32
32
  }
33
33
  return arr[0];
34
34
  },
@@ -66,7 +66,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
66
66
  },
67
67
 
68
68
  ofType<T, N extends T>(type: PrimitiveTypeStr | Type<N>): N[] {
69
- // PrimitiveTypeStr 경우
69
+ // PrimitiveTypeStr case
70
70
  if (typeof type === "string") {
71
71
  return this.filter((item) => {
72
72
  switch (type) {
@@ -87,15 +87,15 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
87
87
  case "Bytes":
88
88
  return item instanceof Uint8Array;
89
89
  default: {
90
- // exhaustive check: PrimitiveTypeStr에 타입 추가 컴파일 에러 발생
90
+ // exhaustive check: Compilation error when a new type is added to PrimitiveTypeStr
91
91
  const _exhaustive: never = type;
92
- throw new ArgumentError(`지원하지 않는 타입: ${_exhaustive}`);
92
+ throw new ArgumentError(`Unsupported type: ${_exhaustive}`);
93
93
  }
94
94
  }
95
95
  }) as N[];
96
96
  }
97
97
 
98
- // Type<N> (생성자) 경우
98
+ // Type<N> (constructor) case
99
99
  return this.filter((item) => item instanceof type || item?.constructor === type) as N[];
100
100
  },
101
101
 
@@ -121,10 +121,10 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
121
121
  return Promise.all(this.map(fn));
122
122
  },
123
123
 
124
- // 배열을 키별로 그룹화
125
- // 성능 고려사항:
126
- // - primitive (string, number ): O(n) - Map 기반
127
- // - 객체 키: O(n²) - objEqual 비교
124
+ // Group array by key
125
+ // Performance considerations:
126
+ // - primitive key (string, number, etc.): O(n) - Map-based
127
+ // - object key: O(n²) - objEqual comparison
128
128
  groupBy<T, K, V>(
129
129
  keySelector: (item: T, index: number) => K,
130
130
  valueSelector?: (item: T, index: number) => V,
@@ -134,14 +134,14 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
134
134
  }[] {
135
135
  const result: { key: K; values: (V | T)[] }[] = [];
136
136
 
137
- // primitive 최적화를 위한 Map ( 문자열 -> result 인덱스)
137
+ // Map for primitive key optimization (key string -> result index)
138
138
  const primitiveKeyIndex = new Map<string, number>();
139
139
 
140
140
  for (let i = 0; i < this.length; i++) {
141
141
  const keyObj = keySelector(this[i], i);
142
142
  const valueObj = valueSelector !== undefined ? valueSelector(this[i], i) : this[i];
143
143
 
144
- // primitive 키는 Map으로 O(n) 처리
144
+ // primitive keys are processed in O(n) using Map
145
145
  if (keyObj == null || typeof keyObj !== "object") {
146
146
  const keyStr = typeof keyObj + ":" + String(keyObj);
147
147
  const existingIndex = primitiveKeyIndex.get(keyStr);
@@ -154,7 +154,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
154
154
  continue;
155
155
  }
156
156
 
157
- // 객체 키는 기존 방식 O(n²)
157
+ // Object keys use the existing approach O(n²)
158
158
  const existsRecord = result.find((item) => objEqual(item.key, keyObj));
159
159
  if (existsRecord !== undefined) {
160
160
  existsRecord.values.push(valueObj);
@@ -179,7 +179,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
179
179
  const valueObj = valueSelector !== undefined ? valueSelector(item, i) : item;
180
180
 
181
181
  if (result.has(keyObj)) {
182
- throw new ArgumentError("키가 중복되었습니다.", { duplicatedKey: keyObj });
182
+ throw new ArgumentError("Duplicated key.", { duplicatedKey: keyObj });
183
183
  }
184
184
  result.set(keyObj, valueObj);
185
185
  }
@@ -200,7 +200,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
200
200
  const valueObj = valueSelector !== undefined ? await valueSelector(item, i) : item;
201
201
 
202
202
  if (result.has(keyObj)) {
203
- throw new ArgumentError("키가 중복되었습니다.", { duplicatedKey: keyObj });
203
+ throw new ArgumentError("Duplicated key.", { duplicatedKey: keyObj });
204
204
  }
205
205
  result.set(keyObj, valueObj);
206
206
  }
@@ -282,9 +282,9 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
282
282
  const key = keySelector(item, i);
283
283
  const valueObj = valueSelector !== undefined ? valueSelector(item, i) : item;
284
284
 
285
- // undefined 값은 "없음"으로 취급하여 덮어쓰기 허용
285
+ // undefined values are treated as "none", allowing overwrite
286
286
  if (result[key] !== undefined) {
287
- throw new ArgumentError("키가 중복되었습니다.", { duplicatedKey: key });
287
+ throw new ArgumentError("Duplicated key.", { duplicatedKey: key });
288
288
  }
289
289
  result[key] = valueObj;
290
290
  }
@@ -293,7 +293,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
293
293
  },
294
294
 
295
295
  toTree<T, K extends keyof T, P extends keyof T>(key: K, parentKey: P): TreeArray<T>[] {
296
- // O(n) 최적화: 기반 인덱싱
296
+ // O(n) optimization: Map-based indexing
297
297
  const childrenMap = this.toArrayMap((item) => item[parentKey]);
298
298
 
299
299
  const fn = (items: T[]): TreeArray<T>[] => {
@@ -310,13 +310,13 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
310
310
  distinct<T>(
311
311
  options?: boolean | { matchAddress?: boolean; keyFn?: (item: T) => string | number },
312
312
  ): T[] {
313
- // 옵션 정규화
313
+ // Normalize options
314
314
  const opts = typeof options === "boolean" ? { matchAddress: options } : (options ?? {});
315
315
 
316
- // matchAddress: Set 기반 O(n)
316
+ // matchAddress: Set-based O(n)
317
317
  if (opts.matchAddress === true) return [...new Set(this)];
318
318
 
319
- // keyFn 제공 시: 커스텀 키 기반 O(n)
319
+ // keyFn provided: custom key-based O(n)
320
320
  if (opts.keyFn) {
321
321
  const seen = new Set<string | number>();
322
322
  const result: T[] = [];
@@ -330,17 +330,17 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
330
330
  return result;
331
331
  }
332
332
 
333
- // 기본: 타입별 처리
333
+ // Default: type-based processing
334
334
  const seen = new Map<string, T>();
335
- const seenRefs = new Set<symbol | ((...args: unknown[]) => unknown)>(); // symbol/function용 O(n) 처리
335
+ const seenRefs = new Set<symbol | ((...args: unknown[]) => unknown)>(); // O(n) processing for symbol/function
336
336
  const result: T[] = [];
337
337
 
338
338
  for (const item of this) {
339
- // primitive 타입은 빠른 경로
339
+ // primitive types take the fast path
340
340
  if (item === null || typeof item !== "object") {
341
341
  const type = typeof item;
342
342
 
343
- // symbol, function Set으로 identity 비교 (O(n))
343
+ // symbol, function use Set for identity comparison (O(n))
344
344
  if (type === "symbol" || type === "function") {
345
345
  if (!seenRefs.has(item)) {
346
346
  seenRefs.add(item);
@@ -349,7 +349,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
349
349
  continue;
350
350
  }
351
351
 
352
- // 나머지 primitive는 타입 prefix + 특수 케이스 처리
352
+ // Other primitives: type prefix + special case handling
353
353
  let key = type + ":";
354
354
  if (Object.is(item, -0)) {
355
355
  key += "-0";
@@ -406,8 +406,8 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
406
406
  const hasKeys = options?.keys !== undefined && options.keys.length > 0;
407
407
  const excludeOpts = { topLevelExcludes: options?.excludes };
408
408
 
409
- // keys 옵션이 있는 경우 target keys 기준으로 Map 미리 인덱싱하여 O(n×m) → O(n+m) 개선
410
- // 값이 같은 target이 여러 있을 있으므로 배열로 저장
409
+ // If keys option is provided, pre-index target by keys in Map to improve O(n×m) → O(n+m)
410
+ // Multiple targets with the same key value can exist, so store as array
411
411
  const keyIndexedTarget = hasKeys ? new Map<string, P[]>() : undefined;
412
412
 
413
413
  if (keyIndexedTarget) {
@@ -425,11 +425,11 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
425
425
  }
426
426
 
427
427
  for (const sourceItem of this) {
428
- // 전체 일치(sameTarget) 우선, 없으면 일치(sameKeyTarget) 검색
428
+ // Prioritize full match (sameTarget), otherwise search for key match (sameKeyTarget)
429
429
  let sameTarget: P | undefined;
430
430
  let sameKeyTarget: P | undefined;
431
431
 
432
- // Set 기반 건너뛰기로 이미 매칭된 항목 스킵 (splice O(n) 제거)
432
+ // Skip already matched items using Set-based skipping (avoid O(n) splice removal)
433
433
  for (const targetItem of uncheckedTarget) {
434
434
  if (!uncheckedTargetSet.has(targetItem)) continue;
435
435
  if (objEqual(targetItem, sourceItem, excludeOpts)) {
@@ -438,14 +438,14 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
438
438
  }
439
439
  }
440
440
 
441
- // 전체 일치가 없고 keys 옵션이 있으면 Map에서 O(1) 조회
441
+ // If no full match and keys option exists, perform O(1) lookup in Map
442
442
  if (sameTarget === undefined && keyIndexedTarget) {
443
443
  const sourceKeyStr = JSON.stringify(
444
444
  options!.keys!.map((k) => (sourceItem as Record<string, unknown>)[k]),
445
445
  );
446
446
  const candidates = keyIndexedTarget.get(sourceKeyStr);
447
447
  if (candidates && candidates.length > 0) {
448
- // uncheckedTargetSet에서 O(1) 조회로 아직 남아있는 첫 번째 항목 선택
448
+ // Select first remaining item using O(1) lookup in uncheckedTargetSet
449
449
  sameKeyTarget = candidates.find((c) => uncheckedTargetSet.has(c));
450
450
  }
451
451
  }
@@ -531,22 +531,22 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
531
531
 
532
532
  const result: (T | P | (T & P))[] = objClone(this);
533
533
 
534
- // source 항목의 원본 인덱스를 미리 계산하여 O(n) 검색을 O(1)로 개선
534
+ // Pre-calculate original index of source items to improve O(n) lookup to O(1)
535
535
  const sourceIndexMap = new Map<T, number>();
536
536
  for (let i = 0; i < this.length; i++) {
537
537
  sourceIndexMap.set(this[i], i);
538
538
  }
539
539
 
540
540
  for (const diff of diffs) {
541
- // 변경시
541
+ // When updating
542
542
  if (diff.source !== undefined && diff.target !== undefined) {
543
543
  const sourceIndex = sourceIndexMap.get(diff.source);
544
544
  if (sourceIndex === undefined) {
545
- throw new SdError("예상치 못한 오류: merge에서 source 항목을 찾을 수 없습니다.");
545
+ throw new SdError("Unexpected error: source item not found in merge.");
546
546
  }
547
547
  result[sourceIndex] = objMerge(diff.source, diff.target);
548
548
  }
549
- // 추가시
549
+ // When adding
550
550
  else if (diff.target !== undefined) {
551
551
  result.push(diff.target);
552
552
  }
@@ -560,7 +560,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
560
560
  for (let i = 0; i < this.length; i++) {
561
561
  const item = selector !== undefined ? selector(this[i], i) : this[i];
562
562
  if (typeof item !== "number") {
563
- throw new ArgumentError("sum number 대해서만 사용할 수 있습니다.", {
563
+ throw new ArgumentError("sum can only be used with numbers.", {
564
564
  type: typeof item,
565
565
  });
566
566
  }
@@ -575,7 +575,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
575
575
  for (let i = 0; i < this.length; i++) {
576
576
  const item = selector !== undefined ? selector(this[i], i) : this[i];
577
577
  if (typeof item !== "number" && typeof item !== "string") {
578
- throw new ArgumentError("min number/string 대해서만 사용할 수 있습니다.", {
578
+ throw new ArgumentError("min can only be used with numbers/strings.", {
579
579
  type: typeof item,
580
580
  });
581
581
  }
@@ -592,7 +592,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
592
592
  for (let i = 0; i < this.length; i++) {
593
593
  const item = selector !== undefined ? selector(this[i], i) : this[i];
594
594
  if (typeof item !== "number" && typeof item !== "string") {
595
- throw new ArgumentError("max number/string 대해서만 사용할 수 있습니다.", {
595
+ throw new ArgumentError("max can only be used with numbers/strings.", {
596
596
  type: typeof item,
597
597
  });
598
598
  }
@@ -622,11 +622,11 @@ const arrayMutableExtensions: MutableArrayExt<any> & ThisType<any[]> = {
622
622
  distinctThis<T>(
623
623
  options?: boolean | { matchAddress?: boolean; keyFn?: (item: T) => string | number },
624
624
  ): T[] {
625
- // 옵션 정규화
625
+ // Normalize options
626
626
  const opts = typeof options === "boolean" ? { matchAddress: options } : (options ?? {});
627
627
 
628
- // matchAddress: Set 기반 O(n)
629
- // 번째 등장한 요소를 유지하기 위해 정방향 순회 제거할 인덱스 수집
628
+ // matchAddress: Set-based O(n)
629
+ // To preserve first occurrence, collect indices to remove after forward traversal
630
630
  if (opts.matchAddress === true) {
631
631
  const seen = new Set<T>();
632
632
  const toRemove: number[] = [];
@@ -637,15 +637,15 @@ const arrayMutableExtensions: MutableArrayExt<any> & ThisType<any[]> = {
637
637
  seen.add(this[i]);
638
638
  }
639
639
  }
640
- // 역순으로 제거 (인덱스 변화 방지)
640
+ // Remove in reverse order (prevent index changes)
641
641
  for (let i = toRemove.length - 1; i >= 0; i--) {
642
642
  this.splice(toRemove[i], 1);
643
643
  }
644
644
  return this;
645
645
  }
646
646
 
647
- // keyFn 제공 시: 커스텀 키 기반 O(n)
648
- // 번째 등장한 요소를 유지하기 위해 정방향 순회 제거할 인덱스 수집
647
+ // keyFn provided: custom key-based O(n)
648
+ // To preserve first occurrence, collect indices to remove after forward traversal
649
649
  if (opts.keyFn) {
650
650
  const seen = new Set<string | number>();
651
651
  const toRemove: number[] = [];
@@ -657,14 +657,14 @@ const arrayMutableExtensions: MutableArrayExt<any> & ThisType<any[]> = {
657
657
  seen.add(key);
658
658
  }
659
659
  }
660
- // 역순으로 제거 (인덱스 변화 방지)
660
+ // Remove in reverse order (prevent index changes)
661
661
  for (let i = toRemove.length - 1; i >= 0; i--) {
662
662
  this.splice(toRemove[i], 1);
663
663
  }
664
664
  return this;
665
665
  }
666
666
 
667
- // 기본: 타입별 처리 (primitive 최적화)
667
+ // Default: type-based processing (primitive optimization)
668
668
  const seen = new Map<string, T>();
669
669
  const seenRefs = new Set<symbol | ((...args: unknown[]) => unknown)>();
670
670
  const toRemoveSet = new Set<number>();
@@ -672,11 +672,11 @@ const arrayMutableExtensions: MutableArrayExt<any> & ThisType<any[]> = {
672
672
  for (let i = 0; i < this.length; i++) {
673
673
  const item = this[i];
674
674
 
675
- // primitive 타입은 빠른 경로 O(n)
675
+ // primitive types take the fast path O(n)
676
676
  if (item === null || typeof item !== "object") {
677
677
  const type = typeof item;
678
678
 
679
- // symbol, function Set으로 identity 비교
679
+ // symbol, function use Set for identity comparison
680
680
  if (type === "symbol" || type === "function") {
681
681
  if (seenRefs.has(item)) {
682
682
  toRemoveSet.add(i);
@@ -686,7 +686,7 @@ const arrayMutableExtensions: MutableArrayExt<any> & ThisType<any[]> = {
686
686
  continue;
687
687
  }
688
688
 
689
- // 나머지 primitive는 타입 prefix + 특수 케이스 처리
689
+ // Other primitives: type prefix + special case handling
690
690
  let key = type + ":";
691
691
  if (Object.is(item, -0)) {
692
692
  key += "-0";
@@ -702,10 +702,10 @@ const arrayMutableExtensions: MutableArrayExt<any> & ThisType<any[]> = {
702
702
  continue;
703
703
  }
704
704
 
705
- // 객체는 깊은 비교 O(n²) - 제거되지 않은 이전 항목들과 비교
705
+ // Objects: deep comparison O(n²) - compare with previous non-removed items
706
706
  let hasDuplicateBefore = false;
707
707
  for (let j = 0; j < i; j++) {
708
- // toRemoveSet에 있는 인덱스는 건너뜀 (O(1) 조회)
708
+ // Skip indices in toRemoveSet (O(1) lookup)
709
709
  if (toRemoveSet.has(j)) continue;
710
710
  if (objEqual(this[j], item)) {
711
711
  hasDuplicateBefore = true;
@@ -717,7 +717,7 @@ const arrayMutableExtensions: MutableArrayExt<any> & ThisType<any[]> = {
717
717
  }
718
718
  }
719
719
 
720
- // 역순으로 제거 (인덱스 변화 방지)
720
+ // Remove in reverse order (prevent index changes)
721
721
  const toRemoveArr = Array.from(toRemoveSet).sort((a, b) => b - a);
722
722
  for (const idx of toRemoveArr) {
723
723
  this.splice(idx, 1);
@@ -757,7 +757,7 @@ const arrayMutableExtensions: MutableArrayExt<any> & ThisType<any[]> = {
757
757
  ? (itemOrSelector as (item: T, index: number) => boolean)
758
758
  : (item: T) => item === itemOrSelector;
759
759
 
760
- // 역방향 순회로 인덱스 변경 문제 방지 (O(n) 성능)
760
+ // Reverse traversal to prevent index change issues (O(n) performance)
761
761
  for (let i = this.length - 1; i >= 0; i--) {
762
762
  if (shouldRemove(this[i], i)) {
763
763
  this.splice(i, 1);
@@ -795,7 +795,7 @@ for (const [name, fn] of Object.entries({
795
795
 
796
796
  //#endregion
797
797
 
798
- //#region 타입 선언
798
+ //#region Type Declarations
799
799
 
800
800
  declare global {
801
801
  interface ReadonlyArray<T> extends ReadonlyArrayExt<T> {}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Array 확장 타입 정의
2
+ * Array extension type definitions
3
3
  */
4
4
 
5
5
  import type { PrimitiveTypeMap, PrimitiveTypeStr, Type } from "../common.types";
@@ -7,71 +7,71 @@ import type { DateTime } from "../types/date-time";
7
7
  import type { DateOnly } from "../types/date-only";
8
8
  import type { Time } from "../types/time";
9
9
 
10
- //#region 인터페이스
10
+ //#region Interfaces
11
11
 
12
12
  export interface ReadonlyArrayExt<TItem> {
13
13
  /**
14
- * 조건에 맞는 단일 요소 반환
15
- * @param predicate 필터 조건 (생략 배열 전체 대상)
16
- * @returns 요소가 없으면 undefined
17
- * @throws ArgumentError 조건에 맞는 요소가 2개 이상이면 발생
14
+ * Return single element matching condition
15
+ * @param predicate Filter condition (if omitted, entire array is target)
16
+ * @returns undefined if element does not exist
17
+ * @throws ArgumentError If 2 or more elements match condition
18
18
  */
19
19
  single(predicate?: (item: TItem, index: number) => boolean): TItem | undefined;
20
20
 
21
21
  /**
22
- * 번째 요소 반환
23
- * @param predicate 필터 조건 (생략 번째 요소 반환)
24
- * @returns 요소가 없으면 undefined
22
+ * Return first element
23
+ * @param predicate Filter condition (if omitted, returns first element)
24
+ * @returns undefined if element does not exist
25
25
  */
26
26
  first(predicate?: (item: TItem, index: number) => boolean): TItem | undefined;
27
27
 
28
- /** 비동기 필터 (순차 실행) */
28
+ /** Async filter (sequential execution) */
29
29
  filterAsync(predicate: (item: TItem, index: number) => Promise<boolean>): Promise<TItem[]>;
30
30
 
31
31
  /**
32
- * 마지막 요소 반환
33
- * @param predicate 필터 조건 (생략 마지막 요소 반환)
34
- * @returns 요소가 없으면 undefined
32
+ * Return last element
33
+ * @param predicate Filter condition (if omitted, returns last element)
34
+ * @returns undefined if element does not exist
35
35
  */
36
36
  last(predicate?: (item: TItem, index: number) => boolean): TItem | undefined;
37
37
 
38
- /** null/undefined 제거 */
38
+ /** Remove null/undefined */
39
39
  filterExists(): NonNullable<TItem>[];
40
40
 
41
- /** 특정 타입의 요소만 필터링 (PrimitiveTypeStr 또는 생성자 타입) */
41
+ /** Filter only elements of specific type (PrimitiveTypeStr or constructor type) */
42
42
  ofType<K extends PrimitiveTypeStr>(type: K): Extract<TItem, PrimitiveTypeMap[K]>[];
43
43
  ofType<N extends TItem>(type: Type<N>): N[];
44
44
 
45
- /** 비동기 매핑 (순차 실행) */
45
+ /** Async mapping (sequential execution) */
46
46
  mapAsync<R>(selector: (item: TItem, index: number) => Promise<R>): Promise<R[]>;
47
47
 
48
- /** 중첩 배열 평탄화 */
48
+ /** Flatten nested array */
49
49
  mapMany(): TItem extends readonly (infer U)[] ? U[] : TItem;
50
50
 
51
- /** 매핑 평탄화 */
51
+ /** Map and then flatten */
52
52
  mapMany<R>(selector: (item: TItem, index: number) => R[]): R[];
53
53
 
54
- /** 비동기 매핑 평탄화 (순차 실행) */
54
+ /** Async mapping and then flatten (sequential execution) */
55
55
  mapManyAsync<R>(selector: (item: TItem, index: number) => Promise<R[]>): Promise<R[]>;
56
56
 
57
57
  /**
58
- * 비동기 병렬 처리 (Promise.all 사용)
59
- * @note 하나라도 reject되면 전체가 fail-fast reject됨 (Promise.all 동작)
58
+ * Async parallel processing (using Promise.all)
59
+ * @note If any rejects, entire operation fail-fast rejects (Promise.all behavior)
60
60
  */
61
61
  parallelAsync<R>(fn: (item: TItem, index: number) => Promise<R>): Promise<R[]>;
62
62
 
63
63
  /**
64
- * 기준 그룹화
65
- * @param keySelector 그룹 선택 함수
66
- * @note O(n²) 복잡도 (객체 지원을 위해 깊은 비교 사용). primitive 키만 필요하면 toArrayMap() O(n)으로 더 효율적
64
+ * Group by key
65
+ * @param keySelector Key selection function for group
66
+ * @note O(n²) complexity (deep comparison for object key support). If only primitive keys are needed, toArrayMap() is more efficient at O(n)
67
67
  */
68
68
  groupBy<K>(keySelector: (item: TItem, index: number) => K): { key: K; values: TItem[] }[];
69
69
 
70
70
  /**
71
- * 기준 그룹화 ( 변환 포함)
72
- * @param keySelector 그룹 선택 함수
73
- * @param valueSelector 변환 함수
74
- * @note O(n²) 복잡도 (객체 지원을 위해 깊은 비교 사용). primitive 키만 필요하면 toArrayMap() O(n)으로 더 효율적
71
+ * Group by key (with value transformation)
72
+ * @param keySelector Key selection function for group
73
+ * @param valueSelector Value transformation function
74
+ * @note O(n²) complexity (deep comparison for object key support). If only primitive keys are needed, toArrayMap() is more efficient at O(n)
75
75
  */
76
76
  groupBy<K, V>(
77
77
  keySelector: (item: TItem, index: number) => K,
@@ -121,16 +121,16 @@ export interface ReadonlyArrayExt<TItem> {
121
121
  ): Record<string, V>;
122
122
 
123
123
  /**
124
- * 평탄한 배열을 트리 구조로 변환한다
124
+ * Convert flat array to tree structure
125
125
  *
126
- * @param keyProp 항목의 고유 속성명
127
- * @param parentKey 부모 항목의 키를 참조하는 속성명
128
- * @returns 루트 항목들의 배열 ( 항목에 children 속성 추가)
126
+ * @param keyProp Unique key property name of each item
127
+ * @param parentKey Property name referencing parent item's key
128
+ * @returns Array of root items (each item has children property added)
129
129
  *
130
130
  * @remarks
131
- * - parentKey 값이 null/undefined 항목이 루트가 된다
132
- * - 내부적으로 toArrayMap 사용하여 O(n) 복잡도로 처리한다
133
- * - 원본 항목은 복사되어 children 속성이 추가된다
131
+ * - Items with null/undefined parentKey value become roots
132
+ * - Internally uses toArrayMap for O(n) complexity
133
+ * - Original items are copied with children property added
134
134
  *
135
135
  * @example
136
136
  * ```typescript
@@ -162,9 +162,9 @@ export interface ReadonlyArrayExt<TItem> {
162
162
  ): TreeArray<TItem>[];
163
163
 
164
164
  /**
165
- * 중복 제거
166
- * @param options matchAddress: 주소 비교 (true Set 사용), keyFn: 커스텀 함수 (O(n) 성능)
167
- * @note 객체 배열에서 keyFn 없이 사용 O(n²) 복잡도. 대량 데이터는 keyFn 사용 권장
165
+ * Remove duplicates
166
+ * @param options matchAddress: address comparison (true uses Set), keyFn: custom key function (O(n) performance)
167
+ * @note O(n²) complexity when used without keyFn on object arrays. Using keyFn is recommended for large data
168
168
  */
169
169
  distinct(
170
170
  options?: boolean | { matchAddress?: boolean; keyFn?: (item: TItem) => string | number },
@@ -179,10 +179,10 @@ export interface ReadonlyArrayExt<TItem> {
179
179
  ): TItem[];
180
180
 
181
181
  /**
182
- * 배열 비교 (INSERT/DELETE/UPDATE)
183
- * @param target 비교 대상 배열
184
- * @param options keys: 비교용, excludes: 비교 제외 속성
185
- * @note target 중복 키가 있으면 번째 매칭만 사용됨
182
+ * Compare two arrays (INSERT/DELETE/UPDATE)
183
+ * @param target Array to compare with
184
+ * @param options keys: for key comparison, excludes: properties to exclude from comparison
185
+ * @note If target has duplicate keys, only first match is used
186
186
  */
187
187
  diffs<TOtherItem>(
188
188
  target: TOtherItem[],
@@ -205,9 +205,9 @@ export interface ReadonlyArrayExt<TItem> {
205
205
  ): (TItem | TOtherItem | (TItem & TOtherItem))[];
206
206
 
207
207
  /**
208
- * 요소의 합계 반환
209
- * @param selector 선택 함수 (생략 요소 자체를 number로 사용)
210
- * @returns 배열인 경우 0 반환
208
+ * Return sum of elements
209
+ * @param selector Value selection function (if omitted, element itself is used as number)
210
+ * @returns 0 if array is empty
211
211
  */
212
212
  sum(selector?: (item: TItem, index: number) => number): number;
213
213
 
@@ -223,49 +223,49 @@ export interface ReadonlyArrayExt<TItem> {
223
223
  }
224
224
 
225
225
  /**
226
- * 원본 배열을 변경하는 확장 메서드
227
- * @mutates 모든 메서드가 원본 배열을 직접 변경합니다
226
+ * Extension methods that mutate the original array
227
+ * @mutates All methods directly modify the original array
228
228
  */
229
229
  export interface MutableArrayExt<TItem> {
230
230
  /**
231
- * 원본 배열에서 중복 제거
232
- * @param options matchAddress: 주소 비교 (true Set 사용), keyFn: 커스텀 함수 (O(n) 성능)
233
- * @note 객체 배열에서 keyFn 없이 사용 O(n²) 복잡도. 대량 데이터는 keyFn 사용 권장
231
+ * Remove duplicates from original array
232
+ * @param options matchAddress: address comparison (true uses Set), keyFn: custom key function (O(n) performance)
233
+ * @note O(n²) complexity when used without keyFn on object arrays. Using keyFn is recommended for large data
234
234
  * @mutates
235
235
  */
236
236
  distinctThis(
237
237
  options?: boolean | { matchAddress?: boolean; keyFn?: (item: TItem) => string | number },
238
238
  ): TItem[];
239
239
 
240
- /** 원본 배열 오름차순 정렬 @mutates */
240
+ /** Sort original array in ascending order @mutates */
241
241
  orderByThis(
242
242
  selector?: (item: TItem) => string | number | DateOnly | DateTime | Time | undefined,
243
243
  ): TItem[];
244
244
 
245
- /** 원본 배열 내림차순 정렬 @mutates */
245
+ /** Sort original array in descending order @mutates */
246
246
  orderByDescThis(
247
247
  selector?: (item: TItem) => string | number | DateOnly | DateTime | Time | undefined,
248
248
  ): TItem[];
249
249
 
250
- /** 원본 배열에 항목 삽입 @mutates */
250
+ /** Insert items into original array @mutates */
251
251
  insert(index: number, ...items: TItem[]): this;
252
252
 
253
- /** 원본 배열에서 항목 제거 @mutates */
253
+ /** Remove item from original array @mutates */
254
254
  remove(item: TItem): this;
255
255
 
256
- /** 원본 배열에서 조건에 맞는 항목 제거 @mutates */
256
+ /** Remove items matching condition from original array @mutates */
257
257
  remove(selector: (item: TItem, index: number) => boolean): this;
258
258
 
259
- /** 원본 배열에서 항목 토글 (있으면 제거, 없으면 추가) @mutates */
259
+ /** Toggle item in original array (remove if exists, add if not) @mutates */
260
260
  toggle(item: TItem): this;
261
261
 
262
- /** 원본 배열 비우기 @mutates */
262
+ /** Clear original array @mutates */
263
263
  clear(): this;
264
264
  }
265
265
 
266
266
  //#endregion
267
267
 
268
- //#region 내보내기 타입
268
+ //#region Export Types
269
269
 
270
270
  export type ArrayDiffsResult<TOriginal, TOther> =
271
271
  | { source: undefined; target: TOther } // INSERT
@@ -279,7 +279,7 @@ export type ArrayDiffs2Result<TItem> =
279
279
 
280
280
  export type TreeArray<TNode> = TNode & { children: TreeArray<TNode>[] };
281
281
 
282
- /** 정렬/비교 가능한 타입 */
282
+ /** Type that can be sorted/compared */
283
283
  export type ComparableType = string | number | boolean | DateTime | DateOnly | Time | undefined;
284
284
 
285
285
  //#endregion