@simplysm/sd-claude 14.0.97 → 14.0.99

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 (77) hide show
  1. package/claude/references/sd-simplysm14/README.md +16 -16
  2. package/claude/references/sd-simplysm14/apis/angular/README.md +81 -153
  3. package/claude/references/sd-simplysm14/apis/angular/controls.md +179 -205
  4. package/claude/references/sd-simplysm14/apis/angular/crud.md +71 -57
  5. package/claude/references/sd-simplysm14/apis/angular/directives.md +49 -109
  6. package/claude/references/sd-simplysm14/apis/angular/features.md +58 -86
  7. package/claude/references/sd-simplysm14/apis/angular/kanban.md +32 -40
  8. package/claude/references/sd-simplysm14/apis/angular/layout.md +38 -52
  9. package/claude/references/sd-simplysm14/apis/angular/overlay.md +86 -110
  10. package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +54 -86
  11. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +82 -74
  12. package/claude/references/sd-simplysm14/apis/angular/sheet.md +56 -80
  13. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +15 -15
  14. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +21 -21
  15. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +79 -53
  16. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +9 -11
  17. package/claude/references/sd-simplysm14/apis/core-browser/README.md +15 -15
  18. package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +20 -20
  19. package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +18 -18
  20. package/claude/references/sd-simplysm14/apis/core-common/README.md +20 -49
  21. package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +66 -55
  22. package/claude/references/sd-simplysm14/apis/core-common/collection-ext.md +83 -56
  23. package/claude/references/sd-simplysm14/apis/core-common/errors.md +32 -21
  24. package/claude/references/sd-simplysm14/apis/core-common/obj.md +57 -39
  25. package/claude/references/sd-simplysm14/apis/core-common/serialization.md +36 -30
  26. package/claude/references/sd-simplysm14/apis/core-common/value-types.md +69 -41
  27. package/claude/references/sd-simplysm14/apis/core-node/README.md +4 -4
  28. package/claude/references/sd-simplysm14/apis/core-node/consola.md +15 -13
  29. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +11 -7
  30. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +8 -8
  31. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +29 -20
  32. package/claude/references/sd-simplysm14/apis/core-node/pathx.md +14 -6
  33. package/claude/references/sd-simplysm14/apis/core-node/worker.md +3 -3
  34. package/claude/references/sd-simplysm14/apis/excel/README.md +3 -3
  35. package/claude/references/sd-simplysm14/apis/excel/cell.md +32 -32
  36. package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +23 -24
  37. package/claude/references/sd-simplysm14/apis/excel/style.md +24 -30
  38. package/claude/references/sd-simplysm14/apis/excel/utils.md +20 -23
  39. package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +60 -71
  40. package/claude/references/sd-simplysm14/apis/excel/wrapper.md +36 -36
  41. package/claude/references/sd-simplysm14/apis/lint/README.md +7 -9
  42. package/claude/references/sd-simplysm14/apis/lint/recommended.md +59 -37
  43. package/claude/references/sd-simplysm14/apis/lint/rules.md +81 -74
  44. package/claude/references/sd-simplysm14/apis/orm-common/README.md +6 -6
  45. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +112 -78
  46. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +131 -75
  47. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +126 -82
  48. package/claude/references/sd-simplysm14/apis/orm-common/schema.md +170 -113
  49. package/claude/references/sd-simplysm14/apis/orm-common/types.md +102 -48
  50. package/claude/references/sd-simplysm14/apis/orm-node/README.md +12 -13
  51. package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +3 -3
  52. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +5 -5
  53. package/claude/references/sd-simplysm14/apis/sd-cli/SdTsCompiler.md +67 -65
  54. package/claude/references/sd-simplysm14/apis/sd-cli/sd-config-types.md +130 -123
  55. package/claude/references/sd-simplysm14/apis/service-client/README.md +63 -63
  56. package/claude/references/sd-simplysm14/apis/service-client/orm.md +22 -22
  57. package/claude/references/sd-simplysm14/apis/service-client/transport.md +30 -26
  58. package/claude/references/sd-simplysm14/apis/service-common/README.md +8 -8
  59. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +13 -6
  60. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +1 -1
  61. package/claude/references/sd-simplysm14/apis/service-server/README.md +43 -47
  62. package/claude/references/sd-simplysm14/apis/service-server/built-in-services.md +35 -0
  63. package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +20 -19
  64. package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +23 -25
  65. package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +9 -9
  66. package/claude/references/sd-simplysm14/apis/storage/README.md +26 -26
  67. package/claude/references/sd-simplysm14/manuals/client-component.md +9 -1
  68. package/claude/references/sd-simplysm14/manuals/client-crud.md +1 -1
  69. package/claude/references/sd-simplysm14/manuals/client-orm.md +1 -0
  70. package/claude/references/sd-simplysm14/manuals/client-service.md +1 -0
  71. package/claude/references/sd-simplysm14/manuals/client-shared-data.md +1 -0
  72. package/claude/references/sd-simplysm14/manuals/client-ssg.md +1 -0
  73. package/claude/sd-system-prompt.md +11 -26
  74. package/claude/skills/sd-docs/references/subagent-prompt.md +4 -3
  75. package/claude/skills/sd-spec/SKILL.md +87 -18
  76. package/claude/skills/sd-spec/references/format.md +2 -2
  77. package/package.json +1 -1
@@ -1,81 +1,108 @@
1
- # @simplysm/core-common — 배열/Set/Map 확장
1
+ # @simplysm/core-common — collection-ext
2
2
 
3
- `@simplysm/core-common` 진입점을 import 하면 `Array`/`ReadonlyArray`/`Set`/`Map` 프로토타입에 확장 메서드가 전역 설치됨(별도 import 불필요, 패키지를 한 번이라도 import 한 코드 전체에 적용). LINQ 류 조회·그룹화·집합 연산·diff/merge·트리 변환을 다룰 함께 참조. 관련 결과 타입(`ArrayDiffsResult`/`ArrayOneWayDiffResult`/`TreeArray`/`ComparableType`)도 진입점에서 export 됨.
3
+ `@simplysm/core-common` 진입점을 import 하면 `Array`/`ReadonlyArray`/`Set`/`Map` 프로토타입에 확장 메서드가 전역 설치됨(별도 import 불필요 패키지를 한 번이라도 import 한 코드 전체에 적용). LINQ 류 조회·그룹화·집합 연산·diff/merge·트리 변환에 사용. 결과/유틸 타입 `ArrayDiffsResult`/`ArrayOneWayDiffResult`/`TreeArray`/`ComparableType` 도 진입점에서 export 됨.
4
4
 
5
- ## Array 확장 조회/필터
5
+ `@mutates` 표시된 메서드는 원본 배열/Set/Map 을 직접 수정한다. 그 외 배열 메서드는 새 배열·Map 등을 반환한다.
6
6
 
