@simplysm/core-node 13.0.69 → 13.0.71
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 +17 -354
- 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 +9 -9
- package/dist/utils/fs.d.ts +96 -96
- package/dist/utils/path.d.ts +22 -22
- package/dist/utils/path.js +1 -1
- package/dist/utils/path.js.map +1 -1
- package/dist/worker/create-worker.d.ts +3 -3
- package/dist/worker/create-worker.js +3 -3
- package/dist/worker/create-worker.js.map +1 -1
- package/dist/worker/types.d.ts +14 -14
- package/dist/worker/worker.d.ts +5 -5
- package/dist/worker/worker.js +12 -12
- package/dist/worker/worker.js.map +1 -1
- package/package.json +6 -5
- package/src/features/fs-watcher.ts +38 -38
- package/src/utils/fs.ts +108 -108
- 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/tests/utils/fs-watcher.spec.ts +339 -0
- package/tests/utils/fs.spec.ts +755 -0
- package/tests/utils/path.spec.ts +192 -0
- package/tests/worker/fixtures/test-worker.ts +35 -0
- package/tests/worker/sd-worker.spec.ts +189 -0
package/src/utils/fs.ts
CHANGED
|
@@ -5,19 +5,19 @@ import { glob as globRaw, type GlobOptions, globSync as globRawSync } from "glob
|
|
|
5
5
|
import { jsonParse, jsonStringify, SdError } from "@simplysm/core-common";
|
|
6
6
|
import "@simplysm/core-common";
|
|
7
7
|
|
|
8
|
-
//#region
|
|
8
|
+
//#region Existence Check
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
* @param targetPath -
|
|
11
|
+
* Checks if a file or directory exists (synchronous).
|
|
12
|
+
* @param targetPath - Path to check
|
|
13
13
|
*/
|
|
14
14
|
export function fsExistsSync(targetPath: string): boolean {
|
|
15
15
|
return fs.existsSync(targetPath);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
20
|
-
* @param targetPath -
|
|
19
|
+
* Checks if a file or directory exists (asynchronous).
|
|
20
|
+
* @param targetPath - Path to check
|
|
21
21
|
*/
|
|
22
22
|
export async function fsExists(targetPath: string): Promise<boolean> {
|
|
23
23
|
try {
|
|
@@ -30,11 +30,11 @@ export async function fsExists(targetPath: string): Promise<boolean> {
|
|
|
30
30
|
|
|
31
31
|
//#endregion
|
|
32
32
|
|
|
33
|
-
//#region
|
|
33
|
+
//#region Create Directory
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
37
|
-
* @param targetPath -
|
|
36
|
+
* Creates a directory (recursive).
|
|
37
|
+
* @param targetPath - Directory path to create
|
|
38
38
|
*/
|
|
39
39
|
export function fsMkdirSync(targetPath: string): void {
|
|
40
40
|
try {
|
|
@@ -45,8 +45,8 @@ export function fsMkdirSync(targetPath: string): void {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
*
|
|
49
|
-
* @param targetPath -
|
|
48
|
+
* Creates a directory (recursive, asynchronous).
|
|
49
|
+
* @param targetPath - Directory path to create
|
|
50
50
|
*/
|
|
51
51
|
export async function fsMkdir(targetPath: string): Promise<void> {
|
|
52
52
|
try {
|
|
@@ -58,12 +58,12 @@ export async function fsMkdir(targetPath: string): Promise<void> {
|
|
|
58
58
|
|
|
59
59
|
//#endregion
|
|
60
60
|
|
|
61
|
-
//#region
|
|
61
|
+
//#region Delete
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
*
|
|
65
|
-
* @param targetPath -
|
|
66
|
-
* @remarks
|
|
64
|
+
* Deletes a file or directory.
|
|
65
|
+
* @param targetPath - Path to delete
|
|
66
|
+
* @remarks The synchronous version fails immediately without retries. Use fsRm for cases with potential transient errors like file locks.
|
|
67
67
|
*/
|
|
68
68
|
export function fsRmSync(targetPath: string): void {
|
|
69
69
|
try {
|
|
@@ -74,9 +74,9 @@ export function fsRmSync(targetPath: string): void {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
|
-
*
|
|
78
|
-
* @param targetPath -
|
|
79
|
-
* @remarks
|
|
77
|
+
* Deletes a file or directory (asynchronous).
|
|
78
|
+
* @param targetPath - Path to delete
|
|
79
|
+
* @remarks The asynchronous version retries up to 6 times (500ms interval) for transient errors like file locks.
|
|
80
80
|
*/
|
|
81
81
|
export async function fsRm(targetPath: string): Promise<void> {
|
|
82
82
|
try {
|
|
@@ -93,21 +93,21 @@ export async function fsRm(targetPath: string): Promise<void> {
|
|
|
93
93
|
|
|
94
94
|
//#endregion
|
|
95
95
|
|
|
96
|
-
//#region
|
|
96
|
+
//#region Copy
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
|
-
*
|
|
99
|
+
* Copies a file or directory.
|
|
100
100
|
*
|
|
101
|
-
* sourcePath
|
|
101
|
+
* If sourcePath does not exist, no action is performed and the function returns.
|
|
102
102
|
*
|
|
103
|
-
* @param sourcePath
|
|
104
|
-
* @param targetPath
|
|
105
|
-
* @param filter
|
|
106
|
-
*
|
|
107
|
-
* true
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
103
|
+
* @param sourcePath Path of the source to copy
|
|
104
|
+
* @param targetPath Destination path for the copy
|
|
105
|
+
* @param filter A filter function that determines whether to copy.
|
|
106
|
+
* The **absolute path** of each file/directory is passed.
|
|
107
|
+
* Returns true to copy, false to exclude.
|
|
108
|
+
* **Note**: The top-level sourcePath is not subject to filtering;
|
|
109
|
+
* the filter function is applied recursively to all children (direct and indirect).
|
|
110
|
+
* Returning false for a directory skips that directory and all its contents.
|
|
111
111
|
*/
|
|
112
112
|
export function fsCopySync(
|
|
113
113
|
sourcePath: string,
|
|
@@ -151,18 +151,18 @@ export function fsCopySync(
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/**
|
|
154
|
-
*
|
|
154
|
+
* Copies a file or directory (asynchronous).
|
|
155
155
|
*
|
|
156
|
-
* sourcePath
|
|
156
|
+
* If sourcePath does not exist, no action is performed and the function returns.
|
|
157
157
|
*
|
|
158
|
-
* @param sourcePath
|
|
159
|
-
* @param targetPath
|
|
160
|
-
* @param filter
|
|
161
|
-
*
|
|
162
|
-
* true
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
158
|
+
* @param sourcePath Path of the source to copy
|
|
159
|
+
* @param targetPath Destination path for the copy
|
|
160
|
+
* @param filter A filter function that determines whether to copy.
|
|
161
|
+
* The **absolute path** of each file/directory is passed.
|
|
162
|
+
* Returns true to copy, false to exclude.
|
|
163
|
+
* **Note**: The top-level sourcePath is not subject to filtering;
|
|
164
|
+
* the filter function is applied recursively to all children (direct and indirect).
|
|
165
|
+
* Returning false for a directory skips that directory and all its contents.
|
|
166
166
|
*/
|
|
167
167
|
export async function fsCopy(
|
|
168
168
|
sourcePath: string,
|
|
@@ -207,11 +207,11 @@ export async function fsCopy(
|
|
|
207
207
|
|
|
208
208
|
//#endregion
|
|
209
209
|
|
|
210
|
-
//#region
|
|
210
|
+
//#region Read File
|
|
211
211
|
|
|
212
212
|
/**
|
|
213
|
-
*
|
|
214
|
-
* @param targetPath -
|
|
213
|
+
* Reads a file as a UTF-8 string.
|
|
214
|
+
* @param targetPath - Path of the file to read
|
|
215
215
|
*/
|
|
216
216
|
export function fsReadSync(targetPath: string): string {
|
|
217
217
|
try {
|
|
@@ -222,8 +222,8 @@ export function fsReadSync(targetPath: string): string {
|
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
/**
|
|
225
|
-
*
|
|
226
|
-
* @param targetPath -
|
|
225
|
+
* Reads a file as a UTF-8 string (asynchronous).
|
|
226
|
+
* @param targetPath - Path of the file to read
|
|
227
227
|
*/
|
|
228
228
|
export async function fsRead(targetPath: string): Promise<string> {
|
|
229
229
|
try {
|
|
@@ -234,8 +234,8 @@ export async function fsRead(targetPath: string): Promise<string> {
|
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
/**
|
|
237
|
-
*
|
|
238
|
-
* @param targetPath -
|
|
237
|
+
* Reads a file as a Buffer.
|
|
238
|
+
* @param targetPath - Path of the file to read
|
|
239
239
|
*/
|
|
240
240
|
export function fsReadBufferSync(targetPath: string): Buffer {
|
|
241
241
|
try {
|
|
@@ -246,8 +246,8 @@ export function fsReadBufferSync(targetPath: string): Buffer {
|
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
/**
|
|
249
|
-
*
|
|
250
|
-
* @param targetPath -
|
|
249
|
+
* Reads a file as a Buffer (asynchronous).
|
|
250
|
+
* @param targetPath - Path of the file to read
|
|
251
251
|
*/
|
|
252
252
|
export async function fsReadBuffer(targetPath: string): Promise<Buffer> {
|
|
253
253
|
try {
|
|
@@ -258,8 +258,8 @@ export async function fsReadBuffer(targetPath: string): Promise<Buffer> {
|
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
/**
|
|
261
|
-
* JSON
|
|
262
|
-
* @param targetPath -
|
|
261
|
+
* Reads a JSON file (using JsonConvert).
|
|
262
|
+
* @param targetPath - Path of the JSON file to read
|
|
263
263
|
*/
|
|
264
264
|
export function fsReadJsonSync<TData = unknown>(targetPath: string): TData {
|
|
265
265
|
const contents = fsReadSync(targetPath);
|
|
@@ -272,8 +272,8 @@ export function fsReadJsonSync<TData = unknown>(targetPath: string): TData {
|
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
/**
|
|
275
|
-
* JSON
|
|
276
|
-
* @param targetPath -
|
|
275
|
+
* Reads a JSON file (using JsonConvert, asynchronous).
|
|
276
|
+
* @param targetPath - Path of the JSON file to read
|
|
277
277
|
*/
|
|
278
278
|
export async function fsReadJson<TData = unknown>(targetPath: string): Promise<TData> {
|
|
279
279
|
const contents = await fsRead(targetPath);
|
|
@@ -287,12 +287,12 @@ export async function fsReadJson<TData = unknown>(targetPath: string): Promise<T
|
|
|
287
287
|
|
|
288
288
|
//#endregion
|
|
289
289
|
|
|
290
|
-
//#region
|
|
290
|
+
//#region Write File
|
|
291
291
|
|
|
292
292
|
/**
|
|
293
|
-
*
|
|
294
|
-
* @param targetPath -
|
|
295
|
-
* @param data -
|
|
293
|
+
* Writes data to a file (auto-creates parent directories).
|
|
294
|
+
* @param targetPath - Path of the file to write
|
|
295
|
+
* @param data - Data to write (string or binary)
|
|
296
296
|
*/
|
|
297
297
|
export function fsWriteSync(targetPath: string, data: string | Uint8Array): void {
|
|
298
298
|
fsMkdirSync(path.dirname(targetPath));
|
|
@@ -305,9 +305,9 @@ export function fsWriteSync(targetPath: string, data: string | Uint8Array): void
|
|
|
305
305
|
}
|
|
306
306
|
|
|
307
307
|
/**
|
|
308
|
-
*
|
|
309
|
-
* @param targetPath -
|
|
310
|
-
* @param data -
|
|
308
|
+
* Writes data to a file (auto-creates parent directories, asynchronous).
|
|
309
|
+
* @param targetPath - Path of the file to write
|
|
310
|
+
* @param data - Data to write (string or binary)
|
|
311
311
|
*/
|
|
312
312
|
export async function fsWrite(targetPath: string, data: string | Uint8Array): Promise<void> {
|
|
313
313
|
await fsMkdir(path.dirname(targetPath));
|
|
@@ -320,10 +320,10 @@ export async function fsWrite(targetPath: string, data: string | Uint8Array): Pr
|
|
|
320
320
|
}
|
|
321
321
|
|
|
322
322
|
/**
|
|
323
|
-
* JSON
|
|
324
|
-
* @param targetPath -
|
|
325
|
-
* @param data -
|
|
326
|
-
* @param options - JSON
|
|
323
|
+
* Writes data to a JSON file (using JsonConvert).
|
|
324
|
+
* @param targetPath - Path of the JSON file to write
|
|
325
|
+
* @param data - Data to write
|
|
326
|
+
* @param options - JSON serialization options
|
|
327
327
|
*/
|
|
328
328
|
export function fsWriteJsonSync(
|
|
329
329
|
targetPath: string,
|
|
@@ -338,10 +338,10 @@ export function fsWriteJsonSync(
|
|
|
338
338
|
}
|
|
339
339
|
|
|
340
340
|
/**
|
|
341
|
-
* JSON
|
|
342
|
-
* @param targetPath -
|
|
343
|
-
* @param data -
|
|
344
|
-
* @param options - JSON
|
|
341
|
+
* Writes data to a JSON file (using JsonConvert, asynchronous).
|
|
342
|
+
* @param targetPath - Path of the JSON file to write
|
|
343
|
+
* @param data - Data to write
|
|
344
|
+
* @param options - JSON serialization options
|
|
345
345
|
*/
|
|
346
346
|
export async function fsWriteJson(
|
|
347
347
|
targetPath: string,
|
|
@@ -357,11 +357,11 @@ export async function fsWriteJson(
|
|
|
357
357
|
|
|
358
358
|
//#endregion
|
|
359
359
|
|
|
360
|
-
//#region
|
|
360
|
+
//#region Read Directory
|
|
361
361
|
|
|
362
362
|
/**
|
|
363
|
-
*
|
|
364
|
-
* @param targetPath -
|
|
363
|
+
* Reads the contents of a directory.
|
|
364
|
+
* @param targetPath - Path of the directory to read
|
|
365
365
|
*/
|
|
366
366
|
export function fsReaddirSync(targetPath: string): string[] {
|
|
367
367
|
try {
|
|
@@ -372,8 +372,8 @@ export function fsReaddirSync(targetPath: string): string[] {
|
|
|
372
372
|
}
|
|
373
373
|
|
|
374
374
|
/**
|
|
375
|
-
*
|
|
376
|
-
* @param targetPath -
|
|
375
|
+
* Reads the contents of a directory (asynchronous).
|
|
376
|
+
* @param targetPath - Path of the directory to read
|
|
377
377
|
*/
|
|
378
378
|
export async function fsReaddir(targetPath: string): Promise<string[]> {
|
|
379
379
|
try {
|
|
@@ -385,11 +385,11 @@ export async function fsReaddir(targetPath: string): Promise<string[]> {
|
|
|
385
385
|
|
|
386
386
|
//#endregion
|
|
387
387
|
|
|
388
|
-
//#region
|
|
388
|
+
//#region File Information
|
|
389
389
|
|
|
390
390
|
/**
|
|
391
|
-
*
|
|
392
|
-
* @param targetPath -
|
|
391
|
+
* Gets file/directory information (follows symbolic links).
|
|
392
|
+
* @param targetPath - Path to query information for
|
|
393
393
|
*/
|
|
394
394
|
export function fsStatSync(targetPath: string): fs.Stats {
|
|
395
395
|
try {
|
|
@@ -400,8 +400,8 @@ export function fsStatSync(targetPath: string): fs.Stats {
|
|
|
400
400
|
}
|
|
401
401
|
|
|
402
402
|
/**
|
|
403
|
-
*
|
|
404
|
-
* @param targetPath -
|
|
403
|
+
* Gets file/directory information (follows symbolic links, asynchronous).
|
|
404
|
+
* @param targetPath - Path to query information for
|
|
405
405
|
*/
|
|
406
406
|
export async function fsStat(targetPath: string): Promise<fs.Stats> {
|
|
407
407
|
try {
|
|
@@ -412,8 +412,8 @@ export async function fsStat(targetPath: string): Promise<fs.Stats> {
|
|
|
412
412
|
}
|
|
413
413
|
|
|
414
414
|
/**
|
|
415
|
-
*
|
|
416
|
-
* @param targetPath -
|
|
415
|
+
* Gets file/directory information (does not follow symbolic links).
|
|
416
|
+
* @param targetPath - Path to query information for
|
|
417
417
|
*/
|
|
418
418
|
export function fsLstatSync(targetPath: string): fs.Stats {
|
|
419
419
|
try {
|
|
@@ -424,8 +424,8 @@ export function fsLstatSync(targetPath: string): fs.Stats {
|
|
|
424
424
|
}
|
|
425
425
|
|
|
426
426
|
/**
|
|
427
|
-
*
|
|
428
|
-
* @param targetPath -
|
|
427
|
+
* Gets file/directory information (does not follow symbolic links, asynchronous).
|
|
428
|
+
* @param targetPath - Path to query information for
|
|
429
429
|
*/
|
|
430
430
|
export async function fsLstat(targetPath: string): Promise<fs.Stats> {
|
|
431
431
|
try {
|
|
@@ -437,13 +437,13 @@ export async function fsLstat(targetPath: string): Promise<fs.Stats> {
|
|
|
437
437
|
|
|
438
438
|
//#endregion
|
|
439
439
|
|
|
440
|
-
//#region
|
|
440
|
+
//#region Glob
|
|
441
441
|
|
|
442
442
|
/**
|
|
443
|
-
*
|
|
444
|
-
* @param pattern -
|
|
445
|
-
* @param options - glob
|
|
446
|
-
* @returns
|
|
443
|
+
* Searches for files using a glob pattern.
|
|
444
|
+
* @param pattern - Glob pattern (e.g., "**\/*.ts")
|
|
445
|
+
* @param options - glob options
|
|
446
|
+
* @returns Array of absolute paths for matched files
|
|
447
447
|
*/
|
|
448
448
|
export function fsGlobSync(pattern: string, options?: GlobOptions): string[] {
|
|
449
449
|
return globRawSync(pattern.replace(/\\/g, "/"), options ?? {}).map((item) =>
|
|
@@ -452,10 +452,10 @@ export function fsGlobSync(pattern: string, options?: GlobOptions): string[] {
|
|
|
452
452
|
}
|
|
453
453
|
|
|
454
454
|
/**
|
|
455
|
-
*
|
|
456
|
-
* @param pattern -
|
|
457
|
-
* @param options - glob
|
|
458
|
-
* @returns
|
|
455
|
+
* Searches for files using a glob pattern (asynchronous).
|
|
456
|
+
* @param pattern - Glob pattern (e.g., "**\/*.ts")
|
|
457
|
+
* @param options - glob options
|
|
458
|
+
* @returns Array of absolute paths for matched files
|
|
459
459
|
*/
|
|
460
460
|
export async function fsGlob(pattern: string, options?: GlobOptions): Promise<string[]> {
|
|
461
461
|
return (await globRaw(pattern.replace(/\\/g, "/"), options ?? {})).map((item) =>
|
|
@@ -465,11 +465,11 @@ export async function fsGlob(pattern: string, options?: GlobOptions): Promise<st
|
|
|
465
465
|
|
|
466
466
|
//#endregion
|
|
467
467
|
|
|
468
|
-
//#region
|
|
468
|
+
//#region Utilities
|
|
469
469
|
|
|
470
470
|
/**
|
|
471
|
-
*
|
|
472
|
-
*
|
|
471
|
+
* Recursively searches and deletes empty directories under a specified directory.
|
|
472
|
+
* If all child directories are deleted and a parent becomes empty, it will also be deleted.
|
|
473
473
|
*/
|
|
474
474
|
export async function fsClearEmptyDirectory(dirPath: string): Promise<void> {
|
|
475
475
|
if (!(await fsExists(dirPath))) return;
|
|
@@ -486,23 +486,23 @@ export async function fsClearEmptyDirectory(dirPath: string): Promise<void> {
|
|
|
486
486
|
}
|
|
487
487
|
}
|
|
488
488
|
|
|
489
|
-
//
|
|
489
|
+
// If there are files, cannot delete
|
|
490
490
|
if (hasFiles) return;
|
|
491
491
|
|
|
492
|
-
//
|
|
492
|
+
// Only re-check if there were no files (child directories may have been deleted)
|
|
493
493
|
if ((await fsReaddir(dirPath)).length === 0) {
|
|
494
494
|
await fsRm(dirPath);
|
|
495
495
|
}
|
|
496
496
|
}
|
|
497
497
|
|
|
498
498
|
/**
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
* @param childGlob -
|
|
502
|
-
* @param fromPath -
|
|
503
|
-
* @param rootPath -
|
|
504
|
-
*
|
|
505
|
-
*
|
|
499
|
+
* Searches for files matching a glob pattern by traversing parent directories from a start path towards the root.
|
|
500
|
+
* Collects all file paths matching the childGlob pattern in each directory.
|
|
501
|
+
* @param childGlob - Glob pattern to search for in each directory
|
|
502
|
+
* @param fromPath - Path to start searching from
|
|
503
|
+
* @param rootPath - Path to stop searching at (if not specified, searches to filesystem root).
|
|
504
|
+
* **Note**: fromPath must be a child path of rootPath.
|
|
505
|
+
* Otherwise, searches to the filesystem root.
|
|
506
506
|
*/
|
|
507
507
|
export function fsFindAllParentChildPathsSync(
|
|
508
508
|
childGlob: string,
|
|
@@ -528,13 +528,13 @@ export function fsFindAllParentChildPathsSync(
|
|
|
528
528
|
}
|
|
529
529
|
|
|
530
530
|
/**
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
* @param childGlob -
|
|
534
|
-
* @param fromPath -
|
|
535
|
-
* @param rootPath -
|
|
536
|
-
*
|
|
537
|
-
*
|
|
531
|
+
* Searches for files matching a glob pattern by traversing parent directories from a start path towards the root (asynchronous).
|
|
532
|
+
* Collects all file paths matching the childGlob pattern in each directory.
|
|
533
|
+
* @param childGlob - Glob pattern to search for in each directory
|
|
534
|
+
* @param fromPath - Path to start searching from
|
|
535
|
+
* @param rootPath - Path to stop searching at (if not specified, searches to filesystem root).
|
|
536
|
+
* **Note**: fromPath must be a child path of rootPath.
|
|
537
|
+
* Otherwise, searches to the filesystem root.
|
|
538
538
|
*/
|
|
539
539
|
export async function fsFindAllParentChildPaths(
|
|
540
540
|
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
|
-
* pathNorm()
|
|
9
|
+
* Brand type representing a normalized path.
|
|
10
|
+
* Can only be created through pathNorm().
|
|
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 Functions
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* Converts to POSIX-style path (backslash → forward slash).
|
|
22
22
|
*
|
|
23
23
|
* @example
|
|
24
24
|
* pathPosix("C:\\Users\\test"); // "C:/Users/test"
|
|
@@ -30,13 +30,13 @@ export function pathPosix(...args: string[]): string {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Changes the directory of a file path.
|
|
34
34
|
*
|
|
35
35
|
* @example
|
|
36
36
|
* pathChangeFileDirectory("/a/b/c.txt", "/a", "/x");
|
|
37
37
|
* // → "/x/b/c.txt"
|
|
38
38
|
*
|
|
39
|
-
* @throws
|
|
39
|
+
* @throws Error if the file is not inside fromDirectory
|
|
40
40
|
*/
|
|
41
41
|
export function pathChangeFileDirectory(
|
|
42
42
|
filePath: string,
|
|
@@ -48,7 +48,7 @@ export function pathChangeFileDirectory(
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
if (!pathIsChildPath(filePath, fromDirectory)) {
|
|
51
|
-
throw new ArgumentError(`'${filePath}'
|
|
51
|
+
throw new ArgumentError(`'${filePath}' is not inside ${fromDirectory}.`, {
|
|
52
52
|
filePath,
|
|
53
53
|
fromDirectory,
|
|
54
54
|
});
|
|
@@ -58,7 +58,7 @@ export function pathChangeFileDirectory(
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
*
|
|
61
|
+
* Returns the filename (basename) without extension.
|
|
62
62
|
*
|
|
63
63
|
* @example
|
|
64
64
|
* pathBasenameWithoutExt("file.txt"); // "file"
|
|
@@ -69,27 +69,27 @@ export function pathBasenameWithoutExt(filePath: string): string {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
|
-
* childPath
|
|
73
|
-
*
|
|
72
|
+
* Checks if childPath is a child path of parentPath.
|
|
73
|
+
* Returns false if the paths are the same.
|
|
74
74
|
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
75
|
+
* Paths are internally normalized using `pathNorm()` and compared using
|
|
76
|
+
* platform-specific path separators (Windows: `\`, Unix: `/`).
|
|
77
77
|
*
|
|
78
78
|
* @example
|
|
79
79
|
* pathIsChildPath("/a/b/c", "/a/b"); // true
|
|
80
80
|
* pathIsChildPath("/a/b", "/a/b/c"); // false
|
|
81
|
-
* pathIsChildPath("/a/b", "/a/b"); // false (
|
|
81
|
+
* pathIsChildPath("/a/b", "/a/b"); // false (same path)
|
|
82
82
|
*/
|
|
83
83
|
export function pathIsChildPath(childPath: string, parentPath: string): boolean {
|
|
84
84
|
const normalizedChild = pathNorm(childPath);
|
|
85
85
|
const normalizedParent = pathNorm(parentPath);
|
|
86
86
|
|
|
87
|
-
//
|
|
87
|
+
// Same path returns false
|
|
88
88
|
if (normalizedChild === normalizedParent) {
|
|
89
89
|
return false;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
//
|
|
92
|
+
// Check if it starts with parent path + separator
|
|
93
93
|
const parentWithSep = normalizedParent.endsWith(path.sep)
|
|
94
94
|
? normalizedParent
|
|
95
95
|
: normalizedParent + path.sep;
|
|
@@ -98,27 +98,27 @@ export function pathIsChildPath(childPath: string, parentPath: string): boolean
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
101
|
+
* Normalizes the path and returns it as NormPath.
|
|
102
|
+
* Converts to absolute path and normalizes using platform-specific separators.
|
|
103
103
|
*
|
|
104
104
|
* @example
|
|
105
105
|
* pathNorm("/some/path"); // NormPath
|
|
106
|
-
* pathNorm("relative", "path"); // NormPath (
|
|
106
|
+
* pathNorm("relative", "path"); // NormPath (converted to absolute path)
|
|
107
107
|
*/
|
|
108
108
|
export function pathNorm(...paths: string[]): NormPath {
|
|
109
109
|
return path.resolve(...paths) as NormPath;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
113
|
+
* Filters files based on a list of target paths.
|
|
114
|
+
* Includes files that match or are children of a target path.
|
|
115
115
|
*
|
|
116
|
-
* @param files -
|
|
117
|
-
*
|
|
118
|
-
* cwd
|
|
119
|
-
* @param targets -
|
|
120
|
-
* @param cwd -
|
|
121
|
-
* @returns targets
|
|
116
|
+
* @param files - File paths to filter.
|
|
117
|
+
* **Note**: Must be absolute paths under cwd.
|
|
118
|
+
* Paths outside cwd are converted to relative paths (../) for processing.
|
|
119
|
+
* @param targets - Target paths (relative to cwd, POSIX style recommended)
|
|
120
|
+
* @param cwd - Current working directory (absolute path)
|
|
121
|
+
* @returns If targets is empty, returns files as-is; otherwise returns only files under target paths
|
|
122
122
|
*
|
|
123
123
|
* @example
|
|
124
124
|
* const files = ["/proj/src/a.ts", "/proj/src/b.ts", "/proj/tests/c.ts"];
|
|
@@ -2,18 +2,18 @@ import { parentPort } from "worker_threads";
|
|
|
2
2
|
import { SdError, transferableDecode, transferableEncode } from "@simplysm/core-common";
|
|
3
3
|
import type { WorkerRequest, WorkerResponse } from "./types";
|
|
4
4
|
|
|
5
|
-
//#region
|
|
5
|
+
//#region createWorker
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Worker factory for use in worker threads.
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
|
-
* //
|
|
11
|
+
* // Worker without events
|
|
12
12
|
* export default createWorker({
|
|
13
13
|
* add: (a: number, b: number) => a + b,
|
|
14
14
|
* });
|
|
15
15
|
*
|
|
16
|
-
* //
|
|
16
|
+
* // Worker with events
|
|
17
17
|
* interface MyEvents { progress: number; }
|
|
18
18
|
* const methods = {
|
|
19
19
|
* calc: (x: number) => { sender.send("progress", 50); return x * 2; },
|
|
@@ -32,13 +32,13 @@ export function createWorker<
|
|
|
32
32
|
__events: TEvents;
|
|
33
33
|
} {
|
|
34
34
|
if (parentPort === null) {
|
|
35
|
-
throw new SdError("
|
|
35
|
+
throw new SdError("This script must be executed in a worker thread (parentPort required).");
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
const port = parentPort;
|
|
39
39
|
|
|
40
|
-
// Worker
|
|
41
|
-
// stdout.write
|
|
40
|
+
// Worker thread's stdout is not automatically forwarded to the main thread
|
|
41
|
+
// Intercept stdout.write and forward it to the main thread via message protocol
|
|
42
42
|
process.stdout.write = (
|
|
43
43
|
chunk: string | Uint8Array,
|
|
44
44
|
encodingOrCallback?: BufferEncoding | ((err?: Error) => void),
|
|
@@ -60,7 +60,7 @@ export function createWorker<
|
|
|
60
60
|
port.on("message", async (serializedRequest: unknown) => {
|
|
61
61
|
const decoded = transferableDecode(serializedRequest);
|
|
62
62
|
|
|
63
|
-
//
|
|
63
|
+
// Validate request structure
|
|
64
64
|
if (
|
|
65
65
|
decoded == null ||
|
|
66
66
|
typeof decoded !== "object" ||
|
|
@@ -77,7 +77,7 @@ export function createWorker<
|
|
|
77
77
|
const errorResponse: WorkerResponse = {
|
|
78
78
|
type: "error",
|
|
79
79
|
request: { id: "unknown", method: "unknown", params: [] },
|
|
80
|
-
body: new SdError(
|
|
80
|
+
body: new SdError(`Invalid worker request format: ${decodedStr}`),
|
|
81
81
|
};
|
|
82
82
|
const serialized = transferableEncode(errorResponse);
|
|
83
83
|
port.postMessage(serialized.result, serialized.transferList);
|
|
@@ -91,7 +91,7 @@ export function createWorker<
|
|
|
91
91
|
const response: WorkerResponse = {
|
|
92
92
|
request,
|
|
93
93
|
type: "error",
|
|
94
|
-
body: new SdError(
|
|
94
|
+
body: new SdError(`Unknown method: ${request.method}`),
|
|
95
95
|
};
|
|
96
96
|
|
|
97
97
|
const serialized = transferableEncode(response);
|