@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.
Files changed (44) hide show
  1. package/README.md +93 -79
  2. package/dist/features/fs-watcher.d.ts +21 -21
  3. package/dist/features/fs-watcher.d.ts.map +1 -1
  4. package/dist/features/fs-watcher.js +176 -114
  5. package/dist/features/fs-watcher.js.map +1 -6
  6. package/dist/index.js +6 -7
  7. package/dist/index.js.map +1 -6
  8. package/dist/utils/fs.d.ts +96 -96
  9. package/dist/utils/fs.d.ts.map +1 -1
  10. package/dist/utils/fs.js +437 -272
  11. package/dist/utils/fs.js.map +1 -6
  12. package/dist/utils/path.d.ts +22 -22
  13. package/dist/utils/path.js +103 -45
  14. package/dist/utils/path.js.map +1 -6
  15. package/dist/worker/create-worker.d.ts +3 -3
  16. package/dist/worker/create-worker.js +106 -81
  17. package/dist/worker/create-worker.js.map +1 -6
  18. package/dist/worker/types.d.ts +14 -14
  19. package/dist/worker/types.js +4 -1
  20. package/dist/worker/types.js.map +1 -6
  21. package/dist/worker/worker.d.ts +5 -5
  22. package/dist/worker/worker.js +168 -132
  23. package/dist/worker/worker.js.map +1 -6
  24. package/docs/fs-watcher.md +107 -0
  25. package/docs/fsx.md +287 -0
  26. package/docs/pathx.md +115 -0
  27. package/docs/worker.md +117 -62
  28. package/lib/worker-dev-proxy.js +15 -0
  29. package/package.json +9 -6
  30. package/src/features/fs-watcher.ts +53 -42
  31. package/src/index.ts +3 -3
  32. package/src/utils/fs.ts +111 -120
  33. package/src/utils/path.ts +26 -26
  34. package/src/worker/create-worker.ts +10 -10
  35. package/src/worker/types.ts +14 -14
  36. package/src/worker/worker.ts +29 -29
  37. package/docs/features.md +0 -91
  38. package/docs/fs.md +0 -309
  39. package/docs/path.md +0 -120
  40. package/tests/utils/fs-watcher.spec.ts +0 -286
  41. package/tests/utils/fs.spec.ts +0 -705
  42. package/tests/utils/path.spec.ts +0 -179
  43. package/tests/worker/fixtures/test-worker.ts +0 -35
  44. 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": "13.0.100",
4
- "description": "Simplysm package - Core module (node)",
5
- "author": "simplysm",
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
- "tests"
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": "13.0.100"
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 metacharacter pattern */
11
+ /** Glob 메타문자 패턴 */
12
12
  const GLOB_CHARS_RE = /[*?{[\]]/;
13
13
 
14
14
  /**
15
- * Extracts the base directory from a glob pattern.
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
- * List of supported file change event types.
33
+ * 지원되는 파일 변경 이벤트 타입 목록.
34
34
  */
35
35
  const FS_WATCHER_EVENTS = ["add", "addDir", "change", "unlink", "unlinkDir"] as const;
36
36
 
37
37
  /**
38
- * File change event type.
38
+ * 파일 변경 이벤트 타입.
39
39
  */
40
40
  export type FsWatcherEvent = (typeof FS_WATCHER_EVENTS)[number];
41
41
 
42
42
  /**
43
- * File change information.
43
+ * 파일 변경 정보.
44
44
  */
45
45
  export interface FsWatcherChangeInfo {
46
- /** Change event type */
46
+ /** 변경 이벤트 타입 */
47
47
  event: FsWatcherEvent;
48
- /** Changed file/directory path (normalized) */
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-based file system watcher wrapper.
58
- * Merges events that occur within a short time and calls the callback once.
57
+ * Chokidar 기반 파일 시스템 감시 래퍼.
58
+ * 짧은 시간 내에 발생하는 이벤트를 병합하여 콜백을 번만 호출한다.
59
59
  *
60
- * **Note**: The `ignoreInitial` option of chokidar is internally always set to `true`.
61
- * If you pass `options.ignoreInitial: false`, the callback will be called with an empty array on the first `onChange` call,
62
- * but the actual initial file list is not included.
63
- * This is intentional behavior to prevent conflicts with the event merging logic.
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
- * // Close
73
+ * // 종료
74
74
  * await watcher.close();
75
75
  */
76
76
  export class FsWatcher {
77
77
  /**
78
- * Starts watching files (asynchronous).
79
- * Waits until the ready event is emitted.
78
+ * 파일 감시를 시작한다 (비동기).
79
+ * ready 이벤트가 발생할 때까지 대기한다.
80
80
  *
81
- * @param paths - Array of file/directory paths or glob patterns to watch
82
- * @param options - chokidar options
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
- watcher._watcher.on("ready", () => {
87
+
88
+ const onReady = () => {
89
+ watcher._watcher.removeListener("error", onError);
88
90
  resolve(watcher);
89
- });
90
- watcher._watcher.on("error", reject);
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
- // Remove duplicate paths
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
- // Log errors that occur during watching
135
+ // 감시 발생하는 오류를 로깅
125
136
  this._watcher.on("error", (err) => {
126
- this._logger.error("FsWatcher error:", err);
137
+ this._logger.error("FsWatcher 오류:", err);
127
138
  });
128
139
  }
129
140
 
130
141
  /**
131
- * Registers a file change event handler.
132
- * Collects events for the specified delay time and calls the callback once.
142
+ * 파일 변경 이벤트 핸들러를 등록한다.
143
+ * 지정된 지연 시간 동안 이벤트를 수집하여 콜백을 호출한다.
133
144
  *
134
- * @param opt.delay - Event merge wait time (ms)
135
- * @param cb - Change event callback
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
- // If ignoreInitial is false, call callback with empty array initially
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
- // Only process supported events
165
+ // 지원되는 이벤트만 처리
155
166
  if (!FS_WATCHER_EVENTS.includes(event as FsWatcherEvent)) return;
156
167
 
157
- // If glob matchers exist, apply pattern filtering
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
- * Event merging strategy:
165
- * If multiple events occur for the same file within a short time, only the final state is passed.
166
- * - add + change → add (modification immediately after creation is considered as creation)
167
- * - add + unlink → no change (immediate deletion after creation is considered as no change)
168
- * - unlink + add → add (recreation after deletion is considered as creation)
169
- * - otherwiseoverwrite with latest event
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 followed by change → keep 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 followed by unlink → no change (deletion)
194
+ // add unlink → 변경 없음 (삭제)
184
195
  changeInfoMap.delete(filePath);
185
196
  } else if (prevEvent === "unlink" && (event === "add" || event === "change")) {
186
- // unlink followed by add/change → add (file recreation)
197
+ // unlink add/change → add (파일 재생성)
187
198
  changeInfoMap.set(filePath, "add");
188
199
  } else if (prevEvent === "unlinkDir" && event === "addDir") {
189
- // unlinkDir followed by addDir → addDir (directory recreation)
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
- * Closes the file watcher.
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
- // Utils
1
+ // 유틸리티
2
2
  export * as fsx from "./utils/fs";
3
3
  export * as pathx from "./utils/path";
4
4
 
5
- // Features
5
+ // 기능
6
6
  export * from "./features/fs-watcher";
7
7
 
8
- // Worker
8
+ // 워커
9
9
  export * from "./worker/types";
10
10
  export * from "./worker/worker";
11
11
  export * from "./worker/create-worker";