7
- - `single(predicate?): TItem | undefined` 조건에 맞는 유일 요소. 2개 이상 매칭이면 `ArgumentError`(데이터 무결성 단언용). predicate 생략 시 전체 대상.
8
- - `first(predicate?): TItem | undefined` — 첫 매칭(생략 시 `[0]`). 없으면 undefined.
9
- - `last(predicate?): TItem | undefined` — 마지막 매칭(생략 시 끝 요소). 뒤에서부터 탐색.
10
- - `filterExists(): NonNullable<TItem>[] ` — null/undefined 제거(타입도 좁힘).
11
- - `ofType(type)` — 특정 타입만 필터. `type` 이 `PrimitiveTypeStr`(`"string"|"number"|"boolean"|"DateTime"|"DateOnly"|"Time"|"Uuid"|"Bytes"`)면 해당 원시·값타입, 생성자(`Type<N>`)면 `instanceof`/생성자 일치로 좁힘.
12
- - `filterAsync(predicate): Promise<TItem[]>` — 비동기 술어를 순차 평가하는 필터.
7
+ ## Array조회
13
8
 
14
- ## Array 확장매핑/평탄화 (비동기)
9
+ - `single(predicate?): TItem | undefined` 조건에 맞는 단일 요소. 2개 이상이면 `ArgumentError`, 없으면 undefined.
10
+ - `first(predicate?): TItem | undefined` — 첫 요소(predicate 있으면 `find`).
11
+ - `last(predicate?): TItem | undefined` — 마지막 요소(predicate 있으면 뒤에서부터 탐색).
12
+ - `filterExists(): NonNullable<TItem>[]` — null/undefined 제거(타입도 `NonNullable` 로 좁힘).
13
+ - `ofType(type): ...` — 특정 타입 요소만 필터. `type` 이 `PrimitiveTypeStr`(`"string"|"number"|"boolean"|"DateTime"|"DateOnly"|"Time"|"Uuid"|"Bytes"`)면 해당 원시/값 타입으로, `Type<N>`(생성자)이면 `instanceof`/`constructor` 일치로 필터하며 반환 타입을 좁힘.
14
+ - `filterAsync(predicate): Promise<TItem[]>` — 비동기 필터(**순차** 실행).
15
+ - `mapAsync(selector): Promise<TResult[]>` — 비동기 매핑(**순차** 실행).
16
+ - `mapMany(selector?): ...` — 인자 없으면 1단계 평탄화 후 `filterExists`, selector 있으면 매핑 후 평탄화·`filterExists`.
17
+ - `mapManyAsync(selector?): Promise<...>` — 비동기(순차) 매핑 후 평탄화.
18
+ - `parallelAsync(fn): Promise<TResult[]>` — `Promise.all` 병렬 실행. 하나라도 reject 되면 전체 즉시 reject.
19
+ - `sum(selector?): number` — 합계(빈 배열은 0). 숫자가 아니면 `ArgumentError`.
20
+ - `min(selector?) / max(selector?)` — 최소/최대(문자열·숫자만, 빈 배열은 undefined). 다른 타입이면 `ArgumentError`.
21
+ - `shuffle(): TItem[]` — Fisher-Yates 셔플한 새 배열.
15
22
 
16
- - `mapAsync(selector): Promise<TResult[]>` — 비동기 매핑(순차).
17
- - `mapMany()` 한 단계 평탄화 후 null 제거. `mapMany(selector)` 매핑 평탄화.
18
- - `mapManyAsync(selector): Promise<TResult[]>` 비동기 매핑 평탄화(순차).
19
- - `parallelAsync(fn): Promise<TResult[]>` — `Promise.all` 병렬 처리. 하나라도 reject 면 전체 즉시 reject(원자성). 부분 실패를 허용하려면 사용하지 말 것.
23
+ ```ts
24
+ [1, 2, 3, 4].filterExists(); // [1, 2, 3, 4]
25
+ users.single((u) => u.id === 1); // id=1 인 유일 항목 또는 undefined
26
+ ```
20
27
 
21
- ## Array 확장 그룹화/Map/Object 변환
28
+ ## Array — 그룹화·맵 변환
22
29
 
23
- - `groupBy(keySelector, valueSelector?): { key; values }[]` — key 그룹. 원시 key 는 O(n)(Map), 객체 key 는 O(n²)(깊은 비교). 원시 key 만이면 `toArrayMap` 이 더 효율적.
24
- - `toMap(keySelector, valueSelector?): Map`key→단일값 Map. 중복 key 면 `ArgumentError`.
25
- - `toMapAsync(...)` — 비동기 selector 버전(중복 `ArgumentError`).
26
- - `toArrayMap(keySelector, valueSelector?): Map<K, V[]>` — key→배열 Map(O(n)). 중복 key 허용·누적.
27
- - `toSetMap(keySelector, valueSelector?): Map<K, Set<V>>` — keySet Map.
28
- - `toMapValues(keySelector, valueSelector)` — key 별로 모은 배열을 `valueSelector(items)` 로 집계해 Map 생성.
29
- - `toObject(keySelector, valueSelector?): Record<string, V>` — 문자열 key→값 객체. 중복 key `ArgumentError`(undefined 값은 덮어쓰기 허용).
30
- - `toTree(keyProp, parentKey): TreeArray<TItem>[]` — 평면 배열을 트리로(`parentKey` 가 null 인 것이 루트, 각 노드에 `children` 추가, 항목은 `clone` 됨, O(n)).
30
+ - `groupBy(keySelector, valueSelector?): { key; values }[]` — key 기준 그룹화. 원시 key 는 O(n)(Map), 객체 key 는 깊은 비교 O(n²).
31
+ - `toMap(keySelector, valueSelector?): Map<K, V>` 1:1 Map. 중복 key 면 `ArgumentError`.
32
+ - `toMapAsync(keySelector, valueSelector?): Promise<Map<K, V>>` — 비동기 selector 지원(순차). 중복 key `ArgumentError`.
33
+ - `toArrayMap(keySelector, valueSelector?): Map<K, V[]>` — 같은 key 끼리 배열로 모음(O(n), `Map.getOrCreate` 사용).
34
+ - `toSetMap(keySelector, valueSelector?): Map<K, Set<V>>` — 같은 key 끼리 Set 으로 모음.
35
+ - `toMapValues(keySelector, valueSelector): Map<K, V>` — key 그룹을 만든 `valueSelector(items: T[])` 로 집계값 생성.
36
+ - `toObject(keySelector, valueSelector?): Record<string, V>` — 문자열 key 객체. 같은 key non-null 값이 이미 있으면 `ArgumentError`(undefined 값은 덮어쓰기 허용).
37
+ - `toTree(keyProp, parentKey): TreeArray<TItem>[]` — 평면 배열을 트리로. `parentKey` 가 null/undefined항목이 루트, 각 항목은 복제되고 `children` 추가(O(n)).
31
38
 
32
- ## Array 확장 — 중복제거/정렬
39
+ ```ts
40
+ items.toArrayMap((x) => x.category); // Map<category, items[]>
41
+ items.toTree("id", "parentId"); // 루트 노드 배열(children 포함)
42
+ ```
33
43
 
