@simplysm/sd-claude 14.0.91 → 14.0.92

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 (93) hide show
  1. package/claude/references/sd-simplysm14/README.md +7 -6
  2. package/claude/references/sd-simplysm14/apis/angular/README.md +59 -39
  3. package/claude/references/sd-simplysm14/apis/angular/controls.md +119 -186
  4. package/claude/references/sd-simplysm14/apis/angular/crud.md +70 -31
  5. package/claude/references/sd-simplysm14/apis/angular/directives.md +55 -57
  6. package/claude/references/sd-simplysm14/apis/angular/features.md +86 -105
  7. package/claude/references/sd-simplysm14/apis/angular/infra.md +48 -57
  8. package/claude/references/sd-simplysm14/apis/angular/layout.md +37 -47
  9. package/claude/references/sd-simplysm14/apis/angular/overlay.md +82 -74
  10. package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +61 -50
  11. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +74 -57
  12. package/claude/references/sd-simplysm14/apis/angular/sheet.md +63 -72
  13. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +23 -18
  14. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +21 -19
  15. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +23 -18
  16. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +72 -32
  17. package/claude/references/sd-simplysm14/apis/core-browser/README.md +18 -18
  18. package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +29 -29
  19. package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +41 -41
  20. package/claude/references/sd-simplysm14/apis/core-common/README.md +97 -90
  21. package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +75 -51
  22. package/claude/references/sd-simplysm14/apis/core-common/collection-ext.md +81 -0
  23. package/claude/references/sd-simplysm14/apis/core-common/errors.md +27 -29
  24. package/claude/references/sd-simplysm14/apis/core-common/obj.md +44 -45
  25. package/claude/references/sd-simplysm14/apis/core-common/serialization.md +34 -33
  26. package/claude/references/sd-simplysm14/apis/core-common/value-types.md +86 -0
  27. package/claude/references/sd-simplysm14/apis/core-node/README.md +6 -6
  28. package/claude/references/sd-simplysm14/apis/core-node/consola.md +3 -0
  29. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +2 -2
  30. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +1 -1
  31. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +2 -2
  32. package/claude/references/sd-simplysm14/apis/core-node/worker.md +6 -3
  33. package/claude/references/sd-simplysm14/apis/excel/README.md +10 -10
  34. package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +4 -2
  35. package/claude/references/sd-simplysm14/apis/excel/utils.md +1 -1
  36. package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +6 -6
  37. package/claude/references/sd-simplysm14/apis/lint/README.md +6 -32
  38. package/claude/references/sd-simplysm14/apis/lint/recommended.md +60 -0
  39. package/claude/references/sd-simplysm14/apis/lint/rules.md +17 -17
  40. package/claude/references/sd-simplysm14/apis/orm-common/README.md +15 -6
  41. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +68 -102
  42. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +75 -89
  43. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +87 -99
  44. package/claude/references/sd-simplysm14/apis/orm-common/schema.md +110 -147
  45. package/claude/references/sd-simplysm14/apis/orm-common/types.md +48 -51
  46. package/claude/references/sd-simplysm14/apis/orm-node/README.md +8 -13
  47. package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +5 -5
  48. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +9 -6
  49. package/claude/references/sd-simplysm14/apis/sd-cli/SdTsCompiler.md +9 -8
  50. package/claude/references/sd-simplysm14/apis/sd-cli/sd-config-types.md +23 -19
  51. package/claude/references/sd-simplysm14/apis/service-client/README.md +20 -12
  52. package/claude/references/sd-simplysm14/apis/service-client/orm.md +6 -6
  53. package/claude/references/sd-simplysm14/apis/service-client/transport.md +1 -1
  54. package/claude/references/sd-simplysm14/apis/service-common/README.md +35 -32
  55. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +23 -22
  56. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +23 -23
  57. package/claude/references/sd-simplysm14/apis/service-server/README.md +51 -43
  58. package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +6 -6
  59. package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +31 -21
  60. package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +8 -8
  61. package/claude/references/sd-simplysm14/apis/storage/README.md +55 -49
  62. package/claude/references/sd-simplysm14/manuals/client-component.md +843 -740
  63. package/claude/references/sd-simplysm14/manuals/client-crud.md +8 -0
  64. package/claude/references/sd-simplysm14/manuals/client-demo.md +6 -16
  65. package/claude/references/sd-simplysm14/manuals/client-shared-data.md +26 -0
  66. package/claude/references/sd-simplysm14/manuals/logging.md +1 -1
  67. package/claude/references/sd-simplysm14/manuals/orm.md +15 -1
  68. package/claude/rules/sd-design-rules.md +7 -0
  69. package/claude/sd-system-prompt.md +5 -8
  70. package/claude/skills/sd-debug/SKILL.md +43 -0
  71. package/claude/skills/sd-debug/workflow.js +390 -0
  72. package/claude/skills/sd-demo/SKILL.md +18 -20
  73. package/claude/skills/sd-dev/SKILL.md +127 -24
  74. package/claude/skills/sd-docs/SKILL.md +5 -3
  75. package/claude/skills/sd-docs/references/subagent-prompt.md +2 -3
  76. package/claude/skills/sd-impl/SKILL.md +18 -18
  77. package/claude/skills/sd-manual/SKILL.md +1 -0
  78. package/claude/skills/sd-review/SKILL.md +24 -18
  79. package/claude/skills/sd-review/workflow.js +324 -0
  80. package/claude/skills/sd-spec/SKILL.md +96 -679
  81. package/claude/skills/sd-spec/references/example-spec.md +28 -50
  82. package/claude/skills/sd-spec/references/format-analyze.md +232 -0
  83. package/claude/skills/sd-spec/references/format-design.md +248 -0
  84. package/claude/skills/sd-spec/workflow-analyze.js +615 -0
  85. package/claude/skills/sd-spec/workflow-design.js +667 -0
  86. package/claude/skills/sd-unpack/scripts/handlers/office_com.py +5 -1
  87. package/package.json +1 -1
  88. package/scripts/postinstall.mjs +157 -18
  89. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +0 -68
  90. package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +0 -77
  91. package/claude/references/sd-simplysm14/apis/core-common/datetime.md +0 -86
  92. package/claude/skills/sd-skill/SKILL.md +0 -245
  93. package/claude/skills/sd-skill/scripts/run_eval.py +0 -380
