ts-repo-utils 10.2.0 → 10.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -10
- package/dist/cmd/check-should-run.d.mts +3 -0
- package/dist/cmd/check-should-run.d.mts.map +1 -0
- package/dist/cmd/check-should-run.mjs +44 -0
- package/dist/cmd/check-should-run.mjs.map +1 -0
- package/dist/cmd/gen-index-ts.mjs +1 -0
- package/dist/cmd/gen-index-ts.mjs.map +1 -1
- package/dist/entry-point.mjs +1 -1
- package/dist/functions/format.d.mts.map +1 -1
- package/dist/functions/format.mjs +13 -12
- package/dist/functions/format.mjs.map +1 -1
- package/dist/functions/index.mjs +1 -1
- package/dist/functions/should-run.d.mts +62 -1
- package/dist/functions/should-run.d.mts.map +1 -1
- package/dist/functions/should-run.mjs +38 -34
- package/dist/functions/should-run.mjs.map +1 -1
- package/dist/functions/workspace-utils/get-workspace-packages.d.mts.map +1 -1
- package/dist/functions/workspace-utils/get-workspace-packages.mjs +2 -5
- package/dist/functions/workspace-utils/get-workspace-packages.mjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +11 -13
- package/src/cmd/check-should-run.mts +45 -0
- package/src/functions/format.mts +23 -13
- package/src/functions/should-run.mts +134 -59
- package/src/functions/should-run.test.mts +196 -0
- package/src/functions/workspace-utils/get-workspace-packages.mts +3 -10
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/ts-repo-utils)
|
|
10
10
|
[](https://github.com/noshiro-pf/mono/blob/main/libs/ts-repo-utils/LICENSE)
|
|
11
|
-
[](https://codecov.io/gh/noshiro-pf/mono)
|
|
12
12
|
|
|
13
13
|
Utilities for TypeScript Repositories.
|
|
14
14
|
|
|
@@ -161,10 +161,56 @@ npm exec -- gen-index-ts ./src --target-ext .mts --index-ext .mts --export-ext .
|
|
|
161
161
|
- `--min-depth` - Minimum depth to start generating index files (default: 0)
|
|
162
162
|
- `--silent` - Suppress output messages (optional)
|
|
163
163
|
|
|
164
|
+
### `check-should-run`
|
|
165
|
+
|
|
166
|
+
Checks whether a CI step should run, based on which files differ from the base branch. Reports `false` when every changed file matches one of the `--paths-ignore` patterns, so a step can be skipped when nothing it checks has changed.
|
|
167
|
+
|
|
168
|
+
Prefer this over a workflow-level `paths-ignore` trigger filter: a workflow that a path filter skips never reports a status check, so a pull request that changed only the filtered paths waits forever on a required check that never arrives. Gating the individual steps keeps the workflow running — and reporting — while doing no work.
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# Skip when the diff only touches a directory nothing checks
|
|
172
|
+
npm exec -- check-should-run --paths-ignore 'experimental/'
|
|
173
|
+
|
|
174
|
+
# Several patterns, and a custom base branch
|
|
175
|
+
npm exec -- check-should-run \
|
|
176
|
+
--paths-ignore 'experimental/' \
|
|
177
|
+
--paths-ignore 'docs/' \
|
|
178
|
+
--paths-ignore '**.md' \
|
|
179
|
+
--base-branch origin/develop
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```yaml
|
|
183
|
+
# Example in GitHub Actions
|
|
184
|
+
- name: Check diff
|
|
185
|
+
id: check_diff
|
|
186
|
+
run: npm exec -- check-should-run --paths-ignore 'experimental/'
|
|
187
|
+
|
|
188
|
+
- name: Run the checks
|
|
189
|
+
if: steps.check_diff.outputs.should_run == 'true'
|
|
190
|
+
run: npm run check
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Options:**
|
|
194
|
+
|
|
195
|
+
- `--paths-ignore` - Patterns whose files do not affect the gated step (optional, can be specified multiple times). Matched with [micromatch](https://github.com/micromatch/micromatch) (with `dot: true`) against paths relative to the repository root, with one shorthand: a pattern ending with `/` is a directory prefix.
|
|
196
|
+
- Exact file matches: `.editorconfig`
|
|
197
|
+
- Directory prefixes: `docs/` (the same as `docs/**`)
|
|
198
|
+
- Globs: `**.md`, `libs/*/samples/**`
|
|
199
|
+
- Default: `[]` — nothing is ignored, so the step always runs when anything changed
|
|
200
|
+
- `--base-branch` - Base branch to compare against for determining changed files (default: `origin/main`)
|
|
201
|
+
|
|
202
|
+
An empty diff reads as "nothing changed", so it reports `should_run=false`. On a push to the base branch itself the diff against that branch is empty for that reason; pass the commit the branch pointed at before the push as `--base-branch` there.
|
|
203
|
+
|
|
204
|
+
**GitHub Actions Integration:**
|
|
205
|
+
|
|
206
|
+
When running in GitHub Actions, the command appends `should_run=true` or `should_run=false` to the file named by the `GITHUB_OUTPUT` environment variable, which can be used in subsequent steps.
|
|
207
|
+
|
|
164
208
|
### `check-should-run-type-checks`
|
|
165
209
|
|
|
166
210
|
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.
|
|
167
211
|
|
|
212
|
+
This is [`check-should-run`](#check-should-run) with a default ignore list of the files a TypeScript project typically has but never type-checks. For a step that is not a type check, use `check-should-run` and state its paths.
|
|
213
|
+
|
|
168
214
|
```bash
|
|
169
215
|
# Basic usage (compares against origin/main)
|
|
170
216
|
npm exec -- check-should-run-type-checks
|
|
@@ -193,11 +239,11 @@ npm exec -- check-should-run-type-checks \
|
|
|
193
239
|
|
|
194
240
|
**Options:**
|
|
195
241
|
|
|
196
|
-
- `--paths-ignore` - Patterns to ignore when checking if type checks should run (optional, can be specified multiple times)
|
|
242
|
+
- `--paths-ignore` - Patterns to ignore when checking if type checks should run (optional, can be specified multiple times). Matched as described for [`check-should-run`](#check-should-run); passing it replaces the default list rather than adding to it.
|
|
197
243
|
- Supports exact file matches: `.cspell.config.yaml`
|
|
198
244
|
- Directory prefixes: `docs/` (matches any file in docs directory)
|
|
199
245
|
- File extensions: `**.md` (matches any markdown file)
|
|
200
|
-
- Default: `['LICENSE', '.editorconfig', '.gitignore', '.cspell.config.yaml', '.markdownlint-cli2.mjs', '.npmignore', '.prettierignore', '.prettierrc', 'docs/', '**.md', '**.txt']`
|
|
246
|
+
- Default: `['LICENSE', '.editorconfig', '.gitignore', '.cspell.json', '.cspell.config.yaml', '.markdownlint-cli2.mjs', '.npmignore', '.prettierignore', '.prettierrc', 'docs/', '**.md', '**.txt']`
|
|
201
247
|
- `--base-branch` - Base branch to compare against for determining changed files (default: `origin/main`)
|
|
202
248
|
|
|
203
249
|
**GitHub Actions Integration:**
|
|
@@ -498,13 +544,27 @@ type Ret = Result<
|
|
|
498
544
|
|
|
499
545
|
#### Build Optimization Utilities
|
|
500
546
|
|
|
547
|
+
##### `checkShouldRun(options?): Promise<boolean>`
|
|
548
|
+
|
|
549
|
+
Checks whether a CI step should run, based on which files differ from the base branch. Reports `false` when every changed file matches one of the ignored patterns.
|
|
550
|
+
(Function version of the `check-should-run` command)
|
|
551
|
+
|
|
501
552
|
##### `checkShouldRunTypeChecks(options?): Promise<boolean>`
|
|
502
553
|
|
|
503
|
-
|
|
554
|
+
`checkShouldRun` with a default ignore list of the files a TypeScript project typically has but never type-checks. Optimizes CI/CD pipelines by skipping type checks when only non-TypeScript files have changed.
|
|
504
555
|
(Function version of the `check-should-run-type-checks` command)
|
|
505
556
|
|
|
506
557
|
```tsx
|
|
507
|
-
import { $, checkShouldRunTypeChecks } from 'ts-repo-utils';
|
|
558
|
+
import { $, checkShouldRun, checkShouldRunTypeChecks } from 'ts-repo-utils';
|
|
559
|
+
|
|
560
|
+
// Gate any step on the paths it cares about
|
|
561
|
+
const shouldRunStyleChecks = await checkShouldRun({
|
|
562
|
+
pathsIgnore: ['experimental/'],
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
if (shouldRunStyleChecks) {
|
|
566
|
+
await $('npm run fmt:check');
|
|
567
|
+
}
|
|
508
568
|
|
|
509
569
|
// Use default settings (compare against origin/main)
|
|
510
570
|
const shouldRun = await checkShouldRunTypeChecks();
|
|
@@ -520,15 +580,17 @@ const shouldRun2 = await checkShouldRunTypeChecks({
|
|
|
520
580
|
});
|
|
521
581
|
```
|
|
522
582
|
|
|
523
|
-
**Options:**
|
|
583
|
+
**Options (both functions):**
|
|
524
584
|
|
|
525
|
-
- `pathsIgnore?` - Patterns to
|
|
585
|
+
- `pathsIgnore?` - Patterns whose files do not affect the gated step. Matched with [micromatch](https://github.com/micromatch/micromatch) (with `dot: true`) against paths relative to the repository root, with a trailing `/` as the shorthand for a directory:
|
|
526
586
|
- Exact file matches: `.cspell.config.yaml`
|
|
527
|
-
- Directory prefixes: `docs/` (
|
|
528
|
-
-
|
|
529
|
-
- Default: `['LICENSE', '.editorconfig', '.gitignore', '.cspell.config.yaml', '.markdownlint-cli2.mjs', '.npmignore', '.prettierignore', '.prettierrc', 'docs/', '**.md', '**.txt']`
|
|
587
|
+
- Directory prefixes: `docs/` (the same as `docs/**`)
|
|
588
|
+
- Globs: `**.md` (matches any markdown file), `libs/*/samples/**`
|
|
589
|
+
- Default: `[]` for `checkShouldRun`; for `checkShouldRunTypeChecks`, `['LICENSE', '.editorconfig', '.gitignore', '.cspell.json', '.cspell.config.yaml', '.markdownlint-cli2.mjs', '.npmignore', '.prettierignore', '.prettierrc', 'docs/', '**.md', '**.txt']` — passing the option replaces that list rather than adding to it
|
|
530
590
|
- `baseBranch?` - Base branch to compare against (default: `origin/main`)
|
|
531
591
|
|
|
592
|
+
Both return whether the step should run, and, in GitHub Actions, append `should_run=<result>` to the file named by `GITHUB_OUTPUT`. An empty diff reads as "nothing changed" and so returns `false`.
|
|
593
|
+
|
|
532
594
|
### Code Formatting Utilities
|
|
533
595
|
|
|
534
596
|
#### `formatFilesGlob(pathGlob: string, options?): Promise<Result<undefined, unknown>>`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-should-run.d.mts","sourceRoot":"","sources":["../../src/cmd/check-should-run.mts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as cmd from 'cmd-ts';
|
|
3
|
+
import { Arr } from 'ts-data-forge';
|
|
4
|
+
import 'node:path';
|
|
5
|
+
import 'node:fs/promises';
|
|
6
|
+
import 'fast-glob';
|
|
7
|
+
import 'node:child_process';
|
|
8
|
+
import 'prettier';
|
|
9
|
+
import 'micromatch';
|
|
10
|
+
import 'node:fs';
|
|
11
|
+
import 'node:url';
|
|
12
|
+
import { checkShouldRun } from '../functions/should-run.mjs';
|
|
13
|
+
import '@sindresorhus/is';
|
|
14
|
+
|
|
15
|
+
const cmdDef = cmd.command({
|
|
16
|
+
name: "check-should-run-cli",
|
|
17
|
+
version: "10.2.0",
|
|
18
|
+
args: {
|
|
19
|
+
pathsIgnore: cmd.multioption({
|
|
20
|
+
long: "paths-ignore",
|
|
21
|
+
type: cmd.optional(cmd.array(cmd.string)),
|
|
22
|
+
description: 'Patterns whose files do not affect the gated step. Matched with micromatch against repository-relative paths, with a trailing "/" as the shorthand for a directory (e.g. "experimental/", ".editorconfig", "**.md"). Defaults to ignoring nothing.'
|
|
23
|
+
}),
|
|
24
|
+
baseBranch: cmd.option({
|
|
25
|
+
long: "base-branch",
|
|
26
|
+
type: cmd.optional(cmd.string),
|
|
27
|
+
description: 'Base branch to compare against for determining changed files. Defaults to "origin/main"'
|
|
28
|
+
})
|
|
29
|
+
},
|
|
30
|
+
handler: (args) => {
|
|
31
|
+
main(args).catch((error) => {
|
|
32
|
+
console.error("An error occurred:", error);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const main = async (args) => {
|
|
38
|
+
await checkShouldRun({
|
|
39
|
+
pathsIgnore: args.pathsIgnore,
|
|
40
|
+
baseBranch: args.baseBranch
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
await cmd.run(cmdDef, Arr.skip(process.argv, 2));
|
|
44
|
+
//# sourceMappingURL=check-should-run.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-should-run.mjs","sources":["../../src/cmd/check-should-run.mts"],"sourcesContent":["#!/usr/bin/env node\n\nimport * as cmd from 'cmd-ts';\nimport { Arr } from 'ts-data-forge';\nimport { checkShouldRun } from '../functions/index.mjs';\n\nconst cmdDef = cmd.command({\n name: 'check-should-run-cli',\n version: '10.2.0',\n args: {\n pathsIgnore: cmd.multioption({\n long: 'paths-ignore',\n type: cmd.optional(cmd.array(cmd.string)),\n description:\n 'Patterns whose files do not affect the gated step. Matched with micromatch against repository-relative paths, with a trailing \"/\" as the shorthand for a directory (e.g. \"experimental/\", \".editorconfig\", \"**.md\"). Defaults to ignoring nothing.',\n }),\n baseBranch: cmd.option({\n long: 'base-branch',\n type: cmd.optional(cmd.string),\n description:\n 'Base branch to compare against for determining changed files. Defaults to \"origin/main\"',\n }),\n },\n handler: (args) => {\n main(args).catch((error: unknown) => {\n console.error('An error occurred:', error);\n\n process.exit(1);\n });\n },\n});\n\nconst main = async (\n args: Readonly<{\n pathsIgnore?: readonly string[];\n baseBranch?: string;\n }>,\n): Promise<void> => {\n await checkShouldRun({\n pathsIgnore: args.pathsIgnore,\n baseBranch: args.baseBranch,\n });\n};\n\nawait cmd.run(cmdDef, Arr.skip(process.argv, 2));\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAMA,MAAM,MAAA,GAAS,IAAI,OAAA,CAAQ;AAAA,EACzB,IAAA,EAAM,sBAAA;AAAA,EACN,OAAA,EAAS,QAAA;AAAA,EACT,IAAA,EAAM;AAAA,IACJ,WAAA,EAAa,IAAI,WAAA,CAAY;AAAA,MAC3B,IAAA,EAAM,cAAA;AAAA,MACN,MAAM,GAAA,CAAI,QAAA,CAAS,IAAI,KAAA,CAAM,GAAA,CAAI,MAAM,CAAC,CAAA;AAAA,MACxC,WAAA,EACE;AAAA,KACH,CAAA;AAAA,IACD,UAAA,EAAY,IAAI,MAAA,CAAO;AAAA,MACrB,IAAA,EAAM,aAAA;AAAA,MACN,IAAA,EAAM,GAAA,CAAI,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA;AAAA,MAC7B,WAAA,EACE;AAAA,KACH;AAAA,GACH;AAAA,EACA,OAAA,EAAS,CAAC,IAAA,KAAS;AACjB,IAAA,IAAA,CAAK,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,KAAA,KAAmB;AACnC,MAAA,OAAA,CAAQ,KAAA,CAAM,sBAAsB,KAAK,CAAA;AAEzC,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IAChB,CAAC,CAAA;AAAA,EACH;AACF,CAAC,CAAA;AAED,MAAM,IAAA,GAAO,OACX,IAAA,KAIkB;AAClB,EAAA,MAAM,cAAA,CAAe;AAAA,IACnB,aAAa,IAAA,CAAK,WAAA;AAAA,IAClB,YAAY,IAAA,CAAK;AAAA,GAClB,CAAA;AACH,CAAA;AAEA,MAAM,GAAA,CAAI,IAAI,MAAA,EAAQ,GAAA,CAAI,KAAK,OAAA,CAAQ,IAAA,EAAM,CAAC,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gen-index-ts.mjs","sources":["../../src/cmd/gen-index-ts.mts"],"sourcesContent":["#!/usr/bin/env node\n\n/* transformer-ignore convert-to-readonly */\n\nimport * as cmd from 'cmd-ts';\nimport { Arr, expectType } from 'ts-data-forge';\n// eslint-disable-next-line import-x/no-internal-modules, import-x/extensions\nimport { type InputOf, type OutputOf } from 'cmd-ts/dist/esm/from.js';\nimport { type NonEmptyArray } from 'ts-type-forge';\nimport { genIndex } from '../functions/index.mjs';\n\ntype Ext = `.${string}`;\n\nconst extensionType = cmd.extendType(cmd.string, {\n from: (s) => {\n if (!s.startsWith('.')) {\n throw new Error(`ext should start with '.'`);\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Promise.resolve(s as Ext);\n },\n});\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst nonEmptyArray = <T extends cmd.Type<any, any>>(\n t: T,\n commandName: string,\n): cmd.Type<readonly InputOf<T>[], NonEmptyArray<OutputOf<T>>> =>\n cmd.extendType(\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n cmd.array(t) as cmd.Type<readonly InputOf<T>[], OutputOf<T>[]>,\n {\n from: (arr) => {\n if (Arr.isEmpty(arr)) {\n throw new Error(\n `No value provided for --${commandName}. At least one value is required.`,\n );\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Promise.resolve(arr as unknown as NonEmptyArray<OutputOf<T>>);\n },\n },\n );\n\nconst cmdDef = cmd.command({\n name: 'gen-index-ts-cli',\n version: '10.1.8',\n args: {\n // required args\n targetDirectory: cmd.positional({\n type: cmd.string,\n displayName: 'target-directory',\n description:\n 'Directory where the index file will be generated (Comma-separated list can be used)',\n }),\n\n targetExtensions: cmd.multioption({\n long: 'target-ext',\n type: nonEmptyArray(extensionType, 'target-ext'),\n description: 'File extensions to include in the index file',\n }),\n indexFileExtension: cmd.option({\n long: 'index-ext',\n type: extensionType,\n description: 'Extension of the index file to be generated',\n }),\n exportStatementExtension: cmd.option({\n long: 'export-ext',\n type: cmd.union([\n extensionType,\n cmd.extendType(cmd.string, {\n from: (s) => {\n if (s !== 'none') {\n throw new Error(\n `export-ext should be 'none' or a valid extension`,\n );\n }\n\n return Promise.resolve('none' as const);\n },\n }),\n ]),\n description: 'Extension of the export statements in the index file',\n }),\n\n // optional args\n exclude: cmd.multioption({\n long: 'exclude',\n type: cmd.optional(cmd.array(cmd.string)),\n description:\n 'Glob patterns of files to exclude from the index file (e.g., \"*.d.mts\", \"*.test.mts\")',\n }),\n formatCommand: cmd.option({\n long: 'fmt',\n type: cmd.optional(cmd.string),\n description:\n 'Command to format after generating the index file (e.g., \"npm run fmt\")',\n }),\n silent: cmd.flag({\n long: 'silent',\n type: cmd.optional(cmd.boolean),\n description: 'If true, suppresses output messages (default: false)',\n }),\n minDepth: cmd.option({\n long: 'min-depth',\n type: cmd.optional(cmd.number),\n description: 'Minimum depth to start generating index files (default: 0)',\n }),\n },\n handler: (args) => {\n expectType<typeof args.targetDirectory, string>('=');\n\n expectType<typeof args.targetExtensions, NonEmptyArray<Ext>>('=');\n\n expectType<typeof args.exportStatementExtension, Ext | 'none'>('=');\n\n expectType<typeof args.indexFileExtension, Ext>('=');\n\n expectType<typeof args.exclude, string[] | undefined>('=');\n\n expectType<typeof args.formatCommand, string | undefined>('=');\n\n expectType<typeof args.silent, boolean | undefined>('=');\n\n expectType<typeof args.minDepth, number | undefined>('=');\n\n main(args).catch((error: unknown) => {\n console.error('An error occurred:', error);\n\n process.exit(1);\n });\n },\n});\n\nconst main = async ({\n targetDirectory,\n targetExtensions,\n exportStatementExtension,\n indexFileExtension,\n exclude,\n formatCommand,\n silent,\n minDepth,\n}: Readonly<{\n targetDirectory: string;\n targetExtensions: readonly Ext[];\n exportStatementExtension: Ext | 'none';\n indexFileExtension: Ext;\n exclude?: readonly string[] | undefined;\n formatCommand?: string | undefined;\n silent?: boolean | undefined;\n minDepth?: number | undefined;\n}>): Promise<void> => {\n await genIndex({\n targetDirectory: targetDirectory.includes(',')\n ? targetDirectory.split(',').map((dir) => dir.trim())\n : targetDirectory,\n exportStatementExtension,\n targetExtensions,\n exclude,\n indexFileExtension,\n formatCommand,\n silent,\n minDepth,\n });\n};\n\nawait cmd.run(cmdDef, Arr.skip(process.argv, 2));\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gen-index-ts.mjs","sources":["../../src/cmd/gen-index-ts.mts"],"sourcesContent":["#!/usr/bin/env node\n\n/* transformer-ignore convert-to-readonly */\n\nimport * as cmd from 'cmd-ts';\nimport { Arr, expectType } from 'ts-data-forge';\n// eslint-disable-next-line import-x/no-internal-modules, import-x/extensions\nimport { type InputOf, type OutputOf } from 'cmd-ts/dist/esm/from.js';\nimport { type NonEmptyArray } from 'ts-type-forge';\nimport { genIndex } from '../functions/index.mjs';\n\ntype Ext = `.${string}`;\n\nconst extensionType = cmd.extendType(cmd.string, {\n from: (s) => {\n if (!s.startsWith('.')) {\n throw new Error(`ext should start with '.'`);\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Promise.resolve(s as Ext);\n },\n});\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst nonEmptyArray = <T extends cmd.Type<any, any>>(\n t: T,\n commandName: string,\n): cmd.Type<readonly InputOf<T>[], NonEmptyArray<OutputOf<T>>> =>\n cmd.extendType(\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n cmd.array(t) as cmd.Type<readonly InputOf<T>[], OutputOf<T>[]>,\n {\n from: (arr) => {\n if (Arr.isEmpty(arr)) {\n throw new Error(\n `No value provided for --${commandName}. At least one value is required.`,\n );\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Promise.resolve(arr as unknown as NonEmptyArray<OutputOf<T>>);\n },\n },\n );\n\nconst cmdDef = cmd.command({\n name: 'gen-index-ts-cli',\n version: '10.1.8',\n args: {\n // required args\n targetDirectory: cmd.positional({\n type: cmd.string,\n displayName: 'target-directory',\n description:\n 'Directory where the index file will be generated (Comma-separated list can be used)',\n }),\n\n targetExtensions: cmd.multioption({\n long: 'target-ext',\n type: nonEmptyArray(extensionType, 'target-ext'),\n description: 'File extensions to include in the index file',\n }),\n indexFileExtension: cmd.option({\n long: 'index-ext',\n type: extensionType,\n description: 'Extension of the index file to be generated',\n }),\n exportStatementExtension: cmd.option({\n long: 'export-ext',\n type: cmd.union([\n extensionType,\n cmd.extendType(cmd.string, {\n from: (s) => {\n if (s !== 'none') {\n throw new Error(\n `export-ext should be 'none' or a valid extension`,\n );\n }\n\n return Promise.resolve('none' as const);\n },\n }),\n ]),\n description: 'Extension of the export statements in the index file',\n }),\n\n // optional args\n exclude: cmd.multioption({\n long: 'exclude',\n type: cmd.optional(cmd.array(cmd.string)),\n description:\n 'Glob patterns of files to exclude from the index file (e.g., \"*.d.mts\", \"*.test.mts\")',\n }),\n formatCommand: cmd.option({\n long: 'fmt',\n type: cmd.optional(cmd.string),\n description:\n 'Command to format after generating the index file (e.g., \"npm run fmt\")',\n }),\n silent: cmd.flag({\n long: 'silent',\n type: cmd.optional(cmd.boolean),\n description: 'If true, suppresses output messages (default: false)',\n }),\n minDepth: cmd.option({\n long: 'min-depth',\n type: cmd.optional(cmd.number),\n description: 'Minimum depth to start generating index files (default: 0)',\n }),\n },\n handler: (args) => {\n expectType<typeof args.targetDirectory, string>('=');\n\n expectType<typeof args.targetExtensions, NonEmptyArray<Ext>>('=');\n\n expectType<typeof args.exportStatementExtension, Ext | 'none'>('=');\n\n expectType<typeof args.indexFileExtension, Ext>('=');\n\n expectType<typeof args.exclude, string[] | undefined>('=');\n\n expectType<typeof args.formatCommand, string | undefined>('=');\n\n expectType<typeof args.silent, boolean | undefined>('=');\n\n expectType<typeof args.minDepth, number | undefined>('=');\n\n main(args).catch((error: unknown) => {\n console.error('An error occurred:', error);\n\n process.exit(1);\n });\n },\n});\n\nconst main = async ({\n targetDirectory,\n targetExtensions,\n exportStatementExtension,\n indexFileExtension,\n exclude,\n formatCommand,\n silent,\n minDepth,\n}: Readonly<{\n targetDirectory: string;\n targetExtensions: readonly Ext[];\n exportStatementExtension: Ext | 'none';\n indexFileExtension: Ext;\n exclude?: readonly string[] | undefined;\n formatCommand?: string | undefined;\n silent?: boolean | undefined;\n minDepth?: number | undefined;\n}>): Promise<void> => {\n await genIndex({\n targetDirectory: targetDirectory.includes(',')\n ? targetDirectory.split(',').map((dir) => dir.trim())\n : targetDirectory,\n exportStatementExtension,\n targetExtensions,\n exclude,\n indexFileExtension,\n formatCommand,\n silent,\n minDepth,\n });\n};\n\nawait cmd.run(cmdDef, Arr.skip(process.argv, 2));\n"],"names":[],"mappings":"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"}
|
package/dist/entry-point.mjs
CHANGED
|
@@ -10,7 +10,7 @@ export { genIndex } from './functions/gen-index.mjs';
|
|
|
10
10
|
export { glob } from './functions/glob.mjs';
|
|
11
11
|
export { isDirectlyExecuted } from './functions/is-directly-executed.mjs';
|
|
12
12
|
export { makeEmptyDir } from './functions/make-empty-dir.mjs';
|
|
13
|
-
export { checkShouldRunTypeChecks } from './functions/should-run.mjs';
|
|
13
|
+
export { checkShouldRun, checkShouldRunTypeChecks } from './functions/should-run.mjs';
|
|
14
14
|
export { executeParallel, executeStages } from './functions/workspace-utils/execute-parallel.mjs';
|
|
15
15
|
export { getWorkspacePackages } from './functions/workspace-utils/get-workspace-packages.mjs';
|
|
16
16
|
export { runCmdInParallelAcrossWorkspaces } from './functions/workspace-utils/run-cmd-in-parallel.mjs';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.mts","sourceRoot":"","sources":["../../src/functions/format.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,OAAO,EAA6B,MAAM,EAAE,MAAM,eAAe,CAAC;AAWlE;;;;GAIG;AACH,eAAO,MAAM,WAAW,UACf,SAAS,MAAM,EAAE,YACd,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;IACjD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC,KACD,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,OAAO,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"format.d.mts","sourceRoot":"","sources":["../../src/functions/format.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,OAAO,EAA6B,MAAM,EAAE,MAAM,eAAe,CAAC;AAWlE;;;;GAIG;AACH,eAAO,MAAM,WAAW,UACf,SAAS,MAAM,EAAE,YACd,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;IACjD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC,KACD,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,OAAO,EAAE,CAAC,CA8I/C,CAAC;AA+DF;;;;GAIG;AACH,eAAO,MAAM,eAAe,aAChB,MAAM,YACN,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;CAClD,CAAC,KACD,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAmCpC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,aACvB,QAAQ,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;IACjD,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC,KACD,OAAO,CACR,MAAM,CACJ,SAAS,EACT,aAAa,GAAG,QAAQ,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,SAAS,OAAO,EAAE,CACnE,CAgEF,CAAC;AA4BF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,SACnB,MAAM,YACF,QAAQ,CAAC;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;IACjD;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC,KACD,OAAO,CACR,MAAM,CACJ,SAAS,EACP,aAAa,GACb,QAAQ,CAAC;IACP,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,GACF,SAAS,OAAO,EAAE,CACrB,CA2FF,CAAC"}
|
|
@@ -25,36 +25,29 @@ const formatFiles = async (files, options) => {
|
|
|
25
25
|
const relativePath = path.relative(gitRoot, filePath);
|
|
26
26
|
return relativePath.startsWith("..") ? filePath : relativePath;
|
|
27
27
|
};
|
|
28
|
+
const mut_skipped = { nonExistent: 0, ignored: 0, noParser: 0 };
|
|
28
29
|
const results = (
|
|
29
30
|
// NOTE: Using Promise.allSettled to ensure all files are processed even if some fail
|
|
30
31
|
await Promise.allSettled(
|
|
31
32
|
files.map(async (filePath) => {
|
|
32
33
|
try {
|
|
33
34
|
if (!await pathExists(filePath)) {
|
|
34
|
-
|
|
35
|
-
`Skipping non-existent file: ${getDisplayPath(filePath)}`
|
|
36
|
-
);
|
|
35
|
+
mut_skipped.nonExistent += 1;
|
|
37
36
|
return Result.ok(void 0);
|
|
38
37
|
}
|
|
39
38
|
if (!noIgnore && (options?.ignore ?? defaultIgnoreFn)(filePath)) {
|
|
40
|
-
|
|
41
|
-
`Skipping ignored file: ${getDisplayPath(filePath)}`
|
|
42
|
-
);
|
|
39
|
+
mut_skipped.ignored += 1;
|
|
43
40
|
return Result.ok(void 0);
|
|
44
41
|
}
|
|
45
42
|
const fileInfo = await prettier.getFileInfo(filePath, {
|
|
46
43
|
ignorePath: ".prettierignore"
|
|
47
44
|
});
|
|
48
45
|
if (!noIgnore && fileInfo.ignored) {
|
|
49
|
-
|
|
50
|
-
`Skipping ignored file: ${getDisplayPath(filePath)}`
|
|
51
|
-
);
|
|
46
|
+
mut_skipped.ignored += 1;
|
|
52
47
|
return Result.ok(void 0);
|
|
53
48
|
}
|
|
54
49
|
if (!noIgnore && (options?.ignoreUnknown ?? true) && fileInfo.inferredParser === null) {
|
|
55
|
-
|
|
56
|
-
`Skipping file (no parser): ${getDisplayPath(filePath)}`
|
|
57
|
-
);
|
|
50
|
+
mut_skipped.noParser += 1;
|
|
58
51
|
return Result.ok(void 0);
|
|
59
52
|
}
|
|
60
53
|
const content = await fs.readFile(filePath, "utf8");
|
|
@@ -82,6 +75,14 @@ const formatFiles = async (files, options) => {
|
|
|
82
75
|
})
|
|
83
76
|
)
|
|
84
77
|
);
|
|
78
|
+
const skipReport = [
|
|
79
|
+
mut_skipped.ignored === 0 ? "" : `${mut_skipped.ignored} ignored`,
|
|
80
|
+
mut_skipped.noParser === 0 ? "" : `${mut_skipped.noParser} with no parser`,
|
|
81
|
+
mut_skipped.nonExistent === 0 ? "" : `${mut_skipped.nonExistent} non-existent`
|
|
82
|
+
].filter((part) => part !== "");
|
|
83
|
+
if (Arr.isNonEmpty(skipReport)) {
|
|
84
|
+
conditionalEcho(`Skipped ${skipReport.join(", ")}.`);
|
|
85
|
+
}
|
|
85
86
|
if (results.every((r) => r.status === "fulfilled")) {
|
|
86
87
|
const fulfilled = results.map((r) => r.value);
|
|
87
88
|
if (fulfilled.every(Result.isOk)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.mjs","sources":["../../src/functions/format.mts"],"sourcesContent":["import { type ExecException } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as prettier from 'prettier';\nimport { Arr, isNotUndefined, pipe, Result } from 'ts-data-forge';\nimport { pathExists } from './assert-path-exists.mjs';\nimport {\n getDiffFrom,\n getGitRoot,\n getModifiedFiles,\n getStagedFiles,\n getUntrackedFiles,\n} from './diff.mjs';\nimport { glob } from './glob.mjs';\n\n/**\n * Format a list of files using Prettier\n *\n * @param files - Array of file paths to format\n */\nexport const formatFiles = async (\n files: readonly string[],\n options?: Readonly<{\n silent?: boolean;\n ignore?: false | ((filePath: string) => boolean);\n ignoreUnknown?: boolean;\n }>,\n): Promise<Result<undefined, readonly unknown[]>> => {\n const silent = options?.silent ?? false;\n\n const noIgnore = options?.ignore === false;\n\n const conditionalEcho = silent ? () => {} : console.info;\n\n if (Arr.isEmpty(files)) {\n conditionalEcho('No files to format');\n\n return Result.ok(undefined);\n }\n\n conditionalEcho(`Formatting ${files.length} files...`);\n\n // Get git root for display purposes\n const gitRootResult = await getGitRoot({ silent: true });\n\n const gitRoot = Result.isOk(gitRootResult) ? gitRootResult.value : undefined;\n\n // Helper function to get display path (relative to git root if available)\n const getDisplayPath = (filePath: string): string => {\n if (gitRoot === undefined) {\n return filePath;\n }\n\n const relativePath = path.relative(gitRoot, filePath);\n\n return relativePath.startsWith('..') ? filePath : relativePath;\n };\n\n // Format each file\n const results: readonly PromiseSettledResult<Result<undefined, unknown>>[] =\n // NOTE: Using Promise.allSettled to ensure all files are processed even if some fail\n await Promise.allSettled(\n files.map(async (filePath) => {\n try {\n // Check if file exists first\n if (!(await pathExists(filePath))) {\n conditionalEcho(\n `Skipping non-existent file: ${getDisplayPath(filePath)}`,\n );\n\n return Result.ok(undefined);\n }\n\n if (!noIgnore && (options?.ignore ?? defaultIgnoreFn)(filePath)) {\n conditionalEcho(\n `Skipping ignored file: ${getDisplayPath(filePath)}`,\n );\n\n return Result.ok(undefined);\n }\n\n // Check if file is ignored by prettier\n const fileInfo = await prettier.getFileInfo(filePath, {\n ignorePath: '.prettierignore',\n });\n\n if (!noIgnore && fileInfo.ignored) {\n conditionalEcho(\n `Skipping ignored file: ${getDisplayPath(filePath)}`,\n );\n\n return Result.ok(undefined);\n }\n\n if (\n !noIgnore &&\n (options?.ignoreUnknown ?? true) &&\n fileInfo.inferredParser === null\n ) {\n // Silently skip files with no parser\n conditionalEcho(\n `Skipping file (no parser): ${getDisplayPath(filePath)}`,\n );\n\n return Result.ok(undefined);\n }\n\n // Read file content\n // eslint-disable-next-line security/detect-non-literal-fs-filename\n const content = await fs.readFile(filePath, 'utf8');\n\n // Resolve prettier config for this file\n const prettierOptions = await prettier.resolveConfig(filePath);\n\n // Format the content\n const formatted = await prettier.format(content, {\n ...prettierOptions,\n filepath: filePath,\n });\n\n // Only write if content changed\n if (formatted === content) {\n conditionalEcho(`Unchanged: ${getDisplayPath(filePath)}`);\n } else {\n // eslint-disable-next-line security/detect-non-literal-fs-filename\n await fs.writeFile(filePath, formatted, 'utf8');\n\n conditionalEcho(`Formatted: ${getDisplayPath(filePath)}`);\n }\n\n return Result.ok(undefined);\n } catch (error) {\n if (!silent) {\n console.error(\n `Error formatting ${getDisplayPath(filePath)}:`,\n error,\n );\n }\n\n return Result.err(error);\n }\n }),\n );\n\n if (results.every((r) => r.status === 'fulfilled')) {\n const fulfilled = results.map((r) => r.value);\n\n if (fulfilled.every(Result.isOk)) {\n return Result.ok(undefined);\n }\n\n return Result.err(fulfilled.filter(Result.isErr).map((r) => r.value));\n }\n\n return Result.err(\n results\n .filter((r) => r.status === 'rejected')\n .map((r): unknown => r.reason),\n );\n};\n\nconst defaultIgnoreFn = (filePath: string): boolean => {\n const filename = path.basename(filePath);\n\n return (\n ignoreFiles.has(filename) ||\n filename.startsWith('.env') ||\n ignoreExtensions.some((ext) => filePath.endsWith(ext)) ||\n pipe(filePath.split(path.sep)).map((pathSegments) =>\n pathSegments.some((segment) => ignoreDirs.includes(segment)),\n ).value\n );\n};\n\nconst ignoreFiles: ReadonlySet<string> = new Set([\n '.DS_Store',\n 'package-lock.json',\n 'yarn.lock',\n 'pnpm-lock.yaml',\n 'LICENSE',\n '.prettierignore',\n '.editorconfig',\n '.gitignore',\n '.npmignore',\n '.envrc',\n '.nvmrc',\n '.npmrc',\n]);\n\nconst ignoreExtensions: readonly `.${string}`[] = [\n '.svg',\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.bmp',\n '.tiff',\n '.bak',\n '.log',\n '.zip',\n '.tar',\n '.gz',\n '.7z',\n '.mp3',\n '.mp4',\n '.avi',\n '.mkv',\n '.tsbuildinfo',\n] as const;\n\nconst ignoreDirs: readonly string[] = [\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n 'out',\n '.cache',\n '.vscode',\n '.yarn',\n '.wireit',\n] as const;\n\n/**\n * Format files matching the given glob pattern using Prettier\n *\n * @param pathGlob - Glob pattern to match files\n */\nexport const formatFilesGlob = async (\n pathGlob: string,\n options?: Readonly<{\n silent?: boolean;\n ignoreUnknown?: boolean;\n ignore?: false | ((filePath: string) => boolean);\n }>,\n): Promise<Result<undefined, unknown>> => {\n const silent = options?.silent ?? false;\n\n const ignoreUnknown = options?.ignoreUnknown ?? true;\n\n const ignore = options?.ignore;\n\n const conditionalEcho = silent ? () => {} : console.info;\n\n // Find all files matching the glob\n const globResult = await glob(pathGlob, {\n absolute: true,\n ignore: ignore === false ? [] : ['**/node_modules/**', '**/.git/**'],\n dot: true,\n });\n\n if (Result.isErr(globResult)) {\n const error = globResult.value;\n\n if (!silent) {\n console.error('Error in formatFiles:', error);\n }\n\n return Result.err(error);\n }\n\n const files = globResult.value;\n\n if (Arr.isEmpty(files)) {\n conditionalEcho('No files found matching pattern:', pathGlob);\n\n return Result.ok(undefined);\n }\n\n return formatFiles(files, { silent, ignoreUnknown, ignore });\n};\n\n/**\n * Format only files that have been changed (git status)\n *\n * @param options - Options for formatting\n * @param options.cwd - If provided, only files within this directory will be\n * formatted. Relative paths are resolved against `process.cwd()`. Defaults to\n * undefined (no filtering; all changed files in the repository are\n * formatted).\n */\nexport const formatUncommittedFiles = async (\n options?: Readonly<{\n untracked?: boolean;\n modified?: boolean;\n staged?: boolean;\n silent?: boolean;\n ignoreUnknown?: boolean;\n ignore?: false | ((filePath: string) => boolean);\n cwd?: string;\n }>,\n): Promise<\n Result<\n undefined,\n ExecException | Readonly<{ message: string }> | readonly unknown[]\n >\n> => {\n const {\n untracked = true,\n modified = true,\n staged = true,\n silent = false,\n ignoreUnknown = true,\n ignore,\n cwd,\n } = options ?? {};\n\n const mut_files: string[] = [];\n\n if (untracked) {\n const untrackedFilesResult = await getUntrackedFiles({ silent });\n\n if (Result.isErr(untrackedFilesResult)) {\n if (!silent) {\n console.error(\n 'Error getting changed files:',\n untrackedFilesResult.value,\n );\n }\n\n return untrackedFilesResult;\n }\n\n mut_files.push(...untrackedFilesResult.value);\n }\n\n if (modified) {\n const diffFilesResult = await getModifiedFiles({ silent });\n\n if (Result.isErr(diffFilesResult)) {\n if (!silent) {\n console.error('Error getting changed files:', diffFilesResult.value);\n }\n\n return diffFilesResult;\n }\n\n mut_files.push(...diffFilesResult.value);\n }\n\n if (staged) {\n const stagedFilesResult = await getStagedFiles({ silent });\n\n if (Result.isErr(stagedFilesResult)) {\n if (!silent) {\n console.error('Error getting changed files:', stagedFilesResult.value);\n }\n\n return stagedFilesResult;\n }\n\n mut_files.push(...stagedFilesResult.value);\n }\n\n return formatFiles(filterFilesByCwd(Arr.uniq(mut_files), cwd), {\n silent,\n ignoreUnknown,\n ignore,\n });\n};\n\n/**\n * Filter a list of file paths to those inside `cwd`. If `cwd` is undefined,\n * returns the original list unchanged. Relative `cwd` is resolved against\n * `process.cwd()`.\n */\nconst filterFilesByCwd = (\n files: readonly string[],\n cwd: string | undefined,\n): readonly string[] => {\n if (cwd === undefined) {\n return files;\n }\n\n const resolvedCwd = path.resolve(cwd);\n\n const cwdWithSep = resolvedCwd.endsWith(path.sep)\n ? resolvedCwd\n : (`${resolvedCwd}${path.sep}` as const);\n\n return files.filter((file) => {\n const absFile = path.isAbsolute(file) ? file : path.resolve(file);\n\n return absFile === resolvedCwd || absFile.startsWith(cwdWithSep);\n });\n};\n\n/**\n * Format only files that differ from the specified base branch or commit\n *\n * @param base - Base branch name or commit hash to compare against (defaults to\n * 'main')\n * @param options - Options for formatting\n * @param options.includeUntracked - Include untracked files in addition to diff\n * files (default is true)\n * @param options.includeStaged - Include staged files in addition to diff files\n * (default is true)\n * @param options.silent - Silent mode to suppress command output (default is\n * false)\n */\nexport const formatDiffFrom = async (\n base: string,\n options?: Readonly<{\n includeUntracked?: boolean;\n includeModified?: boolean;\n includeStaged?: boolean;\n silent?: boolean;\n ignoreUnknown?: boolean;\n ignore?: false | ((filePath: string) => boolean);\n /**\n * If provided, only files within this directory will be formatted.\n * Relative paths are resolved against `process.cwd()`. Defaults to\n * undefined (no filtering; all changed files in the repository are\n * formatted).\n */\n cwd?: string;\n }>,\n): Promise<\n Result<\n undefined,\n | ExecException\n | Readonly<{\n message: string;\n }>\n | readonly unknown[]\n >\n> => {\n // const silent = options?.silent ?? false;\n const {\n silent = false,\n includeUntracked = true,\n includeModified = true,\n includeStaged = true,\n ignoreUnknown = true,\n ignore,\n cwd,\n } = options ?? {};\n\n const conditionalEcho = silent ? () => {} : console.info;\n\n // Get files that differ from base branch/commit (excluding deleted files)\n const diffFromBaseResult = await getDiffFrom(base, {\n silent,\n });\n\n if (Result.isErr(diffFromBaseResult)) {\n if (!silent) {\n console.error('Error getting changed files:', diffFromBaseResult.value);\n }\n\n return diffFromBaseResult;\n }\n\n const diffFiles = diffFromBaseResult.value;\n\n const mut_allFiles: string[] = diffFiles.slice();\n\n // If includeUntracked is true, also get untracked files\n for (const { type, flag, fn } of [\n { type: 'untracked', flag: includeUntracked, fn: getUntrackedFiles },\n { type: 'modified', flag: includeModified, fn: getModifiedFiles },\n { type: 'staged', flag: includeStaged, fn: getStagedFiles },\n ]) {\n if (!flag) {\n continue;\n }\n\n // eslint-disable-next-line no-await-in-loop\n const filesResult = await fn({ silent });\n\n if (Result.isErr(filesResult)) {\n if (!silent) {\n console.error(`Error getting ${type} files:`, filesResult.value);\n }\n\n return filesResult;\n }\n\n const files = filesResult.value;\n\n // Combine and deduplicate files\n mut_allFiles.push(...files);\n }\n\n const allFiles = filterFilesByCwd(Arr.uniq(mut_allFiles), cwd);\n\n if (!silent) {\n const includedFileTypes = [\n includeUntracked ? 'untracked files' : undefined,\n includeModified ? 'modified files' : undefined,\n includeStaged ? 'staged files' : undefined,\n ].filter(isNotUndefined);\n\n const message = [\n `Formatting files that differ from ${base}`,\n includedFileTypes\n .map((s, i) =>\n i !== includedFileTypes.length - 1 ? `, ${s}` : ` and ${s}`,\n )\n .join(''),\n ].join('');\n\n conditionalEcho(`${message}:`, allFiles);\n }\n\n if (Arr.isEmpty(allFiles)) {\n conditionalEcho('No files to format');\n\n return Result.ok(undefined);\n }\n\n return formatFiles(allFiles, {\n silent,\n ignoreUnknown,\n ignore,\n });\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"format.mjs","sources":["../../src/functions/format.mts"],"sourcesContent":["import { type ExecException } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as prettier from 'prettier';\nimport { Arr, isNotUndefined, pipe, Result } from 'ts-data-forge';\nimport { pathExists } from './assert-path-exists.mjs';\nimport {\n getDiffFrom,\n getGitRoot,\n getModifiedFiles,\n getStagedFiles,\n getUntrackedFiles,\n} from './diff.mjs';\nimport { glob } from './glob.mjs';\n\n/**\n * Format a list of files using Prettier\n *\n * @param files - Array of file paths to format\n */\nexport const formatFiles = async (\n files: readonly string[],\n options?: Readonly<{\n silent?: boolean;\n ignore?: false | ((filePath: string) => boolean);\n ignoreUnknown?: boolean;\n }>,\n): Promise<Result<undefined, readonly unknown[]>> => {\n const silent = options?.silent ?? false;\n\n const noIgnore = options?.ignore === false;\n\n const conditionalEcho = silent ? () => {} : console.info;\n\n if (Arr.isEmpty(files)) {\n conditionalEcho('No files to format');\n\n return Result.ok(undefined);\n }\n\n conditionalEcho(`Formatting ${files.length} files...`);\n\n // Get git root for display purposes\n const gitRootResult = await getGitRoot({ silent: true });\n\n const gitRoot = Result.isOk(gitRootResult) ? gitRootResult.value : undefined;\n\n // Helper function to get display path (relative to git root if available)\n const getDisplayPath = (filePath: string): string => {\n if (gitRoot === undefined) {\n return filePath;\n }\n\n const relativePath = path.relative(gitRoot, filePath);\n\n return relativePath.startsWith('..') ? filePath : relativePath;\n };\n\n // Skips are counted rather than named. A repository can hand this function\n // thousands of files it will not touch — a subtree formatted by another tool,\n // or a first diff that contains a whole imported directory — and a line each\n // is both unreadable and enough output to overflow the stdout buffer of a\n // parent process capturing this run.\n const mut_skipped = { nonExistent: 0, ignored: 0, noParser: 0 };\n\n // Format each file\n const results: readonly PromiseSettledResult<Result<undefined, unknown>>[] =\n // NOTE: Using Promise.allSettled to ensure all files are processed even if some fail\n await Promise.allSettled(\n files.map(async (filePath) => {\n try {\n // Check if file exists first\n if (!(await pathExists(filePath))) {\n mut_skipped.nonExistent += 1;\n\n return Result.ok(undefined);\n }\n\n if (!noIgnore && (options?.ignore ?? defaultIgnoreFn)(filePath)) {\n mut_skipped.ignored += 1;\n\n return Result.ok(undefined);\n }\n\n // Check if file is ignored by prettier\n const fileInfo = await prettier.getFileInfo(filePath, {\n ignorePath: '.prettierignore',\n });\n\n if (!noIgnore && fileInfo.ignored) {\n mut_skipped.ignored += 1;\n\n return Result.ok(undefined);\n }\n\n if (\n !noIgnore &&\n (options?.ignoreUnknown ?? true) &&\n fileInfo.inferredParser === null\n ) {\n mut_skipped.noParser += 1;\n\n return Result.ok(undefined);\n }\n\n // Read file content\n // eslint-disable-next-line security/detect-non-literal-fs-filename\n const content = await fs.readFile(filePath, 'utf8');\n\n // Resolve prettier config for this file\n const prettierOptions = await prettier.resolveConfig(filePath);\n\n // Format the content\n const formatted = await prettier.format(content, {\n ...prettierOptions,\n filepath: filePath,\n });\n\n // Only write if content changed\n if (formatted === content) {\n conditionalEcho(`Unchanged: ${getDisplayPath(filePath)}`);\n } else {\n // eslint-disable-next-line security/detect-non-literal-fs-filename\n await fs.writeFile(filePath, formatted, 'utf8');\n\n conditionalEcho(`Formatted: ${getDisplayPath(filePath)}`);\n }\n\n return Result.ok(undefined);\n } catch (error) {\n if (!silent) {\n console.error(\n `Error formatting ${getDisplayPath(filePath)}:`,\n error,\n );\n }\n\n return Result.err(error);\n }\n }),\n );\n\n const skipReport = [\n mut_skipped.ignored === 0 ? '' : `${mut_skipped.ignored} ignored`,\n mut_skipped.noParser === 0 ? '' : `${mut_skipped.noParser} with no parser`,\n mut_skipped.nonExistent === 0\n ? ''\n : `${mut_skipped.nonExistent} non-existent`,\n ].filter((part) => part !== '');\n\n if (Arr.isNonEmpty(skipReport)) {\n conditionalEcho(`Skipped ${skipReport.join(', ')}.`);\n }\n\n if (results.every((r) => r.status === 'fulfilled')) {\n const fulfilled = results.map((r) => r.value);\n\n if (fulfilled.every(Result.isOk)) {\n return Result.ok(undefined);\n }\n\n return Result.err(fulfilled.filter(Result.isErr).map((r) => r.value));\n }\n\n return Result.err(\n results\n .filter((r) => r.status === 'rejected')\n .map((r): unknown => r.reason),\n );\n};\n\nconst defaultIgnoreFn = (filePath: string): boolean => {\n const filename = path.basename(filePath);\n\n return (\n ignoreFiles.has(filename) ||\n filename.startsWith('.env') ||\n ignoreExtensions.some((ext) => filePath.endsWith(ext)) ||\n pipe(filePath.split(path.sep)).map((pathSegments) =>\n pathSegments.some((segment) => ignoreDirs.includes(segment)),\n ).value\n );\n};\n\nconst ignoreFiles: ReadonlySet<string> = new Set([\n '.DS_Store',\n 'package-lock.json',\n 'yarn.lock',\n 'pnpm-lock.yaml',\n 'LICENSE',\n '.prettierignore',\n '.editorconfig',\n '.gitignore',\n '.npmignore',\n '.envrc',\n '.nvmrc',\n '.npmrc',\n]);\n\nconst ignoreExtensions: readonly `.${string}`[] = [\n '.svg',\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.bmp',\n '.tiff',\n '.bak',\n '.log',\n '.zip',\n '.tar',\n '.gz',\n '.7z',\n '.mp3',\n '.mp4',\n '.avi',\n '.mkv',\n '.tsbuildinfo',\n] as const;\n\nconst ignoreDirs: readonly string[] = [\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n 'out',\n '.cache',\n '.vscode',\n '.yarn',\n '.wireit',\n] as const;\n\n/**\n * Format files matching the given glob pattern using Prettier\n *\n * @param pathGlob - Glob pattern to match files\n */\nexport const formatFilesGlob = async (\n pathGlob: string,\n options?: Readonly<{\n silent?: boolean;\n ignoreUnknown?: boolean;\n ignore?: false | ((filePath: string) => boolean);\n }>,\n): Promise<Result<undefined, unknown>> => {\n const silent = options?.silent ?? false;\n\n const ignoreUnknown = options?.ignoreUnknown ?? true;\n\n const ignore = options?.ignore;\n\n const conditionalEcho = silent ? () => {} : console.info;\n\n // Find all files matching the glob\n const globResult = await glob(pathGlob, {\n absolute: true,\n ignore: ignore === false ? [] : ['**/node_modules/**', '**/.git/**'],\n dot: true,\n });\n\n if (Result.isErr(globResult)) {\n const error = globResult.value;\n\n if (!silent) {\n console.error('Error in formatFiles:', error);\n }\n\n return Result.err(error);\n }\n\n const files = globResult.value;\n\n if (Arr.isEmpty(files)) {\n conditionalEcho('No files found matching pattern:', pathGlob);\n\n return Result.ok(undefined);\n }\n\n return formatFiles(files, { silent, ignoreUnknown, ignore });\n};\n\n/**\n * Format only files that have been changed (git status)\n *\n * @param options - Options for formatting\n * @param options.cwd - If provided, only files within this directory will be\n * formatted. Relative paths are resolved against `process.cwd()`. Defaults to\n * undefined (no filtering; all changed files in the repository are\n * formatted).\n */\nexport const formatUncommittedFiles = async (\n options?: Readonly<{\n untracked?: boolean;\n modified?: boolean;\n staged?: boolean;\n silent?: boolean;\n ignoreUnknown?: boolean;\n ignore?: false | ((filePath: string) => boolean);\n cwd?: string;\n }>,\n): Promise<\n Result<\n undefined,\n ExecException | Readonly<{ message: string }> | readonly unknown[]\n >\n> => {\n const {\n untracked = true,\n modified = true,\n staged = true,\n silent = false,\n ignoreUnknown = true,\n ignore,\n cwd,\n } = options ?? {};\n\n const mut_files: string[] = [];\n\n if (untracked) {\n const untrackedFilesResult = await getUntrackedFiles({ silent });\n\n if (Result.isErr(untrackedFilesResult)) {\n if (!silent) {\n console.error(\n 'Error getting changed files:',\n untrackedFilesResult.value,\n );\n }\n\n return untrackedFilesResult;\n }\n\n mut_files.push(...untrackedFilesResult.value);\n }\n\n if (modified) {\n const diffFilesResult = await getModifiedFiles({ silent });\n\n if (Result.isErr(diffFilesResult)) {\n if (!silent) {\n console.error('Error getting changed files:', diffFilesResult.value);\n }\n\n return diffFilesResult;\n }\n\n mut_files.push(...diffFilesResult.value);\n }\n\n if (staged) {\n const stagedFilesResult = await getStagedFiles({ silent });\n\n if (Result.isErr(stagedFilesResult)) {\n if (!silent) {\n console.error('Error getting changed files:', stagedFilesResult.value);\n }\n\n return stagedFilesResult;\n }\n\n mut_files.push(...stagedFilesResult.value);\n }\n\n return formatFiles(filterFilesByCwd(Arr.uniq(mut_files), cwd), {\n silent,\n ignoreUnknown,\n ignore,\n });\n};\n\n/**\n * Filter a list of file paths to those inside `cwd`. If `cwd` is undefined,\n * returns the original list unchanged. Relative `cwd` is resolved against\n * `process.cwd()`.\n */\nconst filterFilesByCwd = (\n files: readonly string[],\n cwd: string | undefined,\n): readonly string[] => {\n if (cwd === undefined) {\n return files;\n }\n\n const resolvedCwd = path.resolve(cwd);\n\n const cwdWithSep = resolvedCwd.endsWith(path.sep)\n ? resolvedCwd\n : (`${resolvedCwd}${path.sep}` as const);\n\n return files.filter((file) => {\n const absFile = path.isAbsolute(file) ? file : path.resolve(file);\n\n return absFile === resolvedCwd || absFile.startsWith(cwdWithSep);\n });\n};\n\n/**\n * Format only files that differ from the specified base branch or commit\n *\n * @param base - Base branch name or commit hash to compare against (defaults to\n * 'main')\n * @param options - Options for formatting\n * @param options.includeUntracked - Include untracked files in addition to diff\n * files (default is true)\n * @param options.includeStaged - Include staged files in addition to diff files\n * (default is true)\n * @param options.silent - Silent mode to suppress command output (default is\n * false)\n */\nexport const formatDiffFrom = async (\n base: string,\n options?: Readonly<{\n includeUntracked?: boolean;\n includeModified?: boolean;\n includeStaged?: boolean;\n silent?: boolean;\n ignoreUnknown?: boolean;\n ignore?: false | ((filePath: string) => boolean);\n /**\n * If provided, only files within this directory will be formatted.\n * Relative paths are resolved against `process.cwd()`. Defaults to\n * undefined (no filtering; all changed files in the repository are\n * formatted).\n */\n cwd?: string;\n }>,\n): Promise<\n Result<\n undefined,\n | ExecException\n | Readonly<{\n message: string;\n }>\n | readonly unknown[]\n >\n> => {\n // const silent = options?.silent ?? false;\n const {\n silent = false,\n includeUntracked = true,\n includeModified = true,\n includeStaged = true,\n ignoreUnknown = true,\n ignore,\n cwd,\n } = options ?? {};\n\n const conditionalEcho = silent ? () => {} : console.info;\n\n // Get files that differ from base branch/commit (excluding deleted files)\n const diffFromBaseResult = await getDiffFrom(base, {\n silent,\n });\n\n if (Result.isErr(diffFromBaseResult)) {\n if (!silent) {\n console.error('Error getting changed files:', diffFromBaseResult.value);\n }\n\n return diffFromBaseResult;\n }\n\n const diffFiles = diffFromBaseResult.value;\n\n const mut_allFiles: string[] = diffFiles.slice();\n\n // If includeUntracked is true, also get untracked files\n for (const { type, flag, fn } of [\n { type: 'untracked', flag: includeUntracked, fn: getUntrackedFiles },\n { type: 'modified', flag: includeModified, fn: getModifiedFiles },\n { type: 'staged', flag: includeStaged, fn: getStagedFiles },\n ]) {\n if (!flag) {\n continue;\n }\n\n // eslint-disable-next-line no-await-in-loop\n const filesResult = await fn({ silent });\n\n if (Result.isErr(filesResult)) {\n if (!silent) {\n console.error(`Error getting ${type} files:`, filesResult.value);\n }\n\n return filesResult;\n }\n\n const files = filesResult.value;\n\n // Combine and deduplicate files\n mut_allFiles.push(...files);\n }\n\n const allFiles = filterFilesByCwd(Arr.uniq(mut_allFiles), cwd);\n\n if (!silent) {\n const includedFileTypes = [\n includeUntracked ? 'untracked files' : undefined,\n includeModified ? 'modified files' : undefined,\n includeStaged ? 'staged files' : undefined,\n ].filter(isNotUndefined);\n\n const message = [\n `Formatting files that differ from ${base}`,\n includedFileTypes\n .map((s, i) =>\n i !== includedFileTypes.length - 1 ? `, ${s}` : ` and ${s}`,\n )\n .join(''),\n ].join('');\n\n conditionalEcho(`${message}:`, allFiles);\n }\n\n if (Arr.isEmpty(allFiles)) {\n conditionalEcho('No files to format');\n\n return Result.ok(undefined);\n }\n\n return formatFiles(allFiles, {\n silent,\n ignoreUnknown,\n ignore,\n });\n};\n"],"names":[],"mappings":";;;;;;;;AAoBO,MAAM,WAAA,GAAc,OACzB,KAAA,EACA,OAAA,KAKmD;AACnD,EAAA,MAAM,MAAA,GAAS,SAAS,MAAA,IAAU,KAAA;AAElC,EAAA,MAAM,QAAA,GAAW,SAAS,MAAA,KAAW,KAAA;AAErC,EAAA,MAAM,eAAA,GAAkB,SAAS,MAAM;AAAA,EAAC,IAAI,OAAA,CAAQ,IAAA;AAEpD,EAAA,IAAI,GAAA,CAAI,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtB,IAAA,eAAA,CAAgB,oBAAoB,CAAA;AAEpC,IAAA,OAAO,MAAA,CAAO,GAAG,MAAS,CAAA;AAAA,EAC5B;AAEA,EAAA,eAAA,CAAgB,CAAA,WAAA,EAAc,KAAA,CAAM,MAAM,CAAA,SAAA,CAAW,CAAA;AAGrD,EAAA,MAAM,gBAAgB,MAAM,UAAA,CAAW,EAAE,MAAA,EAAQ,MAAM,CAAA;AAEvD,EAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,aAAa,CAAA,GAAI,cAAc,KAAA,GAAQ,MAAA;AAGnE,EAAA,MAAM,cAAA,GAAiB,CAAC,QAAA,KAA6B;AACnD,IAAA,IAAI,YAAY,MAAA,EAAW;AACzB,MAAA,OAAO,QAAA;AAAA,IACT;AAEA,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,QAAA,CAAS,OAAA,EAAS,QAAQ,CAAA;AAEpD,IAAA,OAAO,YAAA,CAAa,UAAA,CAAW,IAAI,CAAA,GAAI,QAAA,GAAW,YAAA;AAAA,EACpD,CAAA;AAOA,EAAA,MAAM,cAAc,EAAE,WAAA,EAAa,GAAG,OAAA,EAAS,CAAA,EAAG,UAAU,CAAA,EAAE;AAG9D,EAAA,MAAM,OAAA;AAAA;AAAA,IAEJ,MAAM,OAAA,CAAQ,UAAA;AAAA,MACZ,KAAA,CAAM,GAAA,CAAI,OAAO,QAAA,KAAa;AAC5B,QAAA,IAAI;AAEF,UAAA,IAAI,CAAE,MAAM,UAAA,CAAW,QAAQ,CAAA,EAAI;AACjC,YAAA,WAAA,CAAY,WAAA,IAAe,CAAA;AAE3B,YAAA,OAAO,MAAA,CAAO,GAAG,KAAA,CAAS,CAAA;AAAA,UAC5B;AAEA,UAAA,IAAI,CAAC,QAAA,IAAA,CAAa,OAAA,EAAS,MAAA,IAAU,eAAA,EAAiB,QAAQ,CAAA,EAAG;AAC/D,YAAA,WAAA,CAAY,OAAA,IAAW,CAAA;AAEvB,YAAA,OAAO,MAAA,CAAO,GAAG,KAAA,CAAS,CAAA;AAAA,UAC5B;AAGA,UAAA,MAAM,QAAA,GAAW,MAAM,QAAA,CAAS,WAAA,CAAY,QAAA,EAAU;AAAA,YACpD,UAAA,EAAY;AAAA,WACb,CAAA;AAED,UAAA,IAAI,CAAC,QAAA,IAAY,QAAA,CAAS,OAAA,EAAS;AACjC,YAAA,WAAA,CAAY,OAAA,IAAW,CAAA;AAEvB,YAAA,OAAO,MAAA,CAAO,GAAG,KAAA,CAAS,CAAA;AAAA,UAC5B;AAEA,UAAA,IACE,CAAC,QAAA,KACA,OAAA,EAAS,iBAAiB,IAAA,CAAA,IAC3B,QAAA,CAAS,mBAAmB,IAAA,EAC5B;AACA,YAAA,WAAA,CAAY,QAAA,IAAY,CAAA;AAExB,YAAA,OAAO,MAAA,CAAO,GAAG,KAAA,CAAS,CAAA;AAAA,UAC5B;AAIA,UAAA,MAAM,OAAA,GAAU,MAAM,EAAA,CAAG,QAAA,CAAS,UAAU,MAAM,CAAA;AAGlD,UAAA,MAAM,eAAA,GAAkB,MAAM,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAG7D,UAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,MAAA,CAAO,OAAA,EAAS;AAAA,YAC/C,GAAG,eAAA;AAAA,YACH,QAAA,EAAU;AAAA,WACX,CAAA;AAGD,UAAA,IAAI,cAAc,OAAA,EAAS;AACzB,YAAA,eAAA,CAAgB,CAAA,WAAA,EAAc,cAAA,CAAe,QAAQ,CAAC,CAAA,CAAE,CAAA;AAAA,UAC1D,CAAA,MAAO;AAEL,YAAA,MAAM,EAAA,CAAG,SAAA,CAAU,QAAA,EAAU,SAAA,EAAW,MAAM,CAAA;AAE9C,YAAA,eAAA,CAAgB,CAAA,WAAA,EAAc,cAAA,CAAe,QAAQ,CAAC,CAAA,CAAE,CAAA;AAAA,UAC1D;AAEA,UAAA,OAAO,MAAA,CAAO,GAAG,KAAA,CAAS,CAAA;AAAA,QAC5B,SAAS,KAAA,EAAO;AACd,UAAA,IAAI,CAAC,MAAA,EAAQ;AACX,YAAA,OAAA,CAAQ,KAAA;AAAA,cACN,CAAA,iBAAA,EAAoB,cAAA,CAAe,QAAQ,CAAC,CAAA,CAAA,CAAA;AAAA,cAC5C;AAAA,aACF;AAAA,UACF;AAEA,UAAA,OAAO,MAAA,CAAO,IAAI,KAAK,CAAA;AAAA,QACzB;AAAA,MACF,CAAC;AAAA;AACH,GAAA;AAEF,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,YAAY,OAAA,KAAY,CAAA,GAAI,EAAA,GAAK,CAAA,EAAG,YAAY,OAAO,CAAA,QAAA,CAAA;AAAA,IACvD,YAAY,QAAA,KAAa,CAAA,GAAI,EAAA,GAAK,CAAA,EAAG,YAAY,QAAQ,CAAA,eAAA,CAAA;AAAA,IACzD,YAAY,WAAA,KAAgB,CAAA,GACxB,EAAA,GACA,CAAA,EAAG,YAAY,WAAW,CAAA,aAAA;AAAA,GAChC,CAAE,MAAA,CAAO,CAAC,IAAA,KAAS,SAAS,EAAE,CAAA;AAE9B,EAAA,IAAI,GAAA,CAAI,UAAA,CAAW,UAAU,CAAA,EAAG;AAC9B,IAAA,eAAA,CAAgB,CAAA,QAAA,EAAW,UAAA,CAAW,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,EACrD;AAEA,EAAA,IAAI,QAAQ,KAAA,CAAM,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,WAAW,CAAA,EAAG;AAClD,IAAA,MAAM,YAAY,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,KAAK,CAAA;AAE5C,IAAA,IAAI,SAAA,CAAU,KAAA,CAAM,MAAA,CAAO,IAAI,CAAA,EAAG;AAChC,MAAA,OAAO,MAAA,CAAO,GAAG,MAAS,CAAA;AAAA,IAC5B;AAEA,IAAA,OAAO,MAAA,CAAO,GAAA,CAAI,SAAA,CAAU,MAAA,CAAO,MAAA,CAAO,KAAK,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,EACtE;AAEA,EAAA,OAAO,MAAA,CAAO,GAAA;AAAA,IACZ,OAAA,CACG,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,KAAW,UAAU,CAAA,CACrC,GAAA,CAAI,CAAC,CAAA,KAAe,CAAA,CAAE,MAAM;AAAA,GACjC;AACF;AAEA,MAAM,eAAA,GAAkB,CAAC,QAAA,KAA8B;AACrD,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,CAAS,QAAQ,CAAA;AAEvC,EAAA,OACE,WAAA,CAAY,IAAI,QAAQ,CAAA,IACxB,SAAS,UAAA,CAAW,MAAM,CAAA,IAC1B,gBAAA,CAAiB,IAAA,CAAK,CAAC,QAAQ,QAAA,CAAS,QAAA,CAAS,GAAG,CAAC,CAAA,IACrD,IAAA,CAAK,SAAS,KAAA,CAAM,IAAA,CAAK,GAAG,CAAC,CAAA,CAAE,GAAA;AAAA,IAAI,CAAC,iBAClC,YAAA,CAAa,IAAA,CAAK,CAAC,OAAA,KAAY,UAAA,CAAW,QAAA,CAAS,OAAO,CAAC;AAAA,GAC7D,CAAE,KAAA;AAEN,CAAA;AAEA,MAAM,WAAA,uBAAuC,GAAA,CAAI;AAAA,EAC/C,WAAA;AAAA,EACA,mBAAA;AAAA,EACA,WAAA;AAAA,EACA,gBAAA;AAAA,EACA,SAAA;AAAA,EACA,iBAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAC,CAAA;AAED,MAAM,gBAAA,GAA4C;AAAA,EAChD,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA;AAEA,MAAM,UAAA,GAAgC;AAAA,EACpC,cAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA;AAOO,MAAM,eAAA,GAAkB,OAC7B,QAAA,EACA,OAAA,KAKwC;AACxC,EAAA,MAAM,MAAA,GAAS,SAAS,MAAA,IAAU,KAAA;AAElC,EAAA,MAAM,aAAA,GAAgB,SAAS,aAAA,IAAiB,IAAA;AAEhD,EAAA,MAAM,SAAS,OAAA,EAAS,MAAA;AAExB,EAAA,MAAM,eAAA,GAAkB,SAAS,MAAM;AAAA,EAAC,IAAI,OAAA,CAAQ,IAAA;AAGpD,EAAA,MAAM,UAAA,GAAa,MAAM,IAAA,CAAK,QAAA,EAAU;AAAA,IACtC,QAAA,EAAU,IAAA;AAAA,IACV,QAAQ,MAAA,KAAW,KAAA,GAAQ,EAAC,GAAI,CAAC,sBAAsB,YAAY,CAAA;AAAA,IACnE,GAAA,EAAK;AAAA,GACN,CAAA;AAED,EAAA,IAAI,MAAA,CAAO,KAAA,CAAM,UAAU,CAAA,EAAG;AAC5B,IAAA,MAAM,QAAQ,UAAA,CAAW,KAAA;AAEzB,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,OAAA,CAAQ,KAAA,CAAM,yBAAyB,KAAK,CAAA;AAAA,IAC9C;AAEA,IAAA,OAAO,MAAA,CAAO,IAAI,KAAK,CAAA;AAAA,EACzB;AAEA,EAAA,MAAM,QAAQ,UAAA,CAAW,KAAA;AAEzB,EAAA,IAAI,GAAA,CAAI,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtB,IAAA,eAAA,CAAgB,oCAAoC,QAAQ,CAAA;AAE5D,IAAA,OAAO,MAAA,CAAO,GAAG,MAAS,CAAA;AAAA,EAC5B;AAEA,EAAA,OAAO,YAAY,KAAA,EAAO,EAAE,MAAA,EAAQ,aAAA,EAAe,QAAQ,CAAA;AAC7D;AAWO,MAAM,sBAAA,GAAyB,OACpC,OAAA,KAcG;AACH,EAAA,MAAM;AAAA,IACJ,SAAA,GAAY,IAAA;AAAA,IACZ,QAAA,GAAW,IAAA;AAAA,IACX,MAAA,GAAS,IAAA;AAAA,IACT,MAAA,GAAS,KAAA;AAAA,IACT,aAAA,GAAgB,IAAA;AAAA,IAChB,MAAA;AAAA,IACA;AAAA,GACF,GAAI,WAAW,EAAC;AAEhB,EAAA,MAAM,YAAsB,EAAC;AAE7B,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,MAAM,oBAAA,GAAuB,MAAM,iBAAA,CAAkB,EAAE,QAAQ,CAAA;AAE/D,IAAA,IAAI,MAAA,CAAO,KAAA,CAAM,oBAAoB,CAAA,EAAG;AACtC,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,OAAA,CAAQ,KAAA;AAAA,UACN,8BAAA;AAAA,UACA,oBAAA,CAAqB;AAAA,SACvB;AAAA,MACF;AAEA,MAAA,OAAO,oBAAA;AAAA,IACT;AAEA,IAAA,SAAA,CAAU,IAAA,CAAK,GAAG,oBAAA,CAAqB,KAAK,CAAA;AAAA,EAC9C;AAEA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,MAAM,eAAA,GAAkB,MAAM,gBAAA,CAAiB,EAAE,QAAQ,CAAA;AAEzD,IAAA,IAAI,MAAA,CAAO,KAAA,CAAM,eAAe,CAAA,EAAG;AACjC,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,OAAA,CAAQ,KAAA,CAAM,8BAAA,EAAgC,eAAA,CAAgB,KAAK,CAAA;AAAA,MACrE;AAEA,MAAA,OAAO,eAAA;AAAA,IACT;AAEA,IAAA,SAAA,CAAU,IAAA,CAAK,GAAG,eAAA,CAAgB,KAAK,CAAA;AAAA,EACzC;AAEA,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,iBAAA,GAAoB,MAAM,cAAA,CAAe,EAAE,QAAQ,CAAA;AAEzD,IAAA,IAAI,MAAA,CAAO,KAAA,CAAM,iBAAiB,CAAA,EAAG;AACnC,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,OAAA,CAAQ,KAAA,CAAM,8BAAA,EAAgC,iBAAA,CAAkB,KAAK,CAAA;AAAA,MACvE;AAEA,MAAA,OAAO,iBAAA;AAAA,IACT;AAEA,IAAA,SAAA,CAAU,IAAA,CAAK,GAAG,iBAAA,CAAkB,KAAK,CAAA;AAAA,EAC3C;AAEA,EAAA,OAAO,YAAY,gBAAA,CAAiB,GAAA,CAAI,KAAK,SAAS,CAAA,EAAG,GAAG,CAAA,EAAG;AAAA,IAC7D,MAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACD,CAAA;AACH;AAOA,MAAM,gBAAA,GAAmB,CACvB,KAAA,EACA,GAAA,KACsB;AACtB,EAAA,IAAI,QAAQ,MAAA,EAAW;AACrB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAEpC,EAAA,MAAM,UAAA,GAAa,WAAA,CAAY,QAAA,CAAS,IAAA,CAAK,GAAG,CAAA,GAC5C,WAAA,GACC,CAAA,EAAG,WAAW,CAAA,EAAG,IAAA,CAAK,GAAG,CAAA,CAAA;AAE9B,EAAA,OAAO,KAAA,CAAM,MAAA,CAAO,CAAC,IAAA,KAAS;AAC5B,IAAA,MAAM,OAAA,GAAU,KAAK,UAAA,CAAW,IAAI,IAAI,IAAA,GAAO,IAAA,CAAK,QAAQ,IAAI,CAAA;AAEhE,IAAA,OAAO,OAAA,KAAY,WAAA,IAAe,OAAA,CAAQ,UAAA,CAAW,UAAU,CAAA;AAAA,EACjE,CAAC,CAAA;AACH,CAAA;AAeO,MAAM,cAAA,GAAiB,OAC5B,IAAA,EACA,OAAA,KAwBG;AAEH,EAAA,MAAM;AAAA,IACJ,MAAA,GAAS,KAAA;AAAA,IACT,gBAAA,GAAmB,IAAA;AAAA,IACnB,eAAA,GAAkB,IAAA;AAAA,IAClB,aAAA,GAAgB,IAAA;AAAA,IAChB,aAAA,GAAgB,IAAA;AAAA,IAChB,MAAA;AAAA,IACA;AAAA,GACF,GAAI,WAAW,EAAC;AAEhB,EAAA,MAAM,eAAA,GAAkB,SAAS,MAAM;AAAA,EAAC,IAAI,OAAA,CAAQ,IAAA;AAGpD,EAAA,MAAM,kBAAA,GAAqB,MAAM,WAAA,CAAY,IAAA,EAAM;AAAA,IACjD;AAAA,GACD,CAAA;AAED,EAAA,IAAI,MAAA,CAAO,KAAA,CAAM,kBAAkB,CAAA,EAAG;AACpC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,OAAA,CAAQ,KAAA,CAAM,8BAAA,EAAgC,kBAAA,CAAmB,KAAK,CAAA;AAAA,IACxE;AAEA,IAAA,OAAO,kBAAA;AAAA,EACT;AAEA,EAAA,MAAM,YAAY,kBAAA,CAAmB,KAAA;AAErC,EAAA,MAAM,YAAA,GAAyB,UAAU,KAAA,EAAM;AAG/C,EAAA,KAAA,MAAW,EAAE,IAAA,EAAM,IAAA,EAAM,EAAA,EAAG,IAAK;AAAA,IAC/B,EAAE,IAAA,EAAM,WAAA,EAAa,IAAA,EAAM,gBAAA,EAAkB,IAAI,iBAAA,EAAkB;AAAA,IACnE,EAAE,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,eAAA,EAAiB,IAAI,gBAAA,EAAiB;AAAA,IAChE,EAAE,IAAA,EAAM,QAAA,EAAU,IAAA,EAAM,aAAA,EAAe,IAAI,cAAA;AAAe,GAC5D,EAAG;AACD,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA;AAAA,IACF;AAGA,IAAA,MAAM,WAAA,GAAc,MAAM,EAAA,CAAG,EAAE,QAAQ,CAAA;AAEvC,IAAA,IAAI,MAAA,CAAO,KAAA,CAAM,WAAW,CAAA,EAAG;AAC7B,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,cAAA,EAAiB,IAAI,CAAA,OAAA,CAAA,EAAW,YAAY,KAAK,CAAA;AAAA,MACjE;AAEA,MAAA,OAAO,WAAA;AAAA,IACT;AAEA,IAAA,MAAM,QAAQ,WAAA,CAAY,KAAA;AAG1B,IAAA,YAAA,CAAa,IAAA,CAAK,GAAG,KAAK,CAAA;AAAA,EAC5B;AAEA,EAAA,MAAM,WAAW,gBAAA,CAAiB,GAAA,CAAI,IAAA,CAAK,YAAY,GAAG,GAAG,CAAA;AAE7D,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,iBAAA,GAAoB;AAAA,MACxB,mBAAmB,iBAAA,GAAoB,MAAA;AAAA,MACvC,kBAAkB,gBAAA,GAAmB,MAAA;AAAA,MACrC,gBAAgB,cAAA,GAAiB;AAAA,KACnC,CAAE,OAAO,cAAc,CAAA;AAEvB,IAAA,MAAM,OAAA,GAAU;AAAA,MACd,qCAAqC,IAAI,CAAA,CAAA;AAAA,MACzC,iBAAA,CACG,GAAA;AAAA,QAAI,CAAC,CAAA,EAAG,CAAA,KACP,CAAA,KAAM,iBAAA,CAAkB,MAAA,GAAS,CAAA,GAAI,CAAA,EAAA,EAAK,CAAC,CAAA,CAAA,GAAK,CAAA,KAAA,EAAQ,CAAC,CAAA;AAAA,OAC3D,CACC,KAAK,EAAE;AAAA,KACZ,CAAE,KAAK,EAAE,CAAA;AAET,IAAA,eAAA,CAAgB,CAAA,EAAG,OAAO,CAAA,CAAA,CAAA,EAAK,QAAQ,CAAA;AAAA,EACzC;AAEA,EAAA,IAAI,GAAA,CAAI,OAAA,CAAQ,QAAQ,CAAA,EAAG;AACzB,IAAA,eAAA,CAAgB,oBAAoB,CAAA;AAEpC,IAAA,OAAO,MAAA,CAAO,GAAG,MAAS,CAAA;AAAA,EAC5B;AAEA,EAAA,OAAO,YAAY,QAAA,EAAU;AAAA,IAC3B,MAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACD,CAAA;AACH;;;;"}
|
package/dist/functions/index.mjs
CHANGED
|
@@ -9,7 +9,7 @@ export { genIndex } from './gen-index.mjs';
|
|
|
9
9
|
export { glob } from './glob.mjs';
|
|
10
10
|
export { isDirectlyExecuted } from './is-directly-executed.mjs';
|
|
11
11
|
export { makeEmptyDir } from './make-empty-dir.mjs';
|
|
12
|
-
export { checkShouldRunTypeChecks } from './should-run.mjs';
|
|
12
|
+
export { checkShouldRun, checkShouldRunTypeChecks } from './should-run.mjs';
|
|
13
13
|
export { executeParallel, executeStages } from './workspace-utils/execute-parallel.mjs';
|
|
14
14
|
export { getWorkspacePackages } from './workspace-utils/get-workspace-packages.mjs';
|
|
15
15
|
export { runCmdInParallelAcrossWorkspaces } from './workspace-utils/run-cmd-in-parallel.mjs';
|
|
@@ -1,7 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether a CI step should run, based on which files differ from a base
|
|
3
|
+
* branch. Reports `false` when every changed file matches one of the ignored
|
|
4
|
+
* patterns.
|
|
5
|
+
*
|
|
6
|
+
* This is the general form of {@link checkShouldRunTypeChecks}: it carries no
|
|
7
|
+
* default ignore list, so the caller states exactly which paths are irrelevant
|
|
8
|
+
* to the step being gated.
|
|
9
|
+
*
|
|
10
|
+
* Prefer gating the individual steps of a workflow with this over a
|
|
11
|
+
* `paths-ignore` trigger filter: a workflow that a path filter skips never
|
|
12
|
+
* reports a status check, so a pull request that changed only the filtered
|
|
13
|
+
* paths waits forever on a required check that will never arrive.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // Skip when the diff only touches a directory nothing checks
|
|
18
|
+
* await checkShouldRun({ pathsIgnore: ['experimental/'] });
|
|
19
|
+
*
|
|
20
|
+
* // Custom base branch
|
|
21
|
+
* await checkShouldRun({
|
|
22
|
+
* pathsIgnore: ['docs/', '**.md'],
|
|
23
|
+
* baseBranch: 'origin/develop',
|
|
24
|
+
* });
|
|
25
|
+
* ```;
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* GitHub Actions usage
|
|
29
|
+
* ```yaml
|
|
30
|
+
* - name: Check diff
|
|
31
|
+
* id: check_diff
|
|
32
|
+
* run: npm exec -- check-should-run --paths-ignore 'experimental/'
|
|
33
|
+
*
|
|
34
|
+
* - name: Run the checks
|
|
35
|
+
* if: steps.check_diff.outputs.should_run == 'true'
|
|
36
|
+
* run: npm run check
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @param options - Configuration options
|
|
40
|
+
* @param options.pathsIgnore - Patterns whose files do not affect the step.
|
|
41
|
+
* Matched with micromatch (with `dot: true`) against paths relative to the
|
|
42
|
+
* repository root, with one shorthand: a pattern ending with `/` is a
|
|
43
|
+
* directory prefix, so `docs/` is `docs/**`. Exact file names
|
|
44
|
+
* (`.editorconfig`) and ordinary globs (`**.md`, `docs/**`) both work.
|
|
45
|
+
* Defaults to `[]`, which ignores nothing.
|
|
46
|
+
* @param options.baseBranch - Base branch to compare against for determining
|
|
47
|
+
* changed files. Defaults to `'origin/main'`
|
|
48
|
+
* @returns Whether the step should run. An empty diff reads as "nothing
|
|
49
|
+
* changed" and so returns `false`. When running in GitHub Actions, also
|
|
50
|
+
* appends `should_run=true` or `should_run=false` to the file named by the
|
|
51
|
+
* `GITHUB_OUTPUT` environment variable.
|
|
52
|
+
*/
|
|
53
|
+
export declare const checkShouldRun: (options?: Readonly<{
|
|
54
|
+
pathsIgnore?: readonly string[];
|
|
55
|
+
baseBranch?: string;
|
|
56
|
+
}>) => Promise<boolean>;
|
|
1
57
|
/**
|
|
2
58
|
* Checks if TypeScript type checks should run based on the diff from a base
|
|
3
59
|
* branch. Skips type checks if all changed files match the ignored patterns.
|
|
4
60
|
*
|
|
61
|
+
* This is {@link checkShouldRun} with an ignore list of the files that a
|
|
62
|
+
* TypeScript project typically has but never type-checks — documentation,
|
|
63
|
+
* tooling configuration, license text. Pass `pathsIgnore` to replace that list,
|
|
64
|
+
* or call {@link checkShouldRun} directly for a step that is not a type check.
|
|
65
|
+
*
|
|
5
66
|
* This function is typically used in CI/CD pipelines to determine whether
|
|
6
67
|
* expensive type checking operations should be performed. If all changed files
|
|
7
68
|
* are documentation, configuration, or other non-TypeScript files, type checks
|
|
@@ -37,7 +98,7 @@
|
|
|
37
98
|
*
|
|
38
99
|
* @param options - Configuration options
|
|
39
100
|
* @param options.pathsIgnore - Array of patterns to ignore when determining if
|
|
40
|
-
* type checks should run.
|
|
101
|
+
* type checks should run. Matched as described in {@link checkShouldRun}:
|
|
41
102
|
*
|
|
42
103
|
* - **Exact file matches**: e.g., `.cspell.config.yaml` matches only that file
|
|
43
104
|
* - **Directory prefixes**: e.g., `docs/` matches any file in docs directory
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"should-run.d.mts","sourceRoot":"","sources":["../../src/functions/should-run.mts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"should-run.d.mts","sourceRoot":"","sources":["../../src/functions/should-run.mts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,eAAO,MAAM,cAAc,aACf,QAAQ,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,KACD,OAAO,CAAC,OAAO,CAyCjB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,eAAO,MAAM,wBAAwB,aACzB,QAAQ,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,KACD,OAAO,CAAC,OAAO,CAId,CAAC"}
|
|
@@ -1,51 +1,55 @@
|
|
|
1
|
+
import micromatch from 'micromatch';
|
|
1
2
|
import * as fs from 'node:fs/promises';
|
|
2
3
|
import * as path from 'node:path';
|
|
3
|
-
import { Result } from 'ts-data-forge';
|
|
4
|
-
import { getDiffFrom } from './diff.mjs';
|
|
4
|
+
import { Result, castMutable } from 'ts-data-forge';
|
|
5
|
+
import { getGitRoot, getDiffFrom } from './diff.mjs';
|
|
5
6
|
|
|
6
|
-
const
|
|
7
|
-
const pathsIgnore = options?.pathsIgnore ?? [
|
|
8
|
-
"LICENSE",
|
|
9
|
-
".editorconfig",
|
|
10
|
-
".gitignore",
|
|
11
|
-
".cspell.json",
|
|
12
|
-
".cspell.config.yaml",
|
|
13
|
-
".markdownlint-cli2.mjs",
|
|
14
|
-
".npmignore",
|
|
15
|
-
".prettierignore",
|
|
16
|
-
".prettierrc",
|
|
17
|
-
"docs/",
|
|
18
|
-
"**.md",
|
|
19
|
-
"**.txt"
|
|
20
|
-
];
|
|
7
|
+
const checkShouldRun = async (options) => {
|
|
8
|
+
const pathsIgnore = options?.pathsIgnore ?? [];
|
|
21
9
|
const baseBranch = options?.baseBranch ?? "origin/main";
|
|
22
10
|
const GITHUB_OUTPUT = process.env["GITHUB_OUTPUT"];
|
|
11
|
+
const gitRoot = await getGitRoot();
|
|
12
|
+
if (Result.isErr(gitRoot)) {
|
|
13
|
+
console.error("Error getting the git root:", gitRoot.value);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
23
16
|
const files = await getDiffFrom(baseBranch);
|
|
24
17
|
if (Result.isErr(files)) {
|
|
25
18
|
console.error("Error getting diff:", files.value);
|
|
26
19
|
process.exit(1);
|
|
27
20
|
}
|
|
28
|
-
const
|
|
29
|
-
(file) =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
if (pattern.startsWith("**.")) {
|
|
37
|
-
const extension = pattern.slice(2);
|
|
38
|
-
return path.basename(file).endsWith(extension);
|
|
39
|
-
}
|
|
40
|
-
return false;
|
|
41
|
-
})
|
|
21
|
+
const changedFiles = files.value.map(
|
|
22
|
+
(file) => path.relative(gitRoot.value, file).split(path.sep).join("/")
|
|
23
|
+
);
|
|
24
|
+
const patterns = pathsIgnore.map(toMatchPattern);
|
|
25
|
+
const shouldRun = changedFiles.some(
|
|
26
|
+
(file) => !micromatch.isMatch(file, castMutable(patterns), { dot: true })
|
|
42
27
|
);
|
|
43
28
|
if (GITHUB_OUTPUT !== void 0) {
|
|
44
|
-
await fs.appendFile(GITHUB_OUTPUT, `should_run=${
|
|
29
|
+
await fs.appendFile(GITHUB_OUTPUT, `should_run=${shouldRun}
|
|
45
30
|
`);
|
|
46
31
|
}
|
|
47
|
-
return
|
|
32
|
+
return shouldRun;
|
|
48
33
|
};
|
|
34
|
+
const checkShouldRunTypeChecks = async (options) => checkShouldRun({
|
|
35
|
+
pathsIgnore: options?.pathsIgnore ?? defaultTypeCheckPathsIgnore,
|
|
36
|
+
baseBranch: options?.baseBranch
|
|
37
|
+
});
|
|
38
|
+
const defaultTypeCheckPathsIgnore = [
|
|
39
|
+
"LICENSE",
|
|
40
|
+
".editorconfig",
|
|
41
|
+
".gitignore",
|
|
42
|
+
".cspell.json",
|
|
43
|
+
".cspell.config.yaml",
|
|
44
|
+
".markdownlint-cli2.mjs",
|
|
45
|
+
".npmignore",
|
|
46
|
+
".prettierignore",
|
|
47
|
+
".prettierrc",
|
|
48
|
+
"docs/",
|
|
49
|
+
"**.md",
|
|
50
|
+
"**.txt"
|
|
51
|
+
];
|
|
52
|
+
const toMatchPattern = (pattern) => pattern.endsWith("/") ? `${pattern}**` : pattern;
|
|
49
53
|
|
|
50
|
-
export { checkShouldRunTypeChecks };
|
|
54
|
+
export { checkShouldRun, checkShouldRunTypeChecks };
|
|
51
55
|
//# sourceMappingURL=should-run.mjs.map
|