34
- - `distinct(options?): TItem[]` 중복 제거(새 배열). `options` 가 boolean 이면 `matchAddress`(참조 비교, Set 기반 O(n)). 객체이면 `{ matchAddress?, keyFn? }` — `keyFn`(item→string|number) 주면 O(n), 없으면 객체는 깊은 비교 O(n²).
35
- - `orderBy(selector?): TItem[]` / `orderByDesc(selector?): TItem[]` — 오름/내림차순 새 배열. selector 는 `string|number|DateOnly|DateTime|Time|undefined` 반환(날짜류는 tick 비교). null/undefined 는 오름차순에서 앞, 내림차순에서 뒤.
36
- - `sum(selector?): number` — 합계(빈 배열 0). 숫자 아닌 값이면 `ArgumentError`.
37
- - `min()/max()` (선택자 버전 포함) — 최소/최대(number·string 만, 그 외 `ArgumentError`). 빈 배열이면 undefined.
38
- - `shuffle(): TItem[]` — Fisher-Yates 셔플 새 배열.
44
+ ## Array정렬·중복제거
39
45
 
40
- ## Array 확장diff/merge
46
+ - `distinct(options?): TItem[]`중복 제거(새 배열). `options` 가 boolean 이거나 `{ matchAddress?, keyFn? }`. `matchAddress:true` 면 참조(주소) 비교 O(n), `keyFn` 이면 커스텀 key O(n), 둘 다 없으면 원시값은 O(n)·객체는 깊은 비교 O(n²).
47
+ - `orderBy(selector?) / orderByDesc(selector?)` — 오름/내림 정렬(새 배열). selector 는 `string|number|DateTime|DateOnly|Time|undefined` 반환(날짜형은 tick 으로 비교). null/undefined 는 오름차순에서 앞·내림차순에서 뒤. 비교 불가 타입이면 `ArgumentError`.
48
+ - `distinctThis(options?)` `@mutates` — 원본에서 중복 제거. 옵션은 `distinct` 와 동일.
49
+ - `orderByThis(selector?) / orderByDescThis(selector?)` `@mutates` — 원본 정렬.
41
50
 
42
- - `diffs(target, options?): ArrayDiffsResult[]` 두 배열 비교. `options.keys`(키 비교용 속성들), `options.excludes`(비교 제외 속성). 전체 일치 우선, 없으면 key 일치를 UPDATE 로 봄. 결과 union `ArrayDiffsResult<TOriginal, TOther>`: `{ source: undefined; target }`(INSERT) / `{ source; target: undefined }`(DELETE) / `{ source; target }`(UPDATE).
43
- - `oneWayDiffs(orgItems, keyPropNameOrGetValFn, options?): ArrayOneWayDiffResult[]` — 원본(배열 또는 Map) 대비 단방향 diff. key 추출은 속성명 또는 함수. `options`: `includeSame`(같은 항목도 결과 포함), `excludes`/`includes`(비교 대상 속성 한정). 결과 `ArrayOneWayDiffResult<TItem>`: `{ type: "create"; item; orgItem: undefined }`(key 없거나 원본에 없음) / `{ type: "update"; item; orgItem }`(값 다름) / `{ type: "same"; item; orgItem }`(`includeSame` 시).
44
- - `merge(target, options?): (...)[]` — `diffs` 결과로 source 기준 삼아 UPDATE `obj.merge`, INSERT 추가한 배열(clone 기반). `keys`/`excludes` 는 `diffs` 동일.
51
+ ## Arraydiff·merge
52
+
53
+ - `diffs(target, options?): ArrayDiffsResult<T, P>[]` — 배열 비교. 결과 항목은 INSERT(`source:undefined`)·DELETE(`target:undefined`)·UPDATE(둘 존재) 하나. `options.keys` 지정 key 들로 매칭(전체 깊은 일치 우선, 없으면 key 일치). `options.excludes` 는 비교 제외 속성. target 에 같은 key 가 여럿이면 첫 매칭만.
54
+ - `oneWayDiffs(orgItems, keyPropNameOrGetValFn, options?): ArrayOneWayDiffResult<T>[]` — 원본(`orgItems`: 배열 또는 `Map`) 대비 변경 분류. key 값이 없거나 원본에 없으면 `"create"`, 일치하면(옵션 `includeSame:true` 일 때만) `"same"`, 다르면 `"update"`. `excludes`/`includes` 로 비교 범위 조정.
55
+ - `merge(target, options?): (T | P | (T & P))[]` — `diffs` 결과로 병합한 새 배열. UPDATE 는 `obj.merge` 로 합치고, INSERT 는 뒤에 추가(DELETE 는 유지). source 항목을 못 찾으면 `SdError`.
45
56
 
46
57
  ```ts
47
- const result = current.diffs(prev, { keys: ["id"] });
48
- for (const d of result) {
49
- if (d.source == null) insert(d.target); // INSERT
50
- else if (d.target == null) remove(d.source); // DELETE
51
- else update(d.source, d.target); // UPDATE
52
- }
58
+ const result = orgRows.diffs(newRows, { keys: ["id"] });
59
+ // [{ source, target }, ...] — INSERT/DELETE/UPDATE
60
+ const changes = newRows.oneWayDiffs(orgRows, "id");
61
+ // [{ type: "create"|"update"|"same", item, orgItem }]
53
62
  ```
54
63
 
55
- ## Array 확장 원본 변경(@mutates)
56
-
57
- 원본 배열을 직접 수정하는 변형 메서드. `this` 또는 자기 자신을 반환해 체이닝 가능:
64
+ ## Array — 변형 (@mutates)
58
65
 
59
- - `distinctThis(options?)` — 원본에서 중복 제거(역순 splice).
60
- - `orderByThis(selector?)` / `orderByDescThis(selector?)` — 원본 정렬(`Array.sort`).
61
- - `insert(index, ...items)` — index 위치에 삽입.
62
- - `remove(item)` / `remove(selector)`일치 항목/조건 항목 제거(역순 순회).
63
- - `toggle(item)` — 있으면 제거, 없으면 추가.
64
- - `clear()` — 전체 비움.
66
+ - `insert(index, ...items): this` — 지정 위치에 삽입.
67
+ - `remove(item): this` / `remove(selector): this` — 값(참조) 또는 조건에 맞는 항목 모두 제거(역순 순회).
68
+ - `toggle(item): this` — 있으면 제거, 없으면 추가.
69
+ - `clear(): this` — 전부 제거.
65
70
 
66
71
  ## Set 확장
67
72
 
