@simplysm/core-node 13.0.99 → 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.
Files changed (41) hide show
  1. package/dist/features/fs-watcher.d.ts +21 -21
  2. package/dist/features/fs-watcher.d.ts.map +1 -1
  3. package/dist/features/fs-watcher.js +176 -114
  4. package/dist/features/fs-watcher.js.map +1 -6
  5. package/dist/index.js +6 -7
  6. package/dist/index.js.map +1 -6
  7. package/dist/utils/fs.d.ts +96 -96
  8. package/dist/utils/fs.d.ts.map +1 -1
  9. package/dist/utils/fs.js +437 -272
  10. package/dist/utils/fs.js.map +1 -6
  11. package/dist/utils/path.d.ts +22 -22
  12. package/dist/utils/path.js +103 -45
  13. package/dist/utils/path.js.map +1 -6
  14. package/dist/worker/create-worker.d.ts +3 -3
  15. package/dist/worker/create-worker.js +106 -81
  16. package/dist/worker/create-worker.js.map +1 -6
  17. package/dist/worker/types.d.ts +14 -14
  18. package/dist/worker/types.js +4 -1
  19. package/dist/worker/types.js.map +1 -6
  20. package/dist/worker/worker.d.ts +5 -5
  21. package/dist/worker/worker.js +168 -132
  22. package/dist/worker/worker.js.map +1 -6
  23. package/lib/worker-dev-proxy.js +15 -0
  24. package/package.json +8 -6
  25. package/src/features/fs-watcher.ts +53 -42
  26. package/src/index.ts +3 -3
  27. package/src/utils/fs.ts +111 -120
  28. package/src/utils/path.ts +26 -26
  29. package/src/worker/create-worker.ts +10 -10
  30. package/src/worker/types.ts +14 -14
  31. package/src/worker/worker.ts +29 -29
  32. package/README.md +0 -112
  33. package/docs/features.md +0 -91
  34. package/docs/fs.md +0 -309
  35. package/docs/path.md +0 -120
  36. package/docs/worker.md +0 -168
  37. package/tests/utils/fs-watcher.spec.ts +0 -286
  38. package/tests/utils/fs.spec.ts +0 -705
  39. package/tests/utils/path.spec.ts +0 -179
  40. package/tests/worker/fixtures/test-worker.ts +0 -35
  41. package/tests/worker/sd-worker.spec.ts +0 -174
