@simplysm/sd-claude 14.0.88 → 14.0.89
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/references/sd-simplysm14/README.md +17 -17
- package/claude/references/sd-simplysm14/apis/angular/README.md +27 -53
- package/claude/references/sd-simplysm14/apis/angular/controls.md +37 -105
- package/claude/references/sd-simplysm14/apis/angular/crud.md +46 -43
- package/claude/references/sd-simplysm14/apis/angular/directives.md +22 -32
- package/claude/references/sd-simplysm14/apis/angular/features.md +40 -55
- package/claude/references/sd-simplysm14/apis/angular/infra.md +40 -40
- package/claude/references/sd-simplysm14/apis/angular/layout.md +25 -53
- package/claude/references/sd-simplysm14/apis/angular/overlay.md +70 -82
- package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +44 -39
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +21 -36
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +52 -65
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +65 -70
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +33 -35
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +7 -7
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +29 -29
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +45 -50
- package/claude/references/sd-simplysm14/apis/core-browser/README.md +42 -55
- package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +62 -0
- package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +13 -12
- package/claude/references/sd-simplysm14/apis/core-common/README.md +222 -98
- package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +102 -53
- package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +128 -0
- package/claude/references/sd-simplysm14/apis/core-common/datetime.md +98 -64
- package/claude/references/sd-simplysm14/apis/core-common/errors.md +91 -0
- package/claude/references/sd-simplysm14/apis/core-common/json-transfer.md +34 -28
- package/claude/references/sd-simplysm14/apis/core-common/obj.md +104 -40
- package/claude/references/sd-simplysm14/apis/core-node/README.md +11 -8
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +23 -31
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +33 -22
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +28 -25
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +39 -53
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +26 -29
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +27 -29
- package/claude/references/sd-simplysm14/apis/excel/README.md +14 -14
- package/claude/references/sd-simplysm14/apis/lint/README.md +27 -21
- package/claude/references/sd-simplysm14/apis/lint/rules.md +89 -49
- package/claude/references/sd-simplysm14/apis/orm-common/README.md +5 -59
- package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +98 -67
- package/claude/references/sd-simplysm14/apis/orm-common/expr.md +107 -92
- package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +99 -65
- package/claude/references/sd-simplysm14/apis/orm-common/schema.md +83 -98
- package/claude/references/sd-simplysm14/apis/orm-common/types.md +62 -52
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +62 -25
- package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +27 -27
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +12 -15
- package/claude/references/sd-simplysm14/apis/sd-cli/SdTsCompiler.md +92 -45
- package/claude/references/sd-simplysm14/apis/sd-cli/sd-config-types.md +226 -108
- package/claude/references/sd-simplysm14/apis/service-client/README.md +84 -86
- package/claude/references/sd-simplysm14/apis/service-client/orm.md +14 -11
- package/claude/references/sd-simplysm14/apis/service-client/transport.md +33 -10
- package/claude/references/sd-simplysm14/apis/service-common/README.md +37 -23
- package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +9 -9
- package/claude/references/sd-simplysm14/apis/service-common/protocol.md +13 -13
- package/claude/references/sd-simplysm14/apis/service-server/README.md +81 -65
- package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +32 -35
- package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +44 -33
- package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +34 -45
- package/claude/references/sd-simplysm14/apis/storage/README.md +24 -18
- package/claude/skills/sd-demo/SKILL.md +6 -0
- package/claude/skills/sd-impl/SKILL.md +4 -7
- package/claude/skills/sd-spec/SKILL.md +31 -858
- package/claude/skills/sd-spec/references/spec-authoring.md +519 -0
- package/claude/workflows/sd-docs.js +84 -0
- package/package.json +1 -1
- package/claude/references/sd-simplysm14/apis/orm-common/query-builder.md +0 -29
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/.specs/inventory/spec.md +0 -99
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/package.json +0 -12
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/index.ts +0 -3
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/inbound/inbound.list.ts +0 -150
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/inventory/inventory-master.list.ts +0 -143
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/outbound/outbound.list.ts +0 -150
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/pnpm-workspace.yaml +0 -2
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/sd.config.ts +0 -12
- package/claude/skills/sd-demo/evals/golden.jsonl +0 -1
- package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/package.json +0 -8
- package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/src/.gitkeep +0 -0
- package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/tests/.gitkeep +0 -0
- package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/tsconfig.json +0 -10
- package/claude/skills/sd-dev/evals/golden.jsonl +0 -1
- package/claude/skills/sd-docs/SKILL.md +0 -46
- package/claude/skills/sd-docs/evals/fixtures/new-write/.claude/references/sd-simplysm14/README.md +0 -7
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/package.json +0 -5
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/src/index.ts +0 -3
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/package.json +0 -6
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/src/index.ts +0 -1
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/package.json +0 -5
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/src/index.ts +0 -8
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/README.md +0 -7
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/apis/foo/README.md +0 -3
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/package.json +0 -5
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/src/index.ts +0 -3
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/package.json +0 -6
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/src/index.ts +0 -1
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/package.json +0 -5
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/src/index.ts +0 -8
- package/claude/skills/sd-docs/evals/golden.jsonl +0 -2
- package/claude/skills/sd-impl/evals/fixtures/case-a-new-screen/.specs/260513120000_warehouse/spec.md +0 -101
- package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/.specs/260513120000_warehouse/spec.md +0 -101
- package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/packages/app/src/screens/box-register/box-register.view.ts +0 -46
- package/claude/skills/sd-impl/evals/fixtures/case-c-new-cross/.specs/260513120000_warehouse/spec.md +0 -89
- package/claude/skills/sd-impl/evals/fixtures/case-d-spec-modify/.specs/260513120000_warehouse/spec.md +0 -101
- package/claude/skills/sd-impl/evals/golden.jsonl +0 -4
- package/claude/skills/sd-manual/evals/fixtures/new-manual/src/notification.ts +0 -25
- package/claude/skills/sd-manual/evals/fixtures/update-manual/.claude/references/sd-simplysm14/manuals/notification.md +0 -14
- package/claude/skills/sd-manual/evals/fixtures/update-manual/src/notification.ts +0 -37
- package/claude/skills/sd-manual/evals/golden.jsonl +0 -2
- package/claude/skills/sd-review/evals/fixtures/code-review/src/foo.ts +0 -7
- package/claude/skills/sd-review/evals/fixtures/doc-review/docs/foo.md +0 -4
- package/claude/skills/sd-review/evals/golden.jsonl +0 -2
- package/claude/skills/sd-skill/evals/fixtures/existing-skill/.claude/skills/todo-format/SKILL.md +0 -14
- package/claude/skills/sd-skill/evals/fixtures/new-skill/.gitkeep +0 -0
- package/claude/skills/sd-skill/evals/golden.jsonl +0 -2
- package/claude/skills/sd-spec/evals/fixtures/case-a-split//355/232/214/354/235/230/353/241/235.md +0 -20
- package/claude/skills/sd-spec/evals/fixtures/case-b-detail/.specs/260513120000_warehouse/spec.md +0 -95
- package/claude/skills/sd-spec/evals/golden.jsonl +0 -2
- package/claude/skills/sd-unpack/evals/fixtures/eml-with-text-attachment/meeting.eml +0 -21
- package/claude/skills/sd-unpack/evals/fixtures/simple-eml/meeting.eml +0 -10
- package/claude/skills/sd-unpack/evals/golden.jsonl +0 -2
- package/claude/skills/sd-use/evals/fixtures/empty/.gitkeep +0 -0
- package/claude/skills/sd-use/evals/golden.jsonl +0 -6
- /package/claude/{skills/sd-docs/references/doc-rules.md → workflows/sd-docs.rules.md} +0 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# @simplysm/core-browser — DOM 요소 확장
|
|
2
|
+
|
|
3
|
+
DOM 요소를 다룰 때 함께 읽히는 묶음. `Element.prototype`/`HTMLElement.prototype` 에 등록되는 확장 메서드와, 이벤트 핸들러·다중 요소용 정적 함수(`copyElement`/`pasteToElement`/`getBounds`)로 구성. 패키지를 import 하면 프로토타입 메서드가 자동 등록되므로 별도 초기화 불필요.
|
|
4
|
+
|
|
5
|
+
## Element 확장 메서드
|
|
6
|
+
|
|
7
|
+
`Element.prototype` 에 등록. import 만으로 활성화.
|
|
8
|
+
|
|
9
|
+
- `findAll<TEl>(selector: string): TEl[]` — 선택자 일치 하위 요소를 배열로 반환. 선택자를 trim 한 결과가 빈 문자열이면 `[]`. `querySelectorAll` 결과를 NodeList 대신 배열로 받고 빈 선택자 예외를 회피할 때.
|
|
10
|
+
- `findFirst<TEl>(selector: string): TEl | undefined` — 첫 일치 하위 요소 또는 `undefined`. 빈 선택자도 `undefined`, 미일치도 `undefined`. `querySelector` 의 `null` 을 `undefined` 로 정규화한 형태.
|
|
11
|
+
- `prependChild<TEl>(child: TEl): TEl` — 자식을 첫 번째 위치(`insertBefore(child, firstElementChild)`)에 삽입하고 그 요소 반환. 맨 앞에 끼울 때.
|
|
12
|
+
- `getParents(): Element[]` — 모든 조상 요소를 가까운 것부터 먼 순서로 배열 반환. 조상 체인 순회·특정 조상 포함 판정에.
|
|
13
|
+
- `findTabbableParent(): HTMLElement | undefined` — `tabbable` 라이브러리 기준 첫 탭 이동 가능 조상. 없으면 `undefined`. 포커스 위임 대상을 위로 탐색할 때.
|
|
14
|
+
- `findFirstTabbableChild(): HTMLElement | undefined` — TreeWalker 로 순회한 첫 탭 이동 가능 하위 요소. 없으면 `undefined`. 컨테이너 진입 시 자동 포커스 대상을 찾을 때.
|
|
15
|
+
- `isOffsetElement(): boolean` — `getComputedStyle().position` 이 relative/absolute/fixed/sticky 중 하나면 true, 아니면 false. offset parent(절대배치 기준) 역할 여부 판정에.
|
|
16
|
+
- `isVisible(): boolean` — `getClientRects().length > 0` 이고 `visibility !== "hidden"` 이고 `opacity !== "0"` 를 모두 만족하면 true. 화면 표시 여부 판정에(display:none 은 clientRects 가 비어 false).
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import "@simplysm/core-browser";
|
|
20
|
+
const rows = containerEl.findAll<HTMLElement>("tr");
|
|
21
|
+
const first = containerEl.findFirstTabbableChild();
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## HTMLElement 확장 메서드
|
|
25
|
+
|
|
26
|
+
`HTMLElement.prototype` 에 등록. 위와 동일하게 import 만으로 활성화.
|
|
27
|
+
|
|
28
|
+
- `repaint(): void` — `offsetHeight` 접근으로 강제 동기 레이아웃(reflow)을 유발해 즉시 리페인트. 스타일 변경 직후 즉각 반영을 강제할 때.
|
|
29
|
+
- `getRelativeOffset(parent: HTMLElement | string): { top: number; left: number }` — 부모 기준 CSS `top`/`left` 좌표 계산. 뷰포트 위치(getBoundingClientRect)·부모 내부 스크롤(scrollTop/Left)·중간 요소 border 두께·CSS transform 까지 반영해, 드롭다운/팝업 위치 지정에 바로 쓸 수 있는 좌표 반환. 부모를 못 찾으면 `ArgumentError` throw.
|
|
30
|
+
- `parent: HTMLElement | string` — 기준 부모. 문자열이면 `this.closest(parent)` 로 조상 탐색, 요소면 직접 사용. `document.body` 나 `".container"` 식으로 지정.
|
|
31
|
+
- `scrollIntoViewIfNeeded(target, offset?): void` — 대상이 스크롤 영역의 상단/좌측 경계를 벗어났을 때만 그쪽으로 스크롤해 보이게 함. 하단/우측 방향은 처리하지 않고 브라우저 기본 포커스 스크롤에 위임. 고정 헤더/컬럼이 있는 테이블의 포커스 처리에.
|
|
32
|
+
- `target: { top: number; left: number }` — 컨테이너 내 대상 위치(offsetTop/offsetLeft 기준).
|
|
33
|
+
- `offset: { top: number; left: number }` — 가려지면 안 되는 영역 크기(고정 헤더 높이·고정 컬럼 너비). 기본 `{ top: 0, left: 0 }`.
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
const { top, left } = popupEl.getRelativeOffset(".container");
|
|
37
|
+
scrollEl.scrollIntoViewIfNeeded({ top: cellTop, left: cellLeft }, { top: headerH, left: fixedW });
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 클립보드 / 경계 측정 정적 함수
|
|
41
|
+
|
|
42
|
+
이벤트 핸들러로 붙이거나 다중 요소를 한 번에 처리하는 함수. 프로토타입 확장이 아니라 named export 이므로 직접 import.
|
|
43
|
+
|
|
44
|
+
- `copyElement(event: ClipboardEvent): void` — copy 이벤트 핸들러용. 이벤트 타겟 내 첫 `input/textarea` 의 `value` 를 클립보드 `text/plain` 으로 기록하고 `preventDefault`. clipboardData 가 없거나 타겟이 Element 가 아니거나 input 이 없으면 무동작.
|
|
45
|
+
- `event: ClipboardEvent` — copy 이벤트 객체. `el.addEventListener("copy", copyElement)` 로 등록.
|
|
46
|
+
- `pasteToElement(event: ClipboardEvent): void` — paste 이벤트 핸들러용. 타겟 내 첫 `input/textarea` 의 전체 `value` 를 클립보드 텍스트로 교체하고 `input` 이벤트 dispatch(bubbles: true) 후 `preventDefault`. 커서 위치·선택 영역은 무시하고 전체를 치환.
|
|
47
|
+
- `event: ClipboardEvent` — paste 이벤트 객체. `el.addEventListener("paste", pasteToElement)` 로 등록.
|
|
48
|
+
- `getBounds(els: Element[], timeout?: number): Promise<ElementBounds[]>` — `IntersectionObserver` 로 여러 요소의 뷰포트 기준 경계를 한 번에 측정. 중복은 제거하고 입력 순서대로 정렬해 반환. 빈 배열이면 즉시 `[]`. 모든 요소 관측 완료 시 resolve, 제한시간 초과 시 `TimeoutError` throw(어느 경우든 finally 에서 observer disconnect).
|
|
49
|
+
- `els: Element[]` — 측정 대상. 중복은 제거되고 결과는 입력 순서로 정렬됨.
|
|
50
|
+
- `timeout: number` — 제한시간(ms). 기본 `5000`. 초과 시 `TimeoutError`.
|
|
51
|
+
- `ElementBounds` (반환 항목 타입):
|
|
52
|
+
- `target: Element` — 측정된 요소.
|
|
53
|
+
- `top: number` — 뷰포트 기준 상단 위치(boundingClientRect.top).
|
|
54
|
+
- `left: number` — 뷰포트 기준 좌측 위치(boundingClientRect.left).
|
|
55
|
+
- `width: number` — 요소 너비(boundingClientRect.width).
|
|
56
|
+
- `height: number` — 요소 높이(boundingClientRect.height).
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
inputEl.addEventListener("copy", copyElement);
|
|
60
|
+
inputEl.addEventListener("paste", pasteToElement);
|
|
61
|
+
const bounds = await getBounds([elA, elB], 3000);
|
|
62
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @simplysm/core-browser — IndexedDB 저장소/가상 파일시스템
|
|
2
2
|
|
|
3
|
-
브라우저 IndexedDB 를 다룰 때 함께 읽히는 묶음. `IndexedDbStore` 는 연결·트랜잭션·KV CRUD 를 담당하고, `IndexedDbVirtualFs` 는 그 위에 경로 기반 가상 파일트리(entry put/get, prefix 삭제, 자식 나열, 디렉터리 보장)를 얹음.
|
|
3
|
+
브라우저 IndexedDB 를 다룰 때 함께 읽히는 묶음. `IndexedDbStore` 는 연결·트랜잭션·KV CRUD 를 담당하고, `IndexedDbVirtualFs` 는 그 위에 경로 키 기반 가상 파일트리(entry put/get, prefix 삭제, 자식 나열, 디렉터리 보장)를 얹음.
|
|
4
4
|
|
|
5
5
|
## IndexedDbStore
|
|
6
6
|
|
|
@@ -17,20 +17,20 @@ store.close();
|
|
|
17
17
|
|
|
18
18
|
시그니처:
|
|
19
19
|
|
|
20
|
-
- `new IndexedDbStore(dbName: string, dbVersion: number, storeConfigs: StoreConfig[])` — DB 이름·버전·스토어 설정으로 생성(연결은
|
|
20
|
+
- `new IndexedDbStore(dbName: string, dbVersion: number, storeConfigs: StoreConfig[])` — DB 이름·버전·스토어 설정으로 생성(연결은 지연, 첫 작업 시 오픈).
|
|
21
21
|
- dbName: `string` — IndexedDB 데이터베이스 이름.
|
|
22
|
-
- dbVersion: `number` — DB 버전. 올리면 `onupgradeneeded` 에서 누락 스토어를 생성.
|
|
22
|
+
- dbVersion: `number` — DB 버전. 올리면 `onupgradeneeded` 에서 누락 스토어를 생성. 스키마(스토어 추가) 변경 시 증가.
|
|
23
23
|
- storeConfigs: `StoreConfig[]` — 생성할 오브젝트 스토어 목록.
|
|
24
|
-
- `StoreConfig` — 스토어
|
|
24
|
+
- `StoreConfig` — 스토어 설정 항목.
|
|
25
25
|
- name: `string` — 오브젝트 스토어 이름. upgrade 시 미존재면 `createObjectStore` 로 생성.
|
|
26
26
|
- keyPath: `string` — 스토어 keyPath(레코드에서 키로 쓸 속성명).
|
|
27
|
-
- `open(): Promise<IDBDatabase>` — 연결을 열어 반환. 이미 열렸으면 캐시 반환, 진행 중이면 같은 Promise
|
|
27
|
+
- `open(): Promise<IDBDatabase>` — 연결을 열어 반환. 이미 열렸으면 캐시 반환, 진행 중이면 같은 Promise 공유(중복 오픈 방지). `onupgradeneeded` 시 없는 스토어만 생성. `onversionchange`/`onclose` 시 내부 캐시(`_db`/`_opening`)를 해제해 다음 호출에 재오픈. `onblocked` 면 `Error("다른 연결에 의해 데이터베이스가 차단되었습니다")`, `onerror` 면 원본 에러로 reject. CRUD 가 자동 호출하므로 직접 호출 불필요.
|
|
28
28
|
- `withStore<TResult>(storeName, mode, fn): Promise<TResult>` — 트랜잭션 1건 안에서 `fn(store)` 실행 후 완료까지 대기. `fn` 이 throw 하면 `tx.abort()` 후 그 에러로 reject(롤백), 정상이면 `oncomplete` 시 결과 resolve, `onerror` 면 `tx.error` 로 reject. 커서 등 저수준 IDB 작업을 감쌀 때.
|
|
29
29
|
- storeName: `string` — 트랜잭션 대상 스토어.
|
|
30
|
-
- mode: `IDBTransactionMode` — `"readonly"` | `"readwrite"` | `"versionchange"`.
|
|
30
|
+
- mode: `IDBTransactionMode` — `"readonly"`(읽기 전용) | `"readwrite"`(읽기·쓰기) | `"versionchange"`. 쓰기 작업이면 `"readwrite"`.
|
|
31
31
|
- fn: `(store: IDBObjectStore) => Promise<TResult>` — 스토어를 받아 작업하는 콜백.
|
|
32
|
-
- `get<TValue>(storeName, key): Promise<TValue | undefined>` — 키로 단건 조회. 미존재 시 `undefined
|
|
33
|
-
- `put(storeName, value): Promise<void>` — 레코드 upsert
|
|
32
|
+
- `get<TValue>(storeName, key): Promise<TValue | undefined>` — 키로 단건 조회. 미존재 시 `undefined`(결측 그대로 반환).
|
|
33
|
+
- `put(storeName, value): Promise<void>` — 레코드 upsert. value 에 keyPath 속성이 포함돼야 함.
|
|
34
34
|
- `delete(storeName, key): Promise<void>` — 키로 단건 삭제.
|
|
35
35
|
- `getAll<TItem>(storeName): Promise<TItem[]>` — 스토어 전체 레코드 배열 반환.
|
|
36
36
|
- `close(): void` — 연결을 닫고 내부 캐시 해제. 다음 작업 시 재오픈. 페이지 정리 시 호출.
|
|
@@ -42,7 +42,7 @@ store.close();
|
|
|
42
42
|
|
|
43
43
|
## IndexedDbVirtualFs
|
|
44
44
|
|
|
45
|
-
`IndexedDbStore` 한 스토어를 경로 키 기반 가상 파일시스템처럼 다루는 래퍼. 키는 `keyField` 속성에 들어가는 전체 경로 문자열이고, 각 레코드는 `VirtualFsEntry`(파일/디렉터리 + 선택적 base64 데이터)
|
|
45
|
+
`IndexedDbStore` 의 한 스토어를 경로 키 기반 가상 파일시스템처럼 다루는 래퍼. 키는 `keyField` 속성에 들어가는 전체 경로 문자열이고, 각 레코드는 `VirtualFsEntry`(파일/디렉터리 + 선택적 base64 데이터).
|
|
46
46
|
|
|
47
47
|
```ts
|
|
48
48
|
const fs = new IndexedDbVirtualFs(store, "files", "key");
|
|
@@ -58,18 +58,19 @@ const ok = await fs.deleteByPrefix("/root/a"); // 하위 전체 삭제, 삭제
|
|
|
58
58
|
- db: `IndexedDbStore` — 백엔드 저장소.
|
|
59
59
|
- storeName: `string` — 사용할 오브젝트 스토어 이름.
|
|
60
60
|
- keyField: `string` — 레코드에서 경로 키를 담는 속성명(스토어 keyPath 와 일치해야 함).
|
|
61
|
-
- `VirtualFsEntry` — 저장
|
|
61
|
+
- `VirtualFsEntry` — 저장 엔트리 타입.
|
|
62
62
|
- kind: `"file" | "dir"` — 엔트리 종류. `"file"` = 파일, `"dir"` = 디렉터리. 자식 나열·디렉터리 판정에 사용.
|
|
63
63
|
- dataBase64: `string` — 파일 내용 base64. 디렉터리거나 빈 파일이면 생략(undefined).
|
|
64
64
|
- `getEntry(fullKey): Promise<VirtualFsEntry | undefined>` — 전체 경로 키로 단건 조회. 미존재 시 `undefined`.
|
|
65
65
|
- `putEntry(fullKey, kind, dataBase64?): Promise<void>` — 엔트리 저장. `keyField` 에 `fullKey`, 그리고 `kind`/`dataBase64` 를 함께 기록.
|
|
66
|
+
- fullKey: `string` — 저장할 전체 경로 키.
|
|
66
67
|
- kind: `"file" | "dir"` — 저장할 엔트리 종류.
|
|
67
68
|
- dataBase64: `string` — 파일 데이터(base64). 디렉터리면 생략.
|
|
68
|
-
- `deleteByPrefix(keyPrefix): Promise<boolean>` — 커서로 키가 `keyPrefix` 자신이거나 `keyPrefix + "/"` 로 시작하는 엔트리 전부 삭제(
|
|
69
|
+
- `deleteByPrefix(keyPrefix): Promise<boolean>` — 커서로 키가 `keyPrefix` 자신이거나 `keyPrefix + "/"` 로 시작하는 엔트리 전부 삭제(같은 접두어를 가진 다른 형제 경로 오삭제 방지). 하나라도 지웠으면 `true`, 없으면 `false`. 디렉터리 트리 통째 삭제에.
|
|
69
70
|
- `listChildren(prefix): Promise<{ name: string; isDirectory: boolean }[]>` — `prefix` 직계 자식만 집계. 키에서 prefix 제거 후 첫 세그먼트를 이름으로 삼고, 하위 세그먼트가 더 있거나 엔트리 `kind === "dir"` 면 디렉터리로 판정. 디렉터리 목록 표시용(재귀 아님).
|
|
70
71
|
- 반환 항목 name: `string` — 직계 자식 이름(첫 경로 세그먼트).
|
|
71
72
|
- 반환 항목 isDirectory: `boolean` — 디렉터리 여부.
|
|
72
|
-
- `ensureDir(fullKeyBuilder, dirPath): Promise<void>` — `dirPath` 상의 각 중간 디렉터리를 부모부터 누적 경로마다 없으면 생성. `dirPath === "/"` 면 루트 1건만 생성. 단일 `withStore` 트랜잭션으로 처리(원자적). 파일 쓰기 전 상위 디렉터리 보장에.
|
|
73
|
+
- `ensureDir(fullKeyBuilder, dirPath): Promise<void>` — `dirPath` 상의 각 중간 디렉터리를 부모부터 누적 경로마다 없으면 생성. `dirPath === "/"` 면 루트 1건만 생성. 단일 `withStore("readwrite")` 트랜잭션으로 처리(원자적). 파일 쓰기 전 상위 디렉터리 보장에.
|
|
73
74
|
- fullKeyBuilder: `(path: string) => string` — 누적 경로(예: `/a`, `/a/b`)를 실제 저장 key 로 변환하는 콜백.
|
|
74
75
|
- dirPath: `string` — 보장할 디렉터리 경로(`/` 구분). 빈 세그먼트는 무시.
|
|
75
76
|
|
|
@@ -1,138 +1,262 @@
|
|
|
1
1
|
# @simplysm/core-common
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
런타임 무관(Node.js·브라우저·Worker) 공통 유틸리티 패키지. 값 타입(날짜·UUID), 에러 트리, 비동기 큐/이벤트, Array/Set/Map 프로토타입 확장, 객체/문자열/숫자/바이트/경로/JSON/XML 유틸 네임스페이스를 제공. 패키지를 import 하면 부수효과로 `Array`/`Set`/`Map` 프로토타입 확장이 주입된다.
|
|
4
4
|
|
|
5
5
|
## 사용 트리거 인덱스
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
- **
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
7
|
+
- **에러 클래스** (`SdError`/`ArgumentError`/`NotImplementedError`/`TimeoutError`) — 원인 체인을 가진 에러를 throw 하거나 `instanceof` 로 분기할 때. 자세히: [errors.md](./errors.md)
|
|
8
|
+
- **날짜/시간 값 타입** (`DateTime`/`DateOnly`/`Time`, `dt` 네임스페이스) — 불변 날짜·시간 값을 만들고 파싱·산술·포맷할 때. 자세히: [datetime.md](./datetime.md)
|
|
9
|
+
- **Array 확장 메서드** (`Array.prototype` 전역 확장) — `single`/`groupBy`/`distinct`/`orderBy`/`diffs`/`toTree` 등 컬렉션 가공이 필요할 때. 자세히: [array-ext.md](./array-ext.md)
|
|
10
|
+
- **객체 유틸** (`obj` 네임스페이스, `DeepPartial`/`Type`) — 깊은 복사·동등성·병합·체인 경로 접근·타입 안전 키 순회가 필요할 때. 자세히: [obj.md](./obj.md)
|
|
11
|
+
- **JSON/Worker 직렬화** (`json`/`transfer` 네임스페이스) — 커스텀 타입(날짜·UUID·Map·Set·Error)을 보존하며 JSON 또는 Worker 메시지로 직렬화할 때. 자세히: [json-transfer.md](./json-transfer.md)
|
|
12
|
+
- **비동기 런타임** (`DebounceQueue`/`SerialQueue`/`EventEmitter`/`LazyGcMap`/`createLogger`) — 디바운스·직렬 실행·타입 안전 이벤트·자동 만료 캐시·태그 로거가 필요할 때. 자세히: [async-runtime.md](./async-runtime.md)
|
|
13
|
+
- **`Uuid`** — UUID v4 생성·검증·바이트 변환이 필요할 때. (아래 인라인 "값 타입 보조 — Uuid")
|
|
14
|
+
- **환경변수** (`env`/`parseBoolEnv`) — process.env / import.meta.env 를 런타임 무관하게 읽고 쓸 때. (아래 인라인 "환경변수")
|
|
15
|
+
- **Set/Map 확장** (`Set.prototype.adds`/`toggle`, `Map.prototype.getOrCreate`/`update`) — Set/Map 을 체이닝으로 다룰 때. (아래 인라인 "Set/Map 확장")
|
|
16
|
+
- **문자열 유틸** (`str` 네임스페이스) — 한국어 조사·케이스 변환·전각 변환·빈 문자열 가드가 필요할 때. (아래 인라인 "str")
|
|
17
|
+
- **숫자 유틸** (`num` 네임스페이스) — 느슨한 정수/실수 파싱·천단위 포맷이 필요할 때. (아래 인라인 "num")
|
|
18
|
+
- **바이트 유틸** (`bytes` 네임스페이스) — Uint8Array hex/base64/concat 변환이 필요할 때. (아래 인라인 "bytes")
|
|
19
|
+
- **경로 유틸** (`path` 네임스페이스) — 브라우저에서 POSIX 경로 join/basename/extname 이 필요할 때. (아래 인라인 "path")
|
|
20
|
+
- **XML 유틸** (`xml` 네임스페이스) — XML 파싱/직렬화가 필요할 때. (아래 인라인 "xml")
|
|
21
|
+
- **대기 유틸** (`wait` 네임스페이스) — 조건 폴링·지연이 필요할 때. (아래 인라인 "wait")
|
|
22
|
+
- **에러 메시지 추출** (`err` 네임스페이스) — catch 의 `unknown` 에서 메시지 문자열을 뽑을 때. (아래 인라인 "err")
|
|
23
|
+
- **원시 타입 추론** (`primitive` 네임스페이스, `PrimitiveType*`/`Bytes`) — 런타임 값에서 ORM 원시 타입 문자열을 얻을 때. (아래 인라인 "primitive / 공통 타입")
|
|
24
|
+
- **코드 템플릿 태그** (`js`/`ts`/`html`/`tsql`/`mysql`/`pgsql`) — IDE 하이라이팅 + 들여쓰기 정규화가 필요할 때. (아래 인라인 "템플릿 태그")
|
|
25
|
+
- **`ZipArchive`** — ZIP 읽기/쓰기/압축/해제가 필요할 때. (아래 인라인 "ZipArchive")
|
|
26
|
+
|
|
27
|
+
## 값 타입 보조 — Uuid
|
|
18
28
|
|
|
19
|
-
|
|
29
|
+
```typescript
|
|
30
|
+
class Uuid {
|
|
31
|
+
static generate(): Uuid; // crypto.getRandomValues 기반 v4 생성
|
|
32
|
+
static fromBytes(bytes: Bytes): Uuid; // 16바이트 Uint8Array → Uuid (16바이트 아니면 ArgumentError)
|
|
33
|
+
constructor(uuid: string); // 형식 검증 후 보관 (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, 위반 시 ArgumentError)
|
|
34
|
+
toString(): string; // UUID 문자열 반환
|
|
35
|
+
toBytes(): Bytes; // 16바이트 Uint8Array 반환
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- `generate()` — 새 랜덤 UUID 가 필요할 때(엔티티 PK 등). 암호학적으로 안전한 난수 사용.
|
|
40
|
+
- `fromBytes(bytes)` / `toBytes()` — 바이너리 저장/전송과 문자열 표현 사이를 오갈 때. 입력 바이트 길이가 16 이 아니면 `ArgumentError` throw.
|
|
41
|
+
- `new Uuid(str)` — 외부에서 받은 문자열을 검증해 값으로 승격할 때. 형식 불일치 시 `ArgumentError` throw.
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
const id = Uuid.generate();
|
|
45
|
+
const restored = new Uuid(id.toString());
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 환경변수 — env / parseBoolEnv
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
function env(key: string): string | undefined; // 읽기: process.env 우선, 없으면 import.meta.env
|
|
52
|
+
function env(key: string, value: string): void; // 쓰기: process.env[key] = value (process 존재 시)
|
|
53
|
+
function parseBoolEnv(value: unknown): boolean; // "true"/"1"/"yes"/"on"(대소문자 무시) → true, 그 외 false
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- `env(key)` — 단일 인자. Node 면 `process.env`, 브라우저(Vite) 면 `import.meta.env` 에서 조회. 둘 다 없으면 `undefined`. "값 없음"을 빈 문자열로 치환하지 않음.
|
|
57
|
+
- `env(key, value)` — 2번째 인자 전달 시 쓰기 모드. `process` 가 없는 환경(순수 브라우저)에서는 아무 동작 안 함.
|
|
58
|
+
- `parseBoolEnv(value)` — boolean 플래그용 환경변수를 해석할 때. 위 4개 리터럴만 true.
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
if (parseBoolEnv(env("DEV"))) { /* 개발 모드 */ }
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Set/Map 확장
|
|
65
|
+
|
|
66
|
+
전역 `Set.prototype` / `Map.prototype` 에 메서드를 추가(import 시 자동 적용, `enumerable: false`).
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
interface Set<T> {
|
|
70
|
+
adds(...values: T[]): this; // 여러 값 일괄 추가, this 반환(체이닝)
|
|
71
|
+
toggle(value: T, addOrDel?: "add" | "del"): this; // 토글: 인자 생략 시 있으면 제거/없으면 추가
|
|
72
|
+
}
|
|
73
|
+
interface Map<K, V> {
|
|
74
|
+
getOrCreate(key: K, newValue: V): V; // 값 직접 지정 (key 없을 때만 set)
|
|
75
|
+
getOrCreate(key: K, newValueFn: () => V): V; // 팩토리 지연 생성 (비싼 연산용)
|
|
76
|
+
update(key: K, updateFn: (v: V | undefined) => V): void; // 현재 값(없으면 undefined) → 새 값으로 갱신
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
- `Set.toggle(value, addOrDel)` — `addOrDel` 생략 시 존재 여부로 자동 토글, `"add"` 면 강제 추가, `"del"` 면 강제 제거. 조건부 선택 상태(`isOn ? "add" : "del"`) 표현에 사용.
|
|
81
|
+
- `Map.getOrCreate` — 2번째 인자가 함수면 팩토리로 인식되어 호출됨. 함수 자체를 값으로 저장하려면 `() => myFn` 처럼 한 번 더 감싼다.
|
|
82
|
+
- `Map.update` — key 가 없어도 `updateFn(undefined)` 가 호출되어 새 값이 set 됨. 카운터 증가(`(v) => (v ?? 0) + 1`)·배열 누적에 사용.
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
new Set([1, 2]).adds(3, 4).toggle(2); // {1, 3, 4}
|
|
86
|
+
countMap.update("k", (v) => (v ?? 0) + 1);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## str
|
|
90
|
+
|
|
91
|
+
`import * as str` 로 사용하는 문자열 유틸 네임스페이스.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
str.getKoreanSuffix(text: string, type: "을"|"은"|"이"|"와"|"랑"|"로"|"라"): string;
|
|
95
|
+
str.replaceFullWidth(str: string): string;
|
|
96
|
+
str.toPascalCase(str: string): string;
|
|
97
|
+
str.toCamelCase(str: string): string;
|
|
98
|
+
str.toKebabCase(str: string): string;
|
|
99
|
+
str.toSnakeCase(str: string): string;
|
|
100
|
+
str.isNullOrEmpty(str: string | undefined): str is "" | undefined;
|
|
101
|
+
str.insert(str: string, index: number, insertString: string): string;
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- `getKoreanSuffix(text, type)` — 마지막 글자 받침 유무로 조사 선택. `type` 은 쌍의 대표 글자: `"을"`=을/를, `"은"`=은/는, `"이"`=이/가, `"와"`=과/와, `"랑"`=이랑/랑, `"로"`=으로/로(단 받침 ㄹ이면 "로"), `"라"`=이라/라. 한글 아닌 글자로 끝나면 받침 없음 처리.
|
|
105
|
+
- `replaceFullWidth(str)` — 전각 영문/숫자/공백/괄호를 반각으로. 스캔된 바코드·일본어 입력 정규화에 사용.
|
|
106
|
+
- `toPascalCase`/`toCamelCase`/`toKebabCase`/`toSnakeCase` — `-` `_` `.` 구분자 또는 대문자 경계 기준 케이스 변환. kebab/snake 는 연속 대문자를 각각 분리(`XMLParser`→`x-m-l-parser`)하고 기존 구분자는 보존.
|
|
107
|
+
- `isNullOrEmpty(str)` — 타입 가드. true 면 `"" | undefined`, false 면 비어있지 않은 `string` 으로 좁혀짐.
|
|
108
|
+
- `insert(str, index, insertString)` — 지정 위치에 삽입한 새 문자열 반환(원본 불변).
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
str.getKoreanSuffix("사과", "을"); // "를"
|
|
112
|
+
str.toKebabCase("HelloWorld"); // "hello-world"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## num
|
|
20
116
|
|
|
21
|
-
|
|
117
|
+
```typescript
|
|
118
|
+
num.parseInt(text: unknown): number | undefined; // 비숫자 제거 후 정수 (소수점 이하 버림)
|
|
119
|
+
num.parseFloat(text: unknown): number | undefined; // 비숫자 제거 후 실수
|
|
120
|
+
num.parseRoundedInt(text: unknown): number | undefined; // parseFloat 후 반올림
|
|
121
|
+
num.isNullOrEmpty(val: number | undefined): val is 0 | undefined;
|
|
122
|
+
num.format(val: number, digit?: { max?: number; min?: number }): string;
|
|
123
|
+
```
|
|
22
124
|
|
|
23
|
-
- `
|
|
24
|
-
- `
|
|
25
|
-
- `
|
|
26
|
-
- `
|
|
125
|
+
- `parseInt`/`parseFloat` — `0-9 . -` 외 문자를 제거하고 파싱. 선행 `-` 만 음수 부호로 유지하고 중간 하이픈은 제거(`"010-1234"`→`101234`). 파싱 불가 시 결측(`undefined`) 그대로 반환. 숫자 입력은 그대로(정수는 trunc).
|
|
126
|
+
- `parseRoundedInt` — 소수 반올림이 필요할 때(`"12.6"`→13).
|
|
127
|
+
- `isNullOrEmpty(val)` — 타입 가드. null/undefined/0 이면 true → `0 | undefined`. "0 과 미입력을 같이 비움 처리"가 필요한 화면 가드용.
|
|
128
|
+
- `format(val, digit)` — `toLocaleString` 기반 천단위 구분. `digit.max` 최대 소수 자릿수, `digit.min` 최소(부족분 0 채움). `val` 이 결측이면 결과도 `undefined`(오버로드).
|
|
27
129
|
|
|
28
130
|
```typescript
|
|
29
|
-
|
|
30
|
-
|
|
131
|
+
num.parseInt("1,234원"); // 1234
|
|
132
|
+
num.format(1234.5, { min: 2 }); // "1,234.50"
|
|
31
133
|
```
|
|
32
134
|
|
|
33
|
-
##
|
|
135
|
+
## bytes
|
|
34
136
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
137
|
+
```typescript
|
|
138
|
+
bytes.concat(arrays: Bytes[]): Bytes;
|
|
139
|
+
bytes.toHex(bytes: Bytes): string; // 소문자 hex
|
|
140
|
+
bytes.fromHex(hex: string): Bytes; // 홀수 길이/비hex 문자 → ArgumentError
|
|
141
|
+
bytes.toBase64(bytes: Bytes): string;
|
|
142
|
+
bytes.fromBase64(base64: string): Bytes; // 비base64 문자/잘못된 길이 → ArgumentError
|
|
143
|
+
```
|
|
38
144
|
|
|
39
|
-
|
|
145
|
+
- `concat(arrays)` — 여러 Uint8Array 를 하나로 이어붙인 새 배열. 청크 결합에 사용.
|
|
146
|
+
- `toHex`/`fromHex` — 바이너리를 16진 문자열로 표기/복원. `fromHex` 는 길이가 짝수이고 `[0-9a-fA-F]` 만 허용(위반 시 throw).
|
|
147
|
+
- `toBase64`/`fromBase64` — Node 의존 없는 자체 구현 base64. `fromBase64` 는 공백/패딩 정규화 후 검증, 길이 나머지 1 이면 throw.
|
|
40
148
|
|
|
41
|
-
|
|
149
|
+
## path
|
|
42
150
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
151
|
+
```typescript
|
|
152
|
+
path.join(...segments: string[]): string; // POSIX(슬래시) join, 중복 슬래시 정리
|
|
153
|
+
path.basename(filePath: string, ext?: string): string; // 마지막 세그먼트, ext 일치 시 제거
|
|
154
|
+
path.extname(filePath: string): string; // 확장자(점 포함), 숨김파일은 ""
|
|
155
|
+
```
|
|
48
156
|
|
|
49
|
-
|
|
157
|
+
- POSIX 슬래시(`/`) 전용. Windows 백슬래시 경로는 미지원. 브라우저·Capacitor 환경에서 Node `path` 대체용.
|
|
158
|
+
- `basename(p, ext)` — `ext` 가 끝과 일치하면 그만큼 잘라 확장자 없는 이름 반환.
|
|
159
|
+
- `extname` — `.gitignore` 같은 선행 점 파일은 빈 문자열(`""`).
|
|
50
160
|
|
|
51
|
-
|
|
52
|
-
- `new LazyGcMap({ gcInterval?, expireTime, onExpire? })` — `expireTime`(ms): 마지막 접근 후 이 시간 지나면 삭제. `gcInterval`(ms): GC 주기, 기본 `expireTime/10`(최소 1000). `onExpire(key, value)`: 만료 시 콜백(async 가능, 에러 시 로그 후 계속).
|
|
53
|
-
- `get(key)` — 조회(접근시간 갱신). `has(key)` — 존재 확인(갱신 안 함). `set(key, value)` — 저장(첫 set 에 GC 타이머 시작). `delete(key)` / `clear()`(인스턴스 재사용 가능) / `dispose()`(이후 사용 불가).
|
|
54
|
-
- `getOrCreate(key, factory)` — 없으면 `factory()` 로 생성·저장(dispose 후 호출 시 throw).
|
|
55
|
-
- `size` getter, `keys()`/`values()`/`entries()` 이터레이터.
|
|
161
|
+
## xml
|
|
56
162
|
|
|
57
|
-
|
|
163
|
+
```typescript
|
|
164
|
+
xml.parse(str: string, options?: { stripTagPrefix?: boolean }): unknown;
|
|
165
|
+
xml.stringify(obj: unknown, options?: XmlBuilderOptions): string;
|
|
166
|
+
```
|
|
58
167
|
|
|
59
|
-
|
|
168
|
+
- `parse` — `fast-xml-parser` 기반. 속성은 `$` 객체, 텍스트는 `_` 키, 자식 요소는 배열로. `stripTagPrefix: true` 면 `ns:tag` 의 네임스페이스 접두사 제거(속성 접두사는 유지).
|
|
169
|
+
- `stringify` — `$`(속성)·`_`(텍스트) 규약으로 XML 문자열 생성. `options` 로 fast-xml-parser 빌더 옵션 덮어쓰기.
|
|
60
170
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
- `dispose()` — 모든 리스너 제거.
|
|
171
|
+
```typescript
|
|
172
|
+
xml.parse('<root id="1"><item>hi</item></root>');
|
|
173
|
+
// { root: { $: { id: "1" }, item: [{ _: "hi" }] } }
|
|
174
|
+
```
|
|
66
175
|
|
|
67
|
-
|
|
176
|
+
## wait
|
|
68
177
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
178
|
+
```typescript
|
|
179
|
+
wait.until(forwarder: () => boolean | Promise<boolean>, milliseconds?: number, maxCount?: number): Promise<void>;
|
|
180
|
+
wait.time(millisecond: number): Promise<void>;
|
|
181
|
+
```
|
|
73
182
|
|
|
74
|
-
|
|
183
|
+
- `until(fn, interval, maxCount)` — `fn` 이 true 될 때까지 `interval`(기본 100ms) 간격으로 폴링. 첫 호출에서 true 면 즉시 반환. `maxCount` 지정 시 초과하면 `TimeoutError` throw(미지정이면 무제한).
|
|
184
|
+
- `time(ms)` — `setTimeout` 기반 지연 Promise.
|
|
75
185
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
186
|
+
```typescript
|
|
187
|
+
await wait.until(() => ready, 100, 50); // 최대 50회(5초) 폴링
|
|
188
|
+
await wait.time(300);
|
|
189
|
+
```
|
|
80
190
|
|
|
81
|
-
|
|
191
|
+
## err
|
|
82
192
|
|
|
83
|
-
|
|
193
|
+
```typescript
|
|
194
|
+
err.message(error: unknown): string; // Error 면 .message, 아니면 String(error)
|
|
195
|
+
```
|
|
84
196
|
|
|
85
|
-
|
|
197
|
+
- catch 블록의 `unknown` 에러에서 안전하게 메시지 문자열을 뽑을 때.
|
|
86
198
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
- `str.toPascalCase`/`toCamelCase`/`toKebabCase`/`toSnakeCase(s)` — 케이스 변환(연속 대문자 분리, 기존 구분자 유지).
|
|
91
|
-
- `str.isNullOrEmpty(s): s is "" | undefined` — null/undefined/빈 문자열 타입 가드.
|
|
92
|
-
- `str.insert(s, index, insertString)` — 지정 위치에 문자열 삽입.
|
|
199
|
+
```typescript
|
|
200
|
+
try { /* ... */ } catch (e) { logger.error(err.message(e)); }
|
|
201
|
+
```
|
|
93
202
|
|
|
94
|
-
|
|
95
|
-
- `num.parseInt(text)` / `num.parseFloat(text)` — 비숫자 문자 제거 후 파싱(선행 `-` 만 음수 부호 유지). 실패 시 `undefined`. parseInt 는 소수부 버림.
|
|
96
|
-
- `num.parseRoundedInt(text)` — float 파싱 후 반올림 정수.
|
|
97
|
-
- `num.isNullOrEmpty(val): val is 0 | undefined` — null/undefined/0 타입 가드.
|
|
98
|
-
- `num.format(val, digit?)` — 천 단위 구분 문자열. `digit: { max?, min? }` 소수 자릿수(min 부족분 0 채움). val 이 undefined 면 undefined.
|
|
203
|
+
## primitive / 공통 타입
|
|
99
204
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
- `bytes.toHex(bytes)` / `bytes.fromHex(hex)` — hex 왕복(소문자 출력. fromHex 는 홀수 길이·비hex 문자 시 `ArgumentError`).
|
|
103
|
-
- `bytes.toBase64(bytes)` / `bytes.fromBase64(base64)` — base64 왕복(fromBase64 는 공백·패딩 정규화, 잘못된 문자·길이 시 `ArgumentError`).
|
|
205
|
+
```typescript
|
|
206
|
+
primitive.typeStr(value: PrimitiveTypeMap[PrimitiveTypeStr]): PrimitiveTypeStr; // 런타임 값 → 원시 타입 문자열
|
|
104
207
|
|
|
105
|
-
|
|
106
|
-
|
|
208
|
+
type Bytes = Uint8Array;
|
|
209
|
+
type PrimitiveTypeMap = { string; number; boolean; DateTime; DateOnly; Time; Uuid; Bytes };
|
|
210
|
+
type PrimitiveTypeStr = keyof PrimitiveTypeMap;
|
|
211
|
+
type PrimitiveType = PrimitiveTypeMap[PrimitiveTypeStr] | undefined;
|
|
212
|
+
```
|
|
107
213
|
|
|
108
|
-
|
|
109
|
-
- `
|
|
110
|
-
- `
|
|
214
|
+
- `primitive.typeStr(value)` — 값의 런타임 타입을 보고 `"string"|"number"|"boolean"|"DateTime"|"DateOnly"|"Time"|"Uuid"|"Bytes"` 중 하나 반환. 위 8종 외 값이면 `ArgumentError` throw. ORM 컬럼 타입 추론과 공유.
|
|
215
|
+
- `Bytes` — 바이너리 표준 별칭(`Uint8Array`). Buffer 대신 사용.
|
|
216
|
+
- `PrimitiveType` — 원시 타입 union + `undefined`. 결측 보존을 위해 `undefined` 포함.
|
|
217
|
+
- `DeepPartial<T>` / `Type<T>` 타입 유틸은 [obj.md](./obj.md) 의 "타입 유틸리티" 참조.
|
|
111
218
|
|
|
112
|
-
|
|
113
|
-
- `err.message(error): string` — `unknown` 에러에서 메시지 추출(`Error` 면 `.message`, 아니면 `String()`). catch 블록용.
|
|
219
|
+
## 템플릿 태그
|
|
114
220
|
|
|
115
|
-
|
|
116
|
-
|
|
221
|
+
```typescript
|
|
222
|
+
js / ts / html / tsql / mysql / pgsql (strings: TemplateStringsArray, ...values: unknown[]): string;
|
|
223
|
+
```
|
|
117
224
|
|
|
118
|
-
|
|
225
|
+
- 6개 태그 모두 동작은 동일: 보간 후 공통 들여쓰기 제거 + 앞뒤 빈 줄 trim. 차이는 IDE 의 언어 하이라이팅 힌트뿐(태그 이름이 곧 언어). 보간 값이 null/undefined 면 빈 문자열로 치환.
|
|
119
226
|
|
|
120
|
-
|
|
121
|
-
|
|
227
|
+
```typescript
|
|
228
|
+
const sql = mysql`
|
|
229
|
+
SELECT *
|
|
230
|
+
FROM users
|
|
231
|
+
`; // 공통 들여쓰기가 제거된 두 줄
|
|
232
|
+
```
|
|
122
233
|
|
|
123
|
-
|
|
124
|
-
ZIP 읽기/쓰기/압축/해제 클래스. 내부 캐시로 중복 해제 방지. **사용 후 `close()` 필수**.
|
|
125
|
-
- `new ZipArchive(data?)` — `data`(`Blob | Bytes`) 생략 시 새 아카이브.
|
|
126
|
-
- `get(fileName): Promise<Bytes | undefined>` — 특정 파일 추출. `exists(fileName): Promise<boolean>` — 존재 확인.
|
|
127
|
-
- `extractAll(progressCallback?): Promise<Map<string, Bytes | undefined>>` — 전체 추출. `progressCallback(progress)` 의 `progress: ZipArchiveProgress { fileName, totalSize, extractedSize }`.
|
|
128
|
-
- `write(fileName, bytes)` — 캐시에 파일 추가. `compress(): Promise<Bytes>` — 캐시 내용을 ZIP 으로 압축(내부에서 extractAll 호출, 대용량 메모리 주의). `close()` — 리더 닫고 캐시 비움.
|
|
234
|
+
## ZipArchive
|
|
129
235
|
|
|
130
|
-
|
|
236
|
+
```typescript
|
|
237
|
+
class ZipArchive {
|
|
238
|
+
constructor(data?: Blob | Bytes); // 데이터 생략 시 새(쓰기용) 아카이브
|
|
239
|
+
extractAll(progressCallback?: (p: { fileName: string; totalSize: number; extractedSize: number }) => void): Promise<Map<string, Bytes | undefined>>;
|
|
240
|
+
get(fileName: string): Promise<Bytes | undefined>;
|
|
241
|
+
exists(fileName: string): Promise<boolean>;
|
|
242
|
+
write(fileName: string, bytes: Bytes): void; // 캐시에만 기록
|
|
243
|
+
compress(): Promise<Bytes>;
|
|
244
|
+
close(): Promise<void>;
|
|
245
|
+
}
|
|
246
|
+
```
|
|
131
247
|
|
|
132
|
-
`
|
|
133
|
-
- `
|
|
134
|
-
- `
|
|
135
|
-
- `
|
|
136
|
-
- `
|
|
137
|
-
- `
|
|
138
|
-
|
|
248
|
+
- `constructor(data)` — `Blob`/`Bytes` 전달 시 읽기용, 생략 시 쓰기용 빈 아카이브.
|
|
249
|
+
- `get`/`exists` — 단일 파일 추출/존재 확인. 결과는 내부 캐시에 보관해 재추출 방지.
|
|
250
|
+
- `extractAll(cb)` — 전체 추출. `cb` 는 파일별 진행(`fileName`, 전체 바이트 `totalSize`, 누적 추출 `extractedSize`)을 보고.
|
|
251
|
+
- `write(name, bytes)` — 캐시에만 기록. 실제 압축 산출은 `compress()` 호출 시.
|
|
252
|
+
- `compress()` — 캐시(필요 시 `extractAll`)의 모든 파일을 ZIP 바이트로. 대용량은 전부 메모리 로드되므로 주의.
|
|
253
|
+
- `close()` — 리더 닫고 캐시 비움. `try/finally` 에서 호출 권장.
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
const archive = new ZipArchive(zipBytes);
|
|
257
|
+
try {
|
|
258
|
+
const content = await archive.get("file.txt");
|
|
259
|
+
} finally {
|
|
260
|
+
await archive.close();
|
|
261
|
+
}
|
|
262
|
+
```
|