68
- - `adds(...values): this` — 여러 일괄 추가.
69
- - `toggle(value, addOrDel?: "add" | "del"): this` — 값 토글. `addOrDel` 생략 시 자동 토글, `"add"` 강제 추가, `"del"` 강제 제거(조건부 추가/제거를 한 줄로).
73
+ - `adds(...values: T[]): this` — 여러 값을 번에 추가(`@mutates`).
74
+ - `toggle(value: T, addOrDel?: "add" | "del"): this` — 값 토글(`@mutates`). `addOrDel` 생략 시 자동 토글(있으면 제거·없으면 추가), `"add"` 강제 추가, `"del"` 강제 제거. 조건부 추가/제거를 한 줄로.
75
+
76
+ ```ts
77
+ const set = new Set<number>([1, 2, 3]);
78
+ set.toggle(2); // {1, 3}
79
+ set.toggle(5, isAdmin ? "add" : "del");
80
+ ```
70
81
 
71
82
  ## Map 확장
72
83
 
73
- - `getOrCreate(key, newValue): V` / `getOrCreate(key, newValueFn: () => V): V` — 없으면 설정 후 반환. 둘째 인자가 함수면 **팩토리로 호출**되므로, 함수 자체를 값으로 저장하려면 `() => myFn` 처럼 팩토리로 감쌀 것.
74
- - `update(key, updateFn: (v: V | undefined) => V): void` — 현재 값(없으면 undefined)을 받아 새 값 설정. 카운터 증가·배열 누적 등에.
84
+ - `getOrCreate(key, newValue): V` / `getOrCreate(key, newValueFn: () => V): V` — key 가 있으면 그 값, 없으면 값을 설정 후 반환. 번째 인자가 함수면 **팩토리로 호출**됨(비용 큰 연산 지연 생성). 따라서 `V` 자체가 함수 타입이면 값을 저장하려면 `() => myFn` 처럼 팩토리로 감싸야 함.
85
+ - `update(key, updateFn: (v: V | undefined) => V): void` — 현재 값(없으면 undefined)을 받아 새 값 계산 후 set. 카운터 증가·배열 누적 등 기존 값 기반 갱신에.
86
+
87
+ ```ts
88
+ const arr = map.getOrCreate("k", []); // 없으면 [] 설정 후 반환
89
+ arr.push(item);
90
+ countMap.update("k", (v) => (v ?? 0) + 1); // 카운터 증가
91
+ ```
92
+
93
+ ## 결과/유틸 타입
75
94
 
76
95
  ```ts
77
- const countMap = new Map<string, number>();
78
- countMap.update("a", (v) => (v ?? 0) + 1);
79
- const groupMap = new Map<string, string[]>();
80
- groupMap.getOrCreate("g", () => []).push("item");
96
+ type ArrayDiffsResult<TOriginal, TOther> =
97
+ | { source: undefined; target: TOther } // INSERT
98
+ | { source: TOriginal; target: undefined } // DELETE
99
+ | { source: TOriginal; target: TOther }; // UPDATE
100
+
101
+ type ArrayOneWayDiffResult<TItem> =
102
+ | { type: "create"; item: TItem; orgItem: undefined }
103
+ | { type: "update"; item: TItem; orgItem: TItem }
104
+ | { type: "same"; item: TItem; orgItem: TItem };
105
+
106
+ type TreeArray<TNode> = TNode & { children: TreeArray<TNode>[] };
107
+ type ComparableType = string | number | boolean | DateTime | DateOnly | Time | undefined;
81
108
  ```
@@ -1,6 +1,6 @@
1
- # @simplysm/core-common — 에러 클래스
1
+ # @simplysm/core-common — errors
2
2
 
3
- 원인(cause) 체인을 메시지에 누적하는 `SdError` 파생 에러들, 그리고 catch 블록에서 메시지를 안전하게 뽑는 `err.message`. 예외를 throw 하거나 잡아 사용자 메시지를 만들 함께 참조.
3
+ 원인 체인을 ES2024 `cause` 묶는 에러 클래스군과, catch 블록의 `unknown` 에러에서 메시지를 안전 추출하는 `err` 네임스페이스. `import { SdError, ArgumentError, NotImplementedError, TimeoutError, err } from "@simplysm/core-common"`.
4
4
 
5
5
  ## SdError
6
6
 
@@ -12,24 +12,23 @@ class SdError extends Error {
12
12
  }
13
13
  ```
14
14
 
15
- ES `cause` 활용해 트리 형태로 에러를 감싸는 기반 클래스.
15
+ 트리 구조 조합형 에러. 모든 하위 에러 클래스의 베이스.
16
16
 
17
- - 첫 인자가 `Error` 면 그것을 `cause` 로 보존하고, `cause.stack` 자기 stack 뒤에 `---- cause stack ----` 이어 붙임.
18
- - 메시지들은 **역순으로 `" => "` 결합** 상위(가장 마지막 인자)부터 하위·원인 순으로 읽힘. null 메시지는 제외.
19
- - V8(Node/Chrome)에서는 `Error.captureStackTrace` 생성자 프레임을 stack 에서 제거.
17
+ - 첫 인자가 `Error` 면 그것을 `cause` 로 보관하고, 나머지 가변 인자(`...messages`)와 함께 메시지를 **역순으로** `" => "` 결합. 결과: `상위 메시지 => 하위 메시지 => 원본 에러 메시지`.
18
+ - 인자가 문자열이면 cause 없이 메시지만 역순 결합.
19
+ - 인자가 `Error`/문자열이 아니어도 null 아니면 `String()` 변환해 메시지로 사용.
20
+ - V8 엔진(Node/Chrome)에서는 `Error.captureStackTrace` 로 생성자 프레임 제거. cause 의 stack 이 있으면 현재 stack 끝에 `---- cause stack ----` 구분선과 함께 이어붙임.
20
21
  - `name` 은 `"SdError"`.
21
22
 
22
23
  ```ts
23
24
  try {
24
25
  await fetch(url);
25
- } catch (err) {
26
- throw new SdError(err as Error, "API 호출 실패", "사용자 로드 실패");
26
+ } catch (e) {
27
+ throw new SdError(e as Error, "API 호출 실패", "사용자 로드 실패");
27
28
  // message: "사용자 로드 실패 => API 호출 실패 => <원본 메시지>"
28
29
  }
29
30
  ```
30
31
 
31
- 주의: 첫 인자가 `Error` 가 아니면 메시지로 취급되므로, 원인 보존이 목적이면 `Error` 인스턴스를 첫 인자로 넘길 것.
32
-
33
32
  ## ArgumentError
34
33
 
35
34
  ```ts
@@ -39,15 +38,15 @@ class ArgumentError extends SdError {
39
38
  }
