ts-repo-utils 9.0.0 → 10.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 (83) hide show
  1. package/README.md +194 -215
  2. package/dist/cmd/assert-repo-is-clean.mjs +4 -4
  3. package/dist/cmd/assert-repo-is-clean.mjs.map +1 -1
  4. package/dist/cmd/check-should-run-type-checks.mjs +4 -4
  5. package/dist/cmd/check-should-run-type-checks.mjs.map +1 -1
  6. package/dist/cmd/format-diff-from.mjs +4 -4
  7. package/dist/cmd/format-diff-from.mjs.map +1 -1
  8. package/dist/cmd/format-uncommitted.mjs +4 -4
  9. package/dist/cmd/format-uncommitted.mjs.map +1 -1
  10. package/dist/cmd/gen-index-ts.mjs +4 -4
  11. package/dist/cmd/gen-index-ts.mjs.map +1 -1
  12. package/dist/functions/assert-ext.d.mts +1 -3
  13. package/dist/functions/assert-ext.d.mts.map +1 -1
  14. package/dist/functions/assert-ext.mjs +5 -4
  15. package/dist/functions/assert-ext.mjs.map +1 -1
  16. package/dist/functions/assert-path-exists.d.mts +0 -1
  17. package/dist/functions/assert-path-exists.d.mts.map +1 -1
  18. package/dist/functions/assert-path-exists.mjs +2 -2
  19. package/dist/functions/assert-path-exists.mjs.map +1 -1
  20. package/dist/functions/assert-repo-is-clean.d.mts +0 -1
  21. package/dist/functions/assert-repo-is-clean.d.mts.map +1 -1
  22. package/dist/functions/assert-repo-is-clean.mjs +2 -2
  23. package/dist/functions/assert-repo-is-clean.mjs.map +1 -1
  24. package/dist/functions/create-result-assert.d.mts +0 -1
  25. package/dist/functions/create-result-assert.d.mts.map +1 -1
  26. package/dist/functions/create-result-assert.mjs +1 -2
  27. package/dist/functions/create-result-assert.mjs.map +1 -1
  28. package/dist/functions/diff.d.mts +0 -1
  29. package/dist/functions/diff.d.mts.map +1 -1
  30. package/dist/functions/diff.mjs +1 -1
  31. package/dist/functions/exec-async.mjs +2 -2
  32. package/dist/functions/exec-async.mjs.map +1 -1
  33. package/dist/functions/format.d.mts +0 -1
  34. package/dist/functions/format.d.mts.map +1 -1
  35. package/dist/functions/format.mjs +8 -4
  36. package/dist/functions/format.mjs.map +1 -1
  37. package/dist/functions/gen-index.d.mts +0 -1
  38. package/dist/functions/gen-index.d.mts.map +1 -1
  39. package/dist/functions/gen-index.mjs +8 -3
  40. package/dist/functions/gen-index.mjs.map +1 -1
  41. package/dist/functions/glob.mjs +1 -1
  42. package/dist/functions/should-run.d.mts +0 -1
  43. package/dist/functions/should-run.d.mts.map +1 -1
  44. package/dist/functions/should-run.mjs +3 -1
  45. package/dist/functions/should-run.mjs.map +1 -1
  46. package/dist/functions/workspace-utils/execute-parallel.d.mts +0 -1
  47. package/dist/functions/workspace-utils/execute-parallel.d.mts.map +1 -1
  48. package/dist/functions/workspace-utils/execute-parallel.mjs +0 -1
  49. package/dist/functions/workspace-utils/execute-parallel.mjs.map +1 -1
  50. package/dist/functions/workspace-utils/get-workspace-packages.d.mts +0 -1
  51. package/dist/functions/workspace-utils/get-workspace-packages.d.mts.map +1 -1
  52. package/dist/functions/workspace-utils/get-workspace-packages.mjs +9 -3
  53. package/dist/functions/workspace-utils/get-workspace-packages.mjs.map +1 -1
  54. package/dist/types.d.mts +1 -2
  55. package/package.json +28 -28
  56. package/src/cmd/assert-repo-is-clean.mts +1 -1
  57. package/src/cmd/check-should-run-type-checks.mts +1 -1
  58. package/src/cmd/format-diff-from.mts +1 -1
  59. package/src/cmd/format-uncommitted.mts +1 -1
  60. package/src/cmd/gen-index-ts.mts +1 -1
  61. package/src/functions/assert-ext.mts +6 -6
  62. package/src/functions/assert-path-exists.mts +2 -2
  63. package/src/functions/assert-repo-is-clean.mts +2 -2
  64. package/src/functions/create-result-assert.mts +1 -2
  65. package/src/functions/diff.mts +1 -1
  66. package/src/functions/diff.test.mts +21 -2
  67. package/src/functions/exec-async.mts +2 -2
  68. package/src/functions/exec-async.test.mts +6 -11
  69. package/src/functions/format.mts +8 -4
  70. package/src/functions/format.test.mts +24 -1
  71. package/src/functions/gen-index.mts +9 -3
  72. package/src/functions/glob.mts +1 -1
  73. package/src/functions/should-run.mts +3 -1
  74. package/src/functions/workspace-utils/execute-parallel.mts +0 -1
  75. package/src/functions/workspace-utils/get-workspace-packages.mts +5 -1
  76. package/src/functions/workspace-utils/run-cmd-in-stages.test.mts +0 -1
  77. package/dist/globals.d.mts +0 -1
  78. package/dist/node-global.d.mts +0 -20
  79. package/dist/node-global.d.mts.map +0 -1
  80. package/dist/node-global.mjs +0 -27
  81. package/dist/node-global.mjs.map +0 -1
  82. package/src/globals.d.mts +0 -1
  83. package/src/node-global.mts +0 -49