@@ -1,705 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
- import path from "path";
3
- import fs from "fs";
4
- import os from "os";
5
- import {
6
- existsSync,
7
- exists,
8
- mkdirSync,
9
- mkdir,
10
- rmSync,
11
- rm,
12
- copySync,
13
- copy,
14
- readSync,
15
- read,
16
- readBufferSync,
17
- readBuffer,
18
- readJsonSync,
19
- readJson,
20
- writeSync,
21
- write,
22
- writeJsonSync,
23
- writeJson,
24
- readdirSync,
25
- readdir,
26
- statSync,
27
- stat,
28
- lstatSync,
29
- lstat,
30
- globSync,
31
- glob,
32
- clearEmptyDirectory,
33
- findAllParentChildPathsSync,
34
- findAllParentChildPaths,
35
- } from "../../src/utils/fs";
36
- import { SdError } from "@simplysm/core-common";
37
-
38
- describe("fs functions", () => {
39
- const testDir = path.join(os.tmpdir(), "fs-utils-test-" + Date.now());
40
-
41
- beforeEach(() => {
42
- fs.mkdirSync(testDir, { recursive: true });
43
- });
44
-
45
- afterEach(() => {
46
- fs.rmSync(testDir, { recursive: true, force: true });
47
- });
48
-
49
- //#region exists
50
-
51
- describe("existsSync", () => {
52
- it("returns true for existing file", () => {
53
- const filePath = path.join(testDir, "test.txt");
54
- fs.writeFileSync(filePath, "test");
55
-
56
- expect(existsSync(filePath)).toBe(true);
57
- });
58
-
59
- it("returns false for nonexistent file", () => {
60
- const filePath = path.join(testDir, "nonexistent.txt");
61
- expect(existsSync(filePath)).toBe(false);
62
- });
63
-
64
- });
65
-
66
- describe("exists", () => {
67
- it("returns true for existing file", async () => {
68
- const filePath = path.join(testDir, "test.txt");
69
- fs.writeFileSync(filePath, "test");
70
-
71
- expect(await exists(filePath)).toBe(true);
72
- });
73
-
74
- it("returns false for nonexistent file", async () => {
75
- const filePath = path.join(testDir, "nonexistent.txt");
76
- expect(await exists(filePath)).toBe(false);
77
- });
78
-
79
- });
80
-
81
- //#endregion
82
-
83
- //#region mkdir
84
-
85
- describe("mkdirSync", () => {
86
- it("creates directory", () => {
87
- const dirPath = path.join(testDir, "newdir");
88
- mkdirSync(dirPath);
89
-
90
- expect(fs.existsSync(dirPath)).toBe(true);
91
- expect(fs.statSync(dirPath).isDirectory()).toBe(true);
92
- });
93
-
94
- it("creates nested directories (recursive)", () => {
95
- const dirPath = path.join(testDir, "a/b/c");
96
- mkdirSync(dirPath);
97
-
98
- expect(fs.existsSync(dirPath)).toBe(true);
99
- });
100
-
101
- it("passes without error for existing directory", () => {
102
- expect(() => mkdirSync(testDir)).not.toThrow();
103
- });
104
- });
105
-
106
- describe("mkdir", () => {
107
- it("creates directory asynchronously", async () => {
108
- const dirPath = path.join(testDir, "asyncdir");
109
- await mkdir(dirPath);
110
-
111
- expect(fs.existsSync(dirPath)).toBe(true);
112
- });
113
- });
114
-
115
- //#endregion
116
-
117
- //#region rm
118
-
119
- describe("rmSync", () => {
120
- it("deletes file", () => {
121
- const filePath = path.join(testDir, "todelete.txt");
122
- fs.writeFileSync(filePath, "test");
123
-
124
- rmSync(filePath);
125
-
126
- expect(fs.existsSync(filePath)).toBe(false);
127
- });
128
-
129
- it("deletes directory (recursive)", () => {
130
- const dirPath = path.join(testDir, "todelete");
131
- fs.mkdirSync(dirPath);
132
- fs.writeFileSync(path.join(dirPath, "file.txt"), "test");
133
-
134
- rmSync(dirPath);
135
-
136
- expect(fs.existsSync(dirPath)).toBe(false);
137
- });
138
-
139
- it("passes without error for nonexistent path", () => {
140
- expect(() => rmSync(path.join(testDir, "nonexistent"))).not.toThrow();
141
- });
142
- });
143
-
144
- describe("rm", () => {
145
- it("deletes file asynchronously", async () => {
146
- const filePath = path.join(testDir, "asyncdelete.txt");
147
- fs.writeFileSync(filePath, "test");
148
-
149
- await rm(filePath);
150
-
151
- expect(fs.existsSync(filePath)).toBe(false);
152
- });
153
- });
154
-
155
- //#endregion
156
-
157
- //#region read/write
158
-
159
- describe("readSync", () => {
160
- it("reads file content as UTF-8 string", () => {
161
- const filePath = path.join(testDir, "read.txt");
162
- fs.writeFileSync(filePath, "Hello, World!");
163
-
164
- const content = readSync(filePath);
165
-
166
- expect(content).toBe("Hello, World!");
167
- });
168
-
169
- });
170
-
171
- describe("read", () => {
172
- it("reads file asynchronously", async () => {
173
- const filePath = path.join(testDir, "asyncread.txt");
174
- fs.writeFileSync(filePath, "async content");
175
-
176
- const content = await read(filePath);
177
-
178
- expect(content).toBe("async content");
179
- });
180
- });
181
-
182
- describe("readBufferSync", () => {
183
- it("reads file as Buffer", () => {
184
- const filePath = path.join(testDir, "buffer.txt");
185
- fs.writeFileSync(filePath, "buffer content");
186
-
187
- const buffer = readBufferSync(filePath);
188
-
189
- expect(buffer instanceof Uint8Array).toBe(true);
190
- expect(buffer.toString()).toBe("buffer content");
191
- });
192
- });
193
-
194
- describe("readBuffer", () => {
195
- it("reads file as Buffer asynchronously", async () => {
196
- const filePath = path.join(testDir, "asyncbuffer.txt");
197
- fs.writeFileSync(filePath, "async buffer content");
198
-
199
- const buffer = await readBuffer(filePath);
200
-
201
- expect(buffer instanceof Uint8Array).toBe(true);
202
- expect(buffer.toString()).toBe("async buffer content");
203
- });
204
- });
205
-
206
- describe("writeSync", () => {
207
- it("writes string to file", () => {
208
- const filePath = path.join(testDir, "write.txt");
209
-
210
- writeSync(filePath, "written content");
211
-
212
- expect(fs.readFileSync(filePath, "utf-8")).toBe("written content");
213
- });
214
-
215
- it("writes Buffer to file", () => {
216
- const filePath = path.join(testDir, "buffer-write.bin");
217
- const buffer = new Uint8Array([0x00, 0x01, 0x02, 0xff]);
218
-
219
- writeSync(filePath, buffer);
220
-
221
- expect(new Uint8Array(fs.readFileSync(filePath))).toEqual(buffer);
222
- });
223
-
224
- it("auto-creates parent directory if missing", () => {
225
- const filePath = path.join(testDir, "sub/dir/write.txt");
226
-
227
- writeSync(filePath, "nested content");
228
-
229
- expect(fs.readFileSync(filePath, "utf-8")).toBe("nested content");
230
- });
231
- });
232
-
233
- describe("write", () => {
234
- it("writes file asynchronously", async () => {
235
- const filePath = path.join(testDir, "asyncwrite.txt");
236
-
237
- await write(filePath, "async written");
238
-
239
- expect(fs.readFileSync(filePath, "utf-8")).toBe("async written");
240
- });
241
- });
242
-
243
- //#endregion
244
-
245
- //#region JSON
246
-
247
- describe("readJsonSync", () => {
248
- it("reads JSON file", () => {
249
- const filePath = path.join(testDir, "data.json");
250
- fs.writeFileSync(filePath, '{"name": "test", "value": 42}');
251
-
252
- const data = readJsonSync<{ name: string; value: number }>(filePath);
253
-
254
- expect(data).toEqual({ name: "test", value: 42 });
255
- });
256
-
257
- it("includes truncated content when reading invalid JSON with over 500 characters", () => {
258
- const filePath = path.join(testDir, "long-invalid.json");
259
- const longContent = "{ invalid " + "x".repeat(600) + " }";
260
- fs.writeFileSync(filePath, longContent);
261
-
262
- try {
263
- readJsonSync(filePath);
264
- expect.fail("Should throw error");
265
- } catch (err) {
266
- expect((err as Error).message).toContain("...(truncated)");
267
- }
268
- });
269
- });
270
-
271
- describe("writeJsonSync", () => {
272
- it("writes JSON file", () => {
273
- const filePath = path.join(testDir, "output.json");
274
- const data = { name: "test", value: 42 };
275
-
276
- writeJsonSync(filePath, data);
277
-
278
- const content = JSON.parse(fs.readFileSync(filePath, "utf-8")) as unknown;
279
- expect(content).toEqual(data);
280
- });
281
-
282
- it("writes JSON file with formatting", () => {
283
- const filePath = path.join(testDir, "formatted.json");
284
- const data = { name: "test" };
285
-
286
- writeJsonSync(filePath, data, { space: 2 });
287
-
288
- const content = fs.readFileSync(filePath, "utf-8");
289
- expect(content).toContain("\n");
290
- });
291
-
292
- it("writes JSON file with replacer option", () => {
293
- const filePath = path.join(testDir, "replaced.json");
294
- const data = { name: "test", secret: "hidden" };
295
-
296
- writeJsonSync(filePath, data, {
297
- replacer: (_key, value) =>
298
- typeof value === "string" && value === "hidden" ? undefined : value,
299
- });
300
-
301
- const content = JSON.parse(fs.readFileSync(filePath, "utf-8")) as Record<string, unknown>;
302
- expect(content).toEqual({ name: "test" });
303
- expect(content["secret"]).toBeUndefined();
304
- });
305
- });
306
-
307
- describe("readJson", () => {
308
- it("reads JSON file asynchronously", async () => {
309
- const filePath = path.join(testDir, "asyncdata.json");
310
- fs.writeFileSync(filePath, '{"name": "async", "value": 100}');
311
-
312
- const data = await readJson<{ name: string; value: number }>(filePath);
313
-
314
- expect(data).toEqual({ name: "async", value: 100 });
315
- });
316
- });
317
-
318
- describe("writeJson", () => {
319
- it("writes JSON file asynchronously", async () => {
320
- const filePath = path.join(testDir, "asyncoutput.json");
321
- const data = { name: "async", value: 100 };
322
-
323
- await writeJson(filePath, data);
324
-
325
- const content = JSON.parse(fs.readFileSync(filePath, "utf-8")) as unknown;
326
- expect(content).toEqual(data);
327
- });
328
- });
329
-
330
- //#endregion
331
-
332
- //#region copy
333
-
334
- describe("copySync", () => {
335
- it("copies file", () => {
336
- const source = path.join(testDir, "source.txt");
337
- const target = path.join(testDir, "target.txt");
338
- fs.writeFileSync(source, "source content");
339
-
340
- copySync(source, target);
341
-
342
- expect(fs.readFileSync(target, "utf-8")).toBe("source content");
343
- });
344
-
345
- it("copies directory (recursive)", () => {
346
- const sourceDir = path.join(testDir, "sourceDir");
347
- const targetDir = path.join(testDir, "targetDir");
348
- fs.mkdirSync(sourceDir);
349
- fs.writeFileSync(path.join(sourceDir, "file.txt"), "content");
350
- fs.mkdirSync(path.join(sourceDir, "sub"));
351
- fs.writeFileSync(path.join(sourceDir, "sub/nested.txt"), "nested");
352
-
353
- copySync(sourceDir, targetDir);
354
-
355
- expect(fs.existsSync(path.join(targetDir, "file.txt"))).toBe(true);
356
- expect(fs.existsSync(path.join(targetDir, "sub/nested.txt"))).toBe(true);
357
- });
358
-
359
- it("ignores nonexistent source", () => {
360
- const source = path.join(testDir, "nonexistent");
361
- const target = path.join(testDir, "target");
362
-
363
- expect(() => copySync(source, target)).not.toThrow();
364
- });
365
-
366
- it("selectively copies with filter option", () => {
367
- const sourceDir = path.join(testDir, "filterSource");
368
- const targetDir = path.join(testDir, "filterTarget");
369
- fs.mkdirSync(sourceDir);
370
- fs.writeFileSync(path.join(sourceDir, "include.txt"), "include");
371
- fs.writeFileSync(path.join(sourceDir, "exclude.log"), "exclude");
372
-
373
- copySync(sourceDir, targetDir, (p) => !p.endsWith(".log"));
374
-
375
- expect(fs.existsSync(path.join(targetDir, "include.txt"))).toBe(true);
376
- expect(fs.existsSync(path.join(targetDir, "exclude.log"))).toBe(false);
377
- });
378
-
379
- it("skips subdirectories and items when filter excludes directory", () => {
380
- const sourceDir = path.join(testDir, "filterDirSource");
381
- const targetDir = path.join(testDir, "filterDirTarget");
382
- fs.mkdirSync(sourceDir);
383
- fs.mkdirSync(path.join(sourceDir, "excluded"));
384
- fs.mkdirSync(path.join(sourceDir, "included"));
385
- fs.writeFileSync(path.join(sourceDir, "excluded", "nested.txt"), "nested");
386
- fs.writeFileSync(path.join(sourceDir, "included", "nested.txt"), "nested");
387
-
388
- copySync(sourceDir, targetDir, (p) => !p.includes("excluded"));
389
-
390
- expect(fs.existsSync(path.join(targetDir, "excluded"))).toBe(false);
391
- expect(fs.existsSync(path.join(targetDir, "excluded", "nested.txt"))).toBe(false);
392
- expect(fs.existsSync(path.join(targetDir, "included"))).toBe(true);
393
- expect(fs.existsSync(path.join(targetDir, "included", "nested.txt"))).toBe(true);
394
- });
395
- });
396
-
397
- describe("copy", () => {
398
- it("copies file asynchronously", async () => {
399
- const source = path.join(testDir, "asyncSource.txt");
400
- const target = path.join(testDir, "asyncTarget.txt");
401
- fs.writeFileSync(source, "async source content");
402
-
403
- await copy(source, target);
404
-
405
- expect(fs.readFileSync(target, "utf-8")).toBe("async source content");
406
- });
407
-
408
- it("selectively copies with filter option asynchronously", async () => {
409
- const sourceDir = path.join(testDir, "asyncFilterSource");
410
- const targetDir = path.join(testDir, "asyncFilterTarget");
411
- fs.mkdirSync(sourceDir);
412
- fs.writeFileSync(path.join(sourceDir, "keep.ts"), "keep");
413
- fs.writeFileSync(path.join(sourceDir, "skip.js"), "skip");
414
-
415
- await copy(sourceDir, targetDir, (p) => p.endsWith(".ts"));
416
-
417
- expect(fs.existsSync(path.join(targetDir, "keep.ts"))).toBe(true);
418
- expect(fs.existsSync(path.join(targetDir, "skip.js"))).toBe(false);
419
- });
420
- });
421
-
422
- //#endregion
423
-
424
- //#region readdir
425
-
426
- describe("readdirSync", () => {
427
- it("reads directory contents", () => {
428
- fs.writeFileSync(path.join(testDir, "file1.txt"), "");
429
- fs.writeFileSync(path.join(testDir, "file2.txt"), "");
430
- fs.mkdirSync(path.join(testDir, "subdir"));
431
-
432
- const entries = readdirSync(testDir);
433
-
434
- expect(entries).toContain("file1.txt");
435
- expect(entries).toContain("file2.txt");
436
- expect(entries).toContain("subdir");
437
- });
438
- });
439
-
440
- describe("readdir", () => {
441
- it("reads directory contents asynchronously", async () => {
442
- fs.writeFileSync(path.join(testDir, "async1.txt"), "");
443
- fs.writeFileSync(path.join(testDir, "async2.txt"), "");
444
-
445
- const entries = await readdir(testDir);
446
-
447
- expect(entries).toContain("async1.txt");
448
- expect(entries).toContain("async2.txt");
449
- });
450
- });
451
-
452
- //#endregion
453
-
454
- //#region stat
455
-
456
- describe("statSync", () => {
457
- it("gets file information", () => {
458
- const filePath = path.join(testDir, "statfile.txt");
459
- fs.writeFileSync(filePath, "content");
460
-
461
- const result = statSync(filePath);
462
-
463
- expect(result.isFile()).toBe(true);
464
- expect(result.size).toBeGreaterThan(0);
465
- });
466
-
467
- });
468
-
469
- describe("stat", () => {
470
- it("gets file information asynchronously", async () => {
471
- const filePath = path.join(testDir, "asyncstatfile.txt");
472
- fs.writeFileSync(filePath, "async content");
473
-
474
- const result = await stat(filePath);
475
-
476
- expect(result.isFile()).toBe(true);
477
- expect(result.size).toBeGreaterThan(0);
478
- });
479
- });
480
-
481
- describe("lstatSync", () => {
482
- it("returns symbolic link information for symbolic links", () => {
483
- const targetPath = path.join(testDir, "target.txt");
484
- const linkPath = path.join(testDir, "link.txt");
485
- fs.writeFileSync(targetPath, "target content");
486
- fs.symlinkSync(targetPath, linkPath);
487
-
488
- const lstatResult = lstatSync(linkPath);
489
- const statResult = statSync(linkPath);
490
-
491
- // lstat returns information about the symbolic link itself
492
- expect(lstatResult.isSymbolicLink()).toBe(true);
493
- expect(lstatResult.isFile()).toBe(false);
494
-
495
- // stat returns information about the target of the link
496
- expect(statResult.isSymbolicLink()).toBe(false);
497
- expect(statResult.isFile()).toBe(true);
498
- });
499
- });
500
-
501
- describe("lstat", () => {
502
- it("returns symbolic link information asynchronously", async () => {
503
- const targetPath = path.join(testDir, "async-target.txt");
504
- const linkPath = path.join(testDir, "async-link.txt");
505
- fs.writeFileSync(targetPath, "target content");
506
- fs.symlinkSync(targetPath, linkPath);
507
-
508
- const lstatResult = await lstat(linkPath);
509
- const statResult = await stat(linkPath);
510
-
511
- // lstat returns information about the symbolic link itself
512
- expect(lstatResult.isSymbolicLink()).toBe(true);
513
- expect(lstatResult.isFile()).toBe(false);
514
-
515
- // stat returns information about the target of the link
516
- expect(statResult.isSymbolicLink()).toBe(false);
517
- expect(statResult.isFile()).toBe(true);
518
- });
519
- });
520
-
521
- //#endregion
522
-
523
- //#region glob
524
-
525
- describe("globSync", () => {
526
- it("searches files by glob pattern", () => {
527
- fs.writeFileSync(path.join(testDir, "a.txt"), "");
528
- fs.writeFileSync(path.join(testDir, "b.txt"), "");
529
- fs.writeFileSync(path.join(testDir, "c.js"), "");
530
-
531
- const txtFiles = globSync(path.join(testDir, "*.txt"));
532
-
533
- expect(txtFiles.length).toBe(2);
534
- expect(txtFiles.some((f) => f.endsWith("a.txt"))).toBe(true);
535
- expect(txtFiles.some((f) => f.endsWith("b.txt"))).toBe(true);
536
- });
537
-
538
- it("searches nested directories", () => {
539
- fs.mkdirSync(path.join(testDir, "nested"));
540
- fs.writeFileSync(path.join(testDir, "nested/deep.txt"), "");
541
-
542
- const files = globSync(path.join(testDir, "**/*.txt"));
543
-
544
- expect(files.some((f) => f.endsWith("deep.txt"))).toBe(true);
545
- });
546
-
547
- it("includes hidden files with dot: true option", () => {
548
- fs.writeFileSync(path.join(testDir, ".hidden"), "");
549
- fs.writeFileSync(path.join(testDir, "visible"), "");
550
-
551
- const withoutDot = globSync(path.join(testDir, "*"));
552
- const withDot = globSync(path.join(testDir, "*"), { dot: true });
553
-
554
- expect(withoutDot.some((f) => f.endsWith(".hidden"))).toBe(false);
555
- expect(withDot.some((f) => f.endsWith(".hidden"))).toBe(true);
556
- });
557
- });
558
-
559
- describe("glob", () => {
560
- it("searches files asynchronously by glob pattern", async () => {
561
- fs.writeFileSync(path.join(testDir, "async.txt"), "");
562
-
563
- const files = await glob(path.join(testDir, "*.txt"));
564
-
565
- expect(files.length).toBeGreaterThan(0);
566
- });
567
- });
568
-
569
- //#endregion
570
-
571
- //#region clearEmptyDirectoryAsync
572
-
573
- describe("clearEmptyDirectory", () => {
574
- it("recursively deletes empty directories", async () => {
575
- const emptyDir = path.join(testDir, "empty/nested/deep");
576
- fs.mkdirSync(emptyDir, { recursive: true });
577
-
578
- await clearEmptyDirectory(path.join(testDir, "empty"));
579
-
580
- expect(fs.existsSync(path.join(testDir, "empty"))).toBe(false);
581
- });
582
-
583
- it("keeps directories with files", async () => {
584
- const dirWithFile = path.join(testDir, "notempty");
585
- fs.mkdirSync(dirWithFile);
586
- fs.writeFileSync(path.join(dirWithFile, "file.txt"), "content");
587
-
588
- await clearEmptyDirectory(dirWithFile);
589
-
590
- expect(fs.existsSync(dirWithFile)).toBe(true);
591
- });
592
- });
593
-
594
- //#endregion
595
-
596
- //#region findAllParentChildPaths
597
-
598
- describe("findAllParentChildPathsSync", () => {
599
- it("finds specific file in parent directories", () => {
600
- const deepDir = path.join(testDir, "a/b/c");
601
- fs.mkdirSync(deepDir, { recursive: true });
602
- fs.writeFileSync(path.join(testDir, "marker.txt"), "");
603
- fs.writeFileSync(path.join(testDir, "a/marker.txt"), "");
604
-
605
- const results = findAllParentChildPathsSync("marker.txt", deepDir, testDir);
606
-
607
- expect(results.length).toBe(2);
608
- });
609
-
610
- it("returns empty array when no matching file is found", () => {
611
- const deepDir = path.join(testDir, "a/b/c");
612
- fs.mkdirSync(deepDir, { recursive: true });
613
-
614
- const results = findAllParentChildPathsSync("nonexistent-file.txt", deepDir, testDir);
615
-
616
- expect(results).toEqual([]);
617
- });
618
- });
619
-
620
- describe("findAllParentChildPaths", () => {
621
- it("finds specific file in parent directories asynchronously", async () => {
622
- const deepDir = path.join(testDir, "x/y/z");
623
- fs.mkdirSync(deepDir, { recursive: true });
624
- fs.writeFileSync(path.join(testDir, "config.json"), "");
625
- fs.writeFileSync(path.join(testDir, "x/config.json"), "");
626
-
627
- const results = await findAllParentChildPaths("config.json", deepDir, testDir);
628
-
629
- expect(results.length).toBe(2);
630
- });
631
-
632
- it("returns empty array asynchronously when no matching file is found", async () => {
633
- const deepDir = path.join(testDir, "x/y/z");
634
- fs.mkdirSync(deepDir, { recursive: true });
635
-
636
- const results = await findAllParentChildPaths("nonexistent-file.txt", deepDir, testDir);
637
-
638
- expect(results).toEqual([]);
639
- });
640
- });
641
-
642
- //#endregion
643
-
644
- //#region Error Cases
645
-
646
- describe("error cases", () => {
647
- it("includes path information in SdError when reading nonexistent file", () => {
648
- const filePath = path.join(testDir, "nonexistent.txt");
649
- expect(() => readSync(filePath)).toThrow(SdError);
650
- try {
651
- readSync(filePath);
652
- } catch (err) {
653
- expect((err as Error).message).toContain(filePath);
654
- }
655
- });
656
-
657
- it("includes path information in SdError when reading nonexistent file asynchronously", async () => {
658
- const filePath = path.join(testDir, "nonexistent.txt");
659
- await expect(read(filePath)).rejects.toThrow(SdError);
660
- try {
661
- await read(filePath);
662
- } catch (err) {
663
- expect((err as Error).message).toContain(filePath);
664
- }
665
- });
666
-
667
- it("throws error when reading nonexistent directory", () => {
668
- expect(() => readdirSync(path.join(testDir, "nonexistent"))).toThrow();
669
- });
670
-
671
- it("throws error when stat nonexistent file", () => {
672
- expect(() => statSync(path.join(testDir, "nonexistent.txt"))).toThrow();
673
- });
674
-
675
- it("includes path and content information in SdError when reading invalid JSON", () => {
676
- const filePath = path.join(testDir, "invalid.json");
677
- const content = "{ invalid json }";
678
- fs.writeFileSync(filePath, content);
679
-
680
- expect(() => readJsonSync(filePath)).toThrow(SdError);
681
- try {
682
- readJsonSync(filePath);
683
- } catch (err) {
684
- expect((err as Error).message).toContain(filePath);
685
- expect((err as Error).message).toContain(content);
686
- }
687
- });
688
-
689
- it("includes path and content information in SdError when reading invalid JSON asynchronously", async () => {
690
- const filePath = path.join(testDir, "invalid-async.json");
691
- const content = "{ invalid json }";
692
- fs.writeFileSync(filePath, content);
693
-
694
- await expect(readJson(filePath)).rejects.toThrow(SdError);
695
- try {
696
- await readJson(filePath);
697
- } catch (err) {
698
- expect((err as Error).message).toContain(filePath);
699
- expect((err as Error).message).toContain(content);
700
- }
701
- });
702
- });
703
-
704
- //#endregion
705
- });