40
39
  ```
41
40
 
42
- 유효하지 않은 인자에 대한 에러. 디버깅을 위해 인자 객체를 **YAML 직렬화해 메시지에 첨부**.
41
+ 유효하지 않은 인자 전달 throw. 인자 객체를 `yaml` 라이브러리로 직렬화해 메시지에 첨부(트리 구조를 사람이 읽기 쉽게).
43
42
 
44
- - 첫 인자가 객체면 기본 메시지 `"잘못된 인자입니다."` + YAML.
45
- - 첫 인자가 문자열이면 커스텀 메시지 + 둘째 인자 객체의 YAML.
46
- - `name` 은 `"ArgumentError"`. 패키지 내부 검증 실패(잘못된 UUID, hex 홀수 길이, 중복 key, chain 등)에서 광범위하게 throw 됨.
43
+ - 첫 인자가 객체면 기본 메시지 `"잘못된 인자입니다."` + 빈 줄 + `YAML.stringify(argObj)`.
44
+ - 첫 인자가 문자열이면 메시지 + 빈 줄 + 둘째 인자 객체의 YAML. argObj 가 null 이면 YAML 없이 메시지만.
45
+ - `name` 은 `"ArgumentError"`. 패키지 내부의 인자 검증 실패(Uuid 형식·hex 길이·중복 key·`orderBy` 불가 타입 등) 에러로 throw 됨.
47
46
 
48
47
  ```ts
49
- throw new ArgumentError("잘못된 사용자", { userId: 123 });
50
- // message: "잘못된 사용자\n\nuserId: 123\n"
48
+ throw new ArgumentError("잘못된 사용자", { userId: 123, name: null });
49
+ // "잘못된 사용자\n\nuserId: 123\nname: null\n"
51
50
  ```
52
51
 
53
52
  ## NotImplementedError
@@ -58,7 +57,11 @@ class NotImplementedError extends SdError {
58
57
  }
59
58
  ```
60
59
 
61
- 미구현 분기·추상 메서드 스텁에서 throw. 메시지는 `"미구현"` 뒤에 `message` 있으면 `": " + message` 를 덧붙임. `name` 은 `"NotImplementedError"`.
60
+ 아직 구현되지 않은 분기·추상 스텁에서 throw. 메시지는 `"미구현"` 인자가 있으면 `": " + message` 를 덧붙임. `name` 은 `"NotImplementedError"`.
61
+
62
+ ```ts
63
+ throw new NotImplementedError(`타입 ${type} 처리`); // "미구현: 타입 B 처리"
64
+ ```
62
65
 
63
66
  ## TimeoutError
64
67
 
@@ -68,17 +71,25 @@ class TimeoutError extends SdError {
68
71
  }
69
72
  ```
70
73
 
71
- 대기 시간 초과 에러. 메시지는 `"대기 시간 초과"` + `count` 있으면 `"(N회 시도)"` + `message` 있으면 `": " + message`. `name` 은 `"TimeoutError"`. `wait.until` 이 최대 시도 횟수 초과 시 자동으로 던지며, `err instanceof TimeoutError` 로 분기 가능.
74
+ 대기 시간 초과 throw. 메시지는 `"대기 시간 초과"` `count` 있으면 `(N회 시도)`, `message` 있으면 `: message` 덧붙임. `name` 은 `"TimeoutError"`. `wait.until` 이 최대 시도 횟수를 초과하면 `new TimeoutError(count)` 로 자동 throw 한다([async-runtime.md](./async-runtime.md) 참조).
75
+
76
+ ```ts
77
+ try {
78
+ await wait.until(() => isReady, 100, 50);
79
+ } catch (e) {
80
+ if (e instanceof TimeoutError) { /* ... */ }
81
+ }
82
+ ```
72
83
 
73
- ## err.message
84
+ ## err (에러 메시지 추출)
74
85
 
75
86
  `import { err } from "@simplysm/core-common"` 네임스페이스.
76
87
 
77
- - `message(err: unknown): string` — `unknown` 에러에서 메시지 추출. `Error` `.message`, 아니면 `String(err)`. catch 블록에서 타입 좁히기 없이 메시지를 얻을 때.
88
+ - `message(error: unknown): string` — `Error` 인스턴스면 `.message`, 아니면 `String(error)`. catch 블록의 `unknown` 에러에서 메시지를 안전하게 뽑을 때.
78
89
 
79
90
  ```ts
80
91
  import { err } from "@simplysm/core-common";
81
92
  try { /* ... */ } catch (e) {
82
- toast.danger(err.message(e));
93
+ logger.error(err.message(e));
83
94
  }
84
95
  ```
@@ -1,70 +1,88 @@
1
- # @simplysm/core-common — obj 네임스페이스
1
+ # @simplysm/core-common — obj
2
2
 
3
- `import { obj } from "@simplysm/core-common"`. 깊은 복사·비교·병합과 체인 경로 접근, 타입 안전 Object 헬퍼. 값 타입(`DateTime`/`DateOnly`/`Time`/`Uuid`/`Uint8Array`)·`Date`·`RegExp`·`Map`/`Set`·`Error` 를 인지해 올바르게 다룸. 상태 비교·patch·불변 업데이트가 필요할 때 함께 참조.
3
+ `import { obj } from "@simplysm/core-common"`. 깊은 복사·비교·병합과 체인 경로 접근, 타입 안전 Object 헬퍼. 값 타입(`DateTime`/`DateOnly`/`Time`/`Uuid`/`Uint8Array`)·`Date`·`RegExp`·`Map`/`Set`·`Error` 를 인지해 올바르게 다룸. 상태 비교·patch·불변 업데이트가 필요할 때 사용.
4
4
 
5
- ## clone / equal
5
+ ## clone
6
6
 
7
- - `clone<T>(source: T): T` — 깊은 복사. 순환 참조 지원, 타입/Date/RegExp/Error(cause 포함)/Map/Set/Array/일반객체 처리(프로토타입 유지). 함수·Symbol 은 참조 유지, WeakMap/WeakSet 미지원, getter 는 현재 값으로 평가됨.
8
- - `equal(source, target, options?: EqualOptions): boolean` — 깊은 동등 비교. `EqualOptions` 필드:
9
- - `topLevelIncludes?: string[]` — 지정 시 최상위에서 이 key 들만 비교.
10
- - `topLevelExcludes?: string[]` — 최상위에서 이 key 들 제외하고 비교.
11
- - `ignoreArrayIndex?: boolean` — 배열 순서 무시(순열로 비교, O(n²)).
12
- - `shallow?: boolean` — 1단계 참조 비교만(대용량 시 성능용).
13
- - 비교 시 객체는 null/undefined key 를 무시(존재하지 않는 것과 동일 취급). include/exclude 는 객체 속성 key 에만 적용(Map key 는 항상 포함).
7
+ - `clone<T>(source: T): T` — 깊은 복사. 순환 참조 지원(`WeakMap` 추적). `Date`/`DateTime`/`DateOnly`/`Time`/`Uuid`/`RegExp`/`Uint8Array`/`Array`/`Map`/`Set`/`Error`(cause·커스텀 속성 포함) 를 타입별로 복제하고 프로토타입 체인 유지. 단 **함수·Symbol 은 복사 안 되고 참조 유지**, `WeakMap`/`WeakSet` 미지원(빈 객체로 복사됨), getter/setter 는 현재 값으로 평가되어 복사됨.
14
8
 
15
9
  ```ts
