@simplysm/sd-claude 14.0.76 → 14.0.77
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/output-styles/sd-tone.md +128 -0
- package/claude/references/sd-simplysm14/apis/angular/README.md +28 -89
- package/claude/references/sd-simplysm14/apis/angular/app-structure.md +75 -32
- package/claude/references/sd-simplysm14/apis/angular/buttons.md +65 -29
- package/claude/references/sd-simplysm14/apis/angular/crud.md +86 -21
- package/claude/references/sd-simplysm14/apis/angular/forms.md +168 -42
- package/claude/references/sd-simplysm14/apis/angular/infrastructure.md +200 -49
- package/claude/references/sd-simplysm14/apis/angular/kanban.md +64 -20
- package/claude/references/sd-simplysm14/apis/angular/layout.md +75 -30
- package/claude/references/sd-simplysm14/apis/angular/modal.md +92 -40
- package/claude/references/sd-simplysm14/apis/angular/routing.md +86 -25
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +72 -41
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +113 -21
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +108 -33
- package/claude/references/sd-simplysm14/apis/angular/toast.md +81 -30
- package/claude/references/sd-simplysm14/apis/angular/visual.md +140 -32
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +46 -43
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +59 -48
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +17 -7
- package/claude/references/sd-simplysm14/apis/core-common/README.md +43 -116
- package/claude/references/sd-simplysm14/apis/core-common/extensions.md +74 -109
- package/claude/references/sd-simplysm14/apis/core-common/features.md +40 -35
- package/claude/references/sd-simplysm14/apis/core-common/types.md +80 -106
- package/claude/references/sd-simplysm14/apis/core-common/utils.md +142 -111
- package/claude/references/sd-simplysm14/apis/core-node/README.md +7 -16
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +33 -38
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +25 -33
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +27 -38
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +32 -60
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +14 -45
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +35 -81
- package/claude/references/sd-simplysm14/apis/excel/README.md +178 -80
- package/claude/references/sd-simplysm14/apis/lint/README.md +5 -0
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +1 -1
- package/claude/references/sd-simplysm14/apis/sd-claude/README.md +28 -5
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +1 -1
- package/claude/references/sd-simplysm14/apis/service-client/README.md +57 -50
- package/claude/references/sd-simplysm14/apis/service-server/README.md +8 -15
- package/claude/references/sd-simplysm14/apis/service-server/auth.md +24 -16
- package/claude/references/sd-simplysm14/apis/service-server/builtin-services.md +55 -31
- package/claude/references/sd-simplysm14/apis/service-server/define-service.md +28 -44
- package/claude/references/sd-simplysm14/apis/service-server/internals.md +59 -18
- package/claude/references/sd-simplysm14/apis/service-server/server.md +37 -46
- package/claude/references/sd-simplysm14/manuals/client-component.md +3 -1
- package/claude/references/sd-simplysm14/manuals/logging.md +9 -8
- package/claude/rules/sd-base-rules.md +380 -219
- package/claude/settings.json +1 -0
- package/claude/skills/sd-commit/SKILL.md +31 -8
- package/claude/skills/sd-docs/SKILL.md +15 -10
- package/claude/skills/sd-docs/references/subagent-prompt.md +26 -8
- package/claude/skills/sd-impl/SKILL.md +1 -1
- package/claude/skills/sd-skill/references/skill-authoring.md +1 -1
- package/claude/skills/sd-spec/SKILL.md +22 -13
- package/claude/skills/sd-spec/references/spec-authoring.md +1 -1
- package/claude/skills/sd-unpack/SKILL.md +150 -26
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/_common.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/eml_handler.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/office_com.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/pdf_handler.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/_common.py +17 -2
- package/claude/skills/sd-unpack/scripts/handlers/eml_handler.py +100 -24
- package/claude/skills/sd-unpack/scripts/handlers/msg_handler.py +140 -27
- package/claude/skills/sd-unpack/scripts/handlers/office_com.py +698 -107
- package/claude/skills/sd-unpack/scripts/handlers/office_worker.py +34 -26
- package/claude/skills/sd-unpack/scripts/handlers/pdf_handler.py +130 -8
- package/package.json +1 -1
|
@@ -1,81 +1,53 @@
|
|
|
1
1
|
## @simplysm/core-node — fsx
|
|
2
2
|
|
|
3
|
-
`import { fsx } from "@simplysm/core-node"
|
|
3
|
+
`import { fsx } from "@simplysm/core-node"`. 모든 함수는 동기(`*Sync`) + 비동기 쌍 제공. 실패 시 경로 정보를 포함한 `SdError` throw.
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### 존재 확인 / 디렉토리
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
fsx.mkdirSync(p): void // recursive
|
|
11
|
-
fsx.mkdir(p): Promise<void> // recursive
|
|
12
|
-
fsx.rmSync(p): void // recursive, force, 재시도 없음
|
|
13
|
-
fsx.rm(p): Promise<void> // recursive, force, 6회/500ms 재시도 (파일 잠금 대응)
|
|
14
|
-
```
|
|
7
|
+
- `existsSync(p) / exists(p): boolean | Promise<boolean>` — 파일·디렉토리 존재 여부.
|
|
8
|
+
- `mkdirSync(p) / mkdir(p): void | Promise<void>` — 재귀 생성. 이미 있으면 무시.
|
|
9
|
+
- `readdirSync(p) / readdir(p): string[]` — 자식 이름 배열(절대 경로 아님).
|
|
15
10
|
|
|
16
|
-
|
|
11
|
+
### 삭제
|
|
12
|
+
|
|
13
|
+
- `rmSync(p)` — 재귀+force. **재시도 없음**, 파일 잠금 시 즉시 실패.
|
|
14
|
+
- `rm(p)` — 재귀+force, **최대 6회 / 500ms 간격 재시도**. 일시적 잠금 회피용.
|
|
17
15
|
|
|
18
16
|
### 복사
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
- `copySync(src, dst, filter?) / copy(src, dst, filter?)` — 재귀 복사.
|
|
19
|
+
- `src`: 원본 경로. 존재하지 않으면 no-op.
|
|
20
|
+
- `dst`: 대상 경로. 상위 디렉토리 자동 생성.
|
|
21
|
+
- `filter(absolutePath): boolean`: 하위 항목 1개에 대한 포함 여부. true=포함, false=제외. **최상위 src 는 적용 대상 아님**. 디렉토리에 false 반환 시 그 하위 전체 스킵.
|
|
22
|
+
- 파일 복사 실패 시 최대 6회 / 500ms 재시도.
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
- `filter(absolutePath): boolean` — 각 하위 항목 절대 경로로 호출. 최상위 `src` 자체는 필터 대상 아님. 디렉토리에 false 반환 시 그 하위 전체 스킵.
|
|
27
|
-
- 파일 복사 6회/500ms 재시도 (sync 는 busy-wait).
|
|
24
|
+
### 읽기 / 쓰기
|
|
28
25
|
|
|
29
|
-
|
|
26
|
+
- `readSync(p) / read(p): string` — UTF-8 텍스트.
|
|
27
|
+
- `readBytesSync(p) / readBytes(p): Uint8Array` — 바이너리.
|
|
28
|
+
- `readJsonSync<T>(p) / readJson<T>(p): T` — `@simplysm/core-common` 의 `json.parse` 사용. 파싱 실패 시 본문 앞 500자 미리보기 포함 에러.
|
|
29
|
+
- `writeSync(p, data) / write(p, data)` — `data: string | Uint8Array`. 상위 디렉토리 자동 생성, `flush: true`.
|
|
30
|
+
- `writeJsonSync(p, data, opts?) / writeJson(p, data, opts?)` — `opts.replacer`: JSON.stringify 와 동일한 replacer. `opts.space`: 들여쓰기(숫자=스페이스 수, 문자열=리터럴).
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
fsx.readSync(p): string // utf-8
|
|
33
|
-
fsx.read(p): Promise<string>
|
|
34
|
-
fsx.readBytesSync(p): Uint8Array
|
|
35
|
-
fsx.readBytes(p): Promise<Uint8Array>
|
|
36
|
-
fsx.readJsonSync<T>(p): T // @simplysm/core-common json.parse
|
|
37
|
-
fsx.readJson<T>(p): Promise<T>
|
|
38
|
-
|
|
39
|
-
fsx.writeSync(p, data: string|Uint8Array): void // 상위 디렉토리 자동 생성, flush:true
|
|
40
|
-
fsx.write(p, data): Promise<void>
|
|
41
|
-
fsx.writeJsonSync(p, data, { replacer?, space? }?): void
|
|
42
|
-
fsx.writeJson(p, data, { replacer?, space? }?): Promise<void>
|
|
43
|
-
```
|
|
32
|
+
### Stats
|
|
44
33
|
|
|
45
|
-
|
|
34
|
+
- `statSync / stat` — `fs.Stats`. 심볼릭 링크 따라감.
|
|
35
|
+
- `lstatSync / lstat` — `fs.Stats`. 심볼릭 링크 안 따라감 (링크 자체 정보).
|
|
46
36
|
|
|
47
|
-
###
|
|
37
|
+
### Glob
|
|
48
38
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
fsx.readdir(p): Promise<string[]>
|
|
52
|
-
fsx.statSync(p): fs.Stats // 심볼릭 링크 따라감
|
|
53
|
-
fsx.stat(p): Promise<fs.Stats>
|
|
54
|
-
fsx.lstatSync(p): fs.Stats // 심볼릭 링크 따라가지 않음
|
|
55
|
-
fsx.lstat(p): Promise<fs.Stats>
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### Glob / 트리 유틸
|
|
39
|
+
- `globSync(pattern, options?) / glob(pattern, options?): string[]` — `glob` 패키지 래핑. 패턴 내 백슬래시는 슬래시로 치환 후 호출. 결과는 **항상 절대 경로**로 정규화.
|
|
40
|
+
- `options`: `glob` 패키지의 `GlobOptions`(예: `dot: true` 로 dotfile 포함).
|
|
59
41
|
|
|
60
|
-
|
|
61
|
-
fsx.globSync(pattern, options?: GlobOptions): string[] // 항상 절대 경로, 백슬래시 → 슬래시
|
|
62
|
-
fsx.glob(pattern, options?): Promise<string[]>
|
|
42
|
+
### 트리 유틸
|
|
63
43
|
|
|
64
|
-
|
|
44
|
+
- `clearEmptyDirectory(dirPath)` — 하위까지 재귀 순회, 파일이 없는 디렉토리만 삭제. 파일이 하나라도 있으면 보존.
|
|
45
|
+
- `findAllParentChildPathsSync(childGlob, fromPath, rootPath?) / findAllParentChildPaths(...)` — `fromPath` 부터 루트 방향으로 부모 디렉토리를 따라가며 각 디렉토리에서 `childGlob` 패턴 매칭 파일을 수집. `rootPath` 도달 시 종료(지정 없으면 FS 루트까지). 모노레포 루트 탐색 등에 사용.
|
|
65
46
|
|
|
66
|
-
|
|
67
|
-
fsx.findAllParentChildPaths(childGlob, fromPath, rootPath?): Promise<string[]>
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
`findAllParentChildPaths*`: `fromPath` 에서 루트 방향으로 부모를 순회하며 각 디렉토리에 `childGlob` 적용. `rootPath` 미지정 또는 `fromPath` 가 `rootPath` 하위가 아니면 파일 시스템 루트까지 진행. `pnpm-workspace.yaml` 같은 ancestor 설정 파일 탐색에 사용.
|
|
71
|
-
|
|
72
|
-
사용 예:
|
|
47
|
+
### 예
|
|
73
48
|
|
|
74
49
|
```ts
|
|
75
50
|
import { fsx } from "@simplysm/core-node";
|
|
76
|
-
|
|
77
|
-
await fsx.
|
|
78
|
-
const tsFiles = await fsx.glob("src/**/*.ts");
|
|
79
|
-
const cfg = await fsx.readJson<MyConfig>("sd.config.json");
|
|
80
|
-
await fsx.copy(src, dst, (p) => !p.includes(`${path.sep}node_modules${path.sep}`));
|
|
51
|
+
await fsx.copy("src", "dist", (p) => !p.includes("node_modules"));
|
|
52
|
+
const cfg = await fsx.readJson<{ name: string }>("package.json");
|
|
81
53
|
```
|
|
@@ -1,55 +1,24 @@
|
|
|
1
1
|
## @simplysm/core-node — pathx
|
|
2
2
|
|
|
3
|
-
`import { pathx } from "@simplysm/core-node"
|
|
3
|
+
`import { pathx } from "@simplysm/core-node"`. POSIX 슬래시 경로 정규화·비교·필터링.
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### 타입
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
type PosixPath = string & { [POSIX]: never };
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
`posix()` 또는 `posixResolve()` 결과에만 부여. 슬래시 경로임을 타입으로 보장.
|
|
12
|
-
|
|
13
|
-
### 변환
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
pathx.posix(p: string): PosixPath
|
|
17
|
-
// 백슬래시 → 슬래시 만. resolve 안 함.
|
|
18
|
-
// posix("C:\\Users\\test") === "C:/Users/test"
|
|
19
|
-
|
|
20
|
-
pathx.posixResolve(...args: string[]): PosixPath
|
|
21
|
-
// path.resolve 후 슬래시화. 항상 절대 경로.
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### 비교/판정
|
|
7
|
+
- `PosixPath` — `string & { [POSIX]: never }` 브랜드 타입. `posix()` / `posixResolve()` 만 생성 가능. 글로브·minimatch·URL 호환 경로 표현용.
|
|
25
8
|
|
|
26
|
-
|
|
27
|
-
pathx.isChildPath(child, parent): boolean
|
|
28
|
-
// posixResolve 정규화 후 비교. 동일 경로면 false.
|
|
29
|
-
|
|
30
|
-
pathx.changeFileDirectory(filePath, fromDir, toDir): string
|
|
31
|
-
// filePath 의 fromDir 부분을 toDir 로 치환.
|
|
32
|
-
// filePath === fromDir 이면 toDir 반환.
|
|
33
|
-
// filePath 가 fromDir 하위가 아니면 ArgumentError throw.
|
|
34
|
-
|
|
35
|
-
pathx.basenameWithoutExt(filePath): string
|
|
36
|
-
// path.basename(p, path.extname(p)). "a/b/c.spec.ts" → "c.spec"
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### target 필터링
|
|
40
|
-
|
|
41
|
-
```ts
|
|
42
|
-
pathx.filterByTargets(files: string[], targets: string[], cwd: string): string[]
|
|
43
|
-
```
|
|
9
|
+
### 함수
|
|
44
10
|
|
|
45
|
-
- `
|
|
46
|
-
-
|
|
47
|
-
- `
|
|
48
|
-
- `
|
|
11
|
+
- `posix(p): PosixPath` — 백슬래시→슬래시 치환만. resolve 안 함.
|
|
12
|
+
- `posixResolve(...args): PosixPath` — `path.resolve(...args)` 후 슬래시 치환. 절대 경로 보장.
|
|
13
|
+
- `changeFileDirectory(filePath, fromDirectory, toDirectory): string` — `filePath` 의 디렉토리 prefix 를 `fromDirectory`→`toDirectory` 로 갈아끼움. `filePath === fromDirectory` 면 `toDirectory` 반환. `filePath` 가 `fromDirectory` 하위가 아니면 `ArgumentError` throw.
|
|
14
|
+
- `basenameWithoutExt(filePath): string` — 마지막 확장자 1개 제거한 basename. `"a.spec.ts"` → `"a.spec"`.
|
|
15
|
+
- `isChildPath(childPath, parentPath): boolean` — `child` 가 `parent` **엄격 하위**인지 (동일 경로면 false). 내부적으로 `posixResolve` 정규화 후 `parent + "/"` prefix 매칭.
|
|
16
|
+
- `filterByTargets(files, targets, cwd): string[]` — `files`(cwd 하위 절대 경로 배열)에서 `targets`(cwd 기준 상대 POSIX 경로) 와 일치 또는 하위 항목만 통과. `targets` 가 빈 배열이면 `files` 그대로 반환. sd-cli 의 `-t` 옵션 처리에 사용.
|
|
49
17
|
|
|
50
|
-
|
|
18
|
+
### 예
|
|
51
19
|
|
|
52
20
|
```ts
|
|
53
|
-
|
|
54
|
-
pathx.
|
|
21
|
+
import { pathx } from "@simplysm/core-node";
|
|
22
|
+
const out = pathx.changeFileDirectory("/proj/src/a.ts", "/proj/src", "/proj/dist"); // /proj/dist/a.ts
|
|
23
|
+
pathx.isChildPath("/a/b/c", "/a/b"); // true
|
|
55
24
|
```
|
|
@@ -1,111 +1,65 @@
|
|
|
1
1
|
## @simplysm/core-node — Worker
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
타입 안전한 `worker_threads` 래퍼. 메인에서는 `Worker.create()` 로 프록시 호출, 워커에서는 `createWorker()` 로 메서드·이벤트 노출.
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### 워커 스크립트 — `createWorker`
|
|
6
6
|
|
|
7
7
|
```ts
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
};
|
|
8
|
+
createWorker<TMethods, TEvents = Record<string, never>>(methods: TMethods): {
|
|
9
|
+
send<K extends keyof TEvents & string>(event: K, data?: TEvents[K]): void;
|
|
10
|
+
__methods: TMethods;
|
|
11
|
+
__events: TEvents;
|
|
13
12
|
}
|
|
14
|
-
|
|
15
|
-
type PromisifyMethods<T> = {
|
|
16
|
-
[K in keyof T]: T[K] extends (...args: infer P) => infer R
|
|
17
|
-
? (...args: P) => Promise<Awaited<R>>
|
|
18
|
-
: never;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
type WorkerProxy<TModule extends WorkerModule> =
|
|
22
|
-
PromisifyMethods<TModule["default"]["__methods"]> & {
|
|
23
|
-
on<E extends keyof TModule["default"]["__events"] & string>(
|
|
24
|
-
event: E, listener: (data: TModule["default"]["__events"][E]) => void,
|
|
25
|
-
): void;
|
|
26
|
-
off<E extends keyof TModule["default"]["__events"] & string>(event: E, listener): void;
|
|
27
|
-
terminate(): Promise<void>;
|
|
28
|
-
};
|
|
29
13
|
```
|
|
30
14
|
|
|
31
|
-
|
|
15
|
+
- `methods`: 워커가 제공할 메서드 맵. 각 값은 동기/비동기 함수. 동기 반환도 메인에서는 Promise 로 받음.
|
|
16
|
+
- `TEvents`: 메인으로 발행할 이벤트 시그니처(`{ eventName: payloadType }`).
|
|
17
|
+
- 반환 객체의 `send(event, data?)` 로 메인에 이벤트 push. `__methods`/`__events` 는 타입 추론 전용(런타임 미사용).
|
|
18
|
+
- `parentPort` 없으면 throw (반드시 worker thread 에서 import).
|
|
19
|
+
- `process.stdout.write` 를 가로채 메인의 stdout 으로 전달(worker thread 의 stdout 미전달 한계 우회).
|
|
20
|
+
- 메서드 처리 중 throw → `Error` 직렬화되어 메인 호출 Promise reject.
|
|
21
|
+
|
|
22
|
+
워커 파일은 반드시 `export default createWorker(...)` 형태로 export.
|
|
32
23
|
|
|
33
|
-
### Worker.create
|
|
24
|
+
### 메인 — `Worker.create`
|
|
34
25
|
|
|
35
26
|
```ts
|
|
36
27
|
Worker.create<TModule extends WorkerModule>(
|
|
37
28
|
filePath: string,
|
|
38
29
|
opt?: Omit<WorkerOptions, "stdout" | "stderr">,
|
|
39
|
-
): WorkerProxy<TModule
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
- `filePath`: `file://` URL 또는 절대 경로.
|
|
43
|
-
- 실행 모드는 `import.meta.filename` 확장자로 결정:
|
|
44
|
-
- `.ts` (개발/tsx) → 내부 `lib/worker-dev-proxy.js` 를 띄우고 워커 파일을 argv 로 전달, tsx 로 동적 로드.
|
|
45
|
-
- `.js` (프로덕션) → 워커 파일을 그대로 `new Worker(workerPath, ...)`.
|
|
46
|
-
- 항상 `stdout: true, stderr: true` 로 워커 띄우고 메인의 stdout/stderr 로 pipe. 워커 내부의 `process.stdout.write` 도 메시지 프로토콜(`type: "log"`)로 메인에 전달되어 그대로 stdout 에 출력 — 워커의 `console.log` 가 메인 터미널에 보임.
|
|
47
|
-
- `opt.env` 는 `process.env` 와 머지되어 워커에 전달.
|
|
48
|
-
- 워커 비정상 종료(`exit code !== 0`) 또는 `error` 발생 시 대기 중 모든 호출이 reject. `terminate()` 호출 시에도 in-flight 요청은 모두 reject.
|
|
49
|
-
|
|
50
|
-
### createWorker (워커 측)
|
|
51
|
-
|
|
52
|
-
```ts
|
|
53
|
-
function createWorker<
|
|
54
|
-
TMethods extends Record<string, (...args: any[]) => unknown>,
|
|
55
|
-
TEvents extends Record<string, unknown> = Record<string, never>,
|
|
56
|
-
>(methods: TMethods): {
|
|
57
|
-
send<E extends keyof TEvents & string>(event: E, data?: TEvents[E]): void;
|
|
58
|
-
__methods: TMethods;
|
|
59
|
-
__events: TEvents;
|
|
60
|
-
};
|
|
30
|
+
): WorkerProxy<TModule>
|
|
61
31
|
```
|
|
62
32
|
|
|
63
|
-
- 워커
|
|
64
|
-
- `
|
|
65
|
-
-
|
|
66
|
-
-
|
|
33
|
+
- `TModule`: 워커 파일의 `typeof import("./worker")`. 메서드 시그니처·이벤트 타입 추론 소스.
|
|
34
|
+
- `filePath`: 워커 파일 경로. `file://` URL 또는 절대 경로 모두 허용.
|
|
35
|
+
- `opt`: Node `WorkerOptions` 중 `stdout/stderr` 제외(고정 `true`). `env` 는 `process.env` 와 병합. `argv` 는 dev 모드에서 워커 경로 뒤에 추가.
|
|
36
|
+
- 개발(`import.meta.filename` 이 `.ts`) → 내부 `worker-dev-proxy.js` 를 워커로 띄우고 tsx 로 사용자 워커 동적 로드. 프로덕션(`.js`) → 사용자 파일 직접 실행.
|
|
37
|
+
- 워커 stdout/stderr 는 메인 프로세스로 파이프.
|
|
67
38
|
|
|
68
|
-
###
|
|
39
|
+
### 반환 프록시 — `WorkerProxy<TModule>`
|
|
69
40
|
|
|
70
|
-
|
|
41
|
+
- `methods` (스프레드된 키): 각 메서드 → `(...args) => Promise<Awaited<R>>`. 매 호출마다 UUID 부여, `@simplysm/core-common` 의 `transfer.encode` 로 직렬화하여 `postMessage`.
|
|
42
|
+
- `on(event, listener)` / `off(event, listener)` — 워커가 `send()` 로 발행한 이벤트 구독/해제.
|
|
43
|
+
- `terminate(): Promise<void>` — 대기 중인 모든 요청을 reject 후 워커 종료.
|
|
71
44
|
|
|
72
|
-
|
|
73
|
-
interface WorkerRequest { id: string; method: string; params: unknown[]; }
|
|
45
|
+
### 비정상 종료
|
|
74
46
|
|
|
75
|
-
|
|
76
|
-
| { request: WorkerRequest; type: "return"; body?: unknown }
|
|
77
|
-
| { request: WorkerRequest; type: "error"; body: Error }
|
|
78
|
-
| { type: "event"; event: string; body?: unknown }
|
|
79
|
-
| { type: "log"; body: string };
|
|
80
|
-
```
|
|
47
|
+
- 워커 `exit` (코드≠0, 사용자 terminate 아님) 또는 `error` 발생 시 대기 중인 모든 호출이 `Error("워커가 비정상 종료되었습니다 (코드: N) (method: X)")` 등으로 reject.
|
|
81
48
|
|
|
82
|
-
###
|
|
49
|
+
### 예
|
|
83
50
|
|
|
84
51
|
```ts
|
|
85
52
|
// worker.ts
|
|
86
53
|
import { createWorker } from "@simplysm/core-node";
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const methods = {
|
|
91
|
-
async heavy(x: number) {
|
|
92
|
-
sender.send("progress", 50);
|
|
93
|
-
return x * 2;
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const sender = createWorker<typeof methods, Events>(methods);
|
|
54
|
+
interface E { progress: number }
|
|
55
|
+
const methods = { calc: (n: number) => n * 2 };
|
|
56
|
+
const sender = createWorker<typeof methods, E>(methods);
|
|
98
57
|
export default sender;
|
|
99
|
-
```
|
|
100
58
|
|
|
101
|
-
```ts
|
|
102
59
|
// main.ts
|
|
103
60
|
import { Worker } from "@simplysm/core-node";
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
);
|
|
108
|
-
worker.on("progress", (p) => consola.info(`${p}%`));
|
|
109
|
-
const result = await worker.heavy(21); // 42
|
|
110
|
-
await worker.terminate();
|
|
61
|
+
const w = Worker.create<typeof import("./worker")>("./worker.ts");
|
|
62
|
+
w.on("progress", (p) => console.log(p));
|
|
63
|
+
console.log(await w.calc(21)); // 42
|
|
64
|
+
await w.terminate();
|
|
111
65
|
```
|
|
@@ -1,95 +1,193 @@
|
|
|
1
1
|
# @simplysm/excel
|
|
2
2
|
|
|
3
|
-
OOXML(xlsx)
|
|
3
|
+
OOXML(xlsx) ZIP 을 lazy 로 읽고 쓰는 neutral 패키지. 셀 단위 접근 시점에만 해당 XML(SharedStrings/Styles 등)을 로드하므로 대용량 파일 메모리 효율적.
|
|
4
4
|
|
|
5
5
|
## 사용 트리거 인덱스
|
|
6
|
-
- **`ExcelWorkbook`** — xlsx 바이트/Blob 을 열거나 새 워크북을 만들 때. 사용 후 `close()` 필수.
|
|
7
|
-
- **`ExcelWorkbook.setDefaultStyle`** — 워크북 전역(폰트·정렬·numFmt 등) 셀 표준을 한번에 적용.
|
|
8
|
-
- **`ExcelWorksheet`** — 시트 단위 셀 접근의 진입점. 이름·범위 조회.
|
|
9
|
-
- **`getDataTable` / `setDataMatrix` / `setRecords`** — 시트와 레코드 배열(또는 2D 매트릭스) 간 입출력.
|
|
10
|
-
- **`copyCell` / `copyRow` / `copyCellStyle` / `copyRowStyle` / `insertCopyRow`** — 셀/행 복제·삽입(템플릿 시트 채울 때).
|
|
11
|
-
- **`setZoom` / `freezeAt`** — 시트 뷰 보기 설정(확대·틀 고정).
|
|
12
|
-
- **`setTabColor`** — 시트 탭 색 ARGB 지정.
|
|
13
|
-
- **`addConditionalFormat`** — 셀/범위에 조건부 서식 규칙 적용.
|
|
14
|
-
- **`addImage`** — 시트에 이미지(png/jpg 등) 삽입.
|
|
15
|
-
- **`ExcelCell`** — 단일 셀의 값·수식·스타일·병합.
|
|
16
|
-
- **`ExcelRow`** — 행 단위 셀 일괄 접근.
|
|
17
|
-
- **`ExcelCol`** — 열 단위 셀 접근 + 열 너비 설정.
|
|
18
|
-
- **`ExcelWrapper`** — Zod 스키마로 헤더·타입을 정의해 레코드 배열로 read/write.
|
|
19
|
-
- **`ExcelUtils`** — `"A1"`↔좌표, 범위 주소, Excel 직렬 날짜 ↔ 타임스탬프, numFmt 변환.
|
|
20
|
-
- **`ExcelValueType`** — 셀에 넣고 뺄 수 있는 값의 union (number/string/boolean/DateOnly/DateTime/Time/undefined).
|
|
21
|
-
- **`ExcelStyleOptions`** — `setStyle` / `setDefaultStyle` 입력 옵션 (배경·테두리·정렬·numFmt·폰트).
|
|
22
|
-
- **`ExcelFont`** — `ExcelStyleOptions.font` 의 폰트 속성(크기·family·bold·italic·underline·color·strike).
|
|
23
|
-
- **`ExcelConditionalRule` / `ExcelConditionalRuleStyle`** — `addConditionalFormat` 의 규칙·강조 스타일 타입.
|
|
24
|
-
- **`ExcelAddressPoint` / `ExcelAddressRangePoint`** — 0 기반 좌표 / 범위 좌표.
|
|
25
|
-
- **`ExcelNumberFormat` / `ExcelBorderPosition` / `ExcelHorizontalAlign` / `ExcelVerticalAlign` / `ExcelFontUnderline`** — 스타일 옵션의 enum literal 들.
|
|
26
|
-
|
|
27
|
-
## ExcelWorkbook
|
|
28
|
-
```typescript
|
|
29
|
-
new ExcelWorkbook(arg?: Blob | Bytes)
|
|
30
|
-
getWorksheetNames(): Promise<string[]>
|
|
31
|
-
addWorksheet(name): Promise<ExcelWorksheet>
|
|
32
|
-
getWorksheet(nameOrIndex: string | number): Promise<ExcelWorksheet> // 인덱스 0 기반
|
|
33
|
-
setDefaultStyle(opts: ExcelStyleOptions): Promise<void> // fonts[0]/fills[0]/borders[0] 덮어쓰기, 모든 셀에 전역 적용
|
|
34
|
-
toBytes(): Promise<Bytes>
|
|
35
|
-
toBlob(): Promise<Blob> // xlsx MIME
|
|
36
|
-
close(): Promise<void> // 멱등, 이후 모든 메서드는 throw
|
|
37
|
-
```
|
|
38
|
-
패턴: `const wb = new ExcelWorkbook(bytes); try { ... } finally { await wb.close(); }`. 인자 생략 시 빈 워크북.
|
|
39
6
|
|
|
40
|
-
|
|
7
|
+
- 워크북 열기/생성/저장/해제 → [Workbook](#workbook)
|
|
8
|
+
- 워크시트 추가·조회·이름·뷰(탭색/zoom/freeze) → [Worksheet 기본](#worksheet-기본)
|
|
9
|
+
- 행/열/셀 접근, 데이터 범위, 2D 셀 조회 → [Row · Col · Cell 접근](#row--col--cell-접근)
|
|
10
|
+
- 셀 값/수식/병합 읽고 쓰기 → [Cell 값·수식·병합](#cell-값수식병합)
|
|
11
|
+
- 셀 스타일, 워크북 default 스타일 → [Style](#style)
|
|
12
|
+
- 조건부 서식 → [Conditional Format](#conditional-format)
|
|
13
|
+
- 이미지 삽입 → [Image](#image)
|
|
14
|
+
- 데이터 테이블(레코드 배열) ↔ 시트 → [Data Matrix · Records](#data-matrix--records)
|
|
15
|
+
- Zod 스키마 기반 타입 안전 입출력 → [ExcelWrapper](#excelwrapper)
|
|
16
|
+
- 셀 주소 ↔ 좌표, Excel 날짜 ↔ JS tick → [ExcelUtils](#excelutils)
|
|
17
|
+
- 타입(주소·값·스타일·조건부 규칙 등) → [타입](#타입)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Workbook
|
|
22
|
+
|
|
23
|
+
`new ExcelWorkbook(arg?: Blob | Bytes)` — 인자 없으면 빈 워크북 생성(기본 OOXML 골격: `[Content_Types].xml`, `_rels/.rels`, `xl/workbook.xml`, `xl/_rels/workbook.xml.rels`). 인자가 있으면 ZIP 을 lazy reader 로 열기.
|
|
24
|
+
|
|
25
|
+
핵심 메서드:
|
|
26
|
+
- `getWorksheetNames(): Promise<string[]>` — 시트명 배열.
|
|
27
|
+
- `addWorksheet(name): Promise<ExcelWorksheet>` — 새 시트 추가 + ContentTypes/Rels 갱신.
|
|
28
|
+
- `getWorksheet(nameOrIndex: string | number): Promise<ExcelWorksheet>` — 이름 또는 0 기반 인덱스. 없으면 throw.
|
|
29
|
+
- `setDefaultStyle(opts: ExcelStyleOptions): Promise<void>` — `styles.xml` 의 `fonts[0]/fills[0]/borders[0]` (default 자원 슬롯) 및 `cellXfs[0]` 를 옵션으로 덮어쓰기. 셀 xf 가 자원 id 미지정이면 0번 슬롯이 fallback 되어 전역 적용. 옵션 없는 자원은 0번을 빈 슬롯으로 reset. 미호출 시 원본 보존.
|
|
30
|
+
- `toBytes(): Promise<Bytes>` / `toBlob(): Promise<Blob>` — ZIP 직렬화. Blob 의 mime = `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`.
|
|
31
|
+
- `close(): Promise<void>` — ZIP 리더와 캐시 해제. 호출 후 다른 메서드 호출 시 throw. 재호출 safe(no-op). **반드시 try/finally 로 호출**.
|
|
32
|
+
|
|
41
33
|
```typescript
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// 레코드 배열. 중복 헤더면 throw
|
|
48
|
-
setDataMatrix(matrix: ExcelValueType[][]) // 0,0 부터
|
|
49
|
-
setRecords(records: Record<string, ExcelValueType>[]) // 첫 행 헤더 자동
|
|
50
|
-
copyCell / copyRow / copyCellStyle / copyRowStyle / insertCopyRow
|
|
51
|
-
setZoom(percent) / freezeAt({ r?, c? }) / setTabColor(color) // color: ARGB 8자리
|
|
52
|
-
addConditionalFormat({ ref, rules: ExcelConditionalRule[] }) // 호출마다 priority 누적
|
|
53
|
-
addImage({ bytes, ext, from, to? }) // ext 는 mime lookup. to 생략 시 from+1,+1
|
|
34
|
+
const wb = new ExcelWorkbook(bytes);
|
|
35
|
+
try {
|
|
36
|
+
const ws = await wb.getWorksheet(0);
|
|
37
|
+
// ...
|
|
38
|
+
} finally { await wb.close(); }
|
|
54
39
|
```
|
|
55
40
|
|
|
56
|
-
##
|
|
41
|
+
## Worksheet 기본
|
|
42
|
+
|
|
43
|
+
`ExcelWorksheet` 는 `addWorksheet` / `getWorksheet` 로만 획득(직접 생성자 호출 X).
|
|
44
|
+
|
|
45
|
+
- `getName(): Promise<string>` / `setName(newName: string): Promise<void>`
|
|
46
|
+
- `getRange(): Promise<ExcelAddressRangePoint>` — 데이터가 존재하는 범위(시트의 `<dimension>` 기반).
|
|
47
|
+
- `getCells(): Promise<ExcelCell[][]>` — `range` 전체를 2차원 배열로.
|
|
48
|
+
- `setTabColor(color: string): Promise<void>` — 시트 탭 색. ARGB 8자리 16진수(예: `"00FF0000"`).
|
|
49
|
+
- `setZoom(percent: number): Promise<void>` — 보기 확대 비율(%).
|
|
50
|
+
- `freezeAt(point: { r?: number; c?: number }): Promise<void>` — 행/열 틀 고정.
|
|
51
|
+
- `copyRow(srcR, targetR)` — 행 덮어쓰기 복사.
|
|
52
|
+
- `copyCell(srcAddr, targetAddr)` — 셀 복사.
|
|
53
|
+
- `copyRowStyle(srcR, targetR)` / `copyCellStyle(srcAddr, targetAddr)` — 스타일만 복사.
|
|
54
|
+
- `insertCopyRow(srcR, targetR)` — `targetR` 위치에 행 삽입 복사. 이하 기존 행은 한 칸 아래로 밀린다. 삽입 지점을 관통하는 다중행 병합은 1행 확장. 원본의 단일행 병합은 복제.
|
|
55
|
+
|
|
56
|
+
## Row · Col · Cell 접근
|
|
57
|
+
|
|
58
|
+
`ExcelWorksheet` 인스턴스 메서드 (모두 0 기반 인덱스, 인스턴스는 캐싱됨):
|
|
59
|
+
- `row(r): ExcelRow` / `col(c): ExcelCol` / `cell(r, c): ExcelCell`
|
|
60
|
+
|
|
61
|
+
`ExcelRow`:
|
|
62
|
+
- `cell(c): ExcelCell` — 같은 행의 셀.
|
|
63
|
+
- `getCells(): Promise<ExcelCell[]>` — 시트 `range` 의 열 범위만큼.
|
|
64
|
+
|
|
65
|
+
`ExcelCol`:
|
|
66
|
+
- `cell(r): ExcelCell` — 같은 열의 셀.
|
|
67
|
+
- `getCells(): Promise<ExcelCell[]>` — 시트 `range` 의 행 범위만큼.
|
|
68
|
+
- `setWidth(size: number): Promise<void>` — 열 너비(OOXML 단위).
|
|
69
|
+
|
|
70
|
+
## Cell 값·수식·병합
|
|
71
|
+
|
|
72
|
+
`ExcelCell.addr: ExcelAddressPoint` — 0 기반 `{r, c}`.
|
|
73
|
+
|
|
74
|
+
- `getValue(): Promise<ExcelValueType>` — 셀 타입과 styles.xml 의 numFmt 를 보고 자동 변환:
|
|
75
|
+
- `s`(SharedString) → `string`
|
|
76
|
+
- `str`/`inlineStr` → `string`
|
|
77
|
+
- `b` → `boolean`
|
|
78
|
+
- `n` 또는 타입 미지정 → `numFmt` 가 날짜 계열이면 `DateOnly`/`DateTime`/`Time`, 아니면 `number`. 텍스트 형식(numFmtId 49)이면 `string`.
|
|
79
|
+
- `e`(error) → throw.
|
|
80
|
+
- `setValue(val: ExcelValueType): Promise<void>` — 값 타입으로 자동 분기:
|
|
81
|
+
- `undefined` → 셀 삭제
|
|
82
|
+
- `string` → SharedString 으로 등록(`t="s"`)
|
|
83
|
+
- `boolean` → `t="b"`, `"1"`/`"0"`
|
|
84
|
+
- `number` → numeric
|
|
85
|
+
- `DateOnly`/`DateTime`/`Time` → Excel 날짜 숫자로 변환 + 해당 numFmt(14/22/18) 자동 적용
|
|
86
|
+
- 그 외 타입 → throw.
|
|
87
|
+
- `setFormula(val: string | undefined): Promise<void>` / `getFormula(): Promise<string | undefined>` — 수식 설정/조회. `undefined` 전달 시 셀 삭제.
|
|
88
|
+
- `merge(r, c): Promise<void>` — 현재 셀에서 `(r, c)` 까지 병합(양 끝 inclusive). 예: `cell(0,0).merge(2,2)` → A1:C3.
|
|
89
|
+
|
|
90
|
+
## Style
|
|
91
|
+
|
|
92
|
+
- `cell.setStyle(opts: ExcelStyleOptions): Promise<void>` — 셀 스타일 적용. 기존 styleId 가 있으면 clone + override.
|
|
93
|
+
- `cell.getStyleId(): Promise<string | undefined>` / `setStyleId(id)` — 원시 cellXfs id 조작.
|
|
94
|
+
- `wb.setDefaultStyle(opts)` — 워크북 default. [Workbook](#workbook) 참고.
|
|
95
|
+
|
|
96
|
+
`ExcelStyleOptions`:
|
|
97
|
+
- `background?: string` — 셀 배경. ARGB 8자리(예: `"00FF0000"`).
|
|
98
|
+
- `border?: ("left" | "right" | "top" | "bottom")[]` — 활성화할 변. style 은 thin.
|
|
99
|
+
- `horizontalAlign?: "left" | "center" | "right"` / `verticalAlign?: "top" | "center" | "bottom"`.
|
|
100
|
+
- `numberFormat?: "number" | "string" | "DateOnly" | "DateTime" | "Time"` — 프리셋 numFmtId 매핑(0/49/14/22/18).
|
|
101
|
+
- `numberFormatCode?: string` — 임의 Excel formatCode(예: `"0.000000"`). `numberFormat` 보다 우선.
|
|
102
|
+
- `font?: ExcelFont` — `{ size?, family?, bold?, italic?, underline?: "single"|"double"|"singleAccounting"|"doubleAccounting", color?: ARGB8, strike? }`. 미지정 속성은 emit 안 함(Excel 기본값 표시).
|
|
103
|
+
|
|
104
|
+
## Conditional Format
|
|
105
|
+
|
|
106
|
+
`ws.addConditionalFormat({ ref, rules }): Promise<void>` — 셀/범위에 조건부 서식 규칙 추가. `ref` = `"A1"` 또는 `"A1:B10"`. `rules` 배열 순서가 priority(앞 우선). 같은 시트에 여러 번 호출하면 블록이 누적되고 priority 가 시트 전역으로 이어붙음. 빈 배열이면 no-op.
|
|
107
|
+
|
|
108
|
+
`ExcelConditionalRule` 종류:
|
|
109
|
+
- `{ type: "cellIs", op: "<"|">"|"<="|">="|"="|"<>", value: number|string, style }` — 단일 비교. `value` 가 string 이면 따옴표 리터럴 formula 로 emit, number 면 raw formula.
|
|
110
|
+
- `{ type: "cellIs", op: "between"|"notBetween", value: [a,b], style }` — 양 끝 inclusive 구간.
|
|
111
|
+
- `{ type: "text", op: "contains"|"notContains"|"beginsWith"|"endsWith", value: string, style }` — SEARCH 기반(대소문자 무시) 고정.
|
|
112
|
+
- `{ type: "expression", formula: string, style }` — 임의 수식 식.
|
|
113
|
+
|
|
114
|
+
`ExcelConditionalRuleStyle`:
|
|
115
|
+
- `background?: ARGB8` — 강조 배경.
|
|
116
|
+
- `fontColor?: ARGB8` — 글자색.
|
|
117
|
+
- `fontWeight?: "bold" | "normal"` — `"normal"` 은 base 가 bold 라도 강제 normal.
|
|
118
|
+
|
|
119
|
+
미지정 필드는 base 셀 스타일을 유지하며, 지정 필드만 OOXML dxf 로 emit 되어 Excel native CF 오버레이로 합성.
|
|
120
|
+
|
|
57
121
|
```typescript
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
merge(endR, endC) // 현재 셀부터 (endR,endC) 까지
|
|
63
|
-
getStyleId() / setStyleId(id)
|
|
64
|
-
setStyle(opts: ExcelStyleOptions) // 기존 스타일에 clone-merge
|
|
65
|
-
|
|
66
|
-
// ExcelRow / ExcelCol
|
|
67
|
-
row.cell(c) / col.cell(r)
|
|
68
|
-
row.getCells() / col.getCells()
|
|
69
|
-
col.setWidth(size)
|
|
122
|
+
await ws.addConditionalFormat({
|
|
123
|
+
ref: "B2:B100",
|
|
124
|
+
rules: [{ type: "cellIs", op: "<", value: 1000, style: { background: "00FF0000" } }],
|
|
125
|
+
});
|
|
70
126
|
```
|
|
71
|
-
|
|
127
|
+
|
|
128
|
+
## Image
|
|
129
|
+
|
|
130
|
+
`ws.addImage(opts): Promise<void>`
|
|
131
|
+
- `bytes: Bytes` — 이미지 바이너리.
|
|
132
|
+
- `ext: string` — 확장자(`png`/`jpg` 등). `mime` 라이브러리로 MIME 결정, 미인식 시 throw.
|
|
133
|
+
- `from: { r, c, rOff?: number|string, cOff?: number|string }` — 시작 위치(0 기반 행/열, `rOff/cOff` 는 EMU 오프셋).
|
|
134
|
+
- `to?: { r, c, rOff?, cOff? }` — 끝 위치. 생략 시 `from.r+1`, `from.c+1` 의 1×1 셀 크기.
|
|
135
|
+
|
|
136
|
+
기존 drawing 이 있으면 거기에 picture 를 추가하고, 없으면 `xl/drawings/drawing{N}.xml` 신규 생성 + ContentTypes/sheet rels 연결.
|
|
137
|
+
|
|
138
|
+
## Data Matrix · Records
|
|
139
|
+
|
|
140
|
+
`ws.setDataMatrix(matrix: ExcelValueType[][]): Promise<void>` — 2D 배열(행 우선)을 (0,0) 부터 기록. 셀 값은 `setValue` 와 동일 규칙으로 자동 분기.
|
|
141
|
+
|
|
142
|
+
`ws.setRecords(records: Record<string, ExcelValueType>[]): Promise<void>` — 0행에 헤더(레코드들의 key union, 빈 문자열 제외), 1행부터 데이터.
|
|
143
|
+
|
|
144
|
+
`ws.getDataTable(opt?): Promise<Record<string, ExcelValueType>[]>`:
|
|
145
|
+
- `opt.headerRowIndex?: number` — 헤더 행 인덱스(기본 = `range.s.r`).
|
|
146
|
+
- `opt.checkEndColIndex?: number` — 이 열이 비어 있으면 데이터 종료로 판정.
|
|
147
|
+
- `opt.usableHeaderNameFn?: (headerName) => boolean` — 사용할 헤더 필터. 헤더가 string 타입인 컬럼만 후보. 헤더 중복 발견 시 throw.
|
|
72
148
|
|
|
73
149
|
## ExcelWrapper
|
|
74
|
-
|
|
75
|
-
new ExcelWrapper(schema
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
150
|
+
|
|
151
|
+
`new ExcelWrapper<TSchema>(schema)` — Zod 스키마로 Excel ↔ 레코드 변환. 필드의 `.describe("...")` 가 Excel 헤더 이름. describe 없으면 필드 key.
|
|
152
|
+
|
|
153
|
+
- `read(file, wsNameOrIndex = 0, options?: { excludes? }): Promise<z.infer<TSchema>[]>`
|
|
154
|
+
- 시트의 헤더 행에서 스키마와 매칭되는 컬럼만 추출.
|
|
155
|
+
- 각 행을 변환(`ZodString`→string, `ZodNumber`→`num.parseFloat`, `ZodBoolean`→`"1"/"true"`/`"0"/"false"`/Boolean 강제), `safeParse` 로 검증, 실패 시 throw.
|
|
156
|
+
- 전 컬럼이 null/empty 인 행은 skip.
|
|
157
|
+
- 데이터 0행이면 throw.
|
|
158
|
+
- `options.excludes` 로 특정 필드 제외.
|
|
159
|
+
- 내부적으로 ExcelWorkbook 을 열고 finally 에서 close.
|
|
160
|
+
- `write(wsName, records, options?: { excludes? }): Promise<ExcelWorkbook>`
|
|
161
|
+
- 헤더 = describe 이름 또는 key.
|
|
162
|
+
- 데이터 본문 기록 후 전체 셀에 4변 테두리.
|
|
163
|
+
- 필수 필드(Optional/Nullable/Default 가 아님) + boolean 아닌 필드의 헤더 셀에 노란색(`"00FFFF00"`) 배경.
|
|
164
|
+
- `setZoom(85)`, `freezeAt({ r: 0 })`.
|
|
165
|
+
- 반환된 워크북의 `close()` 는 호출자 책임. 내부 throw 시에는 자동 close 후 rethrow.
|
|
80
166
|
|
|
81
167
|
## ExcelUtils
|
|
82
|
-
```typescript
|
|
83
|
-
stringifyAddr({r,c}) / parseCellAddr("B3") // {r:2,c:1}
|
|
84
|
-
stringifyColAddr(0) // "A" parseColAddr("AA") // 26
|
|
85
|
-
stringifyRangeAddr / parseRangeAddr("A1:C3")
|
|
86
|
-
convertTimeTickToNumber(tick) / convertNumberToTimeTick(serial) // Excel 1899-12-30 기준
|
|
87
|
-
convertNumFmtIdToName / convertNumFmtCodeToName / convertNumFmtNameToId
|
|
88
|
-
```
|
|
89
168
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
- `
|
|
93
|
-
- `
|
|
94
|
-
- `
|
|
95
|
-
- `
|
|
169
|
+
정적 메서드 모음.
|
|
170
|
+
|
|
171
|
+
- `stringifyAddr({r,c})` → `"B3"`. `stringifyRowAddr(r)` → `"3"`. `stringifyColAddr(c)` → `"AA"` 등. `c` 범위 0~16383, 초과 시 throw.
|
|
172
|
+
- `parseCellAddr("B3")` → `{r:2, c:1}`. `parseRowAddr`/`parseColAddr` 동일 패턴.
|
|
173
|
+
- `parseRangeAddr("A1:C3")` → `{s, e}`. 단일 셀 입력 시 `s === e`.
|
|
174
|
+
- `stringifyRangeAddr({s,e})` → `"A1:C3"`. `s === e` 면 단일 주소만.
|
|
175
|
+
- `convertTimeTickToNumber(tick)` / `convertNumberToTimeTick(value)` — JS ms tick ↔ Excel serial date. Excel 기준일 = 1899-12-30.
|
|
176
|
+
- `convertNumFmtCodeToName(code)` → `ExcelNumberFormat`. `"General"` = number. `yy`/`dd`/`mm` 패턴 검출(`hh:mm`/`mm:ss` 의 mm 은 분으로 제외)로 Date/Time 분류. 매칭 실패 시 throw.
|
|
177
|
+
- `convertNumFmtIdToName(id)` → `ExcelNumberFormat`. Excel 내장 ID 범위 기반(숫자: 0–13,37–40,48 / Date: 14–17,27–31,34–36,50–58 / DateTime: 22 / Time: 18–21,32–33,45–47 / string: 49). 매칭 실패 시 throw.
|
|
178
|
+
- `convertNumFmtNameToId(name)` — number→0, DateOnly→14, DateTime→22, Time→18, string→49.
|
|
179
|
+
|
|
180
|
+
## 타입
|
|
181
|
+
|
|
182
|
+
- `ExcelValueType = number | string | DateOnly | DateTime | Time | boolean | undefined` — 셀 값 도메인. `undefined` = 빈 셀.
|
|
183
|
+
- `ExcelNumberFormat = "number" | "string" | "DateOnly" | "DateTime" | "Time"` — 숫자 형식 프리셋 이름.
|
|
184
|
+
- `ExcelCellType = "s" | "b" | "str" | "n" | "inlineStr" | "e"` — OOXML 의 셀 `t` 속성: SharedString / boolean / 수식결과문자열 / 숫자 / 인라인문자열 / 에러.
|
|
185
|
+
- `ExcelAddressPoint = { r: number; c: number }` — 0 기반 좌표.
|
|
186
|
+
- `ExcelAddressRangePoint = { s: ExcelAddressPoint; e: ExcelAddressPoint }` — start/end inclusive.
|
|
187
|
+
- `ExcelBorderPosition = "left" | "right" | "top" | "bottom"`.
|
|
188
|
+
- `ExcelHorizontalAlign = "center" | "left" | "right"` / `ExcelVerticalAlign = "center" | "top" | "bottom"`.
|
|
189
|
+
- `ExcelFontUnderline = "single" | "double" | "singleAccounting" | "doubleAccounting"` — OOXML `<u val>` 그대로.
|
|
190
|
+
- `ExcelFont`, `ExcelStyleOptions` — [Style](#style) 참고.
|
|
191
|
+
- `ExcelConditionalRule`, `ExcelConditionalRuleStyle` — [Conditional Format](#conditional-format) 참고.
|
|
192
|
+
- `ExcelXml` — `{ data: unknown; cleanup(): void }`. ZipCache 가 보관하는 XML 객체의 공통 인터페이스(내부용).
|
|
193
|
+
- `Excel*Data` 인터페이스들 — OOXML XML 의 JS 객체 표현(xml2js 스타일, 내부 처리용). 외부 코드에서 직접 다룰 일 없음.
|
|
@@ -41,6 +41,11 @@ export default [...recommended, { /* overrides */ }];
|
|
|
41
41
|
- `process.env`/`import.meta.env` 직접 접근 금지 → `env("...")` 호출 강제. `env("NODE_ENV")` 자체 금지.
|
|
42
42
|
- `=== undefined` / `!== undefined` 금지 → `== null` / `!= null` 통일.
|
|
43
43
|
- TS 블록 전용: `naming-convention` 으로 `private` 멤버에 leading underscore(`_foo`) 강제, `strict-boolean-expressions` (nullable boolean/object 허용), `ban-ts-comment` (`ts-expect-error` 는 3자 이상 설명 필수), `only-throw-error`, `no-floating-promises` 등.
|
|
44
|
+
- `unused-imports/no-unused-imports` error, `unused-imports/no-unused-vars` error (vars=all, args=after-used, 둘 다 `^_` 시작 식별자는 제외).
|
|
45
|
+
- `@typescript-eslint/no-misused-promises`: `checksVoidReturn.arguments=false`, `inheritedMethods=false` (Angular 이벤트 핸들러 패턴 허용).
|
|
46
|
+
- TS 블록에 등록되는 `@simplysm/*` 룰: `ng-no-async-effect`, `no-hard-private`, `no-subpath-imports-from-simplysm`, `ts-no-unused-injects`, `ts-no-unused-protected-readonly` 는 error, `ts-no-throw-not-implemented-error` 는 warn.
|
|
47
|
+
- HTML 블록에 등록되는 `@simplysm/*` 룰: `ng-template-no-strict-null-check` error, `ng-template-sd-require-binding-attrs` error, `ng-template-no-todo-comments` warn.
|
|
48
|
+
- JS 블록에 등록되는 `@simplysm/*` 룰: `no-subpath-imports-from-simplysm`, `no-hard-private` (둘 다 error).
|
|
44
49
|
|
|
45
50
|
## `./eslint-plugin`
|
|
46
51
|
|