ts-repo-utils 9.0.1 → 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 +190 -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 +19 -19
  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
@@ -215,9 +215,6 @@ Executes a shell command asynchronously with type-safe results.
215
215
  ```tsx
216
216
  import { $, Result } from 'ts-repo-utils';
217
217
 
218
- // or
219
- // import "ts-repo-utils"; // $ and Result are globally defined in ts-repo-utils
220
-
221
218
  const result = await $('npm test');
222
219
 
223
220
  if (Result.isOk(result)) {
@@ -254,9 +251,6 @@ Determines whether a script is being executed directly via CLI or imported as a
254
251
  ```tsx
255
252
  import { isDirectlyExecuted } from 'ts-repo-utils';
256
253
 
257
- // or
258
- // import "ts-repo-utils"; // isDirectlyExecuted is globally defined in ts-repo-utils
259
-
260
254
  // calculator.mjs
261
255
  export const add = (a: number, b: number): number => a + b;
262
256
 
@@ -312,6 +306,28 @@ await assertPathExists('./src/index.ts', 'Entry point file');
312
306
 
313
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.
314
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
+
315
331
  ```tsx
316
332
  import { assertExt } from 'ts-repo-utils';
317
333
 
@@ -330,9 +346,7 @@ await assertExt({
330
346
  });
331
347
  ```
332
348
 
333
- #### `assertExt(config: CheckExtConfig): Promise<void>`
334
-
335
- Validates that all files in specified directories have the correct extensions. Exits with code 1 if any files have incorrect extensions.
349
+ **Configuration Type:**
336
350
 
337
351
  ```tsx
338
352
  type CheckExtConfig = Readonly<{
@@ -344,15 +358,6 @@ type CheckExtConfig = Readonly<{
344
358
  }>;
345
359
  ```
346
360
 
347
- **Configuration Type:**
348
-
349
- ```tsx
350
- import { makeEmptyDir } from 'ts-repo-utils';
351
-
352
- // Reset ./tmp/build before writing artifacts
353
- await makeEmptyDir('./tmp/build');
354
- ```
355
-
356
361
  ### Result Utilities
357
362
 
358
363
  #### `createResultAssert(options): (config) => Promise<TOk>`
@@ -360,13 +365,43 @@ await makeEmptyDir('./tmp/build');
360
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.
361
366
 
362
367
  ```tsx
363
- 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
+ }
364
393
 
365
- const isDirty = await repoIsDirty();
394
+ return Promise.resolve(Result.ok({ port: parsed.port, host: parsed.host }));
395
+ };
366
396
 
367
- if (isDirty) {
368
- console.log('Repository has uncommitted changes');
369
- }
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"}');
370
405
  ```
371
406
 
372
407
  **Options:**