16
- obj.equal(a, b, { topLevelExcludes: ["updatedAt"] }); // updatedAt 제외 비교
10
+ const copy = obj.clone({ at: new DateTime(), tags: new Set([1, 2]) });
11
+ ```
12
+
13
+ ## equal
14
+
15
+ - `equal(source, target, options?: EqualOptions): boolean` — 깊은 동등성 비교. `Date`/값 타입(tick 비교)/`Uuid`(문자열)/`RegExp`(source+flags)/`Array`/`Map`/`Set`/객체를 재귀 비교. 객체·Map 비교에서 null 값 key 는 무시됨.
16
+
17
+ `EqualOptions`:
18
+
19
+ - `topLevelIncludes?: string[]` — 지정 시 그 key 들만 비교(최상위 레벨에만 적용, Map key 에는 미적용).
20
+ - `topLevelExcludes?: string[]` — 비교에서 제외할 key(최상위 레벨에만).
21
+ - `ignoreArrayIndex?: boolean` — true 면 배열 순서 무시(같은 집합의 순열인지). O(n²).
22
+ - `shallow?: boolean` — true 면 1단계 참조 비교(`===`).
23
+
24
+ ```ts
25
+ obj.equal(a, b, { topLevelExcludes: ["updatedAt"] });
17
26
  ```
18
27
 
19
28
  ## merge / merge3
20
29
 
21
- - `merge<S, T>(source, target, opt?: MergeOptions): S & T` — 깊은 병합(새 객체, 원본 불변). `MergeOptions`:
22
- - `arrayProcess?: "replace" | "concat"` — 배열 처리. `"replace"`(기본)=target 배열로 교체, `"concat"`=두 배열 합치고 Set 으로 중복 제거.
23
- - `useDelTargetNull?: boolean` — target 값이 null 이면 결과에서 해당 key 삭제(true). false/미지정이면 source 값 유지.
24
- - 타입이 다르면 target 으로 덮어쓰고, 값 타입/Date/Uint8Array 는 통째로 교체.
25
- - `merge3<S, O, T>(source, origin, target, optionsObj?): { conflict: boolean; result }` — 3-way 병합(공통 조상 origin 기준). 한쪽만 바뀌면 그 값 채택, 양쪽 같으면 그 값, 셋 다 다르면 `conflict: true`(origin 값 유지). `optionsObj` key `Merge3KeyOptions`(`keys`=비교할 하위 key, `excludes`=제외 하위 key, `ignoreArrayIndex`)로 key 마다 `equal` 비교 옵션 지정.
30
+ - `merge<S, T>(source, target, opt?: MergeOptions): S & T` — 깊은 병합(원본 불변, 객체 반환). 타입이 다르거나 값 타입/`Uint8Array` 면 target 으로 교체. `Map` 은 key 별 재귀 병합.
31
+
32
+ `MergeOptions`:
33
+
34
+ - `arrayProcess?: "replace" | "concat"` — 배열 처리. `"replace"`(기본): target 배열로 교체, `"concat"`: source+target 합쳐 `Set` 으로 중복 제거(객체는 참조 비교).
35
+ - `useDelTargetNull?: boolean` — true 면 target 값이 null 인 key 를 결과에서 삭제. false/미지정이면 source 값 유지.
36
+
37
+ - `merge3<S, O, T>(source, origin, target, optionsObj?): { conflict: boolean; result }` — 3-way 병합. origin 을 공통 조상으로 source/target 변경을 합침. 한쪽만 변경됐으면 변경값 사용, 둘 다 같으면 그 값, 셋 다 다르면 충돌(`conflict:true`, origin 값 유지). `optionsObj` 는 key 별 `Merge3KeyOptions`(`keys`/`excludes`/`ignoreArrayIndex` — 각 key 의 `equal` 비교 옵션).
26
38
 
27
39
  ```ts
28
40
  const { conflict, result } = obj.merge3(
29
41
  { a: 1, b: 2 }, { a: 1, b: 1 }, { a: 2, b: 1 },
30
- ); // conflict: false, result: { a: 2, b: 2 }
42
+ ); // conflict:false, result:{ a:2, b:2 }
31
43
  ```
32
44
 
33
- ## pick / omit
45
+ ## omit / pick
34
46
 
35
- - `pick(item, pickKeys): Pick<T, K>` — 지정 key 남긴 새 객체.
36
- - `omit(item, omitKeys): Omit<T, K>` — 지정 key 제외한 새 객체.
47
+ - `omit(item, omitKeys: K[]): Omit<T, K>` — 지정 key 제외한 새 객체.
48
+ - `pick(item, pickKeys: K[]): Pick<T, K>` — 지정 key 담은 새 객체.
49
+ - `omitByFilter(item, omitKeyFn: (key) => boolean): T` — 함수가 true 를 반환하는 key 제외. (`@internal`)
37
50
 
38
51
  ## 체인 경로 접근
39
52
 
40
- 문자열 경로(`"a.b[0].c"`)중첩 값에 접근. 경로는 `.`/`[` `]` 분해하고 숫자 세그먼트는 배열 인덱스로 처리.
53
+ 문자열 경로는 `.` 과 `[]` 분해되고 `?!'"` 문자는 제거되며 숫자 세그먼트는 인덱스로 변환됨.
41
54
 
42
- - `getChainValue(obj, chain): unknown` / `getChainValue(obj, chain, optional: true): unknown | undefined` — 경로 값 조회. `optional` 이면 중간 null/undefined 를 만나도 에러 없이 undefined.
43
- - `getChainValueByDepth(obj, key, depth, optional?)` — 같은 key 로 `depth` 단계 하강(예: `parent` 를 2). `depth < 1` 이면 `ArgumentError`.
44
- - `setChainValue(obj, chain, value): void` — 경로에설정(중간 객체 자동 생성). 빈 chain 이면 `ArgumentError`.
45
- - `deleteChainValue(obj, chain): void` — 경로삭제(중간 경로 없으면 조용히 반환). 빈 chain 이면 `ArgumentError`.
55
+ - `getChainValue(obj, chain): unknown` / `getChainValue(obj, chain, true): unknown | undefined` — `"a.b[0].c"` 경로로 값 조회. 셋째 인자 `true` 중간 null/undefined 를 만나도 throw 없이 undefined 반환.
56
+ - `getChainValueByDepth(obj, key, depth, optional?): ...` — 같은 key 로 `depth` 하강(예: `parent` 를 2단계). `depth < 1` 이면 `ArgumentError`. `optional:true` 면 중간 null 허용. (`@internal`)
57
+ - `setChainValue(obj, chain, value): void` — 경로로설정. 중간 경로 없으면 객체로 생성. 빈 chain 이면 `ArgumentError`.
58
+ - `deleteChainValue(obj, chain): void` — 경로로삭제. 중간 경로가 없으면 조용히 반환. 빈 chain 이면 `ArgumentError`.
59
+
60
+ ```ts
61
+ obj.getChainValue(data, "user.address[0].city", true);
62
+ obj.setChainValue(data, "user.name", "Alice");
63
+ ```
46
64
 
47
- ## 정리/변환 헬퍼
65
+ ## 정리·변환
48
66
 
