ts-repo-utils 6.1.0 → 7.0.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 (51) hide show
  1. package/README.md +153 -33
  2. package/dist/cmd/assert-repo-is-clean.mjs +1 -1
  3. package/dist/cmd/check-should-run-type-checks.mjs +1 -1
  4. package/dist/cmd/format-diff-from.mjs +29 -8
  5. package/dist/cmd/format-diff-from.mjs.map +1 -1
  6. package/dist/cmd/format-uncommitted.d.mts +3 -0
  7. package/dist/cmd/format-uncommitted.d.mts.map +1 -0
  8. package/dist/cmd/format-uncommitted.mjs +59 -0
  9. package/dist/cmd/format-uncommitted.mjs.map +1 -0
  10. package/dist/cmd/gen-index-ts.mjs +1 -1
  11. package/dist/functions/assert-repo-is-clean.d.mts.map +1 -1
  12. package/dist/functions/assert-repo-is-clean.mjs +30 -30
  13. package/dist/functions/assert-repo-is-clean.mjs.map +1 -1
  14. package/dist/functions/diff.d.mts +32 -2
  15. package/dist/functions/diff.d.mts.map +1 -1
  16. package/dist/functions/diff.mjs +47 -29
  17. package/dist/functions/diff.mjs.map +1 -1
  18. package/dist/functions/exec-async.d.mts +4 -4
  19. package/dist/functions/exec-async.d.mts.map +1 -1
  20. package/dist/functions/exec-async.mjs +5 -5
  21. package/dist/functions/exec-async.mjs.map +1 -1
  22. package/dist/functions/format.d.mts +20 -11
  23. package/dist/functions/format.d.mts.map +1 -1
  24. package/dist/functions/format.mjs +136 -110
  25. package/dist/functions/format.mjs.map +1 -1
  26. package/dist/functions/gen-index.d.mts +2 -1
  27. package/dist/functions/gen-index.d.mts.map +1 -1
  28. package/dist/functions/gen-index.mjs +10 -8
  29. package/dist/functions/gen-index.mjs.map +1 -1
  30. package/dist/functions/index.mjs +2 -2
  31. package/dist/index.mjs +2 -2
  32. package/package.json +2 -2
  33. package/src/cmd/assert-repo-is-clean.mts +1 -1
  34. package/src/cmd/check-should-run-type-checks.mts +1 -1
  35. package/src/cmd/format-diff-from.mts +35 -9
  36. package/src/cmd/format-uncommitted.mts +67 -0
  37. package/src/cmd/gen-index-ts.mts +1 -1
  38. package/src/functions/assert-repo-is-clean.mts +43 -34
  39. package/src/functions/diff.mts +85 -32
  40. package/src/functions/diff.test.mts +569 -102
  41. package/src/functions/exec-async.mts +21 -29
  42. package/src/functions/exec-async.test.mts +77 -47
  43. package/src/functions/format.mts +222 -150
  44. package/src/functions/format.test.mts +625 -20
  45. package/src/functions/gen-index.mts +16 -10
  46. package/src/functions/workspace-utils/run-cmd-in-stages.test.mts +266 -0
  47. package/dist/cmd/format-untracked.d.mts +0 -3
  48. package/dist/cmd/format-untracked.d.mts.map +0 -1
  49. package/dist/cmd/format-untracked.mjs +0 -34
  50. package/dist/cmd/format-untracked.mjs.map +0 -1
  51. package/src/cmd/format-untracked.mts +0 -31
@@ -1,19 +1,15 @@
1
- import {
2
- exec,
3
- type ExecException,
4
- type ExecOptions as ExecOptions_,
5
- } from 'node:child_process';
1
+ import * as childProcess from 'node:child_process';
6
2
  import { Result } from 'ts-data-forge';
7
3
 
8
4
  type ExecOptionsCustom = Readonly<{
9
5
  silent?: boolean;
10
6
  }>;
11
7
 
12
- type ExecOptions = DeepReadonly<ExecOptions_ & ExecOptionsCustom>;
8
+ export type ExecOptions = childProcess.ExecOptions & ExecOptionsCustom;
13
9
 
14
- type ExecResult<T extends string | Buffer> = Result<
10
+ export type ExecResult<T extends string | Buffer> = Result<
15
11
  Readonly<{ stdout: T; stderr: T }>,
16
- ExecException
12
+ childProcess.ExecException
17
13
  >;
18
14
 
