@simplysm/sd-claude 14.0.81 → 14.0.83

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.
Files changed (87) hide show
  1. package/claude/references/sd-requirement-source-handling.md +20 -20
  2. package/claude/references/sd-simplysm14/README.md +13 -13
  3. package/claude/references/sd-simplysm14/manuals/client-component.md +92 -92
  4. package/claude/references/sd-simplysm14/manuals/client-crud.md +11 -11
  5. package/claude/references/sd-simplysm14/manuals/client-demo.md +28 -28
  6. package/claude/references/sd-simplysm14/manuals/client-rules.md +1 -1
  7. package/claude/references/sd-simplysm14/manuals/client-setup.md +21 -21
  8. package/claude/references/sd-simplysm14/manuals/client-tab.md +3 -3
  9. package/claude/references/sd-simplysm14/manuals/logging.md +15 -15
  10. package/claude/references/sd-simplysm14/manuals/orm-union.md +6 -6
  11. package/claude/references/sd-simplysm14/manuals/orm.md +19 -19
  12. package/claude/references/sd-simplysm14/manuals/test.md +33 -33
  13. package/claude/rules/sd-base-rules.md +44 -43
  14. package/claude/rules/sd-design-rules.md +18 -18
  15. package/claude/skills/sd-commit/SKILL.md +10 -10
  16. package/claude/skills/sd-config/SKILL.md +2 -2
  17. package/claude/skills/sd-demo/SKILL.md +45 -45
  18. package/claude/skills/sd-dev/SKILL.md +15 -15
  19. package/claude/skills/sd-docs/SKILL.md +7 -7
  20. package/claude/skills/sd-docs/references/subagent-prompt.md +33 -33
  21. package/claude/skills/sd-impl/SKILL.md +60 -60
  22. package/claude/skills/sd-review/SKILL.md +9 -9
  23. package/claude/skills/sd-skill/SKILL.md +74 -74
  24. package/claude/skills/sd-skill/evals/fixtures/existing-skill/.claude/skills/todo-format/SKILL.md +1 -1
  25. package/claude/skills/sd-spec/SKILL.md +355 -319
  26. package/claude/skills/sd-spec/references/example-spec.md +104 -104
  27. package/claude/skills/sd-unpack/SKILL.md +34 -34
  28. package/claude/skills/sd-use/SKILL.md +4 -4
  29. package/package.json +1 -1
  30. package/claude/references/sd-simplysm14/apis/angular/README.md +0 -37
  31. package/claude/references/sd-simplysm14/apis/angular/app-structure.md +0 -92
  32. package/claude/references/sd-simplysm14/apis/angular/buttons.md +0 -88
  33. package/claude/references/sd-simplysm14/apis/angular/crud.md +0 -100
  34. package/claude/references/sd-simplysm14/apis/angular/forms.md +0 -200
  35. package/claude/references/sd-simplysm14/apis/angular/infrastructure.md +0 -231
  36. package/claude/references/sd-simplysm14/apis/angular/kanban.md +0 -80
  37. package/claude/references/sd-simplysm14/apis/angular/layout.md +0 -92
  38. package/claude/references/sd-simplysm14/apis/angular/modal.md +0 -115
  39. package/claude/references/sd-simplysm14/apis/angular/routing.md +0 -107
  40. package/claude/references/sd-simplysm14/apis/angular/select-dropdown.md +0 -35
  41. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +0 -82
  42. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +0 -134
  43. package/claude/references/sd-simplysm14/apis/angular/sheet.md +0 -127
  44. package/claude/references/sd-simplysm14/apis/angular/toast.md +0 -97
  45. package/claude/references/sd-simplysm14/apis/angular/visual.md +0 -167
  46. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +0 -79
  47. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +0 -83
  48. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +0 -91
  49. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +0 -49
  50. package/claude/references/sd-simplysm14/apis/core-browser/README.md +0 -143
  51. package/claude/references/sd-simplysm14/apis/core-common/README.md +0 -58
  52. package/claude/references/sd-simplysm14/apis/core-common/extensions.md +0 -88
  53. package/claude/references/sd-simplysm14/apis/core-common/features.md +0 -51
  54. package/claude/references/sd-simplysm14/apis/core-common/types.md +0 -88
  55. package/claude/references/sd-simplysm14/apis/core-common/utils.md +0 -189
  56. package/claude/references/sd-simplysm14/apis/core-node/README.md +0 -12
  57. package/claude/references/sd-simplysm14/apis/core-node/consola.md +0 -59
  58. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +0 -44
  59. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +0 -42
  60. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +0 -53
  61. package/claude/references/sd-simplysm14/apis/core-node/pathx.md +0 -24
  62. package/claude/references/sd-simplysm14/apis/core-node/worker.md +0 -65
  63. package/claude/references/sd-simplysm14/apis/excel/README.md +0 -193
  64. package/claude/references/sd-simplysm14/apis/lint/README.md +0 -94
  65. package/claude/references/sd-simplysm14/apis/orm-common/README.md +0 -58
  66. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +0 -77
  67. package/claude/references/sd-simplysm14/apis/orm-common/executable.md +0 -20
  68. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +0 -92
  69. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +0 -98
  70. package/claude/references/sd-simplysm14/apis/orm-common/schema-builders.md +0 -128
  71. package/claude/references/sd-simplysm14/apis/orm-node/README.md +0 -69
  72. package/claude/references/sd-simplysm14/apis/sd-claude/README.md +0 -32
  73. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +0 -80
  74. package/claude/references/sd-simplysm14/apis/sd-cli/sd-config.md +0 -155
  75. package/claude/references/sd-simplysm14/apis/service-client/README.md +0 -131
  76. package/claude/references/sd-simplysm14/apis/service-common/README.md +0 -29
  77. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +0 -63
  78. package/claude/references/sd-simplysm14/apis/service-common/messages.md +0 -56
  79. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +0 -64
  80. package/claude/references/sd-simplysm14/apis/service-common/service-types.md +0 -43
  81. package/claude/references/sd-simplysm14/apis/service-server/README.md +0 -13
  82. package/claude/references/sd-simplysm14/apis/service-server/auth.md +0 -39
  83. package/claude/references/sd-simplysm14/apis/service-server/builtin-services.md +0 -71
  84. package/claude/references/sd-simplysm14/apis/service-server/define-service.md +0 -55
  85. package/claude/references/sd-simplysm14/apis/service-server/internals.md +0 -82
  86. package/claude/references/sd-simplysm14/apis/service-server/server.md +0 -57
  87. package/claude/references/sd-simplysm14/apis/storage/README.md +0 -71