@@ -0,0 +1,81 @@
1
+ # @simplysm/core-common — 배열/Set/Map 확장
2
+
3
+ `@simplysm/core-common` 진입점을 import 하면 `Array`/`ReadonlyArray`/`Set`/`Map` 프로토타입에 확장 메서드가 전역 설치됨(별도 import 불필요, 패키지를 한 번이라도 import 한 코드 전체에 적용). LINQ 류 조회·그룹화·집합 연산·diff/merge·트리 변환을 다룰 때 함께 참조. 관련 결과 타입(`ArrayDiffsResult`/`ArrayOneWayDiffResult`/`TreeArray`/`ComparableType`)도 진입점에서 export 됨.
4
+
5
+ ## Array 확장 — 조회/필터
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[]>` — 비동기 술어를 순차 평가하는 필터.
13
+
14
+ ## Array 확장 — 매핑/평탄화 (비동기)
15
+
16
+ - `mapAsync(selector): Promise<TResult[]>` — 비동기 매핑(순차).
17
+ - `mapMany()` — 한 단계 평탄화 후 null 제거. `mapMany(selector)` — 매핑 후 평탄화.
18
+ - `mapManyAsync(selector): Promise<TResult[]>` — 비동기 매핑 후 평탄화(순차).
19
+ - `parallelAsync(fn): Promise<TResult[]>` — `Promise.all` 병렬 처리. 하나라도 reject 면 전체 즉시 reject(원자성). 부분 실패를 허용하려면 사용하지 말 것.
20
+
21
+ ## Array 확장 — 그룹화/Map/Object 변환
22
+
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>>` — key→Set 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)).
31
+
32
+ ## Array 확장 — 중복제거/정렬
33
+
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 셔플 새 배열.
39
+
40
+ ## Array 확장 — diff/merge
41
+
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` 와 동일.
45
+
46
+ ```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
+ }
53
+ ```
54
+
55
+ ## Array 확장 — 원본 변경(@mutates)
56
+
57
+ 원본 배열을 직접 수정하는 변형 메서드. `this` 또는 자기 자신을 반환해 체이닝 가능:
58
+
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()` — 전체 비움.
65
+
66
+ ## Set 확장
67
+
68
+ - `adds(...values): this` — 여러 값 일괄 추가.
69
+ - `toggle(value, addOrDel?: "add" | "del"): this` — 값 토글. `addOrDel` 생략 시 자동 토글, `"add"` 강제 추가, `"del"` 강제 제거(조건부 추가/제거를 한 줄로).
70
+
71
+ ## Map 확장
72
+
73
+ - `getOrCreate(key, newValue): V` / `getOrCreate(key, newValueFn: () => V): V` — 없으면 설정 후 반환. 둘째 인자가 함수면 **팩토리로 호출**되므로, 함수 자체를 값으로 저장하려면 `() => myFn` 처럼 팩토리로 감쌀 것.
74
+ - `update(key, updateFn: (v: V | undefined) => V): void` — 현재 값(없으면 undefined)을 받아 새 값 설정. 카운터 증가·배열 누적 등에.
75
+
76
+ ```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");
81
+ ```
@@ -1,33 +1,34 @@
1
1
  # @simplysm/core-common — 에러 클래스
2
2
 
3
- `throw` 던지거나, 에러 원인을 체인으로 감싸거나, catch 에서 `instanceof` 분기할 함께 읽히는 묶음. 모두 `SdError` 상속하므로 `instanceof SdError` 한꺼번에 잡을 수 있음.
3
+ 원인(cause) 체인을 메시지에 누적하는 `SdError` 파생 에러들, 그리고 catch 블록에서 메시지를 안전하게 뽑는 `err.message`. 예외를 throw 하거나 잡아 사용자 메시지를 만들 함께 참조.
4
4
 
5
5
  ## SdError
6
6
 
7
7
  ```ts
8
8
  class SdError extends Error {
9
9
  override cause?: Error;
10
- constructor(cause: Error, ...messages: string[]); // 원인 에러를 감싸기
11
- constructor(...messages: string[]); // 메시지만으로 생성
10
+ constructor(cause: Error, ...messages: string[]);
11
+ constructor(...messages: string[]);
12
12
  }
13
13
  ```
14
14
 
15
- ES2024 `cause` 를 활용한 트리형 에러. 메시지는 **역순으로** `" => "` 로 결합됨(상위 메시지가 앞).
15
+ ES `cause` 를 활용해 트리 형태로 에러를 감싸는 기반 클래스.
16
16
 
17
- - cause: Error — 첫 인자가 Error 면 원인 에러로 보존(`this.cause`). 원인 에러의 stack 현재 stack 뒤에 `---- cause stack ----` 로 이어 붙음. 하위 호출에서 받은 에러를 상위 문맥으로 감쌀 때.
18
- - ...messages: string[] — 문맥 메시지들. `new SdError(err, "API 호출 실패", "사용자 로드 실패")` `"사용자 로드 실패 => API 호출 실패 => 원본 메시지"`. null/undefined 메시지는 제외됨.
19
- - `name` 은 `"SdError"`. V8(Node·Chrome)에서 `captureStackTrace` 로 생성자 프레임 제거.
17
+ - 첫 인자가 `Error`그것을 `cause` 보존하고, `cause.stack` 자기 stack 뒤에 `---- cause stack ----` 로 이어 붙임.
18
+ - 메시지들은 **역순으로 `" => "` 결합** 상위(가장 마지막 인자)부터 하위·원인 순으로 읽힘. null 메시지는 제외.
19
+ - V8(Node/Chrome)에서는 `Error.captureStackTrace` 로 생성자 프레임을 stack 에서 제거.
20
+ - `name` 은 `"SdError"`.
20
21
 
21
22
  ```ts
22
- import { SdError } from "@simplysm/core-common";
23
23
  try {
24
24
  await fetch(url);
25
25
  } catch (err) {
26
- throw new SdError(err, "API 호출 실패", "사용자 로드 실패");
26
+ throw new SdError(err as Error, "API 호출 실패", "사용자 로드 실패");
27
+ // message: "사용자 로드 실패 => API 호출 실패 => <원본 메시지>"
27
28
  }
28
29
  ```
29
30
 
30
- 주의: 첫 인자가 Error 가 아니면(문자열·기타) cause 없이 메시지로만 취급됨. `new SdError("잘못된 상태", "처리 불가")` `"처리 불가 => 잘못된 상태"`.
31
+ 주의: 첫 인자가 `Error` 가 아니면 메시지로 취급되므로, 원인 보존이 목적이면 `Error` 인스턴스를 인자로 넘길 것.
31
32
 
32
33
  ## ArgumentError
33
34
 
@@ -38,19 +39,17 @@ class ArgumentError extends SdError {
38
39
  }