49
- - `clearUndefined(obj): T` — null/undefined 값 key 삭제(@mutates 원본 수정).
50
- - `clear(obj): {}` — 모든 key 삭제(@mutates).
51
- - `nullToUndefined(obj): T | undefined` — null 을 undefined 로 재귀 변환(@mutates, 타입·순환 참조 보존). null-free 규칙 적용 시.
52
- - `unflatten(flatObj): Record` — `{ "a.b": 1 }` `{ a: { b: 1 } }` 중첩화.
67
+ - `clearUndefined(obj): T` `@mutates @internal` — null/undefined 값 key 삭제(원본 수정).
68
+ - `clear(obj): Record<string, never>` `@mutates @internal` — 모든 key 삭제(원본 수정).
69
+ - `nullToUndefined(obj): T | undefined` `@mutates @internal` — null 을 undefined 로 재귀 변환(원본 수정, 순환 참조 추적). 타입은 변환하지 않음. `json.parse` 가 내부적으로 사용.
70
+ - `unflatten(flatObj): Record<string, unknown>` `@internal` — `{ "a.b.c": 1 }` `{ a: { b: { c: 1 } } }` 로.
53
71
 
54
72
  ## 타입 안전 Object 헬퍼
55
73
 
56
- - `keys(obj): (keyof T)[]` — 타입 보존 `Object.keys`.
57
- - `entries(obj): Entries<T>` — 타입 보존 `Object.entries`(`[K, T[K]]` 튜플 배열).
58
- - `fromEntries(entryPairs): { [K in T[0]]: T[1] }` — 타입 보존 `Object.fromEntries`.
59
- - `map(obj, fn: (key, value) => [newKey | null, newValue]): Record` 엔트리 변환. fn key 자리에 null 반환하면 기존 key 유지. key·값 동시 변환에.
74
+ - `keys(obj): (keyof T)[]` — 타입 안전 `Object.keys`.
75
+ - `entries(obj): Entries<T>` — 타입 안전 `Object.entries`(`[key, value]` 튜플 배열).
76
+ - `fromEntries(entryPairs): { [K in T[0]]: T[1] }` — 타입 안전 `Object.fromEntries`.
77
+ - `map(obj, fn): Record<...>` — 각 엔트리를 `fn(key, value) => [newKey | null, newValue]` 변환한 객체. `newKey` null 이면 원래 key 유지(값만 변환).
60
78
 
61
79
  ```ts
62
- obj.map({ primary: "255,0,0" }, (k, rgb) => [null, `rgb(${rgb})`]);
63
- // { primary: "rgb(255,0,0)" }
80
+ obj.keys({ a: 1, b: 2 }); // ("a" | "b")[]
81
+ obj.map(colors, (k, rgb) => [null, `rgb(${rgb})`]); // 값만 변환
64
82
  ```
65
83
 
66
- ## 타입 유틸리티 (export type)
84
+ ## 유틸 타입
67
85
 
86
+ - `UndefToOptional<TObject>` — `undefined` 를 포함한 속성을 optional 로 변환. `{ a: string; b: string | undefined }` → `{ a: string; b?: string | undefined }`.
87
+ - `OptionalToUndef<TObject>` — optional 속성을 필수 + `undefined` 유니온으로. `{ a: string; b?: string }` → `{ a: string; b: string | undefined }`.
68
88
  - `EqualOptions` / `MergeOptions` / `Merge3KeyOptions` — 위 함수들의 옵션 타입.
69
- - `UndefToOptional<TObject>` — `undefined` 를 포함한 속성을 optional(`?`)로 변환.
70
- - `OptionalToUndef<TObject>` — optional 속성을 필수 + `| undefined` 유니온으로 변환.
@@ -1,56 +1,62 @@
1
- # @simplysm/core-common — 직렬화 (json·xml·bytes·transfer)
1
+ # @simplysm/core-common — serialization
2
2
 
3
- 커스텀 값 타입을 보존하는 직렬화/역직렬화 묶음. JSON 문자열, XML, hex/base64 바이트, Worker 전송 형태를 다룰 때 함께 참조. `json`·`transfer` 는 `DateTime`/`DateOnly`/`Time`/`Uuid`/`Map`/`Set`/`Error`/`Uint8Array`(transfer `RegExp` 추가)를 `__type__` 태그로 보존·복원.
3
+ 커스텀 값 타입을 보존하는 직렬화/역직렬화 묶음. JSON 문자열, XML, hex/base64 바이트, Worker 전송 형태를 다룰 때 사용. `json`·`transfer` 는 타입을 `__type__` 태그 객체로 보존·복원한다. `import { json, xml, bytes, transfer } from "@simplysm/core-common"`.
4
4
 
5
- ## json (`import { json } from "@simplysm/core-common"`)
5
+ ## json (커스텀 타입 보존 JSON)
6
6
 
7
- - `stringify(obj, options?): string` 커스텀 타입 포함 직렬화. `options`:
8
- - `space?: string | number` — JSON 들여쓰기.
9
- - `replacer?: (key, value) => unknown` — 기본 타입 변환 **전** 호출되는 커스텀 변환기.
10
- - `redactBytes?: boolean` true 면 `Uint8Array` 내용을 `"__hidden__"` 으로 가림(로깅용). 이 결과는 `parse` 로 복원 불가.
11
- - 순환 참조 `TypeError`. 전역 프로토타입을 수정하지 않아 Worker 안전. undefined 값은 결과에서 제외.
12
- - `parse<T>(json: string): T` — 역직렬화. `__type__`/`data` 마커로 타입 복원. **모든 JSON null 을 undefined 로 변환**(simplysm null-free 규칙). 사용자 데이터에 `{ __type__, data }` 형태가 있으면 의도치 않게 타입으로 변환될 수 있음에 주의. `redactBytes` 가려진 바이트를 만나면 `SdError`. 파싱 실패 시 `SdError`(개발 모드 `env("DEV")` 면 전체 JSON, 운영 모드면 길이만 메시지에 포함).
7
+ `DateTime`/`DateOnly`/`Time`/`Uuid`/`Set`/`Map`/`Error`/`Uint8Array` `{ __type__, data }` 형태로 직렬화하고 복원. `Date.prototype.toJSON` 같은 전역 프로토타입을 수정하지 않아 Worker 환경에서 안전.
8
+
9
+ - `json.stringify(obj, options?): string`
10
+ - `options.space?: string | number` 들여쓰기.
11
+ - `options.replacer?: (key, value) => unknown` 기본 타입 변환 **전에** 호출되는 커스텀 replacer.
12
+ - `options.redactBytes?: boolean` — true `Uint8Array` 내용을 `"__hidden__"` 으로 대체(로깅용). 이렇게 직렬화하면 `json.parse` 로 복원 불가(복원 시 `SdError` throw).
13
+ - 순환 참조가 있으면 `TypeError`. 객체에 `toJSON` 이 있으면 호출해 그 결과를 사용(위 커스텀 타입은 사전 변환되므로 제외). undefined 값은 결과에서 제외.
14
+ - `json.parse<T>(json): T` — `__type__` 태그를 보고 원래 타입 복원. **모든 JSON null 은 undefined 로 변환됨**(simplysm null-free 규칙). 파싱 실패 시 `SdError`(개발 모드 `env("DEV")` 가 truthy 면 메시지에 전체 JSON, 운영 모드면 길이만).
15
+
16
+ > 주의: 사용자 데이터에 `{ __type__: "Date"|"DateTime"|..., data: ... }` 형태가 있으면 의도치 않게 타입으로 복원될 수 있음.
13
17
 