@@ -1,59 +0,0 @@
1
- ## @simplysm/core-node — consola 설정
2
-
3
- 전역 `consola` 인스턴스에 reporter 를 일괄 부착하는 헬퍼와 reporter 구현체.
4
-
5
- ### setupConsola
6
-
7
- ```ts
8
- setupConsola(opts?: { cli?: boolean }): void
9
- ```
10
-
11
- 전역 `consola.level = LogLevels.debug` 로 설정 후 환경에 따라 reporter 구성:
12
-
13
- - `opts.cli !== true` && `env("DEV")` falsy → **프로덕션**: `createFileReporter()` 만 (JSONL 파일, 콘솔 X).
14
- - 그 외 → **개발**:
15
- - `env("SD_DEBUG")` truthy → `PrettyReporter()` 만 (debug 포함 콘솔).
16
- - 그 외 → `createFileReporter()`(debug 포함 파일) + `PrettyReporter()`(info 이상만 콘솔, `withMaxLevel` 적용).
17
-
18
- `opts.cli`: CLI 프로세스(`sd-cli` 등) 여부. true 면 파일 출력 없이 콘솔만 사용하도록 분기.
19
-
20
- ### withMaxLevel
21
-
22
- ```ts
23
- withMaxLevel(reporter: ConsolaReporter, maxLevel: number): ConsolaReporter
24
- ```
25
-
26
- 기존 reporter 를 감싸 `logObj.level > maxLevel` 인 항목을 버린다. consola `LogLevels` 는 낮을수록 심각(0=fatal/error, 1=warn, 2=log, 3=info, 4=debug, 5=trace).
27
-
28
- ### PrettyReporter
29
-
30
- `class PrettyReporter implements ConsolaReporter` — ANSI 컬러 콘솔 출력.
31
-
32
- - 색상 활성화: `env("NO_COLOR")` 있으면 비활성, `env("FORCE_COLOR")` 있으면 강제, TTY 또는 win32 면 활성.
33
- - level<2 (fatal/error/warn) → `stderr`, 그 외 → `stdout`.
34
- - `type === "box"` → 박스 포맷, `type === "trace"` → 스택 첨부, level<2 또는 `badge: true` → 위아래 빈 줄.
35
- - `Error` args → message + cwd prefix 제거된 스택 + `cause` 재귀 indent.
36
- - `ctx.options.formatOptions.date: true` → 시각 `HH:mm:ss.SSS` 부착.
37
-
38
- ### createFileReporter
39
-
40
- ```ts
41
- createFileReporter(options?: { maxSize?: number; maxDays?: number }): ConsolaReporter
42
- ```
43
-
44
- - `maxSize` (기본 20MB): 파일 1개 최대 크기. 초과 시 `app.<YYYY-MM-DD>.<seq>.log` 시퀀스로 회전.
45
- - `maxDays` (기본 14): cutoff 일자 이전 로그 파일 자동 삭제. 매일 첫 로그 시 1회 실행.
46
- - 출력 위치: `${process.cwd()}/.logs/app.<YYYY-MM-DD>.log` (필요시 `.<seq>` 부착).
47
- - 라인 형식: `{ time, level, tag?, err?: {message,stack}, msg? }` JSONL. `Error` arg 는 `err` 필드로 분리, 나머지는 `msg` 로 공백 연결.
48
- - 날짜 바뀌면 자동 로테이트. `.logs` 디렉토리는 첫 쓰기 시 생성.
49
-
50
- ### 예
51
-
52
- ```ts
53
- import { setupConsola, PrettyReporter, createFileReporter } from "@simplysm/core-node";
54
- import consola from "consola";
55
- setupConsola({ cli: true });
56
-
57
- // 커스텀
58
- consola.options.reporters = [new PrettyReporter(), createFileReporter({ maxDays: 30 })];
59
- ```
@@ -1,44 +0,0 @@
1
- ## @simplysm/core-node — cpx
2
-
3
- `import { cpx } from "@simplysm/core-node"`. 자식 프로세스 spawn 래퍼. stdout/stderr 를 시스템 인코딩으로 자동 디코딩, 실패 시 stderr 포함 에러 throw.
4
-
5
- ### 인코딩 감지
6
-
7
- - `getSystemEncoding(): string` — Windows 는 `chcp` 결과 코드 페이지를, POSIX 는 `LANG`/`LC_ALL` 의 `.<enc>` 부분을 파싱. 실패 시 `"utf-8"`. **결과는 모듈 캐시**.
8
- - `resetEncodingCache(): void` — 캐시 초기화. 환경 변경 후 강제 재감지 시.
9
- - `codePageToEncoding(codePage): string` — Windows 코드 페이지 번호→IANA 인코딩명(65001/949/932/936/950/1252/1251/1250/874 지원, 그 외 `"utf-8"`).
10
- - `decodeBytes(raw: Uint8Array, systemEncoding?: string): string` — UTF-8 fatal decode 시도 → 실패 시 지정 인코딩으로 fallback.
11
-
12
- ### spawn
13
-
14
- ```ts
15
- spawn(cmd, args, options?): SpawnProcess
16
- spawnSync(cmd, args, options?): SpawnResult
17
- ```
18
-
19
- - `options`: Node `SpawnOptions`/`SpawnSyncOptions` + `reject?: boolean`.
20
- - `stdio` 기본 `"pipe"`. pipe 인 스트림만 캡처되며 비-pipe 스트림은 결과 문자열이 빈 문자열.
21
- - `env`: `process.env` 와 병합되어 자식에 전달.
22
- - `reject` (기본 `true`): exitCode≠0 일 때 `false` 면 결과 객체 반환, `true` 면 throw. 에러 메시지는 `Command failed (exit N): <cmd> <args>` + stderr/stdout 마지막 4000자.
23
- - `SpawnResult`: `{ stdout: string; stderr: string; exitCode: number }`. 종료 코드가 없고 시그널만 있으면 exitCode=1.
24
-
25
- ### SpawnProcess
26
-
27
- `spawn()` 반환값. `PromiseLike<SpawnResult>`.
28
-
29
- - `pid: number | undefined` — 자식 PID.
30
- - `then / catch` — `SpawnResult` resolve 또는 에러 reject.
31
- - `kill(signal?): boolean` — 자식 프로세스에 시그널 전송.
32
-
33
- ### resolveStdioPipe
34
-
35
- - `resolveStdioPipe(stdio): { stdout: boolean; stderr: boolean }` — `SpawnOptions["stdio"]` 가 각 스트림에 대해 pipe 인지 판정. 배열·`"pipe"`·`undefined` 모두 처리.
36
-
37
- ### 예
38
-
39
- ```ts
40
- import { cpx } from "@simplysm/core-node";
41
- const { stdout } = await cpx.spawn("git", ["rev-parse", "HEAD"]);
42
- const proc = cpx.spawn("node", ["server.js"], { reject: false });
43
- proc.kill("SIGTERM");
44
- ```
@@ -1,42 +0,0 @@
1
- ## @simplysm/core-node — FsWatcher
2
-
3
- Chokidar 기반 디렉토리/글로브 변경 감시. 짧은 시간 내 이벤트를 병합하여 콜백 1회로 묶고, Windows EPERM 시 자동 재시작.
4
-
5
- ### 타입
6
-
7
- - `FsWatcherEvent = "add" | "addDir" | "change" | "unlink" | "unlinkDir"` — chokidar 원본 이벤트 그대로. 디렉토리/파일 add·unlink 구분.
8
- - `FsWatcherChangeInfo = { event: FsWatcherEvent; path: PosixPath }` — 콜백 인자 1건. `path` 는 POSIX 슬래시 정규화.
9
-
10
- ### 생성
11
-
12
- ```ts
13
- FsWatcher.watch(paths: string[], options?: ChokidarOptions): Promise<FsWatcher>
14
- ```
15
-
16
- - `paths`: 감시 대상. 디렉토리 절대 경로 또는 glob 패턴 혼용 가능. glob 메타문자 이전까지를 실제 감시 base 로 추출 후 chokidar 에 전달.
17
- - `options`: chokidar `ChokidarOptions`. `ignoreInitial` 은 내부적으로 항상 `true` 로 override 되지만, 사용자가 `false` 로 명시한 경우 첫 `onChange` 콜백을 **빈 배열**로 1회 호출(초기 트리거 신호용, 실제 초기 목록은 X).
18
- - `ready` 대기 후 resolve. 초기화 에러 시 close 후 reject.
19
-
20
- ### 메서드
21
-
22
- - `onChange(opt: { delay?: number }, cb: (changes: FsWatcherChangeInfo[]) => void | Promise<void>): this`
23
- - `opt.delay`: 디바운스 ms. 마지막 이벤트로부터 이 시간 후 콜백 1회.
24
- - 같은 파일에 대한 연속 이벤트 자동 병합: `add+change=add`, `add+unlink`=상쇄(제외), `addDir+unlinkDir`=상쇄, `unlink+add=add`, `unlink+change=change`, `unlinkDir+addDir=addDir`. 룩업 미스는 현재 이벤트로 덮어쓰기.
25
- - 콜백은 감시 base 가 아닌 **`paths` 원본 glob 에 매칭되는 경로만** 통과 (minimatch, dot 포함).
26
- - 다중 호출 가능. 각 호출마다 독립 debounce 큐 + handler 등록.
27
- - `close(): Promise<void>` — debounce 큐 dispose + chokidar close.
28
-
29
- ### 자동 복구
30
-
31
- - 감시 디렉토리 소실로 EPERM 발생 시 최대 3회 / 1초 간격으로 watcher 재생성·핸들러 재등록. 성공 시 retry count 리셋, 초과 시 중단(error 로그).
32
- - native `fs.FSWatcher.prototype.emit` 를 모듈 로드 시 1회 패치: listener 0 + `error` 이벤트는 swallow (orphan error 로 인한 프로세스 종료 방지).
33
-
34
- ### 예
35
-
36
- ```ts
37
- const w = await FsWatcher.watch(["src/**/*.ts"]);
38
- w.onChange({ delay: 300 }, async (changes) => {
39
- for (const { path, event } of changes) console.log(event, path);
40
- });
41
- // await w.close();
42
- ```
@@ -1,53 +0,0 @@
1
- ## @simplysm/core-node — fsx
2
-
3
- `import { fsx } from "@simplysm/core-node"`. 모든 함수는 동기(`*Sync`) + 비동기 쌍 제공. 실패 시 경로 정보를 포함한 `SdError` throw.
4
-
5
- ### 존재 확인 / 디렉토리
6
-
7
- - `existsSync(p) / exists(p): boolean | Promise<boolean>` — 파일·디렉토리 존재 여부.
8
- - `mkdirSync(p) / mkdir(p): void | Promise<void>` — 재귀 생성. 이미 있으면 무시.
9
- - `readdirSync(p) / readdir(p): string[]` — 자식 이름 배열(절대 경로 아님).
10
-
11
- ### 삭제
12
-
13
- - `rmSync(p)` — 재귀+force. **재시도 없음**, 파일 잠금 시 즉시 실패.
14
- - `rm(p)` — 재귀+force, **최대 6회 / 500ms 간격 재시도**. 일시적 잠금 회피용.
15
-
16
- ### 복사
17
-
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 재시도.
23
-
24
- ### 읽기 / 쓰기
25
-
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`: 들여쓰기(숫자=스페이스 수, 문자열=리터럴).
31
-
32
- ### Stats
33
-
34
- - `statSync / stat` — `fs.Stats`. 심볼릭 링크 따라감.
35
- - `lstatSync / lstat` — `fs.Stats`. 심볼릭 링크 안 따라감 (링크 자체 정보).
36
-
37
- ### Glob
38
-
39
- - `globSync(pattern, options?) / glob(pattern, options?): string[]` — `glob` 패키지 래핑. 패턴 내 백슬래시는 슬래시로 치환 후 호출. 결과는 **항상 절대 경로**로 정규화.
40
- - `options`: `glob` 패키지의 `GlobOptions`(예: `dot: true` 로 dotfile 포함).
41
-
42
- ### 트리 유틸
43
-
44
- - `clearEmptyDirectory(dirPath)` — 하위까지 재귀 순회, 파일이 없는 디렉토리만 삭제. 파일이 하나라도 있으면 보존.
45
- - `findAllParentChildPathsSync(childGlob, fromPath, rootPath?) / findAllParentChildPaths(...)` — `fromPath` 부터 루트 방향으로 부모 디렉토리를 따라가며 각 디렉토리에서 `childGlob` 패턴 매칭 파일을 수집. `rootPath` 도달 시 종료(지정 없으면 FS 루트까지). 모노레포 루트 탐색 등에 사용.
46
-
47
- ### 예
48
-
49
- ```ts
50
- import { fsx } from "@simplysm/core-node";
51
- await fsx.copy("src", "dist", (p) => !p.includes("node_modules"));
52
- const cfg = await fsx.readJson<{ name: string }>("package.json");
53
- ```
@@ -1,24 +0,0 @@
1
- ## @simplysm/core-node — pathx
2
-
3
- `import { pathx } from "@simplysm/core-node"`. POSIX 슬래시 경로 정규화·비교·필터링.
4
-
5
- ### 타입
6
-
7
- - `PosixPath` — `string & { [POSIX]: never }` 브랜드 타입. `posix()` / `posixResolve()` 만 생성 가능. 글로브·minimatch·URL 호환 경로 표현용.
8
-
9
- ### 함수
10
-
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` 옵션 처리에 사용.
17
-
18
- ### 예
19
-
20
- ```ts
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
24
- ```
@@ -1,65 +0,0 @@
1
- ## @simplysm/core-node — Worker
2
-
3
- 타입 안전한 `worker_threads` 래퍼. 메인에서는 `Worker.create()` 로 프록시 호출, 워커에서는 `createWorker()` 로 메서드·이벤트 노출.
4
-
5
- ### 워커 스크립트 — `createWorker`
6
-
7
- ```ts
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;
12
- }
13
- ```
14
-
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.
23
-
24
- ### 메인 — `Worker.create`
25
-
26
- ```ts
27
- Worker.create<TModule extends WorkerModule>(
28
- filePath: string,
29
- opt?: Omit<WorkerOptions, "stdout" | "stderr">,
30
- ): WorkerProxy<TModule>
31
- ```
32
-
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 는 메인 프로세스로 파이프.
38
-
39
- ### 반환 프록시 — `WorkerProxy<TModule>`
40
-
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 후 워커 종료.
44
-
45
- ### 비정상 종료
46
-
47
- - 워커 `exit` (코드≠0, 사용자 terminate 아님) 또는 `error` 발생 시 대기 중인 모든 호출이 `Error("워커가 비정상 종료되었습니다 (코드: N) (method: X)")` 등으로 reject.
48
-
49
- ### 예
50
-
51
- ```ts
52
- // worker.ts
53
- import { createWorker } from "@simplysm/core-node";
54
- interface E { progress: number }
55
- const methods = { calc: (n: number) => n * 2 };
56
- const sender = createWorker<typeof methods, E>(methods);
57
- export default sender;
58
-
59
- // main.ts
60
- import { Worker } from "@simplysm/core-node";
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();
65
- ```
@@ -1,193 +0,0 @@
1
- # @simplysm/excel
2
-
3
- OOXML(xlsx) ZIP 을 lazy 로 읽고 쓰는 neutral 패키지. 셀 단위 접근 시점에만 해당 XML(SharedStrings/Styles 등)을 로드하므로 대용량 파일 메모리 효율적.
4
-
5
- ## 사용 트리거 인덱스
6
-
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
-
33
- ```typescript
34
- const wb = new ExcelWorkbook(bytes);
35
- try {
36
- const ws = await wb.getWorksheet(0);
37
- // ...
38
- } finally { await wb.close(); }
39
- ```
40
-
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
-
121
- ```typescript
122
- await ws.addConditionalFormat({
123
- ref: "B2:B100",
124
- rules: [{ type: "cellIs", op: "<", value: 1000, style: { background: "00FF0000" } }],
125
- });
126
- ```
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.
148
-
149
- ## ExcelWrapper
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.
166
-
167
- ## ExcelUtils
168
-
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 스타일, 내부 처리용). 외부 코드에서 직접 다룰 일 없음.
@@ -1,94 +0,0 @@
1
- # @simplysm/lint
2
-
3
- Simplysm 컨벤션용 ESLint 플러그인 패키지. 커스텀 규칙 묶음(`./eslint-plugin`)과 typescript-eslint·angular-eslint 통합 flat config 프리셋(`./eslint-recommended`)을 제공한다.
4
-
5
- ## 사용 트리거 인덱스
6
-
7
- - **`./eslint-recommended` (default export)** — 프로젝트 `eslint.config.{js,mjs,cjs}` 에서 그대로 spread 해 simplysm 표준 lint 규칙을 적용할 때.
8
- - **`./eslint-plugin` (default export)** — recommended 를 사용하지 않고 개별 규칙만 골라 쓰거나, 다른 flat config 에서 `@simplysm/<rule>` 로 참조할 때.
9
- - **`ng-no-async-effect`** — Angular `effect()` 콜백을 async 로 작성하지 않게 막을 때.
10
- - **`ng-template-no-strict-null-check`** — Angular 템플릿에서 `=== null|undefined` 대신 `== null` 로 통일시킬 때.
11
- - **`ng-template-no-todo-comments`** — Angular 템플릿 내 `<!-- TODO: ... -->` 를 빌드 경고로 남길 때.
12
- - **`ng-template-sd-require-binding-attrs`** — `sd-*` 컴포넌트에 plain attribute 못 쓰게 하고 property binding 으로 강제할 때.
13
- - **`no-hard-private`** — `#field` 대신 TypeScript `private _field` 스타일을 강제할 때.
14
- - **`no-subpath-imports-from-simplysm`** — `@simplysm/<pkg>/src/...` 직접 import 를 차단할 때.
15
- - **`ts-no-throw-not-implemented-error`** — `NotImplementedError` 잔존을 빌드 경고로 표면화할 때.
16
- - **`ts-no-unused-injects`** — Angular `inject()` 로 받은 미사용 필드를 정리할 때.
17
- - **`ts-no-unused-protected-readonly`** — Angular 컴포넌트 인라인 템플릿/클래스 어느 쪽에서도 안 쓰는 `protected readonly` 필드를 정리할 때.
18
-
19
- ## `./eslint-recommended`
20
-
21
- ```ts
22
- // eslint.config.mjs
23
- import recommended from "@simplysm/lint/eslint-recommended";
24
- export default recommended;
25
- // 또는 추가 config 와 함께
26
- export default [...recommended, { /* overrides */ }];
27
- ```
28
-
29
- `typescript-eslint.config(...)` 결과(flat config 배열). 다음을 합쳐 export 한다:
30
-
31
- - `ignores`: `**/node_modules/**`, `**/dist/**`, `**/.*/**` (디렉터리 단위 스킵).
32
- - `**/*.{js,mjs,cjs}` 블록: globals=node, 플러그인 `import`/`@simplysm`/`unused-imports`, `import/no-extraneous-dependencies` 예외 경로 = `**/lib/**`, `**/eslint.config.{js,cjs,mjs}`, `**/simplysm.{js,cjs,mjs}`, `**/vitest.config.{js,cjs,mjs}`.
33
- - `angular.configs.tsRecommended` + `**/*.ts` 블록: `tseslint.parser` + `parserOptions.project: true`, `angular.processInlineTemplates` processor, `eslint-import-resolver-typescript` resolver(`alwaysTryTypes: true`).
34
- - `**/*.html` 블록: `angular.configs.templateRecommended` + `templateAccessibility` extends, `@angular-eslint/template/eqeqeq` 는 `allowNullOrUndefined: true`, `label-has-associated-control` off, `template/no-any` error.
35
- - `**/tests/**/*.ts` override: `no-console`, `import/no-extraneous-dependencies`, `@simplysm/ts-no-throw-not-implemented-error` off.
36
- - `**/vitest.config.ts` override: `no-restricted-properties` off (vitest 가 `process` 접근 필요).
37
-
38
- 공통으로 강제되는 simplysm 컨벤션:
39
-
40
- - `Buffer`/`buffer`/`events`/`eventemitter3` 금지 → `Uint8Array`/`@simplysm/core-common` 사용 유도.
41
- - `process.env`/`import.meta.env` 직접 접근 금지 → `env("...")` 호출 강제. `env("NODE_ENV")` 자체 금지.
42
- - `=== undefined` / `!== undefined` 금지 → `== null` / `!= null` 통일.
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).
49
-
50
- ## `./eslint-plugin`
51
-
52
- ```ts
53
- // eslint.config.mjs
54
- import simplysm from "@simplysm/lint/eslint-plugin";
55
- export default [{
56
- plugins: { "@simplysm": simplysm },
57
- rules: { "@simplysm/no-hard-private": "error" },
58
- }];
59
- ```
60
-
61
- `{ rules: { ... } }` 형태의 ESLint 플러그인 객체. 노출 규칙(전부 `@simplysm/<name>` 으로 참조):
62
-
63
- ### `ng-no-async-effect` (problem)
64
- `@angular/core`에서 import 한 `effect()` 1번째 인자가 async 함수면 보고. named/aliased/namespace import 모두 추적. `await` 이후 signal read 가 의존성 추적 밖으로 빠지는 문제 방지. 안내: 비동기 작업은 `void untracked(async () => { ... })` 로 감쌀 것.
65
-
66
- ### `ng-template-no-strict-null-check` (problem)
67
- HTML 템플릿 바인딩에서 `=== null|undefined`, `!== null|undefined` 사용 시 보고. `== null`/`!= null` 로 통일 유도. autofix 없음(인라인 템플릿 offset 매핑 문제).
68
-
69
- ### `ng-template-no-todo-comments` (problem, recommended=warn)
70
- HTML 주석 `<!-- TODO: ... -->` 를 정규식으로 탐지해 본문을 메시지로 보고. AST 방문자 없이 raw text 스캔.
71
-
72
- ### `ng-template-sd-require-binding-attrs` (problem, fixable)
73
- `sd-*` 접두사 컴포넌트의 plain attribute 사용을 제한하고 property binding 으로 변환.
74
- - 옵션: `selectorPrefixes`(기본 `["sd-"]`), `allowAttributes`(기본 `["id","class","style","title","tabindex","role"]`), `allowAttributePrefixes`(기본 `["aria-","data-","sd-"]`).
75
- - Autofix: `foo="bar"` → `[foo]="'bar'"`, 값 없으면 `[foo]="true"`.
76
-
77
- ### `no-hard-private` (problem, fixable)
78
- ES private 필드(`#field`, `#method()`, `accessor #field`, `this.#field`) 금지. TypeScript `private _field` 스타일 강제. Autofix 로 `#x` → `_x` 치환 + 선언부에 `private` 키워드 삽입(데코레이터/`static`/`async`/`readonly` 순서 보존). 동일 클래스에 `_x` 멤버가 이미 있으면 `nameConflict` 로 보고만(자동 수정 안 함).
79
-
80
- ### `no-subpath-imports-from-simplysm` (problem, fixable)
81
- `@simplysm/<pkg>/src/...` 형태 import 금지. 정적 `import`, 동적 `import()`, `export ... from`, `export * from` 모두 검사. Autofix: `@simplysm/<pkg>` 로 단축.
82
-
83
- ### `ts-no-throw-not-implemented-error` (suggestion, recommended=warn)
84
- `@simplysm/core-common` 에서 import 한 `NotImplementedError` 의 `new` 호출 보고. named/aliased/namespace import 추적. 인자가 비어있지 않은 문자열 리터럴이면 메시지에 그대로 노출(없으면 `"미구현"`). 동적 import 는 미지원. `**/tests/**/*.ts` 에서는 off.
85
-
86
- ### `ts-no-unused-injects` (problem, fixable)
87
- 클래스 내 `inject()` 로 초기화된 PropertyDefinition 중 같은 클래스 본문에서 식별자로 단 한 번도 참조되지 않는 필드 보고. Autofix 로 해당 필드 라인 제거.
88
-
89
- ### `ts-no-unused-protected-readonly` (problem, fixable)
90
- `@Component({ template: "..." })` 클래스의 `protected readonly` 인스턴스 필드(=static 제외) 중 인라인 템플릿과 클래스 본문 모두에서 미참조면 보고·자동 제거. `templateUrl` 만 있는 경우(=`template` 프로퍼티 없음) 검사 스킵. 템플릿은 `@angular/compiler` 의 `parseTemplate` 로 파싱하며 `*ngFor` 로컬 변수, `@let`, `@if as alias`, `@for item/context`, `@switch`/`@defer` 트리거까지 스코프 처리.
91
-
92
- ## 규칙 작성용 유틸 (내부)
93
-
94
- `createRule` 은 패키지 내부 규칙 정의 전용 헬퍼(`ESLintUtils.RuleCreator` 래퍼)로, 외부 export 표면(`exports` 필드) 에 노출되지 않는다. 소비자 코드에서 직접 사용하지 않음.