ts-repo-utils 7.8.1 → 7.9.0

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 (73) hide show
  1. package/README.md +10 -0
  2. package/dist/cmd/assert-repo-is-clean.mjs +2 -1
  3. package/dist/cmd/assert-repo-is-clean.mjs.map +1 -1
  4. package/dist/cmd/check-should-run-type-checks.mjs +2 -1
  5. package/dist/cmd/check-should-run-type-checks.mjs.map +1 -1
  6. package/dist/cmd/format-diff-from.mjs +2 -1
  7. package/dist/cmd/format-diff-from.mjs.map +1 -1
  8. package/dist/cmd/format-uncommitted.mjs +2 -1
  9. package/dist/cmd/format-uncommitted.mjs.map +1 -1
  10. package/dist/cmd/gen-index-ts.mjs +2 -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 +0 -1
  14. package/dist/functions/assert-ext.d.mts.map +1 -1
  15. package/dist/functions/assert-ext.mjs.map +1 -1
  16. package/dist/functions/assert-path-exists.d.mts.map +1 -1
  17. package/dist/functions/assert-path-exists.mjs.map +1 -1
  18. package/dist/functions/assert-repo-is-clean.d.mts.map +1 -1
  19. package/dist/functions/assert-repo-is-clean.mjs.map +1 -1
  20. package/dist/functions/create-result-assert.d.mts +0 -1
  21. package/dist/functions/create-result-assert.d.mts.map +1 -1
  22. package/dist/functions/create-result-assert.mjs.map +1 -1
  23. package/dist/functions/diff.d.mts +0 -1
  24. package/dist/functions/diff.d.mts.map +1 -1
  25. package/dist/functions/exec-async.d.mts +0 -1
  26. package/dist/functions/exec-async.d.mts.map +1 -1
  27. package/dist/functions/exec-async.mjs.map +1 -1
  28. package/dist/functions/format.d.mts +4 -5
  29. package/dist/functions/format.d.mts.map +1 -1
  30. package/dist/functions/format.mjs +3 -3
  31. package/dist/functions/format.mjs.map +1 -1
  32. package/dist/functions/gen-index.d.mts +0 -1
  33. package/dist/functions/gen-index.d.mts.map +1 -1
  34. package/dist/functions/gen-index.mjs.map +1 -1
  35. package/dist/functions/should-run.d.mts.map +1 -1
  36. package/dist/functions/should-run.mjs.map +1 -1
  37. package/dist/functions/workspace-utils/execute-parallel.d.mts.map +1 -1
  38. package/dist/functions/workspace-utils/execute-parallel.mjs +4 -5
  39. package/dist/functions/workspace-utils/execute-parallel.mjs.map +1 -1
  40. package/dist/functions/workspace-utils/get-workspace-packages.d.mts.map +1 -1
  41. package/dist/functions/workspace-utils/get-workspace-packages.mjs.map +1 -1
  42. package/dist/functions/workspace-utils/run-cmd-in-parallel.d.mts.map +1 -1
  43. package/dist/functions/workspace-utils/run-cmd-in-parallel.mjs +2 -1
  44. package/dist/functions/workspace-utils/run-cmd-in-parallel.mjs.map +1 -1
  45. package/dist/functions/workspace-utils/run-cmd-in-stages.d.mts.map +1 -1
  46. package/dist/functions/workspace-utils/run-cmd-in-stages.mjs +2 -1
  47. package/dist/functions/workspace-utils/run-cmd-in-stages.mjs.map +1 -1
  48. package/dist/node-global.d.mts +0 -1
  49. package/dist/node-global.d.mts.map +1 -1
  50. package/package.json +25 -26
  51. package/src/cmd/assert-repo-is-clean.mts +2 -1
  52. package/src/cmd/check-should-run-type-checks.mts +2 -1
  53. package/src/cmd/format-diff-from.mts +2 -1
  54. package/src/cmd/format-uncommitted.mts +3 -1
  55. package/src/cmd/gen-index-ts.mts +8 -2
  56. package/src/entry-point.mts +1 -0
  57. package/src/functions/assert-ext.mts +4 -0
  58. package/src/functions/assert-path-exists.mts +2 -0
  59. package/src/functions/assert-repo-is-clean.mts +9 -0
  60. package/src/functions/create-result-assert.mts +1 -0
  61. package/src/functions/diff.test.mts +136 -8
  62. package/src/functions/exec-async.mts +4 -0
  63. package/src/functions/exec-async.test.mts +59 -2
  64. package/src/functions/format.mts +26 -7
  65. package/src/functions/format.test.mts +166 -9
  66. package/src/functions/gen-index.mts +16 -0
  67. package/src/functions/should-run.mts +2 -0
  68. package/src/functions/workspace-utils/execute-parallel.mts +27 -5
  69. package/src/functions/workspace-utils/get-workspace-packages.mts +5 -0
  70. package/src/functions/workspace-utils/run-cmd-in-parallel.mts +7 -1
  71. package/src/functions/workspace-utils/run-cmd-in-stages.mts +7 -1
  72. package/src/functions/workspace-utils/run-cmd-in-stages.test.mts +17 -3
  73. package/src/node-global.mts +7 -1