@@ -381,10 +416,10 @@ if (isDirty) {
381
416
  Removes any existing directory at `dir` and recreates it, ensuring a clean target for generated assets or build output.
382
417
 
383
418
  ```tsx
384
- import { assertRepoIsClean } from 'ts-repo-utils';
419
+ import { makeEmptyDir } from 'ts-repo-utils';
385
420
 
386
- // Use in CI/build scripts to ensure clean state
387
- await assertRepoIsClean();
421
+ // Reset ./tmp/build before writing artifacts
422
+ await makeEmptyDir('./tmp/build');
388
423
  ```
389
424
 
390
425
  This helper uses `fs.rm` with `recursive` cleanup before calling `fs.mkdir`, so prefer it over manual `rimraf` + `mkdir` sequences when scripting workflows.
@@ -396,12 +431,13 @@ This helper uses `fs.rm` with `recursive` cleanup before calling `fs.mkdir`, so
396
431
  Checks if the repository has uncommitted changes.
397
432
 
398
433
  ```tsx
399
- import { type ExecException } from 'node:child_process';
434
+ import { repoIsDirty } from 'ts-repo-utils';
400
435
 
401
- type Ret = Result<
402
- readonly string[],
403
- ExecException | Readonly<{ message: string }>
404
- >;
436
+ const isDirty = await repoIsDirty();
437
+
438
+ if (isDirty) {
439
+ console.log('Repository has uncommitted changes');
440
+ }
405
441
  ```
406
442
 
407
443
  #### `assertRepoIsClean(): Promise<void>`
@@ -410,20 +446,10 @@ Checks if the repository is clean and exits with code 1 if it has uncommitted ch
410
446
  (Function version of the `assert-repo-is-clean` command)
411
447
 
412
448
  ```tsx
413
- import { checkShouldRunTypeChecks } from 'ts-repo-utils';
414
-
415
- // Use default settings (compare against origin/main)
416
- const shouldRun = await checkShouldRunTypeChecks();
417
-
418
- if (shouldRun) {
419
- await $('npm run type-check');
420
- }
449
+ import { assertRepoIsClean } from 'ts-repo-utils';
421
450
 
422
- // Custom ignore patterns and base branch
423
- const shouldRun2 = await checkShouldRunTypeChecks({
424
- pathsIgnore: ['.eslintrc.json', 'docs/', '**.md', 'scripts/'],
425
- baseBranch: 'origin/develop',
426
- });
451
+ // Use in CI/build scripts to ensure clean state
452
+ await assertRepoIsClean();
427
453
  ```
428
454
 
429
455
  **Options:**
@@ -460,19 +486,12 @@ Runs `git diff --name-only <base> [--diff-filter=d]`
460
486
  **Common Return Type:**
461
487
 
462
488
  ```tsx
463
- import { formatFilesGlob } from 'ts-repo-utils';
464
-
465
- // Format all TypeScript files in src
466
- await formatFilesGlob('src/**/*.ts');
467
-
468
- // Format specific files
469
- await formatFilesGlob('src/{index,utils}.ts');
489
+ import { type ExecException } from 'node:child_process';
470
490
 
471
- // With custom ignore function
472
- await formatFilesGlob('src/**/*.ts', {
473
- ignore: (filePath) => filePath.includes('generated'),
474
- ignoreUnknown: false, // Error on files without parser
475
- });
491
+ type Ret = Result<
492
+ readonly string[],
493
+ ExecException | Readonly<{ message: string }>
494
+ >;
476
495
  ```
477
496
 
478
497
  #### Build Optimization Utilities
@@ -483,15 +502,19 @@ Checks whether TypeScript type checks should run based on file changes from the
483
502
  (Function version of the `check-should-run-type-checks` command)
484
503
 
485
504
  ```tsx
486
- import { formatUncommittedFiles } from 'ts-repo-utils';
505
+ import { $, checkShouldRunTypeChecks } from 'ts-repo-utils';
487
506
 
488
- // Format only modified files
489
- await formatUncommittedFiles();
507
+ // Use default settings (compare against origin/main)
508
+ const shouldRun = await checkShouldRunTypeChecks();
490
509
 
491
- // With custom options
492
- await formatUncommittedFiles({
493
- untracked: false, // Skip untracked files
494
- 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',
495
518
  });
496
519
  ```
497
520
 
@@ -511,14 +534,19 @@ await formatUncommittedFiles({
511
534
  Formats files matching a glob pattern using Prettier.
512
535
 
513
536
  ```tsx
514
- import { type ExecException } from 'node:child_process';
537
+ import { formatFilesGlob } from 'ts-repo-utils';
515
538
 
516
- type Ret = Promise<
517
- Result<
518
- undefined,
519
- ExecException | Readonly<{ message: string }> | readonly unknown[]
520
- >
521
- >;
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
+ });
522
550
  ```
523
551
 
524
552
  **Options:**
@@ -533,19 +561,15 @@ Formats only files that have been changed according to git status.
533
561
  (Function version of the `format-uncommitted` command)
534
562
 
535
563
  ```tsx
536
- import { formatDiffFrom } from 'ts-repo-utils';
537
-
538
- // Format files different from main branch
539
- await formatDiffFrom('main');
564
+ import { formatUncommittedFiles } from 'ts-repo-utils';
540
565
 
541
- // Format files different from specific commit
542
- await formatDiffFrom('abc123');
566
+ // Format only modified files
567
+ await formatUncommittedFiles();
543
568
 
544
569
  // With custom options
545
- await formatDiffFrom('main', {
546
- includeUntracked: false,
547
- ignore: (filePath) => filePath.includes('vendor'),
548
- ignoreUnknown: false, // Error on files without parser
570
+ await formatUncommittedFiles({
571
+ untracked: false, // Skip untracked files
572
+ ignore: (filePath) => filePath.includes('test'),
549
573
  });
550
574
  ```
551
575
 
@@ -577,11 +601,19 @@ Formats only files that differ from the specified base branch or commit.
577
601
  (Function version of the `format-diff-from` command)
578
602
 
579
603
  ```tsx
580
- import { genIndex } from 'ts-repo-utils';
604
+ import { formatDiffFrom } from 'ts-repo-utils';
581
605
 
582
- await genIndex({
583
- targetDirectory: './src',
584
- 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
585
617
  });
586
618
  ```
587
619
 
@@ -596,6 +628,35 @@ await genIndex({
596
628
 
597
629
  **Return Type:**
598
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
+
599
660
  ```tsx
600
661
  type GenIndexConfig = Readonly<{
601
662
  /** Target directories to generate index files for (string or array of strings) */
@@ -636,39 +697,6 @@ type GenIndexConfig = Readonly<{
636
697
  }>;
637
698
  ```
638
699
 
639
- ### Index File Generation
640
-
641
- #### `genIndex(config: GenIndexConfig): Promise<Result<undefined, unknown>>`
642
-
643
- Generates index files recursively in target directories with automatic barrel exports.
644
- (Function version of the `gen-index-ts` command)
645
-
646
- ```tsx
647
- import { runCmdInStagesAcrossWorkspaces } from 'ts-repo-utils';
648
-
649
- // Run build in dependency order
650
- await runCmdInStagesAcrossWorkspaces({
651
- rootPackageJsonDir: '../',
652
- cmd: 'build',
653
- concurrency: 3,
654
- filterWorkspacePattern: (name) => !name.includes('experimental'),
655
- });
656
- ```
657
-
658
- **Configuration Type:**
659
-
660
- ```tsx
661
- import { runCmdInParallelAcrossWorkspaces } from 'ts-repo-utils';
662
-
663
- // Run tests in parallel across all packages
664
- await runCmdInParallelAcrossWorkspaces({
665
- rootPackageJsonDir: '../',
666
- cmd: 'test',
667
- concurrency: 5,
668
- filterWorkspacePattern: (name) => !name.includes('experimental'),
669
- });
670
- ```
671
-
672
700
  **Features:**
673
701
 
674
702
  - Creates barrel exports for all subdirectories
@@ -689,12 +717,15 @@ await runCmdInParallelAcrossWorkspaces({
689
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.
690
718
 
691
719
  ```tsx
692
- import { getWorkspacePackages } from 'ts-repo-utils';
693
-
694
- const packages = await getWorkspacePackages('.');
720
+ import { runCmdInStagesAcrossWorkspaces } from 'ts-repo-utils';
695
721
 
696
- console.log(packages.map((pkg) => pkg.name));
697
- // ['@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
+ });
698
729
  ```
699
730
 
700
731
  **Options:**
@@ -709,12 +740,15 @@ console.log(packages.map((pkg) => pkg.name));
709
740
  Executes an npm script command across all workspace packages in parallel. Uses fail-fast behavior - stops execution immediately when any package fails.
710
741
 
711
742
  ```tsx
712
- type Package = Readonly<{
713
- name: string;
714
- path: string;
715
- packageJson: JsonValue;
716
- dependencies: Readonly<Record<string, string>>;
717
- }>;
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
+ });
718
752
  ```
719
753
 
720
754
  **Options:**
@@ -729,21 +763,23 @@ type Package = Readonly<{
729
763
  Retrieves all workspace packages from a monorepo based on the workspace patterns defined in the root package.json file.
730
764
 
731
765
  ```tsx
732
- import { executeParallel, getWorkspacePackages } from 'ts-repo-utils';
766
+ import { getWorkspacePackages } from 'ts-repo-utils';
733
767
 
734
768
  const packages = await getWorkspacePackages('.');
735
769
 
736
- await executeParallel(packages, 'lint', 4);
770
+ console.log(packages.map((pkg) => pkg.name));
771
+ // ['@myorg/package-a', '@myorg/package-b', ...]
737
772
  ```
738
773
 
739
774
  **Return Type:**
740
775
 
741
776
  ```tsx
742
- import { executeStages, getWorkspacePackages } from 'ts-repo-utils';
743
-
744
- const packages = await getWorkspacePackages('.');
745
-
746
- 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
+ }>;
747
783
  ```
748
784
 
749
785
  #### `executeParallel(packages, scriptName, concurrency?): Promise<readonly Result[]>`
@@ -751,31 +787,11 @@ await executeStages(packages, 'build', 3);
751
787
  Executes an npm script across multiple packages in parallel with a concurrency limit. Lower-level function used by `runCmdInParallelAcrossWorkspaces`.
752
788
 
753
789
  ```tsx
754
- import 'ts-repo-utils';
755
-
756
- // Now these functions are globally available
757
-
758
- const result = await $('npm test');
759
-
760
- if (Result.isErr(result)) {
761
- console.error(result.value);
762
- }
763
-
764
- echo('Building project...');
765
-
766
- const filePath: string = path.join('src', 'index.ts');
767
-
768
- const configJson: string = await fs.readFile('./config.json', {
769
- encoding: 'utf8',
770
- });
771
-
772
- const home = os.homedir();
790
+ import { executeParallel, getWorkspacePackages } from 'ts-repo-utils';
773
791
 
774
- const files: readonly string[] = await glob('**/*.ts');
792
+ const packages = await getWorkspacePackages('.');
775
793
 
776
- if (isDirectlyExecuted(import.meta.url)) {
777
- echo('Running as CLI');
778
- }
794
+ await executeParallel(packages, 'lint', 4);
779
795
  ```
780
796
 
781
797
  #### `executeStages(packages, scriptName, concurrency?): Promise<void>`
@@ -783,22 +799,11 @@ if (isDirectlyExecuted(import.meta.url)) {
783
799
  Executes an npm script across packages in dependency order stages. Lower-level function used by `runCmdInStagesAcrossWorkspaces`.
784
800
 
785
801
  ```tsx
786
- import {
787
- assertExt,
788
- assertRepoIsClean,
789
- formatUncommittedFiles,
790
- } from 'ts-repo-utils';
791
-
792
- // Validate file extensions
793
- await assertExt({
794
- directories: [{ path: './src', extension: '.ts' }],
795
- });
802
+ import { executeStages, getWorkspacePackages } from 'ts-repo-utils';
796
803
 
797
- // Format changed files
798
- await formatUncommittedFiles();
804
+ const packages = await getWorkspacePackages('.');
799
805
 
800
- // Ensure repository is clean (exits if dirty)
801
- await assertRepoIsClean();
806
+ await executeStages(packages, 'build', 3);
802
807
  ```
803
808
 
804
809
  **Features:**
@@ -809,64 +814,33 @@ await assertRepoIsClean();
809
814
  - Fail-fast behavior on errors
810
815
  - Circular dependency detection
811
816
 
812
- ### Globals
813
-
814
- 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.
815
-
816
- ```tsx
817
- import { formatFilesGlob, genIndex } from 'ts-repo-utils';
818
-
819
- // Generate barrel exports
820
- await genIndex({ targetDirectory: './src' });
821
-
822
- // Type check
823
- await $('tsc --noEmit');
824
-
825
- // Build
826
- await $('rollup -c');
827
-
828
- // Format output
829
- await formatFilesGlob('dist/**/*.js');
830
- ```
831
-
832
- - `$` - The command execution utility described above.
833
- - `Result` - A utility for Result pattern (from [ts-data-forge](https://github.com/noshiro-pf/ts-data-forge#readme))
834
- - `echo` - Equivalent to `console.log`
835
- - `cd` - Equivalent to `process.chdir`
836
- - `path` - `node:path`
837
- - `fs` - `node:fs/promises`
838
- - `os` - `node:os`
839
- - `glob` - `fast-glob`
840
- - `isDirectlyExecuted` - The script execution utility described above.
841
-
842
817
  ## Common Patterns
843
818
 
844
819
  ### Pre-commit Hook
845
820
 
846
821
  ```tsx
847
- import { assertExt, assertPathExists, assertRepoIsClean } from 'ts-repo-utils';
848
-
849
- // Check required files exist (exits with code 1 if files don't exist)
850
- await assertPathExists('./package.json', 'Package manifest');
851
-
852
- await assertPathExists('./tsconfig.json', 'TypeScript config');
822
+ import {
823
+ assertExt,
824
+ assertRepoIsClean,
825
+ formatUncommittedFiles,
826
+ } from 'ts-repo-utils';
853
827
 
854
- // Validate extensions
828
+ // Validate file extensions
855
829
  await assertExt({
856
- directories: [
857
- { path: './src', extension: '.ts' },
858
- { path: './scripts', extension: '.mjs' },
859
- ],
830
+ directories: [{ path: './src', extension: '.ts' }],
860
831
  });
861
832
 
862
- // 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)
863
837
  await assertRepoIsClean();
864
838
  ```
865
839
 
866
840
  ### Build Pipeline
867
841
 
868
842
  ```tsx
869
- import { formatFilesGlob, genIndex } from 'ts-repo-utils';
843
+ import { $, formatFilesGlob, genIndex } from 'ts-repo-utils';
870
844
 
871
845
  // Generate barrel exports
872
846
  await genIndex({ targetDirectory: './src' });
@@ -888,6 +862,7 @@ import { assertExt, assertPathExists, assertRepoIsClean } from 'ts-repo-utils';
888
862
 
889
863
  // Check required files exist (exits with code 1 if files don't exist)
890
864
  await assertPathExists('./package.json', 'Package manifest');
865
+
891
866
  await assertPathExists('./tsconfig.json', 'TypeScript config');
892
867
 
893
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.1',
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.1',
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"}