19
15
  /**
@@ -30,16 +26,19 @@ export function $(
30
26
 
31
27
  export function $(
32
28
  command: string,
29
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
33
30
  options: Readonly<{ encoding: 'buffer' | null } & ExecOptions>,
34
31
  ): Promise<ExecResult<Buffer>>;
35
32
 
36
33
  export function $(
37
34
  command: string,
35
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
38
36
  options: Readonly<{ encoding: BufferEncoding } & ExecOptions>,
39
37
  ): Promise<ExecResult<string>>;
40
38
 
41
39
  export function $(
42
40
  command: string,
41
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
43
42
  options?: Readonly<
44
43
  { encoding?: BufferEncoding | 'buffer' | null } & ExecOptions
45
44
  >,
@@ -52,28 +51,21 @@ export function $(
52
51
 
53
52
  return new Promise((resolve) => {
54
53
  // eslint-disable-next-line security/detect-child-process
55
- exec(
56
- command,
57
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
58
- restOptions as {
59
- encoding?: 'buffer' | null | BufferEncoding;
60
- } & ExecOptions_,
61
- (error, stdout, stderr) => {
62
- if (!silent) {
63
- if (stdout !== '') {
64
- echo(stdout);
65
- }
66
- if (stderr !== '') {
67
- console.error(stderr);
68
- }
54
+ childProcess.exec(command, restOptions, (error, stdout, stderr) => {
55
+ if (!silent) {
56
+ if (stdout !== '') {
57
+ echo(stdout);
69
58
  }
70
-
71
- if (error !== null) {
72
- resolve(Result.err(error));
73
- } else {
74
- resolve(Result.ok({ stdout, stderr }));
59
+ if (stderr !== '') {
60
+ console.error(stderr);
75
61
  }
76
- },
77
- );
62
+ }
63
+
64
+ if (error !== null) {
65
+ resolve(Result.err(error));
66
+ } else {
67
+ resolve(Result.ok({ stdout, stderr }));
68
+ }
69
+ });
78
70
  });
79
71
  }
@@ -448,53 +448,83 @@ describe('exec-async', () => {
448
448
  });
449
449
 
450
450
  test('should demonstrate type equivalence with runtime comparison', async () => {
451
- // Create a type that represents what exec callback receives
452
- type ExecCallbackParams<T extends string | Buffer> = {
453
- error: ExecException | null;
454
- stdout: T;
455
- stderr: T;
456
- };
457
-
458
- // Helper to capture exec callback types
459
- const captureExecTypes = <T extends string | Buffer>(
460
- _encoding?: BufferEncoding | 'buffer' | null,
461
- ): ExecCallbackParams<T> => {
462
- const emptyParams: ExecCallbackParams<T> = {
463
- error: null,
464
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
465
- stdout: undefined as unknown as T,
466
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
467
- stderr: undefined as unknown as T,
468
- };
469
- return emptyParams;
470
- };
471
-
472
- // Default encoding comparison
473
- const _execDefault = captureExecTypes<string>();
474
- const $Default = await $('echo "test"', { silent: true });
475
- if (Result.isOk($Default)) {
476
- expectType<typeof _execDefault.stdout, typeof $Default.value.stdout>(
477
- '=',
478
- );
479
- expectType<typeof _execDefault.stderr, typeof $Default.value.stderr>(
480
- '=',
481
- );
482
- }
483
-
484
- // Buffer encoding comparison
485
- const _execBuffer = captureExecTypes<Buffer>('buffer');
486
- const $Buffer = await $('echo "test"', {
487
- encoding: 'buffer',
488
- silent: true,
489
- });
490
- if (Result.isOk($Buffer)) {
491
- expectType<typeof _execBuffer.stdout, typeof $Buffer.value.stdout>('=');
492
- expectType<typeof _execBuffer.stderr, typeof $Buffer.value.stderr>('=');
493
- }
494
-
495
- // Error type comparison
496
- if (Result.isErr($Default)) {
497
- expectType<ExecException, typeof $Default.value>('=');
451
+ // Mock console functions to suppress output
452
+ const consoleLogSpy = vi
453
+ // eslint-disable-next-line vitest/no-restricted-vi-methods
454
+ .spyOn(console, 'log')
455
+ .mockImplementation(() => {});
456
+
457
+ const consoleErrorSpy = vi
458
+ // eslint-disable-next-line vitest/no-restricted-vi-methods
459
+ .spyOn(console, 'error')
460
+ .mockImplementation(() => {});
461
+
462
+ const stderrWriteSpy = vi
463
+ // eslint-disable-next-line vitest/no-restricted-vi-methods
464
+ .spyOn(process.stderr, 'write')
465
+ .mockImplementation(() => true);
466
+
467
+ try {
468
+ await withSilentEcho(async () => {
469
+ // Create a type that represents what exec callback receives
470
+ type ExecCallbackParams<T extends string | Buffer> = {
471
+ error: ExecException | null;
472
+ stdout: T;
473
+ stderr: T;
474
+ };
475
+
476
+ // Helper to capture exec callback types
477
+ const captureExecTypes = <T extends string | Buffer>(
478
+ _encoding?: BufferEncoding | 'buffer' | null,
479
+ ): ExecCallbackParams<T> => {
480
+ const emptyParams: ExecCallbackParams<T> = {
481
+ error: null,
482
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
483
+ stdout: undefined as unknown as T,
484
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
485
+ stderr: undefined as unknown as T,
486
+ };
487
+ return emptyParams;
488
+ };
489
+
490
+ // Default encoding comparison
491
+ const _execDefault = captureExecTypes<string>();
492
+ const $Default = await $('echo "test"', { silent: true });
493
+ if (Result.isOk($Default)) {
494
+ expectType<
495
+ typeof _execDefault.stdout,
496
+ typeof $Default.value.stdout
497
+ >('=');
498
+ expectType<
499
+ typeof _execDefault.stderr,
500
+ typeof $Default.value.stderr
501
+ >('=');
502
+ }
503
+
504
+ // Buffer encoding comparison
505
+ const _execBuffer = captureExecTypes<Buffer>('buffer');
506
+ const $Buffer = await $('echo "test"', {
507
+ encoding: 'buffer',
508
+ silent: true,
509
+ });
510
+ if (Result.isOk($Buffer)) {
511
+ expectType<typeof _execBuffer.stdout, typeof $Buffer.value.stdout>(
512
+ '=',
513
+ );
514
+ expectType<typeof _execBuffer.stderr, typeof $Buffer.value.stderr>(
515
+ '=',
516
+ );
517
+ }
518
+
519
+ // Error type comparison
520
+ if (Result.isErr($Default)) {
521
+ expectType<ExecException, typeof $Default.value>('=');
522
+ }
523
+ });
524
+ } finally {
525
+ consoleLogSpy.mockRestore();
526
+ consoleErrorSpy.mockRestore();
527
+ stderrWriteSpy.mockRestore();
498
528
  }
499
529
  });
500
530
  });