@simplysm/sd-claude 14.0.76 → 14.0.77
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.
- package/claude/output-styles/sd-tone.md +128 -0
- package/claude/references/sd-simplysm14/apis/angular/README.md +28 -89
- package/claude/references/sd-simplysm14/apis/angular/app-structure.md +75 -32
- package/claude/references/sd-simplysm14/apis/angular/buttons.md +65 -29
- package/claude/references/sd-simplysm14/apis/angular/crud.md +86 -21
- package/claude/references/sd-simplysm14/apis/angular/forms.md +168 -42
- package/claude/references/sd-simplysm14/apis/angular/infrastructure.md +200 -49
- package/claude/references/sd-simplysm14/apis/angular/kanban.md +64 -20
- package/claude/references/sd-simplysm14/apis/angular/layout.md +75 -30
- package/claude/references/sd-simplysm14/apis/angular/modal.md +92 -40
- package/claude/references/sd-simplysm14/apis/angular/routing.md +86 -25
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +72 -41
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +113 -21
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +108 -33
- package/claude/references/sd-simplysm14/apis/angular/toast.md +81 -30
- package/claude/references/sd-simplysm14/apis/angular/visual.md +140 -32
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +46 -43
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +59 -48
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +17 -7
- package/claude/references/sd-simplysm14/apis/core-common/README.md +43 -116
- package/claude/references/sd-simplysm14/apis/core-common/extensions.md +74 -109
- package/claude/references/sd-simplysm14/apis/core-common/features.md +40 -35
- package/claude/references/sd-simplysm14/apis/core-common/types.md +80 -106
- package/claude/references/sd-simplysm14/apis/core-common/utils.md +142 -111
- package/claude/references/sd-simplysm14/apis/core-node/README.md +7 -16
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +33 -38
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +25 -33
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +27 -38
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +32 -60
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +14 -45
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +35 -81
- package/claude/references/sd-simplysm14/apis/excel/README.md +178 -80
- package/claude/references/sd-simplysm14/apis/lint/README.md +5 -0
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +1 -1
- package/claude/references/sd-simplysm14/apis/sd-claude/README.md +28 -5
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +1 -1
- package/claude/references/sd-simplysm14/apis/service-client/README.md +57 -50
- package/claude/references/sd-simplysm14/apis/service-server/README.md +8 -15
- package/claude/references/sd-simplysm14/apis/service-server/auth.md +24 -16
- package/claude/references/sd-simplysm14/apis/service-server/builtin-services.md +55 -31
- package/claude/references/sd-simplysm14/apis/service-server/define-service.md +28 -44
- package/claude/references/sd-simplysm14/apis/service-server/internals.md +59 -18
- package/claude/references/sd-simplysm14/apis/service-server/server.md +37 -46
- package/claude/references/sd-simplysm14/manuals/client-component.md +3 -1
- package/claude/references/sd-simplysm14/manuals/logging.md +9 -8
- package/claude/rules/sd-base-rules.md +380 -219
- package/claude/settings.json +1 -0
- package/claude/skills/sd-commit/SKILL.md +31 -8
- package/claude/skills/sd-docs/SKILL.md +15 -10
- package/claude/skills/sd-docs/references/subagent-prompt.md +26 -8
- package/claude/skills/sd-impl/SKILL.md +1 -1
- package/claude/skills/sd-skill/references/skill-authoring.md +1 -1
- package/claude/skills/sd-spec/SKILL.md +22 -13
- package/claude/skills/sd-spec/references/spec-authoring.md +1 -1
- package/claude/skills/sd-unpack/SKILL.md +150 -26
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/_common.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/eml_handler.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/office_com.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/pdf_handler.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/_common.py +17 -2
- package/claude/skills/sd-unpack/scripts/handlers/eml_handler.py +100 -24
- package/claude/skills/sd-unpack/scripts/handlers/msg_handler.py +140 -27
- package/claude/skills/sd-unpack/scripts/handlers/office_com.py +698 -107
- package/claude/skills/sd-unpack/scripts/handlers/office_worker.py +34 -26
- package/claude/skills/sd-unpack/scripts/handlers/pdf_handler.py +130 -8
- package/package.json +1 -1
|
@@ -1,123 +1,88 @@
|
|
|
1
1
|
# @simplysm/core-common — extensions
|
|
2
2
|
|
|
3
|
-
`
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
3
|
+
`@simplysm/core-common` import 시 자동 적용. 글로벌 `Array`/`ReadonlyArray`/`Map`/`Set` 인터페이스에 ambient declare.
|
|
4
|
+
|
|
5
|
+
## ReadonlyArray<T> (비파괴)
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
single(predicate?): T | undefined // 0~1개만 통과. 2개+ → ArgumentError
|
|
9
|
+
first(predicate?): T | undefined // 첫 요소 (predicate 시 find와 동일)
|
|
10
|
+
last(predicate?): T | undefined // 마지막 요소
|
|
11
|
+
filterAsync(predicate: async): Promise<T[]> // 비동기 필터 (순차)
|
|
12
|
+
filterExists(): NonNullable<T>[] // null/undefined 제거 + 타입 좁힘
|
|
13
|
+
ofType(type: PrimitiveTypeStr | Type<N>): N[] // 원시 타입명 또는 생성자로 필터
|
|
14
|
+
mapAsync(selector: async): Promise<R[]> // 비동기 매핑 (순차)
|
|
15
|
+
mapMany(selector?): R[] // flat + filterExists
|
|
16
|
+
mapManyAsync(selector?: async): Promise<R[]>
|
|
17
|
+
parallelAsync(fn: async): Promise<R[]> // Promise.all (하나 reject 시 전체 reject)
|
|
18
|
+
|
|
19
|
+
groupBy(keySelector, valueSelector?): { key, values }[]
|
|
20
|
+
// 원시 key: O(n) Map 최적화. 객체 key: equal() 비교로 O(n²)
|
|
21
|
+
toMap(keySelector, valueSelector?): Map<K, V> // 중복 key → ArgumentError
|
|
22
|
+
toMapAsync(keySelector: async, valueSelector?: async): Promise<Map>
|
|
23
|
+
toArrayMap(keySelector, valueSelector?): Map<K, V[]> // 중복 허용, array로 누적 (O(n))
|
|
24
|
+
toSetMap(keySelector, valueSelector?): Map<K, Set<V>>
|
|
25
|
+
toMapValues(keySelector, valueSelector(items)): Map<K, V> // value는 그룹 전체로 계산
|
|
26
|
+
toObject(keySelector: → string, valueSelector?): Record<string, V>
|
|
27
|
+
toTree(keyProp, parentKey): TreeArray<T>[] // 평면 → 트리 (parentKey null이면 root)
|
|
28
|
+
|
|
29
|
+
distinct(options?: bool | { matchAddress?, keyFn? }): T[]
|
|
30
|
+
// matchAddress=true: Set 참조 비교. keyFn: 커스텀 키 O(n). 둘 다 없이 객체: O(n²) equal
|
|
31
|
+
orderBy(selector?): T[] // 오름차순 (불변, 새 array)
|
|
32
|
+
orderByDesc(selector?): T[]
|
|
33
|
+
|
|
34
|
+
diffs(target, options?: { keys?, excludes? }): ArrayDiffsResult<T, P>[]
|
|
35
|
+
// 전체 일치 우선, 없으면 keys 일치(update 후보). 결과: INSERT|DELETE|UPDATE
|
|
36
|
+
oneWayDiffs(orgItems: T[] | Map<TKey, T>, keyPropNameOrGetValFn, options?):
|
|
37
|
+
ArrayOneWayDiffResult<T>[] // type: 'create'|'update'|'same'
|
|
38
|
+
merge(target, options?): (T | P | T&P)[] // diffs 후 update는 obj.merge, insert는 append
|
|
39
|
+
|
|
40
|
+
sum(selector?): number // 숫자 아니면 ArgumentError
|
|
41
|
+
min(selector?): number | string | undefined // 숫자/문자열만
|
|
42
|
+
max(selector?): number | string | undefined
|
|
43
|
+
shuffle(): T[] // Fisher-Yates, 새 array
|
|
32
44
|
```
|
|
33
45
|
|
|
34
|
-
|
|
46
|
+
## Array<T> (파괴, @mutates)
|
|
35
47
|
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
arr.toObject(strKeyFn[, valFn]) // 중복 key 시 ArgumentError
|
|
45
|
-
arr.toTree("id", "parentId") // 평면 → 트리 ({...item, children: []}), O(n).
|
|
46
|
-
// parentKey 가 null/undefined 면 루트.
|
|
48
|
+
```ts
|
|
49
|
+
distinctThis(options?) // distinct를 in-place로
|
|
50
|
+
orderByThis(selector?) // Array.prototype.sort 위임 (in-place)
|
|
51
|
+
orderByDescThis(selector?)
|
|
52
|
+
insert(index, ...items) // splice 삽입, this 반환
|
|
53
|
+
remove(item | selector) // 역순 순회 splice 제거
|
|
54
|
+
toggle(item) // 있으면 remove, 없으면 push
|
|
55
|
+
clear() // 전체 비우기
|
|
47
56
|
```
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
## 익스포트 타입
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
type ArrayDiffsResult<TOrig, TOther> =
|
|
62
|
+
| { source: undefined; target: TOther } // INSERT
|
|
63
|
+
| { source: TOrig; target: undefined } // DELETE
|
|
64
|
+
| { source: TOrig; target: TOther } // UPDATE
|
|
65
|
+
type ArrayOneWayDiffResult<T> =
|
|
66
|
+
| { type: 'create'; item: T; orgItem: undefined }
|
|
67
|
+
| { type: 'update'; item: T; orgItem: T }
|
|
68
|
+
| { type: 'same'; item: T; orgItem: T }
|
|
69
|
+
type TreeArray<TNode> = TNode & { children: TreeArray<TNode>[] }
|
|
70
|
+
type ComparableType = string | number | boolean | DateTime | DateOnly | Time | undefined
|
|
58
71
|
```
|
|
59
72
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
63
|
-
arr.diffs(target) // INSERT/DELETE/UPDATE 결과
|
|
64
|
-
arr.diffs(target, { keys: ["id"], excludes? }) // key 기반 매칭 (Map 인덱싱 O(n+m))
|
|
65
|
-
arr.diffs(target, { excludes: [...] })
|
|
66
|
-
// 결과 타입:
|
|
67
|
-
// { source: undefined, target: T } // INSERT
|
|
68
|
-
// { source: T, target: undefined } // DELETE
|
|
69
|
-
// { source: T, target: T } // UPDATE
|
|
73
|
+
## Map<K, V>
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
arr.merge(target[, { keys?, excludes? }]) // diffs 후 source 기반에 target 병합·신규 push
|
|
75
|
+
```ts
|
|
76
|
+
getOrCreate(key, newValue: V): V
|
|
77
|
+
getOrCreate(key, newValueFn: () => V): V // 함수면 팩토리로 호출하여 lazy 생성
|
|
78
|
+
update(key, updateFn: (v: V | undefined) => V): void // key 없어도 fn 호출
|
|
77
79
|
```
|
|
80
|
+
- **주의**: `Map<K, () => void>` 같이 V가 함수 타입이면 두 번째 인자가 팩토리로 인식됨. 함수 값을 저장하려면 `getOrCreate(k, () => myFn)`.
|
|
78
81
|
|
|
79
|
-
|
|
82
|
+
## Set<T>
|
|
80
83
|
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
```ts
|
|
85
|
+
adds(...values: T[]): this // 다중 add
|
|
86
|
+
toggle(value, addOrDel?: "add" | "del"): this
|
|
87
|
+
// 인자 없으면 자동 토글, "add"=강제 추가, "del"=강제 삭제
|
|
84
88
|
```
|
|
85
|
-
|
|
86
|
-
### TreeArray 타입
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
type TreeArray<T> = T & { children: TreeArray<T>[] };
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Array (Mutable — 원본 변경, `@mutates`)
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
arr.distinctThis(options?) // 원본에서 중복 제거 (역순 splice, O(n))
|
|
96
|
-
arr.orderByThis(selector?) / orderByDescThis(selector?)
|
|
97
|
-
arr.insert(index, ...items)
|
|
98
|
-
arr.remove(itemOrSelector) // 일치 항목 모두 제거. 역순 순회.
|
|
99
|
-
arr.toggle(item) // 있으면 remove, 없으면 push
|
|
100
|
-
arr.clear()
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
모두 `this` 반환 (체이닝 가능, `clear/distinctThis/orderBy*This` 는 변경된 자기 자신).
|
|
104
|
-
|
|
105
|
-
## Set
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
set.adds(...values) // 다중 add, this 반환
|
|
109
|
-
set.toggle(value) // 자동 토글
|
|
110
|
-
set.toggle(value, "add" | "del") // 강제 추가/제거
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Map
|
|
114
|
-
|
|
115
|
-
```typescript
|
|
116
|
-
map.getOrCreate(key, defaultValue) // 없으면 set 후 반환
|
|
117
|
-
map.getOrCreate(key, () => expensiveCompute()) // 팩토리 (값이 함수이면 항상 호출됨 — 함수 값을 저장하려면 `() => fn` 으로 한 번 더 감쌀 것)
|
|
118
|
-
map.update(key, (v|undefined) => newV) // 없는 key 도 호출됨 (카운터·배열 push 패턴)
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
## ComparableType
|
|
122
|
-
|
|
123
|
-
`orderBy*` 의 selector 반환 타입: `string | number | boolean | DateTime | DateOnly | Time | undefined`.
|
|
@@ -1,46 +1,51 @@
|
|
|
1
1
|
# @simplysm/core-common — features
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
3
|
+
## EventEmitter<TEvents>
|
|
4
|
+
|
|
5
|
+
EventTarget 기반의 타입 안전 이벤트 이미터. 브라우저·Node 공통.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
class EventEmitter<TEvents extends { [K in keyof TEvents]: unknown } = Record<string, unknown>> {
|
|
9
|
+
on<E extends keyof TEvents & string>(type: E, listener: (data: TEvents[E]) => void): void
|
|
10
|
+
off<E>(type: E, listener: ...): void
|
|
11
|
+
emit<E>(type: E, ...args: TEvents[E] extends void ? [] : [data: TEvents[E]]): void
|
|
12
|
+
listenerCount(type): number
|
|
13
|
+
dispose(): void // 모든 리스너 제거
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
- `TEvents`: `{ eventName: dataType }` 맵. `void` 타입이면 `emit("done")` 인자 생략.
|
|
17
|
+
- 같은 `(type, listener)` 쌍 중복 등록 시 무시.
|
|
18
|
+
- 내부적으로 `CustomEvent.detail`로 데이터 전송. listener는 wrapper로 감싸져 등록되며, listenerMap이 원본 ↔ wrapper 매핑 보관.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
interface MyEvents { data: string; done: void }
|
|
22
|
+
class M extends EventEmitter<MyEvents> {}
|
|
23
|
+
const m = new M();
|
|
24
|
+
m.on("data", s => ...);
|
|
25
|
+
m.emit("data", "hi");
|
|
26
|
+
m.emit("done");
|
|
20
27
|
```
|
|
21
28
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
## DebounceQueue extends EventEmitter\<{ error: SdError }\>
|
|
29
|
+
## DebounceQueue extends EventEmitter<{ error: SdError }>
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
마지막 요청만 실행. 짧은 시간 내 다중 호출 → 마지막 1건만 처리.
|
|
27
32
|
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
q.dispose(); // 타이머·대기 함수 정리
|
|
33
|
+
```ts
|
|
34
|
+
new DebounceQueue(delay?: number) // ms. 생략 시 다음 이벤트 루프 (setTimeout(_, undefined))
|
|
35
|
+
run(fn: () => void | Promise<void>): void
|
|
36
|
+
dispose(): void // 타이머·pending 정리
|
|
33
37
|
```
|
|
38
|
+
- `delay` ms 지난 뒤 가장 최근 `fn` 실행. 실행 중 도착한 추가 `run()`은 디바운스 지연 없이 현재 실행 직후 즉시 처리 (요청 누락 방지).
|
|
39
|
+
- fn throw 시 `SdError`로 감싸 `"error"` 이벤트 발행. 리스너 없으면 `consola` 로그.
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
## SerialQueue extends EventEmitter\<{ error: SdError }\>
|
|
41
|
+
## SerialQueue extends EventEmitter<{ error: SdError }>
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
큐에 추가된 함수들을 순차 실행.
|
|
40
44
|
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
q.dispose(); // 대기 큐 비움 (현재 작업은 완료됨)
|
|
45
|
+
```ts
|
|
46
|
+
new SerialQueue(gap: number = 0) // 각 작업 사이 ms 간격
|
|
47
|
+
run(fn: () => void | Promise<void>): void
|
|
48
|
+
dispose(): void // 대기 큐 비우기 (실행 중은 완료됨)
|
|
46
49
|
```
|
|
50
|
+
- 하나 완료 후 다음 시작. 에러 발생해도 후속 작업 계속 실행. throw는 `SdError` 감싸서 `"error"` 이벤트 (리스너 없으면 `consola.error`).
|
|
51
|
+
- `gap>0` 이면 작업 간 `wait.time(gap)` 대기.
|
|
@@ -1,114 +1,88 @@
|
|
|
1
1
|
# @simplysm/core-common — types
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## DateTime (불변)
|
|
6
|
-
|
|
7
|
-
밀리초 정밀도, 로컬 타임존. 모든 변환/산술 메서드는 새 인스턴스 반환.
|
|
3
|
+
## Uuid
|
|
8
4
|
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
```ts
|
|
6
|
+
class Uuid {
|
|
7
|
+
static generate(): Uuid // crypto.getRandomValues 기반 UUID v4
|
|
8
|
+
static fromBytes(bytes: Bytes): Uuid // 16바이트 Uint8Array → Uuid (길이≠16이면 ArgumentError)
|
|
9
|
+
constructor(uuid: string) // 형식 검증 (실패 시 ArgumentError)
|
|
10
|
+
toString(): string
|
|
11
|
+
toBytes(): Bytes
|
|
12
|
+
}
|
|
17
13
|
```
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
```typescript
|
|
32
|
-
new DateOnly() // 오늘
|
|
33
|
-
new DateOnly(year, month, day)
|
|
34
|
-
new DateOnly(tick) / new DateOnly(date)
|
|
35
|
-
DateOnly.parse(str) // "yyyy-MM-dd" / "yyyyMMdd" (타임존 무관) /
|
|
36
|
-
// ISO 8601 (UTC → 로컬 변환). 실패 시 ArgumentError
|
|
14
|
+
- 정규식 `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i` 로 검증.
|
|
15
|
+
- v4 비트: byte[6]은 0x40 마스크, byte[8]은 0x80 마스크 적용.
|
|
16
|
+
|
|
17
|
+
## DateTime (불변, 로컬 타임존, ms 정밀도)
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
new DateTime() // 현재
|
|
21
|
+
new DateTime(year, month, day, h?, m?, s?, ms?)
|
|
22
|
+
new DateTime(tick: number)
|
|
23
|
+
new DateTime(date: Date)
|
|
24
|
+
static parse(str): DateTime // 'yyyy-MM-dd HH:mm:ss[.fff]', 'yyyyMMddHHmmss',
|
|
25
|
+
// 'yyyy-MM-dd AM/PM HH:mm:ss', '오전/오후', ISO 8601
|
|
37
26
|
```
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
포맷: `toFormatString
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
27
|
+
- 읽기 getter: `year`, `month` (1-12), `day`, `hour`, `minute`, `second`, `millisecond`, `tick`, `dayOfWeek` (0=일~6=토), `timezoneOffsetMinutes`, `isValid`, `date` (내부 Date 복사 X — readonly 참조).
|
|
28
|
+
- 변환: `setYear/Month/Day/Hour/Minute/Second/Millisecond(n)` → 새 인스턴스. `setMonth`는 일수 초과 시 해당 월 말일로 보정 (예: 1월 31일 → 2월 28/29일).
|
|
29
|
+
- 산술: `addYears/Months/Days` (캘린더 기반), `addHours/Minutes/Seconds/Milliseconds` (tick 가산).
|
|
30
|
+
- 포맷: `toFormatString(fmt)` — `dt.format` 형식 문자열. `toString()` = `"yyyy-MM-ddTHH:mm:ss.fffzzz"`.
|
|
31
|
+
- 파싱 실패 시 `ArgumentError`.
|
|
32
|
+
|
|
33
|
+
## DateOnly (불변, 시간 제외)
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
new DateOnly() | new DateOnly(y,m,d) | new DateOnly(tick) | new DateOnly(date)
|
|
37
|
+
static parse(str): DateOnly // 'yyyy-MM-dd', 'yyyyMMdd' (타임존 무관),
|
|
38
|
+
// ISO 8601 (UTC→로컬 변환)
|
|
39
|
+
static getDateByYearWeekSeq(
|
|
40
|
+
{ year, month?, weekSeq },
|
|
41
|
+
weekStartDay = 1, minDaysInFirstWeek = 4,
|
|
42
|
+
): DateOnly // 지정 주차의 시작 날짜
|
|
51
43
|
```
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
44
|
+
- getter: `year`, `month`, `day`, `tick`, `dayOfWeek`, `isValid`.
|
|
45
|
+
- `setYear/Month/Day`, `addYears/Months/Days` 동일 패턴 (월 보정 동일).
|
|
46
|
+
- 주차 API (인스턴스):
|
|
47
|
+
- `getBaseYearMonthSeqForWeekSeq(weekStartDay=1, minDaysInFirstWeek=4)`: 이 날짜가 속한 주의 기준 연/월.
|
|
48
|
+
- `getWeekSeqStartDate(...)`: 이 날짜가 속한 주의 시작 날짜.
|
|
49
|
+
- `getWeekSeqOfYear(...)`: `{ year, weekSeq }`.
|
|
50
|
+
- `getWeekSeqOfMonth(...)`: `{ year, monthSeq, weekSeq }`.
|
|
51
|
+
- `weekStartDay`: 주 시작 요일 (0=일~6=토). 기본 1=월.
|
|
52
|
+
- `minDaysInFirstWeek`: 첫 주 최소 일수 (1~7). 4=ISO 8601, 1=미국식.
|
|
53
|
+
- `toFormatString(fmt)` / `toString()` = `"yyyy-MM-dd"`.
|
|
54
|
+
|
|
55
|
+
## Time (불변, 24시간 순환)
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
new Time() | new Time(h, m, s?, ms?) | new Time(tick) | new Time(date)
|
|
59
|
+
static parse(str): Time // 'HH:mm:ss[.fff]', 'AM/PM HH:mm:ss', ISO 8601
|
|
62
60
|
```
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
61
|
+
- 24시간을 초과/음수인 tick 입력은 자동으로 `% MS_PER_DAY` 정규화.
|
|
62
|
+
- getter: `hour`, `minute`, `second`, `millisecond`, `tick`, `isValid`.
|
|
63
|
+
- `setHour/Minute/Second/Millisecond`, `addHours/Minutes/Seconds/Milliseconds` (24시간 순환).
|
|
64
|
+
- `toFormatString(fmt)` / `toString()` = `"HH:mm:ss.fff"`.
|
|
65
|
+
|
|
66
|
+
## LazyGcMap<TKey, TValue>
|
|
67
|
+
|
|
68
|
+
LRU 접근 시간 갱신 + 주기 GC 로 자동 만료되는 `Map`.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
new LazyGcMap({
|
|
72
|
+
expireTime: number, // 만료 ms (필수). 마지막 접근부터 경과 시 삭제
|
|
73
|
+
gcInterval?: number, // GC 주기 ms. 기본 = max(expireTime/10, 1000)
|
|
74
|
+
onExpire?: (key, value) => void|Promise<void>, // 만료 시 콜백. 비동기 가능, throw하면 로그만
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
has(key) // 접근 시간 갱신 X
|
|
78
|
+
get(key) // 접근 시간 갱신 O
|
|
79
|
+
set(key, val) // GC 타이머 시작
|
|
80
|
+
delete(key) // 비면 GC 중지
|
|
81
|
+
clear() // 전체 삭제 + GC 중지 (인스턴스 재사용 가능)
|
|
82
|
+
dispose() // 영구 정리 (이후 모든 작업 no-op, getOrCreate만 throw)
|
|
83
|
+
getOrCreate(key, factory)
|
|
84
|
+
size, keys(), values(), entries()
|
|
76
85
|
```
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
LRU 자동 만료 Map. **사용 후 반드시 `dispose()` 호출** — 안 하면 GC 타이머가 살아 메모리 누수.
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
const m = new LazyGcMap<K, V>({
|
|
84
|
-
expireTime: 60_000, // 마지막 접근 이후 ms
|
|
85
|
-
gcInterval?: 6_000, // 기본: expireTime/10, 최소 1000ms
|
|
86
|
-
onExpire?: (k, v) => ... , // 비동기 가능, 에러는 로그
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
m.size; m.has(k); m.get(k); m.set(k, v); m.delete(k); m.clear(); m.dispose();
|
|
90
|
-
m.getOrCreate(k, factory); // dispose 후 호출 시 throw
|
|
91
|
-
m.keys() / m.values() / m.entries(); // Iterator
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
`get`/`getOrCreate` 만 접근시간 갱신(LRU). `has` 는 갱신 X. GC 실행 중 같은 key 재등록 시 새 항목 보존.
|
|
95
|
-
|
|
96
|
-
## date-format 토큰
|
|
97
|
-
|
|
98
|
-
`DateTime/DateOnly/Time#toFormatString(formatStr)` 에서 사용. C# 호환.
|
|
99
|
-
|
|
100
|
-
| 토큰 | 의미 | 예 |
|
|
101
|
-
|------|------|----|
|
|
102
|
-
| `yyyy`/`yy` | 연도 4/2자리 | 2024 / 24 |
|
|
103
|
-
| `MM`/`M` | 월 패딩/미패딩 | 01 / 1 |
|
|
104
|
-
| `ddd` | 한글 요일 | 일~토 |
|
|
105
|
-
| `dd`/`d` | 일 패딩/미패딩 | 01 / 1 |
|
|
106
|
-
| `tt` | AM/PM | AM |
|
|
107
|
-
| `hh`/`h` | 12시간 패딩/미패딩 | 01 / 1 |
|
|
108
|
-
| `HH`/`H` | 24시간 패딩/미패딩 | 14 / 14 |
|
|
109
|
-
| `mm`/`m` | 분 | 30 / 30 |
|
|
110
|
-
| `ss`/`s` | 초 | 45 / 45 |
|
|
111
|
-
| `fff`/`ff`/`f` | 밀리초 3/2/1자리 | 123 / 12 / 1 |
|
|
112
|
-
| `zzz`/`zz`/`z` | 타임존 ±HH:mm / ±HH / ±H | +09:00 |
|
|
113
|
-
|
|
114
|
-
긴 토큰이 먼저 매칭 → 부분 매칭 방지.
|
|
86
|
+
- **반드시 `dispose()` 호출 필요** — 안 하면 GC 타이머 leak.
|
|
87
|
+
- GC 중복 실행 방지(`_isGcRunning`). `onExpire` 실행 도중 같은 key로 `set()`되면 새 값은 보존(참조 동일성 비교).
|
|
88
|
+
- 비어있으면 자동 GC 중지 → 재 `set()` 시 자동 재시작.
|