14
18
  ```ts
15
- import { json } from "@simplysm/core-common";
16
- const s = json.stringify({ at: new DateTime(), id: Uuid.generate() });
17
- const o = json.parse<{ at: DateTime; id: Uuid }>(s); // 타입 복원됨
19
+ const text = json.stringify({ at: new DateTime(), id: Uuid.generate() });
20
+ const back = json.parse<{ at: DateTime; id: Uuid }>(text); // 타입 복원됨
18
21
  ```
19
22
 
20
- ## xml (`import { xml } from "@simplysm/core-common"`)
23
+ ## xml
21
24
 
22
25
  `fast-xml-parser` 래퍼. 속성은 `$` 객체, 텍스트 노드는 `_` key, 자식 요소는 배열(루트 제외)로 표현.
23
26
 
24
- - `parse(str, options?: { stripTagPrefix?: boolean }): unknown` — XML→객체. `stripTagPrefix` 면 태그의 네임스페이스 접두사(`ns:tag`)를 제거(속성 접두사는 유지).
25
- - `stringify(obj, options?: XmlBuilderOptions): string` — 객체→XML. `options` 는 fast-xml-parser 빌더 옵션을 그대로 덮어씀.
27
+ - `xml.parse(str, options?: { stripTagPrefix?: boolean }): unknown` — XML→객체. `stripTagPrefix:true` 면 태그명의 네임스페이스 접두사(`ns:tag`)를 제거(속성 접두사는 유지).
28
+ - `xml.stringify(obj, options?: XmlBuilderOptions): string` — 객체→XML. `fast-xml-parser` `XmlBuilderOptions` 그대로 전달(기본 옵션에 덮어씀).
26
29
 
27
30
  ```ts
28
31
  xml.parse('<root id="1"><item>hello</item></root>');
29
32
  // { root: { $: { id: "1" }, item: [{ _: "hello" }] } }
30
33
  ```
31
34
 
32
- ## bytes (`import { bytes } from "@simplysm/core-common"`)
35
+ ## bytes (Uint8Array 인코딩)
36
+
37
+ `import { bytes } from "@simplysm/core-common"`. 모두 `Bytes`(= `Uint8Array`) 대상.
33
38
 
34
- `Uint8Array`(=`Bytes`) 인코딩 유틸. 모두 자체 구현(브라우저·Node 공용).
39
+ - `bytes.concat(arrays: Bytes[]): Bytes` 여러 배열 결합한 새 배열.
40
+ - `bytes.toHex(bytes): string` — 소문자 hex 문자열.
41
+ - `bytes.fromHex(hex): Bytes` — hex→바이트(대소문자 허용). 홀수 길이거나 비 hex 문자면 `ArgumentError`.
42
+ - `bytes.toBase64(bytes): string` — base64 인코딩(자체 구현, 패딩 `=` 포함).
43
+ - `bytes.fromBase64(base64): Bytes` — base64→바이트. 공백·패딩 정규화 후 검증. 비 base64 문자나 `% 4 === 1` 잔여 길이면 `ArgumentError`.
35
44
 
36
- - `concat(arrays: Bytes[]): Bytes` — 여러 바이트 배열 결합.
37
- - `toHex(bytes): string` 소문자 hex 문자열.
38
- - `fromHex(hex): Bytes` — hex→바이트. 홀수 길이·비hex 문자면 `ArgumentError`.
39
- - `toBase64(bytes): string` — base64 문자열.
40
- - `fromBase64(base64): Bytes` — base64→바이트(공백·패딩 정규화). 비base64 문자·잘못된 길이면 `ArgumentError`.
45
+ ```ts
46
+ bytes.toHex(new Uint8Array([255, 0, 127])); // "ff007f"
47
+ bytes.fromBase64("SGVsbG8="); // Uint8Array([72,101,108,108,111])
48
+ ```
41
49
 
42
- ## transfer (`import { transfer } from "@simplysm/core-common"`)
50
+ ## transfer (Worker 전송 직렬화)
43
51
 
44
- Worker 전송용 직렬화. `structuredClone` 이 다루는 커스텀 타입을 `__type__` 태그 객체로 변환하되 `Uint8Array` 그대로 두고 그 `ArrayBuffer` transfer 목록에 담아 zero-copy 전송.
52
+ `import { transfer } from "@simplysm/core-common"`. `structuredClone` 이 지원하지 않는 커스텀 타입을 처리해 Worker `postMessage` 보낼 있게 함. 지원: `Date`/`DateTime`/`DateOnly`/`Time`/`Uuid`/`RegExp`/`Error`(cause·code·detail 포함)/`Uint8Array`/`Array`/`Map`/`Set`/일반 객체. 다른 TypedArray 일반 객체로 처리됨.
45
53
 
46
- - `encode(obj): { result: unknown; transferList: ArrayBuffer[] }` — 전송 가능한 형태로 인코딩. `result` `postMessage` 본문, `transferList` 전송 목록으로 사용. 순환 참조 경로 정보 포함 `TypeError`, 동일 객체 다중 참조는 캐시 재사용(`SharedArrayBuffer` transferList 제외).
47
- - `decode(obj): unknown` — 수신측에서 `__type__` 태그를 다시 타입으로 복원.
54
+ - `transfer.encode(obj): { result: unknown; transferList: ArrayBuffer[] }` — 전송 가능 형태로 변환. `Uint8Array` `ArrayBuffer` zero-copy 전송을 위해 `transferList` 추가(`SharedArrayBuffer` 제외). 순환 참조면 경로 정보를 담은 `TypeError`. 같은 객체가 여러 곳에서 참조되면 인코딩 결과를 캐싱 재사용.
55
+ - `transfer.decode(obj): unknown` — `encode` 결과(또는 Worker 에서 받은 데이터)를 원래 타입으로 복원.
48
56
 
49
57
  ```ts
50
- import { transfer } from "@simplysm/core-common";
51
58
  const { result, transferList } = transfer.encode(data);
52
59
  worker.postMessage(result, transferList);
53
- // 수신측: const data = transfer.decode(event.data);
60
+ // 수신
61
+ const decoded = transfer.decode(event.data);
54
62
  ```
55
-
56
- 주의: `json` 은 문자열 직렬화(바이트는 hex 로), `transfer` 는 객체 그대로 전송(바이트는 zero-copy). 두 경로 모두 같은 커스텀 값 타입을 보존하지만 산출물 형태가 다름 — 저장·전송 매체에 맞게 선택.