ts-repo-utils 7.8.2 → 7.9.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 (62) hide show
  1. package/README.md +10 -0
  2. package/dist/cmd/assert-repo-is-clean.mjs +1 -1
  3. package/dist/cmd/assert-repo-is-clean.mjs.map +1 -1
  4. package/dist/cmd/check-should-run-type-checks.mjs +1 -1
  5. package/dist/cmd/check-should-run-type-checks.mjs.map +1 -1
  6. package/dist/cmd/format-diff-from.mjs +1 -1
  7. package/dist/cmd/format-diff-from.mjs.map +1 -1
  8. package/dist/cmd/format-uncommitted.mjs +1 -1
  9. package/dist/cmd/format-uncommitted.mjs.map +1 -1
  10. package/dist/cmd/gen-index-ts.mjs +1 -1
  11. package/dist/cmd/gen-index-ts.mjs.map +1 -1
  12. package/dist/entry-point.d.mts.map +1 -1
  13. package/dist/functions/assert-ext.d.mts.map +1 -1
  14. package/dist/functions/assert-ext.mjs.map +1 -1
  15. package/dist/functions/assert-path-exists.d.mts.map +1 -1
  16. package/dist/functions/assert-path-exists.mjs.map +1 -1
  17. package/dist/functions/assert-repo-is-clean.d.mts.map +1 -1
  18. package/dist/functions/assert-repo-is-clean.mjs.map +1 -1
  19. package/dist/functions/create-result-assert.d.mts.map +1 -1
  20. package/dist/functions/create-result-assert.mjs.map +1 -1
  21. package/dist/functions/exec-async.mjs.map +1 -1
  22. package/dist/functions/format.d.mts +4 -4
  23. package/dist/functions/format.d.mts.map +1 -1
  24. package/dist/functions/format.mjs +6 -4
  25. package/dist/functions/format.mjs.map +1 -1
  26. package/dist/functions/gen-index.d.mts.map +1 -1
  27. package/dist/functions/gen-index.mjs.map +1 -1
  28. package/dist/functions/should-run.d.mts.map +1 -1
  29. package/dist/functions/should-run.mjs.map +1 -1
  30. package/dist/functions/workspace-utils/execute-parallel.d.mts.map +1 -1
  31. package/dist/functions/workspace-utils/execute-parallel.mjs.map +1 -1
  32. package/dist/functions/workspace-utils/get-workspace-packages.d.mts.map +1 -1
  33. package/dist/functions/workspace-utils/get-workspace-packages.mjs.map +1 -1
  34. package/dist/functions/workspace-utils/run-cmd-in-parallel.d.mts.map +1 -1
  35. package/dist/functions/workspace-utils/run-cmd-in-parallel.mjs.map +1 -1
  36. package/dist/functions/workspace-utils/run-cmd-in-stages.d.mts.map +1 -1
  37. package/dist/functions/workspace-utils/run-cmd-in-stages.mjs.map +1 -1
  38. package/dist/node-global.d.mts.map +1 -1
  39. package/package.json +17 -19
  40. package/src/cmd/assert-repo-is-clean.mts +2 -1
  41. package/src/cmd/check-should-run-type-checks.mts +2 -1
  42. package/src/cmd/format-diff-from.mts +2 -1
  43. package/src/cmd/format-uncommitted.mts +3 -1
  44. package/src/cmd/gen-index-ts.mts +8 -2
  45. package/src/entry-point.mts +1 -0
  46. package/src/functions/assert-ext.mts +4 -0
  47. package/src/functions/assert-path-exists.mts +2 -0
  48. package/src/functions/assert-repo-is-clean.mts +9 -0
  49. package/src/functions/create-result-assert.mts +1 -0
  50. package/src/functions/diff.test.mts +76 -0
  51. package/src/functions/exec-async.mts +4 -0
  52. package/src/functions/exec-async.test.mts +42 -0
  53. package/src/functions/format.mts +29 -7
  54. package/src/functions/format.test.mts +109 -0
  55. package/src/functions/gen-index.mts +16 -0
  56. package/src/functions/should-run.mts +2 -0
  57. package/src/functions/workspace-utils/execute-parallel.mts +23 -0
  58. package/src/functions/workspace-utils/get-workspace-packages.mts +5 -0
  59. package/src/functions/workspace-utils/run-cmd-in-parallel.mts +5 -0
  60. package/src/functions/workspace-utils/run-cmd-in-stages.mts +5 -0
  61. package/src/functions/workspace-utils/run-cmd-in-stages.test.mts +13 -0
  62. package/src/node-global.mts +7 -0
