@simplysm/sd-claude 14.0.88 → 14.0.90
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 +16 -17
- package/claude/references/sd-simplysm14/apis/angular/README.md +39 -43
- package/claude/references/sd-simplysm14/apis/angular/controls.md +174 -80
- package/claude/references/sd-simplysm14/apis/angular/crud.md +41 -50
- package/claude/references/sd-simplysm14/apis/angular/directives.md +60 -26
- package/claude/references/sd-simplysm14/apis/angular/features.md +109 -37
- package/claude/references/sd-simplysm14/apis/angular/infra.md +61 -44
- package/claude/references/sd-simplysm14/apis/angular/layout.md +39 -31
- package/claude/references/sd-simplysm14/apis/angular/overlay.md +73 -85
- package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +54 -39
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +55 -30
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +71 -67
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +82 -72
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +35 -36
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +71 -43
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +38 -30
- 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 +39 -38
- package/claude/references/sd-simplysm14/apis/core-common/README.md +95 -103
- package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +59 -54
- package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +86 -0
- package/claude/references/sd-simplysm14/apis/core-common/datetime.md +57 -66
- package/claude/references/sd-simplysm14/apis/core-common/errors.md +86 -0
- package/claude/references/sd-simplysm14/apis/core-common/obj.md +60 -42
- package/claude/references/sd-simplysm14/apis/core-common/serialization.md +55 -0
- package/claude/references/sd-simplysm14/apis/core-node/README.md +10 -8
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +29 -32
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +34 -22
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +29 -25
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +40 -53
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +22 -29
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +31 -31
- package/claude/references/sd-simplysm14/apis/excel/README.md +26 -26
- package/claude/references/sd-simplysm14/apis/excel/cell.md +37 -29
- package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +29 -15
- package/claude/references/sd-simplysm14/apis/excel/style.md +33 -27
- package/claude/references/sd-simplysm14/apis/excel/utils.md +29 -19
- package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +78 -55
- package/claude/references/sd-simplysm14/apis/excel/wrapper.md +42 -45
- 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 +6 -62
- package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +149 -67
- package/claude/references/sd-simplysm14/apis/orm-common/expr.md +111 -99
- package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +115 -72
- package/claude/references/sd-simplysm14/apis/orm-common/schema.md +134 -92
- package/claude/references/sd-simplysm14/apis/orm-common/types.md +67 -52
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +63 -26
- package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +51 -40
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +10 -12
- 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 +90 -88
- package/claude/references/sd-simplysm14/apis/service-client/orm.md +37 -29
- package/claude/references/sd-simplysm14/apis/service-client/transport.md +45 -20
- package/claude/references/sd-simplysm14/apis/service-common/README.md +89 -40
- package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +126 -34
- package/claude/references/sd-simplysm14/apis/service-common/protocol.md +109 -54
- package/claude/references/sd-simplysm14/apis/service-server/README.md +70 -66
- package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +47 -47
- package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +71 -34
- package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +31 -32
- package/claude/references/sd-simplysm14/apis/storage/README.md +34 -28
- package/claude/references/sd-simplysm14/manuals/client-app-structure.md +142 -140
- package/claude/references/sd-simplysm14/manuals/client-orm.md +1 -1
- package/claude/references/sd-simplysm14/manuals/client-service.md +19 -7
- package/claude/references/sd-simplysm14/manuals/client-shared-data.md +2 -2
- package/claude/references/sd-simplysm14/manuals/client-system-log.md +11 -3
- package/claude/references/sd-simplysm14/manuals/data-log.md +0 -1
- package/claude/references/sd-simplysm14/manuals/orm.md +16 -0
- package/claude/rules/sd-design-rules.md +10 -0
- package/claude/skills/sd-docs/SKILL.md +58 -46
- package/claude/skills/sd-docs/references/{doc-rules.md → subagent-prompt.md} +103 -103
- package/claude/skills/sd-impl/SKILL.md +1 -1
- package/claude/skills/sd-spec/SKILL.md +858 -858
- package/claude/skills/sd-spec/references/example-spec.md +26 -36
- package/package.json +1 -1
- package/claude/references/sd-simplysm14/apis/core-common/json-transfer.md +0 -47
- 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/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
|
@@ -1,138 +1,130 @@
|
|
|
1
1
|
# @simplysm/core-common
|
|
2
2
|
|
|
3
|
-
브라우저·Node 공용 유틸리티 패키지.
|
|
3
|
+
브라우저·Node 공용 유틸리티 패키지. 날짜/시간 값 타입, 에러 클래스, 배열/객체 조작, 직렬화, 비동기 큐, 로거, 환경변수 접근을 제공. 워크스페이스 거의 모든 패키지의 기반.
|
|
4
|
+
|
|
5
|
+
> 부수효과 주의: 이 패키지를 import 하면 `Array.prototype`·`Set.prototype`·`Map.prototype` 에 확장 메서드가 설치됨(전역 prototype 변경). 확장 메서드는 `array.toMap(...)` 처럼 메서드로 직접 호출.
|
|
4
6
|
|
|
5
7
|
## 사용 트리거 인덱스
|
|
6
8
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
throw new SdError(err, "API 호출 실패"); // "API 호출 실패 => <원인 메시지>"
|
|
30
|
-
throw new ArgumentError("잘못된 사용자", { userId }); // YAML 인자 덤프 포함
|
|
9
|
+
- **에러 클래스** — `throw` 할 때, 에러 원인 체인을 만들 때, catch 에서 분기할 때. SdError/ArgumentError/NotImplementedError/TimeoutError. 자세히: [errors.md](./errors.md)
|
|
10
|
+
- **날짜/시간 값 타입** — 날짜·시간을 불변 값으로 다루거나 파싱·포맷·산술할 때. DateTime/DateOnly/Time + `dt` 포맷 네임스페이스. 자세히: [datetime.md](./datetime.md)
|
|
11
|
+
- **배열 확장 메서드** — 배열을 그룹화·정렬·중복제거·Map변환·트리화·diff/merge 할 때. `Array.prototype` 확장. 자세히: [array-ext.md](./array-ext.md)
|
|
12
|
+
- **객체 유틸 (`obj` 네임스페이스)** — 깊은 복사/비교/병합, 체인 경로 접근, key 변환을 할 때. 자세히: [obj.md](./obj.md)
|
|
13
|
+
- **직렬화/Worker 전송** — 커스텀 타입(DateTime·Uuid·Map·Set·Error 등) 포함 데이터를 JSON·XML·바이트·Worker 메시지로 주고받을 때. `json`/`xml`/`bytes`/`transfer` 네임스페이스. 자세히: [serialization.md](./serialization.md)
|
|
14
|
+
- **비동기 큐·이벤트·대기** — 디바운스/직렬 실행, 타입 안전 이벤트, 조건 대기, 자동 만료 Map 이 필요할 때. DebounceQueue/SerialQueue/EventEmitter/wait/LazyGcMap. 자세히: [async-runtime.md](./async-runtime.md)
|
|
15
|
+
- **로거** — 모듈 어디서든 로그를 찍을 때 (아래 인라인).
|
|
16
|
+
- **환경변수** — 환경변수를 읽고/쓰고/boolean 파싱할 때 (아래 인라인).
|
|
17
|
+
- **문자열/숫자/경로 유틸** — 한국어 조사, 케이스 변환, 숫자 파싱·포맷, POSIX 경로 조작 (아래 인라인).
|
|
18
|
+
- **UUID·ZIP·템플릿 태그·Set/Map 확장·공용 타입** — 그 외 단발성 유틸 (아래 인라인).
|
|
19
|
+
|
|
20
|
+
## 로거
|
|
21
|
+
|
|
22
|
+
`createLogger(tag)` — consola 기반 lazy logger 인스턴스 생성. 모듈 레벨에서 호출해도 안전(첫 메서드 접근 시점까지 `consola.withTag` 생성을 지연하므로 이후 `setupConsola()` 의 level/reporters 변경이 반영됨).
|
|
23
|
+
|
|
24
|
+
- tag: string — 로그 prefix 로 표시되는 태그. 형식은 `<도메인>:<역할>` 또는 단일 토큰 권장. 메시지 본문에 `[패키지명]` 수동 prefix 를 넣지 말 것 — 그 역할은 tag 가 담당.
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { createLogger } from "@simplysm/core-common";
|
|
28
|
+
const logger = createLogger("capacitor:auto-update");
|
|
29
|
+
logger.info("최신 버전 확인 중");
|
|
30
|
+
logger.error("checkPermissions 실패", err);
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
`console.*` 직접 호출·`consola.withTag()` 직접 호출 금지 — 항상 `createLogger` 사용.
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
- `env(key, value): void` — `process.env` 에 쓰기(process 가 있을 때만).
|
|
37
|
-
- `parseBoolEnv(value): boolean` — `"true"`/`"1"`/`"yes"`/`"on"`(대소문자 무시) → `true`, 그 외 → `false`.
|
|
35
|
+
## 환경변수
|
|
38
36
|
|
|
39
|
-
|
|
37
|
+
- `env(key)`: → `string | undefined` — 환경변수 읽기. `process.env[key]` 우선, 없으면 `import.meta.env[key]` fallback. Node·브라우저(Vite) 양쪽에서 동작.
|
|
38
|
+
- `env(key, value)`: → `void` — `process.env[key]` 에 값 쓰기 (Node 환경에서만 적용, 브라우저에선 무동작).
|
|
39
|
+
- `parseBoolEnv(value)`: → `boolean` — 환경변수 문자열을 boolean 으로 해석. `"true"|"1"|"yes"|"on"` (대소문자 무시) 이면 true, 그 외(빈 값·undefined 포함) false. 플래그성 env 판정에 사용.
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
```ts
|
|
42
|
+
import { env, parseBoolEnv } from "@simplysm/core-common";
|
|
43
|
+
if (parseBoolEnv(env("DEV"))) { /* 개발 모드 분기 */ }
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 문자열 유틸 (`str` 네임스페이스)
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
- `
|
|
45
|
-
- `
|
|
46
|
-
- `
|
|
47
|
-
- `
|
|
48
|
+
- `str.getKoreanSuffix(text, type)`: → string — 받침 유무로 한국어 조사 선택. type: `"을"`(을/를)·`"은"`(은/는)·`"이"`(이/가)·`"와"`(과/와)·`"랑"`(이랑/랑)·`"로"`(으로/로, 받침 ㄹ 은 "로")·`"라"`(이라/라). 빈 문자열·한글 아님이면 받침 없음 조사 반환. 동적 메시지 조립에 사용.
|
|
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 위치에 문자열 삽입한 새 문자열.
|
|
48
53
|
|
|
49
|
-
|
|
54
|
+
```ts
|
|
55
|
+
import { str } from "@simplysm/core-common";
|
|
56
|
+
`${name}${str.getKoreanSuffix(name, "을")} 저장했습니다`;
|
|
57
|
+
```
|
|
50
58
|
|
|
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()` 이터레이터.
|
|
59
|
+
## 숫자 유틸 (`num` 네임스페이스)
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
- `num.parseInt(text)`: → `number | undefined` — 비숫자 문자 제거 후 정수 파싱. 소수점은 버림(`"12.34"`→12). 선행 `-` 만 음수 부호로 유지, 중간 `-` 제거(`"010-1234"`→101234). 파싱 불가면 undefined.
|
|
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"`.
|
|
58
66
|
|
|
59
|
-
|
|
67
|
+
## 경로 유틸 (`path` 네임스페이스)
|
|
60
68
|
|
|
61
|
-
|
|
62
|
-
- `on(type, listener)` / `off(type, listener)` — 등록/해제(같은 리스너 중복 등록은 무시).
|
|
63
|
-
- `emit(type, data?)` — 발행(데이터 타입이 `void` 면 인자 생략).
|
|
64
|
-
- `listenerCount(type): number` — 리스너 수.
|
|
65
|
-
- `dispose()` — 모든 리스너 제거.
|
|
69
|
+
POSIX 스타일(슬래시 `/`)만 지원. 브라우저·Capacitor 환경용. Windows 백슬래시 경로 미지원.
|
|
66
70
|
|
|
67
|
-
|
|
71
|
+
- `path.join(...segments)`: → string — 세그먼트를 `/` 로 결합. 중간 중복 슬래시·빈 세그먼트 정리.
|
|
72
|
+
- `path.basename(filePath, ext?)`: → string — 파일명 추출. ext 가 주어지고 끝나면 그 확장자 제거.
|
|
73
|
+
- `path.extname(filePath)`: → string — 확장자 추출(`.` 포함). 숨김 파일(`.gitignore`)은 빈 문자열(Node 와 동일).
|
|
68
74
|
|
|
69
|
-
|
|
70
|
-
- `new DebounceQueue(delay?)` — `delay`(ms) 생략 시 다음 이벤트 루프에 즉시.
|
|
71
|
-
- `run(fn)` — 대기 함수 교체(이전 대기 폐기). `dispose()` — 타이머·대기 정리.
|
|
72
|
-
- 작업 에러는 `"error"` 리스너가 있으면 emit, 없으면 내부 로거로 출력.
|
|
75
|
+
## UUID (`Uuid` 클래스)
|
|
73
76
|
|
|
74
|
-
|
|
77
|
+
- `Uuid.generate()`: → Uuid — `crypto.getRandomValues` 기반 암호학적 안전 UUID v4 생성.
|
|
78
|
+
- `new Uuid(uuidStr)` — 문자열로 생성. 형식 불일치면 ArgumentError throw.
|
|
79
|
+
- `Uuid.fromBytes(bytes)`: → Uuid — 16바이트 Uint8Array 로 생성. 길이≠16 이면 ArgumentError.
|
|
80
|
+
- 인스턴스: `toString()` → 문자열, `toBytes()` → 16바이트 Uint8Array.
|
|
75
81
|
|
|
76
|
-
|
|
77
|
-
- `new SerialQueue(gap?)` — `gap`(ms) 작업 사이 간격(기본 0).
|
|
78
|
-
- `run(fn)` — 큐에 추가·실행. `dispose()` — 대기분 비움(실행 중 작업은 완료).
|
|
79
|
-
- 에러 처리는 DebounceQueue 와 동일.
|
|
82
|
+
## ZIP (`ZipArchive` 클래스)
|
|
80
83
|
|
|
81
|
-
|
|
84
|
+
ZIP 읽기/쓰기/압축/해제. 동일 파일 중복 해제 방지용 내부 캐시 사용. 사용 후 `close()` 필수.
|
|
82
85
|
|
|
83
|
-
- `
|
|
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>` — 리더 닫고 캐시 비움.
|
|
84
93
|
|
|
85
|
-
##
|
|
94
|
+
## 템플릿 태그 (코드 하이라이팅용)
|
|
86
95
|
|
|
87
|
-
|
|
88
|
-
- `str.getKoreanSuffix(text, type)` — 받침에 따라 한국어 조사 반환. `type`: `"을"`(을/를)·`"은"`(은/는)·`"이"`(이/가)·`"와"`(과/와)·`"랑"`(이랑/랑)·`"로"`(으로/로, ㄹ받침 예외)·`"라"`(이라/라).
|
|
89
|
-
- `str.replaceFullWidth(s)` — 전각 영문·숫자·공백·괄호 → 반각.
|
|
90
|
-
- `str.toPascalCase`/`toCamelCase`/`toKebabCase`/`toSnakeCase(s)` — 케이스 변환(연속 대문자 분리, 기존 구분자 유지).
|
|
91
|
-
- `str.isNullOrEmpty(s): s is "" | undefined` — null/undefined/빈 문자열 타입 가드.
|
|
92
|
-
- `str.insert(s, index, insertString)` — 지정 위치에 문자열 삽입.
|
|
96
|
+
`js` / `ts` / `html` / `tsql` / `mysql` / `pgsql` — 모두 동일 동작: 템플릿 리터럴을 문자열로 결합하고 공통 들여쓰기를 제거(앞뒤 빈 줄 제거). IDE 하이라이팅·가독성 목적이며 SQL 이스케이프 등 기능 차이는 없음.
|
|
93
97
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
```ts
|
|
99
|
+
import { ts } from "@simplysm/core-common";
|
|
100
|
+
const code = ts`
|
|
101
|
+
interface User { name: string; }
|
|
102
|
+
`; // 들여쓰기 정규화된 문자열
|
|
103
|
+
```
|
|
99
104
|
|
|
100
|
-
|
|
101
|
-
- `bytes.concat(arrays)` — 여러 Uint8Array 결합.
|
|
102
|
-
- `bytes.toHex(bytes)` / `bytes.fromHex(hex)` — hex 왕복(소문자 출력. fromHex 는 홀수 길이·비hex 문자 시 `ArgumentError`).
|
|
103
|
-
- `bytes.toBase64(bytes)` / `bytes.fromBase64(base64)` — base64 왕복(fromBase64 는 공백·패딩 정규화, 잘못된 문자·길이 시 `ArgumentError`).
|
|
105
|
+
## Set 확장 메서드 (`Set.prototype`)
|
|
104
106
|
|
|
105
|
-
|
|
106
|
-
- `
|
|
107
|
+
- `set.adds(...values)`: → this — 여러 값을 한 번에 add. 체이닝 가능.
|
|
108
|
+
- `set.toggle(value, addOrDel?)`: → this — 값 토글. `addOrDel` 생략 시 있으면 제거/없으면 추가, `"add"`=강제 추가, `"del"`=강제 제거. 조건부 추가/제거를 한 줄로.
|
|
107
109
|
|
|
108
|
-
|
|
109
|
-
- `wait.until(forwarder, milliseconds?, maxCount?)` — 조건이 true 될 때까지 대기. `milliseconds` 확인 간격(기본 100), `maxCount` 최대 시도(초과 시 `TimeoutError`, undefined 면 무제한).
|
|
110
|
-
- `wait.time(millisecond)` — 지정 ms 대기 Promise.
|
|
110
|
+
## Map 확장 메서드 (`Map.prototype`)
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
- `
|
|
112
|
+
- `map.getOrCreate(key, newValue)` / `getOrCreate(key, newValueFn)`: → V — key 없으면 값(또는 팩토리 호출 결과) 설정 후 반환, 있으면 기존 값. 주의: V 가 함수 타입이면 두 번째 인자 함수가 팩토리로 인식되어 호출됨 — 함수를 값으로 저장하려면 `() => myFn` 으로 감쌀 것.
|
|
113
|
+
- `map.update(key, updateFn)`: → void — `updateFn(현재값 | undefined)` 결과로 값 설정. key 가 없어도 호출됨. 카운터 증가·배열 누적에 사용. 예: `m.update(k, v => (v ?? 0) + 1)`.
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
- `primitive.typeStr(value): PrimitiveTypeStr` — 런타임 값 → 원시 타입 문자열(`"string"`|`"number"`|`"boolean"`|`"DateTime"`|`"DateOnly"`|`"Time"`|`"Uuid"`|`"Bytes"`). 미지원 타입은 `ArgumentError`.
|
|
115
|
+
## 공용 타입 (`common.types`)
|
|
117
116
|
|
|
118
|
-
|
|
117
|
+
- `Bytes` = `Uint8Array` — 바이너리 데이터 별칭. Buffer 대신 사용.
|
|
118
|
+
- `PrimitiveTypeMap` — 원시 타입 문자열 → 실제 타입 매핑(`string`/`number`/`boolean`/`DateTime`/`DateOnly`/`Time`/`Uuid`/`Bytes`). orm-common 과 공유.
|
|
119
|
+
- `PrimitiveTypeStr` = `keyof PrimitiveTypeMap` — 원시 타입 문자열 key union.
|
|
120
|
+
- `PrimitiveType` — 모든 원시 타입 값의 union(+ undefined).
|
|
121
|
+
- `DeepPartial<T>` — 모든 속성을 재귀적으로 optional 화. 원시/날짜 타입은 그대로 두고 object/array 만 재귀.
|
|
122
|
+
- `Type<TInstance>` — 클래스 생성자 타입(`new (...args) => TInstance`). DI·팩토리·instanceof 체크에 사용.
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
- `js`/`ts`/`html`/`tsql`/`mysql`/`pgsql` — 각각 JS·TS·HTML·MSSQL·MySQL·PostgreSQL 하이라이팅 의도. `` js`...` `` 형태로 사용.
|
|
124
|
+
## 원시 타입 추론 (`primitive` 네임스페이스)
|
|
122
125
|
|
|
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()` — 리더 닫고 캐시 비움.
|
|
126
|
+
- `primitive.typeStr(value)`: → PrimitiveTypeStr — 런타임 값에서 원시 타입 문자열 추론(`"hello"`→`"string"`, `new DateTime()`→`"DateTime"`, `Uint8Array`→`"Bytes"`). 지원 안 되는 타입이면 ArgumentError. ORM 컬럼 타입 판정 등에 사용.
|
|
129
127
|
|
|
130
|
-
##
|
|
128
|
+
## 에러 메시지 추출 (`err` 네임스페이스)
|
|
131
129
|
|
|
132
|
-
`
|
|
133
|
-
- `Bytes` = `Uint8Array` — 바이너리 타입 별칭.
|
|
134
|
-
- `PrimitiveTypeMap` — `{ string, number, boolean, DateTime, DateOnly, Time, Uuid, Bytes }` 원시 타입 매핑(orm-common 과 공유).
|
|
135
|
-
- `PrimitiveTypeStr` = `keyof PrimitiveTypeMap` — 원시 타입 문자열 key.
|
|
136
|
-
- `PrimitiveType` = `PrimitiveTypeMap[PrimitiveTypeStr] | undefined` — 원시 타입 union.
|
|
137
|
-
- `DeepPartial<TObject>` — 모든 속성을 재귀적으로 optional 로(원시 타입은 그대로, object/array 에만 재귀).
|
|
138
|
-
- `Type<TInstance>` — 클래스 생성자 타입(`new (...args) => TInstance`). DI·팩토리·`instanceof` 체크용.
|
|
130
|
+
- `err.message(e)`: → string — `unknown` 에러에서 메시지 추출. Error 면 `.message`, 아니면 `String(e)`. catch 블록의 `unknown` 을 안전하게 문자열화할 때.
|
|
@@ -1,72 +1,77 @@
|
|
|
1
|
-
# @simplysm/core-common —
|
|
1
|
+
# @simplysm/core-common — 배열 확장 메서드
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@simplysm/core-common` import 시 `Array.prototype` 에 설치되는 확장 메서드. 배열을 조회·그룹화·정렬·중복제거·Map/객체/트리 변환·diff/merge·집계할 때 함께 읽힘. 모두 `array.method(...)` 로 직접 호출. enumerable=false 로 설치되어 `for...in`·`Object.keys` 에 노출되지 않음.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
표기: **읽기 전용**(원본 불변, 새 배열/값 반환) vs **@mutates**(원본 직접 수정). 정렬/중복제거는 두 버전(예: `orderBy` vs `orderByThis`)이 있음.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- `first(predicate?)` / `last(predicate?)` — 첫/마지막 요소(predicate 생략 시 인덱스 끝). 없으면 `undefined`.
|
|
9
|
-
- `filterExists()` — `null`/`undefined` 제거. 반환 타입 `NonNullable<T>[]`.
|
|
10
|
-
- `ofType(type)` — 특정 타입 요소만. `type` 은 `PrimitiveTypeStr`("string"|"number"|"boolean"|"DateTime"|"DateOnly"|"Time"|"Uuid"|"Bytes") 또는 생성자(`Type<N>`). 문자열은 typeof/instanceof, 생성자는 `instanceof` + `constructor` 일치로 판정.
|
|
11
|
-
- `sum(selector?)` — 합계. 비어 있으면 0. 숫자가 아니면 `ArgumentError`.
|
|
12
|
-
- `min(selector?)` / `max(selector?)` — 최소/최대(문자열·숫자). 비어 있으면 `undefined`. 그 외 타입은 `ArgumentError`.
|
|
13
|
-
- `shuffle()` — Fisher-Yates 셔플한 새 배열.
|
|
7
|
+
## 조회 / 필터
|
|
14
8
|
|
|
15
|
-
|
|
16
|
-
- `
|
|
17
|
-
- `
|
|
18
|
-
- `
|
|
19
|
-
- `
|
|
9
|
+
- `single(predicate?)`: → `T | undefined` — 조건에 맞는 단 하나 반환. **2개 이상이면 ArgumentError throw**. 0개면 undefined. "유일해야 한다"는 불변식 검증에 사용.
|
|
10
|
+
- `first(predicate?)`: → `T | undefined` — 첫 요소(predicate 있으면 첫 매칭). 없으면 undefined.
|
|
11
|
+
- `last(predicate?)`: → `T | undefined` — 마지막 요소(predicate 있으면 뒤에서 첫 매칭).
|
|
12
|
+
- `filterExists()`: → `NonNullable<T>[]` — null/undefined 제거(타입도 좁혀짐).
|
|
13
|
+
- `ofType(type)`: → 좁혀진 배열 — PrimitiveTypeStr(`"string"`·`"number"`·`"boolean"`·`"DateTime"`·`"DateOnly"`·`"Time"`·`"Uuid"`·`"Bytes"`) 또는 생성자(`Type<N>`)로 필터. 문자열이면 typeof/instanceof, 생성자면 `instanceof` 또는 `constructor` 일치. 혼합 배열에서 특정 타입만 뽑을 때.
|
|
14
|
+
- `filterAsync(predicate)`: → `Promise<T[]>` — 비동기 조건 필터(**순차** 실행).
|
|
20
15
|
|
|
21
|
-
##
|
|
16
|
+
## 비동기 매핑
|
|
22
17
|
|
|
23
|
-
- `
|
|
24
|
-
- `
|
|
25
|
-
- `
|
|
26
|
-
- `
|
|
27
|
-
- `toSetMap(keySelector, valueSelector?)` — `Map<K, Set<V>>`. 값 중복 자동 제거.
|
|
28
|
-
- `toMapValues(keySelector, valueSelector)` — key 별로 모은 `items[]` 를 `valueSelector(items)` 로 집계해 `Map<K,V>`.
|
|
29
|
-
- `toObject(keySelector, valueSelector?)` — `Record<string,V>`. key(문자열) 중복 시 `ArgumentError`(단 기존 값이 null 이면 덮어쓰기 허용).
|
|
30
|
-
- `toTree(keyProp, parentKey)` — 평면 배열 → 트리. `parentKey` 가 null/undefined 인 항목이 루트, 각 노드에 `children` 추가(원본은 clone). 반환 `TreeArray<T>[]`.
|
|
18
|
+
- `mapAsync(selector)`: → `Promise<R[]>` — 비동기 매핑(**순차** 실행, 순서 보존).
|
|
19
|
+
- `parallelAsync(fn)`: → `Promise<R[]>` — `Promise.all` 기반 **병렬** 실행. 하나라도 reject 면 전체 reject. 독립 IO 를 동시에 돌릴 때.
|
|
20
|
+
- `mapMany(selector?)`: → 평탄화 배열 — selector 매핑 후 1단계 flat + `filterExists`. selector 없으면 자신을 flat. 중첩 배열 펼칠 때.
|
|
21
|
+
- `mapManyAsync(selector?)`: → `Promise<...>` — 비동기 매핑 후 평탄화(순차).
|
|
31
22
|
|
|
32
|
-
##
|
|
23
|
+
## 그룹화 / Map·객체 변환
|
|
33
24
|
|
|
34
|
-
- `
|
|
35
|
-
- `
|
|
36
|
-
- `
|
|
37
|
-
- `
|
|
38
|
-
- `
|
|
25
|
+
- `groupBy(keySelector, valueSelector?)`: → `{ key, values }[]` — key 별 그룹. 원시 key 는 O(n), 객체 key 는 깊은 비교 O(n²). 객체 key 가 불필요하면 `toArrayMap` 권장.
|
|
26
|
+
- `toMap(keySelector, valueSelector?)`: → `Map<K, V|T>` — key→단일값. **중복 key 면 ArgumentError**. 1:1 인덱싱에 사용.
|
|
27
|
+
- `toMapAsync(keySelector, valueSelector?)`: → `Promise<Map>` — 위의 비동기(순차) 버전(selector 가 Promise 반환 허용).
|
|
28
|
+
- `toArrayMap(keySelector, valueSelector?)`: → `Map<K, (V|T)[]>` — key→값 배열(중복 허용). O(n) 그룹화의 기본 선택지.
|
|
29
|
+
- `toSetMap(keySelector, valueSelector?)`: → `Map<K, Set<V|T>>` — key→Set(중복 자동 제거).
|
|
30
|
+
- `toMapValues(keySelector, valueSelector)`: → `Map<K, V>` — key 별로 모은 **항목 배열 전체**를 valueSelector(items)→집계값으로 변환. 그룹별 합계 등.
|
|
31
|
+
- `toObject(keySelector, valueSelector?)`: → `Record<string, V|T>` — key(string)→값 객체. 중복 key(둘 다 non-null)면 ArgumentError.
|
|
39
32
|
|
|
40
|
-
##
|
|
33
|
+
## 트리화
|
|
41
34
|
|
|
42
|
-
|
|
43
|
-
- `distinctThis(options?)` — 원본에서 중복 제거(역순 splice).
|
|
44
|
-
- `orderByThis(selector?)` / `orderByDescThis(selector?)` — 원본 in-place 정렬.
|
|
45
|
-
- `insert(index, ...items)` — 지정 위치 삽입.
|
|
46
|
-
- `remove(itemOrSelector)` — 값 일치 또는 조건 함수에 맞는 항목 전부 제거(역순 순회).
|
|
47
|
-
- `toggle(item)` — 있으면 제거, 없으면 push.
|
|
48
|
-
- `clear()` — 전부 비움.
|
|
35
|
+
- `toTree(keyProp, parentKey)`: → `TreeArray<T>[]` — 평면 배열을 트리로. `parentKey` 값이 null/undefined 인 항목이 루트, 각 노드에 `children` 추가(항목은 clone 됨). 내부 `toArrayMap` 으로 O(n). `TreeArray<T> = T & { children: TreeArray<T>[] }`.
|
|
49
36
|
|
|
50
|
-
|
|
37
|
+
```ts
|
|
38
|
+
items.toTree("id", "parentId");
|
|
39
|
+
// [{ id: 1, name: "root", children: [{ id: 2, ..., children: [] }] }]
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 정렬 / 중복제거
|
|
43
|
+
|
|
44
|
+
- `orderBy(selector?)` / `orderByDesc(selector?)`: → `T[]` (새 배열) — selector 가 반환한 string/number/boolean/DateTime/DateOnly/Time/undefined 로 정렬. null/undefined 는 오름차순 앞·내림차순 뒤. 날짜타입은 tick 비교, 문자열은 `localeCompare`. selector 없으면 요소 자체.
|
|
45
|
+
- `orderByThis(selector?)` / `orderByDescThis(selector?)`: → `T[]` @mutates — 원본을 in-place 정렬.
|
|
46
|
+
- `distinct(options?)`: → `T[]` (새 배열) — 중복 제거. options: `true`/`{ matchAddress: true }`=참조 비교 O(n), `{ keyFn }`=커스텀 key O(n), 미지정=원시는 값·객체는 깊은 비교 O(n²). 대량 객체 배열엔 `keyFn` 권장.
|
|
47
|
+
- `distinctThis(options?)`: → `T[]` @mutates — 원본에서 중복 제거(첫 등장만 유지).
|
|
48
|
+
|
|
49
|
+
## diff / merge
|
|
50
|
+
|
|
51
|
+
- `diffs(target, options?)`: → `ArrayDiffsResult<T,P>[]` — 두 배열 비교. 결과 항목은 `{ source: undefined, target }`(INSERT) / `{ source, target: undefined }`(DELETE) / `{ source, target }`(UPDATE). options: `keys`=동일성 판정 key(없으면 전체 깊은 비교), `excludes`=비교 제외 속성. target 에 중복 key 면 첫 매칭만.
|
|
52
|
+
- `oneWayDiffs(orgItems, keyPropNameOrGetValFn, options?)`: → `ArrayOneWayDiffResult<T>[]` — 현재 배열을 원본(배열 또는 `Map<key, item>`) 대비 분류. 결과 type: `"create"`(key 값 없거나 원본에 없음)·`"update"`(값 다름)·`"same"`(같음, `includeSame: true` 일 때만 포함). keyPropNameOrGetValFn 은 key 속성명 또는 `(item)=>키값` 함수. options.excludes/includes 로 비교 범위 조정. 저장 시 INSERT/UPDATE 판정에 사용.
|
|
53
|
+
- `merge(target, options?)`: → `(T|P|(T&P))[]` (새 배열) — `diffs` 결과로 source 를 기준 삼아 병합. UPDATE 는 `obj.merge` 로 깊은 병합, INSERT 는 추가, DELETE 는 유지(원본 보존). options 는 `diffs` 와 동일.
|
|
54
|
+
|
|
55
|
+
`ArrayDiffsResult`·`ArrayOneWayDiffResult`·`TreeArray`·`ComparableType`(=`string | number | boolean | DateTime | DateOnly | Time | undefined`) 타입이 함께 export 됨.
|
|
56
|
+
|
|
57
|
+
## 집계
|
|
51
58
|
|
|
52
|
-
- `
|
|
53
|
-
- `
|
|
59
|
+
- `sum(selector?)`: → number — 합계(빈 배열 0). 숫자 아닌 값이면 ArgumentError.
|
|
60
|
+
- `min(selector?)` / `max(selector?)`: → `string | number | undefined` — 최소/최대. 숫자·문자열만 허용(아니면 ArgumentError). 빈 배열 undefined.
|
|
54
61
|
|
|
55
|
-
##
|
|
62
|
+
## 그 외 @mutates
|
|
56
63
|
|
|
57
|
-
- `
|
|
58
|
-
- `
|
|
64
|
+
- `insert(index, ...items)`: → this — index 위치에 삽입.
|
|
65
|
+
- `remove(item)` / `remove(selector)`: → this — 일치 항목(또는 조건 매칭) 모두 제거(역순 순회 O(n)).
|
|
66
|
+
- `toggle(item)`: → this — 있으면 제거·없으면 push.
|
|
67
|
+
- `clear()`: → this — 전체 비움.
|
|
59
68
|
|
|
60
|
-
##
|
|
69
|
+
## shuffle
|
|
61
70
|
|
|
62
|
-
- `
|
|
63
|
-
- `ArrayOneWayDiffResult<TItem>` — `{ type: "create"|"update"|"same", item, orgItem }` (create 는 `orgItem: undefined`).
|
|
64
|
-
- `TreeArray<TNode>` — `TNode & { children: TreeArray<TNode>[] }`.
|
|
65
|
-
- `ComparableType` — `string | number | boolean | DateTime | DateOnly | Time | undefined`. 정렬/비교 가능 타입.
|
|
71
|
+
- `shuffle()`: → `T[]` (새 배열) — Fisher–Yates 무작위 섞기. 원본 불변.
|
|
66
72
|
|
|
67
|
-
```
|
|
68
|
-
const
|
|
69
|
-
const sorted = items.orderBy((
|
|
70
|
-
const
|
|
71
|
-
const changes = current.oneWayDiffs(original, "id"); // create/update 분류
|
|
73
|
+
```ts
|
|
74
|
+
const grouped = users.toArrayMap((u) => u.teamId); // Map<teamId, User[]>
|
|
75
|
+
const sorted = items.orderBy((x) => x.createdAt); // DateTime 기준 오름차순
|
|
76
|
+
const diff = next.oneWayDiffs(prev, "id"); // create/update/same 분류
|
|
72
77
|
```
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# @simplysm/core-common — 비동기 런타임
|
|
2
|
+
|
|
3
|
+
디바운스/직렬 실행, 타입 안전 이벤트, 조건 대기, 자동 만료 Map 이 필요할 때 함께 읽히는 묶음. 큐 클래스들은 `EventEmitter` 를 상속해 `"error"` 이벤트를 발행함.
|
|
4
|
+
|
|
5
|
+
## EventEmitter<TEvents>
|
|
6
|
+
|
|
7
|
+
`EventTarget` 기반 타입 안전 이벤트 이미터(브라우저·Node 공용). 보통 상속해서 사용. `TEvents` 는 `{ 이벤트명: 데이터타입 }` 맵.
|
|
8
|
+
|
|
9
|
+
- `on(type, listener)`: → void — 리스너 등록. 같은 (type, listener) 중복 등록은 무시.
|
|
10
|
+
- `off(type, listener)`: → void — 리스너 제거.
|
|
11
|
+
- `emit(type, data)`: → void — 발행. 데이터 타입이 `void` 인 이벤트는 인자 없이 `emit(type)`.
|
|
12
|
+
- `listenerCount(type)`: → number — 해당 이벤트 리스너 수.
|
|
13
|
+
- `dispose()`: → void — 모든 리스너 제거.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { EventEmitter } from "@simplysm/core-common";
|
|
17
|
+
interface MyEvents { data: string; done: void; }
|
|
18
|
+
class MyEmitter extends EventEmitter<MyEvents> {}
|
|
19
|
+
const e = new MyEmitter();
|
|
20
|
+
e.on("data", (d) => console.log(d)); // d: string
|
|
21
|
+
e.emit("data", "hello");
|
|
22
|
+
e.emit("done");
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## DebounceQueue
|
|
26
|
+
|
|
27
|
+
짧은 시간 내 여러 호출 중 **마지막 요청만** 실행. 입력 자동완성·연속 상태 변경 일괄 처리에. `EventEmitter<{ error: SdError }>` 상속.
|
|
28
|
+
|
|
29
|
+
- `new DebounceQueue(delay?)` — delay: number(ms). 생략 시 즉시(다음 이벤트 루프).
|
|
30
|
+
- `run(fn)`: → void — `fn: () => void | Promise<void>` 등록. 이전 대기 fn 은 교체됨. delay 후 실행. 실행 중 들어온 요청은 delay 없이 현재 실행 직후 즉시 처리(요청 누락 방지).
|
|
31
|
+
- `dispose()`: → void — 대기 작업·타이머 정리(+ 리스너 제거).
|
|
32
|
+
- fn 에서 throw 시 `"error"` 리스너가 있으면 SdError 로 emit, 없으면 내부 logger.error.
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { DebounceQueue } from "@simplysm/core-common";
|
|
36
|
+
const q = new DebounceQueue(300);
|
|
37
|
+
q.on("error", (err) => console.error(err));
|
|
38
|
+
q.run(() => save(value)); // 300ms 안에 다시 run 하면 이전 건 취소
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## SerialQueue
|
|
42
|
+
|
|
43
|
+
큐에 넣은 작업을 **순차** 실행(앞 작업 완료 후 다음). 에러가 나도 후속 작업은 계속. `EventEmitter<{ error: SdError }>` 상속.
|
|
44
|
+
|
|
45
|
+
- `new SerialQueue(gap?)` — gap: number(ms, 기본 0). 각 작업 사이 대기 간격.
|
|
46
|
+
- `run(fn)`: → void — `fn: () => void | Promise<void>` 추가 후 처리 시작.
|
|
47
|
+
- `dispose()`: → void — 대기 큐 비움(실행 중 작업은 완료됨)(+ 리스너 제거).
|
|
48
|
+
- fn throw 시 처리: DebounceQueue 와 동일(`"error"` emit 또는 logger.error).
|
|
49
|
+
|
|
50
|
+
## wait 네임스페이스
|
|
51
|
+
|
|
52
|
+
- `wait.until(forwarder, milliseconds?, maxCount?)`: → `Promise<void>` — `forwarder()`(boolean | Promise<boolean>) 가 true 될 때까지 대기. 첫 호출에서 true 면 즉시 반환. milliseconds=확인 간격(기본 100). maxCount=최대 시도 횟수(미지정 무제한). 초과 시 **TimeoutError throw**.
|
|
53
|
+
- `wait.time(millisecond)`: → `Promise<void>` — 지정 시간만큼 sleep.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { wait } from "@simplysm/core-common";
|
|
57
|
+
await wait.until(() => isReady, 100, 50); // 100ms 간격 최대 50회, 초과 시 TimeoutError
|
|
58
|
+
await wait.time(500);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## LazyGcMap<TKey, TValue>
|
|
62
|
+
|
|
63
|
+
마지막 접근 이후 일정 시간 지나면 항목을 자동 삭제하는 Map(LRU 접근 시간 갱신). GC 는 항목이 있을 때만 타이머로 동작. 사용 후 **반드시 `dispose()`** — 안 하면 타이머가 남아 메모리 누수.
|
|
64
|
+
|
|
65
|
+
- `new LazyGcMap({ expireTime, gcInterval?, onExpire? })`
|
|
66
|
+
- expireTime: number(ms) — 마지막 접근 후 이 시간 지나면 만료. (필수)
|
|
67
|
+
- gcInterval?: number(ms) — GC 점검 주기. 기본 `max(expireTime/10, 1000)`.
|
|
68
|
+
- onExpire?: `(key, value) => void | Promise<void>` — 만료 시 콜백(비동기 가능). 콜백 throw 는 logger.error 후 계속 진행. 만료 항목 정리·리소스 해제에.
|
|
69
|
+
- `get(key)`: → `V | undefined` — 조회(접근 시간 갱신=만료 연장).
|
|
70
|
+
- `has(key)`: → boolean — 존재 확인(접근 시간 갱신 안 함).
|
|
71
|
+
- `set(key, value)`: → void — 저장(GC 타이머 시작).
|
|
72
|
+
- `getOrCreate(key, factory)`: → V — 없으면 factory()로 생성·저장 후 반환(있으면 접근 시간 갱신). dispose 후 호출 시 throw.
|
|
73
|
+
- `delete(key)`: → boolean / `clear()`: → void(인스턴스 재사용 가능) / `dispose()`: → void(타이머 중지+정리, 이후 사용 불가).
|
|
74
|
+
- `values()` / `keys()` / `entries()`: → Iterator — 순회.
|
|
75
|
+
- `size`: → number — 항목 수.
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { LazyGcMap } from "@simplysm/core-common";
|
|
79
|
+
const cache = new LazyGcMap<string, Conn>({ expireTime: 60000, onExpire: (k, c) => c.close() });
|
|
80
|
+
try {
|
|
81
|
+
const conn = cache.getOrCreate(key, () => createConn());
|
|
82
|
+
} finally {
|
|
83
|
+
// 앱/모듈 종료 시
|
|
84
|
+
cache.dispose();
|
|
85
|
+
}
|
|
86
|
+
```
|