pr-checkmate 1.22.7 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +101 -333
  2. package/cspell.json +9 -1
  3. package/dist/cli.js +32 -2
  4. package/dist/config/constants.d.ts +25 -1
  5. package/dist/config/constants.js +157 -38
  6. package/dist/config/index.d.ts +15 -2
  7. package/dist/config/index.js +28 -7
  8. package/dist/config/loader.js +5 -1
  9. package/dist/core/checks/dependencies/banned-imports.d.ts +2 -0
  10. package/dist/core/checks/dependencies/banned-imports.js +71 -0
  11. package/dist/core/checks/{circular-deps.d.ts → dependencies/circular-deps.d.ts} +1 -1
  12. package/dist/core/checks/{circular-deps.js → dependencies/circular-deps.js} +9 -10
  13. package/dist/core/checks/{dependency-check.d.ts → dependencies/dependency-check.d.ts} +1 -1
  14. package/dist/core/checks/{dependency-check.js → dependencies/dependency-check.js} +3 -3
  15. package/dist/core/checks/{license-check.d.ts → dependencies/license-check.d.ts} +1 -1
  16. package/dist/core/checks/{license-check.js → dependencies/license-check.js} +3 -3
  17. package/dist/core/checks/{npm-audit.d.ts → dependencies/npm-audit.d.ts} +1 -1
  18. package/dist/core/checks/{npm-audit.js → dependencies/npm-audit.js} +3 -3
  19. package/dist/core/checks/{outdated-deps.d.ts → dependencies/outdated-deps.d.ts} +1 -1
  20. package/dist/core/checks/{outdated-deps.js → dependencies/outdated-deps.js} +3 -3
  21. package/dist/core/checks/dependencies/vuln-scan.d.ts +9 -0
  22. package/dist/core/checks/dependencies/vuln-scan.js +41 -0
  23. package/dist/core/checks/findings.d.ts +37 -1
  24. package/dist/core/checks/findings.js +80 -3
  25. package/dist/core/checks/git/custom-rules.d.ts +2 -0
  26. package/dist/core/checks/git/custom-rules.js +102 -0
  27. package/dist/core/checks/{diff-smell.d.ts → git/diff-smell.d.ts} +1 -1
  28. package/dist/core/checks/{diff-smell.js → git/diff-smell.js} +3 -3
  29. package/dist/core/checks/git/large-files.d.ts +2 -0
  30. package/dist/core/checks/git/large-files.js +83 -0
  31. package/dist/core/checks/git/leftover-debug.d.ts +2 -0
  32. package/dist/core/checks/git/leftover-debug.js +77 -0
  33. package/dist/core/checks/git/lockfile-drift.d.ts +2 -0
  34. package/dist/core/checks/git/lockfile-drift.js +114 -0
  35. package/dist/core/checks/git/merge-conflict.d.ts +2 -0
  36. package/dist/core/checks/git/merge-conflict.js +109 -0
  37. package/dist/core/checks/git/missing-tests.d.ts +2 -0
  38. package/dist/core/checks/git/missing-tests.js +92 -0
  39. package/dist/core/checks/git/todo-fixme.d.ts +7 -0
  40. package/dist/core/checks/git/todo-fixme.js +74 -0
  41. package/dist/core/checks/{cpp-format.d.ts → languages/cpp-format.d.ts} +1 -1
  42. package/dist/core/checks/{cpp-format.js → languages/cpp-format.js} +3 -3
  43. package/dist/core/checks/languages/csharp-format.d.ts +13 -0
  44. package/dist/core/checks/languages/csharp-format.js +52 -0
  45. package/dist/core/checks/languages/go-format.d.ts +8 -0
  46. package/dist/core/checks/languages/go-format.js +48 -0
  47. package/dist/core/checks/languages/go-lint.d.ts +8 -0
  48. package/dist/core/checks/languages/go-lint.js +48 -0
  49. package/dist/core/checks/{kotlin-lint.d.ts → languages/kotlin-lint.d.ts} +1 -1
  50. package/dist/core/checks/{kotlin-lint.js → languages/kotlin-lint.js} +13 -17
  51. package/dist/core/checks/{lint.d.ts → languages/lint.d.ts} +1 -1
  52. package/dist/core/checks/{lint.js → languages/lint.js} +25 -14
  53. package/dist/core/checks/languages/php-format.d.ts +9 -0
  54. package/dist/core/checks/languages/php-format.js +49 -0
  55. package/dist/core/checks/{prettier.d.ts → languages/prettier.d.ts} +1 -1
  56. package/dist/core/checks/{prettier.js → languages/prettier.js} +10 -10
  57. package/dist/core/checks/{python-format.d.ts → languages/python-format.d.ts} +1 -1
  58. package/dist/core/checks/{python-format.js → languages/python-format.js} +3 -3
  59. package/dist/core/checks/{python-lint.d.ts → languages/python-lint.d.ts} +1 -1
  60. package/dist/core/checks/{python-lint.js → languages/python-lint.js} +3 -3
  61. package/dist/core/checks/languages/python-typecheck.d.ts +9 -0
  62. package/dist/core/checks/languages/python-typecheck.js +66 -0
  63. package/dist/core/checks/languages/ruby-lint.d.ts +8 -0
  64. package/dist/core/checks/languages/ruby-lint.js +50 -0
  65. package/dist/core/checks/languages/rust-format.d.ts +9 -0
  66. package/dist/core/checks/languages/rust-format.js +45 -0
  67. package/dist/core/checks/languages/rust-lint.d.ts +8 -0
  68. package/dist/core/checks/languages/rust-lint.js +50 -0
  69. package/dist/core/checks/{swift-lint.d.ts → languages/swift-lint.d.ts} +1 -1
  70. package/dist/core/checks/{swift-lint.js → languages/swift-lint.js} +13 -17
  71. package/dist/core/checks/{typecheck.d.ts → languages/typecheck.d.ts} +1 -1
  72. package/dist/core/checks/{typecheck.js → languages/typecheck.js} +3 -3
  73. package/dist/core/checks/{commitlint.d.ts → pr/commitlint.d.ts} +1 -1
  74. package/dist/core/checks/{commitlint.js → pr/commitlint.js} +4 -4
  75. package/dist/core/checks/{pr-body.d.ts → pr/pr-body.d.ts} +1 -1
  76. package/dist/core/checks/{pr-body.js → pr/pr-body.js} +2 -2
  77. package/dist/core/checks/{pr-size-check.d.ts → pr/pr-size-check.d.ts} +1 -1
  78. package/dist/core/checks/{pr-size-check.js → pr/pr-size-check.js} +13 -11
  79. package/dist/core/checks/{pr-title-lint.d.ts → pr/pr-title-lint.d.ts} +1 -1
  80. package/dist/core/checks/{pr-title-lint.js → pr/pr-title-lint.js} +2 -2
  81. package/dist/core/checks/quality/case-collision.d.ts +8 -0
  82. package/dist/core/checks/quality/case-collision.js +40 -0
  83. package/dist/core/checks/quality/config-validation.d.ts +8 -0
  84. package/dist/core/checks/quality/config-validation.js +63 -0
  85. package/dist/core/checks/quality/coverage.d.ts +2 -0
  86. package/dist/core/checks/quality/coverage.js +63 -0
  87. package/dist/core/checks/{dead-code.d.ts → quality/dead-code.d.ts} +1 -1
  88. package/dist/core/checks/{dead-code.js → quality/dead-code.js} +4 -4
  89. package/dist/core/checks/{duplicate-check.d.ts → quality/duplicate-check.d.ts} +1 -1
  90. package/dist/core/checks/{duplicate-check.js → quality/duplicate-check.js} +11 -15
  91. package/dist/core/checks/quality/license-header.d.ts +7 -0
  92. package/dist/core/checks/quality/license-header.js +74 -0
  93. package/dist/core/checks/{markdown-lint.d.ts → quality/markdown-lint.d.ts} +1 -1
  94. package/dist/core/checks/{markdown-lint.js → quality/markdown-lint.js} +8 -21
  95. package/dist/core/checks/{spellcheck.d.ts → quality/spellcheck.d.ts} +1 -1
  96. package/dist/core/checks/{spellcheck.js → quality/spellcheck.js} +11 -19
  97. package/dist/core/checks/{diff-security.d.ts → security/diff-security.d.ts} +1 -1
  98. package/dist/core/checks/security/diff-security.js +262 -0
  99. package/dist/core/checks/security/dockerfile-security.d.ts +2 -0
  100. package/dist/core/checks/security/dockerfile-security.js +92 -0
  101. package/dist/core/checks/security/migration-safety.d.ts +2 -0
  102. package/dist/core/checks/security/migration-safety.js +110 -0
  103. package/dist/core/checks/{security.d.ts → security/security.d.ts} +1 -1
  104. package/dist/core/checks/{security.js → security/security.js} +4 -4
  105. package/dist/core/checks/{sensitive-file-guard.d.ts → security/sensitive-file-guard.d.ts} +1 -1
  106. package/dist/core/checks/{sensitive-file-guard.js → security/sensitive-file-guard.js} +4 -4
  107. package/dist/core/checks/security/workflow-security.d.ts +2 -0
  108. package/dist/core/checks/security/workflow-security.js +75 -0
  109. package/dist/core/context.js +54 -10
  110. package/dist/core/registry.js +73 -28
  111. package/dist/core/reporters.d.ts +4 -3
  112. package/dist/core/reporters.js +104 -4
  113. package/dist/core/run-checks.js +21 -3
  114. package/dist/core/targets.d.ts +17 -1
  115. package/dist/core/targets.js +74 -4
  116. package/dist/core/types.d.ts +13 -1
  117. package/dist/index.d.ts +1 -1
  118. package/dist/index.js +3 -1
  119. package/dist/init.js +86 -8
  120. package/dist/interfaces/index.d.ts +101 -1
  121. package/dist/scripts/copy-configs.js +6 -1
  122. package/dist/utils/detect-language.d.ts +1 -1
  123. package/dist/utils/detect-language.js +32 -3
  124. package/dist/utils/glob.d.ts +10 -0
  125. package/dist/utils/glob.js +25 -0
  126. package/dist/utils/index.d.ts +1 -1
  127. package/dist/utils/index.js +1 -1
  128. package/eslint-default-rules.json +62 -0
  129. package/eslint.config.mjs +6 -66
  130. package/package.json +3 -1
  131. package/pr-checkmate.schema.json +166 -0
  132. package/src/config/cspell.json +9 -1
  133. package/src/config/eslint-default-rules.json +62 -0
  134. package/src/config/pr-checkmate.schema.json +166 -0
  135. package/dist/core/checks/diff-security.js +0 -145
  136. package/dist/utils/delta.d.ts +0 -5
  137. package/dist/utils/delta.js +0 -53
  138. package/src/config/eslint.config.mjs +0 -180
  139. /package/dist/core/checks/{ruff-shared.d.ts → languages/ruff-shared.d.ts} +0 -0
  140. /package/dist/core/checks/{ruff-shared.js → languages/ruff-shared.js} +0 -0
