@simplysm/sd-claude 14.0.47 → 14.0.49

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 (130) hide show
  1. package/{claude/references/sd-simplysm14/sd-claude/usage.md → README.md} +2 -2
  2. package/claude/rules/sd-claude-rules.md +25 -10
  3. package/claude/rules/sd-options.md +11 -6
  4. package/claude/sd-subagent-start.sh +6 -0
  5. package/claude/settings.json +1 -12
  6. package/claude/skills/sd-check/SKILL.md +43 -12
  7. package/claude/skills/sd-claude-docs/SKILL.md +30 -58
  8. package/claude/skills/sd-claude-docs/references/package-claudemd.md +12 -0
  9. package/claude/skills/sd-claude-docs/references/package-doc-gen.md +26 -13
  10. package/claude/skills/sd-commit/SKILL.md +1 -1
  11. package/claude/skills/sd-debug/SKILL.md +5 -3
  12. package/claude/skills/sd-deliverable/SKILL.md +1 -1
  13. package/claude/skills/sd-dev/SKILL.md +14 -9
  14. package/claude/skills/sd-doc-extract/SKILL.md +8 -10
  15. package/claude/skills/sd-doc-extract/_common.py +8 -1
  16. package/claude/skills/sd-doc-extract/_extract_docx.py +74 -34
  17. package/claude/skills/sd-doc-extract/_extract_pdf.py +12 -1
  18. package/claude/skills/sd-doc-extract/_extract_pptx.py +103 -23
  19. package/claude/skills/sd-doc-extract/_extract_xlsb.py +93 -4
  20. package/claude/skills/sd-doc-extract/_extract_xlsx.py +98 -36
  21. package/claude/skills/sd-doc-extract/extract.py +22 -3
  22. package/claude/skills/sd-inner-clarify/SKILL.md +78 -0
  23. package/claude/skills/sd-inner-debug/SKILL.md +1 -1
  24. package/claude/skills/sd-inner-review/SKILL.md +13 -0
  25. package/claude/skills/sd-issue/SKILL.md +1 -1
  26. package/claude/skills/sd-outlook/SKILL.md +1 -1
  27. package/claude/skills/sd-plan/SKILL.md +50 -17
  28. package/claude/skills/sd-prompt/SKILL.md +180 -178
  29. package/claude/skills/sd-prompt/references/eval-runner.md +5 -30
  30. package/claude/skills/sd-prompt/references/sd-eval-env-template.md +23 -0
  31. package/claude/skills/sd-refactor/SKILL.md +2 -2
  32. package/claude/skills/sd-tdd/SKILL.md +45 -16
  33. package/claude/skills/sd-use/SKILL.md +84 -80
  34. package/claude/skills/sd-wbs/SKILL.md +84 -27
  35. package/{claude/references/sd-simplysm14/sd-claude/docs → docs}/assets.md +2 -3
  36. package/{claude/references/sd-simplysm14/sd-claude/docs → docs}/hooks.md +7 -6
  37. package/{claude/references/sd-simplysm14/sd-claude/docs → docs}/scripts.md +1 -9
  38. package/package.json +3 -2
  39. package/scripts/sync.mjs +4 -2
  40. package/claude/references/sd-simplysm14/angular/docs/bootstrap.md +0 -48
  41. package/claude/references/sd-simplysm14/angular/docs/directives.md +0 -236
  42. package/claude/references/sd-simplysm14/angular/docs/features.md +0 -379
  43. package/claude/references/sd-simplysm14/angular/docs/pipes.md +0 -32
  44. package/claude/references/sd-simplysm14/angular/docs/plugins.md +0 -37
  45. package/claude/references/sd-simplysm14/angular/docs/provider-types.md +0 -283
  46. package/claude/references/sd-simplysm14/angular/docs/providers.md +0 -379
  47. package/claude/references/sd-simplysm14/angular/docs/styling.md +0 -222
  48. package/claude/references/sd-simplysm14/angular/docs/type-utilities.md +0 -250
  49. package/claude/references/sd-simplysm14/angular/docs/ui-data.md +0 -275
  50. package/claude/references/sd-simplysm14/angular/docs/ui-form.md +0 -490
  51. package/claude/references/sd-simplysm14/angular/docs/ui-layout.md +0 -140
  52. package/claude/references/sd-simplysm14/angular/docs/ui-navigation.md +0 -273
  53. package/claude/references/sd-simplysm14/angular/docs/ui-overlay.md +0 -157
  54. package/claude/references/sd-simplysm14/angular/docs/ui-visual.md +0 -127
  55. package/claude/references/sd-simplysm14/angular/docs/utils.md +0 -295
  56. package/claude/references/sd-simplysm14/angular/usage.md +0 -489
  57. package/claude/references/sd-simplysm14/capacitor-plugin-auto-update/usage.md +0 -182
  58. package/claude/references/sd-simplysm14/capacitor-plugin-file-system/docs/file-operations.md +0 -154
  59. package/claude/references/sd-simplysm14/capacitor-plugin-file-system/docs/permissions.md +0 -84
  60. package/claude/references/sd-simplysm14/capacitor-plugin-file-system/docs/storage-paths.md +0 -107
  61. package/claude/references/sd-simplysm14/capacitor-plugin-file-system/docs/types.md +0 -83
  62. package/claude/references/sd-simplysm14/capacitor-plugin-file-system/usage.md +0 -133
  63. package/claude/references/sd-simplysm14/capacitor-plugin-intent/usage.md +0 -203
  64. package/claude/references/sd-simplysm14/capacitor-plugin-usb-storage/usage.md +0 -258
  65. package/claude/references/sd-simplysm14/core-browser/usage.md +0 -306
  66. package/claude/references/sd-simplysm14/core-common/docs/errors.md +0 -82
  67. package/claude/references/sd-simplysm14/core-common/docs/extensions.md +0 -167
  68. package/claude/references/sd-simplysm14/core-common/docs/features.md +0 -136
  69. package/claude/references/sd-simplysm14/core-common/docs/types.md +0 -245
  70. package/claude/references/sd-simplysm14/core-common/docs/utils.md +0 -591
  71. package/claude/references/sd-simplysm14/core-common/usage.md +0 -255
  72. package/claude/references/sd-simplysm14/core-node/docs/child-process.md +0 -182
  73. package/claude/references/sd-simplysm14/core-node/docs/features.md +0 -214
  74. package/claude/references/sd-simplysm14/core-node/docs/file-system.md +0 -509
  75. package/claude/references/sd-simplysm14/core-node/docs/file-watching.md +0 -139
  76. package/claude/references/sd-simplysm14/core-node/docs/logging.md +0 -180
  77. package/claude/references/sd-simplysm14/core-node/docs/path.md +0 -176
  78. package/claude/references/sd-simplysm14/core-node/docs/utilities-cpx.md +0 -194
  79. package/claude/references/sd-simplysm14/core-node/docs/utilities-fsx.md +0 -469
  80. package/claude/references/sd-simplysm14/core-node/docs/utilities-pathx.md +0 -151
  81. package/claude/references/sd-simplysm14/core-node/docs/worker-threads.md +0 -334
  82. package/claude/references/sd-simplysm14/core-node/docs/worker.md +0 -205
  83. package/claude/references/sd-simplysm14/core-node/usage.md +0 -259
  84. package/claude/references/sd-simplysm14/excel/docs/core-classes.md +0 -453
  85. package/claude/references/sd-simplysm14/excel/docs/types.md +0 -459
  86. package/claude/references/sd-simplysm14/excel/docs/utilities.md +0 -194
  87. package/claude/references/sd-simplysm14/excel/docs/wrapper.md +0 -73
  88. package/claude/references/sd-simplysm14/excel/usage.md +0 -134
  89. package/claude/references/sd-simplysm14/lint/usage.md +0 -130
  90. package/claude/references/sd-simplysm14/orm-common/docs/core.md +0 -188
  91. package/claude/references/sd-simplysm14/orm-common/docs/expression.md +0 -190
  92. package/claude/references/sd-simplysm14/orm-common/docs/models.md +0 -17
  93. package/claude/references/sd-simplysm14/orm-common/docs/query-builder.md +0 -97
  94. package/claude/references/sd-simplysm14/orm-common/docs/queryable-executable.md +0 -250
  95. package/claude/references/sd-simplysm14/orm-common/docs/schema-builders.md +0 -364
  96. package/claude/references/sd-simplysm14/orm-common/docs/types.md +0 -522
  97. package/claude/references/sd-simplysm14/orm-common/usage.md +0 -229
  98. package/claude/references/sd-simplysm14/orm-node/docs/connections.md +0 -137
  99. package/claude/references/sd-simplysm14/orm-node/docs/core.md +0 -131
  100. package/claude/references/sd-simplysm14/orm-node/docs/types.md +0 -173
  101. package/claude/references/sd-simplysm14/orm-node/usage.md +0 -143
  102. package/claude/references/sd-simplysm14/sd-cli/usage.md +0 -782
  103. package/claude/references/sd-simplysm14/service-client/docs/features.md +0 -217
  104. package/claude/references/sd-simplysm14/service-client/docs/main.md +0 -148
  105. package/claude/references/sd-simplysm14/service-client/docs/protocol.md +0 -53
  106. package/claude/references/sd-simplysm14/service-client/docs/transport.md +0 -131
  107. package/claude/references/sd-simplysm14/service-client/docs/types.md +0 -129
  108. package/claude/references/sd-simplysm14/service-client/usage.md +0 -202
  109. package/claude/references/sd-simplysm14/service-common/docs/app-structure.md +0 -175
  110. package/claude/references/sd-simplysm14/service-common/docs/events.md +0 -64
  111. package/claude/references/sd-simplysm14/service-common/docs/protocol.md +0 -331
  112. package/claude/references/sd-simplysm14/service-common/docs/service-types.md +0 -90
  113. package/claude/references/sd-simplysm14/service-common/docs/types.md +0 -19
  114. package/claude/references/sd-simplysm14/service-common/usage.md +0 -154
  115. package/claude/references/sd-simplysm14/service-server/docs/auth.md +0 -64
  116. package/claude/references/sd-simplysm14/service-server/docs/core.md +0 -174
  117. package/claude/references/sd-simplysm14/service-server/docs/legacy.md +0 -25
  118. package/claude/references/sd-simplysm14/service-server/docs/main.md +0 -88
  119. package/claude/references/sd-simplysm14/service-server/docs/protocol.md +0 -33
  120. package/claude/references/sd-simplysm14/service-server/docs/services.md +0 -94
  121. package/claude/references/sd-simplysm14/service-server/docs/transport-http.md +0 -93
  122. package/claude/references/sd-simplysm14/service-server/docs/transport-socket.md +0 -119
  123. package/claude/references/sd-simplysm14/service-server/docs/types.md +0 -36
  124. package/claude/references/sd-simplysm14/service-server/docs/utils.md +0 -22
  125. package/claude/references/sd-simplysm14/service-server/usage.md +0 -171
  126. package/claude/references/sd-simplysm14/storage/usage.md +0 -301
  127. package/claude/references/sd-simplysm14.md +0 -35
  128. package/claude/rules/sd-clarify.md +0 -23
  129. package/claude/sd-session-start.sh +0 -10
  130. /package/{claude/references/sd-simplysm14/sd-claude/docs → docs}/cli.md +0 -0