39
40
  ```
40
41
 
41
- 유효하지 않은 인자를 받았을 때 던지는 에러. 디버깅을 위해 인자 객체를 **YAML 형식**으로 메시지에 붙임. `name` 은 `"ArgumentError"`.
42
+ 유효하지 않은 인자에 대한 에러. 디버깅을 위해 인자 객체를 **YAML 직렬화해 메시지에 첨부**.
42
43
 
43
- - argObj: Record<string, unknown> 메시지에 YAML 직렬화해 포함할 인자값들. 어떤 입력이 문제였는지 드러낼 때.
44
- - message: string 커스텀 머리말. 생략 `"잘못된 인자입니다."` 사용.
44
+ - 인자가 객체면 기본 메시지 `"잘못된 인자입니다."` + YAML.
45
+ - 인자가 문자열이면 커스텀 메시지 + 둘째 인자 객체의 YAML.
46
+ - `name` 은 `"ArgumentError"`. 패키지 내부 검증 실패(잘못된 UUID, hex 홀수 길이, 중복 key, 빈 chain 등)에서 광범위하게 throw 됨.
45
47
 
46
48
  ```ts
47
- import { ArgumentError } from "@simplysm/core-common";
48
- throw new ArgumentError("유효하지 않은 UUID 형식입니다.", { uuid });
49
- // 메시지: "유효하지 않은 UUID 형식입니다.\n\nuuid: ..."
49
+ throw new ArgumentError("잘못된 사용자", { userId: 123 });
50
+ // message: "잘못된 사용자\n\nuserId: 123\n"
50
51
  ```
51
52
 
52
- 이 패키지 내부 검증(Uuid·bytes·obj 체인 등)에서 이미 광범위하게 throw 하므로, 유효성 위반은 직접 처리하지 말고 그대로 전파하는 편이 일관적.
53
-
54
53
  ## NotImplementedError
55
54
 
56
55
  ```ts
@@ -59,9 +58,7 @@ class NotImplementedError extends SdError {
59
58
  }
