@simplysm/sd-claude 14.0.91 → 14.0.93
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 +7 -6
- package/claude/references/sd-simplysm14/apis/angular/README.md +59 -39
- package/claude/references/sd-simplysm14/apis/angular/controls.md +119 -186
- package/claude/references/sd-simplysm14/apis/angular/crud.md +70 -31
- package/claude/references/sd-simplysm14/apis/angular/directives.md +55 -57
- package/claude/references/sd-simplysm14/apis/angular/features.md +86 -105
- package/claude/references/sd-simplysm14/apis/angular/infra.md +48 -57
- package/claude/references/sd-simplysm14/apis/angular/layout.md +37 -47
- package/claude/references/sd-simplysm14/apis/angular/overlay.md +82 -74
- package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +61 -50
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +74 -57
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +63 -72
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +23 -18
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +21 -19
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +23 -18
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +72 -32
- package/claude/references/sd-simplysm14/apis/core-browser/README.md +18 -18
- package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +29 -29
- package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +41 -41
- package/claude/references/sd-simplysm14/apis/core-common/README.md +97 -90
- package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +75 -51
- package/claude/references/sd-simplysm14/apis/core-common/collection-ext.md +81 -0
- package/claude/references/sd-simplysm14/apis/core-common/errors.md +27 -29
- package/claude/references/sd-simplysm14/apis/core-common/obj.md +44 -45
- package/claude/references/sd-simplysm14/apis/core-common/serialization.md +34 -33
- package/claude/references/sd-simplysm14/apis/core-common/value-types.md +86 -0
- package/claude/references/sd-simplysm14/apis/core-node/README.md +6 -6
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +3 -0
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +2 -2
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +1 -1
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +2 -2
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +6 -3
- package/claude/references/sd-simplysm14/apis/excel/README.md +10 -10
- package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +4 -2
- package/claude/references/sd-simplysm14/apis/excel/utils.md +1 -1
- package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +6 -6
- package/claude/references/sd-simplysm14/apis/lint/README.md +6 -32
- package/claude/references/sd-simplysm14/apis/lint/recommended.md +60 -0
- package/claude/references/sd-simplysm14/apis/lint/rules.md +17 -17
- package/claude/references/sd-simplysm14/apis/orm-common/README.md +15 -6
- package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +68 -102
- package/claude/references/sd-simplysm14/apis/orm-common/expr.md +75 -89
- package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +87 -99
- package/claude/references/sd-simplysm14/apis/orm-common/schema.md +110 -147
- package/claude/references/sd-simplysm14/apis/orm-common/types.md +48 -51
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +8 -13
- package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +5 -5
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +9 -6
- package/claude/references/sd-simplysm14/apis/sd-cli/SdTsCompiler.md +9 -8
- package/claude/references/sd-simplysm14/apis/sd-cli/sd-config-types.md +23 -19
- package/claude/references/sd-simplysm14/apis/service-client/README.md +20 -12
- package/claude/references/sd-simplysm14/apis/service-client/orm.md +6 -6
- package/claude/references/sd-simplysm14/apis/service-client/transport.md +1 -1
- package/claude/references/sd-simplysm14/apis/service-common/README.md +35 -32
- package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +23 -22
- package/claude/references/sd-simplysm14/apis/service-common/protocol.md +23 -23
- package/claude/references/sd-simplysm14/apis/service-server/README.md +51 -43
- package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +6 -6
- package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +31 -21
- package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +8 -8
- package/claude/references/sd-simplysm14/apis/storage/README.md +55 -49
- package/claude/references/sd-simplysm14/manuals/client-component.md +843 -740
- package/claude/references/sd-simplysm14/manuals/client-crud.md +8 -0
- package/claude/references/sd-simplysm14/manuals/client-demo.md +6 -16
- package/claude/references/sd-simplysm14/manuals/client-shared-data.md +26 -0
- package/claude/references/sd-simplysm14/manuals/logging.md +1 -1
- package/claude/references/sd-simplysm14/manuals/orm.md +15 -1
- package/claude/rules/sd-design-rules.md +7 -0
- package/claude/sd-system-prompt.md +5 -8
- package/claude/skills/sd-debug/SKILL.md +43 -0
- package/claude/skills/sd-debug/workflow.js +390 -0
- package/claude/skills/sd-demo/SKILL.md +18 -20
- package/claude/skills/sd-dev/SKILL.md +127 -24
- package/claude/skills/sd-docs/SKILL.md +5 -3
- package/claude/skills/sd-docs/references/subagent-prompt.md +2 -3
- package/claude/skills/sd-impl/SKILL.md +18 -18
- package/claude/skills/sd-manual/SKILL.md +1 -0
- package/claude/skills/sd-review/SKILL.md +24 -18
- package/claude/skills/sd-review/workflow.js +324 -0
- package/claude/skills/sd-spec/SKILL.md +96 -679
- package/claude/skills/sd-spec/references/example-spec.md +28 -50
- package/claude/skills/sd-spec/references/format-analyze.md +232 -0
- package/claude/skills/sd-spec/references/format-design.md +248 -0
- package/claude/skills/sd-spec/workflow-analyze.js +615 -0
- package/claude/skills/sd-spec/workflow-design.js +667 -0
- package/claude/skills/sd-unpack/scripts/handlers/office_com.py +5 -1
- package/package.json +1 -1
- package/scripts/postinstall.mjs +157 -18
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +0 -68
- package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +0 -77
- package/claude/references/sd-simplysm14/apis/core-common/datetime.md +0 -86
- package/claude/skills/sd-skill/SKILL.md +0 -245
- package/claude/skills/sd-skill/scripts/run_eval.py +0 -380
|
@@ -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,28 +17,28 @@ store.close();
|
|
|
17
17
|
|
|
18
18
|
시그니처:
|
|
19
19
|
|
|
20
|
-
- new IndexedDbStore(dbName: string, dbVersion: number, storeConfigs: StoreConfig[]) — DB 이름·버전·스토어 설정으로 생성(연결은 지연, 첫 작업 시 오픈).
|
|
21
|
-
- dbName: string — IndexedDB 데이터베이스 이름.
|
|
22
|
-
- dbVersion: number — DB 버전. 올리면 `onupgradeneeded` 에서 누락 스토어를 생성. 스키마(스토어 추가) 변경 시 증가.
|
|
23
|
-
- storeConfigs: StoreConfig[] — 생성할 오브젝트 스토어 목록.
|
|
24
|
-
- StoreConfig — 스토어 설정 항목.
|
|
25
|
-
- name: string — 오브젝트 스토어 이름. upgrade 시 미존재면 `createObjectStore` 로 생성.
|
|
26
|
-
- keyPath: string — 스토어 keyPath(레코드에서 키로 쓸 속성명).
|
|
27
|
-
- open(): Promise<IDBDatabase
|
|
28
|
-
- withStore<TResult>(storeName, mode, fn): Promise<TResult
|
|
29
|
-
- storeName: string — 트랜잭션 대상 스토어.
|
|
30
|
-
- mode: IDBTransactionMode — `"readonly"`(읽기 전용) | `"readwrite"`(읽기·쓰기) | `"versionchange"
|
|
31
|
-
- fn: (store: IDBObjectStore) => Promise<TResult
|
|
32
|
-
- get<TValue>(storeName, key): Promise<TValue | undefined
|
|
33
|
-
- put(storeName, value): Promise<void
|
|
34
|
-
- delete(storeName, key): Promise<void
|
|
35
|
-
- getAll<TItem>(storeName): Promise<TItem[]
|
|
36
|
-
- close(): void — 연결을 닫고 내부 캐시 해제. 다음 작업 시 재오픈. 페이지 정리 시 호출.
|
|
20
|
+
- `new IndexedDbStore(dbName: string, dbVersion: number, storeConfigs: StoreConfig[])` — DB 이름·버전·스토어 설정으로 생성(연결은 지연, 첫 작업 시 오픈).
|
|
21
|
+
- `dbName: string` — IndexedDB 데이터베이스 이름.
|
|
22
|
+
- `dbVersion: number` — DB 버전. 올리면 `onupgradeneeded` 에서 누락 스토어를 생성. 스키마(스토어 추가) 변경 시 증가.
|
|
23
|
+
- `storeConfigs: StoreConfig[]` — 생성할 오브젝트 스토어 목록.
|
|
24
|
+
- `StoreConfig` — 스토어 설정 항목.
|
|
25
|
+
- `name: string` — 오브젝트 스토어 이름. upgrade 시 미존재면 `createObjectStore` 로 생성.
|
|
26
|
+
- `keyPath: string` — 스토어 keyPath(레코드에서 키로 쓸 속성명).
|
|
27
|
+
- `open(): Promise<IDBDatabase>` — 연결을 열어 반환. 이미 열렸으면 캐시 반환, 진행 중이면 같은 Promise 공유(중복 오픈 방지). `onupgradeneeded` 시 없는 스토어만 생성. `onversionchange`/`onclose` 시 내부 캐시(`_db`/`_opening`)를 해제해 다음 호출에 재오픈. `onblocked` 면 `Error("다른 연결에 의해 데이터베이스가 차단되었습니다")`, `onerror` 면 원본 에러로 reject. CRUD 가 자동 호출하므로 직접 호출 불필요.
|
|
28
|
+
- `withStore<TResult>(storeName, mode, fn): Promise<TResult>` — 트랜잭션 1건 안에서 `fn(store)` 실행 후 완료까지 대기. `fn` 이 throw 하면 `tx.abort()` 후 그 에러로 reject(롤백), 정상이면 `oncomplete` 시 결과 resolve, `onerror` 면 `tx.error` 로 reject. 커서 등 저수준 IDB 작업을 감쌀 때.
|
|
29
|
+
- `storeName: string` — 트랜잭션 대상 스토어.
|
|
30
|
+
- `mode: IDBTransactionMode` — `"readonly"`(읽기 전용) | `"readwrite"`(읽기·쓰기) | `"versionchange"`(스키마 변경). 쓰기 작업이면 `"readwrite"`.
|
|
31
|
+
- `fn: (store: IDBObjectStore) => Promise<TResult>` — 스토어를 받아 작업하는 콜백.
|
|
32
|
+
- `get<TValue>(storeName, key): Promise<TValue | undefined>` — 키로 단건 조회. 미존재 시 `undefined`(결측 그대로 반환).
|
|
33
|
+
- `put(storeName, value): Promise<void>` — 레코드 upsert. value 에 keyPath 속성이 포함돼야 함.
|
|
34
|
+
- `delete(storeName, key): Promise<void>` — 키로 단건 삭제.
|
|
35
|
+
- `getAll<TItem>(storeName): Promise<TItem[]>` — 스토어 전체 레코드 배열 반환.
|
|
36
|
+
- `close(): void` — 연결을 닫고 내부 캐시 해제. 다음 작업 시 재오픈. 페이지 정리 시 호출.
|
|
37
37
|
|
|
38
38
|
주의:
|
|
39
39
|
|
|
40
|
-
- `withStore` 의 fn 이 throw 하면 트랜잭션
|
|
41
|
-
- 버전 변경(`onupgradeneeded`)은 누락 스토어 생성만
|
|
40
|
+
- `withStore` 의 fn 이 throw 하면 트랜잭션 전체가 abort — 다건 쓰기를 하나의 `withStore` 안에 묶으면 원자성이 보장된다.
|
|
41
|
+
- 버전 변경(`onupgradeneeded`)은 누락 스토어 생성만 한다 — 기존 스토어 스키마 변경·인덱스 추가는 별도 처리가 필요하다.
|
|
42
42
|
|
|
43
43
|
## IndexedDbVirtualFs
|
|
44
44
|
|
|
@@ -54,27 +54,27 @@ const ok = await fs.deleteByPrefix("/root/a"); // 하위 전체 삭제, 삭제
|
|
|
54
54
|
|
|
55
55
|
시그니처:
|
|
56
56
|
|
|
57
|
-
- new IndexedDbVirtualFs(db: IndexedDbStore, storeName: string, keyField: string) — 백엔드 store·스토어 이름·키 필드명으로 생성.
|
|
58
|
-
- db: IndexedDbStore — 백엔드 저장소.
|
|
59
|
-
- storeName: string — 사용할 오브젝트 스토어 이름.
|
|
60
|
-
- keyField: string — 레코드에서 경로 키를 담는 속성명(스토어 keyPath 와 일치해야 함).
|
|
61
|
-
- VirtualFsEntry — 저장 엔트리 타입.
|
|
62
|
-
- kind: "file" | "dir" — 엔트리 종류. `"file"` = 파일, `"dir"` = 디렉터리. 자식 나열·디렉터리 판정에 사용.
|
|
63
|
-
- dataBase64
|
|
64
|
-
- getEntry(fullKey): Promise<VirtualFsEntry | undefined
|
|
65
|
-
- putEntry(fullKey, kind, dataBase64?): Promise<void
|
|
66
|
-
- fullKey: string — 저장할 전체 경로 키.
|
|
67
|
-
- kind: "file" | "dir" — 저장할 엔트리 종류.
|
|
68
|
-
- dataBase64
|
|
69
|
-
- deleteByPrefix(keyPrefix): Promise<boolean
|
|
70
|
-
- listChildren(prefix): Promise<{ name: string; isDirectory: boolean }[]
|
|
71
|
-
- 반환 항목 name: string — 직계 자식 이름(첫 경로 세그먼트).
|
|
72
|
-
- 반환 항목 isDirectory: boolean — 디렉터리 여부.
|
|
73
|
-
- ensureDir(fullKeyBuilder, dirPath): Promise<void
|
|
74
|
-
- fullKeyBuilder: (path: string) => string — 누적 경로(예: `/a`, `/a/b`)를 실제 저장 key 로 변환하는 콜백.
|
|
75
|
-
- dirPath: string — 보장할 디렉터리 경로(`/` 구분). 빈 세그먼트는 무시.
|
|
57
|
+
- `new IndexedDbVirtualFs(db: IndexedDbStore, storeName: string, keyField: string)` — 백엔드 store·스토어 이름·키 필드명으로 생성.
|
|
58
|
+
- `db: IndexedDbStore` — 백엔드 저장소.
|
|
59
|
+
- `storeName: string` — 사용할 오브젝트 스토어 이름.
|
|
60
|
+
- `keyField: string` — 레코드에서 경로 키를 담는 속성명(스토어 keyPath 와 일치해야 함).
|
|
61
|
+
- `VirtualFsEntry` — 저장 엔트리 타입.
|
|
62
|
+
- `kind: "file" | "dir"` — 엔트리 종류. `"file"` = 파일, `"dir"` = 디렉터리. 자식 나열·디렉터리 판정에 사용.
|
|
63
|
+
- `dataBase64?: string` — 파일 내용 base64. 디렉터리거나 빈 파일이면 생략(undefined).
|
|
64
|
+
- `getEntry(fullKey): Promise<VirtualFsEntry | undefined>` — 전체 경로 키로 단건 조회. 미존재 시 `undefined`.
|
|
65
|
+
- `putEntry(fullKey, kind, dataBase64?): Promise<void>` — 엔트리 저장. `keyField` 에 `fullKey`, 그리고 `kind`/`dataBase64` 를 함께 기록.
|
|
66
|
+
- `fullKey: string` — 저장할 전체 경로 키.
|
|
67
|
+
- `kind: "file" | "dir"` — 저장할 엔트리 종류.
|
|
68
|
+
- `dataBase64?: string` — 파일 데이터(base64). 디렉터리면 생략.
|
|
69
|
+
- `deleteByPrefix(keyPrefix): Promise<boolean>` — 커서로 키가 `keyPrefix` 자신이거나 `keyPrefix + "/"` 로 시작하는 엔트리를 전부 삭제(같은 접두어를 가진 다른 형제 경로 오삭제 방지). 하나라도 지웠으면 `true`, 없으면 `false`. 디렉터리 트리 통째 삭제에.
|
|
70
|
+
- `listChildren(prefix): Promise<{ name: string; isDirectory: boolean }[]>` — `prefix` 직계 자식만 집계. 키에서 prefix 제거 후 첫 세그먼트를 이름으로 삼고, 하위 세그먼트가 더 있거나 엔트리 `kind === "dir"` 면 디렉터리로 판정. 디렉터리 목록 표시용(재귀 아님).
|
|
71
|
+
- 반환 항목 `name: string` — 직계 자식 이름(첫 경로 세그먼트).
|
|
72
|
+
- 반환 항목 `isDirectory: boolean` — 디렉터리 여부.
|
|
73
|
+
- `ensureDir(fullKeyBuilder, dirPath): Promise<void>` — `dirPath` 상의 각 중간 디렉터리를 부모부터 누적 경로마다 없으면 생성. `dirPath === "/"` 면 루트 1건만 생성. 단일 `withStore("readwrite")` 트랜잭션으로 처리(원자적). 파일 쓰기 전 상위 디렉터리 보장에.
|
|
74
|
+
- `fullKeyBuilder: (path: string) => string` — 누적 경로(예: `/a`, `/a/b`)를 실제 저장 key 로 변환하는 콜백.
|
|
75
|
+
- `dirPath: string` — 보장할 디렉터리 경로(`/` 구분). 빈 세그먼트는 무시.
|
|
76
76
|
|
|
77
77
|
주의:
|
|
78
78
|
|
|
79
|
-
- 모든 범위 조회는 `IDBKeyRange.bound(prefix, prefix + "")` 기반 — 호출측이 fullKey 규칙을 일관되게 유지해 prefix 가 정확한 경로 경계를 갖게 해야
|
|
80
|
-
- `listChildren` 은 직계만 반환(재귀 아님). 트리 전체 순회는 세그먼트별 반복
|
|
79
|
+
- 모든 범위 조회는 `IDBKeyRange.bound(prefix, prefix + "")` 기반 — 호출측이 fullKey 규칙을 일관되게 유지해 prefix 가 정확한 경로 경계를 갖게 해야 한다.
|
|
80
|
+
- `listChildren` 은 직계만 반환(재귀 아님). 트리 전체 순회는 세그먼트별 반복 호출이 필요하다.
|
|
@@ -1,130 +1,137 @@
|
|
|
1
1
|
# @simplysm/core-common
|
|
2
2
|
|
|
3
|
-
브라우저·Node 공용
|
|
4
|
-
|
|
5
|
-
> 부수효과 주의: 이 패키지를 import 하면 `Array.prototype`·`Set.prototype`·`Map.prototype` 에 확장 메서드가 설치됨(전역 prototype 변경). 확장 메서드는 `array.toMap(...)` 처럼 메서드로 직접 호출.
|
|
3
|
+
브라우저·Node 공용 기반 유틸. 날짜/시간 값 타입, 에러 클래스, 배열/Set/Map 확장, 객체 조작, 직렬화(json/xml/bytes/transfer), 비동기 큐·이벤트·대기, 로거·환경변수·원시타입 매핑을 제공.
|
|
6
4
|
|
|
7
5
|
## 사용 트리거 인덱스
|
|
8
6
|
|
|
9
|
-
- **에러 클래스** —
|
|
10
|
-
- **날짜/시간 값
|
|
11
|
-
-
|
|
12
|
-
- **객체
|
|
13
|
-
-
|
|
14
|
-
- **비동기
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- **
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
7
|
+
- **에러 클래스** — 원인 체인을 묶은 에러를 throw 하거나 catch 에서 메시지를 추출할 때. 자세히: [errors.md](./errors.md)
|
|
8
|
+
- **날짜/시간 값 타입 (DateTime·DateOnly·Time·Uuid)** — 불변 날짜/시간/식별자 값을 만들고 파싱·산술·포맷할 때. 자세히: [value-types.md](./value-types.md)
|
|
9
|
+
- **배열/Set/Map 확장** — `arr.single/groupBy/toMap/distinct/orderBy/diffs/toTree` 등 프로토타입 확장 메서드와 `Set.adds/toggle`, `Map.getOrCreate/update` 를 쓸 때. 자세히: [collection-ext.md](./collection-ext.md)
|
|
10
|
+
- **객체 조작 (obj 네임스페이스)** — `obj.clone/equal/merge/merge3/pick/omit/getChainValue/keys/entries` 등 깊은 복사·비교·병합·체인 접근이 필요할 때. 자세히: [obj.md](./obj.md)
|
|
11
|
+
- **직렬화 (json·xml·bytes·transfer)** — 커스텀 타입(DateTime/Uuid/Map/Error 등) 포함 객체를 JSON/XML 문자열, hex/base64, Worker 전송 형태로 변환할 때. 자세히: [serialization.md](./serialization.md)
|
|
12
|
+
- **비동기 런타임 (큐·이벤트·대기·LazyGcMap)** — `DebounceQueue`/`SerialQueue` 로 호출 흐름을 제어하거나, `EventEmitter` 로 타입 안전 이벤트를 다루거나, `wait.until/time`, 자동 만료 Map 이 필요할 때. 자세히: [async-runtime.md](./async-runtime.md)
|
|
13
|
+
- **str (문자열 유틸)** — 한국어 조사 선택, 전각→반각, 케이스 변환, 빈문자열 판별, 삽입. (아래 인라인)
|
|
14
|
+
- **num (숫자 유틸)** — 비숫자 제거 후 정수/실수 파싱, 0/null 판별, 천단위 포맷. (아래 인라인)
|
|
15
|
+
- **path (POSIX 경로 유틸)** — 브라우저용 join/basename/extname. (아래 인라인)
|
|
16
|
+
- **dt (날짜 포맷 헬퍼)** — `DateTime`/`DateOnly`/`Time` 의 `toFormatString` 이 내부적으로 쓰는 C# 스타일 포맷 문자열 변환. (아래 인라인)
|
|
17
|
+
- **primitive (원시타입 추론)** — 런타임 값에서 `PrimitiveTypeStr` 추론. (아래 인라인)
|
|
18
|
+
- **template-strings (코드 하이라이팅 태그)** — `js/ts/html/tsql/mysql/pgsql` 템플릿 태그로 들여쓰기 정규화. (아래 인라인)
|
|
19
|
+
- **ZipArchive** — ZIP 바이트를 읽고 파일 단위로 추출·추가·재압축할 때. (아래 인라인)
|
|
20
|
+
- **env / createLogger** — 환경변수 읽기·쓰기, 모듈 레벨 안전 lazy 로거 생성. (아래 인라인)
|
|
21
|
+
- **공용 타입 (common.types)** — `PrimitiveType`/`PrimitiveTypeStr`/`PrimitiveTypeMap`/`Bytes`/`DeepPartial`/`Type`. (아래 인라인)
|
|
22
|
+
|
|
23
|
+
## str (문자열 유틸)
|
|
24
|
+
|
|
25
|
+
`import { str } from "@simplysm/core-common"` 네임스페이스.
|
|
26
|
+
|
|
27
|
+
- `getKoreanSuffix(text: string, type: "을"|"은"|"이"|"와"|"랑"|"로"|"라"): string` — 마지막 글자 받침 유무로 한국어 조사를 선택. type 은 조사 쌍 식별자: `"을"`=을/를, `"은"`=은/는, `"이"`=이/가, `"와"`=과/와, `"랑"`=이랑/랑, `"로"`=으로/로(받침이 ㄹ이면 "로"), `"라"`=이라/라. 한글이 아니거나 빈 문자열이면 받침 없는 형태 반환. 동적 메시지 조립 시 사용.
|
|
28
|
+
- `replaceFullWidth(str: string): string` — 전각 영문·숫자·공백·괄호를 반각으로 치환. 외부 입력(엑셀·스캐너) 정규화 시.
|
|
29
|
+
- `toPascalCase(str: string): string` — `-`/`_`/`.` 구분자 뒤 글자와 첫 글자를 대문자화. 식별자 변환 시.
|
|
30
|
+
- `toCamelCase(str: string): string` — 구분자 뒤 글자는 대문자화하되 첫 글자는 소문자화.
|
|
31
|
+
- `toKebabCase(str: string): string` — 대문자 앞에 `-` 삽입 후 소문자화. 연속 대문자도 글자별 분리(`XMLParser`→`x-m-l-parser`), 기존 `-`/`_` 구분자는 유지.
|
|
32
|
+
- `toSnakeCase(str: string): string` — `toKebabCase` 와 동일 규칙이되 구분자가 `_`.
|
|
33
|
+
- `isNullOrEmpty(str: string | undefined): str is "" | undefined` — null/undefined/빈문자열이면 true 인 타입 가드. else 분기에서 비어있지 않은 string 으로 좁혀짐.
|
|
34
|
+
- `insert(str: string, index: number, insertString: string): string` — index 위치에 문자열 삽입한 새 문자열.
|
|
25
35
|
|
|
26
36
|
```ts
|
|
27
|
-
import {
|
|
28
|
-
const
|
|
29
|
-
logger.info("최신 버전 확인 중");
|
|
30
|
-
logger.error("checkPermissions 실패", err);
|
|
37
|
+
import { str } from "@simplysm/core-common";
|
|
38
|
+
const label = "사과" + str.getKoreanSuffix("사과", "을") + " 담았습니다."; // "사과를 담았습니다."
|
|
31
39
|
```
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
## num (숫자 유틸)
|
|
34
42
|
|
|
35
|
-
|
|
43
|
+
`import { num } from "@simplysm/core-common"` 네임스페이스. 파싱 계열은 비숫자 문자(0-9·`-`·`.` 외)를 먼저 제거하므로 `"010-1234"` 같은 입력도 받음(선행 `-`만 부호로 유지).
|
|
36
44
|
|
|
37
|
-
- `
|
|
38
|
-
- `
|
|
39
|
-
- `
|
|
45
|
+
- `parseInt(text: unknown): number | undefined` — 정수 파싱. number 면 `Math.trunc`, 소수 문자열이면 정수부만, 파싱 불가면 undefined.
|
|
46
|
+
- `parseFloat(text: unknown): number | undefined` — 실수 파싱. number 는 그대로, 파싱 불가면 undefined.
|
|
47
|
+
- `parseRoundedInt(text: unknown): number | undefined` — `parseFloat` 후 `Math.round`. 반올림 정수가 필요할 때.
|
|
48
|
+
- `isNullOrEmpty(val: number | undefined): val is 0 | undefined` — null/undefined/0 이면 true 인 타입 가드. else 분기에서 0 아닌 number 로 좁혀짐.
|
|
49
|
+
- `format(val, digit?: { max?: number; min?: number }): string | undefined` — 천단위 구분자 포맷. `max`=최대 소수 자릿수, `min`=최소 소수 자릿수(부족분 0 채움). val 이 undefined 면 undefined 반환.
|
|
40
50
|
|
|
41
51
|
```ts
|
|
42
|
-
import {
|
|
43
|
-
|
|
52
|
+
import { num } from "@simplysm/core-common";
|
|
53
|
+
num.format(1234.567, { max: 2 }); // "1,234.57"
|
|
54
|
+
num.parseInt("010-1234-5678"); // 1012345678
|
|
44
55
|
```
|
|
45
56
|
|
|
46
|
-
##
|
|
57
|
+
## path (POSIX 경로 유틸)
|
|
47
58
|
|
|
48
|
-
|
|
49
|
-
- `str.replaceFullWidth(s)`: → string — 전각 영문/숫자/공백/괄호를 반각으로 변환. OCR·외부 입력 정규화에 사용.
|
|
50
|
-
- `str.toPascalCase(s)` / `toCamelCase(s)` / `toKebabCase(s)` / `toSnakeCase(s)`: → string — 케이스 변환. `-`·`_`·`.` 구분자와 대문자 경계를 인식. 코드 생성·식별자 정규화에 사용.
|
|
51
|
-
- `str.isNullOrEmpty(s)`: → `s is "" | undefined` — null/undefined/빈 문자열 판정(타입 가드). false 분기에서 non-empty string 으로 좁혀짐.
|
|
52
|
-
- `str.insert(s, index, insertString)`: → string — index 위치에 문자열 삽입한 새 문자열.
|
|
53
|
-
|
|
54
|
-
```ts
|
|
55
|
-
import { str } from "@simplysm/core-common";
|
|
56
|
-
`${name}${str.getKoreanSuffix(name, "을")} 저장했습니다`;
|
|
57
|
-
```
|
|
59
|
+
`import { path } from "@simplysm/core-common"` 네임스페이스. POSIX 슬래시 경로만 지원(Windows 백슬래시 미지원). 브라우저·Capacitor 환경용 Node `path` 대체.
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
- `join(...segments: string[]): string` — 슬래시로 결합하며 중간 세그먼트의 앞뒤 슬래시·빈 세그먼트 제거.
|
|
62
|
+
- `basename(filePath: string, ext?: string): string` — 마지막 세그먼트 추출. `ext` 가 끝과 일치하면 제거.
|
|
63
|
+
- `extname(filePath: string): string` — 마지막 `.` 이후 확장자(`.` 포함). 숨김파일(`.gitignore`)은 빈 문자열.
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
- `num.parseFloat(text)`: → `number | undefined` — 위와 동일 규칙으로 실수 파싱.
|
|
63
|
-
- `num.parseRoundedInt(text)`: → `number | undefined` — float 파싱 후 반올림한 정수. 소수 입력을 반올림 정수로 받을 때.
|
|
64
|
-
- `num.isNullOrEmpty(val)`: → `val is 0 | undefined` — null/undefined/0 판정(타입 가드). false 분기에서 0 아닌 숫자로 좁혀짐.
|
|
65
|
-
- `num.format(val, digit?)`: → string(또는 입력이 undefined 면 undefined) — 천 단위 구분자 포함 포맷. `digit.max`=최대 소수 자릿수, `digit.min`=최소 소수 자릿수(부족분 0 채움). `format(1234.567, { max: 2 })`→`"1,234.57"`.
|
|
65
|
+
## dt (날짜 포맷 헬퍼)
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
`import { dt } from "@simplysm/core-common"` 네임스페이스. 보통 `DateTime`/`DateOnly`/`Time` 의 `toFormatString` 을 통해 간접 사용.
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
- `format(formatString: string, args: { year?, month?, day?, hour?, minute?, second?, millisecond?, timezoneOffsetMinutes? }): string` — C# 스타일 포맷 토큰 치환. 토큰: `yyyy/yy`(연), `MM/M`(월), `ddd`(요일 한글)/`dd/d`(일), `tt`(AM/PM), `hh/h`(12시간)/`HH/H`(24시간), `mm/m`(분), `ss/s`(초), `fff/ff/f`(밀리초), `zzz/zz/z`(타임존 오프셋). 전달되지 않은 구성요소의 토큰은 치환되지 않음.
|
|
70
|
+
- `normalizeMonth(year, month, day): { year; month; day }` — 1-12 범위 밖 월을 연도로 이월하고, 대상 월 일수를 넘는 일은 말일로 보정.
|
|
71
|
+
- `convert12To24(rawHour: number, isPM: boolean): number` — 12시간제(1-12)+오전/오후를 24시간제(0-23)로 변환.
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
- `path.basename(filePath, ext?)`: → string — 파일명 추출. ext 가 주어지고 끝나면 그 확장자 제거.
|
|
73
|
-
- `path.extname(filePath)`: → string — 확장자 추출(`.` 포함). 숨김 파일(`.gitignore`)은 빈 문자열(Node 와 동일).
|
|
73
|
+
## primitive (원시타입 추론)
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
`import { primitive } from "@simplysm/core-common"` 네임스페이스.
|
|
76
76
|
|
|
77
|
-
- `
|
|
78
|
-
- `new Uuid(uuidStr)` — 문자열로 생성. 형식 불일치면 ArgumentError throw.
|
|
79
|
-
- `Uuid.fromBytes(bytes)`: → Uuid — 16바이트 Uint8Array 로 생성. 길이≠16 이면 ArgumentError.
|
|
80
|
-
- 인스턴스: `toString()` → 문자열, `toBytes()` → 16바이트 Uint8Array.
|
|
77
|
+
- `typeStr(value): PrimitiveTypeStr` — 런타임 값에서 `"string"|"number"|"boolean"|"DateTime"|"DateOnly"|"Time"|"Uuid"|"Bytes"` 중 해당 문자열 반환. 지원하지 않는 타입이면 `ArgumentError` throw. ORM/직렬화에서 값 타입을 문자열 키로 다룰 때.
|
|
81
78
|
|
|
82
|
-
##
|
|
79
|
+
## template-strings (코드 하이라이팅 태그)
|
|
83
80
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
- `new ZipArchive(data?)` — data(`Blob | Uint8Array`) 주면 읽기용, 생략하면 새 아카이브.
|
|
87
|
-
- `extractAll(progressCallback?)`: → `Promise<Map<string, Bytes | undefined>>` — 모든 파일 추출. 콜백은 `{ fileName, totalSize, extractedSize }` 진행률 수신.
|
|
88
|
-
- `get(fileName)`: → `Promise<Bytes | undefined>` — 단일 파일 추출(없으면 undefined).
|
|
89
|
-
- `exists(fileName)`: → `Promise<boolean>` — 파일 존재 여부.
|
|
90
|
-
- `write(fileName, bytes)`: → void — 파일을 캐시에 등록(아직 압축 전).
|
|
91
|
-
- `compress()`: → `Promise<Bytes>` — 캐시된 전체 파일을 ZIP 바이트로 압축. 내부적으로 `extractAll()` 호출(대용량 시 메모리 주의).
|
|
92
|
-
- `close()`: → `Promise<void>` — 리더 닫고 캐시 비움.
|
|
93
|
-
|
|
94
|
-
## 템플릿 태그 (코드 하이라이팅용)
|
|
95
|
-
|
|
96
|
-
`js` / `ts` / `html` / `tsql` / `mysql` / `pgsql` — 모두 동일 동작: 템플릿 리터럴을 문자열로 결합하고 공통 들여쓰기를 제거(앞뒤 빈 줄 제거). IDE 하이라이팅·가독성 목적이며 SQL 이스케이프 등 기능 차이는 없음.
|
|
81
|
+
`import { js, ts, html, tsql, mysql, pgsql } from "@simplysm/core-common"`. 모두 동일 동작 — 보간값을 문자열로 합친 뒤 공통 최소 들여쓰기를 제거하고 앞뒤 빈 줄을 잘라냄. 함수별 차이는 IDE 하이라이팅 언어 힌트뿐(js/ts/html/T-SQL/MySQL/PostgreSQL). 런타임 검증·이스케이프는 하지 않음.
|
|
97
82
|
|
|
98
83
|
```ts
|
|
99
84
|
import { ts } from "@simplysm/core-common";
|
|
100
85
|
const code = ts`
|
|
101
|
-
interface User {
|
|
102
|
-
|
|
86
|
+
interface User {
|
|
87
|
+
name: string;
|
|
88
|
+
}
|
|
89
|
+
`; // 앞 공통 들여쓰기 제거된 문자열
|
|
103
90
|
```
|
|
104
91
|
|
|
105
|
-
##
|
|
92
|
+
## ZipArchive
|
|
93
|
+
|
|
94
|
+
`import { ZipArchive } from "@simplysm/core-common"`. `@zip.js/zip.js` 래퍼. 읽기/쓰기를 한 인스턴스로 다루며 추출 결과를 내부 캐시에 보관. 사용 후 `close()` 필수.
|
|
106
95
|
|
|
107
|
-
- `
|
|
108
|
-
- `
|
|
96
|
+
- `new ZipArchive(data?: Blob | Bytes)` — `data` 생략 시 새 빈 아카이브, 주면 읽기용 리더 구성(`Uint8Array`→`Uint8ArrayReader`, `Blob`→`BlobReader`).
|
|
97
|
+
- `extractAll(progressCallback?: (p: ZipArchiveProgress) => void): Promise<Map<string, Bytes | undefined>>` — 전체 파일 추출. 콜백 인자 `ZipArchiveProgress` 필드: `fileName`=현재 파일명, `totalSize`=전체 비압축 크기, `extractedSize`=누적 추출 크기.
|
|
98
|
+
- `get(fileName: string): Promise<Bytes | undefined>` — 단일 파일 추출(없으면 undefined). 캐시 우선.
|
|
99
|
+
- `exists(fileName: string): Promise<boolean>` — 파일 존재 여부.
|
|
100
|
+
- `write(fileName: string, bytes: Bytes): void` — 캐시에 파일 등록(아직 압축 안 함).
|
|
101
|
+
- `compress(): Promise<Bytes>` — 캐시(및 원본 추출분)를 ZIP 바이트로 압축. 내부적으로 `extractAll()` 호출하므로 전체가 메모리에 로드됨.
|
|
102
|
+
- `close(): Promise<void>` — 리더 닫고 캐시 비움.
|
|
109
103
|
|
|
110
|
-
|
|
104
|
+
```ts
|
|
105
|
+
const zip = new ZipArchive(zipBytes);
|
|
106
|
+
try {
|
|
107
|
+
const content = await zip.get("file.txt");
|
|
108
|
+
} finally {
|
|
109
|
+
await zip.close();
|
|
110
|
+
}
|
|
111
|
+
```
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
- `map.update(key, updateFn)`: → void — `updateFn(현재값 | undefined)` 결과로 값 설정. key 가 없어도 호출됨. 카운터 증가·배열 누적에 사용. 예: `m.update(k, v => (v ?? 0) + 1)`.
|
|
113
|
+
## env / createLogger
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
`import { env, parseBoolEnv, createLogger } from "@simplysm/core-common"`.
|
|
116
116
|
|
|
117
|
-
- `
|
|
118
|
-
- `
|
|
119
|
-
- `
|
|
120
|
-
- `
|
|
121
|
-
- `DeepPartial<T>` — 모든 속성을 재귀적으로 optional 화. 원시/날짜 타입은 그대로 두고 object/array 만 재귀.
|
|
122
|
-
- `Type<TInstance>` — 클래스 생성자 타입(`new (...args) => TInstance`). DI·팩토리·instanceof 체크에 사용.
|
|
117
|
+
- `env(key: string): string | undefined` — 환경변수 읽기. `process.env` 우선, 없으면 `import.meta.env` fallback(Node 에선 보통 undefined).
|
|
118
|
+
- `env(key: string, value: string): void` — `process.env[key]` 에 쓰기(process 없는 런타임이면 무시).
|
|
119
|
+
- `parseBoolEnv(value: unknown): boolean` — `"true"/"1"/"yes"/"on"`(대소문자 무시)이면 true, 그 외 false. 환경변수 boolean 해석 시.
|
|
120
|
+
- `createLogger(tag: string): ConsolaInstance` — consola 태그 로거를 첫 메서드 접근 시점까지 지연 생성하는 Proxy. 모듈 레벨에서 선언해도 이후 `setupConsola` 의 level/reporters 변경이 반영됨. 모듈 최상단에 로거를 두고 싶을 때 `consola.withTag()` 직접 호출 대신 사용.
|
|
123
121
|
|
|
124
|
-
|
|
122
|
+
```ts
|
|
123
|
+
import { createLogger, env, parseBoolEnv } from "@simplysm/core-common";
|
|
124
|
+
const logger = createLogger("MyModule");
|
|
125
|
+
if (parseBoolEnv(env("DEV"))) logger.debug("dev mode");
|
|
126
|
+
```
|
|
125
127
|
|
|
126
|
-
|
|
128
|
+
## 공용 타입 (common.types)
|
|
127
129
|
|
|
128
|
-
|
|
130
|
+
`import type { ... } from "@simplysm/core-common"`. orm-common 등과 공유되는 원시타입 매핑·유틸 타입.
|
|
129
131
|
|
|
130
|
-
- `
|
|
132
|
+
- `Bytes = Uint8Array` — 바이너리 값 타입(Node `Buffer` 대신 사용).
|
|
133
|
+
- `PrimitiveTypeMap` — 원시타입 문자열 key → 실제 타입 매핑(`string/number/boolean/DateTime/DateOnly/Time/Uuid/Bytes`).
|
|
134
|
+
- `PrimitiveTypeStr = keyof PrimitiveTypeMap` — 위 매핑의 key 유니온.
|
|
135
|
+
- `PrimitiveType = PrimitiveTypeMap[PrimitiveTypeStr] | undefined` — 모든 원시 값 유니온(undefined 포함).
|
|
136
|
+
- `DeepPartial<TObject>` — 원시타입은 그대로 두고 객체/배열만 재귀적으로 optional 화. 부분 패치 입력 타입에.
|
|
137
|
+
- `Type<TInstance>` — `new (...args) => TInstance` 생성자 타입. 팩토리·DI·`instanceof` 분기에서 클래스를 값으로 받을 때.
|
|
@@ -1,86 +1,110 @@
|
|
|
1
|
-
# @simplysm/core-common — 비동기 런타임
|
|
1
|
+
# @simplysm/core-common — 비동기 런타임 (큐·이벤트·대기·LazyGcMap)
|
|
2
2
|
|
|
3
|
-
디바운스/직렬
|
|
3
|
+
호출 흐름 제어(디바운스/직렬 큐), 타입 안전 이벤트(EventEmitter), 대기 헬퍼(wait), 자동 만료 Map(LazyGcMap). 비동기 작업 조율·이벤트 배선·타이머 자원 정리가 필요할 때 함께 참조. 큐와 EventEmitter 는 `dispose()` 로 자원을 정리해야 함.
|
|
4
4
|
|
|
5
|
-
## EventEmitter
|
|
5
|
+
## EventEmitter
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```ts
|
|
8
|
+
class EventEmitter<TEvents extends { [K in keyof TEvents]: unknown } = Record<string, unknown>> {}
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`EventTarget` 기반 타입 안전 이벤트 이미터(브라우저·Node 공용). `TEvents` 는 이벤트명→데이터 타입 맵.
|
|
8
12
|
|
|
9
|
-
- `on(type, listener)
|
|
10
|
-
- `off(type, listener)
|
|
11
|
-
- `emit(type,
|
|
12
|
-
- `listenerCount(type)
|
|
13
|
-
- `dispose()
|
|
13
|
+
- `on(type, listener: (data: TEvents[type]) => void): void` — 리스너 등록(같은 리스너 중복 등록은 무시).
|
|
14
|
+
- `off(type, listener): void` — 리스너 제거.
|
|
15
|
+
- `emit(type, ...args): void` — 발행. 데이터 타입이 `void` 면 인자 없이 호출.
|
|
16
|
+
- `listenerCount(type): number` — 해당 이벤트의 리스너 수.
|
|
17
|
+
- `dispose(): void` — 모든 리스너 제거.
|
|
14
18
|
|
|
15
19
|
```ts
|
|
16
|
-
import { EventEmitter } from "@simplysm/core-common";
|
|
17
20
|
interface MyEvents { data: string; done: void; }
|
|
18
21
|
class MyEmitter extends EventEmitter<MyEvents> {}
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
const em = new MyEmitter();
|
|
23
|
+
em.on("data", (d) => console.log(d)); // d: string
|
|
24
|
+
em.emit("data", "hello");
|
|
25
|
+
em.emit("done"); // void 는 인자 없이
|
|
23
26
|
```
|
|
24
27
|
|
|
25
28
|
## DebounceQueue
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
```ts
|
|
31
|
+
class DebounceQueue extends EventEmitter<{ error: SdError }> {
|
|
32
|
+
constructor(delay?: number);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
연속 호출 시 **마지막 요청만** 실행하는 디바운스 큐. 입력 자동완성·연속 상태 변경 일괄 처리에.
|
|
28
37
|
|
|
29
|
-
- `
|
|
30
|
-
- `run(fn
|
|
31
|
-
- `dispose()
|
|
32
|
-
-
|
|
38
|
+
- `constructor(delay?)` — `delay`(ms) 생략 시 다음 이벤트 루프에 즉시 실행.
|
|
39
|
+
- `run(fn: () => void | Promise<void>): void` — 큐에 등록. 대기 중 함수가 있으면 교체. 실행 중에 도착한 요청은 디바운스 없이 현재 실행 직후 즉시 처리(누락 방지 의도).
|
|
40
|
+
- `dispose(): void` — 대기 함수·타이머 정리(EventEmitter dispose 포함).
|
|
41
|
+
- 작업 throw 시 `"error"` 리스너가 있으면 `SdError` 로 emit, 없으면 내부 로거로 출력.
|
|
42
|
+
|
|
43
|
+
## SerialQueue
|
|
33
44
|
|
|
34
45
|
```ts
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
q.run(() => save(value)); // 300ms 안에 다시 run 하면 이전 건 취소
|
|
46
|
+
class SerialQueue extends EventEmitter<{ error: SdError }> {
|
|
47
|
+
constructor(gap?: number);
|
|
48
|
+
}
|
|
39
49
|
```
|
|
40
50
|
|
|
41
|
-
|
|
51
|
+
큐에 등록된 함수를 **순차 실행**(이전 완료 후 다음). 에러가 나도 후속 작업은 계속.
|
|
42
52
|
|
|
43
|
-
|
|
53
|
+
- `constructor(gap = 0)` — 각 작업 사이 간격(ms).
|
|
54
|
+
- `run(fn: () => void | Promise<void>): void` — 큐에 추가하고 실행 시작.
|
|
55
|
+
- `dispose(): void` — 대기 큐 비움(실행 중 작업은 완료됨, EventEmitter dispose 포함).
|
|
56
|
+
- 작업 throw 시 `"error"` 리스너가 있으면 `SdError` emit, 없으면 내부 로거 출력.
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
```ts
|
|
59
|
+
const q = new SerialQueue();
|
|
60
|
+
q.run(async () => { await save(a); });
|
|
61
|
+
q.run(async () => { await save(b); }); // a 완료 후 실행
|
|
62
|
+
```
|
|
49
63
|
|
|
50
|
-
## wait
|
|
64
|
+
## wait (`import { wait } from "@simplysm/core-common"`)
|
|
51
65
|
|
|
52
|
-
- `
|
|
53
|
-
- `
|
|
66
|
+
- `until(forwarder: () => boolean | Promise<boolean>, milliseconds = 100, maxCount?): Promise<void>` — 조건이 true 가 될 때까지 `milliseconds` 간격으로 폴링. 첫 평가에서 true 면 즉시 반환. `maxCount` 지정 시 초과하면 `TimeoutError` throw(미지정이면 무제한).
|
|
67
|
+
- `time(millisecond: number): Promise<void>` — 지정 시간만큼 대기(`setTimeout` Promise 화).
|
|
54
68
|
|
|
55
69
|
```ts
|
|
56
70
|
import { wait } from "@simplysm/core-common";
|
|
57
|
-
await wait.until(() => isReady, 100, 50); // 100ms
|
|
58
|
-
await wait.time(
|
|
71
|
+
await wait.until(() => isReady, 100, 50); // 100ms 간격, 50회 초과 시 TimeoutError
|
|
72
|
+
await wait.time(300);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## LazyGcMap
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
class LazyGcMap<TKey, TValue> {
|
|
79
|
+
constructor(options: {
|
|
80
|
+
gcInterval?: number;
|
|
81
|
+
expireTime: number;
|
|
82
|
+
onExpire?: (key: TKey, value: TValue) => void | Promise<void>;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
59
85
|
```
|
|
60
86
|
|
|
61
|
-
|
|
87
|
+
LRU 접근 시간 기반 자동 만료 Map. 지정 시간 동안 접근 없으면 GC 타이머가 삭제. 캐시·세션 보관에. **사용 후 `dispose()` 필수**(아니면 GC 타이머가 계속 돌아 메모리 누수).
|
|
62
88
|
|
|
63
|
-
|
|
89
|
+
생성자 옵션:
|
|
90
|
+
- `expireTime: number` — 마지막 접근 후 이 ms 가 지나면 만료(필수).
|
|
91
|
+
- `gcInterval?: number` — GC 주기(ms). 생략 시 `expireTime/10`(최소 1000).
|
|
92
|
+
- `onExpire?: (key, value) => void | Promise<void>` — 만료 시 콜백(비동기 가능). 콜백 throw 시 로그 출력 후 계속 진행.
|
|
64
93
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
- `
|
|
70
|
-
- `
|
|
71
|
-
-
|
|
72
|
-
- `getOrCreate(key, factory)`: → V — 없으면 factory()로 생성·저장 후 반환(있으면 접근 시간 갱신). dispose 후 호출 시 throw.
|
|
73
|
-
- `delete(key)`: → boolean / `clear()`: → void(인스턴스 재사용 가능) / `dispose()`: → void(타이머 중지+정리, 이후 사용 불가).
|
|
74
|
-
- `values()` / `keys()` / `entries()`: → Iterator — 순회.
|
|
75
|
-
- `size`: → number — 항목 수.
|
|
94
|
+
메서드:
|
|
95
|
+
- `get(key)` — 조회 + 접근 시간 갱신(LRU). `has(key)` — 존재 확인(시간 갱신 안 함).
|
|
96
|
+
- `set(key, value)` — 저장 + 접근 시간 설정, GC 타이머 시작.
|
|
97
|
+
- `getOrCreate(key, factory)` — 없으면 `factory()` 로 생성·저장. dispose 후 호출 시 throw.
|
|
98
|
+
- `delete(key)` — 삭제(비면 GC 중지). `clear()` — 전체 삭제(인스턴스 재사용 가능). `dispose()` — 정리 후 사용 불가.
|
|
99
|
+
- `size` — 항목 수. `values()/keys()/entries()` — 이터레이터.
|
|
100
|
+
- GC 는 중복 실행 방지(이전 GC 가 끝나야 다음). 만료 콜백 중 같은 key 로 `set` 되면 재등록 항목은 삭제하지 않음(항목 참조 동일성으로 판정).
|
|
76
101
|
|
|
77
102
|
```ts
|
|
78
|
-
|
|
79
|
-
const cache = new LazyGcMap<string, Conn>({ expireTime: 60000, onExpire: (k, c) => c.close() });
|
|
103
|
+
const cache = new LazyGcMap<string, Session>({ expireTime: 60000 });
|
|
80
104
|
try {
|
|
81
|
-
|
|
105
|
+
cache.set("u1", session);
|
|
106
|
+
const s = cache.getOrCreate("u2", () => loadSession("u2"));
|
|
82
107
|
} finally {
|
|
83
|
-
// 앱/모듈 종료 시
|
|
84
108
|
cache.dispose();
|
|
85
109
|
}
|
|
86
110
|
```
|