package/README.md CHANGED
@@ -9,66 +9,73 @@
9
9
  ![jscpd](https://img.shields.io/badge/jscpd-5-blue)
10
10
  [![API Docs](https://img.shields.io/badge/API_docs-TypeDoc-9600FF?logo=readthedocs&logoColor=white)](https://pr-checkmate-docs.pages.dev)
11
11
 
12
- > **PR CheckMate** is a universal PR quality checker that runs as a single `npm install` and works across **TypeScript, JavaScript, Python, C++, Swift, and Android/Kotlin** repositories — no per-language toolchain setup required.
13
-
14
- ---
15
-
16
- ## Why PR CheckMate?
17
-
18
- Most teams wire up linters and formatters separately for each repository. PR CheckMate ships everything pre-bundled: you add one step to your GitHub Actions workflow and every check runs automatically, in parallel, on every PR.
19
-
20
- - **One package, any stack** — TypeScript, Python, C++, Swift, Android (Kotlin/Java). Language is auto-detected from your repo.
21
- - **Zero client tooling** — ESLint, Prettier, cspell, jscpd, gitleaks, clang-format (WASM), and Ruff (WASM) are bundled. Clients install nothing extra.
22
- - **Delta mode** — only changed files are checked in PR context. Full-project fallback for local runs.
23
- - **Parallel execution** — independent checks run concurrently (~4× faster than sequential CI).
24
- - **Non-intrusive** — every check can be disabled per-repo via `pr-checkmate.json`.
25
-
26
- ---
12
+ > PR CheckMate is a universal PR quality checker: one `npm install`, 48 checks across
13
+ > 11 languages, running in CI on every pull request. The bundled languages need no
14
+ > per-language toolchain setup.
15
+
16
+ ## Why PR CheckMate
17
+
18
+ Most teams wire up linters and formatters separately in every repo. PR CheckMate ships
19
+ them pre-bundled. You add one step to a GitHub Actions workflow and the checks run on
20
+ every PR.
21
+
22
+ - One package, any stack. Language is auto-detected from the repo.
23
+ - Bundled tooling. ESLint, Prettier, Ruff, clang-format, and gitleaks run inside the
24
+ package (WASM/JS), so clients install nothing for those languages.
25
+ - Delta mode. In a PR only the changed files are checked; a full-project scan is the
26
+ fallback outside PR context.
27
+ - Parallel phases. Checks run concurrently within each phase: blocking, then
28
+ informational, then format.
29
+ - Reports in the PR. Results post as a single comment that updates in place, and
30
+ formatter fixes are committed back to the branch.
31
+ - Tunable. Any check can be re-scoped, downgraded, or disabled in `pr-checkmate.json`.
27
32
 
28
33
  ## Language Support
29
34
 
30
- | Language | Detection | Lint | Format | Type Check | Notes |
31
- |---|---|---|---|---|---|
32
- | **TypeScript** | `tsconfig.json` | ESLint + SonarJS | Prettier | `tsc --noEmit` | Fully bundled |
33
- | **JavaScript** | `package.json` | ESLint | Prettier | — | Fully bundled |
34
- | **Python** | `pyproject.toml`, `requirements.txt` | Ruff (WASM) | Ruff (WASM) | — | Fully bundled, no Python install needed |
35
- | **C++** | `CMakeLists.txt` | — | clang-format (WASM) | — | Fully bundled, no clang install needed |
36
- | **Swift** | `Package.swift` | SwiftLint | — | — | Requires `swiftlint` on runner |
37
- | **Android/Kotlin** | `build.gradle`, `AndroidManifest.xml` | ktlint | — | — | Requires `ktlint` on runner |
35
+ Bundled languages need nothing on the runner. Runner-dependency languages need their
36
+ tool installed; the check skips gracefully when the tool is absent.
38
37
 
39
- Universal checks (all languages): secret scanning, PR size, PR title, PR body, duplicate code, dead code, license compliance, markdown lint, spellcheck, sensitive file guard, diff security scan.
40
-
41
- ---
38
+ | Language | Checks | Toolchain |
39
+ |---|---|---|
40
+ | TypeScript / JavaScript | ESLint, Prettier, `tsc --noEmit` | Bundled |
41
+ | Python | Ruff (lint + format), mypy/pyright (types) | Ruff bundled; types need mypy or pyright on the runner |
42
+ | C++ | clang-format | Bundled |
43
+ | Swift | SwiftLint | `swiftlint` on the runner |
44
+ | Kotlin / Java | ktlint | `ktlint` on the runner |
45
+ | Go | `go vet`, `gofmt` | Go toolchain on the runner |
46
+ | Rust | `cargo clippy`, `cargo fmt` | Rust toolchain on the runner |
47
+ | C# | `dotnet format` | .NET SDK on the runner |
48
+ | Ruby | RuboCop | `rubocop` on the runner |
49
+ | PHP | PHP-CS-Fixer | `php-cs-fixer` on the runner |
50
+
51
+ Secret scanning (gitleaks) and the universal git-diff checks are bundled and run for
52
+ every language.
42
53
 
43
54
  ## Quickstart
44
55
 
45
- ### 1. Install
56
+ Install:
46
57
 
47
58
  ```bash
48
59
  npm install --save-dev pr-checkmate
49
60
  ```
50
61
 
51
- ### 2. Initialize
62
+ Scaffold `pr-checkmate.json` and `.github/workflows/pr-checkmate.yml` for the detected
63
+ languages:
52
64
 
53
65
  ```bash
54
66
  npx pr-checkmate init
55
67
  ```
56
68
 
57
- Creates `pr-checkmate.json` and `.github/workflows/pr-checkmate.yml` tailored to the detected languages in your repo.
58
-
59
- ### 3. Run
69
+ Run all checks:
60
70
 
61
71
  ```bash
62
72
  npx pr-checkmate all
63
73
  ```
64
74
 
65
- ---
66
-
67
- ## GitHub Actions — Examples by Language
75
+ ## GitHub Actions
68
76
 
69
- All examples follow the same structure: checkout → setup runtime (if needed) → `npm install pr-checkmate` → `npx pr-checkmate all`.
70
-
71
- ### TypeScript / JavaScript
77
+ Every workflow follows the same shape: checkout, set up Node, install, run. The
78
+ TypeScript setup is the baseline:
72
79
 
73
80
  ```yaml
74
81
  name: PR CheckMate
@@ -92,324 +99,85 @@ jobs:
92
99
  - run: npx pr-checkmate all
93
100
  ```
94
101
 
95
- ---
102
+ For a runner-dependency language, add its toolchain setup step before the run: Go with
103
+ `actions/setup-go`, Rust with `dtolnay/rust-toolchain`, C# with `actions/setup-dotnet`,
104
+ Ruby with `ruby/setup-ruby` (plus `gem install rubocop`), PHP with
105
+ `shivammathur/setup-php` (tools: `php-cs-fixer`), Kotlin by fetching the `ktlint`
106
+ binary. Swift's `swiftlint` is pre-installed on `macos-latest`. Anything missing is
107
+ skipped, not failed.
96
108
 
97
- ### Python
109
+ ## Checks
98
110
 
99
- ```yaml
100
- name: PR CheckMate
101
- on:
102
- pull_request:
103
- branches: [main]
111
+ 48 checks, grouped by category and run in parallel within each phase:
104
112
 
105
- permissions:
106
- contents: read
107
- pull-requests: write
108
-
109
- jobs:
110
- quality:
111
- runs-on: ubuntu-latest
112
- steps:
113
- - uses: actions/checkout@v4
114
- with: { fetch-depth: 0 }
115
- - uses: actions/setup-node@v4
116
- with: { node-version: 24 }
117
- # No pip install needed — Ruff runs via bundled WASM
118
- - run: npm install pr-checkmate
119
- - run: npx pr-checkmate all
120
- ```
121
-
122
- > Ruff (lint + format) runs via WASM — no Python or pip required on the runner.
123
-
124
- ---
125
-
126
- ### C++
127
-
128
- ```yaml
129
- name: PR CheckMate
130
- on:
131
- pull_request:
132
- branches: [main]
133
-
134
- permissions:
135
- contents: write
136
- pull-requests: write
137
-
138
- jobs:
139
- quality:
140
- runs-on: ubuntu-latest
141
- steps:
142
- - uses: actions/checkout@v4
143
- with: { fetch-depth: 0 }
144
- - uses: actions/setup-node@v4
145
- with: { node-version: 24 }
146
- # No clang install needed — clang-format runs via bundled WASM
147
- - run: npm install pr-checkmate
148
- - run: npx pr-checkmate all
149
- ```
150
-
151
- > clang-format runs via WASM — no system clang or LLVM install required.
152
-
153
- ---
154
-
155
- ### Swift
156
-
157
- ```yaml
158
- name: PR CheckMate
159
- on:
160
- pull_request:
161
- branches: [main]
162
-
163
- permissions:
164
- contents: read
165
- pull-requests: write
166
-
167
- jobs:
168
- quality:
169
- runs-on: macos-latest # SwiftLint is pre-installed on macOS runners
170
- steps:
171
- - uses: actions/checkout@v4
172
- with: { fetch-depth: 0 }
173
- - uses: actions/setup-node@v4
174
- with: { node-version: 24 }
175
- - run: npm install pr-checkmate
176
- - run: npx pr-checkmate all
177
- ```
178
-
179
- > `swiftlint` is pre-installed on GitHub's `macos-latest` runner. If not available, the check is skipped automatically.
180
-
181
- ---
182
-
183
- ### Android / Kotlin
184
-
185
- ```yaml
186
- name: PR CheckMate
187
- on:
188
- pull_request:
189
- branches: [main]
190
-
191
- permissions:
192
- contents: read
193
- pull-requests: write
194
-
195
- jobs:
196
- quality:
197
- runs-on: ubuntu-latest
198
- steps:
199
- - uses: actions/checkout@v4
200
- with: { fetch-depth: 0 }
201
- - uses: actions/setup-node@v4
202
- with: { node-version: 24 }
203
- - name: Install ktlint
204
- run: |
205
- curl -sSLO https://github.com/pinterest/ktlint/releases/latest/download/ktlint
206
- chmod +x ktlint
207
- sudo mv ktlint /usr/local/bin/
208
- - run: npm install pr-checkmate
209
- - run: npx pr-checkmate all
210
- ```
211
-
212
- > `ktlint` is not pre-installed on Ubuntu runners — the snippet above fetches the latest release binary. If ktlint is unavailable, the check is skipped automatically.
213
-
214
- ---
215
-
216
- ## All Checks
217
-
218
- | Check | Phase | Description |
219
- |---|---|---|
220
- | ESLint + SonarJS + JSDoc | blocking | Lint with complexity, import order, and doc coverage rules |
221
- | TypeScript | blocking | `tsc --noEmit` type check |
222
- | Dependency Check | blocking | Unused / missing deps via depcheck; silence CLI-only false positives with `dependency.ignore` |
223
- | NPM Audit | blocking | Vulnerability scan (`moderate`+) |
224
- | Circular Deps | blocking | Circular dependency detection |
225
- | License Check | blocking | Blocks GPL / AGPL / LGPL packages |
226
- | Ruff Lint | informational | Python linting via WASM |
227
- | SwiftLint | informational | Swift linting |
228
- | ktlint | informational | Kotlin linting |
229
- | Dead Code | informational | Unused exports (`ts-unused-exports`); test and mock files are excluded from the report by default — override with `deadCode.ignoreFiles` (regex) |
230
- | Duplicate Code | informational | `jscpd` — 5 lines / 50 tokens threshold; test files ignored by default (set `duplicate.ignore`); only source-code formats are scanned, so YAML/JSON/Markdown are skipped unless you override `duplicate.formats` |
231
- | Diff Smell | informational | `console.*`, `debugger`, `TODO/FIXME` in added lines |
232
- | Diff Security | informational | XSS, `eval`, SQLi, weak crypto in added lines |
233
- | Sensitive Files | informational | `.env`, private keys, CI configs touched in PR |
234
- | PR Size | informational | Warns if PR > 50 files or 1 000 lines |
235
- | PR Title | informational | Conventional Commits format |
236
- | PR Body | informational | Min 20 chars + ticket reference |
237
- | Commitlint | informational | Commit message convention |
238
- | Outdated Deps | informational | Major-behind packages |
239
- | Markdown Lint | informational | `.md` / `.mdx` via markdownlint |
240
- | Spellcheck | informational | EN, ES, FR, RU, UK, HE dictionaries |
241
- | Prettier | format | Auto-format; commits fixes back to branch |
242
- | C++ Format | format | clang-format via WASM |
243
- | Python Format | format | Ruff formatter via WASM |
244
-
245
- ---
113
+ - Universal git-diff (18) — language-agnostic and bundled: merge-conflict markers,
114
+ secret scan, diff security (JS/TS/Python/Go/Kotlin), GitHub Actions and Dockerfile
115
+ security, case-collision, custom rules, banned imports, license headers, leftover
116
+ debug lines, lockfile drift, large/binary files, TODO/FIXME, missing tests, coverage
117
+ presence, DB migration safety, and sensitive-file guard.
118
+ - Dependencies (6) — unused/missing, circular, outdated, license compliance, npm audit,
119
+ and a cross-language vuln scan (osv-scanner, opt-in).
120
+ - Quality (4) — duplicate code, dead code, multi-language spellcheck, markdown lint.
121
+ - PR hygiene (4) — size, title, body, and commit-message convention.
122
+ - Per-language (16) — lint, format, and type-check for the languages listed above.
246
123
 
247
124
  ## Configuration
248
125
 
249
- All checks can be tuned or disabled per-repo via `pr-checkmate.json`:
250
-
251
- ```json
126
+ Everything lives in `pr-checkmate.json`. Run `npx pr-checkmate init` to scaffold the
127
+ full file for your detected languages.
128
+
129
+ - Severity map. The one universal control. Key any check by its display name (as it
130
+ appears in the report) and set `"error"` to fail the run, `"warn"` for advisory, or
131
+ `"off"` to disable it. This works for every check, old or new.
132
+ - Per-check options. For example `prSize.maxFiles`/`maxLines`, `largeFiles.maxSizeKb`
133
+ and `allow`, `prBody.minLength`, `duplicate.minLines`, `missingTests.ignore`, or
134
+ `<check>.ignore` to mute a single finding. Any check also takes `enabled: false`.
135
+ - `customRules`. Your own regex rules run against the diff; a rule with
136
+ `severity: "error"` blocks the run. Fields: `name`, `pattern`, `message?`,
137
+ `severity?`, `include?`, `exclude?`.
138
+ - `bannedImports` forbids specific dependencies or imports. `licenseHeader` requires a
139
+ header on newly added source files (opt-in).
140
+ - Inline suppression. Append `// pr-checkmate-ignore` to any line to skip it.
141
+
142
+ ```jsonc
252
143
  {
253
- "sourcePath": "src",
254
- "lint": {
255
- "rules": { "no-console": "error" },
256
- "ignorePatterns": ["**/*.generated.ts"]
144
+ // Promote, downgrade, or disable ANY check by its display name.
145
+ "severity": {
146
+ "PR Size": "error", // oversized PRs now fail the run
147
+ "Spellcheck": "off" // turn a check off entirely
257
148
  },
258
- "python": { "enabled": true, "ruff": { "lint": true, "format": true } },
259
- "swift": { "enabled": true },
260
- "kotlin": { "enabled": true },
261
- "cpp": { "enabled": true, "clangFormat": { "style": "Google" } },
262
- "duplicate": {
263
- "enabled": true,
264
- "minLines": 10,
265
- "formats": ["javascript", "typescript", "jsx", "tsx", "python", "kotlin", "swift", "c", "cpp"],
266
- "ignore": ["**/__tests__/**", "**/*.test.*", "**/*.spec.*", "**/test/**", "**/tests/**"]
267
- },
268
- "deadCode": {
269
- "enabled": true,
270
- "ignoreFiles": ["src/index\\.ts", "handler"]
271
- },
272
- "dependency": {
273
- "enabled": true,
274
- "ignore": ["@types/*", "some-cli-tool"]
275
- },
276
- "commitlint": {
277
- "enabled": true,
278
- "types": ["feat", "fix", "docs", "chore", "ci", "refactor", "test"]
279
- },
280
- "licenseCheck": {
281
- "allowPackages": [],
282
- "allowLicenses": ["LGPL-3.0"]
283
- },
284
- "prBody": { "enabled": true, "minLength": 20, "requireTicket": true }
149
+ "prSize": { "maxFiles": 40, "maxLines": 800 },
150
+ "customRules": [
151
+ { "name": "no-fixme", "pattern": "FIXME", "severity": "error" }
152
+ ]
153
+ // Skip a single line by appending `// pr-checkmate-ignore` to it.
285
154
  }
286
155
  ```
287
156
 
288
- A note on `duplicate.ignore`:
289
-
290
- - Setting it replaces the default test-file list rather than merging with it. If you add your own patterns, include any test globs you still want excluded.
291
- - `node_modules/**`, `dist/**`, and `.git/**` are always excluded, regardless of config.
292
- - `duplicate.formats` defaults to source-code formats only, so data files like YAML, JSON, and Markdown are not scanned. Setting it replaces the default list, so add `"yaml"` if you want duplication flagged in those files too.
293
-
294
- A note on `dependency.ignore`:
295
-
296
- - List dependency names or globs (such as `"@types/*"`) to exclude from the unused/missing check. The values are passed straight to depcheck's `--ignores`.
297
- - Use it for packages that only run as CLI binaries or are referenced from config files. depcheck sees no `import` for them and would otherwise flag them as unused.
298
- - When set, `dependency.ignore` takes precedence over any `.depcheckrc` file. Leave it empty or unset and your existing `.depcheckrc` still applies.
299
-
300
- A note on `deadCode.ignoreFiles`:
301
-
302
- - The values are regex sources, not globs, and each one is matched against the file path. So `\.test\.` matches any file with `.test.` in its name.
303
- - It defaults to test and mock files: `/__tests__/`, `/__mocks__/`, `/__mock__/`, `/tests?/`, `\.test\.`, `\.spec\.`. Their exports are consumed only by the test runner, so they showed up as false-positive "unused" before.
304
- - Setting it replaces the default list rather than merging with it. Reach for it to exempt entry points or barrels like `src/index.ts` or a lambda `handler` whose exports are the public surface.
305
- - It applies to the report only and never drops files from analysis, so a match here cannot cascade into missed dead code elsewhere.
306
-
307
- ---
308
-
309
- ## Delta Mode
310
-
311
- In GitHub Actions PR context, language checks automatically switch to **delta mode** — only files changed in the PR are checked. Outside PR context (local, push workflows) the checks fall back to a full project scan.
157
+ ## PR Summary Comment
312
158
 
313
- ---
159
+ After `npx pr-checkmate all`, a summary table is posted to the PR and updated in place
160
+ on later pushes, so there are no duplicate comments. Format fixes (Prettier, Ruff,
161
+ clang-format, and the rest) are committed straight back to the branch. Posting needs
162
+ the `pull-requests: write` permission, which the generated workflow already includes.
314
163
 
315
164
  ## Programmatic API
316
165
 
317
- Besides the CLI, PR CheckMate ships a typed programmatic API. Install the package and import checks directly — useful for embedding the same quality gates inside your own tooling. The full reference is published at the [API docs site](https://pr-checkmate-docs.pages.dev).
318
-
319
- Run the built-in checks:
166
+ Besides the CLI, PR CheckMate ships a typed API for embedding the same gates in your own
167
+ tooling. Import `runChecks`, `defineCheck`, and the outcome helpers, then run the
168
+ registry or your own checks. The full reference is at the
169
+ [API docs site](https://pr-checkmate-docs.pages.dev).
320
170
 
321
171
  ```ts
322
172
  import { runChecks } from 'pr-checkmate';
323
- import type { CheckReport } from 'pr-checkmate';
324
-
325
- const report: CheckReport = await runChecks({
326
- cwd: process.cwd(),
327
- reporter: 'stdout', // 'none' | 'stdout' | 'github' | (report) => void
328
- });
329
173
 
174
+ const report = await runChecks({ cwd: process.cwd(), reporter: 'github' });
330
175
  if (!report.ok) process.exit(1);
331
176
  ```
332
177
 
333
- `runChecks` never throws on violations and never calls `process.exit` — the caller decides. `report.ok` is `true` when nothing failed; warnings and skips do not affect it.
334
-
335
- Author a custom check:
336
-
337
- ```ts
338
- import { runChecks, defineCheck, pass, fail } from 'pr-checkmate';
339
-
340
- const noFixmes = defineCheck({
341
- name: 'no-fixmes',
342
- phase: 'lint',
343
- applies: () => true,
344
- run: async (ctx) => {
345
- // inspect ctx (config, changed files, language, sha range) and return an outcome
346
- return pass();
347
- },
348
- });
349
-
350
- await runChecks({ checks: [noFixmes] }); // appended to the built-in registry by default
351
- ```
352
-
353
- ### Key exports
354
-
355
- | Export | Purpose |
356
- |---|---|
357
- | `runChecks` | Run the check pipeline; returns a structured `CheckReport` |
358
- | `buildContext` | Build the `CheckContext` (language, config, sha range) checks receive |
359
- | `REGISTRY` | The array of built-in checks |
360
- | `defineCheck` | Identity helper for authoring a `Check` with full type inference |
361
- | `pass` / `warn` / `fail` / `skip` | Outcome constructors for check bodies |
362
- | `getSourcePath` / `getPackageConfigPath` / `hasLocalConfig` | Config-path helpers |
363
- | Types | `Check`, `CheckContext`, `CheckReport`, `CheckResult`, `CheckOutcome`, `CheckStatus`, `RunOptions`, `Language`, `Phase`, `ReporterKind`, `ReporterFn`, `PRCheckMateConfig` |
364
-
365
- Regenerate the docs locally with `npm run docs` (output in `docs/api`).
366
-
367
- ---
368
-
369
- ## PR Summary Comment
370
-
371
- After `npx pr-checkmate all`, a summary table is posted to the PR. On repeated pushes the comment is updated in place — no duplicate comments.
372
-
373
- ```text
374
- ## PR CheckMate Summary
375
-
376
- 11 passed · 3 warnings · 0 failed · 0 skipped
377
-
378
- | Check | Result |
379
- |----------------|-----------------------------------------|
380
- | ESLint | ✅ pass |
381
- | TypeScript | ✅ pass |
382
- | Ruff Lint | ⚠️ warn — 3 issues in 2 files |
383
- | Diff Smell | ⚠️ warn — 2x console.*(), 1x TODO |
384
- | PR Body | ⚠️ warn — no ticket reference |
385
- | ... | ... |
386
- ```
387
-
388
- Requires `pull-requests: write` permission — the generated workflow includes this automatically.
389
-
390
- ---
391
-
392
- ## Tech Stack
393
-
394
- | Tool | Role |
395
- |---|---|
396
- | ESLint + @typescript-eslint | TypeScript / JS linting |
397
- | eslint-plugin-sonarjs | Complexity analysis |
398
- | eslint-plugin-import | Import ordering |
399
- | eslint-plugin-jsdoc | Documentation coverage |
400
- | Prettier | Code formatting |
401
- | @astral-sh/ruff-wasm-nodejs | Python lint + format (WASM) |
402
- | @wasm-fmt/clang-format | C++ formatting (WASM) |
403
- | SwiftLint | Swift linting (system binary) |
404
- | ktlint | Kotlin linting (system binary) |
405
- | cspell | Multilingual spellcheck |
406
- | gitleaks | Secret scanning |
407
- | depcheck | Dependency analysis |
408
- | ts-unused-exports | Dead code detection |
409
- | jscpd | Duplicate code detection |
410
- | license-checker | License compliance |
411
-
412
- ---
178
+ `runChecks` never throws on violations and never calls `process.exit`; the caller
179
+ decides. `report.ok` is `true` when nothing failed, and warnings and skips do not
180
+ affect it.
413
181
 
414
182
  ## License
415
183
 
package/cspell.json CHANGED
@@ -693,7 +693,15 @@
693
693
  "litert",
694
694
  "SHTPB",
695
695
  "FUTX",
696
- "subdirs"
696
+ "subdirs",
697
+ "clippy",
698
+ "mypy",
699
+ "pyright",
700
+ "jacoco",
701
+ "depcheckrc",
702
+ "gofmt",
703
+ "dotnet",
704
+ "rubocop"
697
705
  ],
698
706
  "ignorePaths": [
699
707
  "**/node_modules/**",
package/dist/cli.js CHANGED
@@ -22,6 +22,21 @@ const COMMAND_TO_CHECK = {
22
22
  typecheck: 'TypeScript',
23
23
  'diff-smell': 'Diff Smells',
24
24
  'diff-security': 'Diff Security',
25
+ 'workflow-security': 'Workflow Security',
26
+ 'custom-rules': 'Custom Rules',
27
+ 'banned-imports': 'Banned Imports',
28
+ 'license-header': 'License Header',
29
+ 'config-validation': 'Config Validation',
30
+ 'dockerfile-security': 'Dockerfile Security',
31
+ 'case-collision': 'Case Collision',
32
+ 'vuln-scan': 'Vuln Scan',
33
+ 'leftover-debug': 'Leftover Debug',
34
+ 'lockfile-drift': 'Lockfile Drift',
35
+ 'large-files': 'Large Files',
36
+ 'todo-fixme': 'TODO/FIXME',
37
+ 'missing-tests': 'Missing Tests',
38
+ coverage: 'Coverage',
39
+ 'migration-safety': 'Migration Safety',
25
40
  'sensitive-files': 'Sensitive Files',
26
41
  'pr-body': 'PR Body',
27
42
  duplicate: 'Duplicate Code',
@@ -29,6 +44,14 @@ const COMMAND_TO_CHECK = {
29
44
  'cpp-format': 'C++ Format',
30
45
  'python-lint': 'Ruff Lint',
31
46
  'python-format': 'Ruff Format',
47
+ 'python-typecheck': 'Python Types',
48
+ 'go-lint': 'Go Vet',
49
+ 'go-format': 'Go Format',
50
+ 'rust-lint': 'Clippy',
51
+ 'rust-format': 'Rustfmt',
52
+ 'csharp-format': 'C# Format',
53
+ 'ruby-lint': 'RuboCop',
54
+ 'php-format': 'PHP CS Fixer',
32
55
  };
33
56
  const cmd = process.argv[2];
34
57
  void (async () => {
@@ -37,9 +60,16 @@ void (async () => {
37
60
  await (0, init_1.init)();
38
61
  process.exit(0);
39
62
  }
40
- // Full run: post a GitHub summary comment and allow formatters to write.
63
+ // Full run: auto-detect the CI platform (GitHub/GitLab/Bitbucket), post the
64
+ // summary to its PR/MR, and allow formatters to write.
41
65
  if (!cmd || cmd === 'all') {
42
- const report = await (0, core_1.runChecks)({ reporter: 'github', write: true });
66
+ const report = await (0, core_1.runChecks)({ reporter: 'auto', write: true });
67
+ process.exit(report.ok ? 0 : 1);
68
+ }
69
+ // Local pre-commit: check the staged changes (index vs HEAD), print to
70
+ // stdout, never modify files. Exits non-zero on failure to block the commit.
71
+ if (cmd === 'precommit') {
72
+ const report = await (0, core_1.runChecks)({ staged: true, reporter: 'stdout', write: false });
43
73
  process.exit(report.ok ? 0 : 1);
44
74
  }
45
75
  const checkName = COMMAND_TO_CHECK[cmd];
@@ -1,5 +1,20 @@
1
1
  /**
2
- * Common patterns to ignore in all checks
2
+ * Build output, dependency, tooling, and report directories that are never
3
+ * product code. Every check excludes them by directory-name segment match (see
4
+ * `targets.ts`): a match on any segment of a path drops the file. Untracked
5
+ * build dirs are already excluded because checks read git-tracked files only —
6
+ * this list additionally covers dirs that repos commonly *commit* (`.github`,
7
+ * `.vscode`, `.idea`, `.claude`) and any checked-in build artifacts.
8
+ *
9
+ * Covers the common ecosystems: Node/JS/web, Python, Java/Kotlin/Gradle/Android,
10
+ * Swift/iOS/Xcode, and C/C++/CMake. Add more here.
11
+ */
12
+ export declare const IGNORED_DIRS: string[];
13
+ /**
14
+ * Glob form of the ignore list, for tools that take glob ignores directly
15
+ * (ESLint `--ignore-pattern`, cspell `--exclude`, the generated
16
+ * `.prettierignore`). Combines {@link IGNORED_DIRS} with a few tool-specific
17
+ * nested report globs that are not plain directory names.
3
18
  */
4
19
  export declare const IGNORE_PATTERNS: string[];
5
20
  /**
@@ -66,3 +81,12 @@ export declare const documentation: {
66
81
  cspell: string;
67
82
  };
68
83
  export declare const CONFIG_FILE: string;
84
+ /**
85
+ * Every top-level key PR CheckMate recognises in pr-checkmate.json — the union
86
+ * of the `PRCheckMateConfig` interface fields and the keys the `init` generator
87
+ * writes (which use `eslint`/`cspell`/`markdownlint` rather than the interface's
88
+ * `lint`/`spellcheck`). The Config Validation check warns on any key not in this
89
+ * set (typos), ignoring `//`-prefixed comment keys and `$schema`. Keep in sync
90
+ * when adding a new configurable check.
91
+ */
92
+ export declare const KNOWN_CONFIG_KEYS: Set<string>;