60
59
  ```
61
60
 
62
- 아직 구현되지 않은 기능이 호출됐을 때. 메시지는 `"미구현"` 또는 `"미구현: <message>"`. `name` 은 `"NotImplementedError"`. 추상 메서드 스텁, 미구현 분기에 사용.
63
-
64
- - message?: string — 무엇이 미구현인지 추가 설명. 예: `throw new NotImplementedError(\`타입 ${type} 처리\`)`.
61
+ 미구현 분기·추상 메서드 스텁에서 throw. 메시지는 `"미구현"` 뒤에 `message` 가 있으면 `": " + message` 를 덧붙임. `name` 은 `"NotImplementedError"`.
65
62
 
66
63
  ## TimeoutError
67
64
 
@@ -71,16 +68,17 @@ class TimeoutError extends SdError {
71
68
  }
72
69
  ```
73
70
 
74
- 대기 시간 초과 에러. 메시지는 `"대기 시간 초과"` + (count 있으면 `(N회 시도)`) + (message 있으면 `: <message>`). `name` 은 `"TimeoutError"`.
71
+ 대기 시간 초과 에러. 메시지는 `"대기 시간 초과"` + `count` 있으면 `"(N회 시도)"` + `message` 있으면 `": " + message`. `name` 은 `"TimeoutError"`. `wait.until` 이 최대 시도 횟수 초과 시 자동으로 던지며, `err instanceof TimeoutError` 로 분기 가능.
72
+
73
+ ## err.message
75
74
 
76
- - count?: number 시도 횟수. `wait.until(...)` 이 최대 시도 초과 시 자동으로 이 에러를 throw(시도 횟수를 넣어).
77
- - message?: string — 무엇을 기다리다 초과했는지 추가 설명.
75
+ `import { err } from "@simplysm/core-common"` 네임스페이스.
76
+
77
+ - `message(err: unknown): string` — `unknown` 에러에서 메시지 추출. `Error` 면 `.message`, 아니면 `String(err)`. catch 블록에서 타입 좁히기 없이 메시지를 얻을 때.
78
78
 
79
79
  ```ts
80
- import { TimeoutError, wait } from "@simplysm/core-common";
81
- try {
82
- await wait.until(() => isReady, 100, 50);
83
- } catch (err) {
84
- if (err instanceof TimeoutError) { /* 타임아웃 처리 */ }
80
+ import { err } from "@simplysm/core-common";
81
+ try { /* ... */ } catch (e) {
82
+ toast.danger(err.message(e));
85
83
  }
86
84
  ```
@@ -1,71 +1,70 @@
1
1
  # @simplysm/core-common — obj 네임스페이스
2
2
 
3
- `import { obj } from "@simplysm/core-common"` 로 접근하는 객체 조작 유틸. 깊은 복사/비교/병합, 체인 경로 접근, key 변환을 함께 읽힘. 깊은 연산은 커스텀 값 타입(DateTime·DateOnly·Time·Uuid·Uint8Array)·Date·RegExp·Map·Set·Error 를 인지하고 순환 참조를 처리함.
3
+ `import { obj } from "@simplysm/core-common"`. 깊은 복사·비교·병합과 체인 경로 접근, 타입 안전 Object 헬퍼. 값 타입(`DateTime`/`DateOnly`/`Time`/`Uuid`/`Uint8Array`)·`Date`·`RegExp`·`Map`/`Set`·`Error`인지해 올바르게 다룸. 상태 비교·patch·불변 업데이트가 필요할 때 함께 참조.
4
4
 
5
- ## clone
5
+ ## clone / equal
6
6
 
7
- - `obj.clone(source)`: 동일 타입 — 깊은 복사. 순환 참조 지원. Date/DateTime/DateOnly/Time/Uuid/Uint8Array/RegExp/Array/Map/Set/Error(cause·커스텀 속성 포함) 일반 객체(프로토타입 체인 유지)를 복제.
8
- - 주의: 함수·Symbol 복사 안 되고 참조 유지. WeakMap/WeakSet 미지원(빈 객체화). getter/setter 현재 값으로 평가되어 복사(접근자 자체는 복사 안 됨).
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 는 항상 포함).
9
14
 
10
- ## equal
11
-
12
- - `obj.equal(source, target, options?)`: → boolean — 깊은 동등성 비교. Date/날짜타입(tick)/Uuid(문자열)/RegExp/Array/Map/Set/일반 객체를 인지. null/undefined 인 속성은 비교에서 제외(없는 것으로 취급).
13
-
14
- 옵션(`EqualOptions`):
15
- - topLevelIncludes?: string[] — 비교할 key 화이트리스트(최상위 객체 속성에만 적용). 일부 필드만 같으면 OK 로 볼 때.
16
- - topLevelExcludes?: string[] — 비교에서 뺄 key(최상위만). `updatedAt` 같은 변동 필드 무시할 때.
17
- - ignoreArrayIndex?: boolean — true 면 배열 순서 무시(같은 다중집합인지). O(n²). `[1,2,3]==[3,2,1]`.
18
- - shallow?: boolean — true 면 1단계만 참조 비교. 대용량에서 성능 우선일 때.
19
- - 주의: include/exclude 는 객체 속성 key 에만 적용. Map 의 key 는 항상 전부 비교됨.
15
+ ```ts
16
+ obj.equal(a, b, { topLevelExcludes: ["updatedAt"] }); // updatedAt 제외 비교
17
+ ```
20
18
 
21
19
  ## merge / merge3
22
20
 
23
- - `obj.merge(source, target, opt?)`: `Source & Target` — 깊은 병합(원본 불변, 객체 반환). target 값으로 source 를 덮어쓰되 객체/Map 은 재귀 병합. 날짜타입·Uuid·Uint8Array 는 통째로 교체.
24
- - opt.arrayProcess?: `"replace" | "concat"` — 배열 처리. `"replace"`(기본)=target 배열로 교체, `"concat"`=합치고 Set 으로 중복 제거(객체는 참조 비교).
25
- - opt.useDelTargetNull?: boolean — true 면 target 값이 null 해당 key 결과에서 삭제. 패치에서 "필드 제거"를 표현할 때.
26
- - `obj.merge3(source, origin, target, optionsObj?)`: `{ conflict, result }` — 3-way 병합(공통 조상 origin 기준). source 만 바뀌면 source, target 만 바뀌면 target, 둘 다 같으면 그 값, 셋 다 다르면 conflict=true(origin 유지). optionsObj key 별 비교 옵션(`Merge3KeyOptions`: keys/excludes/ignoreArrayIndex). 동시 편집 충돌 감지에 사용.
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` 비교 옵션 지정.
27
26
 
28
27
  ```ts
29
- import { obj } from "@simplysm/core-common";
30
- const merged = obj.merge(base, patch, { arrayProcess: "concat", useDelTargetNull: true });
31
- const { conflict, result } = obj.merge3(mine, origin, theirs);
28
+ const { conflict, result } = obj.merge3(
29
+ { a: 1, b: 2 }, { a: 1, b: 1 }, { a: 2, b: 1 },
30
+ ); // conflict: false, result: { a: 2, b: 2 }
32
31
  ```
33
32
 
34
- ## omit / pick
33
+ ## pick / omit
35
34
 
36
- - `obj.omit(item, omitKeys)`: → `Omit<T,K>` — 지정 key 제외한 새 객체.
37
- - `obj.omitByFilter(item, omitKeyFn)`: T — `omitKeyFn(key)` 가 true 인 key 제외(예: `_` 로 시작하는 내부 속성).
38
- - `obj.pick(item, pickKeys)`: → `Pick<T,K>` — 지정 key 만 남긴 새 객체.
35
+ - `pick(item, pickKeys): Pick<T, K>` — 지정 key 남긴 새 객체.
36
+ - `omit(item, omitKeys): Omit<T, K>` 지정 key 제외한 객체.
39
37
 
40
38
  ## 체인 경로 접근
41
39
 
42
- 문자열 경로(`"a.b[0].c"`)로 중첩 접근. `?`·`!`·따옴표는 무시됨.
40
+ 문자열 경로(`"a.b[0].c"`)로 중첩 값에 접근. 경로는 `.`/`[` `]` 로 분해하고 숫자 세그먼트는 배열 인덱스로 처리.
43
41
 
44
- - `obj.getChainValue(o, chain)` / `getChainValue(o, chain, true)`: unknown — 경로 값 조회. 세 번째 `true` 중간 null/undefined 를 만나도 에러 없이 undefined.
45
- - `obj.getChainValueByDepth(o, key, depth, optional?)`: → 값 — 같은 key 로 depth 단계 하강(예: `parent` 를 2번). depth<1 이면 ArgumentError. optional 처리는 위와 동일.
46
- - `obj.setChainValue(o, chain, value)`: void — 경로에 값 설정(중간 객체 자동 생성). 빈 chain 이면 ArgumentError.
47
- - `obj.deleteChainValue(o, chain)`: void — 경로 값 삭제(중간 경로 없으면 조용히 반환).
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`.
48
46
 
49
- ## 정리 유틸 (@mutates)
47
+ ## 정리/변환 헬퍼
50
48
 
51
- - `obj.clearUndefined(o)`: T — null/undefined 값 key 원본에서 삭제.
52
- - `obj.clear(o)`: 빈 객체 — 모든 key 삭제.
53
- - `obj.nullToUndefined(o)`: → `T | undefined` — null 을 undefined 로 재귀 변환(순환 안전). 날짜타입·Uuid 통과. simplysm 의 null-free 규칙 적용에 사용.
54
- - `obj.unflatten(flatObj)`: 중첩 객체 — `{ "a.b.c": 1 }` → `{ a: { b: { c: 1 } } }`.
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 } }` 중첩화.
55
53
 
56
- ## 타입 안전 Object.* 와 변환
54
+ ## 타입 안전 Object 헬퍼
57
55
 
58
- - `obj.keys(o)`: → `(keyof T)[]` — 타입 안전 `Object.keys`.
59
- - `obj.entries(o)`: → `Entries<T>` — 타입 안전 `Object.entries`(튜플 타입 보존).
60
- - `obj.fromEntries(entryPairs)`: 객체 — 타입 안전 `Object.fromEntries`.
61
- - `obj.map(o, fn)`: → 새 객체 — 각 엔트리를 `fn(key, value) => [newKey | null, newValue]` 변환. newKey null 이면 기존 key 유지(값만 변환). key+값 동시 변환 가능.
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·값 동시 변환에.
62
60
 
63
61
  ```ts
64
- obj.map(colors, (key, rgb) => [`${key}Light`, `rgb(${rgb})`]);
62
+ obj.map({ primary: "255,0,0" }, (k, rgb) => [null, `rgb(${rgb})`]);
63
+ // { primary: "rgb(255,0,0)" }
65
64
  ```
66
65
 
67
- ## 함께 export 되는 타입 유틸
66
+ ## 타입 유틸리티 (export type)
68
67
 
69
- - `UndefToOptional<T>` `undefined` 포함한 속성을 optional(`?`)로 변환.
70
- - `OptionalToUndef<T>` — optional 속성을 `필수 + undefined` union 으로 변환.
71
- - 옵션 타입: `EqualOptions`·`MergeOptions`·`Merge3KeyOptions`.
68
+ - `EqualOptions` / `MergeOptions` / `Merge3KeyOptions` 함수들의 옵션 타입.
69
+ - `UndefToOptional<TObject>` — `undefined` 포함한 속성을 optional(`?`)로 변환.
70
+ - `OptionalToUndef<TObject>` optional 속성을 필수 + `| undefined` 유니온으로 변환.
@@ -1,55 +1,56 @@
1
- # @simplysm/core-common — 직렬화 / Worker 전송
1
+ # @simplysm/core-common — 직렬화 (json·xml·bytes·transfer)
2
2
 
3
- 커스텀 타입(DateTime·DateOnly·Time·Uuid·Map·Set·Error·Uint8Array 등)을 포함한 데이터를 JSON·XML·바이트·Worker 메시지로 주고받을 때 함께 읽히는 묶음. JSON·transfer 는 `__type__` 태그 방식으로 표준 직렬화가 잃어버리는 타입을 복원함.
3
+ 커스텀 타입을 보존하는 직렬화/역직렬화 묶음. JSON 문자열, XML, hex/base64 바이트, Worker 전송 형태를 다룰 때 함께 참조. `json`·`transfer` 는 `DateTime`/`DateOnly`/`Time`/`Uuid`/`Map`/`Set`/`Error`/`Uint8Array`(transfer `RegExp` 추가)를 `__type__` 태그로 보존·복원.
4
4
 
5
- ## json 네임스페이스
5
+ ## json (`import { json } from "@simplysm/core-common"`)
6
6
 
7
- - `json.stringify(obj, options?)`: string — 커스텀 타입 보존 JSON 직렬화. Date/DateTime/DateOnly/Time/Uuid/Set/Map/Error/Uint8Array 를 `{ __type__, data }` 형태로 변환. 전역 프로토타입을 건드리지 않아 Worker 환경에서도 안전. 순환 참조면 TypeError.
8
- - options.space?: `string | number` — 들여쓰기(숫자=공백 수, 문자열=들여쓰기 문자).
9
- - options.replacer?: `(key, value) => unknown` — 기본 타입 변환 **전에** 호출되는 커스텀 변환.
10
- - options.redactBytes?: boolean — true 면 Uint8Array 내용을 `"__hidden__"` 대체(로깅용). 이 결과는 `json.parse` 로 복원 불가.
11
- - `json.parse<T>(json)`: T `json.stringify` 결과 역직렬화. `__type__` 태그를 보고 원래 타입 복원. **모든 JSON null 은 undefined 변환**됨(null-free 규칙). `redactBytes` 로 가려진 Uint8Array 를 만나면 SdError. 파싱 실패 시 SdError(개발 모드 `env("DEV")` 이면 전체 JSON, 운영이면 길이만 메시지에 포함).
12
- - 주의: 사용자 데이터에 `{ __type__: "Date"|..., data: ... }` 형태가 우연히 들어 있으면 의도치 않게 타입으로 변환될 수 있음.
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, 운영 모드면 길이만 메시지에 포함).
13
13
 
14
14
  ```ts
15
15
  import { json } from "@simplysm/core-common";
16
- const text = json.stringify({ at: new DateTime(), ids: new Set([1, 2]) });
17
- const back = json.parse<{ at: DateTime; ids: Set<number> }>(text); // 타입 복원
16
+ const s = json.stringify({ at: new DateTime(), id: Uuid.generate() });
17
+ const o = json.parse<{ at: DateTime; id: Uuid }>(s); // 타입 복원됨
18
18
  ```
19
19
 
20
- ## transfer 네임스페이스 (Worker 전송)
20
+ ## xml (`import { xml } from "@simplysm/core-common"`)
21
21
 
22
- `structuredClone` 다루는 커스텀 타입을 Worker 보내기 위한 인코딩/디코딩. `postMessage` 의 transferList(zero-copy) 연동.
22
+ `fast-xml-parser` 래퍼. 속성은 `$` 객체, 텍스트 노드는 `_` key, 자식 요소는 배열(루트 제외) 표현.
23
23
 
24
- - `transfer.encode(obj)`: `{ result, transferList }` — 직렬화 가능한 형태로 변환. Uint8Array 의 ArrayBuffer transferList 에 모아 zero-copy 전송 준비(SharedArrayBuffer 제외). Date/DateTime/DateOnly/Time/Uuid/RegExp/Error(cause·code·detail 포함)는 `__type__` 태그로 변환, Array/Map/Set/일반 객체는 재귀. 같은 객체 재참조는 캐시 재사용. **순환 참조면 TypeError(경로 포함)**.
25
- - `transfer.decode(obj)`: unknown Worker 수신 데이터를 커스텀 타입으로 복원(encode 역).
24
+ - `parse(str, options?: { stripTagPrefix?: boolean }): unknown` — XML→객체. `stripTagPrefix` 태그의 네임스페이스 접두사(`ns:tag`)제거(속성 접두사는 유지).
25
+ - `stringify(obj, options?: XmlBuilderOptions): string`객체→XML. `options` fast-xml-parser 빌더 옵션을 그대로 덮어씀.
26
26
 
27
27
  ```ts
28
- import { transfer } from "@simplysm/core-common";
29
- const { result, transferList } = transfer.encode(data);
30
- worker.postMessage(result, transferList);
31
- // worker 측: const decoded = transfer.decode(event.data);
28
+ xml.parse('<root id="1"><item>hello</item></root>');
29
+ // { root: { $: { id: "1" }, item: [{ _: "hello" }] } }
32
30
  ```
33
31
 
34
- json 과의 차이: transfer 는 날짜를 tick(숫자)로 인코딩하고 RegExp 지원하며 Uint8Array 를 변환 없이 transferList 로 넘김(메모리 효율). 문자열 산출물이 필요하면 json, Worker 간 객체 전송이면 transfer.
32
+ ## bytes (`import { bytes } from "@simplysm/core-common"`)
35
33
 
36
- ## bytes 네임스페이스 (Uint8Array 인코딩)
34
+ `Uint8Array`(=`Bytes`) 인코딩 유틸. 모두 자체 구현(브라우저·Node 공용).
37
35
 
38
- - `bytes.concat(arrays)`: Bytes — 여러 Uint8Array 결합.
39
- - `bytes.toHex(b)`: string — 소문자 hex 문자열.
40
- - `bytes.fromHex(hex)`: Bytes — hex(대소문자 허용)→바이트. 홀수 길이·비 hex 문자면 ArgumentError.
41
- - `bytes.toBase64(b)`: string — Base64 인코딩(표준 패딩 `=`).
42
- - `bytes.fromBase64(b64)`: Bytes — Base64 디코딩. 공백·패딩 정규화 base64 문자·잘못된 길이면 ArgumentError.
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`.
43
41
 
44
- ## xml 네임스페이스
42
+ ## transfer (`import { transfer } from "@simplysm/core-common"`)
45
43
 
46
- `fast-xml-parser` 래퍼. 속성은 `$` 객체, 텍스트 노드는 `_` key, 자식 요소는 배열로 표현.
44
+ Worker 간 전송용 직렬화. `structuredClone` 다루는 커스텀 타입을 `__type__` 태그 객체로 변환하되 `Uint8Array` 그대로 두고 `ArrayBuffer` 를 transfer 목록에 담아 zero-copy 전송.
47
45
 
48
- - `xml.parse(str, options?)`: unknown — XML→객체. `options.stripTagPrefix?: boolean` true 태그의 네임스페이스 접두사(`ns:tag`→`tag`) 제거(속성 접두사는 유지).
49
- - `xml.stringify(obj, options?)`: string 객체→XML. options 는 `fast-xml-parser` `XmlBuilderOptions`(선택).
46
+ - `encode(obj): { result: unknown; transferList: ArrayBuffer[] }` 전송 가능한 형태로 인코딩. `result` `postMessage` 본문, `transferList` 전송 목록으로 사용. 순환 참조 시 경로 정보 포함 `TypeError`, 동일 객체 다중 참조는 캐시 재사용(`SharedArrayBuffer` transferList 제외).
47
+ - `decode(obj): unknown`수신측에서 `__type__` 태그를 다시 값 타입으로 복원.
50
48
 
51
49
  ```ts
52
- import { xml } from "@simplysm/core-common";
53
- xml.parse('<root id="1"><item>hello</item></root>');
54
- // { root: { $: { id: "1" }, item: [{ _: "hello" }] } }
50
+ import { transfer } from "@simplysm/core-common";
51
+ const { result, transferList } = transfer.encode(data);
52
+ worker.postMessage(result, transferList);
53
+ // 수신측: const data = transfer.decode(event.data);
55
54
  ```
55
+
56
+ 주의: `json` 은 문자열 직렬화(바이트는 hex 로), `transfer` 는 객체 그대로 전송(바이트는 zero-copy). 두 경로 모두 같은 커스텀 값 타입을 보존하지만 산출물 형태가 다름 — 저장·전송 매체에 맞게 선택.
@@ -0,0 +1,86 @@
1
+ # @simplysm/core-common — 날짜·시간 값 타입
2
+
3
+ 불변(immutable) 날짜/시간/식별자 값 타입 `DateTime`·`DateOnly`·`Time`·`Uuid`. 모두 set/add 계열이 **새 인스턴스를 반환**하며 로컬 타임존 기준으로 동작. ORM 컬럼·폼 입력·직렬화 전반에서 함께 다뤄짐.
4
+
5
+ ## DateTime
6
+
7
+ 밀리초 정밀도 날짜+시간. 내부에 `readonly date: Date` 보유.
8
+
9
+ 생성자:
10
+ - `new DateTime()` — 현재 시각.
11
+ - `new DateTime(year, month, day, hour?, minute?, second?, millisecond?)` — month 는 1-12(내부에서 0-기준 변환). 시·분·초·밀리초 생략 시 0.
12
+ - `new DateTime(tick: number)` — epoch 밀리초.
13
+ - `new DateTime(date: Date)` — Date 복제.
14
+
15
+ `static parse(str): DateTime` — 다음 형식 인식, 실패 시 `ArgumentError`: `yyyy-MM-dd HH:mm:ss(.fff)`, `yyyyMMddHHmmss`, `yyyy-MM-dd AM/PM HH:mm:ss`, `yyyy-MM-dd 오전/오후 HH:mm:ss`, ISO 8601(`Date.parse` 경유).
16
+
17
+ 게터(읽기 전용):
18
+ - `year/month/day/hour/minute/second/millisecond` — 각 구성요소(month 는 1-12).
19
+ - `tick` — epoch 밀리초.
20
+ - `dayOfWeek` — 요일(일=0 ~ 토=6).
21
+ - `timezoneOffsetMinutes` — 로컬 오프셋(분, KST=+540).
22
+ - `isValid` — 내부 Date 가 유효하면 true.
23
+
24
+ 불변 변환(새 인스턴스):
25
+ - `setYear/setMonth/setDay/setHour/setMinute/setSecond/setMillisecond(n)` — 해당 구성요소만 교체. `setYear`/`setMonth` 는 대상 월 일수를 넘으면 말일로 보정, `setDay` 는 JS Date 규칙대로 월 넘김.
26
+ - `addYears/addMonths/addDays/addHours/addMinutes/addSeconds/addMilliseconds(n)` — 더하기(연/월/일은 set 경유 보정, 시 이하는 tick 가산).
27
+ - `toFormatString(formatStr)` — C# 스타일 토큰 포맷(`dt.format` 위임, 토큰 목록은 README dt 섹션 참조).
28
+ - `toString()` — `"yyyy-MM-ddTHH:mm:ss.fffzzz"`.
29
+
30
+ ```ts
31
+ const dt = DateTime.parse("2025-01-15 10:30:00");
32
+ dt.addDays(1).toFormatString("yyyy-MM-dd"); // "2025-01-16"
33
+ ```
34
+
35
+ ## DateOnly
36
+
37
+ 시간 없는 날짜(`yyyy-MM-dd`). `readonly date: Date`(시각 0).
38
+
39
+ 생성자: `new DateOnly()`(오늘), `(year, month, day)`, `(tick)`, `(date)` — 모두 시각을 0 으로 정규화.
40
+
41
+ `static parse(str)` — `yyyy-MM-dd`·`yyyyMMdd` 는 타임존 무관하게 문자열에서 직접 추출, ISO 8601 은 UTC 해석 후 로컬로 변환(DST 지역은 대상 날짜 오프셋 사용). 실패 시 `ArgumentError`. 서버/클라이언트 타임존이 다르면 `yyyy-MM-dd` 권장.
42
+
43
+ 게터: `isValid`, `year/month/day`, `tick`, `dayOfWeek`.
44
+
45
+ 불변 변환: `setYear/setMonth/setDay`, `addYears/addMonths/addDays`(DateTime 과 동일 보정 규칙), `toFormatString`, `toString()`(`"yyyy-MM-dd"`).
46
+
47
+ 주차 계산(ISO 8601 기본: 월요일 시작, 첫 주 최소 4일). 공통 옵션: `weekStartDay`(0=일~6=토, 기본 1), `minDaysInFirstWeek`(1-7, 기본 4):
48
+ - `getBaseYearMonthSeqForWeekSeq(weekStartDay?, minDaysInFirstWeek?): { year; monthSeq }` — 이 날짜가 속한 주의 기준 연·월.
49
+ - `getWeekSeqStartDate(weekStartDay?, minDaysInFirstWeek?): DateOnly` — 속한 주의 시작 날짜.
50
+ - `getWeekSeqOfYear(weekStartDay?, minDaysInFirstWeek?): { year; weekSeq }` — 연 기준 주차.
51
+ - `getWeekSeqOfMonth(weekStartDay?, minDaysInFirstWeek?): { year; monthSeq; weekSeq }` — 월 기준 주차.
52
+ - `static getDateByYearWeekSeq(arg: { year; month?; weekSeq }, weekStartDay?, minDaysInFirstWeek?): DateOnly` — 연(+선택 월)·주차로 그 주 시작 날짜 역산.
53
+
54
+ ```ts
55
+ new DateOnly(2025, 1, 6).getWeekSeqOfYear(); // { year: 2025, weekSeq: 2 }
56
+ DateOnly.getDateByYearWeekSeq({ year: 2025, weekSeq: 2 }); // 2025-01-06
57
+ ```
58
+
59
+ ## Time
60
+
61
+ 날짜 없는 시간(`HH:mm:ss.fff`). 내부 tick 은 0 이상 하루 미만으로 정규화(24h 순환, 음수는 양수로 보정).
62
+
63
+ 생성자: `new Time()`(현재 시각의 시간부), `(hour, minute, second?, millisecond?)`, `(tick)`, `(date)`(Date 의 시간부만).
64
+
65
+ `static parse(str)` — `HH:mm:ss(.fff)`, `AM/PM HH:mm:ss`, ISO 8601 의 시간부. 실패 시 `ArgumentError`.
66
+
67
+ 게터: `hour/minute/second/millisecond`, `tick`, `isValid`.
68
+
69
+ 불변 변환: `setHour/setMinute/setSecond/setMillisecond`, `addHours/addMinutes/addSeconds/addMilliseconds`(모두 24시간 순환), `toFormatString`, `toString()`(`"HH:mm:ss.fff"`).
70
+
71
+ ## Uuid
72
+
73
+ UUID v4 래퍼. 내부에 정규화된 문자열 보유. `crypto.getRandomValues` 기반 난수.
74
+
75
+ - `static generate(): Uuid` — 암호학적으로 안전한 새 v4.
76
+ - `static fromBytes(bytes: Bytes): Uuid` — 16바이트 배열에서 생성. 길이가 16 아니면 `ArgumentError`.
77
+ - `new Uuid(uuid: string)` — `8-4-4-4-12` 형식 검증, 불일치 시 `ArgumentError`.
78
+ - `toString(): string` — 표준 문자열.
79
+ - `toBytes(): Bytes` — 16바이트 `Uint8Array`.
80
+
81
+ ```ts
82
+ const id = Uuid.generate();
83
+ id.toString(); // "550e8400-e29b-41d4-a716-446655440000" 형태
84
+ ```
85
+
86
+ 주의: 모든 값 타입은 불변이므로 `set/add` 결과를 변수에 다시 받아야 함. `obj.clone`/`obj.equal`/`json` 직렬화가 이들 타입을 인지해 tick/문자열 기준으로 복제·비교·복원함.
@@ -1,16 +1,16 @@
1
1
  # @simplysm/core-node
2
2
 
3
- Node.js 런타임 전용 유틸·기능 모음. `@simplysm/core-common` 위에 Node API(`fs`/`path`/`child_process`/`worker_threads`/`chokidar`/`consola`)를 얹은 계층이므로 브라우저에서는 사용 불가.
3
+ Node 전용 기반 유틸·기능 모음. `@simplysm/core-common` 위에 Node API(`fs`/`path`/`child_process`/`worker_threads`/`chokidar`/`consola`)를 얹은 계층이라 브라우저에서는 사용 불가.
4
4
 
5
5
  `cpx`/`fsx`/`pathx` 는 `export * as` 네임스페이스로 노출되므로 항상 접두사로 호출한다 (`import { fsx } from "@simplysm/core-node"` → `fsx.read(...)`). 나머지(FsWatcher, consola 셋업, worker)는 named export.
6
6
 
7
7
  ## 사용 트리거 인덱스
8
8
 
9
- - **fsx** — 파일/디렉토리 존재 확인·생성·삭제·복사·읽기/쓰기(텍스트·바이너리·JSON)·stat·glob·부모 탐색을 동기/비동기 쌍으로 다룰 때. 모든 오류를 `SdError(원인, 경로)` 로 감싸 throw. 자세히: [fsx.md](./fsx.md)
10
- - **pathx** — 경로를 POSIX(슬래시)로 정규화하거나, 하위경로 판정·디렉토리 치환·확장자 제거 basename·타겟 필터링 같은 경로 문자열 가공이 필요할 때. 자세히: [pathx.md](./pathx.md)
11
- - **cpx** — 외부 명령을 실행해 stdout/stderr 를 OS 인코딩으로 디코딩해 받을 때(`spawn`/`spawnSync`), 또는 OS 코드페이지 인코딩 감지가 필요할 때. exitCode≠0 자동 throw. 자세히: [cpx.md](./cpx.md)
9
+ - **fsx** — 파일/디렉토리 존재 확인·생성·삭제·복사·읽기/쓰기(텍스트·바이너리·JSON)·stat·glob·빈 디렉토리 정리·부모 방향 탐색을 동기/비동기 쌍으로 다룰 때. 실패는 모두 `SdError(원인, 경로)` 로 감싸 throw. 자세히: [fsx.md](./fsx.md)
10
+ - **pathx** — 경로를 POSIX(슬래시)로 정규화(`PosixPath` 브랜드)하거나, 하위 경로 판정·디렉토리 치환·확장자 제거 basename·타겟 필터링 같은 경로 문자열 가공이 필요할 때. 자세히: [pathx.md](./pathx.md)
11
+ - **cpx** — 외부 명령을 자식 프로세스로 실행해(`spawn`/`spawnSync`) stdout/stderr OS 인코딩(Windows 코드페이지·POSIX LANG)으로 디코딩해 받을 때. exitCode≠0 자동 throw. 자세히: [cpx.md](./cpx.md)
12
12
  - **FsWatcher / FsWatcherEvent / FsWatcherChangeInfo** — glob 경로를 chokidar 로 감시하며 짧은 시간 내 이벤트를 병합해 콜백 한 번으로 받을 때(watch 빌드 등). 자세히: [fs-watcher.md](./fs-watcher.md)
13
13
  - **setupConsola / PrettyReporter / createFileReporter / FileReporterOptions / SetupConsolaOptions / withMaxLevel** — Node 진입점(서버·CLI)에서 consola 전역 로거의 콘솔/파일 출력 형식을 환경별로 1회 셋업하거나 reporter 를 커스텀할 때. 자세히: [consola.md](./consola.md)
14
- - **Worker / createWorker / WorkerProxy / WorkerModule / PromisifyMethods / WorkerRequest / WorkerResponse** — worker_threads 를 타입 안전한 메서드 호출·이벤트·로그 전달 프록시로 쓸 때. 자세히: [worker.md](./worker.md)
14
+ - **Worker / createWorker / WorkerProxy / WorkerModule / PromisifyMethods / WorkerRequest / WorkerResponse** — worker_threads 를 타입 안전한 메서드 호출·이벤트·로그 전달 프록시로 쓸 때. 워커 측은 `createWorker`, 메인 측은 `Worker.create`. 자세히: [worker.md](./worker.md)
15
15
 
16
- 위 6개 군은 사용 시점·컨텍스트가 분리되어 각각 별도 `.md` 로 분할됨. README 인라인 군 없음.
16
+ 위 6개 군은 사용 시점·컨텍스트가 분리되고 시그니처 분량이 커 각각 별도 `.md` 로 분할됨. README 인라인 군 없음.
@@ -45,4 +45,7 @@ consola.options.reporters = [createFileReporter({ maxSize: 5 * 1024 * 1024, maxD
45
45
  ## FileReporterOptions / SetupConsolaOptions
46
46
 
47
47
  - `interface FileReporterOptions { maxSize?: number; maxDays?: number }` — 위 createFileReporter 옵션 타입.
48
+ - `maxSize?: number` — 로그 파일 1개의 최대 바이트(기본 20MB). 초과 시 seq 파일로 분할.
49
+ - `maxDays?: number` — 로그 보관 일수(기본 14). 초과 날짜 파일 삭제.
48
50
  - `interface SetupConsolaOptions { cli?: boolean }` — 위 setupConsola 옵션 타입.
51
+ - `cli?: boolean` — CLI 모드 여부. true 면 prod 라도 콘솔 출력 경로 사용.
@@ -30,10 +30,10 @@ if (r.exitCode !== 0) { /* 직접 처리 */ }
30
30
 
31
31
  ## SpawnProcess
32
32
 
33
- `spawn` 반환 타입. Promise 처럼 쓰면서 프로세스 제어를 함께 제공.
33
+ `spawn` 반환 타입. Promise 처럼 쓰면서 프로세스 제어를 함께 제공(`implements PromiseLike<SpawnResult>`).
34
34
 
35
35
  - `pid: number | undefined` — 자식 프로세스 PID(생성 전이면 undefined).
36
- - `then(...)` / `catch(...)` — `SpawnResult` 로 resolve 되는 thenable(그래서 `await` 가능).
36
+ - `then(onfulfilled?, onrejected?)` / `catch(onrejected?)` — `SpawnResult` 로 resolve 되는 thenable(그래서 `await` 가능).
37
37
  - `kill(signal?: NodeJS.Signals | number): boolean` — 프로세스에 시그널 전송. 타임아웃·취소 시 사용.
38
38
 
39
39
  ```ts
@@ -5,7 +5,7 @@ chokidar 기반 파일 감시 래퍼 (`packages/core-node/src/features/fs-watche
5
5
  ## FsWatcher.watch (정적 진입점)
6
6
 
7
7
  - `static watch(paths: string[], options?: chokidar.ChokidarOptions): Promise<FsWatcher>` — 감시 시작. ready 될 때까지 대기 후 인스턴스 반환. ready 전 에러 시 watcher 를 close 하고 throw.
8
- - `paths: string[]` — 감시할 경로/glob 패턴 배열. 내부적으로 각 패턴의 glob 메타문자 이전 base 디렉토리를 추출해 chokidar 에 등록하고, 콜백 단계에서 원본 패턴으로 minimatch 재필터(패턴 자체 + `패턴/**` 양쪽 매칭).
8
+ - `paths: string[]` — 감시할 경로/glob 패턴 배열. 내부적으로 각 패턴의 glob 메타문자 이전 base 디렉토리를 추출해 chokidar 에 등록하고, 콜백 단계에서 원본 패턴으로 minimatch 재필터(패턴 자체 + `패턴/**` 양쪽을 `dot: true` 로 매칭).
9
9
  - `options?: ChokidarOptions` — chokidar 옵션. `persistent` 기본 true. `ignoreInitial` 은 chokidar 에는 내부적으로 항상 true 로 강제(초기 스캔 이벤트 무시).
10
10
  - `options.ignoreInitial: false` 지정 시 → `onChange` 의 첫 콜백이 **빈 배열 `[]`** 로 1회 호출됨(실제 초기 파일 목록은 담기지 않음 — 이벤트 병합과의 충돌 방지). "초기 1회 전체 빌드 후 변경 감시" 패턴 트리거용.
11
11
 
@@ -22,13 +22,13 @@
22
22
  - `sourcePath: string` — 원본. **존재하지 않으면 아무 것도 안 하고 반환**(throw 안 함).
23
23
  - `targetPath: string` — 대상. 원본이 디렉토리면 대상 디렉토리를 만들고 하위를 재귀 복사(glob `*`, `dot: true` 로 숨김 포함), 파일이면 상위 디렉토리 생성 후 복사.
24
24
  - `filter?: (absolutePath: string) => boolean` — 복사 여부 결정. 각 하위 항목의 **절대 경로**가 전달되며 true=복사, false=제외. **최상위 sourcePath 자신은 필터 대상 아님**. 디렉토리에 false 면 그 디렉토리와 모든 내용을 건너뜀. 빌드 산출물 중 특정 파일만 복사할 때 사용.
25
- - 파일 복사 실패 시 500ms 대기(sync 는 busy-wait, async 는 setTimeout)로 최대 7회 시도 후에도 실패하면 `SdError`.
25
+ - 파일 복사 실패 시 500ms 대기(sync 는 busy-wait, async 는 setTimeout)로 최대 7회(i=0..6) 시도 후에도 실패하면 `SdError`.
26
26
 
27
27
  ## 읽기
28
28
 
29
29
  - `readSync(targetPath: string): string` / `read(...): Promise<string>` — UTF-8 문자열로 읽음.
30
30
  - `readBytesSync(targetPath: string): Uint8Array` / `readBytes(...): Promise<Uint8Array>` — 바이너리(`Uint8Array`)로 읽음.
31
- - `readJsonSync<TData = unknown>(targetPath): TData` / `readJson<TData = unknown>(...): Promise<TData>` — 읽어 `json.parse`(`@simplysm/core-common`, Date 등 특수타입 복원)로 파싱. 파싱 실패 시 SdError 메시지에 내용 앞 500자 프리뷰를 첨부.
31
+ - `readJsonSync<TData = unknown>(targetPath): TData` / `readJson<TData = unknown>(...): Promise<TData>` — 읽어 `json.parse`(`@simplysm/core-common`, Date 등 특수타입 복원)로 파싱. 파싱 실패 시 SdError 메시지에 내용 앞 500자 프리뷰(+`...(truncated)`)를 첨부.
32
32
  - 제네릭 `TData` — 파싱 결과 타입. 호출부에서 기대 타입을 지정해 반환 타입을 좁힘.
33
33
 
34
34
  ## 쓰기