@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,39 +1,51 @@
|
|
|
1
1
|
# @simplysm/core-node — cpx
|
|
2
2
|
|
|
3
|
-
`
|
|
3
|
+
`export * as cpx` 네임스페이스 (`packages/core-node/src/utils/cp.ts`). 자식 프로세스 실행 + 출력 OS 인코딩 디코딩. `cpx.spawn(...)` 형태로 호출. 출력은 OS 코드페이지(Windows `chcp`, POSIX `LANG`/`LC_ALL`)를 감지해 디코딩하므로 한글 등 비-UTF8 콘솔 출력도 깨지지 않음.
|
|
4
4
|
|
|
5
5
|
## spawn / spawnSync
|
|
6
6
|
|
|
7
|
-
- `spawn(cmd
|
|
8
|
-
- `spawnSync(cmd
|
|
9
|
-
- `
|
|
10
|
-
- `
|
|
11
|
-
- `options
|
|
12
|
-
|
|
7
|
+
- `spawn(cmd, args, options?): SpawnProcess` — 자식 프로세스를 비동기 실행. 반환값은 `await` 가능하며(`PromiseLike<SpawnResult>`) 동시에 `pid`/`kill` 접근 가능.
|
|
8
|
+
- `spawnSync(cmd, args, options?): SpawnResult` — 동기 실행. 즉시 결과 반환.
|
|
9
|
+
- `cmd: string` — 실행 명령.
|
|
10
|
+
- `args: string[]` — 인자 배열.
|
|
11
|
+
- `options` — Node `SpawnOptions`(spawn) / `SpawnSyncOptions`(spawnSync) + `reject?: boolean`.
|
|
12
|
+
- `env` — 전달 env. 항상 `process.env` 와 병합됨(전달분이 덮어씀).
|
|
13
|
+
- `stdio` — 기본 `"pipe"`. pipe 인 스트림만 캡처되어 결과 문자열에 담김. `"inherit"` 등이면 해당 스트림은 빈 문자열.
|
|
14
|
+
- `reject?: boolean` — exitCode 가 0 이 아닐 때 동작. 기본(미지정/true): 실패 메시지로 reject(spawn) 또는 throw(spawnSync). `false`: 0 이 아니어도 정상 반환(직접 exitCode 를 검사하려는 경우).
|
|
15
|
+
|
|
16
|
+
실패 메시지 형식: `Command failed (exit <code>): <cmd> <args>` 뒤에 stderr(없으면 stdout) 마지막 4000자.
|
|
13
17
|
|
|
14
18
|
```ts
|
|
15
|
-
|
|
19
|
+
import { cpx } from "@simplysm/core-node";
|
|
20
|
+
const { stdout, exitCode } = await cpx.spawn("git", ["status", "--short"]);
|
|
16
21
|
const r = cpx.spawnSync("node", ["-v"], { reject: false });
|
|
17
22
|
if (r.exitCode !== 0) { /* 직접 처리 */ }
|
|
18
23
|
```
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
## SpawnResult
|
|
26
|
+
|
|
27
|
+
- `interface SpawnResult { stdout: string; stderr: string; exitCode: number }` — 실행 결과.
|
|
28
|
+
- `stdout` / `stderr` — pipe 로 캡처된 출력(OS 인코딩 디코딩 적용). 비-pipe 스트림이면 `""`.
|
|
29
|
+
- `exitCode` — 종료 코드. 코드 없이 시그널로 종료됐으면 1, 정상이면 0.
|
|
30
|
+
|
|
31
|
+
## SpawnProcess
|
|
32
|
+
|
|
33
|
+
`spawn` 반환 타입. Promise 처럼 쓰면서 프로세스 제어를 함께 제공.
|
|
34
|
+
|
|
35
|
+
- `pid: number | undefined` — 자식 프로세스 PID(생성 전이면 undefined).
|
|
36
|
+
- `then(...)` / `catch(...)` — `SpawnResult` 로 resolve 되는 thenable(그래서 `await` 가능).
|
|
37
|
+
- `kill(signal?: NodeJS.Signals | number): boolean` — 프로세스에 시그널 전송. 타임아웃·취소 시 사용.
|
|
22
38
|
|
|
23
39
|
```ts
|
|
24
40
|
const proc = cpx.spawn("long-task", []);
|
|
25
|
-
proc.kill("SIGTERM");
|
|
41
|
+
setTimeout(() => proc.kill("SIGTERM"), 5000);
|
|
42
|
+
const result = await proc;
|
|
26
43
|
```
|
|
27
44
|
|
|
28
|
-
## 인코딩
|
|
29
|
-
|
|
30
|
-
- `getSystemEncoding(): string` — OS 시스템 인코딩 감지(Windows: `chcp` 코드페이지, POSIX: `LANG`/`LC_ALL` 의 `.` 뒤 부분). 결과를 캐시. 감지 실패 시 `"utf-8"`. spawn 결과 디코딩에 내부적으로 사용.
|
|
31
|
-
- `resetEncodingCache(): void` — 위 캐시 무효화(코드페이지 변경 후 재감지 / 테스트 용).
|
|
32
|
-
- `codePageToEncoding(codePage: number): string` — Windows 코드페이지 번호 → 인코딩명(예: 65001→utf-8, 949→euc-kr, 932→shift-jis). 매핑 없으면 `"utf-8"`.
|
|
33
|
-
- `decodeBytes(raw: Uint8Array, systemEncoding?: string): string` — 바이트 디코딩. 인코딩이 utf-8 이면 그대로 디코딩, 아니면 utf-8(fatal) 시도 후 실패 시 시스템 인코딩으로 폴백. `systemEncoding` 미지정 시 `getSystemEncoding()` 사용.
|
|
34
|
-
- `resolveStdioPipe(stdio): { stdout: boolean; stderr: boolean }` — `stdio` 옵션에서 stdout/stderr 가 pipe 인지 판정. 배열이면 인덱스 1/2 가 `"pipe"` 인지 검사, 단일 값/`null` 이면 둘 다 동일 판정. 캡처 여부 결정에 사용.
|
|
35
|
-
|
|
36
|
-
## 주의사항
|
|
45
|
+
## 인코딩 유틸
|
|
37
46
|
|
|
38
|
-
-
|
|
39
|
-
-
|
|
47
|
+
- `getSystemEncoding(): string` — OS 콘솔 인코딩 감지(결과 캐시됨). Windows 는 `chcp` 코드페이지, POSIX 는 `LANG`/`LC_ALL` 의 `.` 뒤 인코딩(`utf8`→`utf-8` 정규화). 감지 실패 시 `"utf-8"` fallback. spawn 출력 디코딩에 내부적으로 사용.
|
|
48
|
+
- `resetEncodingCache(): void` — `getSystemEncoding` 캐시 초기화. 런타임 중 코드페이지가 바뀐 경우 재감지를 강제.
|
|
49
|
+
- `codePageToEncoding(codePage: number): string` — Windows 코드페이지 숫자 → 인코딩명. 매핑: 65001→utf-8, 949→euc-kr, 932→shift-jis, 936→gbk, 950→big5, 1252→windows-1252, 1251→windows-1251, 1250→windows-1250, 874→windows-874. 미등록 코드페이지는 `"utf-8"`.
|
|
50
|
+
- `resolveStdioPipe(stdio): { stdout: boolean; stderr: boolean }` — stdio 옵션에서 stdout/stderr 가 pipe 인지 판정. 배열이면 index 1/2 가 `"pipe"` 인지, 단일값이면 `"pipe"` 또는 미지정(null)일 때 둘 다 pipe. 캡처 여부 사전 판단용.
|
|
51
|
+
- `decodeBytes(raw: Uint8Array, systemEncoding?: string): string` — 바이트열을 인코딩으로 디코딩. `systemEncoding` 미지정 시 `getSystemEncoding()` 사용. 인코딩이 utf-8 이 아니어도 먼저 UTF-8(fatal) 디코딩을 시도해 성공하면 UTF-8 로, 실패 시 지정 인코딩으로 디코딩(UTF-8/레거시 혼재 출력 대응).
|
|
@@ -1,38 +1,42 @@
|
|
|
1
1
|
# @simplysm/core-node — FsWatcher
|
|
2
2
|
|
|
3
|
-
chokidar 기반 파일 감시
|
|
3
|
+
chokidar 기반 파일 감시 래퍼 (`packages/core-node/src/features/fs-watcher.ts`). watch 빌드처럼 "여러 변경을 모아 한 번에 처리"해야 할 때 사용. 짧은 시간 내 이벤트를 디바운스+병합해 콜백을 한 번만 호출하고, Windows 의 EPERM(감시 디렉토리 소실) 발생 시 watcher 를 자동 재시작한다. 모듈 로드 시 native FSWatcher prototype 의 orphan `error` emit 를 swallow 하는 가드를 1회 설치(close 중 race 로 인한 프로세스 종료 방지).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## FsWatcher.watch (정적 진입점)
|
|
6
6
|
|
|
7
|
-
- `
|
|
8
|
-
- `
|
|
9
|
-
- `options
|
|
10
|
-
- `
|
|
11
|
-
- `opt.delay?: number` — 디바운스 ms. 마지막 이벤트 후 이 시간만큼 잠잠하면 누적 변경을 한 번에 전달.
|
|
12
|
-
- `cb: (changeInfos: FsWatcherChangeInfo[]) => void | Promise<void>` — 병합된 변경 목록으로 호출.
|
|
13
|
-
- `close(): Promise<void>` — 디바운스 큐를 dispose 한 뒤 chokidar 종료.
|
|
7
|
+
- `static watch(paths: string[], options?: chokidar.ChokidarOptions): Promise<FsWatcher>` — 감시 시작. ready 될 때까지 대기 후 인스턴스 반환. ready 전 에러 시 watcher 를 close 하고 throw.
|
|
8
|
+
- `paths: string[]` — 감시할 경로/glob 패턴 배열. 내부적으로 각 패턴의 glob 메타문자 이전 base 디렉토리를 추출해 chokidar 에 등록하고, 콜백 단계에서 원본 패턴으로 minimatch 재필터(패턴 자체 + `패턴/**` 양쪽 매칭).
|
|
9
|
+
- `options?: ChokidarOptions` — chokidar 옵션. `persistent` 기본 true. `ignoreInitial` 은 chokidar 에는 내부적으로 항상 true 로 강제(초기 스캔 이벤트 무시).
|
|
10
|
+
- `options.ignoreInitial: false` 지정 시 → `onChange` 의 첫 콜백이 **빈 배열 `[]`** 로 1회 호출됨(실제 초기 파일 목록은 담기지 않음 — 이벤트 병합과의 충돌 방지). "초기 1회 전체 빌드 후 변경 감시" 패턴 트리거용.
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
## 이벤트 병합 규칙
|
|
12
|
+
```ts
|
|
13
|
+
import { FsWatcher } from "@simplysm/core-node";
|
|
14
|
+
const watcher = await FsWatcher.watch(["src/**/*.ts"]);
|
|
15
|
+
```
|
|
21
16
|
|
|
22
|
-
|
|
17
|
+
## onChange
|
|
23
18
|
|
|
24
|
-
|
|
19
|
+
- `onChange(opt, cb): this` — 디바운스된 변경 콜백 등록. 체이닝 가능(this 반환). 여러 번 호출해 핸들러 다중 등록 가능.
|
|
20
|
+
- `opt.delay?: number` — 디바운스 지연(ms). 이 시간 내 들어온 이벤트를 모아 한 번 호출(`DebounceQueue` 사용). 생략 시 DebounceQueue 기본값.
|
|
21
|
+
- `cb: (changeInfos: FsWatcherChangeInfo[]) => void | Promise<void>` — 병합된 변경 목록 콜백. async 가능.
|
|
22
|
+
- 이벤트 병합: 같은 파일에 대해 `add+change→add`, `add+unlink→상쇄(콜백 제외)`, `addDir+unlinkDir→상쇄`, `unlink+add→add`, `unlink+change→change`, `unlinkDir+addDir→addDir`. 그 외 조합은 최신 이벤트로 덮어씀. → 생성 직후 삭제된 임시파일 등은 콜백에 안 나타남.
|
|
25
23
|
|
|
26
24
|
```ts
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
for (const { event, path } of changes) console.log(`${event}: ${path}`);
|
|
25
|
+
watcher.onChange({ delay: 300 }, (changes) => {
|
|
26
|
+
for (const { path, event } of changes) console.log(`${event}: ${path}`);
|
|
30
27
|
});
|
|
31
|
-
await watcher.close();
|
|
32
28
|
```
|
|
33
29
|
|
|
34
|
-
##
|
|
30
|
+
## close
|
|
31
|
+
|
|
32
|
+
- `close(): Promise<void>` — 디바운스 큐를 dispose 한 뒤 chokidar watcher 종료. 감시 해제 시 반드시 호출.
|
|
33
|
+
|
|
34
|
+
## FsWatcherChangeInfo / FsWatcherEvent
|
|
35
|
+
|
|
36
|
+
- `interface FsWatcherChangeInfo { event: FsWatcherEvent; path: PosixPath }` — 변경 1건. `path` 는 슬래시 정규화된 `PosixPath`(pathx 의 브랜드 타입).
|
|
37
|
+
- `type FsWatcherEvent = "add" | "addDir" | "change" | "unlink" | "unlinkDir"` — 변경 종류.
|
|
38
|
+
- `add` — 파일 생성. `addDir` — 디렉토리 생성. `change` — 파일 내용 변경. `unlink` — 파일 삭제. `unlinkDir` — 디렉토리 삭제.
|
|
39
|
+
|
|
40
|
+
## EPERM 자동 복구 동작
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
- EPERM 자동 재시작은 최대 3회(1초 간격). 초과 시 error 로그 후 중단하므로 이후 변경이 감지되지 않을 수 있음.
|
|
38
|
-
- 모듈 로드 시 native `fs.FSWatcher.prototype.emit` 에 가드를 설치해, listener 없는 orphan `error` 이벤트로 인한 프로세스 종료를 방지함(부수효과 — import 만으로 1회 적용).
|
|
42
|
+
EPERM 감지 시 최대 3회(1000ms 간격) watcher 재생성을 시도하며 등록된 핸들러를 다시 부착한다. 성공 시 `success` 로그, 한도 초과 시 `error` 로그 후 중단. 로거 태그는 `sd-fs-watcher`(consola). 재시도는 자동 복구이므로 호출측에서 별도 처리 불필요.
|
|
@@ -1,86 +1,73 @@
|
|
|
1
1
|
# @simplysm/core-node — fsx
|
|
2
2
|
|
|
3
|
-
`
|
|
3
|
+
`export * as fsx` 네임스페이스 (`packages/core-node/src/utils/fs.ts`). Node `fs` 를 감싼 파일시스템 IO. 대부분 동기(`...Sync`)/비동기 쌍을 제공하며, 실패 시 모두 `SdError(err, targetPath)` 로 원인+경로를 붙여 throw 한다. 항상 `fsx.<fn>(...)` 형태로 호출.
|
|
4
4
|
|
|
5
5
|
## 존재 확인
|
|
6
6
|
|
|
7
|
-
- `existsSync(targetPath: string): boolean`
|
|
7
|
+
- `existsSync(targetPath: string): boolean` — 파일/디렉토리 존재 여부(동기). 내부적으로 `fs.existsSync`.
|
|
8
|
+
- `exists(targetPath: string): Promise<boolean>` — 동일(비동기). `fs.access` 실패를 catch 해 false 반환(throw 안 함).
|
|
8
9
|
|
|
9
10
|
## 디렉토리 생성
|
|
10
11
|
|
|
11
|
-
- `mkdirSync(targetPath: string): void` / `mkdir(targetPath: string): Promise<void>` — `recursive: true`
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
await fsx.mkdir("dist/sub");
|
|
15
|
-
```
|
|
12
|
+
- `mkdirSync(targetPath: string): void` / `mkdir(targetPath: string): Promise<void>` — 재귀 생성(`recursive: true`). 중간 경로가 없어도 전부 만든다. 실패 시 `SdError`.
|
|
16
13
|
|
|
17
14
|
## 삭제
|
|
18
15
|
|
|
19
|
-
- `rmSync(targetPath: string): void` —
|
|
20
|
-
- `rm(targetPath: string): Promise<void>` —
|
|
16
|
+
- `rmSync(targetPath: string): void` — 재귀+force 삭제. **재시도 없이 즉시 실패**. 파일 잠금 등 일시 오류가 예상되면 비동기 `rm` 을 쓸 것.
|
|
17
|
+
- `rm(targetPath: string): Promise<void>` — 재귀+force 삭제. 일시 오류에 대해 **500ms 간격 최대 6회 재시도**(`retryDelay: 500, maxRetries: 6`). Windows 파일 잠금 회피용.
|
|
21
18
|
|
|
22
19
|
## 복사
|
|
23
20
|
|
|
24
|
-
- `copySync(sourcePath
|
|
25
|
-
- `
|
|
21
|
+
- `copySync(sourcePath, targetPath, filter?): void` / `copy(sourcePath, targetPath, filter?): Promise<void>` — 파일/디렉토리 복사. async 는 하위 항목을 `parallelAsync` 로 병렬 복사.
|
|
22
|
+
- `sourcePath: string` — 원본. **존재하지 않으면 아무 것도 안 하고 반환**(throw 안 함).
|
|
23
|
+
- `targetPath: string` — 대상. 원본이 디렉토리면 대상 디렉토리를 만들고 하위를 재귀 복사(glob `*`, `dot: true` 로 숨김 포함), 파일이면 상위 디렉토리 생성 후 복사.
|
|
24
|
+
- `filter?: (absolutePath: string) => boolean` — 복사 여부 결정. 각 하위 항목의 **절대 경로**가 전달되며 true=복사, false=제외. **최상위 sourcePath 자신은 필터 대상 아님**. 디렉토리에 false 면 그 디렉토리와 모든 내용을 건너뜀. 빌드 산출물 중 특정 파일만 복사할 때 사용.
|
|
25
|
+
- 파일 복사 실패 시 500ms 대기(sync 는 busy-wait, async 는 setTimeout)로 최대 7회 시도 후에도 실패하면 `SdError`.
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
await fsx.copy("src", "dist", (p) => !p.endsWith(".map"));
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## 파일 읽기
|
|
32
|
-
|
|
33
|
-
- `readSync(targetPath: string): string` / `read(...): Promise<string>` — UTF-8 문자열로 읽기.
|
|
34
|
-
- `readBytesSync(targetPath: string): Uint8Array` / `readBytes(...): Promise<Uint8Array>` — 바이너리로 읽기.
|
|
35
|
-
- `readJsonSync<TData = unknown>(targetPath: string): TData` / `readJson<TData = unknown>(...): Promise<TData>` — `@simplysm/core-common` 의 `json.parse` 로 파싱(표준 `JSON` 아님 — Date 등 확장 타입 복원). 파싱 실패 시 경로 + 내용 500자 프리뷰를 포함해 throw.
|
|
36
|
-
|
|
37
|
-
```ts
|
|
38
|
-
const cfg = await fsx.readJson<{ version: string }>("package.json");
|
|
39
|
-
```
|
|
27
|
+
## 읽기
|
|
40
28
|
|
|
41
|
-
|
|
29
|
+
- `readSync(targetPath: string): string` / `read(...): Promise<string>` — UTF-8 문자열로 읽음.
|
|
30
|
+
- `readBytesSync(targetPath: string): Uint8Array` / `readBytes(...): Promise<Uint8Array>` — 바이너리(`Uint8Array`)로 읽음.
|
|
31
|
+
- `readJsonSync<TData = unknown>(targetPath): TData` / `readJson<TData = unknown>(...): Promise<TData>` — 읽어 `json.parse`(`@simplysm/core-common`, Date 등 특수타입 복원)로 파싱. 파싱 실패 시 SdError 메시지에 내용 앞 500자 프리뷰를 첨부.
|
|
32
|
+
- 제네릭 `TData` — 파싱 결과 타입. 호출부에서 기대 타입을 지정해 반환 타입을 좁힘.
|
|
42
33
|
|
|
43
|
-
|
|
44
|
-
- `writeJsonSync(targetPath: string, data: unknown, options?): void` / `writeJson(...): Promise<void>` — `json.stringify` 로 직렬화 후 기록.
|
|
45
|
-
- `options.replacer?: (this, key: string | undefined, value: unknown) => unknown` — 직렬화 시 값 변환 replacer.
|
|
46
|
-
- `options.space?: string | number` — 들여쓰기(가독 출력용).
|
|
34
|
+
## 쓰기
|
|
47
35
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
36
|
+
- `writeSync(targetPath, data): void` / `write(targetPath, data): Promise<void>` — **상위 디렉토리 자동 생성** 후 기록(`flush: true` 로 디스크 플러시까지 보장).
|
|
37
|
+
- `data: string | Uint8Array` — 텍스트 또는 바이너리.
|
|
38
|
+
- `writeJsonSync(targetPath, data, options?): void` / `writeJson(targetPath, data, options?): Promise<void>` — `json.stringify` 로 직렬화 후 write.
|
|
39
|
+
- `data: unknown` — 직렬화 대상.
|
|
40
|
+
- `options?.replacer?: (this, key, value) => unknown` — JSON.stringify 의 replacer 와 동일 역할. 특정 키 값을 변환·제외할 때.
|
|
41
|
+
- `options?.space?: string | number` — 들여쓰기. 사람이 읽을 파일이면 `2` 같은 값 지정, 생략 시 압축.
|
|
51
42
|
|
|
52
43
|
## 디렉토리 읽기
|
|
53
44
|
|
|
54
|
-
- `readdirSync(targetPath: string): string[]` / `readdir(...): Promise<string[]>` —
|
|
45
|
+
- `readdirSync(targetPath: string): string[]` / `readdir(...): Promise<string[]>` — 디렉토리 직계 항목명(전체 경로 아닌 이름만) 배열.
|
|
55
46
|
|
|
56
47
|
## 파일 정보
|
|
57
48
|
|
|
58
|
-
- `statSync(targetPath
|
|
59
|
-
- `lstatSync(targetPath
|
|
49
|
+
- `statSync(targetPath): fs.Stats` / `stat(...): Promise<fs.Stats>` — 정보 조회. **심볼릭 링크를 따라감**(링크 대상의 정보).
|
|
50
|
+
- `lstatSync(targetPath): fs.Stats` / `lstat(...): Promise<fs.Stats>` — 정보 조회. **심볼릭 링크를 따라가지 않음**(링크 자체 정보). 링크/실파일을 구분해야 하면 lstat.
|
|
60
51
|
|
|
61
52
|
## Glob
|
|
62
53
|
|
|
63
|
-
- `globSync(pattern: string, options?: GlobOptions): string[]` / `glob(...): Promise<string[]>` — glob
|
|
64
|
-
- `
|
|
65
|
-
|
|
66
|
-
```ts
|
|
67
|
-
const files = await fsx.glob("src/**/*.ts", { ignore: ["**/*.d.ts"] });
|
|
68
|
-
```
|
|
54
|
+
- `globSync(pattern: string, options?: GlobOptions): string[]` / `glob(...): Promise<string[]>` — glob 검색. 입력 패턴의 `\` 를 `/` 로 치환해 매칭하고, 결과는 모두 `path.resolve` 로 **절대 경로**화해 반환.
|
|
55
|
+
- `pattern: string` — glob 패턴(예: `"src/**/*.ts"`).
|
|
56
|
+
- `options?: GlobOptions` — `glob` 패키지 옵션 그대로(`dot`, `cwd`, `ignore` 등). 숨김 파일 포함하려면 `{ dot: true }`. 생략 시 빈 객체.
|
|
69
57
|
|
|
70
58
|
## 유틸리티
|
|
71
59
|
|
|
72
|
-
- `clearEmptyDirectory(dirPath: string): Promise<void>` — 하위를 재귀
|
|
73
|
-
- `findAllParentChildPathsSync(childGlob
|
|
74
|
-
- `childGlob` — 각 디렉토리에서 검색할 glob
|
|
75
|
-
- `fromPath` — 탐색 시작 경로.
|
|
76
|
-
- `rootPath
|
|
60
|
+
- `clearEmptyDirectory(dirPath: string): Promise<void>` — `dirPath` 하위를 재귀 순회하며 **빈 디렉토리만** 삭제. 하위가 모두 비어 상위도 비게 되면 상위도 삭제. 파일이 하나라도 있으면 그 디렉토리는 보존. 존재하지 않으면 즉시 반환.
|
|
61
|
+
- `findAllParentChildPathsSync(childGlob, fromPath, rootPath?): string[]` / `findAllParentChildPaths(...): Promise<string[]>` — `fromPath` 에서 루트 방향으로 부모 디렉토리를 거슬러 올라가며 각 디렉토리에서 `childGlob` 매칭 파일을 모아 평탄화 반환. 상위 디렉토리들의 설정 파일(예: 각 단계 `package.json`) 수집에 사용.
|
|
62
|
+
- `childGlob: string` — 각 디렉토리에서 검색할 glob.
|
|
63
|
+
- `fromPath: string` — 탐색 시작 경로.
|
|
64
|
+
- `rootPath?: string` — 탐색 중단 경로. 생략 시 파일시스템 루트까지. **주의: fromPath 는 rootPath 의 하위여야 함**, 아니면 루트까지 올라간다.
|
|
65
|
+
|
|
66
|
+
## 사용 예
|
|
77
67
|
|
|
78
68
|
```ts
|
|
79
|
-
|
|
69
|
+
import { fsx } from "@simplysm/core-node";
|
|
70
|
+
await fsx.writeJson("dist/meta.json", { builtAt: new Date() }, { space: 2 });
|
|
71
|
+
await fsx.copy("src", "dist", (p) => !p.endsWith(".ts")); // .ts 제외 복사
|
|
72
|
+
const pkgs = await fsx.findAllParentChildPaths("package.json", process.cwd());
|
|
80
73
|
```
|
|
81
|
-
|
|
82
|
-
## 주의사항
|
|
83
|
-
|
|
84
|
-
- 동기 `rmSync`/`copySync` 는 재시도 동작이 비동기와 다름(rmSync 는 무재시도). Windows EPERM/잠금이 우려되면 비동기 버전 사용.
|
|
85
|
-
- glob 결과는 항상 절대 경로 — 상대 경로가 필요하면 호출 측에서 `path.relative` 처리.
|
|
86
|
-
- JSON IO 는 표준 `JSON` 이 아닌 `@simplysm/core-common` 의 `json` 사용 — Date 등 확장 타입 복원이 다름.
|
|
@@ -1,42 +1,35 @@
|
|
|
1
1
|
# @simplysm/core-node — pathx
|
|
2
2
|
|
|
3
|
-
`
|
|
3
|
+
`export * as pathx` 네임스페이스 (`packages/core-node/src/utils/path.ts`). 경로 문자열 가공·판정 유틸. OS 무관 비교를 위해 POSIX 슬래시(`/`)로 정규화하는 것이 핵심. `pathx.<fn>(...)` 형태로 호출.
|
|
4
4
|
|
|
5
|
-
## PosixPath
|
|
5
|
+
## PosixPath (브랜드 타입)
|
|
6
6
|
|
|
7
|
-
- `
|
|
8
|
-
- `posixResolve(...args: string[]): PosixPath` — `path.resolve` 로 절대 경로화한 뒤 슬래시 치환. 상대 입력은 cwd 기준으로 절대화.
|
|
9
|
-
- `PosixPath` — `string & { [POSIX]: never }` 브랜드 타입. `posix`/`posixResolve` 로만 생성 가능. POSIX 슬래시 경로임을 타입으로 보장할 때 쓰임(예: `FsWatcherChangeInfo.path`).
|
|
7
|
+
- `type PosixPath = string & { [POSIX]: never }` — POSIX 슬래시 경로임을 나타내는 브랜드 타입. `posix()`/`posixResolve()` 로만 생성 가능(심볼 키라 외부에서 캐스팅 없이는 못 만듦). 일반 `string` 을 PosixPath 자리에 직접 넣을 수 없어, 정규화를 강제하는 타입 가드 역할.
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
pathx.posix("C:\\a\\b"); // "C:/a/b"
|
|
13
|
-
pathx.posixResolve("a", "b"); // "<cwd>/a/b"
|
|
14
|
-
```
|
|
9
|
+
## 정규화
|
|
15
10
|
|
|
16
|
-
|
|
11
|
+
- `posix(p: string): PosixPath` — 백슬래시 → 슬래시 치환만 수행. **결합·resolve 안 함**. 예: `posix("C:\\Users\\test")` → `"C:/Users/test"`. 이미 절대/상대 경로인 문자열을 POSIX 표기로만 바꿀 때.
|
|
12
|
+
- `posixResolve(...args: string[]): PosixPath` — 인자들을 `path.resolve` 로 절대 경로 결합 후 슬래시로 변환. 예: `posixResolve("/base", "sub", "f.txt")` → `"/base/sub/f.txt"`, 상대경로 단독이면 cwd 기준 절대화. 경로 결합+정규화를 동시에 할 때.
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
- `changeFileDirectory(filePath: string, fromDirectory: string, toDirectory: string): string` — filePath 의 소속 디렉토리를 from→to 로 교체. `filePath === fromDirectory` 면 toDirectory 반환. from 하위가 아니면 `ArgumentError` throw. 빌드 출력 경로 산출에 사용.
|
|
20
|
-
- `basenameWithoutExt(filePath: string): string` — 마지막 확장자만 제거한 basename. `file.spec.ts` → `file.spec`.
|
|
14
|
+
## 경로 가공
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
pathx.changeFileDirectory("/src/x.ts", "/src", "/dist"); // "/dist/x.ts"
|
|
25
|
-
```
|
|
16
|
+
- `changeFileDirectory(filePath, fromDirectory, toDirectory): string` — `filePath` 의 디렉토리 prefix 를 `fromDirectory` → `toDirectory` 로 치환(상대 위치 유지). 예: `("/a/b/c.txt", "/a", "/x")` → `"/x/b/c.txt"`. `filePath === fromDirectory` 면 `toDirectory` 반환. **filePath 가 fromDirectory 내부가 아니면 `ArgumentError` throw**. src→dist 같은 출력 경로 산출에 사용.
|
|
17
|
+
- `basenameWithoutExt(filePath: string): string` — 확장자 1단계만 제거한 basename. 예: `"file.txt"` → `"file"`, `"a/file.spec.ts"` → `"file.spec"`(마지막 확장자만 제거).
|
|
26
18
|
|
|
27
|
-
##
|
|
19
|
+
## 판정·필터링
|
|
28
20
|
|
|
29
|
-
- `
|
|
30
|
-
|
|
31
|
-
- `
|
|
32
|
-
- `
|
|
21
|
+
- `isChildPath(childPath, parentPath): boolean` — `childPath` 가 `parentPath` 의 하위인지. 양쪽을 `posixResolve` 로 정규화 후 비교. **동일 경로면 false**(자기 자신은 하위 아님). 경계 오탐 방지를 위해 parent 끝에 `/` 를 붙여 startsWith 비교.
|
|
22
|
+
- `filterByTargets(files, targets, cwd): string[]` — 파일 목록을 타겟 경로 하위만 남김.
|
|
23
|
+
- `files: string[]` — 필터링할 파일. **cwd 하위 절대 경로여야 함**(외부 경로는 `../` 상대경로로 변환되어 매칭 실패 가능).
|
|
24
|
+
- `targets: string[]` — 대상 경로(cwd 기준 상대, POSIX 권장). 각 파일의 cwd-상대경로가 target 과 같거나 `target + "/"` 로 시작하면 통과.
|
|
25
|
+
- `cwd: string` — 기준 작업 디렉토리(절대 경로).
|
|
26
|
+
- **`targets` 가 비면 `files` 를 그대로 반환**(필터 미적용). CLI 의 `-t <패키지>` 같은 부분 빌드 대상 한정에 사용.
|
|
27
|
+
|
|
28
|
+
## 사용 예
|
|
33
29
|
|
|
34
30
|
```ts
|
|
35
|
-
pathx
|
|
36
|
-
|
|
31
|
+
import { pathx } from "@simplysm/core-node";
|
|
32
|
+
const out = pathx.changeFileDirectory(srcFile, "/proj/src", "/proj/dist");
|
|
33
|
+
if (pathx.isChildPath(out, "/proj")) { /* ... */ }
|
|
34
|
+
const targeted = pathx.filterByTargets(allFiles, ["src", "tests"], process.cwd());
|
|
37
35
|
```
|
|
38
|
-
|
|
39
|
-
## 주의사항
|
|
40
|
-
|
|
41
|
-
- `filterByTargets` 의 `targets` 가 비면 전체 통과 — 빈 결과를 기대하지 말 것.
|
|
42
|
-
- `changeFileDirectory` 는 범위 밖 입력을 silent 처리하지 않고 throw 하므로, 호출 전 `isChildPath` 로 보장하거나 throw 를 처리.
|
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
# @simplysm/core-node —
|
|
1
|
+
# @simplysm/core-node — worker
|
|
2
2
|
|
|
3
|
-
worker_threads 를 타입
|
|
3
|
+
`worker_threads` 를 타입 안전하게 쓰기 위한 래퍼 (`packages/core-node/src/worker/*`). 워커 파일에서 `createWorker(methods)` 로 메서드 묶음을 만들어 `export default` 하고, 메인에서 `Worker.create<typeof import("./worker")>(path)` 로 프록시를 만들어 `await worker.method(...)` 처럼 호출. 메시지 직렬화는 `@simplysm/core-common` 의 `transfer`(Date 등 특수타입·transferList 지원)를 사용한다. 개발(`.ts`)·프로덕션(`.js`) 양쪽을 자동 분기한다.
|
|
4
4
|
|
|
5
|
-
## createWorker (워커 측)
|
|
5
|
+
## createWorker (워커 스레드 측)
|
|
6
6
|
|
|
7
|
-
- `createWorker<TMethods, TEvents>(methods
|
|
8
|
-
- `methods: Record<string, (...args: any[]) => unknown>` —
|
|
9
|
-
- `TEvents extends Record<string, unknown>` —
|
|
10
|
-
- `send<
|
|
11
|
-
- `__methods` / `__events` — 타입
|
|
12
|
-
- 워커의 `process.stdout.write` 는 내부에서 가로채져 메시지 프로토콜로 메인의 stdout 에 전달됨(워커 로그가 메인 콘솔에 보임).
|
|
7
|
+
- `createWorker<TMethods, TEvents>(methods): { send; __methods; __events }` — 워커 스레드 진입 파일에서 호출하고 그 반환을 `export default`. `parentPort` 가 없으면(워커 컨텍스트 아님) `SdError` throw. 메서드 호출 메시지를 수신해 실행 후 결과/에러를 응답하고, 워커의 `process.stdout.write` 를 가로채 메인으로 로그를 전달한다.
|
|
8
|
+
- `methods: TMethods` (`Record<string, (...args: any[]) => unknown>`) — 워커가 제공할 메서드 맵. 동기/비동기 모두 가능(내부에서 await). 알 수 없는 메서드 호출 시 `SdError("알 수 없는 메서드: ...")` 로 응답.
|
|
9
|
+
- 제네릭 `TEvents extends Record<string, unknown>`(기본 `Record<string, never>`) — 워커가 보낼 이벤트명→데이터 타입 맵(메인의 `on` 타입 추론에 사용).
|
|
10
|
+
- 반환 `send<K extends keyof TEvents & string>(event, data?): void` — 워커→메인 이벤트 전송. 진행률 등 메서드 반환과 별개의 통지에 사용.
|
|
11
|
+
- 반환 `__methods` / `__events` — 타입 추론용 마커. 런타임 값이 아니라 `Worker.create<typeof import(...)>` 의 타입에서만 참조됨.
|
|
13
12
|
|
|
14
13
|
```ts
|
|
15
|
-
// worker.ts
|
|
16
|
-
|
|
14
|
+
// worker.ts (워커 스레드 진입)
|
|
15
|
+
import { createWorker } from "@simplysm/core-node";
|
|
16
|
+
interface MyEvents { progress: number; }
|
|
17
17
|
const methods = {
|
|
18
18
|
calc: (x: number) => { sender.send("progress", 50); return x * 2; },
|
|
19
19
|
};
|
|
20
|
-
const sender = createWorker<typeof methods,
|
|
20
|
+
const sender = createWorker<typeof methods, MyEvents>(methods);
|
|
21
21
|
export default sender;
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
## Worker.create (메인 측)
|
|
25
25
|
|
|
26
|
-
- `Worker.create<TModule extends WorkerModule>(filePath
|
|
27
|
-
- `filePath` — 워커 파일 경로.
|
|
28
|
-
- `opt?: Omit<WorkerRawOptions, "stdout" | "stderr">` —
|
|
29
|
-
- `WorkerProxy<TModule>` — 프록시 형태:
|
|
30
|
-
- 각 메서드 — `(...args) => Promise<Awaited<R>>`. 호출하면 RPC. 워커 핸들러 에러는 reject.
|
|
31
|
-
- `on(event, listener)` / `off(event, listener)` — 워커 `send` 이벤트 구독/해제.
|
|
32
|
-
- `terminate(): Promise<void>` — 워커 종료. 대기 중 요청은 reject.
|
|
26
|
+
- `Worker.create<TModule extends WorkerModule>(filePath, opt?): WorkerProxy<TModule>` — 워커 스레드를 띄우고 메서드 프록시를 반환. 메서드 호출은 메시지로 전달되어 결과가 Promise 로 resolve/reject 된다. 워커 stdout/stderr 는 메인 프로세스로 파이프되며, 워커 비정상 종료(exit code≠0)·error 시 대기 중인 모든 호출이 reject 된다. 로거 태그 `sd-worker`.
|
|
27
|
+
- `filePath: string` — 워커 파일 경로. `file://` URL 또는 절대 경로. 확장자가 `.ts` 면 dev 모드로 `lib/worker-dev-proxy.js`(tsx 로 TS 동적 로드)를 통해 실행, `.js` 면 직접 실행.
|
|
28
|
+
- `opt?: Omit<WorkerRawOptions, "stdout" | "stderr">` — worker_threads 옵션(stdout/stderr 는 내부 고정이라 제외). `env` 는 `process.env` 와 병합 전달, `argv` 는 dev 모드에서 워커 경로 뒤에 이어 붙음.
|
|
33
29
|
|
|
34
30
|
```ts
|
|
35
|
-
// main.ts
|
|
31
|
+
// main.ts (메인 측)
|
|
32
|
+
import { Worker } from "@simplysm/core-node";
|
|
36
33
|
const worker = Worker.create<typeof import("./worker")>("./worker.ts");
|
|
37
34
|
worker.on("progress", (p) => console.log(p));
|
|
38
|
-
const
|
|
35
|
+
const result = await worker.calc(10); // 20
|
|
39
36
|
await worker.terminate();
|
|
40
37
|
```
|
|
41
38
|
|
|
42
|
-
##
|
|
39
|
+
## WorkerProxy
|
|
40
|
+
|
|
41
|
+
`Worker.create` 반환 프록시. 워커 메서드 + 예약 메서드 3종을 제공.
|
|
43
42
|
|
|
44
|
-
-
|
|
45
|
-
- `
|
|
46
|
-
- `
|
|
47
|
-
- `
|
|
48
|
-
- `WorkerResponse` — 내부 응답 유니온: `return`(반환값) / `error`(Error) / `event`(send 이벤트) / `log`(stdout 전달).
|
|
43
|
+
- 메서드 프록시: `TModule["default"]["__methods"]` 의 각 메서드가 `(...args) => Promise<Awaited<R>>` 로 노출(`PromisifyMethods`). 동기 메서드도 postMessage 기반이라 항상 Promise.
|
|
44
|
+
- `on<TEventName>(event, listener): void` — 워커 `send` 이벤트 구독. `event`/`listener` 타입은 `TEvents` 에서 추론.
|
|
45
|
+
- `off<TEventName>(event, listener): void` — 이벤트 구독 해제.
|
|
46
|
+
- `terminate(): Promise<void>` — 워커 종료. 대기 중 호출은 "워커가 종료되었습니다" 로 reject 후 스레드 종료.
|
|
49
47
|
|
|
50
|
-
##
|
|
48
|
+
## 타입
|
|
51
49
|
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
50
|
+
- `interface WorkerModule { default: { __methods: Record<string, (...args: any[]) => unknown>; __events: Record<string, unknown> } }` — `Worker.create` 의 제네릭 제약. `typeof import("./worker")` 가 이 구조를 만족(=`createWorker` 반환을 default export).
|
|
51
|
+
- `type PromisifyMethods<TMethods>` — 각 메서드 반환을 `Promise<Awaited<R>>` 로 바꾸는 매핑 타입. 함수가 아닌 멤버는 `never`.
|
|
52
|
+
- `type WorkerProxy<TModule>` — 위 프록시 타입.
|
|
53
|
+
- `interface WorkerRequest { id: string; method: string; params: unknown[] }` — 내부 요청 메시지.
|
|
54
|
+
- `type WorkerResponse` — 내부 응답 메시지 union: `return`(결과) / `error`(Error) / `event`(워커 send) / `log`(stdout 전달). 직접 다룰 일은 거의 없음.
|
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
# @simplysm/excel
|
|
2
2
|
|
|
3
|
-
OOXML(.xlsx) 워크북을 ZIP 단위 lazy-load 로 읽고 쓰는 라이브러리. 대용량 파일에서도 접근한 셀에 필요한 XML
|
|
3
|
+
OOXML(.xlsx) 워크북을 ZIP 단위 lazy-load 로 읽고 쓰는 순수 TypeScript 라이브러리. 대용량 파일에서도 접근한 셀에 필요한 XML 파트(SharedStrings/Styles 등)만 그때그때 로드하므로 모든 셀 메서드가 `async` 다. `ExcelWorkbook` 진입점에서 시트 추가·셀 값/수식·스타일·조건부 서식·이미지·행 복사·뷰 설정을 다루며, Zod 스키마 기반 `ExcelWrapper` 로 레코드 배열 ↔ 엑셀 변환도 지원한다. 외부 의존은 `@simplysm/core-common`(DateOnly/DateTime/Time/Bytes), `zod`, `mime` 뿐.
|
|
4
4
|
|
|
5
5
|
## 사용 트리거 인덱스
|
|
6
6
|
|
|
7
|
-
- **ExcelWorkbook / ExcelWorksheet** — .xlsx
|
|
8
|
-
- **ExcelCell / ExcelRow / ExcelCol** — 개별 셀의 값·수식·병합·스타일을 읽고 쓰거나 행/열 단위로 셀을
|
|
9
|
-
- **셀 스타일 (ExcelStyleOptions / ExcelFont)** — 셀 또는 워크북 default
|
|
7
|
+
- **ExcelWorkbook / ExcelWorksheet** — .xlsx 를 열거나 새로 만들고 시트를 추가/조회하며 바이트·Blob 로 내보낼 때. 시트 단위 데이터 테이블·매트릭스·레코드 쓰기·행 복사/삽입·이미지·뷰(zoom/freeze/탭색) 처리 포함. 자세히: [workbook-worksheet.md](./workbook-worksheet.md)
|
|
8
|
+
- **ExcelCell / ExcelRow / ExcelCol** — 개별 셀의 값·수식·병합·스타일을 읽고 쓰거나 행/열 단위로 셀을 순회하고 열 너비를 줄 때. 자세히: [cell.md](./cell.md)
|
|
9
|
+
- **셀 스타일 (ExcelStyleOptions / ExcelFont)** — 셀(`cell.setStyle`) 또는 워크북 default(`wb.setDefaultStyle`)의 배경·테두리·정렬·숫자형식·폰트를 지정할 때. 자세히: [style.md](./style.md)
|
|
10
10
|
- **조건부 서식 (ExcelConditionalRule / ExcelConditionalRuleStyle)** — 셀/범위에 값 비교·텍스트 매칭·수식 기반 native CF 규칙을 추가할 때. 자세히: [conditional-format.md](./conditional-format.md)
|
|
11
|
-
- **ExcelWrapper** — Zod 스키마로 헤더 매핑·타입 변환·유효성 검사를 자동화해 레코드 배열 ↔
|
|
12
|
-
- **ExcelUtils** — 셀 주소(A1 ↔ 좌표) 변환,
|
|
13
|
-
- **값/주소/형식 타입** — 셀 값 유니온·숫자형식 프리셋·셀 타입·주소
|
|
11
|
+
- **ExcelWrapper** — Zod 스키마로 헤더 매핑·타입 변환·유효성 검사를 자동화해 레코드 배열 ↔ 엑셀을 변환할 때. 자세히: [wrapper.md](./wrapper.md)
|
|
12
|
+
- **ExcelUtils** — 셀 주소(A1 ↔ 좌표) 변환, 엑셀 날짜 시리얼 ↔ 타임스탬프 변환, 숫자형식 코드/ID/이름 상호 변환이 필요할 때. 자세히: [utils.md](./utils.md)
|
|
13
|
+
- **값/주소/형식 타입** — 셀 값 유니온·숫자형식 프리셋·셀 타입·주소 좌표·정렬/테두리/밑줄 enum 을 시그니처에서 참조할 때. 아래 인라인 섹션 참조.
|
|
14
14
|
- **OOXML XML-shape 타입** — `ExcelXml*` / `Excel*Data` 류. 라이브러리 내부 XML 파서/직렬화기가 쓰는 OOXML 노드 구조 타입. 아래 인라인 섹션 참조.
|
|
15
15
|
|
|
16
16
|
## 값/주소/형식 타입
|
|
17
17
|
|
|
18
|
-
`./types` 가 노출하는 사용자 대면 타입. 셀 값을 다루거나 메서드 시그니처를 해석할 때 참조.
|
|
18
|
+
`./types` 가 노출하는 사용자 대면 값/형식 타입. 셀 값을 다루거나 메서드 시그니처를 해석할 때 참조.
|
|
19
19
|
|
|
20
|
-
- `ExcelValueType` = `number | string | DateOnly | DateTime | Time | boolean | undefined` — 셀이 가질 수 있는 값 유니온. `getValue()` 반환·`setValue()` 인자 타입. `undefined` =
|
|
21
|
-
- `ExcelNumberFormat` = `"number" | "string" | "DateOnly" | "DateTime" | "Time"` — 숫자형식 프리셋 이름.
|
|
22
|
-
- `ExcelCellType` = `"s" | "b" | "str" | "n" | "inlineStr" | "e"` — OOXML 셀 `t` 속성. `"s"` = SharedString 인덱스 참조, `"b"` = boolean, `"str"` = 수식 결과 문자열, `"n"` = 숫자, `"inlineStr"` = 인라인 서식 텍스트, `"e"` = 에러(읽기 시 throw). 보통 직접 다루지 않고 `getValue`/`setValue` 가 자동
|
|
23
|
-
- `ExcelAddressPoint` = `{ r: number; c: number }` — 0 기반 행(`r`)·열(`c`) 좌표. 셀 단일 위치 단위.
|
|
24
|
-
- `ExcelAddressRangePoint` = `{ s: ExcelAddressPoint; e: ExcelAddressPoint }` — 범위 좌표. `s` = 시작(좌상단), `e` = 끝(
|
|
25
|
-
- `ExcelBorderPosition` = `"left" | "right" | "top" | "bottom"` — 테두리 적용 변. `ExcelStyleOptions.border` 배열 원소.
|
|
26
|
-
- `ExcelHorizontalAlign` = `"center" | "left" | "right"` — 가로
|
|
27
|
-
- `ExcelVerticalAlign` = `"center" | "top" | "bottom"` — 세로
|
|
28
|
-
- `ExcelFontUnderline` = `"single" | "double" | "singleAccounting" | "doubleAccounting"` — 밑줄 종류. OOXML `<u val="...">` 의 val 에 그대로 매핑.
|
|
20
|
+
- `ExcelValueType` = `number | string | DateOnly | DateTime | Time | boolean | undefined` — 셀이 가질 수 있는 값 유니온. `getValue()` 반환·`setValue()` 인자 타입. `undefined` = "값 없음"(읽기 시 빈 셀, 쓰기 시 셀 삭제)이므로 결측을 끝까지 보존. `DateOnly`/`DateTime`/`Time` 은 `@simplysm/core-common` 타입이며 셀에 시리얼 숫자 + 날짜 numFmt 로 저장된다.
|
|
21
|
+
- `ExcelNumberFormat` = `"number" | "string" | "DateOnly" | "DateTime" | "Time"` — 숫자형식 프리셋 이름. `"number"` = 일반 수치, `"string"` = 텍스트 형식, `"DateOnly"`/`"DateTime"`/`"Time"` = 날짜/시간 시리얼 해석·표시. `ExcelStyleOptions.numberFormat` 와 `ExcelUtils` 변환의 공용 단위. 날짜 형식 화면이면 셀 값으로 직접 `DateOnly`/`Time` 을 넣어 자동 numFmt 를 받는 편이 단순.
|
|
22
|
+
- `ExcelCellType` = `"s" | "b" | "str" | "n" | "inlineStr" | "e"` — OOXML 셀 `t` 속성. `"s"` = SharedString 인덱스 참조, `"b"` = boolean(`"1"`/`"0"`), `"str"` = 수식 결과 문자열, `"n"` = 숫자, `"inlineStr"` = 인라인 서식 텍스트, `"e"` = 에러(읽기 시 throw). 보통 직접 다루지 않고 `getValue`/`setValue` 가 자동 매핑하므로, 외부 생성 파일의 셀 타입 분기를 직접 검사할 때만 참조.
|
|
23
|
+
- `ExcelAddressPoint` = `{ r: number; c: number }` — 0 기반 행(`r`)·열(`c`) 좌표. 셀 단일 위치 단위. `cell(r, c)` 인덱스와 동일 0 기반.
|
|
24
|
+
- `ExcelAddressRangePoint` = `{ s: ExcelAddressPoint; e: ExcelAddressPoint }` — 범위 좌표. `s` = 시작(좌상단), `e` = 끝(우하단, inclusive). `getRange()` 반환 타입이며 시트 순회 루프 경계로 쓴다.
|
|
25
|
+
- `ExcelBorderPosition` = `"left" | "right" | "top" | "bottom"` — 테두리 적용 변. `ExcelStyleOptions.border` 배열 원소. 4변 전부면 4개를 배열에 모두 넣음.
|
|
26
|
+
- `ExcelHorizontalAlign` = `"center" | "left" | "right"` — 가로 정렬 값. 미지정 시 셀 기본(엑셀 자동).
|
|
27
|
+
- `ExcelVerticalAlign` = `"center" | "top" | "bottom"` — 세로 정렬 값. 미지정 시 셀 기본.
|
|
28
|
+
- `ExcelFontUnderline` = `"single" | "double" | "singleAccounting" | "doubleAccounting"` — 밑줄 종류. OOXML `<u val="...">` 의 val 에 그대로 매핑. 회계용 밑줄이 필요할 때 `*Accounting`.
|
|
29
29
|
|
|
30
30
|
## OOXML XML-shape 타입
|
|
31
31
|
|
|
32
|
-
`./types` 가 함께 export 하는 다음 인터페이스·타입은 라이브러리 내부 XML 파서/직렬화기가 OOXML 파트의 파싱 결과(`xml2js` 스타일의 `$`=속성,
|
|
32
|
+
`./types` 가 함께 export 하는 다음 인터페이스·타입은 라이브러리 내부 XML 파서/직렬화기가 OOXML 파트의 파싱 결과(`xml2js` 스타일의 `$`=속성, 자식은 단일 원소 배열로 래핑)를 표현하는 데이터 모델이다. 일반 사용 흐름(값/스타일/시트 API)에서는 직접 다루지 않으며, OOXML 노드를 직접 조작·검증할 때만 참조한다. 풀이는 각 타입이 표현하는 파트 1줄로 한정.
|
|
33
33
|
|
|
34
|
-
- `ExcelXmlContentTypeData` — `[Content_Types].xml` 의 `Types`(Default
|
|
35
|
-
- `ExcelXmlRelationshipData` / `ExcelRelationshipData` — `*.rels` 의 `Relationships` 및 개별 `Relationship`(Id/Target/Type) 구조.
|
|
34
|
+
- `ExcelXmlContentTypeData` — `[Content_Types].xml` 의 `Types`(Default 확장자 매핑·Override 파트 등록) 구조.
|
|
35
|
+
- `ExcelXmlRelationshipData` / `ExcelRelationshipData` — `*.rels` 의 `Relationships` 컨테이너 및 개별 `Relationship`(Id/Target/Type) 구조.
|
|
36
36
|
- `ExcelXmlWorkbookData` — `xl/workbook.xml` 의 `workbook`(bookViews/sheets 등) 구조.
|
|
37
|
-
- `ExcelXmlWorksheetData` — `xl/worksheets/sheetN.xml` 의 `worksheet`(sheetPr
|
|
38
|
-
- `ExcelXmlConditionalFormattingData` / `ExcelXmlCfRuleData` — `<conditionalFormatting>` 블록과 `<cfRule>`(type/operator/priority/dxfId/formula) 구조. `ExcelXmlCfRuleData["$"]["type"|"operator"]`
|
|
39
|
-
- `ExcelRowData` / `ExcelCellData` — `<row r="..">` 과 `<c r=".." s="
|
|
40
|
-
- `ExcelXmlDrawingData` — `xl/drawings/drawingN.xml` 의 `wsDr`(twoCellAnchor/pic/blipFill/spPr
|
|
41
|
-
- `ExcelXmlSharedStringData` / `ExcelXmlSharedStringDataSi` / `ExcelXmlSharedStringDataText` — `xl/sharedStrings.xml` 의 `sst` 와 `si` 항목(단순 `t` 또는 서식 run `r[]`), 텍스트 노드(`space="preserve"` 보존) 구조.
|
|
37
|
+
- `ExcelXmlWorksheetData` — `xl/worksheets/sheetN.xml` 의 `worksheet`(sheetPr 탭색/dimension/sheetViews 뷰·틀고정/cols 열너비/sheetData 행·셀/mergeCells/conditionalFormatting/drawing) 구조.
|
|
38
|
+
- `ExcelXmlConditionalFormattingData` / `ExcelXmlCfRuleData` — `<conditionalFormatting sqref="...">` 블록과 `<cfRule>`(type/operator/priority/dxfId/text/formula) 구조. `ExcelXmlCfRuleData["$"]["type"|"operator"]` 인덱스 타입은 규칙 spec 빌드 시 내부에서 참조된다.
|
|
39
|
+
- `ExcelRowData` / `ExcelCellData` — `<row r="..">` 과 `<c r=".." s="스타일ID" t="타입">`(v=값, f=수식, is=인라인 문자열) 구조.
|
|
40
|
+
- `ExcelXmlDrawingData` — `xl/drawings/drawingN.xml` 의 `wsDr`(twoCellAnchor from/to 앵커, pic/blipFill/spPr 이미지 노드) 구조.
|
|
41
|
+
- `ExcelXmlSharedStringData` / `ExcelXmlSharedStringDataSi` / `ExcelXmlSharedStringDataText` — `xl/sharedStrings.xml` 의 `sst` 와 `si` 항목(단순 `t` 또는 서식 run `r[]` 유니온), 텍스트 노드(`space="preserve"` 공백 보존) 구조.
|
|
42
42
|
- `ExcelXmlStyleData` 및 하위(`...Font` / `...Fill` / `...Border` / `...Xf` / `...Dxf`) — `xl/styles.xml` 의 `styleSheet`(numFmts/fonts/fills/borders/cellXfs/dxfs) 와 각 자원 노드 구조.
|
|
43
|
-
- `ExcelXml` = `{ readonly data: unknown; cleanup(): void }` — 모든 XML 파트
|
|
43
|
+
- `ExcelXml` = `{ readonly data: unknown; cleanup(): void }` — 모든 XML 파트 래퍼 클래스가 따르는 공통 인터페이스. `data` = 파싱된 노드 트리, `cleanup()` = 직렬화 직전 빈 노드 정리 등 마무리. 외부에서 구현할 일은 거의 없다.
|