@@ -1,306 +0,0 @@
1
- # @simplysm/core-browser
2
-
3
- 브라우저 전용 유틸리티 패키지. DOM 프로토타입 확장, 파일 다운로드/업로드, HTTP fetch, IndexedDB 추상화를 제공한다.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @simplysm/core-browser
9
- ```
10
-
11
- ## API Overview
12
-
13
- ### Extensions
14
-
15
- 사이드 이펙트 모듈로, 패키지를 임포트하면 자동으로 `Element`와 `HTMLElement` 프로토타입에 메서드가 추가된다.
16
-
17
- | API | Type | Description |
18
- |-----|------|-------------|
19
- | `ElementBounds` | interface | 요소 경계 정보 (target, top, left, width, height) |
20
- | `copyElement` | function | copy 이벤트 핸들러에서 요소 내 input/textarea 값을 클립보드에 복사 |
21
- | `pasteToElement` | function | paste 이벤트 핸들러에서 클립보드 텍스트를 요소 내 input/textarea에 붙여넣기 |
22
- | `getBounds` | function | IntersectionObserver로 여러 요소의 경계 정보를 비동기 조회 |
23
- | `Element.prototype.findAll` | prototype extension | 선택자와 일치하는 모든 하위 요소 검색 |
24
- | `Element.prototype.findFirst` | prototype extension | 선택자와 일치하는 첫 번째 요소 검색 |
25
- | `Element.prototype.prependChild` | prototype extension | 요소를 첫 번째 자식으로 삽입 |
26
- | `Element.prototype.getParents` | prototype extension | 모든 부모 요소를 가까운 순서로 조회 |
27
- | `Element.prototype.findTabbableParent` | prototype extension | 첫 번째 탭 이동 가능한 부모 요소 검색 (tabbable 사용) |
28
- | `Element.prototype.findFirstTabbableChild` | prototype extension | 첫 번째 탭 이동 가능한 자식 요소 검색 (tabbable 사용) |
29
- | `Element.prototype.isOffsetElement` | prototype extension | position이 relative/absolute/fixed/sticky인지 확인 |
30
- | `Element.prototype.isVisible` | prototype extension | 요소가 화면에 보이는지 확인 (clientRects, visibility, opacity) |
31
- | `HTMLElement.prototype.repaint` | prototype extension | 강제 리페인트 트리거 (offsetHeight 접근) |
32
- | `HTMLElement.prototype.getRelativeOffset` | prototype extension | 부모 요소 기준 상대 위치 계산 (CSS top/left 용) |
33
- | `HTMLElement.prototype.scrollIntoViewIfNeeded` | prototype extension | offset 영역에 가려진 경우 대상이 보이도록 스크롤 |
34
-
35
- #### `ElementBounds`
36
-
37
- ```typescript
38
- export interface ElementBounds {
39
- target: Element;
40
- top: number;
41
- left: number;
42
- width: number;
43
- height: number;
44
- }
45
- ```
46
-
47
- | Field | Type | Description |
48
- |-------|------|-------------|
49
- | `target` | `Element` | 측정 대상 요소 |
50
- | `top` | `number` | 뷰포트 기준 상단 위치 |
51
- | `left` | `number` | 뷰포트 기준 좌측 위치 |
52
- | `width` | `number` | 요소 너비 |
53
- | `height` | `number` | 요소 높이 |
54
-
55
- #### `copyElement`
56
-
57
- ```typescript
58
- export function copyElement(event: ClipboardEvent): void
59
- ```
60
-
61
- copy 이벤트 핸들러와 함께 사용한다. 이벤트 타겟 요소 내의 첫 번째 `input` 또는 `textarea`를 찾아 그 값을 클립보드에 설정한다. 해당 요소가 없으면 아무 동작도 하지 않는다.
62
-
63
- #### `pasteToElement`
64
-
65
- ```typescript
66
- export function pasteToElement(event: ClipboardEvent): void
67
- ```
68
-
69
- paste 이벤트 핸들러와 함께 사용한다. 이벤트 타겟 요소 내의 첫 번째 `input` 또는 `textarea`를 찾아 값 전체를 클립보드 텍스트로 교체한다. 커서 위치나 선택 영역은 고려하지 않는다. `input` 이벤트를 dispatch한다.
70
-
71
- #### `getBounds`
72
-
73
- ```typescript
74
- export async function getBounds(els: Element[], timeout?: number): Promise<ElementBounds[]>
75
- ```
76
-
77
- IntersectionObserver를 사용하여 여러 요소의 경계 정보를 비동기로 조회한다. 중복 요소는 자동 제거되며, 입력 순서대로 결과가 정렬된다. `timeout` 기본값은 5000ms이며, 시간 내에 응답이 없으면 `TimeoutError`를 던진다.
78
-
79
- #### Element Prototype Extensions
80
-
81
- `Element.prototype`에 추가되는 메서드들:
82
-
83
- ```typescript
84
- // 선택자와 일치하는 모든 하위 요소 검색 (빈 선택자 -> 빈 배열)
85
- element.findAll<TEl extends Element = Element>(selector: string): TEl[]
86
-
87
- // 선택자와 일치하는 첫 번째 요소 (빈 선택자 -> undefined)
88
- element.findFirst<TEl extends Element = Element>(selector: string): TEl | undefined
89
-
90
- // 요소를 첫 번째 자식으로 삽입
91
- element.prependChild<TEl extends Element>(child: TEl): TEl
92
-
93
- // 모든 부모 요소 배열 (가까운 순서)
94
- element.getParents(): Element[]
95
-
96
- // 첫 번째 탭 이동 가능한 부모 요소 (tabbable 라이브러리 사용)
97
- element.findTabbableParent(): HTMLElement | undefined
98
-
99
- // 첫 번째 탭 이동 가능한 자식 요소 (tabbable 라이브러리 사용)
100
- element.findFirstTabbableChild(): HTMLElement | undefined
101
-
102
- // position이 relative/absolute/fixed/sticky인지 확인
103
- element.isOffsetElement(): boolean
104
-
105
- // 화면에 보이는지 확인 (clientRects, visibility, opacity)
106
- element.isVisible(): boolean
107
- ```
108
-
109
- #### HTMLElement Prototype Extensions
110
-
111
- `HTMLElement.prototype`에 추가되는 메서드들:
112
-
113
- ```typescript
114
- // 강제 리페인트 (offsetHeight 접근으로 reflow 트리거)
115
- htmlElement.repaint(): void
116
-
117
- // 부모 요소 기준 상대 위치 계산 (CSS top/left에 사용 가능)
118
- // parent: HTMLElement 또는 CSS 선택자 문자열
119
- // border 두께, CSS transform 변환 포함
120
- // 부모를 찾을 수 없으면 ArgumentError throw
121
- htmlElement.getRelativeOffset(parent: HTMLElement | string): { top: number; left: number }
122
-
123
- // offset 영역에 가려진 경우 스크롤 조정
124
- // target: 컨테이너 내 대상 위치 (offsetTop, offsetLeft)
125
- // offset: 가려지면 안 되는 영역 크기 (기본값 { top: 0, left: 0 })
126
- // 상단/좌측 방향만 처리, 하단/우측은 브라우저 기본 동작에 의존
127
- htmlElement.scrollIntoViewIfNeeded(
128
- target: { top: number; left: number },
129
- offset?: { top: number; left: number }
130
- ): void
131
- ```
132
-
133
- ### Utils
134
-
135
- | API | Type | Description |
136
- |-----|------|-------------|
137
- | `downloadBlob` | function | Blob을 파일로 다운로드 (링크 클릭 방식) |
138
- | `DownloadProgress` | interface | 다운로드 진행 정보 (receivedLength, contentLength) |
139
- | `fetchUrlBytes` | function | URL에서 Uint8Array 다운로드 (진행 콜백 지원) |
140
- | `openFileDialog` | function | 파일 선택 대화상자를 프로그래밍 방식으로 열기 |
141
- | `StoreConfig` | interface | IndexedDbStore 스토어 설정 (name, keyPath) |
142
- | `IndexedDbStore` | class | IndexedDB를 Promise 기반으로 래핑한 저수준 CRUD 클래스 |
143
- | `VirtualFsEntry` | interface | 가상 파일시스템 엔트리 (kind, dataBase64) |
144
- | `IndexedDbVirtualFs` | class | IndexedDB 기반 경로 기반 가상 파일시스템 |
145
-
146
- #### `downloadBlob`
147
-
148
- ```typescript
149
- export function downloadBlob(blob: Blob, fileName: string): void
150
- ```
151
-
152
- Blob을 파일로 다운로드한다. `<a>` 태그를 생성하여 클릭하는 방식이다. Object URL은 1초 후 자동 해제된다.
153
-
154
- #### `DownloadProgress`
155
-
156
- ```typescript
157
- export interface DownloadProgress {
158
- receivedLength: number;
159
- contentLength: number;
160
- }
161
- ```
162
-
163
- | Field | Type | Description |
164
- |-------|------|-------------|
165
- | `receivedLength` | `number` | 현재까지 수신한 바이트 수 |
166
- | `contentLength` | `number` | 전체 콘텐츠 길이 (Content-Length 헤더 값) |
167
-
168
- #### `fetchUrlBytes`
169
-
170
- ```typescript
171
- export async function fetchUrlBytes(
172
- url: string,
173
- options?: { onProgress?: (progress: DownloadProgress) => void },
174
- ): Promise<Uint8Array>
175
- ```
176
-
177
- URL에서 바이너리 데이터를 `Uint8Array`로 다운로드한다. `Content-Length` 헤더가 있으면 사전 할당으로 메모리 효율을 높이고, 없으면 청크 수집 후 `bytes.concat`으로 병합한다. 진행 콜백은 `options.onProgress`로 수신한다. 응답이 실패하면 Error를 던진다.
178
-
179
- #### `openFileDialog`
180
-
181
- ```typescript
182
- export function openFileDialog(options?: {
183
- accept?: string;
184
- multiple?: boolean;
185
- }): Promise<File[] | undefined>
186
- ```
187
-
188
- 프로그래밍 방식으로 파일 선택 대화상자를 연다. `accept`로 파일 형식 필터, `multiple`로 다중 선택 여부를 지정한다. 파일 선택 시 `File[]` 반환, 취소 시 `undefined` 반환.
189
-
190
- #### `StoreConfig`
191
-
192
- ```typescript
193
- export interface StoreConfig {
194
- name: string;
195
- keyPath: string;
196
- }
197
- ```
198
-
199
- | Field | Type | Description |
200
- |-------|------|-------------|
201
- | `name` | `string` | object store 이름 |
202
- | `keyPath` | `string` | 기본 키 경로 |
203
-
204
- #### `IndexedDbStore`
205
-
206
- ```typescript
207
- export class IndexedDbStore {
208
- constructor(dbName: string, dbVersion: number, storeConfigs: StoreConfig[])
209
-
210
- open(): Promise<IDBDatabase>
211
- withStore<TResult>(storeName: string, mode: IDBTransactionMode, fn: (store: IDBObjectStore) => Promise<TResult>): Promise<TResult>
212
- get<TValue>(storeName: string, key: IDBValidKey): Promise<TValue | undefined>
213
- put(storeName: string, value: unknown): Promise<void>
214
- delete(storeName: string, key: IDBValidKey): Promise<void>
215
- getAll<TItem>(storeName: string): Promise<TItem[]>
216
- close(): void
217
- }
218
- ```
219
-
220
- IndexedDB를 Promise 기반으로 래핑한 저수준 클래스. 생성자에서 DB 이름, 버전, 스토어 설정을 받는다.
221
-
222
- | Method | Description |
223
- |--------|-------------|
224
- | `open()` | DB 연결을 열고 `IDBDatabase`를 반환. 중복 호출에 안전 (이미 열려 있으면 기존 인스턴스 반환) |
225
- | `withStore(storeName, mode, fn)` | 지정 스토어에서 트랜잭션을 열고 `fn`을 실행. fn이 에러를 던지면 트랜잭션을 abort한다 |
226
- | `get(storeName, key)` | 키로 단일 항목 조회. 없으면 `undefined` |
227
- | `put(storeName, value)` | 항목 추가/갱신 (keyPath에 해당하는 필드가 value에 포함되어야 함) |
228
- | `delete(storeName, key)` | 키로 항목 삭제 |
229
- | `getAll(storeName)` | 스토어의 모든 항목 조회 |
230
- | `close()` | DB 연결 닫기 |
231
-
232
- #### `VirtualFsEntry`
233
-
234
- ```typescript
235
- export interface VirtualFsEntry {
236
- kind: "file" | "dir";
237
- dataBase64?: string;
238
- }
239
- ```
240
-
241
- | Field | Type | Description |
242
- |-------|------|-------------|
243
- | `kind` | `"file" \| "dir"` | 엔트리 종류 (파일 또는 디렉토리) |
244
- | `dataBase64` | `string \| undefined` | 파일 데이터 (Base64 인코딩, 디렉토리인 경우 없음) |
245
-
246
- #### `IndexedDbVirtualFs`
247
-
248
- ```typescript
249
- export class IndexedDbVirtualFs {
250
- constructor(db: IndexedDbStore, storeName: string, keyField: string)
251
-
252
- getEntry(fullKey: string): Promise<VirtualFsEntry | undefined>
253
- putEntry(fullKey: string, kind: "file" | "dir", dataBase64?: string): Promise<void>
254
- deleteByPrefix(keyPrefix: string): Promise<boolean>
255
- listChildren(prefix: string): Promise<{ name: string; isDirectory: boolean }[]>
256
- ensureDir(fullKeyBuilder: (path: string) => string, dirPath: string): Promise<void>
257
- }
258
- ```
259
-
260
- `IndexedDbStore` 위에 경로 기반 가상 파일시스템을 구현하는 클래스. 키는 `/path/to/file` 형태의 문자열.
261
-
262
- | Method | Description |
263
- |--------|-------------|
264
- | `getEntry(fullKey)` | 경로에 해당하는 엔트리 조회. 없으면 `undefined` |
265
- | `putEntry(fullKey, kind, dataBase64?)` | 엔트리 추가/갱신. `kind`는 `"file"` 또는 `"dir"` |
266
- | `deleteByPrefix(keyPrefix)` | 접두사와 일치하는 모든 엔트리 삭제. 삭제된 항목이 있으면 `true` |
267
- | `listChildren(prefix)` | 접두사 바로 아래 자식 목록 반환. 이름과 디렉토리 여부 포함 |
268
- | `ensureDir(fullKeyBuilder, dirPath)` | 경로의 모든 중간 디렉토리를 재귀적으로 생성. 이미 있으면 건너뜀 |
269
-
270
- ## Usage Examples
271
-
272
- ### Blob 파일 다운로드
273
-
274
- ```typescript
275
- import { downloadBlob } from "@simplysm/core-browser";
276
-
277
- const data = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
278
- const blob = new Blob([data], { type: "application/octet-stream" });
279
- downloadBlob(blob, "output.bin");
280
- ```
281
-
282
- ### IndexedDB CRUD
283
-
284
- ```typescript
285
- import { IndexedDbStore } from "@simplysm/core-browser";
286
-
287
- const store = new IndexedDbStore("myDb", 1, [{ name: "items", keyPath: "id" }]);
288
-
289
- await store.put("items", { id: "key1", value: "hello" });
290
- const item = await store.get<{ id: string; value: string }>("items", "key1");
291
- const all = await store.getAll<{ id: string; value: string }>("items");
292
- await store.delete("items", "key1");
293
- store.close();
294
- ```
295
-
296
- ### DOM 프로토타입 확장 사용
297
-
298
- ```typescript
299
- import "@simplysm/core-browser";
300
-
301
- const container = document.querySelector(".container")!;
302
- const buttons = container.findAll<HTMLButtonElement>("button");
303
- const firstInput = container.findFirst<HTMLInputElement>("input[type=text]");
304
- const parents = container.getParents();
305
- const focusable = container.findFirstTabbableChild();
306
- ```
@@ -1,82 +0,0 @@
1
- # Errors
2
-
3
- ## `SdError`
4
-
5
- 트리 구조 에러 체인을 지원하는 에러 클래스. ES2024 `cause` 속성을 활용한다.
6
-
7
- ```typescript
8
- export class SdError extends Error {
9
- override cause?: Error;
10
-
11
- /** 원인 에러를 감싸서 생성. 메시지는 역순으로 결합됨 */
12
- constructor(cause: Error, ...messages: string[]);
13
- /** 메시지만으로 생성 */
14
- constructor(...messages: string[]);
15
- }
16
- ```
17
-
18
- 생성자에 전달된 메시지들은 역순으로 결합된다. `cause`가 `Error` 인스턴스이면 그 메시지도 체인 끝에 추가된다.
19
-
20
- ```typescript
21
- throw new SdError(err, "API 호출 실패", "사용자 로드 실패");
22
- // message: "사용자 로드 실패 => API 호출 실패 => 원본 에러 메시지"
23
-
24
- throw new SdError("잘못된 상태", "처리 불가");
25
- // message: "처리 불가 => 잘못된 상태"
26
- ```
27
-
28
- ## `ArgumentError`
29
-
30
- 유효하지 않은 인자를 전달받았을 때 발생하는 에러. 인자 객체를 YAML 형식으로 메시지에 포함하여 디버깅을 용이하게 한다.
31
-
32
- ```typescript
33
- export class ArgumentError extends SdError {
34
- /** 기본 메시지("잘못된 인자입니다.")와 함께 인자 객체를 YAML 형식으로 출력 */
35
- constructor(argObj: Record<string, unknown>);
36
- /** 커스텀 메시지와 함께 인자 객체를 YAML 형식으로 출력 */
37
- constructor(message: string, argObj: Record<string, unknown>);
38
- }
39
- ```
40
-
41
- ```typescript
42
- throw new ArgumentError({ userId: 123, name: null });
43
- // message: "잘못된 인자입니다.\n\nuserId: 123\nname: null"
44
-
45
- throw new ArgumentError("잘못된 사용자", { userId: 123 });
46
- // message: "잘못된 사용자\n\nuserId: 123"
47
- ```
48
-
49
- ## `NotImplementedError`
50
-
51
- 아직 구현되지 않은 기능이 호출되었을 때 발생하는 에러.
52
-
53
- ```typescript
54
- export class NotImplementedError extends SdError {
55
- constructor(message?: string);
56
- }
57
- ```
58
-
59
- ```typescript
60
- throw new NotImplementedError("서브클래스에서 구현 필요");
61
- // message: "미구현: 서브클래스에서 구현 필요"
62
- ```
63
-
64
- ## `TimeoutError`
65
-
66
- 대기 시간이 초과되었을 때 발생하는 에러. `wait.until()`에서 최대 시도 횟수를 초과하면 자동으로 발생한다.
67
-
68
- ```typescript
69
- export class TimeoutError extends SdError {
70
- constructor(count?: number, message?: string);
71
- }
72
- ```
73
-
74
- | Parameter | Type | Description |
75
- |-----------|------|-------------|
76
- | `count` | `number \| undefined` | 시도 횟수 |
77
- | `message` | `string \| undefined` | 추가 메시지 |
78
-
79
- ```typescript
80
- throw new TimeoutError(50, "API 응답 대기 초과");
81
- // message: "대기 시간 초과(50회 시도): API 응답 대기 초과"
82
- ```
@@ -1,167 +0,0 @@
1
- # Extensions (Prototype)
2
-
3
- `@simplysm/core-common`을 import하면 `Array`, `Map`, `Set` 프로토타입 확장이 자동 등록된다.
4
-
5
- ```typescript
6
- import "@simplysm/core-common"; // side-effect import — 확장 등록
7
- ```
8
-
9
- ## Array Extensions (Immutable)
10
-
11
- 새 배열을 반환하며 원본 배열을 변경하지 않는다.
12
-
13
- | Method | Signature | Description |
14
- |--------|-----------|-------------|
15
- | `single` | `(predicate?) => T \| undefined` | 조건에 맞는 단일 요소 반환. 2개 이상이면 `ArgumentError` 발생 |
16
- | `first` | `(predicate?) => T \| undefined` | 첫 번째 요소 반환 |
17
- | `last` | `(predicate?) => T \| undefined` | 마지막 요소 반환 |
18
- | `filterExists` | `() => NonNullable<T>[]` | null/undefined 제거 |
19
- | `ofType` | `(type) => TNarrow[]` | 특정 타입의 요소만 필터 (`PrimitiveTypeStr` 또는 생성자) |
20
- | `mapAsync` | `(selector) => Promise<TResult[]>` | 비동기 매핑 (순차 실행) |
21
- | `filterAsync` | `(predicate) => Promise<T[]>` | 비동기 필터 (순차 실행) |
22
- | `mapMany` | `(selector?) => TResult[]` | 매핑 후 평탄화 (또는 중첩 배열 평탄화) |
23
- | `mapManyAsync` | `(selector?) => Promise<TResult[]>` | 비동기 매핑 후 평탄화 (순차 실행) |
24
- | `parallelAsync` | `(fn) => Promise<TResult[]>` | 비동기 병렬 처리 (`Promise.all` 사용) |
25
- | `groupBy` | `(keySelector, valueSelector?) => { key, values }[]` | key 기준 그룹화. 객체 key는 O(n²), 원시 key는 O(n) |
26
- | `toMap` | `(keySelector, valueSelector?) => Map<TKey, TValue>` | Map으로 변환. 중복 key이면 `ArgumentError` 발생 |
27
- | `toMapAsync` | `(keySelector, valueSelector?) => Promise<Map<TKey, TValue>>` | 비동기 Map으로 변환 |
28
- | `toArrayMap` | `(keySelector, valueSelector?) => Map<TKey, TValue[]>` | 그룹 Map으로 변환. O(n) 성능 |
29
- | `toSetMap` | `(keySelector, valueSelector?) => Map<TKey, Set<TValue>>` | 그룹 Set Map으로 변환 |
30
- | `toMapValues` | `(keySelector, valueSelector) => Map<TKey, TValue>` | 그룹화 후 그룹별로 값 변환 |
31
- | `toObject` | `(keySelector, valueSelector?) => Record<string, TValue>` | 일반 객체로 변환. 중복 key이면 `ArgumentError` 발생 |
32
- | `toTree` | `(keyProp, parentKey) => TreeArray<T>[]` | 평면 배열을 트리 구조로 변환. O(n) 복잡도 |
33
- | `distinct` | `(options?) => T[]` | 중복 제거. 객체 배열에서 `keyFn` 없이 사용하면 O(n²) |
34
- | `orderBy` | `(selector?) => T[]` | 오름차순 정렬 |
35
- | `orderByDesc` | `(selector?) => T[]` | 내림차순 정렬 |
36
- | `diffs` | `(target, options?) => ArrayDiffsResult<T, P>[]` | 두 배열 비교 (INSERT/DELETE/UPDATE) |
37
- | `oneWayDiffs` | `(orgItems, keyPropNameOrGetValFn, options?) => ArrayOneWayDiffResult<T>[]` | 단방향 차이 계산 (create/update/same) |
38
- | `merge` | `(target, options?) => (T \| P \| T&P)[]` | 두 배열 병합 |
39
- | `sum` | `(selector?) => number` | 합계. 빈 배열이면 0 |
40
- | `min` | `(selector?) => T \| undefined` | 최솟값 |
41
- | `max` | `(selector?) => T \| undefined` | 최댓값 |
42
- | `shuffle` | `() => T[]` | 무작위 섞기 |
43
-
44
- ### `toTree` 상세
45
-
46
- ```typescript
47
- interface Item {
48
- id: number;
49
- parentId?: number;
50
- name: string;
51
- }
52
-
53
- const items: Item[] = [
54
- { id: 1, name: "root" },
55
- { id: 2, parentId: 1, name: "child1" },
56
- { id: 3, parentId: 2, name: "grandchild" },
57
- ];
58
-
59
- const tree = items.toTree("id", "parentId");
60
- // [{ id: 1, name: "root", children: [
61
- // { id: 2, name: "child1", children: [
62
- // { id: 3, name: "grandchild", children: [] }
63
- // ]}
64
- // ]}]
65
- ```
66
-
67
- ### `diffs` 상세
68
-
69
- ```typescript
70
- const diffs = newItems.diffs(oldItems, { keys: ["id"], excludes: ["updatedAt"] });
71
- // ArrayDiffsResult: { source: undefined, target: item } (INSERT)
72
- // { source: item, target: undefined } (DELETE)
73
- // { source: item, target: item } (UPDATE)
74
- ```
75
-
76
- ### `oneWayDiffs` 상세
77
-
78
- ```typescript
79
- const diffs = newItems.oneWayDiffs(orgItems, "id", { includeSame: false });
80
- // ArrayOneWayDiffResult: { type: "create", item, orgItem: undefined }
81
- // { type: "update", item, orgItem }
82
- // { type: "same", item, orgItem }
83
- ```
84
-
85
- ## Array Extensions (Mutable)
86
-
87
- 원본 배열을 직접 변경한다.
88
-
89
- | Method | Signature | Description |
90
- |--------|-----------|-------------|
91
- | `insert` | `(index, ...items) => this` | 지정 위치에 항목 삽입 |
92
- | `remove` | `(item \| selector) => this` | 항목 또는 조건에 맞는 항목 제거 |
93
- | `toggle` | `(item) => this` | 항목 토글 (있으면 제거, 없으면 추가) |
94
- | `clear` | `() => this` | 배열 비우기 |
95
- | `distinctThis` | `(options?) => T[]` | 원본 배열에서 중복 제거 |
96
- | `orderByThis` | `(selector?) => T[]` | 원본 배열을 오름차순 정렬 |
97
- | `orderByDescThis` | `(selector?) => T[]` | 원본 배열을 내림차순 정렬 |
98
-
99
- ## Map Extensions
100
-
101
- | Method | Signature | Description |
102
- |--------|-----------|-------------|
103
- | `getOrCreate` | `(key, newValue \| newValueFn) => V` | key가 없으면 새 값을 설정하고 반환. V 타입이 함수이면 팩토리로 감싸야 함 |
104
- | `update` | `(key, updateFn) => void` | 기존 값을 기반으로 업데이트. key가 없어도 `updateFn`이 호출됨 |
105
-
106
- ```typescript
107
- const map = new Map<string, number[]>();
108
- const arr = map.getOrCreate("key", []); // 없으면 [] 설정 후 반환
109
-
110
- const countMap = new Map<string, number>();
111
- countMap.update("key", (v) => (v ?? 0) + 1); // 카운터 증가
112
- ```
113
-
114
- ## Set Extensions
115
-
116
- | Method | Signature | Description |
117
- |--------|-----------|-------------|
118
- | `adds` | `(...values: T[]) => this` | 여러 값을 한 번에 추가 |
119
- | `toggle` | `(value, addOrDel?) => this` | 값 토글. `addOrDel`로 강제 추가/제거 가능 |
120
-
121
- ```typescript
122
- const set = new Set<number>([1, 2, 3]);
123
- set.adds(4, 5, 6); // 여러 항목 추가
124
- set.toggle(2); // 2가 있으므로 제거 → {1, 3, 4, 5, 6}
125
- set.toggle(99, "add"); // 강제 추가
126
- set.toggle(99, "del"); // 강제 제거
127
- ```
128
-
129
- ## Exported Types
130
-
131
- ### `ArrayDiffsResult<TOriginal, TOther>`
132
-
133
- `diffs()` 메서드의 반환 타입. discriminated union으로 `source`와 `target` 중 하나가 `undefined`이면 INSERT/DELETE, 둘 다 있으면 UPDATE.
134
-
135
- ```typescript
136
- export type ArrayDiffsResult<TOriginal, TOther> =
137
- | { source: undefined; target: TOther } // INSERT
138
- | { source: TOriginal; target: undefined } // DELETE
139
- | { source: TOriginal; target: TOther }; // UPDATE
140
- ```
141
-
142
- ### `ArrayOneWayDiffResult<TItem>`
143
-
144
- `oneWayDiffs()` 메서드의 반환 타입. `type` 필드로 분기.
145
-
146
- ```typescript
147
- export type ArrayOneWayDiffResult<TItem> =
148
- | { type: "create"; item: TItem; orgItem: undefined }
149
- | { type: "update"; item: TItem; orgItem: TItem }
150
- | { type: "same"; item: TItem; orgItem: TItem };
151
- ```
152
-
153
- ### `TreeArray<TNode>`
154
-
155
- `toTree()` 메서드의 반환 타입. 원본 타입에 `children` 속성이 추가된다.
156
-
157
- ```typescript
158
- export type TreeArray<TNode> = TNode & { children: TreeArray<TNode>[] };
159
- ```
160
-
161
- ### `ComparableType`
162
-
163
- `orderBy`, `orderByDesc`, `orderByThis`, `orderByDescThis`의 selector 반환 타입.
164
-
165
- ```typescript
166
- export type ComparableType = string | number | boolean | DateTime | DateOnly | Time | undefined;
167
- ```
@@ -1,136 +0,0 @@
1
- # Features
2
-
3
- ## `EventEmitter<TEvents>`
4
-
5
- EventTarget 기반의 타입 안전한 이벤트 이미터. 브라우저와 Node.js 모두에서 사용 가능하다.
6
-
7
- ```typescript
8
- export class EventEmitter<
9
- TEvents extends { [K in keyof TEvents]: unknown } = Record<string, unknown>,
10
- > {
11
- on<TEventName extends keyof TEvents & string>(
12
- type: TEventName,
13
- listener: (data: TEvents[TEventName]) => void,
14
- ): void;
15
-
16
- off<TEventName extends keyof TEvents & string>(
17
- type: TEventName,
18
- listener: (data: TEvents[TEventName]) => void,
19
- ): void;
20
-
21
- emit<TEventName extends keyof TEvents & string>(
22
- type: TEventName,
23
- ...args: TEvents[TEventName] extends void ? [] : [data: TEvents[TEventName]]
24
- ): void;
25
-
26
- listenerCount<TEventName extends keyof TEvents & string>(type: TEventName): number;
27
-
28
- dispose(): void;
29
- }
30
- ```
31
-
32
- ### 메서드
33
-
34
- | Method | Description |
35
- |--------|-------------|
36
- | `on(type, listener)` | 이벤트 리스너 등록. 같은 리스너를 같은 이벤트에 중복 등록하면 무시됨 |
37
- | `off(type, listener)` | 이벤트 리스너 제거 |
38
- | `emit(type, data?)` | 이벤트 발행. `void` 타입 이벤트는 인자 없이 호출 |
39
- | `listenerCount(type)` | 특정 이벤트의 등록된 리스너 수 반환 |
40
- | `dispose()` | 모든 이벤트 리스너 제거 |
41
-
42
- ```typescript
43
- interface MyEvents {
44
- data: string;
45
- error: Error;
46
- done: void;
47
- }
48
-
49
- class MyService extends EventEmitter<MyEvents> {}
50
-
51
- const svc = new MyService();
52
- svc.on("data", (data) => console.log(data)); // data: string
53
- svc.emit("data", "hello");
54
- svc.emit("done"); // void 타입은 인자 없이 호출
55
- svc.dispose(); // 모든 리스너 정리
56
- ```
57
-
58
- ---
59
-
60
- ## `DebounceQueue`
61
-
62
- 짧은 시간 내에 여러 번 호출되면 마지막 요청만 실행하는 비동기 디바운스 큐.
63
-
64
- `EventEmitter<{ error: SdError }>`를 상속한다. 에러 리스너가 없으면 `consola`로 로그 출력한다.
65
-
66
- ```typescript
67
- export class DebounceQueue extends EventEmitter<{ error: SdError }> {
68
- constructor(delay?: number);
69
-
70
- run(fn: () => void | Promise<void>): void;
71
-
72
- override dispose(): void;
73
- }
74
- ```
75
-
76
- | Parameter | Type | Description |
77
- |-----------|------|-------------|
78
- | `delay` | `number \| undefined` | 디바운스 지연 시간 (ms). 생략 시 즉시 실행 (다음 이벤트 루프) |
79
-
80
- 실행 중에 추가된 요청은 디바운스 지연 없이 현재 실행 완료 직후 즉시 처리된다.
81
-
82
- ```typescript
83
- const dq = new DebounceQueue(300);
84
- dq.on("error", (err) => console.error(err));
85
- dq.run(() => console.log("1")); // 무시됨
86
- dq.run(() => console.log("2")); // 무시됨
87
- dq.run(() => console.log("3")); // 300ms 후 실행
88
-
89
- // 자원 정리
90
- const dq2 = new DebounceQueue(100);
91
- try {
92
- dq2.run(() => { /* ... */ });
93
- } finally {
94
- dq2.dispose();
95
- }
96
- ```
97
-
98
- ---
99
-
100
- ## `SerialQueue`
101
-
102
- 큐에 추가된 함수들을 순차적으로 실행하는 비동기 직렬 큐. 하나의 작업이 완료된 후에야 다음 작업이 시작된다. 에러가 발생해도 후속 작업은 계속 실행된다.
103
-
104
- `EventEmitter<{ error: SdError }>`를 상속한다. 에러 리스너가 없으면 `consola`로 로그 출력한다.
105
-
106
- ```typescript
107
- export class SerialQueue extends EventEmitter<{ error: SdError }> {
108
- constructor(gap?: number);
109
-
110
- run(fn: () => void | Promise<void>): void;
111
-
112
- override dispose(): void;
113
- }
114
- ```
115
-
116
- | Parameter | Type | Description |
117
- |-----------|------|-------------|
118
- | `gap` | `number` | 각 작업 사이의 간격 (ms). 기본값: 0 |
119
-
120
- `dispose()`는 대기 중인 큐를 비운다 (현재 실행 중인 작업은 완료됨).
121
-
122
- ```typescript
123
- const sq = new SerialQueue();
124
- sq.on("error", (err) => console.error(err));
125
- sq.run(async () => await fetch("/api/1"));
126
- sq.run(async () => await fetch("/api/2")); // 1 완료 후 실행
127
- sq.run(async () => await fetch("/api/3")); // 2 완료 후 실행
128
-
129
- // 100ms 간격으로 실행, 자원 정리
130
- const sq2 = new SerialQueue(100);
131
- try {
132
- sq2.run(async () => { /* ... */ });
133
- } finally {
134
- sq2.dispose();
135
- }
136
- ```