package/README.md CHANGED
@@ -130,6 +130,9 @@ npm exec -- gen-index-ts ./src --target-ext .mts --target-ext .tsx --index-ext .
130
130
  # With exclude patterns
131
131
  npm exec -- gen-index-ts ./src --target-ext .ts --index-ext .ts --export-ext .js --exclude '*.test.ts' --exclude '*.spec.ts'
132
132
 
133
+ # Skip generating index files at the root level (depth 0), only generate from depth 1 onwards
134
+ npm exec -- gen-index-ts ./src --target-ext .mts --index-ext .mts --export-ext .mjs --min-depth 1
135
+
133
136
  # Example in npm scripts
134
137
  "gi": "gen-index-ts ./src --index-ext .mts --export-ext .mjs --target-ext .mts --target-ext .tsx --fmt 'npm run fmt'"
135
138
  ```
@@ -155,6 +158,7 @@ npm exec -- gen-index-ts ./src --target-ext .ts --index-ext .ts --export-ext .js
155
158
  - `--export-ext` - Extension of the export statements in the index file (required, or 'none')
156
159
  - `--exclude` - Glob patterns of files to exclude (optional, can be specified multiple times)
157
160
  - `--fmt` - Command to format after generating the index file (optional)
161
+ - `--min-depth` - Minimum depth to start generating index files (default: 0)
158
162
  - `--silent` - Suppress output messages (optional)
159
163
 
160
164
  ### `check-should-run-type-checks`
@@ -211,9 +215,6 @@ Executes a shell command asynchronously with type-safe results.
211
215
  ```tsx
212
216
  import { $, Result } from 'ts-repo-utils';
213
217
 
214
- // or
215
- // import "ts-repo-utils"; // $ and Result are globally defined in ts-repo-utils
216
-
217
218
  const result = await $('npm test');
218
219
 
