@simplysm/core-node 13.0.100 → 14.0.1
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/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/lib/worker-dev-proxy.js +15 -0
- package/package.json +8 -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/README.md +0 -112
- package/docs/features.md +0 -91
- package/docs/fs.md +0 -309
- package/docs/path.md +0 -120
- package/docs/worker.md +0 -168
- 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/src/utils/fs.ts
CHANGED
|
@@ -5,19 +5,19 @@ import { glob as globRaw, type GlobOptions, globSync as globRawSync } from "glob
|
|
|
5
5
|
import { json, SdError } from "@simplysm/core-common";
|
|
6
6
|
import "@simplysm/core-common";
|
|
7
7
|
|
|
8
|
-
//#region
|
|
8
|
+
//#region 존재 여부 확인
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
* @param targetPath -
|
|
11
|
+
* 파일 또는 디렉토리가 존재하는지 확인한다 (동기).
|
|
12
|
+
* @param targetPath - 확인할 경로
|
|
13
13
|
*/
|
|
14
14
|
export function existsSync(targetPath: string): boolean {
|
|
15
15
|
return fs.existsSync(targetPath);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
20
|
-
* @param targetPath -
|
|
19
|
+
* 파일 또는 디렉토리가 존재하는지 확인한다 (비동기).
|
|
20
|
+
* @param targetPath - 확인할 경로
|
|
21
21
|
*/
|
|
22
22
|
export async function exists(targetPath: string): Promise<boolean> {
|
|
23
23
|
try {
|
|
@@ -30,11 +30,11 @@ export async function exists(targetPath: string): Promise<boolean> {
|
|
|
30
30
|
|
|
31
31
|
//#endregion
|
|
32
32
|
|
|
33
|
-
//#region
|
|
33
|
+
//#region 디렉토리 생성
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
37
|
-
* @param targetPath -
|
|
36
|
+
* 디렉토리를 생성한다 (재귀적).
|
|
37
|
+
* @param targetPath - 생성할 디렉토리 경로
|
|
38
38
|
*/
|
|
39
39
|
export function mkdirSync(targetPath: string): void {
|
|
40
40
|
try {
|
|
@@ -45,8 +45,8 @@ export function mkdirSync(targetPath: string): void {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
*
|
|
49
|
-
* @param targetPath -
|
|
48
|
+
* 디렉토리를 생성한다 (재귀적, 비동기).
|
|
49
|
+
* @param targetPath - 생성할 디렉토리 경로
|
|
50
50
|
*/
|
|
51
51
|
export async function mkdir(targetPath: string): Promise<void> {
|
|
52
52
|
try {
|
|
@@ -58,12 +58,12 @@ export async function mkdir(targetPath: string): Promise<void> {
|
|
|
58
58
|
|
|
59
59
|
//#endregion
|
|
60
60
|
|
|
61
|
-
//#region
|
|
61
|
+
//#region 삭제
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
*
|
|
65
|
-
* @param targetPath -
|
|
66
|
-
* @remarks
|
|
64
|
+
* 파일 또는 디렉토리를 삭제한다.
|
|
65
|
+
* @param targetPath - 삭제할 경로
|
|
66
|
+
* @remarks 동기 버전은 재시도 없이 즉시 실패한다. 파일 잠금 등 일시적 오류가 발생할 수 있는 경우 rm을 사용하라.
|
|
67
67
|
*/
|
|
68
68
|
export function rmSync(targetPath: string): void {
|
|
69
69
|
try {
|
|
@@ -74,9 +74,9 @@ export function rmSync(targetPath: string): void {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
|
-
*
|
|
78
|
-
* @param targetPath -
|
|
79
|
-
* @remarks
|
|
77
|
+
* 파일 또는 디렉토리를 삭제한다 (비동기).
|
|
78
|
+
* @param targetPath - 삭제할 경로
|
|
79
|
+
* @remarks 비동기 버전은 파일 잠금 등 일시적 오류에 대해 최대 6회(500ms 간격) 재시도한다.
|
|
80
80
|
*/
|
|
81
81
|
export async function rm(targetPath: string): Promise<void> {
|
|
82
82
|
try {
|
|
@@ -93,7 +93,7 @@ export async function rm(targetPath: string): Promise<void> {
|
|
|
93
93
|
|
|
94
94
|
//#endregion
|
|
95
95
|
|
|
96
|
-
//#region
|
|
96
|
+
//#region 복사
|
|
97
97
|
|
|
98
98
|
interface CopyEntry {
|
|
99
99
|
sourcePath: string;
|
|
@@ -119,18 +119,18 @@ function collectCopyEntries(
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
/**
|
|
122
|
-
*
|
|
122
|
+
* 파일 또는 디렉토리를 복사한다.
|
|
123
123
|
*
|
|
124
|
-
*
|
|
124
|
+
* sourcePath가 존재하지 않으면 아무 작업도 수행하지 않고 반환한다.
|
|
125
125
|
*
|
|
126
|
-
* @param sourcePath
|
|
127
|
-
* @param targetPath
|
|
128
|
-
* @param filter
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
126
|
+
* @param sourcePath 복사할 원본 경로
|
|
127
|
+
* @param targetPath 복사 대상 경로
|
|
128
|
+
* @param filter 복사 여부를 결정하는 필터 함수.
|
|
129
|
+
* 각 파일/디렉토리의 **절대 경로**가 전달된다.
|
|
130
|
+
* true를 반환하면 복사, false를 반환하면 제외한다.
|
|
131
|
+
* **주의**: 최상위 sourcePath는 필터링 대상이 아니며,
|
|
132
|
+
* 필터 함수는 모든 하위 항목(직접 및 간접)에 재귀적으로 적용된다.
|
|
133
|
+
* 디렉토리에 대해 false를 반환하면 해당 디렉토리와 모든 내용을 건너뛴다.
|
|
134
134
|
*/
|
|
135
135
|
export function copySync(
|
|
136
136
|
sourcePath: string,
|
|
@@ -141,12 +141,7 @@ export function copySync(
|
|
|
141
141
|
return;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
try {
|
|
146
|
-
stats = fs.lstatSync(sourcePath);
|
|
147
|
-
} catch (err) {
|
|
148
|
-
throw new SdError(err, sourcePath);
|
|
149
|
-
}
|
|
144
|
+
const stats = lstatSync(sourcePath);
|
|
150
145
|
|
|
151
146
|
if (stats.isDirectory()) {
|
|
152
147
|
mkdirSync(targetPath);
|
|
@@ -166,18 +161,18 @@ export function copySync(
|
|
|
166
161
|
}
|
|
167
162
|
|
|
168
163
|
/**
|
|
169
|
-
*
|
|
164
|
+
* 파일 또는 디렉토리를 복사한다 (비동기).
|
|
170
165
|
*
|
|
171
|
-
*
|
|
166
|
+
* sourcePath가 존재하지 않으면 아무 작업도 수행하지 않고 반환한다.
|
|
172
167
|
*
|
|
173
|
-
* @param sourcePath
|
|
174
|
-
* @param targetPath
|
|
175
|
-
* @param filter
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
168
|
+
* @param sourcePath 복사할 원본 경로
|
|
169
|
+
* @param targetPath 복사 대상 경로
|
|
170
|
+
* @param filter 복사 여부를 결정하는 필터 함수.
|
|
171
|
+
* 각 파일/디렉토리의 **절대 경로**가 전달된다.
|
|
172
|
+
* true를 반환하면 복사, false를 반환하면 제외한다.
|
|
173
|
+
* **주의**: 최상위 sourcePath는 필터링 대상이 아니며,
|
|
174
|
+
* 필터 함수는 모든 하위 항목(직접 및 간접)에 재귀적으로 적용된다.
|
|
175
|
+
* 디렉토리에 대해 false를 반환하면 해당 디렉토리와 모든 내용을 건너뛴다.
|
|
181
176
|
*/
|
|
182
177
|
export async function copy(
|
|
183
178
|
sourcePath: string,
|
|
@@ -188,12 +183,7 @@ export async function copy(
|
|
|
188
183
|
return;
|
|
189
184
|
}
|
|
190
185
|
|
|
191
|
-
|
|
192
|
-
try {
|
|
193
|
-
stats = await fs.promises.lstat(sourcePath);
|
|
194
|
-
} catch (err) {
|
|
195
|
-
throw new SdError(err, sourcePath);
|
|
196
|
-
}
|
|
186
|
+
const stats = await lstat(sourcePath);
|
|
197
187
|
|
|
198
188
|
if (stats.isDirectory()) {
|
|
199
189
|
await mkdir(targetPath);
|
|
@@ -215,11 +205,11 @@ export async function copy(
|
|
|
215
205
|
|
|
216
206
|
//#endregion
|
|
217
207
|
|
|
218
|
-
//#region
|
|
208
|
+
//#region 파일 읽기
|
|
219
209
|
|
|
220
210
|
/**
|
|
221
|
-
*
|
|
222
|
-
* @param targetPath -
|
|
211
|
+
* 파일을 UTF-8 문자열로 읽는다.
|
|
212
|
+
* @param targetPath - 읽을 파일 경로
|
|
223
213
|
*/
|
|
224
214
|
export function readSync(targetPath: string): string {
|
|
225
215
|
try {
|
|
@@ -230,8 +220,8 @@ export function readSync(targetPath: string): string {
|
|
|
230
220
|
}
|
|
231
221
|
|
|
232
222
|
/**
|
|
233
|
-
*
|
|
234
|
-
* @param targetPath -
|
|
223
|
+
* 파일을 UTF-8 문자열로 읽는다 (비동기).
|
|
224
|
+
* @param targetPath - 읽을 파일 경로
|
|
235
225
|
*/
|
|
236
226
|
export async function read(targetPath: string): Promise<string> {
|
|
237
227
|
try {
|
|
@@ -242,8 +232,8 @@ export async function read(targetPath: string): Promise<string> {
|
|
|
242
232
|
}
|
|
243
233
|
|
|
244
234
|
/**
|
|
245
|
-
*
|
|
246
|
-
* @param targetPath -
|
|
235
|
+
* 파일을 Buffer로 읽는다.
|
|
236
|
+
* @param targetPath - 읽을 파일 경로
|
|
247
237
|
*/
|
|
248
238
|
export function readBufferSync(targetPath: string): Buffer {
|
|
249
239
|
try {
|
|
@@ -254,8 +244,8 @@ export function readBufferSync(targetPath: string): Buffer {
|
|
|
254
244
|
}
|
|
255
245
|
|
|
256
246
|
/**
|
|
257
|
-
*
|
|
258
|
-
* @param targetPath -
|
|
247
|
+
* 파일을 Buffer로 읽는다 (비동기).
|
|
248
|
+
* @param targetPath - 읽을 파일 경로
|
|
259
249
|
*/
|
|
260
250
|
export async function readBuffer(targetPath: string): Promise<Buffer> {
|
|
261
251
|
try {
|
|
@@ -266,8 +256,8 @@ export async function readBuffer(targetPath: string): Promise<Buffer> {
|
|
|
266
256
|
}
|
|
267
257
|
|
|
268
258
|
/**
|
|
269
|
-
*
|
|
270
|
-
* @param targetPath -
|
|
259
|
+
* JSON 파일을 읽는다 (JsonConvert 사용).
|
|
260
|
+
* @param targetPath - 읽을 JSON 파일 경로
|
|
271
261
|
*/
|
|
272
262
|
export function readJsonSync<TData = unknown>(targetPath: string): TData {
|
|
273
263
|
const contents = readSync(targetPath);
|
|
@@ -280,8 +270,8 @@ export function readJsonSync<TData = unknown>(targetPath: string): TData {
|
|
|
280
270
|
}
|
|
281
271
|
|
|
282
272
|
/**
|
|
283
|
-
*
|
|
284
|
-
* @param targetPath -
|
|
273
|
+
* JSON 파일을 읽는다 (JsonConvert 사용, 비동기).
|
|
274
|
+
* @param targetPath - 읽을 JSON 파일 경로
|
|
285
275
|
*/
|
|
286
276
|
export async function readJson<TData = unknown>(targetPath: string): Promise<TData> {
|
|
287
277
|
const contents = await read(targetPath);
|
|
@@ -295,12 +285,12 @@ export async function readJson<TData = unknown>(targetPath: string): Promise<TDa
|
|
|
295
285
|
|
|
296
286
|
//#endregion
|
|
297
287
|
|
|
298
|
-
//#region
|
|
288
|
+
//#region 파일 쓰기
|
|
299
289
|
|
|
300
290
|
/**
|
|
301
|
-
*
|
|
302
|
-
* @param targetPath -
|
|
303
|
-
* @param data -
|
|
291
|
+
* 파일에 데이터를 쓴다 (상위 디렉토리 자동 생성).
|
|
292
|
+
* @param targetPath - 쓸 파일 경로
|
|
293
|
+
* @param data - 쓸 데이터 (문자열 또는 바이너리)
|
|
304
294
|
*/
|
|
305
295
|
export function writeSync(targetPath: string, data: string | Uint8Array): void {
|
|
306
296
|
mkdirSync(path.dirname(targetPath));
|
|
@@ -313,9 +303,9 @@ export function writeSync(targetPath: string, data: string | Uint8Array): void {
|
|
|
313
303
|
}
|
|
314
304
|
|
|
315
305
|
/**
|
|
316
|
-
*
|
|
317
|
-
* @param targetPath -
|
|
318
|
-
* @param data -
|
|
306
|
+
* 파일에 데이터를 쓴다 (상위 디렉토리 자동 생성, 비동기).
|
|
307
|
+
* @param targetPath - 쓸 파일 경로
|
|
308
|
+
* @param data - 쓸 데이터 (문자열 또는 바이너리)
|
|
319
309
|
*/
|
|
320
310
|
export async function write(targetPath: string, data: string | Uint8Array): Promise<void> {
|
|
321
311
|
await mkdir(path.dirname(targetPath));
|
|
@@ -328,10 +318,10 @@ export async function write(targetPath: string, data: string | Uint8Array): Prom
|
|
|
328
318
|
}
|
|
329
319
|
|
|
330
320
|
/**
|
|
331
|
-
*
|
|
332
|
-
* @param targetPath -
|
|
333
|
-
* @param data -
|
|
334
|
-
* @param options - JSON
|
|
321
|
+
* JSON 파일에 데이터를 쓴다 (JsonConvert 사용).
|
|
322
|
+
* @param targetPath - 쓸 JSON 파일 경로
|
|
323
|
+
* @param data - 쓸 데이터
|
|
324
|
+
* @param options - JSON 직렬화 옵션
|
|
335
325
|
*/
|
|
336
326
|
export function writeJsonSync(
|
|
337
327
|
targetPath: string,
|
|
@@ -346,10 +336,10 @@ export function writeJsonSync(
|
|
|
346
336
|
}
|
|
347
337
|
|
|
348
338
|
/**
|
|
349
|
-
*
|
|
350
|
-
* @param targetPath -
|
|
351
|
-
* @param data -
|
|
352
|
-
* @param options - JSON
|
|
339
|
+
* JSON 파일에 데이터를 쓴다 (JsonConvert 사용, 비동기).
|
|
340
|
+
* @param targetPath - 쓸 JSON 파일 경로
|
|
341
|
+
* @param data - 쓸 데이터
|
|
342
|
+
* @param options - JSON 직렬화 옵션
|
|
353
343
|
*/
|
|
354
344
|
export async function writeJson(
|
|
355
345
|
targetPath: string,
|
|
@@ -365,11 +355,11 @@ export async function writeJson(
|
|
|
365
355
|
|
|
366
356
|
//#endregion
|
|
367
357
|
|
|
368
|
-
//#region
|
|
358
|
+
//#region 디렉토리 읽기
|
|
369
359
|
|
|
370
360
|
/**
|
|
371
|
-
*
|
|
372
|
-
* @param targetPath -
|
|
361
|
+
* 디렉토리의 내용을 읽는다.
|
|
362
|
+
* @param targetPath - 읽을 디렉토리 경로
|
|
373
363
|
*/
|
|
374
364
|
export function readdirSync(targetPath: string): string[] {
|
|
375
365
|
try {
|
|
@@ -380,8 +370,8 @@ export function readdirSync(targetPath: string): string[] {
|
|
|
380
370
|
}
|
|
381
371
|
|
|
382
372
|
/**
|
|
383
|
-
*
|
|
384
|
-
* @param targetPath -
|
|
373
|
+
* 디렉토리의 내용을 읽는다 (비동기).
|
|
374
|
+
* @param targetPath - 읽을 디렉토리 경로
|
|
385
375
|
*/
|
|
386
376
|
export async function readdir(targetPath: string): Promise<string[]> {
|
|
387
377
|
try {
|
|
@@ -393,11 +383,11 @@ export async function readdir(targetPath: string): Promise<string[]> {
|
|
|
393
383
|
|
|
394
384
|
//#endregion
|
|
395
385
|
|
|
396
|
-
//#region
|
|
386
|
+
//#region 파일 정보
|
|
397
387
|
|
|
398
388
|
/**
|
|
399
|
-
*
|
|
400
|
-
* @param targetPath -
|
|
389
|
+
* 파일/디렉토리 정보를 가져온다 (심볼릭 링크를 따라감).
|
|
390
|
+
* @param targetPath - 정보를 조회할 경로
|
|
401
391
|
*/
|
|
402
392
|
export function statSync(targetPath: string): fs.Stats {
|
|
403
393
|
try {
|
|
@@ -408,8 +398,8 @@ export function statSync(targetPath: string): fs.Stats {
|
|
|
408
398
|
}
|
|
409
399
|
|
|
410
400
|
/**
|
|
411
|
-
*
|
|
412
|
-
* @param targetPath -
|
|
401
|
+
* 파일/디렉토리 정보를 가져온다 (심볼릭 링크를 따라감, 비동기).
|
|
402
|
+
* @param targetPath - 정보를 조회할 경로
|
|
413
403
|
*/
|
|
414
404
|
export async function stat(targetPath: string): Promise<fs.Stats> {
|
|
415
405
|
try {
|
|
@@ -420,8 +410,8 @@ export async function stat(targetPath: string): Promise<fs.Stats> {
|
|
|
420
410
|
}
|
|
421
411
|
|
|
422
412
|
/**
|
|
423
|
-
*
|
|
424
|
-
* @param targetPath -
|
|
413
|
+
* 파일/디렉토리 정보를 가져온다 (심볼릭 링크를 따라가지 않음).
|
|
414
|
+
* @param targetPath - 정보를 조회할 경로
|
|
425
415
|
*/
|
|
426
416
|
export function lstatSync(targetPath: string): fs.Stats {
|
|
427
417
|
try {
|
|
@@ -432,8 +422,8 @@ export function lstatSync(targetPath: string): fs.Stats {
|
|
|
432
422
|
}
|
|
433
423
|
|
|
434
424
|
/**
|
|
435
|
-
*
|
|
436
|
-
* @param targetPath -
|
|
425
|
+
* 파일/디렉토리 정보를 가져온다 (심볼릭 링크를 따라가지 않음, 비동기).
|
|
426
|
+
* @param targetPath - 정보를 조회할 경로
|
|
437
427
|
*/
|
|
438
428
|
export async function lstat(targetPath: string): Promise<fs.Stats> {
|
|
439
429
|
try {
|
|
@@ -448,10 +438,10 @@ export async function lstat(targetPath: string): Promise<fs.Stats> {
|
|
|
448
438
|
//#region Glob
|
|
449
439
|
|
|
450
440
|
/**
|
|
451
|
-
*
|
|
452
|
-
* @param pattern - Glob
|
|
453
|
-
* @param options - glob
|
|
454
|
-
* @returns
|
|
441
|
+
* Glob 패턴을 사용하여 파일을 검색한다.
|
|
442
|
+
* @param pattern - Glob 패턴 (예: "**\/*.ts")
|
|
443
|
+
* @param options - glob 옵션
|
|
444
|
+
* @returns 매칭된 파일의 절대 경로 배열
|
|
455
445
|
*/
|
|
456
446
|
export function globSync(pattern: string, options?: GlobOptions): string[] {
|
|
457
447
|
return globRawSync(pattern.replace(/\\/g, "/"), options ?? {}).map((item) =>
|
|
@@ -460,10 +450,10 @@ export function globSync(pattern: string, options?: GlobOptions): string[] {
|
|
|
460
450
|
}
|
|
461
451
|
|
|
462
452
|
/**
|
|
463
|
-
*
|
|
464
|
-
* @param pattern - Glob
|
|
465
|
-
* @param options - glob
|
|
466
|
-
* @returns
|
|
453
|
+
* Glob 패턴을 사용하여 파일을 검색한다 (비동기).
|
|
454
|
+
* @param pattern - Glob 패턴 (예: "**\/*.ts")
|
|
455
|
+
* @param options - glob 옵션
|
|
456
|
+
* @returns 매칭된 파일의 절대 경로 배열
|
|
467
457
|
*/
|
|
468
458
|
export async function glob(pattern: string, options?: GlobOptions): Promise<string[]> {
|
|
469
459
|
return (await globRaw(pattern.replace(/\\/g, "/"), options ?? {})).map((item) =>
|
|
@@ -473,11 +463,11 @@ export async function glob(pattern: string, options?: GlobOptions): Promise<stri
|
|
|
473
463
|
|
|
474
464
|
//#endregion
|
|
475
465
|
|
|
476
|
-
//#region
|
|
466
|
+
//#region 유틸리티
|
|
477
467
|
|
|
478
468
|
/**
|
|
479
|
-
*
|
|
480
|
-
*
|
|
469
|
+
* 지정된 디렉토리 하위의 빈 디렉토리를 재귀적으로 검색하여 삭제한다.
|
|
470
|
+
* 모든 하위 디렉토리가 삭제되어 상위 디렉토리가 비게 되면, 해당 디렉토리도 삭제된다.
|
|
481
471
|
*/
|
|
482
472
|
export async function clearEmptyDirectory(dirPath: string): Promise<void> {
|
|
483
473
|
if (!(await exists(dirPath))) return;
|
|
@@ -487,30 +477,31 @@ export async function clearEmptyDirectory(dirPath: string): Promise<void> {
|
|
|
487
477
|
|
|
488
478
|
for (const childName of childNames) {
|
|
489
479
|
const childPath = path.resolve(dirPath, childName);
|
|
490
|
-
|
|
480
|
+
const childStat = await lstat(childPath);
|
|
481
|
+
if (childStat.isDirectory()) {
|
|
491
482
|
await clearEmptyDirectory(childPath);
|
|
492
483
|
} else {
|
|
493
484
|
hasFiles = true;
|
|
494
485
|
}
|
|
495
486
|
}
|
|
496
487
|
|
|
497
|
-
//
|
|
488
|
+
// 파일이 있으면 삭제 불가
|
|
498
489
|
if (hasFiles) return;
|
|
499
490
|
|
|
500
|
-
//
|
|
491
|
+
// 파일이 없는 경우에만 다시 확인 (하위 디렉토리가 삭제되었을 수 있음)
|
|
501
492
|
if ((await readdir(dirPath)).length === 0) {
|
|
502
493
|
await rm(dirPath);
|
|
503
494
|
}
|
|
504
495
|
}
|
|
505
496
|
|
|
506
497
|
/**
|
|
507
|
-
*
|
|
508
|
-
*
|
|
509
|
-
* @param childGlob -
|
|
510
|
-
* @param fromPath -
|
|
511
|
-
* @param rootPath -
|
|
512
|
-
*
|
|
513
|
-
*
|
|
498
|
+
* 시작 경로에서 루트 방향으로 부모 디렉토리를 순회하며 glob 패턴에 매칭되는 파일을 검색한다.
|
|
499
|
+
* 각 디렉토리에서 childGlob 패턴에 매칭되는 모든 파일 경로를 수집한다.
|
|
500
|
+
* @param childGlob - 각 디렉토리에서 검색할 glob 패턴
|
|
501
|
+
* @param fromPath - 검색을 시작할 경로
|
|
502
|
+
* @param rootPath - 검색을 중단할 경로 (지정하지 않으면 파일 시스템 루트까지 검색).
|
|
503
|
+
* **주의**: fromPath는 rootPath의 하위 경로여야 한다.
|
|
504
|
+
* 그렇지 않으면 파일 시스템 루트까지 검색한다.
|
|
514
505
|
*/
|
|
515
506
|
export function findAllParentChildPathsSync(
|
|
516
507
|
childGlob: string,
|
|
@@ -536,13 +527,13 @@ export function findAllParentChildPathsSync(
|
|
|
536
527
|
}
|
|
537
528
|
|
|
538
529
|
/**
|
|
539
|
-
*
|
|
540
|
-
*
|
|
541
|
-
* @param childGlob -
|
|
542
|
-
* @param fromPath -
|
|
543
|
-
* @param rootPath -
|
|
544
|
-
*
|
|
545
|
-
*
|
|
530
|
+
* 시작 경로에서 루트 방향으로 부모 디렉토리를 순회하며 glob 패턴에 매칭되는 파일을 검색한다 (비동기).
|
|
531
|
+
* 각 디렉토리에서 childGlob 패턴에 매칭되는 모든 파일 경로를 수집한다.
|
|
532
|
+
* @param childGlob - 각 디렉토리에서 검색할 glob 패턴
|
|
533
|
+
* @param fromPath - 검색을 시작할 경로
|
|
534
|
+
* @param rootPath - 검색을 중단할 경로 (지정하지 않으면 파일 시스템 루트까지 검색).
|
|
535
|
+
* **주의**: fromPath는 rootPath의 하위 경로여야 한다.
|
|
536
|
+
* 그렇지 않으면 파일 시스템 루트까지 검색한다.
|
|
546
537
|
*/
|
|
547
538
|
export async function findAllParentChildPaths(
|
|
548
539
|
childGlob: string,
|
package/src/utils/path.ts
CHANGED
|
@@ -6,8 +6,8 @@ import { ArgumentError } from "@simplysm/core-common";
|
|
|
6
6
|
const NORM = Symbol("NormPath");
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* 정규화된 경로를 나타내는 브랜드 타입.
|
|
10
|
+
* norm()을 통해서만 생성할 수 있다.
|
|
11
11
|
*/
|
|
12
12
|
export type NormPath = string & {
|
|
13
13
|
[NORM]: never;
|
|
@@ -15,10 +15,10 @@ export type NormPath = string & {
|
|
|
15
15
|
|
|
16
16
|
//#endregion
|
|
17
17
|
|
|
18
|
-
//#region
|
|
18
|
+
//#region 함수
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* POSIX 스타일 경로로 변환한다 (백슬래시 → 슬래시).
|
|
22
22
|
*
|
|
23
23
|
* @example
|
|
24
24
|
* posix("C:\\Users\\test"); // "C:/Users/test"
|
|
@@ -30,13 +30,13 @@ export function posix(...args: string[]): string {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* 파일 경로의 디렉토리를 변경한다.
|
|
34
34
|
*
|
|
35
35
|
* @example
|
|
36
36
|
* changeFileDirectory("/a/b/c.txt", "/a", "/x");
|
|
37
37
|
* // → "/x/b/c.txt"
|
|
38
38
|
*
|
|
39
|
-
* @throws
|
|
39
|
+
* @throws 파일이 fromDirectory 내부에 없는 경우 에러 발생
|
|
40
40
|
*/
|
|
41
41
|
export function changeFileDirectory(
|
|
42
42
|
filePath: string,
|
|
@@ -48,7 +48,7 @@ export function changeFileDirectory(
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
if (!isChildPath(filePath, fromDirectory)) {
|
|
51
|
-
throw new ArgumentError(`'${filePath}'
|
|
51
|
+
throw new ArgumentError(`'${filePath}'은(는) ${fromDirectory} 내부에 없습니다.`, {
|
|
52
52
|
filePath,
|
|
53
53
|
fromDirectory,
|
|
54
54
|
});
|
|
@@ -58,7 +58,7 @@ export function changeFileDirectory(
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
*
|
|
61
|
+
* 확장자를 제외한 파일명(basename)을 반환한다.
|
|
62
62
|
*
|
|
63
63
|
* @example
|
|
64
64
|
* basenameWithoutExt("file.txt"); // "file"
|
|
@@ -69,27 +69,27 @@ export function basenameWithoutExt(filePath: string): string {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
72
|
+
* childPath가 parentPath의 하위 경로인지 확인한다.
|
|
73
|
+
* 동일한 경로이면 false를 반환한다.
|
|
74
74
|
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
75
|
+
* 경로는 내부적으로 `norm()`을 사용하여 정규화되며,
|
|
76
|
+
* 플랫폼별 경로 구분자(Windows: `\`, Unix: `/`)를 사용하여 비교한다.
|
|
77
77
|
*
|
|
78
78
|
* @example
|
|
79
79
|
* isChildPath("/a/b/c", "/a/b"); // true
|
|
80
80
|
* isChildPath("/a/b", "/a/b/c"); // false
|
|
81
|
-
* isChildPath("/a/b", "/a/b"); // false (
|
|
81
|
+
* isChildPath("/a/b", "/a/b"); // false (동일 경로)
|
|
82
82
|
*/
|
|
83
83
|
export function isChildPath(childPath: string, parentPath: string): boolean {
|
|
84
84
|
const normalizedChild = norm(childPath);
|
|
85
85
|
const normalizedParent = norm(parentPath);
|
|
86
86
|
|
|
87
|
-
//
|
|
87
|
+
// 동일 경로는 false 반환
|
|
88
88
|
if (normalizedChild === normalizedParent) {
|
|
89
89
|
return false;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
//
|
|
92
|
+
// 부모 경로 + 구분자로 시작하는지 확인
|
|
93
93
|
const parentWithSep = normalizedParent.endsWith(path.sep)
|
|
94
94
|
? normalizedParent
|
|
95
95
|
: normalizedParent + path.sep;
|
|
@@ -98,27 +98,27 @@ export function isChildPath(childPath: string, parentPath: string): boolean {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
101
|
+
* 경로를 정규화하여 NormPath로 반환한다.
|
|
102
|
+
* 절대 경로로 변환하고 플랫폼별 구분자로 정규화한다.
|
|
103
103
|
*
|
|
104
104
|
* @example
|
|
105
105
|
* norm("/some/path"); // NormPath
|
|
106
|
-
* norm("relative", "path"); // NormPath (
|
|
106
|
+
* norm("relative", "path"); // NormPath (절대 경로로 변환됨)
|
|
107
107
|
*/
|
|
108
108
|
export function norm(...paths: string[]): NormPath {
|
|
109
109
|
return path.resolve(...paths) as NormPath;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
113
|
+
* 대상 경로 목록을 기반으로 파일을 필터링한다.
|
|
114
|
+
* 대상 경로와 일치하거나 하위에 있는 파일을 포함한다.
|
|
115
115
|
*
|
|
116
|
-
* @param files -
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* @param targets -
|
|
120
|
-
* @param cwd -
|
|
121
|
-
* @returns
|
|
116
|
+
* @param files - 필터링할 파일 경로.
|
|
117
|
+
* **주의**: cwd 하위의 절대 경로여야 한다.
|
|
118
|
+
* cwd 외부의 경로는 상대 경로(../)로 변환되어 처리된다.
|
|
119
|
+
* @param targets - 대상 경로 (cwd 기준 상대 경로, POSIX 스타일 권장)
|
|
120
|
+
* @param cwd - 현재 작업 디렉토리 (절대 경로)
|
|
121
|
+
* @returns targets가 비어있으면 files를 그대로 반환; 그렇지 않으면 대상 경로 하위의 파일만 반환
|
|
122
122
|
*
|
|
123
123
|
* @example
|
|
124
124
|
* const files = ["/proj/src/a.ts", "/proj/src/b.ts", "/proj/tests/c.ts"];
|