@@ -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 {
@@ -82,15 +90,17 @@ describe('diff', () => {
82
90
  };
83
91
  };
84
92
 
85
- describe('getUntrackedFiles', () => {
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 {
91
100
  const result = await repoFunctions.getUntrackedFiles({ silent: true });
92
101
 
93
102
  expect(Result.isOk(result)).toBe(true);
103
+
94
104
  if (Result.isOk(result)) {
95
105
  expect(Array.isArray(result.value)).toBe(true);
96
106
  }
@@ -101,11 +111,13 @@ describe('diff', () => {
101
111
 
102
112
  test('should detect newly created files', async () => {
103
113
  const { repoPath, cleanup } = await createTempRepo();
114
+
104
115
  const repoFunctions = createRepoFunctions(repoPath);
105
116
 
106
117
  try {
107
118
  // Create a new file in the temp repository
108
119
  const testFileName = `test-new-file-${crypto.randomUUID()}.tmp`;
120
+
109
121
  const testFilePath = path.join(repoPath, testFileName);
110
122
 
111
123
  await fs.writeFile(testFilePath, 'test content');
@@ -113,8 +125,10 @@ describe('diff', () => {
113
125
  const result = await repoFunctions.getUntrackedFiles({ silent: true });
114
126
 
115
127
  expect(Result.isOk(result)).toBe(true);
128
+
116
129
  if (Result.isOk(result)) {
117
130
  const files = result.value;
131
+
118
132
  expect(files).toContain(testFileName);
119
133
  }
120
134
  } finally {
@@ -124,11 +138,13 @@ describe('diff', () => {
124
138
 
125
139
  test('should detect modified existing files', async () => {
126
140
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
141
+
127
142
  const repoFunctions = createRepoFunctions(repoPath);
128
143
 
129
144
  try {
130
145
  // Create and track a file first
131
146
  const testFileName = `test-modify-file-${crypto.randomUUID()}.tmp`;
147
+
132
148
  const testFilePath = path.join(repoPath, testFileName);
133
149
 
134
150
  await fs.writeFile(testFilePath, 'initial content');
@@ -142,8 +158,10 @@ describe('diff', () => {
142
158
  const result = await repoFunctions.getUntrackedFiles({ silent: true });
143
159
 
144
160
  expect(Result.isOk(result)).toBe(true);
161
+
145
162
  if (Result.isOk(result)) {
146
163
  const files = result.value;
164
+
147
165
  expect(files).not.toContain(testFileName);
148
166
  }
149
167
  } finally {
@@ -153,14 +171,19 @@ describe('diff', () => {
153
171
 
154
172
  test('should detect multiple types of changes', async () => {
155
173
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
174
+
156
175
  const repoFunctions = createRepoFunctions(repoPath);
157
176
 
158
177
  try {
159
178
  // Create multiple test files
160
179
  const uuid = crypto.randomUUID();
180
+
161
181
  const newFile = `test-new-file-${uuid}.tmp`;
182
+
162
183
  const modifyFile = `test-modify-file-${uuid}.tmp`;
184
+
163
185
  const newFilePath = path.join(repoPath, newFile);
186
+
164
187
  const modifyFilePath = path.join(repoPath, modifyFile);
165
188
 
166
189
  // Create new file
@@ -168,6 +191,7 @@ describe('diff', () => {
168
191
 
169
192
  // Create and track another file
170
193
  await fs.writeFile(modifyFilePath, 'initial content');
194
+
171
195
  await execInRepo(`git add ${modifyFile}`, { silent: true });
172
196
 
173
197
  // Modify the tracked file
@@ -176,9 +200,12 @@ describe('diff', () => {
176
200
  const result = await repoFunctions.getUntrackedFiles({ silent: true });
177
201
 
178
202
  expect(Result.isOk(result)).toBe(true);
203
+
179
204
  if (Result.isOk(result)) {
180
205
  const files = result.value;
206
+
181
207
  expect(files).toContain(newFile);
208
+
182
209
  expect(files).not.toContain(modifyFile);
183
210
  }
184
211
  } finally {
@@ -188,17 +215,21 @@ describe('diff', () => {
188
215
 
189
216
  test('should exclude deleted files from results', async () => {
190
217
  const { repoPath, cleanup } = await createTempRepo();
218
+
191
219
  const repoFunctions = createRepoFunctions(repoPath);
192
220
 
193
221
  try {
194
222
  const result = await repoFunctions.getUntrackedFiles({ silent: true });
195
223
 
196
224
  expect(Result.isOk(result)).toBe(true);
225
+
197
226
  if (Result.isOk(result)) {
198
227
  const files = result.value;
228
+
199
229
  // Verify no deleted files are included (status 'D')
200
230
  for (const file of files) {
201
- expect(typeof file).toBe('string');
231
+ expectTypeOf(file).toBeString();
232
+
202
233
  expect(file.length).toBeGreaterThan(0);
203
234
  }
204
235
  }
@@ -209,6 +240,7 @@ describe('diff', () => {
209
240
 
210
241
  test('should handle git command errors gracefully', async () => {
211
242
  const { repoPath, cleanup } = await createTempRepo();
243
+
212
244
  const repoFunctions = createRepoFunctions(repoPath);
213
245
 
214
246
  try {
@@ -223,19 +255,23 @@ describe('diff', () => {
223
255
 
224
256
  test('should parse git status output correctly', async () => {
225
257
  const { repoPath, cleanup } = await createTempRepo();
258
+
226
259
  const repoFunctions = createRepoFunctions(repoPath);
227
260
 
228
261
  try {
229
262
  const result = await repoFunctions.getUntrackedFiles({ silent: true });
230
263
 
231
264
  expect(Result.isOk(result)).toBe(true);
265
+
232
266
  if (Result.isOk(result)) {
233
267
  const files = result.value;
234
268
 
235
269
  // Each file should be a non-empty string
236
270
  for (const file of files) {
237
- expect(typeof file).toBe('string');
271
+ expectTypeOf(file).toBeString();
272
+
238
273
  expect(file.trim()).toBe(file); // No leading/trailing whitespace
274
+
239
275
  expect(file.length).toBeGreaterThan(0);
240
276
  }
241
277
  }
@@ -246,12 +282,14 @@ describe('diff', () => {
246
282
 
247
283
  test('should work with silent option', async () => {
248
284
  const { repoPath, cleanup } = await createTempRepo();
285
+
249
286
  const repoFunctions = createRepoFunctions(repoPath);
250
287
 
251
288
  try {
252
289
  const result = await repoFunctions.getUntrackedFiles({ silent: true });
253
290
 
254
291
  expect(Result.isOk(result)).toBe(true);
292
+
255
293
  if (Result.isOk(result)) {
256
294
  expect(Array.isArray(result.value)).toBe(true);
257
295
  }
@@ -261,14 +299,17 @@ describe('diff', () => {
261
299
  });
262
300
  });
263
301
 
264
- describe('getStagedFiles', () => {
302
+ describe(getStagedFiles, () => {
265
303
  test('should return empty array when no files are staged', async () => {
266
304
  const { repoPath, cleanup } = await createTempRepo();
305
+
267
306
  const repoFunctions = createRepoFunctions(repoPath);
268
307
 
269
308
  try {
270
309
  const result = await repoFunctions.getStagedFiles({ silent: true });
310
+
271
311
  expect(Result.isOk(result)).toBe(true);
312
+
272
313
  if (Result.isOk(result)) {
273
314
  expect(Array.isArray(result.value)).toBe(true);
274
315
  }
@@ -279,20 +320,27 @@ describe('diff', () => {
279
320
 
280
321
  test('should detect staged files', async () => {
281
322
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
323
+
282
324
  const repoFunctions = createRepoFunctions(repoPath);
283
325
 
284
326
  try {
285
327
  // Create a new file
286
328
  const testFileName = `test-staged-file-${crypto.randomUUID()}.tmp`;
329
+
287
330
  const testFilePath = path.join(repoPath, testFileName);
331
+
288
332
  await fs.writeFile(testFilePath, 'staged file content');
333
+
289
334
  // Stage the file
290
335
  await execInRepo(`git add ${testFileName}`, { silent: true });
291
336
 
292
337
  const result = await repoFunctions.getStagedFiles({ silent: true });
338
+
293
339
  expect(Result.isOk(result)).toBe(true);
340
+
294
341
  if (Result.isOk(result)) {
295
342
  const files = result.value;
343
+
296
344
  expect(files).toContain(testFileName);
297
345
  }
298
346
  } finally {
@@ -302,26 +350,37 @@ describe('diff', () => {
302
350
 
303
351
  test('should detect multiple staged files', async () => {
304
352
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
353
+
305
354
  const repoFunctions = createRepoFunctions(repoPath);
306
355
 
307
356
  try {
308
357
  // Create multiple test files
309
358
  const uuid = crypto.randomUUID();
359
+
310
360
  const file1 = `test-staged-file1-${uuid}.tmp`;
361
+
311
362
  const file2 = `test-staged-file2-${uuid}.tmp`;
363
+
312
364
  const filePath1 = path.join(repoPath, file1);
365
+
313
366
  const filePath2 = path.join(repoPath, file2);
314
367
 
315
368
  await fs.writeFile(filePath1, 'staged file 1 content');
369
+
316
370
  await fs.writeFile(filePath2, 'staged file 2 content');
371
+
317
372
  // Stage both files
318
373
  await execInRepo(`git add ${file1} ${file2}`, { silent: true });
319
374
 
320
375
  const result = await repoFunctions.getStagedFiles({ silent: true });
376
+
321
377
  expect(Result.isOk(result)).toBe(true);
378
+
322
379
  if (Result.isOk(result)) {
323
380
  const files = result.value;
381
+
324
382
  expect(files).toContain(file1);
383
+
325
384
  expect(files).toContain(file2);
326
385
  }
327
386
  } finally {
@@ -331,15 +390,19 @@ describe('diff', () => {
331
390
 
332
391
  test('should exclude deleted files by default', async () => {
333
392
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
393
+
334
394
  const repoFunctions = createRepoFunctions(repoPath);
335
395
 
336
396
  try {
337
397
  const testFileName = `test-deleted-file-${crypto.randomUUID()}.tmp`;
398
+
338
399
  const testFilePath = path.join(repoPath, testFileName);
339
400
 
340
401
  // Create a file and commit it
341
402
  await fs.writeFile(testFilePath, 'file to be deleted');
403
+
342
404
  await execInRepo(`git add ${testFileName}`, { silent: true });
405
+
343
406
  await execInRepo(
344
407
  `git commit -m "Add test file for deletion" --no-verify`,
345
408
  {
@@ -349,15 +412,19 @@ describe('diff', () => {
349
412
 
350
413
  // Delete the file and stage the deletion
351
414
  await fs.rm(testFilePath, { force: true });
415
+
352
416
  await execInRepo(`git add ${testFileName}`, { silent: true });
353
417
 
354
418
  // Test with excludeDeleted = true (default)
355
419
  const resultExclude = await repoFunctions.getStagedFiles({
356
420
  silent: true,
357
421
  });
422
+
358
423
  expect(Result.isOk(resultExclude)).toBe(true);
424
+
359
425
  if (Result.isOk(resultExclude)) {
360
426
  const files = resultExclude.value;
427
+
361
428
  expect(files).not.toContain(testFileName);
362
429
  }
363
430
 
@@ -366,6 +433,7 @@ describe('diff', () => {
366
433
  const gitStatusResult = await execInRepo(`git status --porcelain`, {
367
434
  silent: true,
368
435
  });
436
+
369
437
  const hasDeletion =
370
438
  Result.isOk(gitStatusResult) &&
371
439
  gitStatusResult.value.stdout.includes(`D ${testFileName}`);
@@ -375,9 +443,12 @@ describe('diff', () => {
375
443
  excludeDeleted: false,
376
444
  silent: true,
377
445
  });
446
+
378
447
  expect(Result.isOk(resultInclude)).toBe(true);
448
+
379
449
  if (Result.isOk(resultInclude)) {
380
450
  const files = resultInclude.value;
451
+
381
452
  expect(files).toContain(testFileName);
382
453
  }
383
454
  } else {
@@ -393,16 +464,21 @@ describe('diff', () => {
393
464
 
394
465
  test('should parse staged files output correctly', async () => {
395
466
  const { repoPath, cleanup } = await createTempRepo();
467
+
396
468
  const repoFunctions = createRepoFunctions(repoPath);
397
469
 
398
470
  try {
399
471
  const result = await repoFunctions.getStagedFiles({ silent: true });
472
+
400
473
  expect(Result.isOk(result)).toBe(true);
474
+
401
475
  if (Result.isOk(result)) {
402
476
  const files = result.value;
477
+
403
478
  // Each file should be a non-empty string
404
479
  for (const file of files) {
405
- expect(typeof file).toBe('string');
480
+ expectTypeOf(file).toBeString();
481
+
406
482
  expect(file.trim()).toBe(file); // No leading/trailing whitespace
407
483
  }
408
484
  }
@@ -413,11 +489,14 @@ describe('diff', () => {
413
489
 
414
490
  test('should work with silent option', async () => {
415
491
  const { repoPath, cleanup } = await createTempRepo();
492
+
416
493
  const repoFunctions = createRepoFunctions(repoPath);
417
494
 
418
495
  try {
419
496
  const result = await repoFunctions.getStagedFiles({ silent: true });
497
+
420
498
  expect(Result.isOk(result)).toBe(true);
499
+
421
500
  if (Result.isOk(result)) {
422
501
  expect(Array.isArray(result.value)).toBe(true);
423
502
  }
@@ -428,10 +507,12 @@ describe('diff', () => {
428
507
 
429
508
  test('should handle git command errors gracefully', async () => {
430
509
  const { repoPath, cleanup } = await createTempRepo();
510
+
431
511
  const repoFunctions = createRepoFunctions(repoPath);
432
512
 
433
513
  try {
434
514
  const result = await repoFunctions.getStagedFiles({ silent: true });
515
+
435
516
  // Should always return a Result, either Ok or Err
436
517
  expect(Result.isOk(result) || Result.isErr(result)).toBe(true);
437
518
  } finally {
@@ -440,14 +521,17 @@ describe('diff', () => {
440
521
  });
441
522
  });
442
523
 
443
- describe('getModifiedFiles', () => {
524
+ describe(getModifiedFiles, () => {
444
525
  test('should return empty array when no files are modified', async () => {
445
526
  const { repoPath, cleanup } = await createTempRepo();
527
+
446
528
  const repoFunctions = createRepoFunctions(repoPath);
447
529
 
448
530
  try {
449
531
  const result = await repoFunctions.getModifiedFiles({ silent: true });
532
+
450
533
  expect(Result.isOk(result)).toBe(true);
534
+
451
535
  if (Result.isOk(result)) {
452
536
  expect(Array.isArray(result.value)).toBe(true);
453
537
  }
@@ -458,15 +542,19 @@ describe('diff', () => {
458
542
 
459
543
  test('should detect modified files', async () => {
460
544
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
545
+
461
546
  const repoFunctions = createRepoFunctions(repoPath);
462
547
 
463
548
  try {
464
549
  // Create a new file and commit it first
465
550
  const testFileName = `test-modified-file-${crypto.randomUUID()}.tmp`;
551
+
466
552
  const testFilePath = path.join(repoPath, testFileName);
467
553
 
468
554
  await fs.writeFile(testFilePath, 'initial content');
555
+
469
556
  await execInRepo(`git add ${testFileName}`, { silent: true });
557
+
470
558
  await execInRepo(
471
559
  `git commit -m "Add file for modification test" --no-verify`,
472
560
  { silent: true },
@@ -476,9 +564,12 @@ describe('diff', () => {
476
564
  await fs.writeFile(testFilePath, 'modified content');
477
565
 
478
566
  const result = await repoFunctions.getModifiedFiles({ silent: true });
567
+
479
568
  expect(Result.isOk(result)).toBe(true);
569
+
480
570
  if (Result.isOk(result)) {
481
571
  const files = result.value;
572
+
482
573
  expect(files).toContain(testFileName);
483
574
  }
484
575
  } finally {
@@ -488,19 +579,27 @@ describe('diff', () => {
488
579
 
489
580
  test('should detect multiple modified files', async () => {
490
581
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
582
+
491
583
  const repoFunctions = createRepoFunctions(repoPath);
492
584
 
493
585
  try {
494
586
  const uuid = crypto.randomUUID();
587
+
495
588
  const file1 = `test-modified-file1-${uuid}.tmp`;
589
+
496
590
  const file2 = `test-modified-file2-${uuid}.tmp`;
591
+
497
592
  const filePath1 = path.join(repoPath, file1);
593
+
498
594
  const filePath2 = path.join(repoPath, file2);
499
595
 
500
596
  // Create and commit both files
501
597
  await fs.writeFile(filePath1, 'initial content 1');
598
+
502
599
  await fs.writeFile(filePath2, 'initial content 2');
600
+
503
601
  await execInRepo(`git add ${file1} ${file2}`, { silent: true });
602
+
504
603
  await execInRepo(
505
604
  `git commit -m "Add files for modification test" --no-verify`,
506
605
  { silent: true },
@@ -508,13 +607,18 @@ describe('diff', () => {
508
607
 
509
608
  // Modify both files
510
609
  await fs.writeFile(filePath1, 'modified content 1');
610
+
511
611
  await fs.writeFile(filePath2, 'modified content 2');
512
612
 
513
613
  const result = await repoFunctions.getModifiedFiles({ silent: true });
614
+
514
615
  expect(Result.isOk(result)).toBe(true);
616
+
515
617
  if (Result.isOk(result)) {
516
618
  const files = result.value;
619
+
517
620
  expect(files).toContain(file1);
621
+
518
622
  expect(files).toContain(file2);
519
623
  }
520
624
  } finally {
@@ -524,15 +628,19 @@ describe('diff', () => {
524
628
 
525
629
  test('should exclude deleted files by default', async () => {
526
630
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
631
+
527
632
  const repoFunctions = createRepoFunctions(repoPath);
528
633
 
529
634
  try {
530
635
  const testFileName = `test-deleted-modified-file-${crypto.randomUUID()}.tmp`;
636
+
531
637
  const testFilePath = path.join(repoPath, testFileName);
532
638
 
533
639
  // Create a file and commit it
534
640
  await fs.writeFile(testFilePath, 'file to be deleted');
641
+
535
642
  await execInRepo(`git add ${testFileName}`, { silent: true });
643
+
536
644
  await execInRepo(
537
645
  `git commit -m "Add test file for deletion" --no-verify`,
538
646
  { silent: true },
@@ -545,9 +653,12 @@ describe('diff', () => {
545
653
  const resultExclude = await repoFunctions.getModifiedFiles({
546
654
  silent: true,
547
655
  });
656
+
548
657
  expect(Result.isOk(resultExclude)).toBe(true);
658
+
549
659
  if (Result.isOk(resultExclude)) {
550
660
  const files = resultExclude.value;
661
+
551
662
  expect(files).not.toContain(testFileName);
552
663
  }
553
664
 
@@ -556,9 +667,12 @@ describe('diff', () => {
556
667
  excludeDeleted: false,
557
668
  silent: true,
558
669
  });
670
+
559
671
  expect(Result.isOk(resultInclude)).toBe(true);
672
+
560
673
  if (Result.isOk(resultInclude)) {
561
674
  const files = resultInclude.value;
675
+
562
676
  expect(files).toContain(testFileName);
563
677
  }
564
678
  } finally {
@@ -568,16 +682,21 @@ describe('diff', () => {
568
682
 
569
683
  test('should parse modified files output correctly', async () => {
570
684
  const { repoPath, cleanup } = await createTempRepo();
685
+
571
686
  const repoFunctions = createRepoFunctions(repoPath);
572
687
 
573
688
  try {
574
689
  const result = await repoFunctions.getModifiedFiles({ silent: true });
690
+
575
691
  expect(Result.isOk(result)).toBe(true);
692
+
576
693
  if (Result.isOk(result)) {
577
694
  const files = result.value;
695
+
578
696
  // Each file should be a non-empty string
579
697
  for (const file of files) {
580
- expect(typeof file).toBe('string');
698
+ expectTypeOf(file).toBeString();
699
+
581
700
  expect(file.trim()).toBe(file); // No leading/trailing whitespace
582
701
  }
583
702
  }
@@ -588,11 +707,14 @@ describe('diff', () => {
588
707
 
589
708
  test('should work with silent option', async () => {
590
709
  const { repoPath, cleanup } = await createTempRepo();
710
+
591
711
  const repoFunctions = createRepoFunctions(repoPath);
592
712
 
593
713
  try {
594
714
  const result = await repoFunctions.getModifiedFiles({ silent: true });
715
+
595
716
  expect(Result.isOk(result)).toBe(true);
717
+
596
718
  if (Result.isOk(result)) {
597
719
  expect(Array.isArray(result.value)).toBe(true);
598
720
  }
@@ -603,10 +725,12 @@ describe('diff', () => {
603
725
 
604
726
  test('should handle git command errors gracefully', async () => {
605
727
  const { repoPath, cleanup } = await createTempRepo();
728
+
606
729
  const repoFunctions = createRepoFunctions(repoPath);
607
730
 
608
731
  try {
609
732
  const result = await repoFunctions.getModifiedFiles({ silent: true });
733
+
610
734
  // Should always return a Result, either Ok or Err
611
735
  expect(Result.isOk(result) || Result.isErr(result)).toBe(true);
612
736
  } finally {
@@ -615,18 +739,22 @@ describe('diff', () => {
615
739
  });
616
740
  });
617
741
 
618
- describe('getDiffFrom', () => {
742
+ describe(getDiffFrom, () => {
619
743
  test('should work with silent option', async () => {
620
744
  const { repoPath, cleanup, execInRepo } = await createTempRepo();
745
+
621
746
  const repoFunctions = createRepoFunctions(repoPath);
622
747
 
623
748
  try {
624
749
  // Create an initial commit to have something to diff against
625
750
  const testFileName = `test-initial-file-${crypto.randomUUID()}.tmp`;
751
+
626
752
  const testFilePath = path.join(repoPath, testFileName);
627
753
 
628
754
  await fs.writeFile(testFilePath, 'initial content');
755
+
629
756
  await execInRepo(`git add ${testFileName}`, { silent: true });
757
+
630
758
  await execInRepo(`git commit -m "Initial commit" --no-verify`, {
631
759
  silent: true,
632
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