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.
- package/README.md +10 -0
- package/dist/cmd/assert-repo-is-clean.mjs +1 -1
- package/dist/cmd/assert-repo-is-clean.mjs.map +1 -1
- package/dist/cmd/check-should-run-type-checks.mjs +1 -1
- package/dist/cmd/check-should-run-type-checks.mjs.map +1 -1
- package/dist/cmd/format-diff-from.mjs +1 -1
- package/dist/cmd/format-diff-from.mjs.map +1 -1
- package/dist/cmd/format-uncommitted.mjs +1 -1
- package/dist/cmd/format-uncommitted.mjs.map +1 -1
- package/dist/cmd/gen-index-ts.mjs +1 -1
- package/dist/cmd/gen-index-ts.mjs.map +1 -1
- package/dist/entry-point.d.mts.map +1 -1
- package/dist/functions/assert-ext.d.mts.map +1 -1
- package/dist/functions/assert-ext.mjs.map +1 -1
- package/dist/functions/assert-path-exists.d.mts.map +1 -1
- package/dist/functions/assert-path-exists.mjs.map +1 -1
- package/dist/functions/assert-repo-is-clean.d.mts.map +1 -1
- package/dist/functions/assert-repo-is-clean.mjs.map +1 -1
- package/dist/functions/create-result-assert.d.mts.map +1 -1
- package/dist/functions/create-result-assert.mjs.map +1 -1
- package/dist/functions/exec-async.mjs.map +1 -1
- package/dist/functions/format.d.mts +4 -4
- package/dist/functions/format.d.mts.map +1 -1
- package/dist/functions/format.mjs +6 -4
- package/dist/functions/format.mjs.map +1 -1
- package/dist/functions/gen-index.d.mts.map +1 -1
- package/dist/functions/gen-index.mjs.map +1 -1
- package/dist/functions/should-run.d.mts.map +1 -1
- package/dist/functions/should-run.mjs.map +1 -1
- package/dist/functions/workspace-utils/execute-parallel.d.mts.map +1 -1
- package/dist/functions/workspace-utils/execute-parallel.mjs.map +1 -1
- package/dist/functions/workspace-utils/get-workspace-packages.d.mts.map +1 -1
- package/dist/functions/workspace-utils/get-workspace-packages.mjs.map +1 -1
- package/dist/functions/workspace-utils/run-cmd-in-parallel.d.mts.map +1 -1
- package/dist/functions/workspace-utils/run-cmd-in-parallel.mjs.map +1 -1
- package/dist/functions/workspace-utils/run-cmd-in-stages.d.mts.map +1 -1
- package/dist/functions/workspace-utils/run-cmd-in-stages.mjs.map +1 -1
- package/dist/node-global.d.mts.map +1 -1
- package/package.json +17 -19
- package/src/cmd/assert-repo-is-clean.mts +2 -1
- package/src/cmd/check-should-run-type-checks.mts +2 -1
- package/src/cmd/format-diff-from.mts +2 -1
- package/src/cmd/format-uncommitted.mts +3 -1
- package/src/cmd/gen-index-ts.mts +8 -2
- package/src/entry-point.mts +1 -0
- package/src/functions/assert-ext.mts +4 -0
- package/src/functions/assert-path-exists.mts +2 -0
- package/src/functions/assert-repo-is-clean.mts +9 -0
- package/src/functions/create-result-assert.mts +1 -0
- package/src/functions/diff.test.mts +76 -0
- package/src/functions/exec-async.mts +4 -0
- package/src/functions/exec-async.test.mts +42 -0
- package/src/functions/format.mts +29 -7
- package/src/functions/format.test.mts +109 -0
- package/src/functions/gen-index.mts +16 -0
- package/src/functions/should-run.mts +2 -0
- package/src/functions/workspace-utils/execute-parallel.mts +23 -0
- package/src/functions/workspace-utils/get-workspace-packages.mts +5 -0
- package/src/functions/workspace-utils/run-cmd-in-parallel.mts +5 -0
- package/src/functions/workspace-utils/run-cmd-in-stages.mts +5 -0
- package/src/functions/workspace-utils/run-cmd-in-stages.test.mts +13 -0
- 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
|
});
|