@simplysm/core-node 13.0.100 → 14.0.4
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 +93 -79
- package/dist/features/fs-watcher.d.ts +21 -21
- package/dist/features/fs-watcher.d.ts.map +1 -1
- package/dist/features/fs-watcher.js +176 -114
- package/dist/features/fs-watcher.js.map +1 -6
- package/dist/index.js +6 -7
- package/dist/index.js.map +1 -6
- package/dist/utils/fs.d.ts +96 -96
- package/dist/utils/fs.d.ts.map +1 -1
- package/dist/utils/fs.js +437 -272
- package/dist/utils/fs.js.map +1 -6
- package/dist/utils/path.d.ts +22 -22
- package/dist/utils/path.js +103 -45
- package/dist/utils/path.js.map +1 -6
- package/dist/worker/create-worker.d.ts +3 -3
- package/dist/worker/create-worker.js +106 -81
- package/dist/worker/create-worker.js.map +1 -6
- package/dist/worker/types.d.ts +14 -14
- package/dist/worker/types.js +4 -1
- package/dist/worker/types.js.map +1 -6
- package/dist/worker/worker.d.ts +5 -5
- package/dist/worker/worker.js +168 -132
- package/dist/worker/worker.js.map +1 -6
- package/docs/fs-watcher.md +107 -0
- package/docs/fsx.md +287 -0
- package/docs/pathx.md +115 -0
- package/docs/worker.md +117 -62
- package/lib/worker-dev-proxy.js +15 -0
- package/package.json +9 -6
- package/src/features/fs-watcher.ts +53 -42
- package/src/index.ts +3 -3
- package/src/utils/fs.ts +111 -120
- package/src/utils/path.ts +26 -26
- package/src/worker/create-worker.ts +10 -10
- package/src/worker/types.ts +14 -14
- package/src/worker/worker.ts +29 -29
- package/docs/features.md +0 -91
- package/docs/fs.md +0 -309
- package/docs/path.md +0 -120
- package/tests/utils/fs-watcher.spec.ts +0 -286
- package/tests/utils/fs.spec.ts +0 -705
- package/tests/utils/path.spec.ts +0 -179
- package/tests/worker/fixtures/test-worker.ts +0 -35
- package/tests/worker/sd-worker.spec.ts +0 -174
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/core-node",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"author": "
|
|
3
|
+
"version": "14.0.4",
|
|
4
|
+
"description": "심플리즘 패키지 - 코어 (node)",
|
|
5
|
+
"author": "심플리즘",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
|
-
"docs",
|
|
18
17
|
"src",
|
|
19
|
-
"
|
|
18
|
+
"lib",
|
|
19
|
+
"docs"
|
|
20
20
|
],
|
|
21
21
|
"sideEffects": false,
|
|
22
22
|
"dependencies": {
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
"glob": "^13.0.6",
|
|
26
26
|
"minimatch": "^10.2.4",
|
|
27
27
|
"tsx": "^4.21.0",
|
|
28
|
-
"@simplysm/core-common": "
|
|
28
|
+
"@simplysm/core-common": "14.0.4"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^20.19.37"
|
|
29
32
|
}
|
|
30
33
|
}
|
|
@@ -8,11 +8,11 @@ import { type NormPath, norm } from "../utils/path";
|
|
|
8
8
|
|
|
9
9
|
//#region Helpers
|
|
10
10
|
|
|
11
|
-
/** Glob
|
|
11
|
+
/** Glob 메타문자 패턴 */
|
|
12
12
|
const GLOB_CHARS_RE = /[*?{[\]]/;
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Glob 패턴에서 기본 디렉토리를 추출한다.
|
|
16
16
|
* @example extractGlobBase("/home/user/src/**\/*.ts") → "/home/user/src"
|
|
17
17
|
*/
|
|
18
18
|
function extractGlobBase(globPath: string): string {
|
|
@@ -30,22 +30,22 @@ function extractGlobBase(globPath: string): string {
|
|
|
30
30
|
//#region Types
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* 지원되는 파일 변경 이벤트 타입 목록.
|
|
34
34
|
*/
|
|
35
35
|
const FS_WATCHER_EVENTS = ["add", "addDir", "change", "unlink", "unlinkDir"] as const;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
38
|
+
* 파일 변경 이벤트 타입.
|
|
39
39
|
*/
|
|
40
40
|
export type FsWatcherEvent = (typeof FS_WATCHER_EVENTS)[number];
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
43
|
+
* 파일 변경 정보.
|
|
44
44
|
*/
|
|
45
45
|
export interface FsWatcherChangeInfo {
|
|
46
|
-
/**
|
|
46
|
+
/** 변경 이벤트 타입 */
|
|
47
47
|
event: FsWatcherEvent;
|
|
48
|
-
/**
|
|
48
|
+
/** 변경된 파일/디렉토리 경로 (정규화됨) */
|
|
49
49
|
path: NormPath;
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -54,13 +54,13 @@ export interface FsWatcherChangeInfo {
|
|
|
54
54
|
//#region FsWatcher
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
* Chokidar
|
|
58
|
-
*
|
|
57
|
+
* Chokidar 기반 파일 시스템 감시 래퍼.
|
|
58
|
+
* 짧은 시간 내에 발생하는 이벤트를 병합하여 콜백을 한 번만 호출한다.
|
|
59
59
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
60
|
+
* **주의**: chokidar의 `ignoreInitial` 옵션은 내부적으로 항상 `true`로 설정된다.
|
|
61
|
+
* `options.ignoreInitial: false`를 전달하면 첫 번째 `onChange` 호출 시 빈 배열로 콜백이 호출되지만,
|
|
62
|
+
* 실제 초기 파일 목록은 포함되지 않는다.
|
|
63
|
+
* 이는 이벤트 병합 로직과의 충돌을 방지하기 위한 의도적인 동작이다.
|
|
64
64
|
*
|
|
65
65
|
* @example
|
|
66
66
|
* const watcher = await FsWatcher.watch(["src/**\/*.ts"]);
|
|
@@ -70,24 +70,35 @@ export interface FsWatcherChangeInfo {
|
|
|
70
70
|
* }
|
|
71
71
|
* });
|
|
72
72
|
*
|
|
73
|
-
* //
|
|
73
|
+
* // 종료
|
|
74
74
|
* await watcher.close();
|
|
75
75
|
*/
|
|
76
76
|
export class FsWatcher {
|
|
77
77
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
78
|
+
* 파일 감시를 시작한다 (비동기).
|
|
79
|
+
* ready 이벤트가 발생할 때까지 대기한다.
|
|
80
80
|
*
|
|
81
|
-
* @param paths -
|
|
82
|
-
* @param options - chokidar
|
|
81
|
+
* @param paths - 감시할 파일/디렉토리 경로 또는 glob 패턴 배열
|
|
82
|
+
* @param options - chokidar 옵션
|
|
83
83
|
*/
|
|
84
84
|
static async watch(paths: string[], options?: chokidar.ChokidarOptions): Promise<FsWatcher> {
|
|
85
85
|
return new Promise<FsWatcher>((resolve, reject) => {
|
|
86
86
|
const watcher = new FsWatcher(paths, options);
|
|
87
|
-
|
|
87
|
+
|
|
88
|
+
const onReady = () => {
|
|
89
|
+
watcher._watcher.removeListener("error", onError);
|
|
88
90
|
resolve(watcher);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
+
};
|
|
92
|
+
const onError = (err: unknown) => {
|
|
93
|
+
watcher._watcher.removeListener("ready", onReady);
|
|
94
|
+
watcher.close().then(
|
|
95
|
+
() => reject(err),
|
|
96
|
+
() => reject(err),
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
watcher._watcher.once("ready", onReady);
|
|
101
|
+
watcher._watcher.once("error", onError);
|
|
91
102
|
});
|
|
92
103
|
}
|
|
93
104
|
|
|
@@ -111,7 +122,7 @@ export class FsWatcher {
|
|
|
111
122
|
}
|
|
112
123
|
}
|
|
113
124
|
|
|
114
|
-
//
|
|
125
|
+
// 중복 경로 제거
|
|
115
126
|
const uniquePaths = [...new Set(watchPaths)];
|
|
116
127
|
|
|
117
128
|
this._watcher = chokidar.watch(uniquePaths, {
|
|
@@ -121,18 +132,18 @@ export class FsWatcher {
|
|
|
121
132
|
});
|
|
122
133
|
this._ignoreInitial = options?.ignoreInitial ?? this._ignoreInitial;
|
|
123
134
|
|
|
124
|
-
//
|
|
135
|
+
// 감시 중 발생하는 오류를 로깅
|
|
125
136
|
this._watcher.on("error", (err) => {
|
|
126
|
-
this._logger.error("FsWatcher
|
|
137
|
+
this._logger.error("FsWatcher 오류:", err);
|
|
127
138
|
});
|
|
128
139
|
}
|
|
129
140
|
|
|
130
141
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
142
|
+
* 파일 변경 이벤트 핸들러를 등록한다.
|
|
143
|
+
* 지정된 지연 시간 동안 이벤트를 수집하여 콜백을 한 번 호출한다.
|
|
133
144
|
*
|
|
134
|
-
* @param opt.delay -
|
|
135
|
-
* @param cb -
|
|
145
|
+
* @param opt.delay - 이벤트 병합 대기 시간 (ms)
|
|
146
|
+
* @param cb - 변경 이벤트 콜백
|
|
136
147
|
*/
|
|
137
148
|
onChange(
|
|
138
149
|
opt: { delay?: number },
|
|
@@ -143,7 +154,7 @@ export class FsWatcher {
|
|
|
143
154
|
|
|
144
155
|
let changeInfoMap = new Map<string, EventName>();
|
|
145
156
|
|
|
146
|
-
//
|
|
157
|
+
// ignoreInitial이 false이면 초기에 빈 배열로 콜백 호출
|
|
147
158
|
if (!this._ignoreInitial) {
|
|
148
159
|
fnQ.run(async () => {
|
|
149
160
|
await cb([]);
|
|
@@ -151,22 +162,22 @@ export class FsWatcher {
|
|
|
151
162
|
}
|
|
152
163
|
|
|
153
164
|
this._watcher.on("all", (event, filePath) => {
|
|
154
|
-
//
|
|
165
|
+
// 지원되는 이벤트만 처리
|
|
155
166
|
if (!FS_WATCHER_EVENTS.includes(event as FsWatcherEvent)) return;
|
|
156
167
|
|
|
157
|
-
//
|
|
168
|
+
// glob matcher가 존재하면 패턴 필터링 적용
|
|
158
169
|
if (this._globMatchers.length > 0) {
|
|
159
170
|
const posixFilePath = filePath.replace(/\\/g, "/");
|
|
160
171
|
if (!this._globMatchers.some((m) => m.match(posixFilePath))) return;
|
|
161
172
|
}
|
|
162
173
|
|
|
163
174
|
/*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* - add + change → add (
|
|
167
|
-
* - add + unlink →
|
|
168
|
-
* - unlink + add → add (
|
|
169
|
-
* -
|
|
175
|
+
* 이벤트 병합 전략:
|
|
176
|
+
* 같은 파일에 대해 짧은 시간 내에 여러 이벤트가 발생하면, 최종 상태만 전달한다.
|
|
177
|
+
* - add + change → add (생성 직후 수정은 생성으로 간주)
|
|
178
|
+
* - add + unlink → 변경 없음 (생성 직후 삭제는 변경 없음으로 간주)
|
|
179
|
+
* - unlink + add → add (삭제 후 재생성은 생성으로 간주)
|
|
180
|
+
* - 그 외 → 최신 이벤트로 덮어쓰기
|
|
170
181
|
*/
|
|
171
182
|
if (!changeInfoMap.has(filePath)) {
|
|
172
183
|
changeInfoMap.set(filePath, event);
|
|
@@ -174,19 +185,19 @@ export class FsWatcher {
|
|
|
174
185
|
const prevEvent = changeInfoMap.get(filePath)!;
|
|
175
186
|
|
|
176
187
|
if (prevEvent === "add" && event === "change") {
|
|
177
|
-
// add
|
|
188
|
+
// add 후 change → add 유지
|
|
178
189
|
changeInfoMap.set(filePath, "add");
|
|
179
190
|
} else if (
|
|
180
191
|
(prevEvent === "add" && event === "unlink") ||
|
|
181
192
|
(prevEvent === "addDir" && event === "unlinkDir")
|
|
182
193
|
) {
|
|
183
|
-
// add
|
|
194
|
+
// add 후 unlink → 변경 없음 (삭제)
|
|
184
195
|
changeInfoMap.delete(filePath);
|
|
185
196
|
} else if (prevEvent === "unlink" && (event === "add" || event === "change")) {
|
|
186
|
-
// unlink
|
|
197
|
+
// unlink 후 add/change → add (파일 재생성)
|
|
187
198
|
changeInfoMap.set(filePath, "add");
|
|
188
199
|
} else if (prevEvent === "unlinkDir" && event === "addDir") {
|
|
189
|
-
// unlinkDir
|
|
200
|
+
// unlinkDir 후 addDir → addDir (디렉토리 재생성)
|
|
190
201
|
changeInfoMap.set(filePath, "addDir");
|
|
191
202
|
} else {
|
|
192
203
|
changeInfoMap.set(filePath, event);
|
|
@@ -213,7 +224,7 @@ export class FsWatcher {
|
|
|
213
224
|
}
|
|
214
225
|
|
|
215
226
|
/**
|
|
216
|
-
*
|
|
227
|
+
* 파일 감시자를 종료한다.
|
|
217
228
|
*/
|
|
218
229
|
async close(): Promise<void> {
|
|
219
230
|
for (const q of this._debounceQueues) {
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
//
|
|
1
|
+
// 유틸리티
|
|
2
2
|
export * as fsx from "./utils/fs";
|
|
3
3
|
export * as pathx from "./utils/path";
|
|
4
4
|
|
|
5
|
-
//
|
|
5
|
+
// 기능
|
|
6
6
|
export * from "./features/fs-watcher";
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// 워커
|
|
9
9
|
export * from "./worker/types";
|
|
10
10
|
export * from "./worker/worker";
|
|
11
11
|
export * from "./worker/create-worker";
|