219
220
  if (Result.isOk(result)) {
@@ -250,9 +251,6 @@ Determines whether a script is being executed directly via CLI or imported as a
250
251
  ```tsx
251
252
  import { isDirectlyExecuted } from 'ts-repo-utils';
252
253
 
253
- // or
254
- // import "ts-repo-utils"; // isDirectlyExecuted is globally defined in ts-repo-utils
255
-
256
254
  // calculator.mjs
257
255
  export const add = (a: number, b: number): number => a + b;
258
256
 
@@ -308,6 +306,28 @@ await assertPathExists('./src/index.ts', 'Entry point file');
308
306
 
309
307
  Runs the extension validation and reports findings without exiting the process. Useful when you want to combine extension checks with other validations or surface the failure information in a custom way.
310
308
 
309
+ ```tsx
310
+ import { Result } from 'ts-data-forge';
311
+ import { checkExt } from 'ts-repo-utils';
312
+
313
+ const result = await checkExt({
314
+ directories: [
315
+ { path: './src', extension: '.ts' },
316
+ { path: './scripts', extension: '.mjs' },
317
+ ],
318
+ });
319
+
320
+ if (Result.isErr(result)) {
321
+ console.error(result.value.message);
322
+
323
+ console.error('Files with wrong extensions:', result.value.files);
324
+ }
325
+ ```
326
+
327
+ #### `assertExt(config: CheckExtConfig): Promise<void>`
328
+
329
+ Validates that all files in specified directories have the correct extensions. Exits with code 1 if any files have incorrect extensions.
330
+
311
331
  ```tsx
312
332
  import { assertExt } from 'ts-repo-utils';
313
333
 
@@ -326,9 +346,7 @@ await assertExt({
326
346
  });
327
347
  ```
328
348
 
329
- #### `assertExt(config: CheckExtConfig): Promise<void>`
330
-
331
- Validates that all files in specified directories have the correct extensions. Exits with code 1 if any files have incorrect extensions.
349
+ **Configuration Type:**
332
350
 
333
351
  ```tsx
334
352
  type CheckExtConfig = Readonly<{
@@ -340,15 +358,6 @@ type CheckExtConfig = Readonly<{
340
358
  }>;
341
359
  ```
342
360
 
343
- **Configuration Type:**
344
-
345
- ```tsx
346
- import { makeEmptyDir } from 'ts-repo-utils';
347
-
348
- // Reset ./tmp/build before writing artifacts
349
- await makeEmptyDir('./tmp/build');
350
- ```
351
-
352
361
  ### Result Utilities
353
362
 
354
363
  #### `createResultAssert(options): (config) => Promise<TOk>`
@@ -356,13 +365,43 @@ await makeEmptyDir('./tmp/build');
356
365
  Creates an assert-style wrapper around a function that returns a `Result`, exiting the process with a non-zero code when the underlying function yields an error. The wrapper keeps success handling customizable while reusing the composable Result-based variant elsewhere.
357
366
 
358
367
  ```tsx
359
- import { repoIsDirty } from 'ts-repo-utils';
368
+ import { hasKey, isNumber, isRecord, isString, Result } from 'ts-data-forge';
369
+ import { createResultAssert } from 'ts-repo-utils';
370
+
371
+ type AppConfig = Readonly<{ port: number; host: string }>;
372
+
373
+ const parseConfig = (
374
+ raw: string,
375
+ ): Promise<Result<AppConfig, Readonly<{ message: string }>>> => {
376
+ const parsed: unknown = ((): unknown => {
377
+ try {
378
+ return JSON.parse(raw);
379
+ } catch {
380
+ return undefined;
381
+ }
382
+ })();
383
+
384
+ if (
385
+ !isRecord(parsed) ||
386
+ !hasKey(parsed, 'port') ||
387
+ !hasKey(parsed, 'host') ||
388
+ !isNumber(parsed.port) ||
389
+ !isString(parsed.host)
390
+ ) {
391
+ return Promise.resolve(Result.err({ message: 'Invalid config shape' }));
392
+ }
360
393
 
361
- const isDirty = await repoIsDirty();
394
+ return Promise.resolve(Result.ok({ port: parsed.port, host: parsed.host }));
395
+ };
362
396
 
363
- if (isDirty) {
364
- console.log('Repository has uncommitted changes');
365
- }
397
+ const assertValidConfig = createResultAssert({
398
+ run: parseConfig,
399
+ onSuccess: (config) => {
400
+ console.log(`✓ Config loaded: ${config.host}:${config.port}`);
401
+ },
402
+ });
403
+
404
+ await assertValidConfig('{"port":3000,"host":"localhost"}');
366
405
  ```
367
406
 
368
407
  **Options:**
@@ -377,10 +416,10 @@ if (isDirty) {
377
416
  Removes any existing directory at `dir` and recreates it, ensuring a clean target for generated assets or build output.
378
417
 
379
418
  ```tsx
380
- import { assertRepoIsClean } from 'ts-repo-utils';
419
+ import { makeEmptyDir } from 'ts-repo-utils';
381
420
 
382
- // Use in CI/build scripts to ensure clean state
383
- await assertRepoIsClean();
421
+ // Reset ./tmp/build before writing artifacts
422
+ await makeEmptyDir('./tmp/build');
384
423
  ```
385
424
 
386
425
  This helper uses `fs.rm` with `recursive` cleanup before calling `fs.mkdir`, so prefer it over manual `rimraf` + `mkdir` sequences when scripting workflows.
@@ -392,12 +431,13 @@ This helper uses `fs.rm` with `recursive` cleanup before calling `fs.mkdir`, so
392
431
  Checks if the repository has uncommitted changes.
393
432
 
394
433
  ```tsx
395
- import { type ExecException } from 'node:child_process';
434
+ import { repoIsDirty } from 'ts-repo-utils';
396
435
 
397
- type Ret = Result<
398
- readonly string[],
399
- ExecException | Readonly<{ message: string }>
400
- >;
436
+ const isDirty = await repoIsDirty();
437
+
438
+ if (isDirty) {
439
+ console.log('Repository has uncommitted changes');
440
+ }
401
441
  ```
402
442
 
403
443
  #### `assertRepoIsClean(): Promise<void>`
@@ -406,20 +446,10 @@ Checks if the repository is clean and exits with code 1 if it has uncommitted ch
406
446
  (Function version of the `assert-repo-is-clean` command)
407
447
 
408
448
  ```tsx
409
- import { checkShouldRunTypeChecks } from 'ts-repo-utils';
410
-
411
- // Use default settings (compare against origin/main)
412
- const shouldRun = await checkShouldRunTypeChecks();
413
-
414
- if (shouldRun) {
415
- await $('npm run type-check');
416
- }
449
+ import { assertRepoIsClean } from 'ts-repo-utils';
417
450
 
418
- // Custom ignore patterns and base branch
419
- const shouldRun2 = await checkShouldRunTypeChecks({
420
- pathsIgnore: ['.eslintrc.json', 'docs/', '**.md', 'scripts/'],
421
- baseBranch: 'origin/develop',
422
- });
451
+ // Use in CI/build scripts to ensure clean state
452
+ await assertRepoIsClean();
423
453
  ```
424
454
 
425
455
  **Options:**
@@ -456,19 +486,12 @@ Runs `git diff --name-only <base> [--diff-filter=d]`
456
486
  **Common Return Type:**
457
487
 
458
488
  ```tsx
459
- import { formatFilesGlob } from 'ts-repo-utils';
460
-
461
- // Format all TypeScript files in src
462
- await formatFilesGlob('src/**/*.ts');
463
-
464
- // Format specific files
465
- await formatFilesGlob('src/{index,utils}.ts');
489
+ import { type ExecException } from 'node:child_process';
466
490
 
467
- // With custom ignore function
468
- await formatFilesGlob('src/**/*.ts', {
469
- ignore: (filePath) => filePath.includes('generated'),
470
- ignoreUnknown: false, // Error on files without parser
471
- });
491
+ type Ret = Result<
492
+ readonly string[],
493
+ ExecException | Readonly<{ message: string }>
494
+ >;
472
495
  ```
473
496
 
474
497
  #### Build Optimization Utilities
@@ -479,15 +502,19 @@ Checks whether TypeScript type checks should run based on file changes from the
479
502
  (Function version of the `check-should-run-type-checks` command)
480
503
 
481
504
  ```tsx
482
- import { formatUncommittedFiles } from 'ts-repo-utils';
505
+ import { $, checkShouldRunTypeChecks } from 'ts-repo-utils';
483
506
 
484
- // Format only modified files
485
- await formatUncommittedFiles();
507
+ // Use default settings (compare against origin/main)
508
+ const shouldRun = await checkShouldRunTypeChecks();
486
509
 
487
- // With custom options
488
- await formatUncommittedFiles({
489
- untracked: false, // Skip untracked files
490
- ignore: (filePath) => filePath.includes('test'),
510
+ if (shouldRun) {
511
+ await $('npm run type-check');
512
+ }
513
+
514
+ // Custom ignore patterns and base branch
515
+ const shouldRun2 = await checkShouldRunTypeChecks({
516
+ pathsIgnore: ['.eslintrc.json', 'docs/', '**.md', 'scripts/'],
517
+ baseBranch: 'origin/develop',
491
518
  });
492
519
  ```
493
520
 
@@ -507,14 +534,19 @@ await formatUncommittedFiles({
507
534
  Formats files matching a glob pattern using Prettier.
508
535
 
509
536
  ```tsx
510
- import { type ExecException } from 'node:child_process';
537
+ import { formatFilesGlob } from 'ts-repo-utils';
511
538
 
512
- type Ret = Promise<
513
- Result<
514
- undefined,
515
- ExecException | Readonly<{ message: string }> | readonly unknown[]
516
- >
517
- >;
539
+ // Format all TypeScript files in src
540
+ await formatFilesGlob('src/**/*.ts');
541
+
542
+ // Format specific files
543
+ await formatFilesGlob('src/{index,utils}.ts');
544
+
545
+ // With custom ignore function
546
+ await formatFilesGlob('src/**/*.ts', {
547
+ ignore: (filePath) => filePath.includes('generated'),
548
+ ignoreUnknown: false, // Error on files without parser
549
+ });
518
550
  ```
519
551
 
520
552
  **Options:**
@@ -529,19 +561,15 @@ Formats only files that have been changed according to git status.
529
561
  (Function version of the `format-uncommitted` command)
530
562
 
531
563
  ```tsx
532
- import { formatDiffFrom } from 'ts-repo-utils';
533
-
534
- // Format files different from main branch
535
- await formatDiffFrom('main');
564
+ import { formatUncommittedFiles } from 'ts-repo-utils';
536
565
 
537
- // Format files different from specific commit
538
- await formatDiffFrom('abc123');
566
+ // Format only modified files
567
+ await formatUncommittedFiles();
539
568
 
540
569
  // With custom options
541
- await formatDiffFrom('main', {
542
- includeUntracked: false,
543
- ignore: (filePath) => filePath.includes('vendor'),
544
- ignoreUnknown: false, // Error on files without parser
570
+ await formatUncommittedFiles({
571
+ untracked: false, // Skip untracked files
572
+ ignore: (filePath) => filePath.includes('test'),
545
573
  });
546
574
  ```
547
575
 
@@ -573,11 +601,19 @@ Formats only files that differ from the specified base branch or commit.
573
601
  (Function version of the `format-diff-from` command)
574
602
 
575
603
  ```tsx
576
- import { genIndex } from 'ts-repo-utils';
604
+ import { formatDiffFrom } from 'ts-repo-utils';
577
605
 
578
- await genIndex({
579
- targetDirectory: './src',
580
- exclude: ['*.test.ts', '*.spec.ts'],
606
+ // Format files different from main branch
607
+ await formatDiffFrom('main');
608
+
609
+ // Format files different from specific commit
610
+ await formatDiffFrom('abc123');
611
+
612
+ // With custom options
613
+ await formatDiffFrom('main', {
614
+ includeUntracked: false,
615
+ ignore: (filePath) => filePath.includes('vendor'),
616
+ ignoreUnknown: false, // Error on files without parser
581
617
  });
582
618
  ```
583
619
 
@@ -592,6 +628,35 @@ await genIndex({
592
628
 
593
629
  **Return Type:**
594
630
 
631
+ ```tsx
632
+ import { type ExecException } from 'node:child_process';
633
+
634
+ type Ret = Promise<
635
+ Result<
636
+ undefined,
637
+ ExecException | Readonly<{ message: string }> | readonly unknown[]
638
+ >
639
+ >;
640
+ ```
641
+
642
+ ### Index File Generation
643
+
644
+ #### `genIndex(config: GenIndexConfig): Promise<Result<undefined, unknown>>`
645
+
646
+ Generates index files recursively in target directories with automatic barrel exports.
647
+ (Function version of the `gen-index-ts` command)
648
+
649
+ ```tsx
650
+ import { genIndex } from 'ts-repo-utils';
651
+
652
+ await genIndex({
653
+ targetDirectory: './src',
654
+ exclude: ['*.test.ts', '*.spec.ts'],
655
+ });
656
+ ```
657
+
658
+ **Configuration Type:**
659
+
595
660
  ```tsx
596
661
  type GenIndexConfig = Readonly<{
597
662
  /** Target directories to generate index files for (string or array of strings) */
@@ -632,39 +697,6 @@ type GenIndexConfig = Readonly<{
632
697
  }>;
633
698
  ```
634
699
 
635
- ### Index File Generation
636
-
637
- #### `genIndex(config: GenIndexConfig): Promise<Result<undefined, unknown>>`
638
-
639
- Generates index files recursively in target directories with automatic barrel exports.
640
- (Function version of the `gen-index-ts` command)
641
-
642
- ```tsx
643
- import { runCmdInStagesAcrossWorkspaces } from 'ts-repo-utils';
644
-
645
- // Run build in dependency order
646
- await runCmdInStagesAcrossWorkspaces({
647
- rootPackageJsonDir: '../',
648
- cmd: 'build',
649
- concurrency: 3,
650
- filterWorkspacePattern: (name) => !name.includes('experimental'),
651
- });
652
- ```
653
-
654
- **Configuration Type:**
655
-
656
- ```tsx
657
- import { runCmdInParallelAcrossWorkspaces } from 'ts-repo-utils';
658
-
659
- // Run tests in parallel across all packages
660
- await runCmdInParallelAcrossWorkspaces({
661
- rootPackageJsonDir: '../',
662
- cmd: 'test',
663
- concurrency: 5,
664
- filterWorkspacePattern: (name) => !name.includes('experimental'),
665
- });
666
- ```
667
-
668
700
  **Features:**
669
701
 
670
702
  - Creates barrel exports for all subdirectories
@@ -685,12 +717,15 @@ await runCmdInParallelAcrossWorkspaces({
685
717
  Executes an npm script command across all workspace packages in dependency order stages. Packages are grouped into stages where each stage contains packages whose dependencies have been completed in previous stages. Uses fail-fast behavior.
686
718
 
687
719
  ```tsx
688
- import { getWorkspacePackages } from 'ts-repo-utils';
689
-
690
- const packages = await getWorkspacePackages('.');
720
+ import { runCmdInStagesAcrossWorkspaces } from 'ts-repo-utils';
691
721
 
692
- console.log(packages.map((pkg) => pkg.name));
693
- // ['@myorg/package-a', '@myorg/package-b', ...]
722
+ // Run build in dependency order
723
+ await runCmdInStagesAcrossWorkspaces({
724
+ rootPackageJsonDir: '../',
725
+ cmd: 'build',
726
+ concurrency: 3,
727
+ filterWorkspacePattern: (name) => !name.includes('experimental'),
728
+ });
694
729
  ```
695
730
 
696
731
  **Options:**
@@ -705,12 +740,15 @@ console.log(packages.map((pkg) => pkg.name));
705
740
  Executes an npm script command across all workspace packages in parallel. Uses fail-fast behavior - stops execution immediately when any package fails.
706
741
 
707
742
  ```tsx
708
- type Package = Readonly<{
709
- name: string;
710
- path: string;
711
- packageJson: JsonValue;
712
- dependencies: Readonly<Record<string, string>>;
713
- }>;
743
+ import { runCmdInParallelAcrossWorkspaces } from 'ts-repo-utils';
744
+
745
+ // Run tests in parallel across all packages
746
+ await runCmdInParallelAcrossWorkspaces({
747
+ rootPackageJsonDir: '../',
748
+ cmd: 'test',
749
+ concurrency: 5,
750
+ filterWorkspacePattern: (name) => !name.includes('experimental'),
751
+ });
714
752
  ```
715
753
 
716
754
  **Options:**
@@ -725,21 +763,23 @@ type Package = Readonly<{
725
763
  Retrieves all workspace packages from a monorepo based on the workspace patterns defined in the root package.json file.
726
764
 
727
765
  ```tsx
728
- import { executeParallel, getWorkspacePackages } from 'ts-repo-utils';
766
+ import { getWorkspacePackages } from 'ts-repo-utils';
729
767
 
730
768
  const packages = await getWorkspacePackages('.');
731
769
 
732
- await executeParallel(packages, 'lint', 4);
770
+ console.log(packages.map((pkg) => pkg.name));
771
+ // ['@myorg/package-a', '@myorg/package-b', ...]
733
772
  ```
734
773
 
735
774
  **Return Type:**
736
775
 
737
776
  ```tsx
738
- import { executeStages, getWorkspacePackages } from 'ts-repo-utils';
739
-
740
- const packages = await getWorkspacePackages('.');
741
-
742
- await executeStages(packages, 'build', 3);
777
+ type Package = Readonly<{
778
+ name: string;
779
+ path: string;
780
+ packageJson: JsonValue;
781
+ dependencies: Readonly<Record<string, string>>;
782
+ }>;
743
783
  ```
744
784
 
745
785
  #### `executeParallel(packages, scriptName, concurrency?): Promise<readonly Result[]>`
@@ -747,31 +787,11 @@ await executeStages(packages, 'build', 3);
747
787
  Executes an npm script across multiple packages in parallel with a concurrency limit. Lower-level function used by `runCmdInParallelAcrossWorkspaces`.
748
788
 
749
789
  ```tsx
750
- import 'ts-repo-utils';
751
-
752
- // Now these functions are globally available
753
-
754
- const result = await $('npm test');
755
-
756
- if (Result.isErr(result)) {
757
- console.error(result.value);
758
- }
759
-
760
- echo('Building project...');
761
-
762
- const filePath: string = path.join('src', 'index.ts');
763
-
764
- const configJson: string = await fs.readFile('./config.json', {
765
- encoding: 'utf8',
766
- });
767
-
768
- const home = os.homedir();
790
+ import { executeParallel, getWorkspacePackages } from 'ts-repo-utils';
769
791
 
770
- const files: readonly string[] = await glob('**/*.ts');
792
+ const packages = await getWorkspacePackages('.');
771
793
 
772
- if (isDirectlyExecuted(import.meta.url)) {
773
- echo('Running as CLI');
774
- }
794
+ await executeParallel(packages, 'lint', 4);
775
795
  ```
776
796
 
777
797
  #### `executeStages(packages, scriptName, concurrency?): Promise<void>`
@@ -779,22 +799,11 @@ if (isDirectlyExecuted(import.meta.url)) {
779
799
  Executes an npm script across packages in dependency order stages. Lower-level function used by `runCmdInStagesAcrossWorkspaces`.
780
800
 
781
801
  ```tsx
782
- import {
783
- assertExt,
784
- assertRepoIsClean,
785
- formatUncommittedFiles,
786
- } from 'ts-repo-utils';
787
-
788
- // Validate file extensions
789
- await assertExt({
790
- directories: [{ path: './src', extension: '.ts' }],
791
- });
802
+ import { executeStages, getWorkspacePackages } from 'ts-repo-utils';
792
803
 
793
- // Format changed files
794
- await formatUncommittedFiles();
804
+ const packages = await getWorkspacePackages('.');
795
805
 
796
- // Ensure repository is clean (exits if dirty)
797
- await assertRepoIsClean();
806
+ await executeStages(packages, 'build', 3);
798
807
  ```
799
808
 
800
809
  **Features:**
@@ -805,64 +814,33 @@ await assertRepoIsClean();
805
814
  - Fail-fast behavior on errors
806
815
  - Circular dependency detection
807
816
 
808
- ### Globals
809
-
810
- When you import `ts-repo-utils` without destructuring, several utilities become globally available. This is useful for scripts where you want quick access to common functions without explicit imports.
811
-
812
- ```tsx
813
- import { formatFilesGlob, genIndex } from 'ts-repo-utils';
814
-
815
- // Generate barrel exports
816
- await genIndex({ targetDirectory: './src' });
817
-
818
- // Type check
819
- await $('tsc --noEmit');
820
-
821
- // Build
822
- await $('rollup -c');
823
-
824
- // Format output
825
- await formatFilesGlob('dist/**/*.js');
826
- ```
827
-
828
- - `$` - The command execution utility described above.
829
- - `Result` - A utility for Result pattern (from [ts-data-forge](https://github.com/noshiro-pf/ts-data-forge#readme))
830
- - `echo` - Equivalent to `console.log`
831
- - `cd` - Equivalent to `process.chdir`
832
- - `path` - `node:path`
833
- - `fs` - `node:fs/promises`
834
- - `os` - `node:os`
835
- - `glob` - `fast-glob`
836
- - `isDirectlyExecuted` - The script execution utility described above.
837
-
838
817
  ## Common Patterns
839
818
 
840
819
  ### Pre-commit Hook
841
820
 
842
821
  ```tsx
843
- import { assertExt, assertPathExists, assertRepoIsClean } from 'ts-repo-utils';
844
-
845
- // Check required files exist (exits with code 1 if files don't exist)
846
- await assertPathExists('./package.json', 'Package manifest');
847
-
848
- await assertPathExists('./tsconfig.json', 'TypeScript config');
822
+ import {
823
+ assertExt,
824
+ assertRepoIsClean,
825
+ formatUncommittedFiles,
826
+ } from 'ts-repo-utils';
849
827
 
850
- // Validate extensions
828
+ // Validate file extensions
851
829
  await assertExt({
852
- directories: [
853
- { path: './src', extension: '.ts' },
854
- { path: './scripts', extension: '.mjs' },
855
- ],
830
+ directories: [{ path: './src', extension: '.ts' }],
856
831
  });
857
832
 
858
- // Verify clean repository state (exits with code 1 if repo is dirty)
833
+ // Format changed files
834
+ await formatUncommittedFiles();
835
+
836
+ // Ensure repository is clean (exits if dirty)
859
837
  await assertRepoIsClean();
860
838
  ```
861
839
 
862
840
  ### Build Pipeline
863
841
 
864
842
  ```tsx
865
- import { formatFilesGlob, genIndex } from 'ts-repo-utils';
843
+ import { $, formatFilesGlob, genIndex } from 'ts-repo-utils';
866
844
 
867
845
  // Generate barrel exports
868
846
  await genIndex({ targetDirectory: './src' });
@@ -884,6 +862,7 @@ import { assertExt, assertPathExists, assertRepoIsClean } from 'ts-repo-utils';
884
862
 
885
863
  // Check required files exist (exits with code 1 if files don't exist)
886
864
  await assertPathExists('./package.json', 'Package manifest');
865
+
887
866
  await assertPathExists('./tsconfig.json', 'TypeScript config');
888
867
 
889
868
  // Validate extensions
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import * as cmd from 'cmd-ts';
3
+ import 'node:path';
3
4
  import 'ts-data-forge';
4
- import '../node-global.mjs';
5
+ import 'node:fs/promises';
6
+ import 'fast-glob';
5
7
  import { assertRepoIsClean } from '../functions/assert-repo-is-clean.mjs';
6
8
  import 'node:child_process';
7
9
  import 'prettier';
8
10
  import 'micromatch';
9
- import 'fast-glob';
10
11
  import 'node:fs';
11
12
  import 'node:url';
12
- import 'node:fs/promises';
13
13
  import '@sindresorhus/is';
14
14
 
15
15
  const cmdDef = cmd.command({
16
16
  name: 'assert-repo-is-clean-cli',
17
- version: '9.0.0',
17
+ version: '10.0.0',
18
18
  args: {
19
19
  silent: cmd.flag({
20
20
  long: 'silent',
@@ -1 +1 @@
1
- {"version":3,"file":"assert-repo-is-clean.mjs","sources":["../../src/cmd/assert-repo-is-clean.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;AAKA,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC;AACzB,IAAA,IAAI,EAAE,0BAA0B;AAChC,IAAA,OAAO,EAAE,OAAO;AAChB,IAAA,IAAI,EAAE;AACJ,QAAA,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC;AACf,YAAA,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;AAC/B,YAAA,WAAW,EAAE,sDAAsD;SACpE,CAAC;AACH,KAAA;AACD,IAAA,OAAO,EAAE,CAAC,IAAI,KAAI;QAChB,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,KAAI;AAClC,YAAA,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC;AAE1C,YAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AACjB,QAAA,CAAC,CAAC;IACJ,CAAC;AACF,CAAA,CAAC;AAEF,MAAM,IAAI,GAAG,OAAO,IAAoC,KAAmB;IACzE,MAAM,iBAAiB,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"assert-repo-is-clean.mjs","sources":["../../src/cmd/assert-repo-is-clean.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;AAKA,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC;AACzB,IAAA,IAAI,EAAE,0BAA0B;AAChC,IAAA,OAAO,EAAE,QAAQ;AACjB,IAAA,IAAI,EAAE;AACJ,QAAA,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC;AACf,YAAA,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;AAC/B,YAAA,WAAW,EAAE,sDAAsD;SACpE,CAAC;AACH,KAAA;AACD,IAAA,OAAO,EAAE,CAAC,IAAI,KAAI;QAChB,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,KAAI;AAClC,YAAA,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC;AAE1C,YAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AACjB,QAAA,CAAC,CAAC;IACJ,CAAC;AACF,CAAA,CAAC;AAEF,MAAM,IAAI,GAAG,OAAO,IAAoC,KAAmB;IACzE,MAAM,iBAAiB,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC"}
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import * as cmd from 'cmd-ts';
3
+ import 'node:path';
3
4
  import 'ts-data-forge';
4
- import '../node-global.mjs';
5
+ import 'node:fs/promises';
6
+ import 'fast-glob';
5
7
  import 'node:child_process';
6
8
  import 'prettier';
7
9
  import 'micromatch';
8
- import 'fast-glob';
9
10
  import 'node:fs';
10
11
  import 'node:url';
11
- import 'node:fs/promises';
12
12
  import { checkShouldRunTypeChecks } from '../functions/should-run.mjs';
13
13
  import '@sindresorhus/is';
14
14
 
15
15
  const cmdDef = cmd.command({
16
16
  name: 'check-should-run-type-checks-cli',
17
- version: '9.0.0',
17
+ version: '10.0.0',
18
18
  args: {
19
19
  pathsIgnore: cmd.multioption({
20
20
  long: 'paths-ignore',
@@ -1 +1 @@
1
- {"version":3,"file":"check-should-run-type-checks.mjs","sources":["../../src/cmd/check-should-run-type-checks.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;AAKA,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC;AACzB,IAAA,IAAI,EAAE,kCAAkC;AACxC,IAAA,OAAO,EAAE,OAAO;AAChB,IAAA,IAAI,EAAE;AACJ,QAAA,WAAW,EAAE,GAAG,CAAC,WAAW,CAAC;AAC3B,YAAA,IAAI,EAAE,cAAc;AACpB,YAAA,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACzC,YAAA,WAAW,EACT,0KAA0K;SAC7K,CAAC;AACF,QAAA,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC;AACrB,YAAA,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;AAC9B,YAAA,WAAW,EACT,yFAAyF;SAC5F,CAAC;AACH,KAAA;AACD,IAAA,OAAO,EAAE,CAAC,IAAI,KAAI;QAChB,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,KAAI;AAClC,YAAA,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC;AAE1C,YAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AACjB,QAAA,CAAC,CAAC;IACJ,CAAC;AACF,CAAA,CAAC;AAEF,MAAM,IAAI,GAAG,OACX,IAGE,KACe;AACjB,IAAA,MAAM,wBAAwB,CAAC;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;AAC5B,KAAA,CAAC;AACJ,CAAC;AAED,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"check-should-run-type-checks.mjs","sources":["../../src/cmd/check-should-run-type-checks.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;AAKA,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC;AACzB,IAAA,IAAI,EAAE,kCAAkC;AACxC,IAAA,OAAO,EAAE,QAAQ;AACjB,IAAA,IAAI,EAAE;AACJ,QAAA,WAAW,EAAE,GAAG,CAAC,WAAW,CAAC;AAC3B,YAAA,IAAI,EAAE,cAAc;AACpB,YAAA,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACzC,YAAA,WAAW,EACT,0KAA0K;SAC7K,CAAC;AACF,QAAA,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC;AACrB,YAAA,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;AAC9B,YAAA,WAAW,EACT,yFAAyF;SAC5F,CAAC;AACH,KAAA;AACD,IAAA,OAAO,EAAE,CAAC,IAAI,KAAI;QAChB,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,KAAI;AAClC,YAAA,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC;AAE1C,YAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AACjB,QAAA,CAAC,CAAC;IACJ,CAAC;AACF,CAAA,CAAC;AAEF,MAAM,IAAI,GAAG,OACX,IAGE,KACe;AACjB,IAAA,MAAM,wBAAwB,CAAC;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;AAC5B,KAAA,CAAC;AACJ,CAAC;AAED,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC"}