@@ -21,6 +21,7 @@ describe('diff', () => {
21
21
  ) => Promise<Result<{ stdout: string; stderr: string }, unknown>>;
22
22
  }> => {
23
23
  const tempDir = await fs.mkdtemp(path.join(tmpdir(), 'temp-repo-'));
24
+
24
25
  const repoPath = tempDir;
25
26
 
26
27
  // Initialize git repository
@@ -29,9 +30,12 @@ describe('diff', () => {
29
30
  options?: Readonly<{ silent?: boolean }>,
30
31
  ): Promise<ExecResult<string>> => {
31
32
  const originalCwd = process.cwd();
33
+
32
34
  process.chdir(repoPath);
35
+
33
36
  try {
34
37
  const result = await $(cmd, { silent: options?.silent ?? false });
38
+
35
39
  return result;
36
40
  } finally {
37
41
  process.chdir(originalCwd);
@@ -39,7 +43,9 @@ describe('diff', () => {
39
43
  };
40
44
 
41
45
  await execInRepo('git init', { silent: true });
46
+
42
47
  await execInRepo('git config user.name "Test User"', { silent: true });
48
+
43
49
  await execInRepo('git config user.email "test@example.com"', {
44
50
  silent: true,
45
51
  });
@@ -60,7 +66,9 @@ describe('diff', () => {
60
66
  const createRepoFunctions = (repoPath: string) => {
61
67
  const executeInRepo = async <T,>(fn: () => Promise<T>): Promise<T> => {
62
68
  const originalCwd = process.cwd();
69
+
63
70
  process.chdir(repoPath);
71
+
64
72
  try {
65
73
  return await fn();
66
74
  } finally {
@@ -85,6 +93,7 @@ describe('diff', () => {
85
93
  describe(getUntrackedFiles, () => {
86
94
  test('should return empty array when no files are changed', async () => {
87
95
  const { repoPath, cleanup } = await createTempRepo();
96
+
88
97
  const repoFunctions = createRepoFunctions(repoPath);
89
98
 
90
99
  try {
@@ -102,11 +111,13 @@ describe('diff', () => {
102
111
 
103
112
  test('should detect newly created files', async () => {
104
113
  const { repoPath, cleanup } = await createTempRepo();
114
+
105
115
  const repoFunctions = createRepoFunctions(repoPath);
106
116
 
107
117
  try {
108
118
  // Create a new file in the temp repository
109
119
  const testFileName = `test-new-file-${crypto.randomUUID()}.tmp`;
120
+
110
121
  const testFilePath = path.join(repoPath, testFileName);
111
122
 
112
123
  await fs.writeFile(testFilePath, 'test content');
@@ -127,11 +138,13 @@ describe('diff', () => {
127
138
 
128
139
  test('should detect modified existing files', async () => {
129
140
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
141
+
130
142
  const repoFunctions = createRepoFunctions(repoPath);
131
143
 
132
144
  try {
133
145
  // Create and track a file first
134
146
  const testFileName = `test-modify-file-${crypto.randomUUID()}.tmp`;
147
+
135
148
  const testFilePath = path.join(repoPath, testFileName);
136
149
 
137
150
  await fs.writeFile(testFilePath, 'initial content');
@@ -158,14 +171,19 @@ describe('diff', () => {
158
171
 
159
172
  test('should detect multiple types of changes', async () => {
160
173
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
174
+
161
175
  const repoFunctions = createRepoFunctions(repoPath);
162
176
 
163
177
  try {
164
178
  // Create multiple test files
165
179
  const uuid = crypto.randomUUID();
180
+
166
181
  const newFile = `test-new-file-${uuid}.tmp`;
182
+
167
183
  const modifyFile = `test-modify-file-${uuid}.tmp`;
184
+
168
185
  const newFilePath = path.join(repoPath, newFile);
186
+
169
187
  const modifyFilePath = path.join(repoPath, modifyFile);
170
188
 
171
189
  // Create new file
@@ -173,6 +191,7 @@ describe('diff', () => {
173
191
 
174
192
  // Create and track another file
175
193
  await fs.writeFile(modifyFilePath, 'initial content');
194
+
176
195
  await execInRepo(`git add ${modifyFile}`, { silent: true });
177
196
 
178
197
  // Modify the tracked file
@@ -186,6 +205,7 @@ describe('diff', () => {
186
205
  const files = result.value;
187
206
 
188
207
  expect(files).toContain(newFile);
208
+
189
209
  expect(files).not.toContain(modifyFile);
190
210
  }
191
211
  } finally {
@@ -195,6 +215,7 @@ describe('diff', () => {
195
215
 
196
216
  test('should exclude deleted files from results', async () => {
197
217
  const { repoPath, cleanup } = await createTempRepo();
218
+
198
219
  const repoFunctions = createRepoFunctions(repoPath);
199
220
 
200
221
  try {
@@ -204,6 +225,7 @@ describe('diff', () => {
204
225
 
205
226
  if (Result.isOk(result)) {
206
227
  const files = result.value;
228
+
207
229
  // Verify no deleted files are included (status 'D')
208
230
  for (const file of files) {
209
231
  expectTypeOf(file).toBeString();
@@ -218,6 +240,7 @@ describe('diff', () => {
218
240
 
219
241
  test('should handle git command errors gracefully', async () => {
220
242
  const { repoPath, cleanup } = await createTempRepo();
243
+
221
244
  const repoFunctions = createRepoFunctions(repoPath);
222
245
 
223
246
  try {
@@ -232,6 +255,7 @@ describe('diff', () => {
232
255
 
233
256
  test('should parse git status output correctly', async () => {
234
257
  const { repoPath, cleanup } = await createTempRepo();
258
+
235
259
  const repoFunctions = createRepoFunctions(repoPath);
236
260
 
237
261
  try {
@@ -247,6 +271,7 @@ describe('diff', () => {
247
271
  expectTypeOf(file).toBeString();
248
272
 
249
273
  expect(file.trim()).toBe(file); // No leading/trailing whitespace
274
+
250
275
  expect(file.length).toBeGreaterThan(0);
251
276
  }
252
277
  }
@@ -257,6 +282,7 @@ describe('diff', () => {
257
282
 
258
283
  test('should work with silent option', async () => {
259
284
  const { repoPath, cleanup } = await createTempRepo();
285
+
260
286
  const repoFunctions = createRepoFunctions(repoPath);
261
287
 
262
288
  try {
@@ -276,6 +302,7 @@ describe('diff', () => {
276
302
  describe(getStagedFiles, () => {
277
303
  test('should return empty array when no files are staged', async () => {
278
304
  const { repoPath, cleanup } = await createTempRepo();
305
+
279
306
  const repoFunctions = createRepoFunctions(repoPath);
280
307
 
281
308
  try {
@@ -293,13 +320,17 @@ describe('diff', () => {
293
320
 
294
321
  test('should detect staged files', async () => {
295
322
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
323
+
296
324
  const repoFunctions = createRepoFunctions(repoPath);
297
325
 
298
326
  try {
299
327
  // Create a new file
300
328
  const testFileName = `test-staged-file-${crypto.randomUUID()}.tmp`;
329
+
301
330
  const testFilePath = path.join(repoPath, testFileName);
331
+
302
332
  await fs.writeFile(testFilePath, 'staged file content');
333
+
303
334
  // Stage the file
304
335
  await execInRepo(`git add ${testFileName}`, { silent: true });
305
336
 
@@ -319,18 +350,25 @@ describe('diff', () => {
319
350
 
320
351
  test('should detect multiple staged files', async () => {
321
352
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
353
+
322
354
  const repoFunctions = createRepoFunctions(repoPath);
323
355
 
324
356
  try {
325
357
  // Create multiple test files
326
358
  const uuid = crypto.randomUUID();
359
+
327
360
  const file1 = `test-staged-file1-${uuid}.tmp`;
361
+
328
362
  const file2 = `test-staged-file2-${uuid}.tmp`;
363
+
329
364
  const filePath1 = path.join(repoPath, file1);
365
+
330
366
  const filePath2 = path.join(repoPath, file2);
331
367
 
332
368
  await fs.writeFile(filePath1, 'staged file 1 content');
369
+
333
370
  await fs.writeFile(filePath2, 'staged file 2 content');
371
+
334
372
  // Stage both files
335
373
  await execInRepo(`git add ${file1} ${file2}`, { silent: true });
336
374
 
@@ -342,6 +380,7 @@ describe('diff', () => {
342
380
  const files = result.value;
343
381
 
344
382
  expect(files).toContain(file1);
383
+
345
384
  expect(files).toContain(file2);
346
385
  }
347
386
  } finally {
@@ -351,15 +390,19 @@ describe('diff', () => {
351
390
 
352
391
  test('should exclude deleted files by default', async () => {
353
392
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
393
+
354
394
  const repoFunctions = createRepoFunctions(repoPath);
355
395
 
356
396
  try {
357
397
  const testFileName = `test-deleted-file-${crypto.randomUUID()}.tmp`;
398
+
358
399
  const testFilePath = path.join(repoPath, testFileName);
359
400
 
360
401
  // Create a file and commit it
361
402
  await fs.writeFile(testFilePath, 'file to be deleted');
403
+
362
404
  await execInRepo(`git add ${testFileName}`, { silent: true });
405
+
363
406
  await execInRepo(
364
407
  `git commit -m "Add test file for deletion" --no-verify`,
365
408
  {
@@ -369,6 +412,7 @@ describe('diff', () => {
369
412
 
370
413
  // Delete the file and stage the deletion
371
414
  await fs.rm(testFilePath, { force: true });
415
+
372
416
  await execInRepo(`git add ${testFileName}`, { silent: true });
373
417
 
374
418
  // Test with excludeDeleted = true (default)
@@ -389,6 +433,7 @@ describe('diff', () => {
389
433
  const gitStatusResult = await execInRepo(`git status --porcelain`, {
390
434
  silent: true,
391
435
  });
436
+
392
437
  const hasDeletion =
393
438
  Result.isOk(gitStatusResult) &&
394
439
  gitStatusResult.value.stdout.includes(`D ${testFileName}`);
@@ -419,6 +464,7 @@ describe('diff', () => {
419
464
 
420
465
  test('should parse staged files output correctly', async () => {
421
466
  const { repoPath, cleanup } = await createTempRepo();
467
+
422
468
  const repoFunctions = createRepoFunctions(repoPath);
423
469
 
424
470
  try {
@@ -428,6 +474,7 @@ describe('diff', () => {
428
474
 
429
475
  if (Result.isOk(result)) {
430
476
  const files = result.value;
477
+
431
478
  // Each file should be a non-empty string
432
479
  for (const file of files) {
433
480
  expectTypeOf(file).toBeString();
@@ -442,6 +489,7 @@ describe('diff', () => {
442
489
 
443
490
  test('should work with silent option', async () => {
444
491
  const { repoPath, cleanup } = await createTempRepo();
492
+
445
493
  const repoFunctions = createRepoFunctions(repoPath);
446
494
 
447
495
  try {
@@ -459,6 +507,7 @@ describe('diff', () => {
459
507
 
460
508
  test('should handle git command errors gracefully', async () => {
461
509
  const { repoPath, cleanup } = await createTempRepo();
510
+
462
511
  const repoFunctions = createRepoFunctions(repoPath);
463
512
 
464
513
  try {
@@ -475,6 +524,7 @@ describe('diff', () => {
475
524
  describe(getModifiedFiles, () => {
476
525
  test('should return empty array when no files are modified', async () => {
477
526
  const { repoPath, cleanup } = await createTempRepo();
527
+
478
528
  const repoFunctions = createRepoFunctions(repoPath);
479
529
 
480
530
  try {
@@ -492,15 +542,19 @@ describe('diff', () => {
492
542
 
493
543
  test('should detect modified files', async () => {
494
544
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
545
+
495
546
  const repoFunctions = createRepoFunctions(repoPath);
496
547
 
497
548
  try {
498
549
  // Create a new file and commit it first
499
550
  const testFileName = `test-modified-file-${crypto.randomUUID()}.tmp`;
551
+
500
552
  const testFilePath = path.join(repoPath, testFileName);
501
553
 
502
554
  await fs.writeFile(testFilePath, 'initial content');
555
+
503
556
  await execInRepo(`git add ${testFileName}`, { silent: true });
557
+
504
558
  await execInRepo(
505
559
  `git commit -m "Add file for modification test" --no-verify`,
506
560
  { silent: true },
@@ -525,19 +579,27 @@ describe('diff', () => {
525
579
 
526
580
  test('should detect multiple modified files', async () => {
527
581
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
582
+
528
583
  const repoFunctions = createRepoFunctions(repoPath);
529
584
 
530
585
  try {
531
586
  const uuid = crypto.randomUUID();
587
+
532
588
  const file1 = `test-modified-file1-${uuid}.tmp`;
589
+
533
590
  const file2 = `test-modified-file2-${uuid}.tmp`;
591
+
534
592
  const filePath1 = path.join(repoPath, file1);
593
+
535
594
  const filePath2 = path.join(repoPath, file2);
536
595
 
537
596
  // Create and commit both files
538
597
  await fs.writeFile(filePath1, 'initial content 1');
598
+
539
599
  await fs.writeFile(filePath2, 'initial content 2');
600
+
540
601
  await execInRepo(`git add ${file1} ${file2}`, { silent: true });
602
+
541
603
  await execInRepo(
542
604
  `git commit -m "Add files for modification test" --no-verify`,
543
605
  { silent: true },
@@ -545,6 +607,7 @@ describe('diff', () => {
545
607
 
546
608
  // Modify both files
547
609
  await fs.writeFile(filePath1, 'modified content 1');
610
+
548
611
  await fs.writeFile(filePath2, 'modified content 2');
549
612
 
550
613
  const result = await repoFunctions.getModifiedFiles({ silent: true });
@@ -555,6 +618,7 @@ describe('diff', () => {
555
618
  const files = result.value;
556
619
 
557
620
  expect(files).toContain(file1);
621
+
558
622
  expect(files).toContain(file2);
559
623
  }
560
624
  } finally {
@@ -564,15 +628,19 @@ describe('diff', () => {
564
628
 
565
629
  test('should exclude deleted files by default', async () => {
566
630
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
631
+
567
632
  const repoFunctions = createRepoFunctions(repoPath);
568
633
 
569
634
  try {
570
635
  const testFileName = `test-deleted-modified-file-${crypto.randomUUID()}.tmp`;
636
+
571
637
  const testFilePath = path.join(repoPath, testFileName);
572
638
 
573
639
  // Create a file and commit it
574
640
  await fs.writeFile(testFilePath, 'file to be deleted');
641
+
575
642
  await execInRepo(`git add ${testFileName}`, { silent: true });
643
+
576
644
  await execInRepo(
577
645
  `git commit -m "Add test file for deletion" --no-verify`,
578
646
  { silent: true },
@@ -614,6 +682,7 @@ describe('diff', () => {
614
682
 
615
683
  test('should parse modified files output correctly', async () => {
616
684
  const { repoPath, cleanup } = await createTempRepo();
685
+
617
686
  const repoFunctions = createRepoFunctions(repoPath);
618
687
 
619
688
  try {
@@ -623,6 +692,7 @@ describe('diff', () => {
623
692
 
624
693
  if (Result.isOk(result)) {
625
694
  const files = result.value;
695
+
626
696
  // Each file should be a non-empty string
627
697
  for (const file of files) {
628
698
  expectTypeOf(file).toBeString();
@@ -637,6 +707,7 @@ describe('diff', () => {
637
707
 
638
708
  test('should work with silent option', async () => {
639
709
  const { repoPath, cleanup } = await createTempRepo();
710
+
640
711
  const repoFunctions = createRepoFunctions(repoPath);
641
712
 
642
713
  try {
@@ -654,6 +725,7 @@ describe('diff', () => {
654
725
 
655
726
  test('should handle git command errors gracefully', async () => {
656
727
  const { repoPath, cleanup } = await createTempRepo();
728
+
657
729
  const repoFunctions = createRepoFunctions(repoPath);
658
730
 
659
731
  try {
@@ -670,15 +742,19 @@ describe('diff', () => {
670
742
  describe(getDiffFrom, () => {
671
743
  test('should work with silent option', async () => {
672
744
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
745
+
673
746
  const repoFunctions = createRepoFunctions(repoPath);
674
747
 
675
748
  try {
676
749
  // Create an initial commit to have something to diff against
677
750
  const testFileName = `test-initial-file-${crypto.randomUUID()}.tmp`;
751
+
678
752
  const testFilePath = path.join(repoPath, testFileName);
679
753
 
680
754
  await fs.writeFile(testFilePath, 'initial content');
755
+
681
756
  await execInRepo(`git add ${testFileName}`, { silent: true });
757
+
682
758
  await execInRepo(`git commit -m "Initial commit" --no-verify`, {
683
759
  silent: true,
684
760
  });
@@ -62,6 +62,7 @@ export function $(
62
62
  options?: ExecOptionsWithStringEncoding | ExecOptionsWithBufferEncoding,
63
63
  ): Promise<ExecResult<string | Buffer>> {
64
64
  const { silent = false, ...restOptions } = options ?? {};
65
+
65
66
  const normalizedOptions: NormalizedExecOptions = restOptions;
66
67
 
67
68
  if (!silent) {
@@ -79,6 +80,7 @@ export function $(
79
80
  if (!isEmpty(stdout)) {
80
81
  echo(stdout);
81
82
  }
83
+
82
84
  if (!isEmpty(stderr)) {
83
85
  console.error(stderr);
84
86
  }
@@ -86,6 +88,7 @@ export function $(
86
88
 
87
89
  if (error !== null) {
88
90
  resolve(Result.err(error));
91
+
89
92
  return;
90
93
  }
91
94
 
@@ -106,6 +109,7 @@ export function $(
106
109
  handleResult(error, stdout, stderr);
107
110
  },
108
111
  );
112
+
109
113
  return;
110
114
  }
111
115
 
@@ -10,10 +10,12 @@ describe('exec-async', () => {
10
10
  const withSilentEcho = async <T,>(fn: () => Promise<T>): Promise<T> => {
11
11
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
12
12
  const originalEcho = (globalThis as any).echo;
13
+
13
14
  // eslint-disable-next-line functional/immutable-data, @typescript-eslint/no-unsafe-member-access
14
15
  (globalThis as any).echo = () => {
15
16
  // Silent implementation - no output
16
17
  };
18
+
17
19
  try {
18
20
  return await fn();
19
21
  } finally {
@@ -30,6 +32,7 @@ describe('exec-async', () => {
30
32
 
31
33
  if (Result.isOk(result)) {
32
34
  expect(result.value.stdout.trim()).toBe('hello world');
35
+
33
36
  expect(result.value.stderr).toBe('');
34
37
  }
35
38
  });
@@ -41,6 +44,7 @@ describe('exec-async', () => {
41
44
 
42
45
  if (Result.isOk(result)) {
43
46
  expect(result.value.stdout.trim()).toBe('line1\nline2\nline3');
47
+
44
48
  expect(result.value.stderr).toBe('');
45
49
  }
46
50
  });
@@ -52,6 +56,7 @@ describe('exec-async', () => {
52
56
 
53
57
  if (Result.isOk(result)) {
54
58
  expect(result.value.stdout).toBe('');
59
+
55
60
  expect(result.value.stderr).toBe('');
56
61
  }
57
62
  });
@@ -65,6 +70,7 @@ describe('exec-async', () => {
65
70
 
66
71
  if (Result.isErr(result)) {
67
72
  expect(result.value).toBeDefined();
73
+
68
74
  expect(result.value.code).toBeDefined();
69
75
  }
70
76
  });
@@ -76,6 +82,7 @@ describe('exec-async', () => {
76
82
 
77
83
  if (Result.isErr(result)) {
78
84
  expect(result.value).toBeDefined();
85
+
79
86
  expect(result.value.code).toBe(1);
80
87
  }
81
88
  });
@@ -138,6 +145,7 @@ describe('exec-async', () => {
138
145
 
139
146
  if (Result.isOk(result)) {
140
147
  expect(Buffer.isBuffer(result.value.stdout)).toBe(true);
148
+
141
149
  expect(Buffer.isBuffer(result.value.stderr)).toBe(true);
142
150
  }
143
151
  });
@@ -149,6 +157,7 @@ describe('exec-async', () => {
149
157
 
150
158
  if (Result.isOk(result)) {
151
159
  expect(Buffer.isBuffer(result.value.stdout)).toBe(true);
160
+
152
161
  expect(Buffer.isBuffer(result.value.stderr)).toBe(true);
153
162
  }
154
163
  });
@@ -223,6 +232,7 @@ describe('exec-async', () => {
223
232
  if (Result.isOk(result)) {
224
233
  // These assignments will fail at compile time if types don't match
225
234
  assertType<string>(result.value.stdout);
235
+
226
236
  assertType<string>(result.value.stderr);
227
237
  }
228
238
  });
@@ -249,6 +259,7 @@ describe('exec-async', () => {
249
259
 
250
260
  if (Result.isOk(result)) {
251
261
  assertType<Buffer>(result.value.stdout);
262
+
252
263
  assertType<Buffer>(result.value.stderr);
253
264
  }
254
265
  });
@@ -263,6 +274,7 @@ describe('exec-async', () => {
263
274
 
264
275
  if (Result.isOk(result)) {
265
276
  assertType<Buffer>(result.value.stdout);
277
+
266
278
  assertType<Buffer>(result.value.stderr);
267
279
  }
268
280
  });
@@ -272,10 +284,12 @@ describe('exec-async', () => {
272
284
  encoding: 'utf8',
273
285
  silent: true,
274
286
  });
287
+
275
288
  const _resultAscii = await $('echo "test"', {
276
289
  encoding: 'ascii',
277
290
  silent: true,
278
291
  });
292
+
279
293
  const _resultBase64 = await $('echo "test"', {
280
294
  encoding: 'base64',
281
295
  silent: true,
@@ -299,17 +313,21 @@ describe('exec-async', () => {
299
313
 
300
314
  test('should maintain type safety with const encoding values', async () => {
301
315
  const bufferEncoding = 'buffer';
316
+
302
317
  const nullEncoding = null;
318
+
303
319
  const utf8Encoding = 'utf8';
304
320
 
305
321
  const _resultBuffer = await $('echo "test"', {
306
322
  encoding: bufferEncoding,
307
323
  silent: true,
308
324
  });
325
+
309
326
  const _resultNull = await $('echo "test"', {
310
327
  encoding: nullEncoding,
311
328
  silent: true,
312
329
  });
330
+
313
331
  const _resultUtf8 = await $('echo "test"', {
314
332
  encoding: utf8Encoding,
315
333
  silent: true,
@@ -365,12 +383,15 @@ describe('exec-async', () => {
365
383
  // Type check for native exec with default options
366
384
  exec('echo "test"', (error, stdout, stderr) => {
367
385
  expectType<ExecException | null, typeof error>('=');
386
+
368
387
  expectType<string, typeof stdout>('=');
388
+
369
389
  expectType<string, typeof stderr>('=');
370
390
  });
371
391
 
372
392
  // The $ function should produce the same types wrapped in Result (suppressed for clean output)
373
393
  const _resultPromise = withSilentEcho(async () => $('echo "test"'));
394
+
374
395
  expectType<
375
396
  typeof _resultPromise,
376
397
  Promise<
@@ -383,7 +404,9 @@ describe('exec-async', () => {
383
404
  // Type check for native exec with buffer encoding
384
405
  exec('echo "test"', { encoding: 'buffer' }, (error, stdout, stderr) => {
385
406
  expectType<ExecException | null, typeof error>('=');
407
+
386
408
  expectType<Buffer, typeof stdout>('>=');
409
+
387
410
  expectType<Buffer, typeof stderr>('>=');
388
411
  });
389
412
 
@@ -391,6 +414,7 @@ describe('exec-async', () => {
391
414
  const _resultPromise = withSilentEcho(async () =>
392
415
  $('echo "test"', { encoding: 'buffer' }),
393
416
  );
417
+
394
418
  expectType<
395
419
  typeof _resultPromise,
396
420
  Promise<
@@ -403,7 +427,9 @@ describe('exec-async', () => {
403
427
  // Type check for native exec with null encoding
404
428
  exec('echo "test"', { encoding: null }, (error, stdout, stderr) => {
405
429
  expectType<ExecException | null, typeof error>('=');
430
+
406
431
  expectType<Buffer, typeof stdout>('>=');
432
+
407
433
  expectType<Buffer, typeof stderr>('>=');
408
434
  });
409
435
 
@@ -411,6 +437,7 @@ describe('exec-async', () => {
411
437
  const _resultPromise = withSilentEcho(async () =>
412
438
  $('echo "test"', { encoding: null }),
413
439
  );
440
+
414
441
  expectType<
415
442
  typeof _resultPromise,
416
443
  Promise<
@@ -423,7 +450,9 @@ describe('exec-async', () => {
423
450
  // Type check for native exec with utf8 encoding
424
451
  exec('echo "test"', { encoding: 'utf8' }, (error, stdout, stderr) => {
425
452
  expectType<ExecException | null, typeof error>('=');
453
+
426
454
  expectType<string, typeof stdout>('=');
455
+
427
456
  expectType<string, typeof stderr>('=');
428
457
  });
429
458
 
@@ -431,6 +460,7 @@ describe('exec-async', () => {
431
460
  const _resultPromise = withSilentEcho(async () =>
432
461
  $('echo "test"', { encoding: 'utf8' }),
433
462
  );
463
+
434
464
  expectType<
435
465
  typeof _resultPromise,
436
466
  Promise<
@@ -446,7 +476,9 @@ describe('exec-async', () => {
446
476
  { encoding: 'utf8', timeout: 5000 },
447
477
  (error, stdout, stderr) => {
448
478
  expectType<ExecException | null, typeof error>('=');
479
+
449
480
  expectType<string, typeof stdout>('=');
481
+
450
482
  expectType<string, typeof stderr>('=');
451
483
  },
452
484
  );
@@ -456,6 +488,7 @@ describe('exec-async', () => {
456
488
  encoding: 'utf8',
457
489
  silent: true,
458
490
  });
491
+
459
492
  expectType<
460
493
  typeof _resultPromise,
461
494
  Promise<
@@ -503,17 +536,21 @@ describe('exec-async', () => {
503
536
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
504
537
  stderr: undefined as unknown as T,
505
538
  };
539
+
506
540
  return emptyParams;
507
541
  };
508
542
 
509
543
  // Default encoding comparison
510
544
  const _execDefault = captureExecTypes<string>();
545
+
511
546
  const $Default = await $('echo "test"', { silent: true });
547
+
512
548
  if (Result.isOk($Default)) {
513
549
  expectType<
514
550
  typeof _execDefault.stdout,
515
551
  typeof $Default.value.stdout
516
552
  >('=');
553
+
517
554
  expectType<
518
555
  typeof _execDefault.stderr,
519
556
  typeof $Default.value.stderr
@@ -522,14 +559,17 @@ describe('exec-async', () => {
522
559
 
523
560
  // Buffer encoding comparison
524
561
  const _execBuffer = captureExecTypes<Buffer>('buffer');
562
+
525
563
  const $Buffer = await $('echo "test"', {
526
564
  encoding: 'buffer',
527
565
  silent: true,
528
566
  });
567
+
529
568
  if (Result.isOk($Buffer)) {
530
569
  expectType<typeof _execBuffer.stdout, typeof $Buffer.value.stdout>(
531
570
  '=',
532
571
  );
572
+
533
573
  expectType<typeof _execBuffer.stderr, typeof $Buffer.value.stderr>(
534
574
  '=',
535
575
  );
@@ -542,7 +582,9 @@ describe('exec-async', () => {
542
582
  });
543
583
  } finally {
544
584
  consoleLogSpy.mockRestore();
585
+
545
586
  consoleErrorSpy.mockRestore();
587
+
546
588
  stderrWriteSpy.mockRestore();
547
589
  }
548
590
  });