@simplysm/core-node 13.0.2 → 13.0.7
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs-watcher.d.ts","sourceRoot":"","sources":["../../src/features/fs-watcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"fs-watcher.d.ts","sourceRoot":"","sources":["../../src/features/fs-watcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AAKrC,OAAO,EAAE,KAAK,QAAQ,EAAY,MAAM,eAAe,CAAC;AAyBxD;;GAEG;AACH,QAAA,MAAM,iBAAiB,6DAA8D,CAAC;AAEtF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,gBAAgB;IAChB,KAAK,EAAE,cAAc,CAAC;IACtB,4BAA4B;IAC5B,IAAI,EAAE,QAAQ,CAAC;CAChB;AAMD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,SAAS;IACpB;;;;;;OAMG;WACU,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IAU3F,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAuB;IACvD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAmB;IAEjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAE5D,OAAO;IA6BP;;;;;;OAMG;IACH,QAAQ,CAAC,GAAG,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,EAAE,EAAE,CAAC,WAAW,EAAE,mBAAmB,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAwEzG;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B"}
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { DebounceQueue } from "@simplysm/core-common";
|
|
2
2
|
import * as chokidar from "chokidar";
|
|
3
3
|
import consola from "consola";
|
|
4
|
+
import { Minimatch } from "minimatch";
|
|
5
|
+
import path from "path";
|
|
4
6
|
import { pathNorm } from "../utils/path.js";
|
|
7
|
+
const GLOB_CHARS_RE = /[*?{[\]]/;
|
|
8
|
+
function extractGlobBase(globPath) {
|
|
9
|
+
const segments = globPath.split(/[/\\]/);
|
|
10
|
+
const baseSegments = [];
|
|
11
|
+
for (const seg of segments) {
|
|
12
|
+
if (GLOB_CHARS_RE.test(seg)) break;
|
|
13
|
+
baseSegments.push(seg);
|
|
14
|
+
}
|
|
15
|
+
return baseSegments.join(path.sep) || path.sep;
|
|
16
|
+
}
|
|
5
17
|
const FS_WATCHER_EVENTS = ["add", "addDir", "change", "unlink", "unlinkDir"];
|
|
6
18
|
class FsWatcher {
|
|
7
19
|
/**
|
|
@@ -23,9 +35,21 @@ class FsWatcher {
|
|
|
23
35
|
_watcher;
|
|
24
36
|
_ignoreInitial = true;
|
|
25
37
|
_debounceQueues = [];
|
|
38
|
+
_globMatchers = [];
|
|
26
39
|
_logger = consola.withTag("sd-fs-watcher");
|
|
27
40
|
constructor(paths, options) {
|
|
28
|
-
|
|
41
|
+
const watchPaths = [];
|
|
42
|
+
for (const p of paths) {
|
|
43
|
+
const posixPath = p.replace(/\\/g, "/");
|
|
44
|
+
if (GLOB_CHARS_RE.test(posixPath)) {
|
|
45
|
+
this._globMatchers.push(new Minimatch(posixPath, { dot: true }));
|
|
46
|
+
watchPaths.push(extractGlobBase(p));
|
|
47
|
+
} else {
|
|
48
|
+
watchPaths.push(p);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const uniquePaths = [...new Set(watchPaths)];
|
|
52
|
+
this._watcher = chokidar.watch(uniquePaths, {
|
|
29
53
|
persistent: true,
|
|
30
54
|
...options,
|
|
31
55
|
ignoreInitial: true
|
|
@@ -53,6 +77,10 @@ class FsWatcher {
|
|
|
53
77
|
}
|
|
54
78
|
this._watcher.on("all", (event, filePath) => {
|
|
55
79
|
if (!FS_WATCHER_EVENTS.includes(event)) return;
|
|
80
|
+
if (this._globMatchers.length > 0) {
|
|
81
|
+
const posixFilePath = filePath.replace(/\\/g, "/");
|
|
82
|
+
if (!this._globMatchers.some((m) => m.match(posixFilePath))) return;
|
|
83
|
+
}
|
|
56
84
|
if (!changeInfoMap.has(filePath)) {
|
|
57
85
|
changeInfoMap.set(filePath, event);
|
|
58
86
|
}
|
|
@@ -73,8 +101,8 @@ class FsWatcher {
|
|
|
73
101
|
const currChangeInfoMap = changeInfoMap;
|
|
74
102
|
changeInfoMap = /* @__PURE__ */ new Map();
|
|
75
103
|
const changeInfos = Array.from(currChangeInfoMap.entries()).map(
|
|
76
|
-
([
|
|
77
|
-
path: pathNorm(
|
|
104
|
+
([changedPath, evt]) => ({
|
|
105
|
+
path: pathNorm(changedPath),
|
|
78
106
|
event: evt
|
|
79
107
|
})
|
|
80
108
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/features/fs-watcher.ts"],
|
|
4
|
-
"mappings": "AAAA,SAAS,qBAAqB;AAC9B,YAAY,cAAc;AAC1B,OAAO,aAAa;AAEpB,SAAwB,gBAAgB;
|
|
4
|
+
"mappings": "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",
|
|
5
5
|
"names": []
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/core-node",
|
|
3
|
-
"version": "13.0.
|
|
3
|
+
"version": "13.0.7",
|
|
4
4
|
"description": "심플리즘 패키지 - 코어 모듈 (node)",
|
|
5
5
|
"author": "김석래",
|
|
6
6
|
"repository": {
|
|
@@ -20,8 +20,9 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"chokidar": "^5.0.0",
|
|
22
22
|
"consola": "^3.4.2",
|
|
23
|
-
"glob": "^13.0.
|
|
23
|
+
"glob": "^13.0.3",
|
|
24
|
+
"minimatch": "^10.2.0",
|
|
24
25
|
"tsx": "^4.21.0",
|
|
25
|
-
"@simplysm/core-common": "13.0.
|
|
26
|
+
"@simplysm/core-common": "13.0.7"
|
|
26
27
|
}
|
|
27
28
|
}
|
|
@@ -2,8 +2,31 @@ import { DebounceQueue } from "@simplysm/core-common";
|
|
|
2
2
|
import * as chokidar from "chokidar";
|
|
3
3
|
import consola from "consola";
|
|
4
4
|
import type { EventName } from "chokidar/handler.js";
|
|
5
|
+
import { Minimatch } from "minimatch";
|
|
6
|
+
import path from "path";
|
|
5
7
|
import { type NormPath, pathNorm } from "../utils/path";
|
|
6
8
|
|
|
9
|
+
//#region Helpers
|
|
10
|
+
|
|
11
|
+
/** glob 메타문자 패턴 */
|
|
12
|
+
const GLOB_CHARS_RE = /[*?{[\]]/;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* glob 패턴에서 base 디렉토리 추출.
|
|
16
|
+
* @example extractGlobBase("/home/user/src/**\/*.ts") → "/home/user/src"
|
|
17
|
+
*/
|
|
18
|
+
function extractGlobBase(globPath: string): string {
|
|
19
|
+
const segments = globPath.split(/[/\\]/);
|
|
20
|
+
const baseSegments: string[] = [];
|
|
21
|
+
for (const seg of segments) {
|
|
22
|
+
if (GLOB_CHARS_RE.test(seg)) break;
|
|
23
|
+
baseSegments.push(seg);
|
|
24
|
+
}
|
|
25
|
+
return baseSegments.join(path.sep) || path.sep;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
|
|
7
30
|
//#region Types
|
|
8
31
|
|
|
9
32
|
/**
|
|
@@ -71,11 +94,27 @@ export class FsWatcher {
|
|
|
71
94
|
private readonly _watcher: chokidar.FSWatcher;
|
|
72
95
|
private readonly _ignoreInitial: boolean = true;
|
|
73
96
|
private readonly _debounceQueues: DebounceQueue[] = [];
|
|
97
|
+
private readonly _globMatchers: Minimatch[] = [];
|
|
74
98
|
|
|
75
99
|
private readonly _logger = consola.withTag("sd-fs-watcher");
|
|
76
100
|
|
|
77
101
|
private constructor(paths: string[], options?: chokidar.ChokidarOptions) {
|
|
78
|
-
|
|
102
|
+
const watchPaths: string[] = [];
|
|
103
|
+
|
|
104
|
+
for (const p of paths) {
|
|
105
|
+
const posixPath = p.replace(/\\/g, "/");
|
|
106
|
+
if (GLOB_CHARS_RE.test(posixPath)) {
|
|
107
|
+
this._globMatchers.push(new Minimatch(posixPath, { dot: true }));
|
|
108
|
+
watchPaths.push(extractGlobBase(p));
|
|
109
|
+
} else {
|
|
110
|
+
watchPaths.push(p);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 중복 경로 제거
|
|
115
|
+
const uniquePaths = [...new Set(watchPaths)];
|
|
116
|
+
|
|
117
|
+
this._watcher = chokidar.watch(uniquePaths, {
|
|
79
118
|
persistent: true,
|
|
80
119
|
...options,
|
|
81
120
|
ignoreInitial: true,
|
|
@@ -112,6 +151,12 @@ export class FsWatcher {
|
|
|
112
151
|
// 지원하는 이벤트만 처리
|
|
113
152
|
if (!FS_WATCHER_EVENTS.includes(event as FsWatcherEvent)) return;
|
|
114
153
|
|
|
154
|
+
// glob 매처가 있으면 패턴 필터링 적용
|
|
155
|
+
if (this._globMatchers.length > 0) {
|
|
156
|
+
const posixFilePath = filePath.replace(/\\/g, "/");
|
|
157
|
+
if (!this._globMatchers.some((m) => m.match(posixFilePath))) return;
|
|
158
|
+
}
|
|
159
|
+
|
|
115
160
|
/*
|
|
116
161
|
* 이벤트 병합 전략:
|
|
117
162
|
* 짧은 시간 내 같은 파일에 대해 여러 이벤트가 발생하면 최종 상태만 전달한다.
|
|
@@ -148,8 +193,8 @@ export class FsWatcher {
|
|
|
148
193
|
changeInfoMap = new Map<string, EventName>();
|
|
149
194
|
|
|
150
195
|
const changeInfos = Array.from(currChangeInfoMap.entries()).map(
|
|
151
|
-
([
|
|
152
|
-
path: pathNorm(
|
|
196
|
+
([changedPath, evt]): FsWatcherChangeInfo => ({
|
|
197
|
+
path: pathNorm(changedPath),
|
|
153
198
|
event: evt as FsWatcherEvent,
|
|
154
199
|
}),
|
|
155
200
|
);
|