ts-repo-utils 7.1.1 → 7.3.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.
- package/README.md +264 -249
- package/dist/cmd/assert-repo-is-clean.mjs +2 -1
- package/dist/cmd/assert-repo-is-clean.mjs.map +1 -1
- package/dist/cmd/check-should-run-type-checks.mjs +2 -1
- package/dist/cmd/check-should-run-type-checks.mjs.map +1 -1
- package/dist/cmd/format-diff-from.mjs +9 -1
- package/dist/cmd/format-diff-from.mjs.map +1 -1
- package/dist/cmd/format-uncommitted.mjs +9 -1
- package/dist/cmd/format-uncommitted.mjs.map +1 -1
- package/dist/cmd/gen-index-ts.mjs +2 -1
- package/dist/cmd/gen-index-ts.mjs.map +1 -1
- package/dist/functions/format.d.mts +7 -0
- package/dist/functions/format.d.mts.map +1 -1
- package/dist/functions/format.mjs +21 -5
- package/dist/functions/format.mjs.map +1 -1
- package/dist/functions/index.d.mts +1 -0
- package/dist/functions/index.d.mts.map +1 -1
- package/dist/functions/index.mjs +1 -0
- package/dist/functions/index.mjs.map +1 -1
- package/dist/functions/is-directly-executed.d.mts +2 -0
- package/dist/functions/is-directly-executed.d.mts.map +1 -0
- package/dist/functions/is-directly-executed.mjs +6 -0
- package/dist/functions/is-directly-executed.mjs.map +1 -0
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/node-global.d.mts.map +1 -1
- package/dist/node-global.mjs +3 -0
- package/dist/node-global.mjs.map +1 -1
- package/package.json +6 -6
- package/src/cmd/assert-repo-is-clean.mts +1 -1
- package/src/cmd/check-should-run-type-checks.mts +1 -1
- package/src/cmd/format-diff-from.mts +9 -1
- package/src/cmd/format-uncommitted.mts +9 -1
- package/src/cmd/gen-index-ts.mts +1 -1
- package/src/functions/format.mts +36 -4
- package/src/functions/index.mts +1 -0
- package/src/functions/is-directly-executed.mts +4 -0
- package/src/node-global.mts +4 -2
package/README.md
CHANGED
|
@@ -12,47 +12,24 @@ A comprehensive toolkit for managing TypeScript projects with strict ESM support
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
npm
|
|
15
|
+
npm add --save-dev ts-repo-utils
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
## CLI Commands
|
|
19
|
-
|
|
20
|
-
`ts-repo-utils` provides several CLI commands that can be used directly or through npm scripts.
|
|
21
|
-
|
|
22
|
-
### `gen-index-ts`
|
|
23
|
-
|
|
24
|
-
Generates index.ts files recursively in target directories with automatic barrel exports.
|
|
25
|
-
|
|
26
18
|
```bash
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# With formatting command
|
|
31
|
-
npm exec -- gen-index-ts ./src --target-ext .mts --index-ext .mts --export-ext .mjs --fmt 'npm run fmt'
|
|
32
|
-
|
|
33
|
-
# Multiple target extensions
|
|
34
|
-
npm exec -- gen-index-ts ./src --target-ext .mts --target-ext .tsx --index-ext .mts --export-ext .mjs
|
|
35
|
-
|
|
36
|
-
# With exclude patterns
|
|
37
|
-
npm exec -- gen-index-ts ./src --target-ext .ts --index-ext .ts --export-ext .js --exclude '*.test.ts' --exclude '*.spec.ts'
|
|
19
|
+
yarn add --dev ts-repo-utils
|
|
20
|
+
```
|
|
38
21
|
|
|
39
|
-
|
|
40
|
-
|
|
22
|
+
```bash
|
|
23
|
+
pnpm add --save-dev ts-repo-utils
|
|
41
24
|
```
|
|
42
25
|
|
|
43
|
-
|
|
26
|
+
## CLI Commands
|
|
44
27
|
|
|
45
|
-
-
|
|
46
|
-
- `--target-ext` - File extensions to include in the index file (required, can be specified multiple times)
|
|
47
|
-
- `--index-ext` - Extension of the index file to be generated (required)
|
|
48
|
-
- `--export-ext` - Extension of the export statements in the index file (required, or 'none')
|
|
49
|
-
- `--exclude` - Glob patterns of files to exclude (optional, can be specified multiple times)
|
|
50
|
-
- `--fmt` - Command to format after generating the index file (optional)
|
|
51
|
-
- `--silent` - Suppress output messages (optional)
|
|
28
|
+
`ts-repo-utils` provides several CLI commands that can be used directly or through npm scripts.
|
|
52
29
|
|
|
53
30
|
### `assert-repo-is-clean`
|
|
54
31
|
|
|
55
|
-
Checks if repository is clean and exits with code 1 if
|
|
32
|
+
Checks if the repository is clean (i.e., there are no uncommitted changes, untracked files, or staged files) and exits with code 1 if any are present.
|
|
56
33
|
|
|
57
34
|
```bash
|
|
58
35
|
# Basic usage
|
|
@@ -64,6 +41,8 @@ npm exec -- assert-repo-is-clean --silent
|
|
|
64
41
|
|
|
65
42
|
```yaml
|
|
66
43
|
# Example in GitHub Actions
|
|
44
|
+
- name: Format check
|
|
45
|
+
run: npm run fmt
|
|
67
46
|
- name: Check if there is no file diff
|
|
68
47
|
run: npm exec -- assert-repo-is-clean
|
|
69
48
|
```
|
|
@@ -90,6 +69,7 @@ npm exec -- format-uncommitted --silent
|
|
|
90
69
|
- `--exclude-modified` - Exclude modified files (default: false)
|
|
91
70
|
- `--exclude-staged` - Exclude staged files (default: false)
|
|
92
71
|
- `--silent` - Suppress output messages (default: false)
|
|
72
|
+
- `--ignore-unknown` - Skip files without a Prettier parser instead of erroring (default: true)
|
|
93
73
|
|
|
94
74
|
### `format-diff-from`
|
|
95
75
|
|
|
@@ -107,9 +87,16 @@ npm exec -- format-diff-from main --exclude-untracked
|
|
|
107
87
|
|
|
108
88
|
# Silent mode
|
|
109
89
|
npm exec -- format-diff-from main --silent
|
|
90
|
+
```
|
|
110
91
|
|
|
111
|
-
|
|
112
|
-
|
|
92
|
+
Example in npm scripts:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"scripts": {
|
|
97
|
+
"fmt": "npm exec -- format-diff-from origin/main"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
113
100
|
```
|
|
114
101
|
|
|
115
102
|
**Options:**
|
|
@@ -119,10 +106,55 @@ npm exec -- format-diff-from main --silent
|
|
|
119
106
|
- `--exclude-modified` - Exclude modified files (default: false)
|
|
120
107
|
- `--exclude-staged` - Exclude staged files (default: false)
|
|
121
108
|
- `--silent` - Suppress output messages (default: false)
|
|
109
|
+
- `--ignore-unknown` - Skip files without a Prettier parser instead of erroring (default: true)
|
|
110
|
+
|
|
111
|
+
### `gen-index-ts`
|
|
112
|
+
|
|
113
|
+
Generates index.ts files recursively in target directories with automatic barrel exports.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Basic usage with required options
|
|
117
|
+
npm exec -- gen-index-ts ./src --target-ext .mts --index-ext .mts --export-ext .mjs
|
|
118
|
+
|
|
119
|
+
# With formatting command
|
|
120
|
+
npm exec -- gen-index-ts ./src --target-ext .mts --index-ext .mts --export-ext .mjs --fmt 'npm run fmt'
|
|
121
|
+
|
|
122
|
+
# Multiple target extensions
|
|
123
|
+
npm exec -- gen-index-ts ./src --target-ext .mts --target-ext .tsx --index-ext .mts --export-ext .mjs
|
|
124
|
+
|
|
125
|
+
# With exclude patterns
|
|
126
|
+
npm exec -- gen-index-ts ./src --target-ext .ts --index-ext .ts --export-ext .js --exclude '*.test.ts' --exclude '*.spec.ts'
|
|
127
|
+
|
|
128
|
+
# Example in npm scripts
|
|
129
|
+
"gi": "gen-index-ts ./src --index-ext .mts --export-ext .mjs --target-ext .mts --target-ext .tsx --fmt 'npm run fmt'"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Features:**
|
|
133
|
+
|
|
134
|
+
- Creates barrel exports for all subdirectories
|
|
135
|
+
- Supports complex glob exclusion patterns (using micromatch)
|
|
136
|
+
- Automatically formats generated files using the project's Prettier config
|
|
137
|
+
- Works with both single directories and directory arrays
|
|
138
|
+
- Respects source and export extension configuration
|
|
139
|
+
|
|
140
|
+
**Benefits:**
|
|
141
|
+
|
|
142
|
+
- Prevents forgetting to export modules
|
|
143
|
+
- TypeScript can detect duplicate variables, type names, etc.
|
|
144
|
+
|
|
145
|
+
**Options:**
|
|
146
|
+
|
|
147
|
+
- `<target-directory>` - Directory where the index file will be generated (comma-separated list can be used)
|
|
148
|
+
- `--target-ext` - File extensions to include in the index file (required, can be specified multiple times)
|
|
149
|
+
- `--index-ext` - Extension of the index file to be generated (required)
|
|
150
|
+
- `--export-ext` - Extension of the export statements in the index file (required, or 'none')
|
|
151
|
+
- `--exclude` - Glob patterns of files to exclude (optional, can be specified multiple times)
|
|
152
|
+
- `--fmt` - Command to format after generating the index file (optional)
|
|
153
|
+
- `--silent` - Suppress output messages (optional)
|
|
122
154
|
|
|
123
155
|
### `check-should-run-type-checks`
|
|
124
156
|
|
|
125
|
-
Checks
|
|
157
|
+
Checks whether TypeScript type checks should run based on file changes from the base branch. Optimizes CI/CD pipelines by skipping type checks when only non-TypeScript files have changed. The determination of "non-TypeScript files" is based on configurable ignore patterns, which can be specified using the `--paths-ignore` option.
|
|
126
158
|
|
|
127
159
|
```bash
|
|
128
160
|
# Basic usage (compares against origin/main)
|
|
@@ -163,39 +195,46 @@ npm exec -- check-should-run-type-checks \
|
|
|
163
195
|
|
|
164
196
|
When running in GitHub Actions, the command sets the `GITHUB_OUTPUT` environment variable with `should_run=true` or `should_run=false`, which can be used in subsequent steps.
|
|
165
197
|
|
|
166
|
-
|
|
198
|
+
## API Reference
|
|
167
199
|
|
|
168
|
-
|
|
200
|
+
### Command Execution
|
|
169
201
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
202
|
+
#### `$(command: string, options?: ExecOptions): Promise<ExecResult>`
|
|
203
|
+
|
|
204
|
+
Executes a shell command asynchronously with type-safe results.
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
import { $, Result } from 'ts-repo-utils';
|
|
208
|
+
|
|
209
|
+
// or
|
|
210
|
+
// import "ts-repo-utils"; // $ and Result are globally defined in ts-repo-utils
|
|
211
|
+
|
|
212
|
+
const result = await $('npm test');
|
|
213
|
+
|
|
214
|
+
if (Result.isOk(result)) {
|
|
215
|
+
console.log('Tests passed:', result.value.stdout);
|
|
216
|
+
} else {
|
|
217
|
+
console.error('Tests failed:', result.value.message);
|
|
177
218
|
}
|
|
178
219
|
```
|
|
179
220
|
|
|
180
|
-
|
|
221
|
+
**Options:**
|
|
181
222
|
|
|
182
|
-
|
|
223
|
+
- `silent?: boolean` - Don't log command/output (default: false)
|
|
224
|
+
- `'node:child_process'` `exec` function options
|
|
183
225
|
|
|
184
|
-
|
|
185
|
-
# GitHub Actions example
|
|
186
|
-
- name: Format check
|
|
187
|
-
run: |
|
|
188
|
-
npm run fmt
|
|
189
|
-
npm exec -- assert-repo-is-clean
|
|
226
|
+
**Return Type:**
|
|
190
227
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
228
|
+
```typescript
|
|
229
|
+
type Ret = Promise<
|
|
230
|
+
Result<
|
|
231
|
+
Readonly<{ stdout: string | Buffer; stderr: string | Buffer }>,
|
|
232
|
+
import('node:child_process').ExecException
|
|
233
|
+
>
|
|
234
|
+
>;
|
|
196
235
|
```
|
|
197
236
|
|
|
198
|
-
|
|
237
|
+
### Script Execution Utilities
|
|
199
238
|
|
|
200
239
|
### Path and File System Utilities
|
|
201
240
|
|
|
@@ -207,7 +246,7 @@ Checks if a file or directory exists at the specified path.
|
|
|
207
246
|
import { pathExists } from 'ts-repo-utils';
|
|
208
247
|
|
|
209
248
|
const exists = await pathExists('./src/index.ts');
|
|
210
|
-
console.log(exists); // true or false
|
|
249
|
+
console.log(exists satisfies boolean); // true or false
|
|
211
250
|
```
|
|
212
251
|
|
|
213
252
|
#### `assertPathExists(filePath: string, description?: string): Promise<void>`
|
|
@@ -221,8 +260,6 @@ import { assertPathExists } from 'ts-repo-utils';
|
|
|
221
260
|
await assertPathExists('./src/index.ts', 'Entry point file');
|
|
222
261
|
```
|
|
223
262
|
|
|
224
|
-
### File Extension Validation
|
|
225
|
-
|
|
226
263
|
#### `assertExt(config: CheckExtConfig): Promise<void>`
|
|
227
264
|
|
|
228
265
|
Validates that all files in specified directories have the correct extensions. Exits with code 1 if any files have incorrect extensions.
|
|
@@ -248,12 +285,12 @@ await assertExt({
|
|
|
248
285
|
**Configuration Type:**
|
|
249
286
|
|
|
250
287
|
```typescript
|
|
251
|
-
type CheckExtConfig =
|
|
252
|
-
directories: {
|
|
288
|
+
type CheckExtConfig = Readonly<{
|
|
289
|
+
directories: readonly Readonly<{
|
|
253
290
|
path: string; // Directory path to check
|
|
254
291
|
extension: string; // Expected file extension (including the dot)
|
|
255
|
-
ignorePatterns?: string[]; // Optional glob patterns to ignore
|
|
256
|
-
}[];
|
|
292
|
+
ignorePatterns?: readonly string[]; // Optional glob patterns to ignore
|
|
293
|
+
}>[];
|
|
257
294
|
}>;
|
|
258
295
|
```
|
|
259
296
|
|
|
@@ -274,7 +311,8 @@ if (isDirty) {
|
|
|
274
311
|
|
|
275
312
|
#### `assertRepoIsClean(): Promise<void>`
|
|
276
313
|
|
|
277
|
-
Checks if repository is clean and exits with code 1 if it has uncommitted changes (shows changes and diff).
|
|
314
|
+
Checks if the repository is clean and exits with code 1 if it has uncommitted changes (shows changes and diff).
|
|
315
|
+
(Function version of the `assert-repo-is-clean` command)
|
|
278
316
|
|
|
279
317
|
```typescript
|
|
280
318
|
import { assertRepoIsClean } from 'ts-repo-utils';
|
|
@@ -291,22 +329,22 @@ await assertRepoIsClean();
|
|
|
291
329
|
|
|
292
330
|
##### `getUntrackedFiles(options?)`
|
|
293
331
|
|
|
294
|
-
|
|
332
|
+
Gets untracked files from the working tree (files not added to git).
|
|
295
333
|
Runs `git ls-files --others --exclude-standard [--deleted]`
|
|
296
334
|
|
|
297
335
|
##### `getModifiedFiles(options?)`
|
|
298
336
|
|
|
299
|
-
|
|
337
|
+
Gets modified files from the working tree (files that have been changed but not staged).
|
|
300
338
|
Runs `git diff --name-only [--diff-filter=d]`
|
|
301
339
|
|
|
302
340
|
##### `getStagedFiles(options?)`
|
|
303
341
|
|
|
304
|
-
|
|
342
|
+
Gets files that are staged for commit (files added with git add).
|
|
305
343
|
Runs `git diff --staged --name-only [--diff-filter=d]`
|
|
306
344
|
|
|
307
345
|
##### `getDiffFrom(base: string, options?)`
|
|
308
346
|
|
|
309
|
-
|
|
347
|
+
Gets files that differ from the specified base branch or commit.
|
|
310
348
|
Runs `git diff --name-only <base> [--diff-filter=d]`
|
|
311
349
|
|
|
312
350
|
**Common options:**
|
|
@@ -319,95 +357,15 @@ Runs `git diff --name-only <base> [--diff-filter=d]`
|
|
|
319
357
|
```typescript
|
|
320
358
|
type Ret = Result<
|
|
321
359
|
readonly string[],
|
|
322
|
-
ExecException | Readonly<{ message: string }>
|
|
323
|
-
>;
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
### Build Optimization Utilities
|
|
327
|
-
|
|
328
|
-
#### `checkShouldRunTypeChecks(options?): Promise<boolean>`
|
|
329
|
-
|
|
330
|
-
Checks if TypeScript type checks should run based on the diff from a base branch. Optimizes CI/CD pipelines by skipping type checks when only non-TypeScript files are changed.
|
|
331
|
-
|
|
332
|
-
```typescript
|
|
333
|
-
import { checkShouldRunTypeChecks } from 'ts-repo-utils';
|
|
334
|
-
|
|
335
|
-
// Use default settings (compare against origin/main)
|
|
336
|
-
const shouldRun = await checkShouldRunTypeChecks();
|
|
337
|
-
|
|
338
|
-
if (shouldRun) {
|
|
339
|
-
await $('npm run type-check');
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Custom ignore patterns and base branch
|
|
343
|
-
const shouldRun = await checkShouldRunTypeChecks({
|
|
344
|
-
pathsIgnore: ['.eslintrc.json', 'docs/', '**.md', 'scripts/'],
|
|
345
|
-
baseBranch: 'origin/develop',
|
|
346
|
-
});
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
**Options:**
|
|
350
|
-
|
|
351
|
-
- `pathsIgnore?` - Patterns to ignore when checking if type checks should run:
|
|
352
|
-
- Exact file matches: `.cspell.json`
|
|
353
|
-
- Directory prefixes: `docs/` (matches any file in docs directory)
|
|
354
|
-
- File extensions: `**.md` (matches any markdown file)
|
|
355
|
-
- Default: `['LICENSE', '.editorconfig', '.gitignore', '.cspell.json', '.markdownlint-cli2.mjs', '.npmignore', '.prettierignore', '.prettierrc', 'docs/', '**.md', '**.txt']`
|
|
356
|
-
- `baseBranch?` - Base branch to compare against (default: `origin/main`)
|
|
357
|
-
|
|
358
|
-
**GitHub Actions Integration:**
|
|
359
|
-
|
|
360
|
-
When running in GitHub Actions, sets `GITHUB_OUTPUT` with `should_run=true/false`:
|
|
361
|
-
|
|
362
|
-
```yaml
|
|
363
|
-
- name: Check if type checks should run
|
|
364
|
-
id: check_diff
|
|
365
|
-
run: npx check-should-run-type-checks
|
|
366
|
-
|
|
367
|
-
- name: Run type checks
|
|
368
|
-
if: steps.check_diff.outputs.should_run == 'true'
|
|
369
|
-
run: npm run type-check
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
### Command Execution
|
|
373
|
-
|
|
374
|
-
#### `$(command: string, options?: ExecOptions): Promise<ExecResult>`
|
|
375
|
-
|
|
376
|
-
Executes a shell command asynchronously with timeout support and type-safe results.
|
|
377
|
-
|
|
378
|
-
```typescript
|
|
379
|
-
import { $ } from 'ts-repo-utils';
|
|
380
|
-
|
|
381
|
-
const result = await $('npm test', { timeout: 60000 });
|
|
382
|
-
|
|
383
|
-
if (result.type === 'ok') {
|
|
384
|
-
console.log('Tests passed:', result.stdout);
|
|
385
|
-
} else {
|
|
386
|
-
console.error('Tests failed:', result.exception.message);
|
|
387
|
-
}
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
**Options:**
|
|
391
|
-
|
|
392
|
-
- `silent?: boolean` - Don't log command/output (default: false)
|
|
393
|
-
- `'node:child_process'` `exec` function options
|
|
394
|
-
|
|
395
|
-
**Return Type:**
|
|
396
|
-
|
|
397
|
-
```typescript
|
|
398
|
-
type Ret = Promise<
|
|
399
|
-
Result<
|
|
400
|
-
Readonly<{ stdout: string | Buffer; stderr: string | Buffer }>,
|
|
401
|
-
import('node:child_process').ExecException
|
|
402
|
-
>
|
|
360
|
+
import('node:child_process').ExecException | Readonly<{ message: string }>
|
|
403
361
|
>;
|
|
404
362
|
```
|
|
405
363
|
|
|
406
364
|
### Code Formatting Utilities
|
|
407
365
|
|
|
408
|
-
#### `formatFilesGlob(pathGlob: string): Promise<Result<undefined, unknown>>`
|
|
366
|
+
#### `formatFilesGlob(pathGlob: string, options?): Promise<Result<undefined, unknown>>`
|
|
409
367
|
|
|
410
|
-
|
|
368
|
+
Formats files matching a glob pattern using Prettier.
|
|
411
369
|
|
|
412
370
|
```typescript
|
|
413
371
|
import { formatFilesGlob } from 'ts-repo-utils';
|
|
@@ -417,21 +375,36 @@ await formatFilesGlob('src/**/*.ts');
|
|
|
417
375
|
|
|
418
376
|
// Format specific files
|
|
419
377
|
await formatFilesGlob('src/{index,utils}.ts');
|
|
378
|
+
|
|
379
|
+
// With custom ignore function
|
|
380
|
+
await formatFilesGlob('src/**/*.ts', {
|
|
381
|
+
ignore: (filePath) => filePath.includes('generated'),
|
|
382
|
+
ignoreUnknown: false, // Error on files without parser
|
|
383
|
+
});
|
|
420
384
|
```
|
|
421
385
|
|
|
422
386
|
**Options:**
|
|
423
387
|
|
|
424
388
|
- `silent?` - Suppress output messages (default: false)
|
|
389
|
+
- `ignoreUnknown?` - Skip files without a Prettier parser instead of erroring (default: true)
|
|
390
|
+
- `ignore?` - Custom function to ignore files (default: built-in ignore list)
|
|
425
391
|
|
|
426
|
-
#### `formatUncommittedFiles(): Promise<Result>`
|
|
392
|
+
#### `formatUncommittedFiles(options?): Promise<Result>`
|
|
427
393
|
|
|
428
|
-
|
|
394
|
+
Formats only files that have been changed according to git status.
|
|
395
|
+
(Function version of the `format-uncommitted` command)
|
|
429
396
|
|
|
430
397
|
```typescript
|
|
431
398
|
import { formatUncommittedFiles } from 'ts-repo-utils';
|
|
432
399
|
|
|
433
400
|
// Format only modified files
|
|
434
401
|
await formatUncommittedFiles();
|
|
402
|
+
|
|
403
|
+
// With custom options
|
|
404
|
+
await formatUncommittedFiles({
|
|
405
|
+
untracked: false, // Skip untracked files
|
|
406
|
+
ignore: (filePath) => filePath.includes('test'),
|
|
407
|
+
});
|
|
435
408
|
```
|
|
436
409
|
|
|
437
410
|
**Options:**
|
|
@@ -440,6 +413,8 @@ await formatUncommittedFiles();
|
|
|
440
413
|
- `modified?` - Format modified files (default: true)
|
|
441
414
|
- `staged?` - Format staged files (default: true)
|
|
442
415
|
- `silent?` - Suppress output messages (default: false)
|
|
416
|
+
- `ignoreUnknown?` - Skip files without a Prettier parser instead of erroring (default: true)
|
|
417
|
+
- `ignore?` - Custom function to ignore files (default: built-in ignore list)
|
|
443
418
|
|
|
444
419
|
**Return Type:**
|
|
445
420
|
|
|
@@ -447,14 +422,17 @@ await formatUncommittedFiles();
|
|
|
447
422
|
type Ret = Promise<
|
|
448
423
|
Result<
|
|
449
424
|
undefined,
|
|
450
|
-
|
|
425
|
+
| import('node:child_process').ExecException
|
|
426
|
+
| Readonly<{ message: string }>
|
|
427
|
+
| readonly unknown[]
|
|
451
428
|
>
|
|
452
429
|
>;
|
|
453
430
|
```
|
|
454
431
|
|
|
455
|
-
#### `formatDiffFrom(base: string): Promise<Result>`
|
|
432
|
+
#### `formatDiffFrom(base: string, options?): Promise<Result>`
|
|
456
433
|
|
|
457
|
-
|
|
434
|
+
Formats only files that differ from the specified base branch or commit.
|
|
435
|
+
(Function version of the `format-diff-from` command)
|
|
458
436
|
|
|
459
437
|
```typescript
|
|
460
438
|
import { formatDiffFrom } from 'ts-repo-utils';
|
|
@@ -464,6 +442,13 @@ await formatDiffFrom('main');
|
|
|
464
442
|
|
|
465
443
|
// Format files different from specific commit
|
|
466
444
|
await formatDiffFrom('abc123');
|
|
445
|
+
|
|
446
|
+
// With custom options
|
|
447
|
+
await formatDiffFrom('main', {
|
|
448
|
+
includeUntracked: false,
|
|
449
|
+
ignore: (filePath) => filePath.includes('vendor'),
|
|
450
|
+
ignoreUnknown: false, // Error on files without parser
|
|
451
|
+
});
|
|
467
452
|
```
|
|
468
453
|
|
|
469
454
|
**Options:**
|
|
@@ -472,6 +457,8 @@ await formatDiffFrom('abc123');
|
|
|
472
457
|
- `includeModified?` - Include modified files in addition to diff files (default: true)
|
|
473
458
|
- `includeStaged?` - Include staged files in addition to diff files (default: true)
|
|
474
459
|
- `silent?` - Suppress output messages (default: false)
|
|
460
|
+
- `ignoreUnknown?` - Skip files without a Prettier parser instead of erroring (default: true)
|
|
461
|
+
- `ignore?` - Custom function to ignore files (default: built-in ignore list)
|
|
475
462
|
|
|
476
463
|
**Return Type:**
|
|
477
464
|
|
|
@@ -479,26 +466,102 @@ await formatDiffFrom('abc123');
|
|
|
479
466
|
type Ret = Promise<
|
|
480
467
|
Result<
|
|
481
468
|
undefined,
|
|
482
|
-
|
|
469
|
+
| import('node:child_process').ExecException
|
|
470
|
+
| Readonly<{ message: string }>
|
|
471
|
+
| readonly unknown[]
|
|
483
472
|
>
|
|
484
473
|
>;
|
|
485
474
|
```
|
|
486
475
|
|
|
487
|
-
###
|
|
476
|
+
### Index File Generation
|
|
477
|
+
|
|
478
|
+
#### `genIndex(config: GenIndexConfig): Promise<Result<undefined, unknown>>`
|
|
479
|
+
|
|
480
|
+
Generates index files recursively in target directories with automatic barrel exports.
|
|
481
|
+
(Function version of the `gen-index-ts` command)
|
|
482
|
+
|
|
483
|
+
```typescript
|
|
484
|
+
import { genIndex } from 'ts-repo-utils';
|
|
485
|
+
|
|
486
|
+
await genIndex({
|
|
487
|
+
targetDirectory: './src',
|
|
488
|
+
exclude: ['*.test.ts', '*.spec.ts'],
|
|
489
|
+
});
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
**Configuration Type:**
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
type GenIndexConfig = Readonly<{
|
|
496
|
+
/**
|
|
497
|
+
* Target directories to generate index files for (string or array of
|
|
498
|
+
* strings)
|
|
499
|
+
*/
|
|
500
|
+
targetDirectory: string | readonly string[];
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Glob patterns for files or predicate function to exclude from exports
|
|
504
|
+
* (default: excludes `'**\/*.{test,spec}.?(c|m)[jt]s?(x)'` and
|
|
505
|
+
* `'**\/*.d.?(c|m)ts'`)
|
|
506
|
+
*/
|
|
507
|
+
exclude?:
|
|
508
|
+
| readonly string[]
|
|
509
|
+
| ((
|
|
510
|
+
args: Readonly<{
|
|
511
|
+
absolutePath: string;
|
|
512
|
+
relativePath: string;
|
|
513
|
+
fileName: string;
|
|
514
|
+
}>,
|
|
515
|
+
) => boolean);
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* File extensions of source files to include in exports (default: ['.ts',
|
|
519
|
+
* '.tsx'])
|
|
520
|
+
*/
|
|
521
|
+
targetExtensions?: readonly `.${string}`[];
|
|
522
|
+
|
|
523
|
+
/** File extension of index files to generate (default: '.ts') */
|
|
524
|
+
indexFileExtension?: `.${string}`;
|
|
525
|
+
|
|
526
|
+
/** File extension to use in export statements (default: '.js') */
|
|
527
|
+
exportStatementExtension?: `.${string}` | 'none';
|
|
528
|
+
|
|
529
|
+
/** Command to run for formatting generated files (optional) */
|
|
530
|
+
formatCommand?: string;
|
|
531
|
+
|
|
532
|
+
/** Whether to suppress output during execution (default: false) */
|
|
533
|
+
silent?: boolean;
|
|
534
|
+
}>;
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
**Features:**
|
|
538
|
+
|
|
539
|
+
- Creates barrel exports for all subdirectories
|
|
540
|
+
- Supports complex glob exclusion patterns (using micromatch)
|
|
541
|
+
- Automatically formats generated files using the project's Prettier config
|
|
542
|
+
- Works with both single directories and directory arrays
|
|
543
|
+
- Respects source and export extension configuration
|
|
544
|
+
|
|
545
|
+
**Benefits:**
|
|
546
|
+
|
|
547
|
+
- Prevents forgetting to export modules
|
|
548
|
+
- TypeScript can detect duplicate variables, type names, etc.
|
|
549
|
+
|
|
550
|
+
### Monorepo Workspace Management Utilities
|
|
488
551
|
|
|
489
552
|
#### `runCmdInStagesAcrossWorkspaces(options): Promise<void>`
|
|
490
553
|
|
|
491
|
-
Executes
|
|
554
|
+
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.
|
|
492
555
|
|
|
493
556
|
```typescript
|
|
494
557
|
import { runCmdInStagesAcrossWorkspaces } from 'ts-repo-utils';
|
|
495
558
|
|
|
496
559
|
// Run build in dependency order
|
|
497
560
|
await runCmdInStagesAcrossWorkspaces({
|
|
498
|
-
rootPackageJsonDir: '
|
|
561
|
+
rootPackageJsonDir: '../',
|
|
499
562
|
cmd: 'build',
|
|
500
563
|
concurrency: 3,
|
|
501
|
-
filterWorkspacePattern: (name) => !name.includes('
|
|
564
|
+
filterWorkspacePattern: (name) => !name.includes('experimental'),
|
|
502
565
|
});
|
|
503
566
|
```
|
|
504
567
|
|
|
@@ -511,16 +574,17 @@ await runCmdInStagesAcrossWorkspaces({
|
|
|
511
574
|
|
|
512
575
|
#### `runCmdInParallelAcrossWorkspaces(options): Promise<void>`
|
|
513
576
|
|
|
514
|
-
Executes
|
|
577
|
+
Executes an npm script command across all workspace packages in parallel. Uses fail-fast behavior - stops execution immediately when any package fails.
|
|
515
578
|
|
|
516
579
|
```typescript
|
|
517
580
|
import { runCmdInParallelAcrossWorkspaces } from 'ts-repo-utils';
|
|
518
581
|
|
|
519
582
|
// Run tests in parallel across all packages
|
|
520
583
|
await runCmdInParallelAcrossWorkspaces({
|
|
521
|
-
rootPackageJsonDir: '
|
|
584
|
+
rootPackageJsonDir: '../',
|
|
522
585
|
cmd: 'test',
|
|
523
586
|
concurrency: 5,
|
|
587
|
+
filterWorkspacePattern: (name) => !name.includes('experimental'),
|
|
524
588
|
});
|
|
525
589
|
```
|
|
526
590
|
|
|
@@ -546,17 +610,17 @@ console.log(packages.map((pkg) => pkg.name));
|
|
|
546
610
|
**Return Type:**
|
|
547
611
|
|
|
548
612
|
```typescript
|
|
549
|
-
type Package = {
|
|
613
|
+
type Package = Readonly<{
|
|
550
614
|
name: string;
|
|
551
615
|
path: string;
|
|
552
616
|
packageJson: JsonValue;
|
|
553
|
-
dependencies: Record<string, string
|
|
554
|
-
}
|
|
617
|
+
dependencies: Readonly<Record<string, string>>;
|
|
618
|
+
}>;
|
|
555
619
|
```
|
|
556
620
|
|
|
557
621
|
#### `executeParallel(packages, scriptName, concurrency?): Promise<readonly Result[]>`
|
|
558
622
|
|
|
559
|
-
Executes
|
|
623
|
+
Executes an npm script across multiple packages in parallel with a concurrency limit. Lower-level function used by `runCmdInParallelAcrossWorkspaces`.
|
|
560
624
|
|
|
561
625
|
```typescript
|
|
562
626
|
import { executeParallel, getWorkspacePackages } from 'ts-repo-utils';
|
|
@@ -567,7 +631,7 @@ await executeParallel(packages, 'lint', 4);
|
|
|
567
631
|
|
|
568
632
|
#### `executeStages(packages, scriptName, concurrency?): Promise<void>`
|
|
569
633
|
|
|
570
|
-
Executes
|
|
634
|
+
Executes an npm script across packages in dependency order stages. Lower-level function used by `runCmdInStagesAcrossWorkspaces`.
|
|
571
635
|
|
|
572
636
|
```typescript
|
|
573
637
|
import { executeStages, getWorkspacePackages } from 'ts-repo-utils';
|
|
@@ -584,93 +648,44 @@ await executeStages(packages, 'build', 3);
|
|
|
584
648
|
- Fail-fast behavior on errors
|
|
585
649
|
- Circular dependency detection
|
|
586
650
|
|
|
587
|
-
###
|
|
588
|
-
|
|
589
|
-
#### `genIndex(config: GenIndexConfig): Promise<Result<undefined, unknown>>`
|
|
651
|
+
### Globals
|
|
590
652
|
|
|
591
|
-
|
|
653
|
+
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.
|
|
592
654
|
|
|
593
655
|
```typescript
|
|
594
|
-
import
|
|
595
|
-
|
|
596
|
-
await genIndex({
|
|
597
|
-
targetDirectory: './src',
|
|
598
|
-
exclude: ['*.test.ts', '*.spec.ts'],
|
|
599
|
-
});
|
|
600
|
-
```
|
|
656
|
+
import 'ts-repo-utils';
|
|
601
657
|
|
|
602
|
-
|
|
658
|
+
// Now these functions are globally available
|
|
603
659
|
|
|
604
|
-
|
|
605
|
-
type GenIndexConfig = DeepReadonly<{
|
|
606
|
-
/**
|
|
607
|
-
* Target directories to generate index files for (string or array of
|
|
608
|
-
* strings)
|
|
609
|
-
*/
|
|
610
|
-
targetDirectory: string | readonly string[];
|
|
660
|
+
await $('npm test');
|
|
611
661
|
|
|
612
|
-
|
|
613
|
-
* Glob patterns of files or predicate function to exclude from exports
|
|
614
|
-
* (default: excludes `'**\/*.{test,spec}.?(c|m)[jt]s?(x)'` and
|
|
615
|
-
* `'**\/*.d.?(c|m)ts'`)
|
|
616
|
-
*/
|
|
617
|
-
exclude?:
|
|
618
|
-
| readonly string[]
|
|
619
|
-
| ((
|
|
620
|
-
args: Readonly<{
|
|
621
|
-
absolutePath: string;
|
|
622
|
-
relativePath: string;
|
|
623
|
-
fileName: string;
|
|
624
|
-
}>,
|
|
625
|
-
) => boolean);
|
|
662
|
+
echo('Building project...');
|
|
626
663
|
|
|
627
|
-
|
|
628
|
-
targetExtensions?: readonly `.${string}`[];
|
|
664
|
+
const filePath: string = path.join('src', 'index.ts');
|
|
629
665
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
/** File extension to use in export statements (default: '.js') */
|
|
634
|
-
exportStatementExtension?: `.${string}` | 'none';
|
|
635
|
-
|
|
636
|
-
/** Command to run for formatting generated files (optional) */
|
|
637
|
-
formatCommand?: string;
|
|
666
|
+
const configJson: string = await fs.readFile('./config.json', {
|
|
667
|
+
encoding: 'utf8',
|
|
668
|
+
});
|
|
638
669
|
|
|
639
|
-
|
|
640
|
-
silent?: boolean;
|
|
641
|
-
}>;
|
|
670
|
+
const files: readonly string[] = await glob('**/*.ts');
|
|
642
671
|
```
|
|
643
672
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
-
|
|
647
|
-
-
|
|
648
|
-
-
|
|
649
|
-
- Works with both single directories and directory arrays
|
|
650
|
-
- Respects source and export extension configuration
|
|
651
|
-
|
|
652
|
-
**Benefits:**
|
|
653
|
-
|
|
654
|
-
- Prevents forgetting to export libraries
|
|
655
|
-
- tsc can detect duplicate variables, type names, etc.
|
|
656
|
-
|
|
657
|
-
## Key Features
|
|
658
|
-
|
|
659
|
-
- **Type Safety**: All functions use strict TypeScript types with readonly parameters
|
|
660
|
-
- **Error Handling**: Comprehensive error handling with descriptive messages
|
|
661
|
-
- **Git Integration**: Built-in git status and diff utilities
|
|
662
|
-
- **Formatting**: Prettier integration with configuration resolution
|
|
663
|
-
- **ESM Support**: Designed for ES modules with .mts/.mjs extension handling
|
|
664
|
-
- **Concurrent Processing**: Uses Promise.all for performance optimization
|
|
665
|
-
- **Configurable**: Flexible configuration options with sensible defaults
|
|
666
|
-
- **Console Feedback**: Informative logging throughout operations
|
|
673
|
+
- `$` - The command execution utility described above.
|
|
674
|
+
- `echo` - Equivalent to `console.log`
|
|
675
|
+
- `path` - `node:path`
|
|
676
|
+
- `fs` - `node:fs/promises`
|
|
677
|
+
- `glob` - `fast-glob`
|
|
667
678
|
|
|
668
679
|
## Common Patterns
|
|
669
680
|
|
|
670
681
|
### Pre-commit Hook
|
|
671
682
|
|
|
672
683
|
```typescript
|
|
673
|
-
import {
|
|
684
|
+
import {
|
|
685
|
+
assertExt,
|
|
686
|
+
assertRepoIsClean,
|
|
687
|
+
formatUncommittedFiles,
|
|
688
|
+
} from 'ts-repo-utils';
|
|
674
689
|
|
|
675
690
|
// Validate file extensions
|
|
676
691
|
await assertExt({
|
|
@@ -687,15 +702,7 @@ await assertRepoIsClean();
|
|
|
687
702
|
### Build Pipeline
|
|
688
703
|
|
|
689
704
|
```typescript
|
|
690
|
-
import {
|
|
691
|
-
|
|
692
|
-
// Validate extensions
|
|
693
|
-
await assertExt({
|
|
694
|
-
directories: [
|
|
695
|
-
{ path: './src', extension: '.ts' },
|
|
696
|
-
{ path: './scripts', extension: '.mjs' },
|
|
697
|
-
],
|
|
698
|
-
});
|
|
705
|
+
import { formatFilesGlob, genIndex } from 'ts-repo-utils';
|
|
699
706
|
|
|
700
707
|
// Generate barrel exports
|
|
701
708
|
await genIndex({ targetDirectory: './src' });
|
|
@@ -713,12 +720,20 @@ await formatFilesGlob('dist/**/*.js');
|
|
|
713
720
|
### Project Validation
|
|
714
721
|
|
|
715
722
|
```typescript
|
|
716
|
-
import {
|
|
723
|
+
import { assertExt, assertPathExists, assertRepoIsClean } from 'ts-repo-utils';
|
|
717
724
|
|
|
718
725
|
// Check required files exist (exits with code 1 if files don't exist)
|
|
719
726
|
await assertPathExists('./package.json', 'Package manifest');
|
|
720
727
|
await assertPathExists('./tsconfig.json', 'TypeScript config');
|
|
721
728
|
|
|
729
|
+
// Validate extensions
|
|
730
|
+
await assertExt({
|
|
731
|
+
directories: [
|
|
732
|
+
{ path: './src', extension: '.ts' },
|
|
733
|
+
{ path: './scripts', extension: '.mjs' },
|
|
734
|
+
],
|
|
735
|
+
});
|
|
736
|
+
|
|
722
737
|
// Verify clean repository state (exits with code 1 if repo is dirty)
|
|
723
738
|
await assertRepoIsClean();
|
|
724
739
|
```
|