@simplysm/core-node 13.0.96 → 13.0.98
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/README.md +29 -288
- package/docs/features.md +91 -0
- package/docs/fs.md +309 -0
- package/docs/path.md +120 -0
- package/docs/worker.md +168 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,315 +1,56 @@
|
|
|
1
1
|
# @simplysm/core-node
|
|
2
2
|
|
|
3
|
-
Node.js
|
|
3
|
+
Core module (node) -- Node.js utilities for file system, path, watching, and workers.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install @simplysm/core-node
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## Exports
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
@simplysm/core-node
|
|
17
|
-
├── fsx # 파일시스템 유틸리티 (namespace)
|
|
18
|
-
├── pathx # 경로 유틸리티 (namespace)
|
|
19
|
-
├── FsWatcher # 파일 감시 (class)
|
|
20
|
-
├── Worker # 타입 안전한 Worker 스레드 (object)
|
|
21
|
-
├── createWorker # Worker 팩토리 (function)
|
|
22
|
-
└── types # NormPath, WorkerModule, WorkerProxy, ...
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## 주요 사용법
|
|
28
|
-
|
|
29
|
-
### fsx -- 파일시스템 유틸리티
|
|
30
|
-
|
|
31
|
-
모든 함수는 async/sync 쌍으로 제공된다 (예: `read` / `readSync`).
|
|
13
|
+
All utilities are re-exported from the package entry point:
|
|
32
14
|
|
|
33
15
|
```typescript
|
|
34
|
-
import { fsx } from "@simplysm/core-node";
|
|
35
|
-
|
|
36
|
-
// 존재 확인
|
|
37
|
-
await fsx.exists("/path/to/file");
|
|
38
|
-
fsx.existsSync("/path/to/file");
|
|
39
|
-
|
|
40
|
-
// 디렉토리 생성 (재귀)
|
|
41
|
-
await fsx.mkdir("/path/to/dir");
|
|
42
|
-
fsx.mkdirSync("/path/to/dir");
|
|
43
|
-
|
|
44
|
-
// 삭제
|
|
45
|
-
// async: 6회 재시도, 500ms 간격 (파일 잠금 등 일시적 오류 대응)
|
|
46
|
-
// sync: 재시도 없이 즉시 실패
|
|
47
|
-
await fsx.rm("/path/to/target");
|
|
48
|
-
fsx.rmSync("/path/to/target");
|
|
49
|
-
|
|
50
|
-
// 복사 (필터 지원)
|
|
51
|
-
// 필터는 자식 경로에만 적용, 최상위 sourcePath는 필터링 대상이 아님
|
|
52
|
-
// 디렉토리에 false를 반환하면 해당 디렉토리와 모든 하위 내용을 건너뜀
|
|
53
|
-
// sourcePath가 존재하지 않으면 아무 동작 없이 반환
|
|
54
|
-
await fsx.copy(src, dst, (absPath) => !absPath.includes("node_modules"));
|
|
55
|
-
fsx.copySync(src, dst);
|
|
56
|
-
|
|
57
|
-
// 읽기
|
|
58
|
-
const text = await fsx.read("/path/to/file.txt"); // UTF-8 문자열
|
|
59
|
-
const buf = await fsx.readBuffer("/path/to/file.bin"); // Buffer
|
|
60
|
-
const config = await fsx.readJson<Config>("/path/config.json"); // JSON 파싱 (core-common의 json.parse 사용)
|
|
61
|
-
|
|
62
|
-
// 쓰기 (부모 디렉토리 자동 생성)
|
|
63
|
-
await fsx.write("/path/to/file.txt", content); // string | Uint8Array
|
|
64
|
-
await fsx.writeJson("/path/to/config.json", data, { space: 2 });
|
|
65
|
-
// writeJson의 options: { replacer?, space? }
|
|
66
|
-
|
|
67
|
-
// 디렉토리 읽기
|
|
68
|
-
const entries = await fsx.readdir("/path/to/dir"); // string[]
|
|
69
|
-
|
|
70
|
-
// 파일 정보
|
|
71
|
-
const stats = await fsx.stat("/path/to/file"); // 심볼릭 링크 따라감
|
|
72
|
-
const lstats = await fsx.lstat("/path/to/symlink"); // 심볼릭 링크 자체 정보
|
|
73
|
-
|
|
74
|
-
// Glob 패턴 검색 (절대 경로 반환)
|
|
75
|
-
const files = await fsx.glob("**/*.ts", { cwd: "/project" });
|
|
76
|
-
const filesSync = fsx.globSync("**/*.ts", { cwd: "/project" });
|
|
77
|
-
|
|
78
|
-
// 빈 디렉토리 정리 (재귀적으로 빈 디렉토리 삭제)
|
|
79
|
-
await fsx.clearEmptyDirectory("/path/to/dir");
|
|
80
|
-
|
|
81
|
-
// 상위 디렉토리 탐색
|
|
82
|
-
// fromPath에서 루트까지 각 디렉토리에서 childGlob 패턴에 매칭되는 파일 검색
|
|
83
|
-
const paths = await fsx.findAllParentChildPaths("package.json", "/project/src/deep");
|
|
84
|
-
const pathsSync = fsx.findAllParentChildPathsSync("package.json", "/project/src/deep", "/project"); // rootPath 지정 가능
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### pathx -- 경로 유틸리티
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
import { pathx } from "@simplysm/core-node";
|
|
91
|
-
import type { NormPath } from "@simplysm/core-node";
|
|
92
|
-
|
|
93
|
-
// POSIX 변환 (여러 인자를 path.join 후 변환)
|
|
94
|
-
pathx.posix("C:\\Users\\test"); // "C:/Users/test"
|
|
95
|
-
pathx.posix("src", "index.ts"); // "src/index.ts"
|
|
96
|
-
|
|
97
|
-
// 정규화 (절대 경로, 브랜드 타입 NormPath 반환)
|
|
98
|
-
const norm: NormPath = pathx.norm("relative/path");
|
|
99
|
-
const norm2: NormPath = pathx.norm("base", "relative"); // 여러 경로 조합 가능
|
|
100
|
-
|
|
101
|
-
// 디렉토리 변경
|
|
102
|
-
pathx.changeFileDirectory("/a/b/c.txt", "/a", "/x"); // "/x/b/c.txt"
|
|
103
|
-
// filePath가 fromDirectory 하위가 아니면 ArgumentError 발생
|
|
104
|
-
|
|
105
|
-
// 확장자 없는 파일명
|
|
106
|
-
pathx.basenameWithoutExt("/path/file.spec.ts"); // "file.spec"
|
|
107
|
-
|
|
108
|
-
// 자식 경로 확인
|
|
109
|
-
pathx.isChildPath("/a/b/c", "/a/b"); // true
|
|
110
|
-
pathx.isChildPath("/a/b", "/a/b"); // false (동일 경로)
|
|
111
|
-
|
|
112
|
-
// 대상 경로 필터링
|
|
113
|
-
pathx.filterByTargets(
|
|
114
|
-
["/proj/src/a.ts", "/proj/tests/c.ts"],
|
|
115
|
-
["src"],
|
|
116
|
-
"/proj"
|
|
117
|
-
);
|
|
118
|
-
// ["/proj/src/a.ts"]
|
|
119
|
-
// targets가 빈 배열이면 files를 그대로 반환
|
|
16
|
+
import { fsx, pathx, FsWatcher, Worker, createWorker } from "@simplysm/core-node";
|
|
120
17
|
```
|
|
121
18
|
|
|
122
|
-
|
|
19
|
+
- **`fsx`** -- File system utilities (namespace). See [docs/fs.md](docs/fs.md)
|
|
20
|
+
- **`pathx`** -- Path utilities (namespace). See [docs/path.md](docs/path.md)
|
|
21
|
+
- **`FsWatcher`** -- Chokidar-based file system watcher. See [docs/features.md](docs/features.md)
|
|
22
|
+
- **Worker / createWorker** -- Type-safe worker_threads wrapper. See [docs/worker.md](docs/worker.md)
|
|
123
23
|
|
|
124
|
-
|
|
24
|
+
## Quick Start
|
|
125
25
|
|
|
126
26
|
```typescript
|
|
127
|
-
import { FsWatcher } from "@simplysm/core-node";
|
|
128
|
-
import type { FsWatcherEvent, FsWatcherChangeInfo } from "@simplysm/core-node";
|
|
27
|
+
import { fsx, pathx, FsWatcher, Worker, createWorker } from "@simplysm/core-node";
|
|
129
28
|
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
"/project/src", // 디렉토리 경로
|
|
134
|
-
"/project/lib/**/*.js", // glob 패턴
|
|
135
|
-
]);
|
|
29
|
+
// File system
|
|
30
|
+
const content = await fsx.read("/path/to/file.txt");
|
|
31
|
+
await fsx.write("/path/to/output.txt", content);
|
|
136
32
|
|
|
137
|
-
//
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
ignored: /node_modules/,
|
|
141
|
-
});
|
|
33
|
+
// Path utilities
|
|
34
|
+
const normalized = pathx.norm("/some/path");
|
|
35
|
+
const posixPath = pathx.posix("C:\\Users\\test");
|
|
142
36
|
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
watcher.onChange({ delay: 300 }, (changes
|
|
146
|
-
for (const {
|
|
147
|
-
//
|
|
148
|
-
// path: NormPath (정규화된 절대 경로)
|
|
37
|
+
// File watching
|
|
38
|
+
const watcher = await FsWatcher.watch(["src/**/*.ts"]);
|
|
39
|
+
watcher.onChange({ delay: 300 }, (changes) => {
|
|
40
|
+
for (const { path, event } of changes) {
|
|
41
|
+
// handle changes
|
|
149
42
|
}
|
|
150
43
|
});
|
|
151
44
|
|
|
152
|
-
//
|
|
153
|
-
await watcher.close();
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
**이벤트 병합 전략** (같은 파일에 대해 짧은 시간 내 여러 이벤트 발생 시):
|
|
157
|
-
- `add` + `change` -> `add` (생성 직후 수정은 생성으로 처리)
|
|
158
|
-
- `add` + `unlink` -> 제거 (생성 후 즉시 삭제는 무변경)
|
|
159
|
-
- `unlink` + `add` -> `add` (삭제 후 재생성은 생성으로 처리)
|
|
160
|
-
- `unlink` + `change` -> `add` (삭제 후 변경은 생성으로 처리)
|
|
161
|
-
- `unlinkDir` + `addDir` -> `addDir`
|
|
162
|
-
- 그 외 -> 마지막 이벤트로 덮어쓰기
|
|
163
|
-
|
|
164
|
-
### Worker -- 타입 안전한 Worker 스레드
|
|
165
|
-
|
|
166
|
-
#### Worker 파일 작성 (worker.ts)
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
import { createWorker } from "@simplysm/core-node";
|
|
170
|
-
|
|
171
|
-
// 이벤트 없는 Worker
|
|
172
|
-
export default createWorker({
|
|
173
|
-
add: (a: number, b: number) => a + b,
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
// 이벤트가 있는 Worker
|
|
177
|
-
interface MyEvents {
|
|
178
|
-
progress: number;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const methods = {
|
|
182
|
-
processFile: async (path: string) => {
|
|
183
|
-
sender.send("progress", 50);
|
|
184
|
-
// ... 처리 ...
|
|
185
|
-
sender.send("progress", 100);
|
|
186
|
-
return "done";
|
|
187
|
-
},
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
const sender = createWorker<typeof methods, MyEvents>(methods);
|
|
191
|
-
export default sender;
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
#### 메인 스레드에서 사용
|
|
195
|
-
|
|
196
|
-
```typescript
|
|
197
|
-
import { Worker } from "@simplysm/core-node";
|
|
198
|
-
|
|
199
|
-
// Worker 생성 (타입 추론을 위해 typeof import 사용)
|
|
45
|
+
// Workers
|
|
200
46
|
const worker = Worker.create<typeof import("./worker")>("./worker.ts");
|
|
201
|
-
|
|
202
|
-
// 옵션 전달 (WorkerOptions에서 stdout/stderr 제외)
|
|
203
|
-
const worker2 = Worker.create<typeof import("./worker")>("./worker.ts", {
|
|
204
|
-
env: { NODE_ENV: "production" },
|
|
205
|
-
argv: ["--verbose"],
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
// 메서드 호출 (자동 Promise 래핑)
|
|
209
|
-
const result = await worker.add(10, 20); // 30
|
|
210
|
-
|
|
211
|
-
// 이벤트 수신
|
|
212
|
-
const handler = (value: number) => { /* ... */ };
|
|
213
|
-
worker.on("progress", handler);
|
|
214
|
-
worker.off("progress", handler); // 이벤트 해제
|
|
215
|
-
|
|
216
|
-
// 종료
|
|
47
|
+
const result = await worker.add(10, 20);
|
|
217
48
|
await worker.terminate();
|
|
218
49
|
```
|
|
219
50
|
|
|
220
|
-
|
|
221
|
-
- `.ts` 파일은 tsx를 통해 자동 실행 (개발 환경), `.js` 파일은 직접 Worker 생성 (프로덕션)
|
|
222
|
-
- UUID 기반 요청 추적으로 동시 요청 지원
|
|
223
|
-
- Worker 크래시 시 대기 중인 모든 요청 자동 reject
|
|
224
|
-
- Worker 내 `process.stdout.write`는 메인 스레드로 자동 전달
|
|
225
|
-
- `@simplysm/core-common`의 `transfer`를 사용하여 메시지 직렬화
|
|
226
|
-
- `file://` URL 경로와 절대 경로 모두 지원
|
|
227
|
-
|
|
228
|
-
---
|
|
229
|
-
|
|
230
|
-
## API 레퍼런스
|
|
231
|
-
|
|
232
|
-
### fsx (namespace)
|
|
233
|
-
|
|
234
|
-
| 함수 | 시그니처 | 설명 |
|
|
235
|
-
|------|----------|------|
|
|
236
|
-
| `exists` | `(targetPath: string) => Promise<boolean>` | 파일/디렉토리 존재 확인 |
|
|
237
|
-
| `existsSync` | `(targetPath: string) => boolean` | 동기 버전 |
|
|
238
|
-
| `mkdir` | `(targetPath: string) => Promise<void>` | 디렉토리 재귀 생성 |
|
|
239
|
-
| `mkdirSync` | `(targetPath: string) => void` | 동기 버전 |
|
|
240
|
-
| `rm` | `(targetPath: string) => Promise<void>` | 삭제 (6회 재시도, 500ms 간격) |
|
|
241
|
-
| `rmSync` | `(targetPath: string) => void` | 동기 버전 (재시도 없음) |
|
|
242
|
-
| `copy` | `(src, dst, filter?) => Promise<void>` | 파일/디렉토리 복사 (async 시 병렬 처리) |
|
|
243
|
-
| `copySync` | `(src, dst, filter?) => void` | 동기 버전 |
|
|
244
|
-
| `read` | `(targetPath: string) => Promise<string>` | UTF-8 텍스트 읽기 |
|
|
245
|
-
| `readSync` | `(targetPath: string) => string` | 동기 버전 |
|
|
246
|
-
| `readBuffer` | `(targetPath: string) => Promise<Buffer>` | 바이너리 읽기 |
|
|
247
|
-
| `readBufferSync` | `(targetPath: string) => Buffer` | 동기 버전 |
|
|
248
|
-
| `readJson` | `<T>(targetPath: string) => Promise<T>` | JSON 파일 읽기 |
|
|
249
|
-
| `readJsonSync` | `<T>(targetPath: string) => T` | 동기 버전 |
|
|
250
|
-
| `write` | `(targetPath, data: string \| Uint8Array) => Promise<void>` | 파일 쓰기 (부모 디렉토리 자동 생성) |
|
|
251
|
-
| `writeSync` | `(targetPath, data: string \| Uint8Array) => void` | 동기 버전 |
|
|
252
|
-
| `writeJson` | `(targetPath, data, options?) => Promise<void>` | JSON 파일 쓰기 |
|
|
253
|
-
| `writeJsonSync` | `(targetPath, data, options?) => void` | 동기 버전 |
|
|
254
|
-
| `readdir` | `(targetPath: string) => Promise<string[]>` | 디렉토리 내용 읽기 |
|
|
255
|
-
| `readdirSync` | `(targetPath: string) => string[]` | 동기 버전 |
|
|
256
|
-
| `stat` | `(targetPath: string) => Promise<fs.Stats>` | 파일 정보 (심링크 따라감) |
|
|
257
|
-
| `statSync` | `(targetPath: string) => fs.Stats` | 동기 버전 |
|
|
258
|
-
| `lstat` | `(targetPath: string) => Promise<fs.Stats>` | 파일 정보 (심링크 자체) |
|
|
259
|
-
| `lstatSync` | `(targetPath: string) => fs.Stats` | 동기 버전 |
|
|
260
|
-
| `glob` | `(pattern, options?: GlobOptions) => Promise<string[]>` | Glob 패턴 검색 (절대 경로 반환) |
|
|
261
|
-
| `globSync` | `(pattern, options?: GlobOptions) => string[]` | 동기 버전 |
|
|
262
|
-
| `clearEmptyDirectory` | `(dirPath: string) => Promise<void>` | 빈 디렉토리 재귀 삭제 |
|
|
263
|
-
| `findAllParentChildPaths` | `(childGlob, fromPath, rootPath?) => Promise<string[]>` | 상위 디렉토리 탐색 |
|
|
264
|
-
| `findAllParentChildPathsSync` | `(childGlob, fromPath, rootPath?) => string[]` | 동기 버전 |
|
|
265
|
-
|
|
266
|
-
### pathx (namespace)
|
|
267
|
-
|
|
268
|
-
| 함수 | 시그니처 | 설명 |
|
|
269
|
-
|------|----------|------|
|
|
270
|
-
| `posix` | `(...args: string[]) => string` | POSIX 경로 변환 (path.join 후 `\` -> `/`) |
|
|
271
|
-
| `norm` | `(...paths: string[]) => NormPath` | 절대 경로 정규화 (브랜드 타입) |
|
|
272
|
-
| `changeFileDirectory` | `(filePath, fromDir, toDir) => string` | 파일의 기준 디렉토리 변경 |
|
|
273
|
-
| `basenameWithoutExt` | `(filePath: string) => string` | 확장자 제외한 파일명 |
|
|
274
|
-
| `isChildPath` | `(childPath, parentPath) => boolean` | 자식 경로 여부 확인 |
|
|
275
|
-
| `filterByTargets` | `(files, targets, cwd) => string[]` | 대상 경로 기준 파일 필터링 |
|
|
276
|
-
|
|
277
|
-
### FsWatcher (class)
|
|
278
|
-
|
|
279
|
-
| 멤버 | 시그니처 | 설명 |
|
|
280
|
-
|------|----------|------|
|
|
281
|
-
| `static watch` | `(paths: string[], options?: ChokidarOptions) => Promise<FsWatcher>` | 감시 시작 (ready까지 대기) |
|
|
282
|
-
| `onChange` | `(opt: { delay?: number }, cb) => this` | 변경 이벤트 핸들러 등록 (체이닝 가능) |
|
|
283
|
-
| `close` | `() => Promise<void>` | 감시 종료 |
|
|
284
|
-
|
|
285
|
-
### Worker (object)
|
|
286
|
-
|
|
287
|
-
| 멤버 | 시그니처 | 설명 |
|
|
288
|
-
|------|----------|------|
|
|
289
|
-
| `create` | `<TModule>(filePath, opt?) => WorkerProxy<TModule>` | 타입 안전한 Worker 프록시 생성 |
|
|
290
|
-
|
|
291
|
-
### createWorker (function)
|
|
292
|
-
|
|
293
|
-
```typescript
|
|
294
|
-
function createWorker<
|
|
295
|
-
TMethods extends Record<string, (...args: any[]) => unknown>,
|
|
296
|
-
TEvents extends Record<string, unknown> = Record<string, never>,
|
|
297
|
-
>(methods: TMethods): {
|
|
298
|
-
send<K extends keyof TEvents & string>(event: K, data?: TEvents[K]): void;
|
|
299
|
-
__methods: TMethods;
|
|
300
|
-
__events: TEvents;
|
|
301
|
-
}
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
### 타입
|
|
51
|
+
## Documentation
|
|
305
52
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
| `FsWatcherChangeInfo` | `{ event: FsWatcherEvent; path: NormPath }` |
|
|
311
|
-
| `WorkerModule` | Worker 모듈 타입 구조 (타입 추론용) |
|
|
312
|
-
| `WorkerProxy<TModule>` | Worker 프록시 타입 (메서드 + `on`/`off`/`terminate`) |
|
|
313
|
-
| `PromisifyMethods<T>` | 메서드 반환값을 Promise로 래핑하는 매핑 타입 |
|
|
314
|
-
| `WorkerRequest` | 내부 Worker 요청 메시지 타입 |
|
|
315
|
-
| `WorkerResponse` | 내부 Worker 응답 메시지 타입 (return/error/event/log) |
|
|
53
|
+
- [File System Utilities](docs/fs.md)
|
|
54
|
+
- [Path Utilities](docs/path.md)
|
|
55
|
+
- [Features (FsWatcher)](docs/features.md)
|
|
56
|
+
- [Worker](docs/worker.md)
|
package/docs/features.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Features
|
|
2
|
+
|
|
3
|
+
## FsWatcher
|
|
4
|
+
|
|
5
|
+
Chokidar-based file system watcher wrapper. Merges events that occur within a short time and calls the callback once.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { FsWatcher } from "@simplysm/core-node";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Types
|
|
12
|
+
|
|
13
|
+
#### `FsWatcherEvent`
|
|
14
|
+
|
|
15
|
+
File change event type.
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
type FsWatcherEvent = "add" | "addDir" | "change" | "unlink" | "unlinkDir";
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
#### `FsWatcherChangeInfo`
|
|
22
|
+
|
|
23
|
+
File change information.
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
interface FsWatcherChangeInfo {
|
|
27
|
+
/** Change event type */
|
|
28
|
+
event: FsWatcherEvent;
|
|
29
|
+
/** Changed file/directory path (normalized) */
|
|
30
|
+
path: NormPath;
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Class: `FsWatcher`
|
|
35
|
+
|
|
36
|
+
The `ignoreInitial` option of chokidar is internally always set to `true`. If you pass `options.ignoreInitial: false`, the callback will be called with an empty array on the first `onChange` call, but the actual initial file list is not included. This is intentional behavior to prevent conflicts with the event merging logic.
|
|
37
|
+
|
|
38
|
+
#### `FsWatcher.watch`
|
|
39
|
+
|
|
40
|
+
Starts watching files (asynchronous). Waits until the ready event is emitted.
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
static async watch(paths: string[], options?: chokidar.ChokidarOptions): Promise<FsWatcher>;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Parameters:**
|
|
47
|
+
- `paths` -- Array of file/directory paths or glob patterns to watch
|
|
48
|
+
- `options` -- chokidar options
|
|
49
|
+
|
|
50
|
+
#### `onChange`
|
|
51
|
+
|
|
52
|
+
Registers a file change event handler. Collects events for the specified delay time and calls the callback once.
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
onChange(
|
|
56
|
+
opt: { delay?: number },
|
|
57
|
+
cb: (changeInfos: FsWatcherChangeInfo[]) => void | Promise<void>,
|
|
58
|
+
): this;
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Parameters:**
|
|
62
|
+
- `opt.delay` -- Event merge wait time (ms)
|
|
63
|
+
- `cb` -- Change event callback
|
|
64
|
+
|
|
65
|
+
Event merging strategy:
|
|
66
|
+
- `add` + `change` -> `add` (modification immediately after creation is considered as creation)
|
|
67
|
+
- `add` + `unlink` -> no change (immediate deletion after creation is considered as no change)
|
|
68
|
+
- `unlink` + `add` -> `add` (recreation after deletion is considered as creation)
|
|
69
|
+
- Otherwise -> overwrite with latest event
|
|
70
|
+
|
|
71
|
+
#### `close`
|
|
72
|
+
|
|
73
|
+
Closes the file watcher.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
async close(): Promise<void>;
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Example
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const watcher = await FsWatcher.watch(["src/**/*.ts"]);
|
|
83
|
+
watcher.onChange({ delay: 300 }, (changes) => {
|
|
84
|
+
for (const { path, event } of changes) {
|
|
85
|
+
console.log(`${event}: ${path}`);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Close
|
|
90
|
+
await watcher.close();
|
|
91
|
+
```
|
package/docs/fs.md
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# File System Utilities
|
|
2
|
+
|
|
3
|
+
File system utilities exported as the `fsx` namespace.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { fsx } from "@simplysm/core-node";
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Existence Check
|
|
10
|
+
|
|
11
|
+
### `existsSync`
|
|
12
|
+
|
|
13
|
+
Checks if a file or directory exists (synchronous).
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
function existsSync(targetPath: string): boolean;
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### `exists`
|
|
20
|
+
|
|
21
|
+
Checks if a file or directory exists (asynchronous).
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
function exists(targetPath: string): Promise<boolean>;
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Create Directory
|
|
28
|
+
|
|
29
|
+
### `mkdirSync`
|
|
30
|
+
|
|
31
|
+
Creates a directory (recursive).
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
function mkdirSync(targetPath: string): void;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### `mkdir`
|
|
38
|
+
|
|
39
|
+
Creates a directory (recursive, asynchronous).
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
function mkdir(targetPath: string): Promise<void>;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Delete
|
|
46
|
+
|
|
47
|
+
### `rmSync`
|
|
48
|
+
|
|
49
|
+
Deletes a file or directory.
|
|
50
|
+
|
|
51
|
+
The synchronous version fails immediately without retries. Use `rm` for cases with potential transient errors like file locks.
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
function rmSync(targetPath: string): void;
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### `rm`
|
|
58
|
+
|
|
59
|
+
Deletes a file or directory (asynchronous).
|
|
60
|
+
|
|
61
|
+
The asynchronous version retries up to 6 times (500ms interval) for transient errors like file locks.
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
function rm(targetPath: string): Promise<void>;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Copy
|
|
68
|
+
|
|
69
|
+
### `copySync`
|
|
70
|
+
|
|
71
|
+
Copies a file or directory.
|
|
72
|
+
|
|
73
|
+
If `sourcePath` does not exist, no action is performed and the function returns.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
function copySync(
|
|
77
|
+
sourcePath: string,
|
|
78
|
+
targetPath: string,
|
|
79
|
+
filter?: (absolutePath: string) => boolean,
|
|
80
|
+
): void;
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Parameters:**
|
|
84
|
+
- `sourcePath` -- Path of the source to copy
|
|
85
|
+
- `targetPath` -- Destination path for the copy
|
|
86
|
+
- `filter` -- A filter function that determines whether to copy. The **absolute path** of each file/directory is passed. Returns `true` to copy, `false` to exclude. The top-level `sourcePath` is not subject to filtering; the filter function is applied recursively to all children. Returning `false` for a directory skips that directory and all its contents.
|
|
87
|
+
|
|
88
|
+
### `copy`
|
|
89
|
+
|
|
90
|
+
Copies a file or directory (asynchronous). Same behavior as `copySync`.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
function copy(
|
|
94
|
+
sourcePath: string,
|
|
95
|
+
targetPath: string,
|
|
96
|
+
filter?: (absolutePath: string) => boolean,
|
|
97
|
+
): Promise<void>;
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Read File
|
|
101
|
+
|
|
102
|
+
### `readSync`
|
|
103
|
+
|
|
104
|
+
Reads a file as a UTF-8 string.
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
function readSync(targetPath: string): string;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### `read`
|
|
111
|
+
|
|
112
|
+
Reads a file as a UTF-8 string (asynchronous).
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
function read(targetPath: string): Promise<string>;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### `readBufferSync`
|
|
119
|
+
|
|
120
|
+
Reads a file as a Buffer.
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
function readBufferSync(targetPath: string): Buffer;
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### `readBuffer`
|
|
127
|
+
|
|
128
|
+
Reads a file as a Buffer (asynchronous).
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
function readBuffer(targetPath: string): Promise<Buffer>;
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### `readJsonSync`
|
|
135
|
+
|
|
136
|
+
Reads a JSON file (using JsonConvert).
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
function readJsonSync<TData = unknown>(targetPath: string): TData;
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### `readJson`
|
|
143
|
+
|
|
144
|
+
Reads a JSON file (using JsonConvert, asynchronous).
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
function readJson<TData = unknown>(targetPath: string): Promise<TData>;
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Write File
|
|
151
|
+
|
|
152
|
+
### `writeSync`
|
|
153
|
+
|
|
154
|
+
Writes data to a file (auto-creates parent directories).
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
function writeSync(targetPath: string, data: string | Uint8Array): void;
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### `write`
|
|
161
|
+
|
|
162
|
+
Writes data to a file (auto-creates parent directories, asynchronous).
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
function write(targetPath: string, data: string | Uint8Array): Promise<void>;
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### `writeJsonSync`
|
|
169
|
+
|
|
170
|
+
Writes data to a JSON file (using JsonConvert).
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
function writeJsonSync(
|
|
174
|
+
targetPath: string,
|
|
175
|
+
data: unknown,
|
|
176
|
+
options?: {
|
|
177
|
+
replacer?: (this: unknown, key: string | undefined, value: unknown) => unknown;
|
|
178
|
+
space?: string | number;
|
|
179
|
+
},
|
|
180
|
+
): void;
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### `writeJson`
|
|
184
|
+
|
|
185
|
+
Writes data to a JSON file (using JsonConvert, asynchronous).
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
function writeJson(
|
|
189
|
+
targetPath: string,
|
|
190
|
+
data: unknown,
|
|
191
|
+
options?: {
|
|
192
|
+
replacer?: (this: unknown, key: string | undefined, value: unknown) => unknown;
|
|
193
|
+
space?: string | number;
|
|
194
|
+
},
|
|
195
|
+
): Promise<void>;
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Read Directory
|
|
199
|
+
|
|
200
|
+
### `readdirSync`
|
|
201
|
+
|
|
202
|
+
Reads the contents of a directory.
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
function readdirSync(targetPath: string): string[];
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### `readdir`
|
|
209
|
+
|
|
210
|
+
Reads the contents of a directory (asynchronous).
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
function readdir(targetPath: string): Promise<string[]>;
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## File Information
|
|
217
|
+
|
|
218
|
+
### `statSync`
|
|
219
|
+
|
|
220
|
+
Gets file/directory information (follows symbolic links).
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
function statSync(targetPath: string): fs.Stats;
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### `stat`
|
|
227
|
+
|
|
228
|
+
Gets file/directory information (follows symbolic links, asynchronous).
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
function stat(targetPath: string): Promise<fs.Stats>;
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### `lstatSync`
|
|
235
|
+
|
|
236
|
+
Gets file/directory information (does not follow symbolic links).
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
function lstatSync(targetPath: string): fs.Stats;
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### `lstat`
|
|
243
|
+
|
|
244
|
+
Gets file/directory information (does not follow symbolic links, asynchronous).
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
function lstat(targetPath: string): Promise<fs.Stats>;
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Glob
|
|
251
|
+
|
|
252
|
+
### `globSync`
|
|
253
|
+
|
|
254
|
+
Searches for files using a glob pattern.
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
function globSync(pattern: string, options?: GlobOptions): string[];
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Returns an array of absolute paths for matched files.
|
|
261
|
+
|
|
262
|
+
### `glob`
|
|
263
|
+
|
|
264
|
+
Searches for files using a glob pattern (asynchronous).
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
function glob(pattern: string, options?: GlobOptions): Promise<string[]>;
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Returns an array of absolute paths for matched files.
|
|
271
|
+
|
|
272
|
+
## Utilities
|
|
273
|
+
|
|
274
|
+
### `clearEmptyDirectory`
|
|
275
|
+
|
|
276
|
+
Recursively searches and deletes empty directories under a specified directory. If all child directories are deleted and a parent becomes empty, it will also be deleted.
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
function clearEmptyDirectory(dirPath: string): Promise<void>;
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### `findAllParentChildPathsSync`
|
|
283
|
+
|
|
284
|
+
Searches for files matching a glob pattern by traversing parent directories from a start path towards the root. Collects all file paths matching the `childGlob` pattern in each directory.
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
function findAllParentChildPathsSync(
|
|
288
|
+
childGlob: string,
|
|
289
|
+
fromPath: string,
|
|
290
|
+
rootPath?: string,
|
|
291
|
+
): string[];
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**Parameters:**
|
|
295
|
+
- `childGlob` -- Glob pattern to search for in each directory
|
|
296
|
+
- `fromPath` -- Path to start searching from
|
|
297
|
+
- `rootPath` -- Path to stop searching at (if not specified, searches to filesystem root). `fromPath` must be a child path of `rootPath`. Otherwise, searches to the filesystem root.
|
|
298
|
+
|
|
299
|
+
### `findAllParentChildPaths`
|
|
300
|
+
|
|
301
|
+
Asynchronous version of `findAllParentChildPathsSync`.
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
function findAllParentChildPaths(
|
|
305
|
+
childGlob: string,
|
|
306
|
+
fromPath: string,
|
|
307
|
+
rootPath?: string,
|
|
308
|
+
): Promise<string[]>;
|
|
309
|
+
```
|
package/docs/path.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Path Utilities
|
|
2
|
+
|
|
3
|
+
Path utilities exported as the `pathx` namespace.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { pathx } from "@simplysm/core-node";
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Types
|
|
10
|
+
|
|
11
|
+
### `NormPath`
|
|
12
|
+
|
|
13
|
+
Brand type representing a normalized path. Can only be created through `norm()`.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
type NormPath = string & { [NORM]: never };
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Functions
|
|
20
|
+
|
|
21
|
+
### `posix`
|
|
22
|
+
|
|
23
|
+
Converts to POSIX-style path (backslash to forward slash).
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
function posix(...args: string[]): string;
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Examples:**
|
|
30
|
+
```typescript
|
|
31
|
+
posix("C:\\Users\\test"); // "C:/Users/test"
|
|
32
|
+
posix("src", "index.ts"); // "src/index.ts"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### `changeFileDirectory`
|
|
36
|
+
|
|
37
|
+
Changes the directory of a file path.
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
function changeFileDirectory(
|
|
41
|
+
filePath: string,
|
|
42
|
+
fromDirectory: string,
|
|
43
|
+
toDirectory: string,
|
|
44
|
+
): string;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Throws an error if the file is not inside `fromDirectory`.
|
|
48
|
+
|
|
49
|
+
**Example:**
|
|
50
|
+
```typescript
|
|
51
|
+
changeFileDirectory("/a/b/c.txt", "/a", "/x");
|
|
52
|
+
// "/x/b/c.txt"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### `basenameWithoutExt`
|
|
56
|
+
|
|
57
|
+
Returns the filename (basename) without extension.
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
function basenameWithoutExt(filePath: string): string;
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Examples:**
|
|
64
|
+
```typescript
|
|
65
|
+
basenameWithoutExt("file.txt"); // "file"
|
|
66
|
+
basenameWithoutExt("/path/to/file.spec.ts"); // "file.spec"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### `isChildPath`
|
|
70
|
+
|
|
71
|
+
Checks if `childPath` is a child path of `parentPath`. Returns `false` if the paths are the same.
|
|
72
|
+
|
|
73
|
+
Paths are internally normalized using `norm()` and compared using platform-specific path separators.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
function isChildPath(childPath: string, parentPath: string): boolean;
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Examples:**
|
|
80
|
+
```typescript
|
|
81
|
+
isChildPath("/a/b/c", "/a/b"); // true
|
|
82
|
+
isChildPath("/a/b", "/a/b/c"); // false
|
|
83
|
+
isChildPath("/a/b", "/a/b"); // false (same path)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `norm`
|
|
87
|
+
|
|
88
|
+
Normalizes the path and returns it as `NormPath`. Converts to absolute path and normalizes using platform-specific separators.
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
function norm(...paths: string[]): NormPath;
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Examples:**
|
|
95
|
+
```typescript
|
|
96
|
+
norm("/some/path"); // NormPath
|
|
97
|
+
norm("relative", "path"); // NormPath (converted to absolute path)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `filterByTargets`
|
|
101
|
+
|
|
102
|
+
Filters files based on a list of target paths. Includes files that match or are children of a target path.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
function filterByTargets(files: string[], targets: string[], cwd: string): string[];
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Parameters:**
|
|
109
|
+
- `files` -- File paths to filter. Must be absolute paths under `cwd`.
|
|
110
|
+
- `targets` -- Target paths (relative to `cwd`, POSIX style recommended)
|
|
111
|
+
- `cwd` -- Current working directory (absolute path)
|
|
112
|
+
|
|
113
|
+
If `targets` is empty, returns `files` as-is; otherwise returns only files under target paths.
|
|
114
|
+
|
|
115
|
+
**Example:**
|
|
116
|
+
```typescript
|
|
117
|
+
const files = ["/proj/src/a.ts", "/proj/src/b.ts", "/proj/tests/c.ts"];
|
|
118
|
+
filterByTargets(files, ["src"], "/proj");
|
|
119
|
+
// ["/proj/src/a.ts", "/proj/src/b.ts"]
|
|
120
|
+
```
|
package/docs/worker.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Worker
|
|
2
|
+
|
|
3
|
+
Type-safe `worker_threads` wrapper providing a proxy-based RPC interface for worker threads.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { Worker, createWorker } from "@simplysm/core-node";
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Types
|
|
10
|
+
|
|
11
|
+
### `WorkerModule`
|
|
12
|
+
|
|
13
|
+
Type structure of the worker module returned by `createWorker()`. Used for type inference in `Worker.create<typeof import("./worker")>()`.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
interface WorkerModule {
|
|
17
|
+
default: {
|
|
18
|
+
__methods: Record<string, (...args: any[]) => unknown>;
|
|
19
|
+
__events: Record<string, unknown>;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### `PromisifyMethods<TMethods>`
|
|
25
|
+
|
|
26
|
+
Mapping type that wraps method return values in `Promise`. Worker methods operate based on `postMessage` and are always asynchronous, so synchronous method types are also converted to `Promise<Awaited<R>>`.
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
type PromisifyMethods<TMethods> = {
|
|
30
|
+
[K in keyof TMethods]: TMethods[K] extends (...args: infer P) => infer R
|
|
31
|
+
? (...args: P) => Promise<Awaited<R>>
|
|
32
|
+
: never;
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### `WorkerProxy<TModule>`
|
|
37
|
+
|
|
38
|
+
Proxy type returned by `Worker.create()`. Provides promisified methods + `on()` + `off()` + `terminate()`.
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
type WorkerProxy<TModule extends WorkerModule> = PromisifyMethods<
|
|
42
|
+
TModule["default"]["__methods"]
|
|
43
|
+
> & {
|
|
44
|
+
/** Registers a worker event listener. */
|
|
45
|
+
on<TEventName extends keyof TModule["default"]["__events"] & string>(
|
|
46
|
+
event: TEventName,
|
|
47
|
+
listener: (data: TModule["default"]["__events"][TEventName]) => void,
|
|
48
|
+
): void;
|
|
49
|
+
|
|
50
|
+
/** Unregisters a worker event listener. */
|
|
51
|
+
off<TEventName extends keyof TModule["default"]["__events"] & string>(
|
|
52
|
+
event: TEventName,
|
|
53
|
+
listener: (data: TModule["default"]["__events"][TEventName]) => void,
|
|
54
|
+
): void;
|
|
55
|
+
|
|
56
|
+
/** Terminates the worker. */
|
|
57
|
+
terminate(): Promise<void>;
|
|
58
|
+
};
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### `WorkerRequest`
|
|
62
|
+
|
|
63
|
+
Internal worker request message.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
interface WorkerRequest {
|
|
67
|
+
id: string;
|
|
68
|
+
method: string;
|
|
69
|
+
params: unknown[];
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### `WorkerResponse`
|
|
74
|
+
|
|
75
|
+
Internal worker response message.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
type WorkerResponse =
|
|
79
|
+
| { request: WorkerRequest; type: "return"; body?: unknown }
|
|
80
|
+
| { request: WorkerRequest; type: "error"; body: Error }
|
|
81
|
+
| { type: "event"; event: string; body?: unknown }
|
|
82
|
+
| { type: "log"; body: string };
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## `Worker.create`
|
|
86
|
+
|
|
87
|
+
Creates a type-safe Worker Proxy.
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
const Worker = {
|
|
91
|
+
create<TModule extends WorkerModule>(
|
|
92
|
+
filePath: string,
|
|
93
|
+
opt?: Omit<WorkerOptions, "stdout" | "stderr">,
|
|
94
|
+
): WorkerProxy<TModule>;
|
|
95
|
+
};
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Parameters:**
|
|
99
|
+
- `filePath` -- Worker file path (file:// URL or absolute path)
|
|
100
|
+
- `opt` -- Worker options
|
|
101
|
+
|
|
102
|
+
**Returns:** Proxy object (supports direct method calls, `on()`, `off()`, and `terminate()`)
|
|
103
|
+
|
|
104
|
+
In development (`.ts` files), TypeScript worker files are executed via tsx. In production (`.js` files), Worker is created directly.
|
|
105
|
+
|
|
106
|
+
## `createWorker`
|
|
107
|
+
|
|
108
|
+
Worker factory for use in worker threads. This is the function called inside the worker file.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
function createWorker<
|
|
112
|
+
TMethods extends Record<string, (...args: any[]) => unknown>,
|
|
113
|
+
TEvents extends Record<string, unknown> = Record<string, never>,
|
|
114
|
+
>(
|
|
115
|
+
methods: TMethods,
|
|
116
|
+
): {
|
|
117
|
+
send<TEventName extends keyof TEvents & string>(event: TEventName, data?: TEvents[TEventName]): void;
|
|
118
|
+
__methods: TMethods;
|
|
119
|
+
__events: TEvents;
|
|
120
|
+
};
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Example
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
// worker.ts
|
|
127
|
+
import { createWorker } from "@simplysm/core-node";
|
|
128
|
+
|
|
129
|
+
export default createWorker({
|
|
130
|
+
add: (a: number, b: number) => a + b,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// main.ts
|
|
134
|
+
import { Worker } from "@simplysm/core-node";
|
|
135
|
+
|
|
136
|
+
const worker = Worker.create<typeof import("./worker")>("./worker.ts");
|
|
137
|
+
const result = await worker.add(10, 20); // 30
|
|
138
|
+
await worker.terminate();
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Worker with Events
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// worker.ts
|
|
145
|
+
import { createWorker } from "@simplysm/core-node";
|
|
146
|
+
|
|
147
|
+
interface MyEvents {
|
|
148
|
+
progress: number;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const methods = {
|
|
152
|
+
calc: (x: number) => {
|
|
153
|
+
sender.send("progress", 50);
|
|
154
|
+
return x * 2;
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const sender = createWorker<typeof methods, MyEvents>(methods);
|
|
159
|
+
export default sender;
|
|
160
|
+
|
|
161
|
+
// main.ts
|
|
162
|
+
const worker = Worker.create<typeof import("./worker")>("./worker.ts");
|
|
163
|
+
worker.on("progress", (value) => {
|
|
164
|
+
console.log(`Progress: ${value}%`);
|
|
165
|
+
});
|
|
166
|
+
const result = await worker.calc(5); // 10
|
|
167
|
+
await worker.terminate();
|
|
168
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/core-node",
|
|
3
|
-
"version": "13.0.
|
|
3
|
+
"version": "13.0.98",
|
|
4
4
|
"description": "Simplysm package - Core module (node)",
|
|
5
5
|
"author": "simplysm",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -25,6 +25,6 @@
|
|
|
25
25
|
"glob": "^13.0.6",
|
|
26
26
|
"minimatch": "^10.2.4",
|
|
27
27
|
"tsx": "^4.21.0",
|
|
28
|
-
"@simplysm/core-common": "13.0.
|
|
28
|
+
"@simplysm/core-common": "13.0.98"
|
|
29
29
|
}
|
|
30
30
|
}
|