@simplysm/sd-claude 14.0.47 → 14.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{claude/references/sd-simplysm14/sd-claude/usage.md → README.md} +2 -2
- package/claude/rules/sd-claude-rules.md +25 -10
- package/claude/rules/sd-options.md +11 -6
- package/claude/sd-subagent-start.sh +6 -0
- package/claude/settings.json +1 -12
- package/claude/skills/sd-check/SKILL.md +43 -12
- package/claude/skills/sd-claude-docs/SKILL.md +30 -58
- package/claude/skills/sd-claude-docs/references/package-claudemd.md +12 -0
- package/claude/skills/sd-claude-docs/references/package-doc-gen.md +26 -13
- package/claude/skills/sd-commit/SKILL.md +1 -1
- package/claude/skills/sd-debug/SKILL.md +5 -3
- package/claude/skills/sd-deliverable/SKILL.md +1 -1
- package/claude/skills/sd-dev/SKILL.md +14 -9
- package/claude/skills/sd-doc-extract/SKILL.md +8 -10
- package/claude/skills/sd-doc-extract/_common.py +8 -1
- package/claude/skills/sd-doc-extract/_extract_docx.py +74 -34
- package/claude/skills/sd-doc-extract/_extract_pdf.py +12 -1
- package/claude/skills/sd-doc-extract/_extract_pptx.py +103 -23
- package/claude/skills/sd-doc-extract/_extract_xlsb.py +93 -4
- package/claude/skills/sd-doc-extract/_extract_xlsx.py +98 -36
- package/claude/skills/sd-doc-extract/extract.py +22 -3
- package/claude/skills/sd-inner-clarify/SKILL.md +78 -0
- package/claude/skills/sd-inner-debug/SKILL.md +1 -1
- package/claude/skills/sd-inner-review/SKILL.md +13 -0
- package/claude/skills/sd-issue/SKILL.md +1 -1
- package/claude/skills/sd-outlook/SKILL.md +1 -1
- package/claude/skills/sd-plan/SKILL.md +50 -17
- package/claude/skills/sd-prompt/SKILL.md +180 -178
- package/claude/skills/sd-prompt/references/eval-runner.md +5 -30
- package/claude/skills/sd-prompt/references/sd-eval-env-template.md +23 -0
- package/claude/skills/sd-refactor/SKILL.md +2 -2
- package/claude/skills/sd-tdd/SKILL.md +45 -16
- package/claude/skills/sd-use/SKILL.md +84 -80
- package/claude/skills/sd-wbs/SKILL.md +84 -27
- package/{claude/references/sd-simplysm14/sd-claude/docs → docs}/assets.md +2 -3
- package/{claude/references/sd-simplysm14/sd-claude/docs → docs}/hooks.md +7 -6
- package/{claude/references/sd-simplysm14/sd-claude/docs → docs}/scripts.md +1 -9
- package/package.json +3 -2
- package/scripts/sync.mjs +4 -2
- package/claude/references/sd-simplysm14/angular/docs/bootstrap.md +0 -48
- package/claude/references/sd-simplysm14/angular/docs/directives.md +0 -236
- package/claude/references/sd-simplysm14/angular/docs/features.md +0 -379
- package/claude/references/sd-simplysm14/angular/docs/pipes.md +0 -32
- package/claude/references/sd-simplysm14/angular/docs/plugins.md +0 -37
- package/claude/references/sd-simplysm14/angular/docs/provider-types.md +0 -283
- package/claude/references/sd-simplysm14/angular/docs/providers.md +0 -379
- package/claude/references/sd-simplysm14/angular/docs/styling.md +0 -222
- package/claude/references/sd-simplysm14/angular/docs/type-utilities.md +0 -250
- package/claude/references/sd-simplysm14/angular/docs/ui-data.md +0 -275
- package/claude/references/sd-simplysm14/angular/docs/ui-form.md +0 -490
- package/claude/references/sd-simplysm14/angular/docs/ui-layout.md +0 -140
- package/claude/references/sd-simplysm14/angular/docs/ui-navigation.md +0 -273
- package/claude/references/sd-simplysm14/angular/docs/ui-overlay.md +0 -157
- package/claude/references/sd-simplysm14/angular/docs/ui-visual.md +0 -127
- package/claude/references/sd-simplysm14/angular/docs/utils.md +0 -295
- package/claude/references/sd-simplysm14/angular/usage.md +0 -489
- package/claude/references/sd-simplysm14/capacitor-plugin-auto-update/usage.md +0 -182
- package/claude/references/sd-simplysm14/capacitor-plugin-file-system/docs/file-operations.md +0 -154
- package/claude/references/sd-simplysm14/capacitor-plugin-file-system/docs/permissions.md +0 -84
- package/claude/references/sd-simplysm14/capacitor-plugin-file-system/docs/storage-paths.md +0 -107
- package/claude/references/sd-simplysm14/capacitor-plugin-file-system/docs/types.md +0 -83
- package/claude/references/sd-simplysm14/capacitor-plugin-file-system/usage.md +0 -133
- package/claude/references/sd-simplysm14/capacitor-plugin-intent/usage.md +0 -203
- package/claude/references/sd-simplysm14/capacitor-plugin-usb-storage/usage.md +0 -258
- package/claude/references/sd-simplysm14/core-browser/usage.md +0 -306
- package/claude/references/sd-simplysm14/core-common/docs/errors.md +0 -82
- package/claude/references/sd-simplysm14/core-common/docs/extensions.md +0 -167
- package/claude/references/sd-simplysm14/core-common/docs/features.md +0 -136
- package/claude/references/sd-simplysm14/core-common/docs/types.md +0 -245
- package/claude/references/sd-simplysm14/core-common/docs/utils.md +0 -591
- package/claude/references/sd-simplysm14/core-common/usage.md +0 -255
- package/claude/references/sd-simplysm14/core-node/docs/child-process.md +0 -182
- package/claude/references/sd-simplysm14/core-node/docs/features.md +0 -214
- package/claude/references/sd-simplysm14/core-node/docs/file-system.md +0 -509
- package/claude/references/sd-simplysm14/core-node/docs/file-watching.md +0 -139
- package/claude/references/sd-simplysm14/core-node/docs/logging.md +0 -180
- package/claude/references/sd-simplysm14/core-node/docs/path.md +0 -176
- package/claude/references/sd-simplysm14/core-node/docs/utilities-cpx.md +0 -194
- package/claude/references/sd-simplysm14/core-node/docs/utilities-fsx.md +0 -469
- package/claude/references/sd-simplysm14/core-node/docs/utilities-pathx.md +0 -151
- package/claude/references/sd-simplysm14/core-node/docs/worker-threads.md +0 -334
- package/claude/references/sd-simplysm14/core-node/docs/worker.md +0 -205
- package/claude/references/sd-simplysm14/core-node/usage.md +0 -259
- package/claude/references/sd-simplysm14/excel/docs/core-classes.md +0 -453
- package/claude/references/sd-simplysm14/excel/docs/types.md +0 -459
- package/claude/references/sd-simplysm14/excel/docs/utilities.md +0 -194
- package/claude/references/sd-simplysm14/excel/docs/wrapper.md +0 -73
- package/claude/references/sd-simplysm14/excel/usage.md +0 -134
- package/claude/references/sd-simplysm14/lint/usage.md +0 -130
- package/claude/references/sd-simplysm14/orm-common/docs/core.md +0 -188
- package/claude/references/sd-simplysm14/orm-common/docs/expression.md +0 -190
- package/claude/references/sd-simplysm14/orm-common/docs/models.md +0 -17
- package/claude/references/sd-simplysm14/orm-common/docs/query-builder.md +0 -97
- package/claude/references/sd-simplysm14/orm-common/docs/queryable-executable.md +0 -250
- package/claude/references/sd-simplysm14/orm-common/docs/schema-builders.md +0 -364
- package/claude/references/sd-simplysm14/orm-common/docs/types.md +0 -522
- package/claude/references/sd-simplysm14/orm-common/usage.md +0 -229
- package/claude/references/sd-simplysm14/orm-node/docs/connections.md +0 -137
- package/claude/references/sd-simplysm14/orm-node/docs/core.md +0 -131
- package/claude/references/sd-simplysm14/orm-node/docs/types.md +0 -173
- package/claude/references/sd-simplysm14/orm-node/usage.md +0 -143
- package/claude/references/sd-simplysm14/sd-cli/usage.md +0 -782
- package/claude/references/sd-simplysm14/service-client/docs/features.md +0 -217
- package/claude/references/sd-simplysm14/service-client/docs/main.md +0 -148
- package/claude/references/sd-simplysm14/service-client/docs/protocol.md +0 -53
- package/claude/references/sd-simplysm14/service-client/docs/transport.md +0 -131
- package/claude/references/sd-simplysm14/service-client/docs/types.md +0 -129
- package/claude/references/sd-simplysm14/service-client/usage.md +0 -202
- package/claude/references/sd-simplysm14/service-common/docs/app-structure.md +0 -175
- package/claude/references/sd-simplysm14/service-common/docs/events.md +0 -64
- package/claude/references/sd-simplysm14/service-common/docs/protocol.md +0 -331
- package/claude/references/sd-simplysm14/service-common/docs/service-types.md +0 -90
- package/claude/references/sd-simplysm14/service-common/docs/types.md +0 -19
- package/claude/references/sd-simplysm14/service-common/usage.md +0 -154
- package/claude/references/sd-simplysm14/service-server/docs/auth.md +0 -64
- package/claude/references/sd-simplysm14/service-server/docs/core.md +0 -174
- package/claude/references/sd-simplysm14/service-server/docs/legacy.md +0 -25
- package/claude/references/sd-simplysm14/service-server/docs/main.md +0 -88
- package/claude/references/sd-simplysm14/service-server/docs/protocol.md +0 -33
- package/claude/references/sd-simplysm14/service-server/docs/services.md +0 -94
- package/claude/references/sd-simplysm14/service-server/docs/transport-http.md +0 -93
- package/claude/references/sd-simplysm14/service-server/docs/transport-socket.md +0 -119
- package/claude/references/sd-simplysm14/service-server/docs/types.md +0 -36
- package/claude/references/sd-simplysm14/service-server/docs/utils.md +0 -22
- package/claude/references/sd-simplysm14/service-server/usage.md +0 -171
- package/claude/references/sd-simplysm14/storage/usage.md +0 -301
- package/claude/references/sd-simplysm14.md +0 -35
- package/claude/rules/sd-clarify.md +0 -23
- package/claude/sd-session-start.sh +0 -10
- /package/{claude/references/sd-simplysm14/sd-claude/docs → docs}/cli.md +0 -0
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
# @simplysm/core-common
|
|
2
|
-
|
|
3
|
-
브라우저와 Node.js 모두에서 사용 가능한 순수 공통 유틸리티 패키지. 다른 `@simplysm/*` 패키지에 대한 내부 의존성이 없는 리프 패키지다.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @simplysm/core-common
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## API Overview
|
|
12
|
-
|
|
13
|
-
### Errors
|
|
14
|
-
|
|
15
|
-
| API | Type | Description |
|
|
16
|
-
|-----|------|-------------|
|
|
17
|
-
| `SdError` | class | 트리 구조 에러 체인 지원. 메시지를 역순으로 결합 (상위 => 하위 => 원인) |
|
|
18
|
-
| `ArgumentError` | class | 인자 유효성 오류. 인자 객체를 YAML 형식으로 메시지에 포함 |
|
|
19
|
-
| `NotImplementedError` | class | 미구현 기능 호출 시 발생 |
|
|
20
|
-
| `TimeoutError` | class | 대기 시간 초과 시 발생 (시도 횟수 포함) |
|
|
21
|
-
|
|
22
|
-
→ See [docs/errors.md](./docs/errors.md) for details.
|
|
23
|
-
|
|
24
|
-
### Types (Value Objects)
|
|
25
|
-
|
|
26
|
-
| API | Type | Description |
|
|
27
|
-
|-----|------|-------------|
|
|
28
|
-
| `DateTime` | class | 불변 날짜시간 (밀리초 정밀도, 로컬 타임존) |
|
|
29
|
-
| `DateOnly` | class | 불변 날짜 (시간 제외, 주차 계산 지원) |
|
|
30
|
-
| `Time` | class | 불변 시간 (24시간 순환, 날짜 제외) |
|
|
31
|
-
| `Uuid` | class | UUID v4 (crypto.getRandomValues 기반) |
|
|
32
|
-
| `LazyGcMap<TKey, TValue>` | class | 자동 만료 기능이 있는 LRU Map |
|
|
33
|
-
|
|
34
|
-
→ See [docs/types.md](./docs/types.md) for details.
|
|
35
|
-
|
|
36
|
-
### Features
|
|
37
|
-
|
|
38
|
-
| API | Type | Description |
|
|
39
|
-
|-----|------|-------------|
|
|
40
|
-
| `EventEmitter<TEvents>` | class | 타입 안전 EventEmitter (EventTarget 기반, 브라우저/Node.js 모두 지원) |
|
|
41
|
-
| `DebounceQueue` | class | 비동기 디바운스 큐 (짧은 시간 내 다수 호출 시 마지막만 실행) |
|
|
42
|
-
| `SerialQueue` | class | 비동기 직렬 큐 (순차 실행 보장) |
|
|
43
|
-
|
|
44
|
-
→ See [docs/features.md](./docs/features.md) for details.
|
|
45
|
-
|
|
46
|
-
### Extensions (Prototype)
|
|
47
|
-
|
|
48
|
-
Array, Map, Set 프로토타입 확장이 자동 등록됨 (side-effect import):
|
|
49
|
-
|
|
50
|
-
| API | Type | Description |
|
|
51
|
-
|-----|------|-------------|
|
|
52
|
-
| **Array Methods (Immutable)** | | `single`, `first`, `last`, `filterExists`, `ofType`, `groupBy`, `toMap`, `toMapAsync`, `toArrayMap`, `toSetMap`, `toMapValues`, `toObject`, `toTree`, `distinct`, `orderBy`, `orderByDesc`, `diffs`, `oneWayDiffs`, `merge`, `sum`, `min`, `max`, `shuffle`, `mapAsync`, `filterAsync`, `mapMany`, `mapManyAsync`, `parallelAsync` |
|
|
53
|
-
| **Array Methods (Mutable)** | | `remove`, `insert`, `toggle`, `clear`, `distinctThis`, `orderByThis`, `orderByDescThis` |
|
|
54
|
-
| **Map Extensions** | | `getOrCreate`, `update` |
|
|
55
|
-
| **Set Extensions** | | `adds`, `toggle` |
|
|
56
|
-
| `ArrayDiffsResult<T, P>` | type | diffs() 결과 타입 (INSERT/DELETE/UPDATE) |
|
|
57
|
-
| `ArrayOneWayDiffResult<T>` | type | oneWayDiffs() 결과 타입 (create/update/same) |
|
|
58
|
-
| `TreeArray<T>` | type | toTree() 결과 타입 (children 속성 추가) |
|
|
59
|
-
| `ComparableType` | type | 정렬/비교 가능한 타입 union |
|
|
60
|
-
|
|
61
|
-
→ See [docs/extensions.md](./docs/extensions.md) for details.
|
|
62
|
-
|
|
63
|
-
### Environment
|
|
64
|
-
|
|
65
|
-
| API | Type | Description |
|
|
66
|
-
|-----|------|-------------|
|
|
67
|
-
| `env` | function | 환경변수 get/set. `env(key)` 읽기, `env(key, value)` 쓰기 |
|
|
68
|
-
| `parseBoolEnv` | function | 환경변수 값을 boolean으로 파싱 ("true"/"1"/"yes"/"on" -> true) |
|
|
69
|
-
|
|
70
|
-
### Utils (Namespace Imports)
|
|
71
|
-
|
|
72
|
-
| API | Type | Description |
|
|
73
|
-
|-----|------|-------------|
|
|
74
|
-
| `obj` | namespace | clone, equal, merge, merge3, omit, omitByFilter, pick, getChainValue, getChainValueByDepth, setChainValue, deleteChainValue, clearUndefined, clear, nullToUndefined, unflatten, keys, entries, fromEntries, map |
|
|
75
|
-
| `str` | namespace | getKoreanSuffix, replaceFullWidth, toPascalCase, toCamelCase, toKebabCase, toSnakeCase, isNullOrEmpty, insert |
|
|
76
|
-
| `num` | namespace | parseInt, parseFloat, parseRoundedInt, isNullOrEmpty, format |
|
|
77
|
-
| `bytes` | namespace | concat, toHex, fromHex, toBase64, fromBase64 |
|
|
78
|
-
| `path` | namespace | join, basename, extname |
|
|
79
|
-
| `json` | namespace | stringify, parse |
|
|
80
|
-
| `xml` | namespace | parse, stringify |
|
|
81
|
-
| `wait` | namespace | until, time |
|
|
82
|
-
| `transfer` | namespace | encode, decode |
|
|
83
|
-
| `err` | namespace | message |
|
|
84
|
-
| `dt` | namespace | format, normalizeMonth, convert12To24 |
|
|
85
|
-
| `primitive` | namespace | typeStr |
|
|
86
|
-
|
|
87
|
-
→ See [docs/utils.md](./docs/utils.md) for details.
|
|
88
|
-
|
|
89
|
-
### Utils (Direct Exports)
|
|
90
|
-
|
|
91
|
-
| API | Type | Description |
|
|
92
|
-
|-----|------|-------------|
|
|
93
|
-
| `js` | function | JavaScript 코드 하이라이팅용 태그드 템플릿 리터럴 |
|
|
94
|
-
| `ts` | function | TypeScript 코드 하이라이팅용 태그드 템플릿 리터럴 |
|
|
95
|
-
| `html` | function | HTML 마크업 하이라이팅용 태그드 템플릿 리터럴 |
|
|
96
|
-
| `tsql` | function | MSSQL T-SQL 하이라이팅용 태그드 템플릿 리터럴 |
|
|
97
|
-
| `mysql` | function | MySQL SQL 하이라이팅용 태그드 템플릿 리터럴 |
|
|
98
|
-
| `pgsql` | function | PostgreSQL SQL 하이라이팅용 태그드 템플릿 리터럴 |
|
|
99
|
-
| `ZipArchive` | class | ZIP 파일 읽기/쓰기/압축/해제 (캐싱, 진행률 콜백 지원) |
|
|
100
|
-
| `ZipArchiveProgress` | interface | ZipArchive 진행률 콜백 데이터 |
|
|
101
|
-
|
|
102
|
-
### Type Utilities
|
|
103
|
-
|
|
104
|
-
| API | Type | Description |
|
|
105
|
-
|-----|------|-------------|
|
|
106
|
-
| `Bytes` | type | `Uint8Array` 별칭 (Buffer 대신 사용) |
|
|
107
|
-
| `PrimitiveTypeMap` | type | 원시 타입 문자열 key -> 타입 매핑 |
|
|
108
|
-
| `PrimitiveTypeStr` | type | 원시 타입 문자열 key union (`"string" \| "number" \| ...`) |
|
|
109
|
-
| `PrimitiveType` | type | 원시 타입 union (`string \| number \| boolean \| DateTime \| ...`) |
|
|
110
|
-
| `DeepPartial<T>` | type | 모든 속성을 재귀적으로 optional로 변환 |
|
|
111
|
-
| `Type<T>` | interface | 생성자 타입 (`new (...args) => T`) |
|
|
112
|
-
| `EqualOptions` | interface | obj.equal() 옵션 |
|
|
113
|
-
| `MergeOptions` | interface | obj.merge() 옵션 |
|
|
114
|
-
| `Merge3KeyOptions` | interface | obj.merge3() key 옵션 |
|
|
115
|
-
| `DtNormalizedMonth` | interface | dt.normalizeMonth() 결과 타입 |
|
|
116
|
-
| `UndefToOptional<T>` | type | undefined 타입을 optional로 변환 |
|
|
117
|
-
| `OptionalToUndef<T>` | type | optional 속성을 undefined 포함 타입으로 변환 |
|
|
118
|
-
|
|
119
|
-
→ See [docs/utils.md](./docs/utils.md) for details.
|
|
120
|
-
|
|
121
|
-
## Usage Examples
|
|
122
|
-
|
|
123
|
-
### 프로토타입 확장 사용
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
126
|
-
import "@simplysm/core-common";
|
|
127
|
-
|
|
128
|
-
// Array 확장
|
|
129
|
-
const users = [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }];
|
|
130
|
-
const user = users.single((u) => u.id === 1);
|
|
131
|
-
const grouped = users.groupBy((u) => u.name);
|
|
132
|
-
const sorted = users.orderBy((u) => u.name);
|
|
133
|
-
const diffs = newUsers.diffs(oldUsers, { keys: ["id"] });
|
|
134
|
-
|
|
135
|
-
// Map 확장
|
|
136
|
-
const cache = new Map<string, number[]>();
|
|
137
|
-
const arr = cache.getOrCreate("key", []);
|
|
138
|
-
|
|
139
|
-
// Set 확장
|
|
140
|
-
const set = new Set<string>();
|
|
141
|
-
set.adds("a", "b", "c"); // 여러 항목 추가
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### 에러 체인 처리
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
import { SdError } from "@simplysm/core-common";
|
|
148
|
-
|
|
149
|
-
try {
|
|
150
|
-
await fetch(url);
|
|
151
|
-
} catch (err) {
|
|
152
|
-
throw new SdError(err, "API 호출 실패", "사용자 로드 실패");
|
|
153
|
-
// 결과 메시지: "사용자 로드 실패 => API 호출 실패 => 원본 에러 메시지"
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### 네임스페이스 유틸리티 사용
|
|
158
|
-
|
|
159
|
-
```typescript
|
|
160
|
-
import { obj, str, json, DateTime, Uuid } from "@simplysm/core-common";
|
|
161
|
-
|
|
162
|
-
// 깊은 복사 및 비교
|
|
163
|
-
const copied = obj.clone({ nested: { data: [1, 2, 3] } });
|
|
164
|
-
const isEqual = obj.equal(a, b, { topLevelExcludes: ["updatedAt"] });
|
|
165
|
-
const merged = obj.merge(defaults, overrides);
|
|
166
|
-
|
|
167
|
-
// obj.omit, obj.pick
|
|
168
|
-
const noId = obj.omit(user, ["id"]);
|
|
169
|
-
const onlyName = obj.pick(user, ["name", "email"]);
|
|
170
|
-
|
|
171
|
-
// 한국어 조사 처리
|
|
172
|
-
const suffix = str.getKoreanSuffix("파일", "을"); // "을"
|
|
173
|
-
const camel = str.toCamelCase("HelloWorld"); // "helloWorld"
|
|
174
|
-
|
|
175
|
-
// 커스텀 타입 지원 JSON 직렬화
|
|
176
|
-
const serialized = json.stringify({
|
|
177
|
-
date: new DateTime(),
|
|
178
|
-
id: Uuid.generate()
|
|
179
|
-
});
|
|
180
|
-
const restored = json.parse(serialized); // DateTime, Uuid 타입 복원됨
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### 비동기 큐 사용
|
|
184
|
-
|
|
185
|
-
```typescript
|
|
186
|
-
import { DebounceQueue, SerialQueue } from "@simplysm/core-common";
|
|
187
|
-
|
|
188
|
-
// 디바운스 큐: 짧은 시간 내 재호출 시 이전 호출 무시
|
|
189
|
-
const dq = new DebounceQueue(300);
|
|
190
|
-
dq.on("error", (err) => console.error(err));
|
|
191
|
-
dq.run(() => saveData());
|
|
192
|
-
dq.run(() => saveData()); // 첫 번째 호출 무시, 300ms 후 마지막만 실행
|
|
193
|
-
|
|
194
|
-
// 직렬 큐: 순차 실행
|
|
195
|
-
const sq = new SerialQueue();
|
|
196
|
-
sq.run(async () => await step1());
|
|
197
|
-
sq.run(async () => await step2()); // step1 완료 후 실행
|
|
198
|
-
sq.run(async () => await step3()); // step2 완료 후 실행
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### DateTime 사용
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
import { DateTime, DateOnly, Time, Uuid } from "@simplysm/core-common";
|
|
205
|
-
|
|
206
|
-
const now = new DateTime();
|
|
207
|
-
const specific = new DateTime(2025, 1, 15, 10, 30, 0);
|
|
208
|
-
const parsed = DateTime.parse("2025-01-15 10:30:00");
|
|
209
|
-
const formatted = now.toFormatString("yyyy-MM-dd HH:mm:ss");
|
|
210
|
-
const today = new DateOnly();
|
|
211
|
-
const id = Uuid.generate();
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### 자동 만료 Map 사용
|
|
215
|
-
|
|
216
|
-
```typescript
|
|
217
|
-
import { LazyGcMap } from "@simplysm/core-common";
|
|
218
|
-
|
|
219
|
-
const cache = new LazyGcMap<string, Data>({
|
|
220
|
-
expireTime: 60_000,
|
|
221
|
-
onExpire: async (key, value) => {
|
|
222
|
-
await value.cleanup();
|
|
223
|
-
},
|
|
224
|
-
});
|
|
225
|
-
try {
|
|
226
|
-
cache.set("key", data);
|
|
227
|
-
const val = cache.get("key"); // 접근 시간 갱신
|
|
228
|
-
} finally {
|
|
229
|
-
cache.dispose();
|
|
230
|
-
}
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
### EventEmitter 사용
|
|
234
|
-
|
|
235
|
-
```typescript
|
|
236
|
-
import { EventEmitter } from "@simplysm/core-common";
|
|
237
|
-
|
|
238
|
-
interface MyEvents {
|
|
239
|
-
data: string;
|
|
240
|
-
error: Error;
|
|
241
|
-
done: void;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
class MyService extends EventEmitter<MyEvents> {
|
|
245
|
-
async load() {
|
|
246
|
-
this.emit("data", "Loading...");
|
|
247
|
-
this.emit("done"); // void 타입은 인자 없이 호출
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const svc = new MyService();
|
|
252
|
-
svc.on("data", (data) => console.log(data)); // data: string
|
|
253
|
-
svc.on("done", () => console.log("completed"));
|
|
254
|
-
await svc.load();
|
|
255
|
-
```
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
# Child Process (cpx)
|
|
2
|
-
|
|
3
|
-
## `spawn`
|
|
4
|
-
|
|
5
|
-
자식 프로세스를 실행한다 (비동기).
|
|
6
|
-
|
|
7
|
-
SpawnProcess를 반환하며, await로 결과를 기다리거나 kill()로 프로세스를 종료할 수 있다.
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
export function spawn(
|
|
11
|
-
cmd: string,
|
|
12
|
-
args: string[],
|
|
13
|
-
options?: SpawnOptions & { reject?: boolean },
|
|
14
|
-
): SpawnProcess
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
| Parameter | Type | Description |
|
|
18
|
-
|-----------|------|-------------|
|
|
19
|
-
| `cmd` | string | 실행할 명령어 |
|
|
20
|
-
| `args` | string[] | 명령어 인자 배열 |
|
|
21
|
-
| `options` | SpawnOptions & { reject?: boolean } (optional) | spawn 옵션. `reject: false`를 지정하면 exitCode !== 0일 때도 reject되지 않음 (기본값: true) |
|
|
22
|
-
|
|
23
|
-
**Return**: SpawnProcess (PromiseLike + kill() 메서드)
|
|
24
|
-
|
|
25
|
-
**Note**: 기본적으로 `exitCode !== 0`이면 reject된다. `options.reject: false`를 지정하면 항상 resolve된다.
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## `spawnSync`
|
|
30
|
-
|
|
31
|
-
자식 프로세스를 동기로 실행한다.
|
|
32
|
-
|
|
33
|
-
```typescript
|
|
34
|
-
export function spawnSync(
|
|
35
|
-
cmd: string,
|
|
36
|
-
args: string[],
|
|
37
|
-
options?: SpawnSyncOptions & { reject?: boolean },
|
|
38
|
-
): SpawnResult
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
| Parameter | Type | Description |
|
|
42
|
-
|-----------|------|-------------|
|
|
43
|
-
| `cmd` | string | 실행할 명령어 |
|
|
44
|
-
| `args` | string[] | 명령어 인자 배열 |
|
|
45
|
-
| `options` | SpawnSyncOptions & { reject?: boolean } (optional) | spawn 옵션. `reject: false`를 지정하면 exitCode !== 0일 때도 throw되지 않음 (기본값: true) |
|
|
46
|
-
|
|
47
|
-
**Return**: SpawnResult
|
|
48
|
-
|
|
49
|
-
**Note**: 기본적으로 `exitCode !== 0`이면 throw된다. `options.reject: false`를 지정하면 항상 반환된다.
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## `SpawnProcess`
|
|
54
|
-
|
|
55
|
-
spawn() 반환 타입. PromiseLike를 구현하므로 await로 사용 가능하며, kill() 메서드로 프로세스를 종료할 수 있다.
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
export class SpawnProcess implements PromiseLike<SpawnResult> {
|
|
59
|
-
get pid(): number | undefined
|
|
60
|
-
then<TResult1 = SpawnResult, TResult2 = never>(
|
|
61
|
-
onfulfilled?: ((value: SpawnResult) => TResult1 | PromiseLike<TResult1>) | null,
|
|
62
|
-
onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,
|
|
63
|
-
): Promise<TResult1 | TResult2>
|
|
64
|
-
catch<TResult = never>(
|
|
65
|
-
onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null,
|
|
66
|
-
): Promise<SpawnResult | TResult>
|
|
67
|
-
kill(signal?: NodeJS.Signals | number): boolean
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### Properties
|
|
72
|
-
|
|
73
|
-
| Name | Type | Description |
|
|
74
|
-
|------|------|-------------|
|
|
75
|
-
| `pid` | number \| undefined | 자식 프로세스의 PID |
|
|
76
|
-
|
|
77
|
-
### Methods
|
|
78
|
-
|
|
79
|
-
| Name | Signature | Description |
|
|
80
|
-
|------|-----------|-------------|
|
|
81
|
-
| `then` | `<TResult1, TResult2>(onfulfilled?, onrejected?): Promise` | Promise의 then 메서드 |
|
|
82
|
-
| `catch` | `<TResult>(onrejected?): Promise` | Promise의 catch 메서드 |
|
|
83
|
-
| `kill` | `(signal?): boolean` | 프로세스에 신호를 보낸다 (기본값: SIGTERM) |
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## `SpawnResult`
|
|
88
|
-
|
|
89
|
-
spawn/spawnSync 결과.
|
|
90
|
-
|
|
91
|
-
```typescript
|
|
92
|
-
export interface SpawnResult {
|
|
93
|
-
stdout: string;
|
|
94
|
-
stderr: string;
|
|
95
|
-
exitCode: number;
|
|
96
|
-
}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
| Field | Type | Description |
|
|
100
|
-
|-------|------|-------------|
|
|
101
|
-
| `stdout` | string | 표준 출력 내용 |
|
|
102
|
-
| `stderr` | string | 표준 에러 내용 |
|
|
103
|
-
| `exitCode` | number | 프로세스 종료 코드 |
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## `getSystemEncoding`
|
|
108
|
-
|
|
109
|
-
시스템의 기본 인코딩을 감지한다.
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
export function getSystemEncoding(): string
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
**Return**: 시스템 인코딩 (예: "utf-8", "euc-kr")
|
|
116
|
-
|
|
117
|
-
**Note**: 결과는 캐시되므로 반복 호출은 빠르다. 캐시를 초기화하려면 resetEncodingCache()를 호출한다.
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
## `codePageToEncoding`
|
|
122
|
-
|
|
123
|
-
Windows 코드 페이지 번호를 인코딩 이름으로 변환한다.
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
126
|
-
export function codePageToEncoding(codePage: number): string
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
| Parameter | Type | Description |
|
|
130
|
-
|-----------|------|-------------|
|
|
131
|
-
| `codePage` | number | Windows 코드 페이지 번호 (예: 65001 = UTF-8, 949 = EUC-KR) |
|
|
132
|
-
|
|
133
|
-
**Return**: 인코딩 이름 (예: "utf-8"). 미지의 코드 페이지는 "utf-8"으로 폴백된다.
|
|
134
|
-
|
|
135
|
-
---
|
|
136
|
-
|
|
137
|
-
## `resetEncodingCache`
|
|
138
|
-
|
|
139
|
-
캐시된 시스템 인코딩을 초기화한다.
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
export function resetEncodingCache(): void
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
## `decodeBytes`
|
|
148
|
-
|
|
149
|
-
Uint8Array를 문자열로 디코딩한다.
|
|
150
|
-
|
|
151
|
-
```typescript
|
|
152
|
-
export function decodeBytes(raw: Uint8Array, systemEncoding?: string): string
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
| Parameter | Type | Description |
|
|
156
|
-
|-----------|------|-------------|
|
|
157
|
-
| `raw` | Uint8Array | 디코딩할 바이트 배열 |
|
|
158
|
-
| `systemEncoding` | string (optional) | 인코딩 이름. 생략하면 getSystemEncoding()의 결과를 사용한다. |
|
|
159
|
-
|
|
160
|
-
**Return**: 디코딩된 문자열
|
|
161
|
-
|
|
162
|
-
**Note**: UTF-8이 아닌 인코딩인 경우, 먼저 UTF-8로 디코딩을 시도하고 실패하면 지정된 인코딩으로 시도한다.
|
|
163
|
-
|
|
164
|
-
---
|
|
165
|
-
|
|
166
|
-
## `resolveStdioPipe`
|
|
167
|
-
|
|
168
|
-
stdio 옵션에서 stdout/stderr의 pipe 여부를 추출한다.
|
|
169
|
-
|
|
170
|
-
```typescript
|
|
171
|
-
export function resolveStdioPipe(
|
|
172
|
-
stdio: SpawnOptions["stdio"],
|
|
173
|
-
): { stdout: boolean; stderr: boolean }
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
| Parameter | Type | Description |
|
|
177
|
-
|-----------|------|-------------|
|
|
178
|
-
| `stdio` | SpawnOptions["stdio"] | spawn 옵션의 stdio 설정 |
|
|
179
|
-
|
|
180
|
-
**Return**: `{ stdout: boolean, stderr: boolean }` - 각 스트림이 pipe인지 여부
|
|
181
|
-
|
|
182
|
-
**Note**: stdio가 배열이 아니면, "pipe"(또는 undefined)일 때 true, 그 외엔 false를 반환한다.
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
# Features
|
|
2
|
-
|
|
3
|
-
파일 시스템 감시와 consola 로깅 설정 기능을 제공한다.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## `FsWatcherEvent`
|
|
8
|
-
|
|
9
|
-
지원되는 파일 변경 이벤트 타입.
|
|
10
|
-
|
|
11
|
-
```typescript
|
|
12
|
-
export type FsWatcherEvent = "add" | "addDir" | "change" | "unlink" | "unlinkDir";
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
| Value | Description |
|
|
16
|
-
|-------|-------------|
|
|
17
|
-
| `"add"` | 파일 추가 |
|
|
18
|
-
| `"addDir"` | 디렉토리 추가 |
|
|
19
|
-
| `"change"` | 파일 수정 |
|
|
20
|
-
| `"unlink"` | 파일 삭제 |
|
|
21
|
-
| `"unlinkDir"` | 디렉토리 삭제 |
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## `FsWatcherChangeInfo`
|
|
26
|
-
|
|
27
|
-
파일 변경 정보.
|
|
28
|
-
|
|
29
|
-
```typescript
|
|
30
|
-
export interface FsWatcherChangeInfo {
|
|
31
|
-
event: FsWatcherEvent;
|
|
32
|
-
path: PosixPath;
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
| Field | Type | Description |
|
|
37
|
-
|-------|------|-------------|
|
|
38
|
-
| `event` | `FsWatcherEvent` | 변경 이벤트 타입 |
|
|
39
|
-
| `path` | `PosixPath` | 변경된 파일/디렉토리 경로 (정규화됨) |
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## `FsWatcher`
|
|
44
|
-
|
|
45
|
-
Chokidar 기반 파일 시스템 감시 래퍼. 짧은 시간 내에 발생하는 이벤트를 병합하여 콜백을 한 번만 호출한다. EPERM 에러 발생 시 최대 3회 watcher를 자동 재시작한다.
|
|
46
|
-
|
|
47
|
-
**주의**: chokidar의 `ignoreInitial` 옵션은 내부적으로 항상 `true`로 설정된다.
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
export class FsWatcher {
|
|
51
|
-
static async watch(paths: string[], options?: chokidar.ChokidarOptions): Promise<FsWatcher>;
|
|
52
|
-
onChange(opt: { delay?: number }, cb: (changeInfos: FsWatcherChangeInfo[]) => void | Promise<void>): this;
|
|
53
|
-
async close(): Promise<void>;
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### `FsWatcher.watch` (static)
|
|
58
|
-
|
|
59
|
-
파일 감시를 시작한다 (비동기). ready 이벤트가 발생할 때까지 대기한다.
|
|
60
|
-
|
|
61
|
-
| Parameter | Type | Description |
|
|
62
|
-
|-----------|------|-------------|
|
|
63
|
-
| `paths` | `string[]` | 감시할 파일/디렉토리 경로 또는 glob 패턴 배열 |
|
|
64
|
-
| `options` | `chokidar.ChokidarOptions` | chokidar 옵션 |
|
|
65
|
-
|
|
66
|
-
### `onChange`
|
|
67
|
-
|
|
68
|
-
파일 변경 이벤트 핸들러를 등록한다. 지정된 지연 시간 동안 이벤트를 수집하여 콜백을 한 번 호출한다.
|
|
69
|
-
|
|
70
|
-
| Parameter | Type | Description |
|
|
71
|
-
|-----------|------|-------------|
|
|
72
|
-
| `opt.delay` | `number` | 이벤트 병합 대기 시간 (ms) |
|
|
73
|
-
| `cb` | `(changeInfos: FsWatcherChangeInfo[]) => void \| Promise<void>` | 변경 이벤트 콜백 |
|
|
74
|
-
|
|
75
|
-
**반환**: `this` (메서드 체이닝 가능)
|
|
76
|
-
|
|
77
|
-
이벤트 병합 전략:
|
|
78
|
-
- `add` + `change` → `add` (생성 직후 수정은 생성으로 간주)
|
|
79
|
-
- `add` + `unlink` → 변경 없음 (생성 직후 삭제는 변경 없음으로 간주)
|
|
80
|
-
- `unlink` + `add` → `add` (삭제 후 재생성은 생성으로 간주)
|
|
81
|
-
|
|
82
|
-
### `close`
|
|
83
|
-
|
|
84
|
-
파일 감시자를 종료한다.
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
import { FsWatcher } from "@simplysm/core-node";
|
|
88
|
-
|
|
89
|
-
const watcher = await FsWatcher.watch(["src/**/*.ts"]);
|
|
90
|
-
|
|
91
|
-
watcher.onChange({ delay: 300 }, (changes) => {
|
|
92
|
-
for (const { event, path } of changes) {
|
|
93
|
-
// event: "add" | "addDir" | "change" | "unlink" | "unlinkDir"
|
|
94
|
-
// path: PosixPath
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
await watcher.close();
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## `PrettyReporter`
|
|
104
|
-
|
|
105
|
-
터미널 출력용 consola reporter. 이벤트 타입별 아이콘과 색상을 적용하고, Error 객체의 스택 트레이스를 포맷팅한다.
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
export class PrettyReporter implements ConsolaReporter {
|
|
109
|
-
log(logObj: LogObject, ctx: { options: ConsolaOptions }): void;
|
|
110
|
-
}
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
- error/fatal 레벨은 `process.stderr`로 출력
|
|
114
|
-
- 그 외는 `process.stdout`으로 출력
|
|
115
|
-
- 터미널 색상 지원 여부를 자동 감지 (`NO_COLOR`, `FORCE_COLOR`, `isTTY`, Windows 감지)
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## `FileReporterOptions`
|
|
120
|
-
|
|
121
|
-
`createFileReporter()`의 옵션.
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
export interface FileReporterOptions {
|
|
125
|
-
maxSize?: number;
|
|
126
|
-
maxDays?: number;
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
| Field | Type | Description |
|
|
131
|
-
|-------|------|-------------|
|
|
132
|
-
| `maxSize` | `number` | 단일 로그 파일 최대 크기 (bytes). 기본값 20MB (20 \* 1024 \* 1024) |
|
|
133
|
-
| `maxDays` | `number` | 보관할 로그 파일 최대 일수. 기본값 14일 |
|
|
134
|
-
|
|
135
|
-
---
|
|
136
|
-
|
|
137
|
-
## `createFileReporter`
|
|
138
|
-
|
|
139
|
-
파일 기반 consola reporter를 생성한다. `.logs/` 디렉토리에 `app.YYYY-MM-DD.log` 형식으로 JSON 라인을 기록한다.
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
export function createFileReporter(options?: FileReporterOptions): ConsolaReporter
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
| Parameter | Type | Description |
|
|
146
|
-
|-----------|------|-------------|
|
|
147
|
-
| `options` | `FileReporterOptions` | 로그 파일 옵션 |
|
|
148
|
-
|
|
149
|
-
**동작 방식**:
|
|
150
|
-
- 날짜가 바뀌면 새 파일로 로테이션
|
|
151
|
-
- 파일 크기가 `maxSize`를 초과하면 `app.YYYY-MM-DD.1.log`, `app.YYYY-MM-DD.2.log` 형식으로 순번 추가
|
|
152
|
-
- `maxDays`보다 오래된 파일은 자동 삭제
|
|
153
|
-
- 각 로그 항목은 `{ time, level, tag?, msg?, err? }` JSON 형식
|
|
154
|
-
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
## `withMaxLevel`
|
|
158
|
-
|
|
159
|
-
consola reporter를 지정된 로그 레벨 이하로 제한하는 래퍼를 반환한다.
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
export function withMaxLevel(reporter: ConsolaReporter, maxLevel: number): ConsolaReporter
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
| Parameter | Type | Description |
|
|
166
|
-
|-----------|------|-------------|
|
|
167
|
-
| `reporter` | `ConsolaReporter` | 감쌀 reporter |
|
|
168
|
-
| `maxLevel` | `number` | 이 값보다 높은 레벨의 로그는 전달하지 않는다 |
|
|
169
|
-
|
|
170
|
-
consola의 로그 레벨: `0=fatal`, `1=error`, `2=warn`, `3=log`, `4=info`, `5=success`, `999=debug`
|
|
171
|
-
|
|
172
|
-
---
|
|
173
|
-
|
|
174
|
-
## `SetupConsolaOptions`
|
|
175
|
-
|
|
176
|
-
`setupConsola()`의 옵션.
|
|
177
|
-
|
|
178
|
-
```typescript
|
|
179
|
-
export interface SetupConsolaOptions {
|
|
180
|
-
cli?: boolean;
|
|
181
|
-
}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
| Field | Type | Description |
|
|
185
|
-
|-------|------|-------------|
|
|
186
|
-
| `cli` | `boolean` | true이면 CLI 모드. 프로덕션 경로를 건너뛰고 개발 경로로 진입한다. `SD_DEBUG`가 없으면 `FileReporter` + `PrettyReporter`(info 이하) 조합 사용 |
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
## `setupConsola`
|
|
191
|
-
|
|
192
|
-
환경에 따라 consola reporter를 자동 구성한다.
|
|
193
|
-
|
|
194
|
-
```typescript
|
|
195
|
-
export function setupConsola(opts?: SetupConsolaOptions): void
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
환경별 동작:
|
|
199
|
-
|
|
200
|
-
| 환경 | 동작 |
|
|
201
|
-
|------|------|
|
|
202
|
-
| 프로덕션 (`DEV` 환경변수 없음, `cli` 아님) | `FileReporter`만 사용, debug 레벨까지 파일 기록 |
|
|
203
|
-
| 개발 또는 `cli: true`, `SD_DEBUG=true` | `PrettyReporter`만 사용, debug 레벨까지 터미널 출력 |
|
|
204
|
-
| 개발 또는 `cli: true` (일반) | `FileReporter` + `PrettyReporter`(info 이하만), debug는 파일에만 기록 |
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
import { setupConsola } from "@simplysm/core-node";
|
|
208
|
-
|
|
209
|
-
// 환경별 자동 구성
|
|
210
|
-
setupConsola();
|
|
211
|
-
|
|
212
|
-
// CLI 모드 (항상 PrettyReporter 사용)
|
|
213
|
-
setupConsola({ cli: true });
|
|
214
|
-
```
|