pr-checkmate 3.0.4 → 3.1.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 (378) hide show
  1. package/dist/{cli.js → cjs/cli.js} +30 -30
  2. package/dist/{config → cjs/config}/index.d.ts +2 -2
  3. package/dist/{config → cjs/config}/index.js +8 -7
  4. package/dist/{config → cjs/config}/loader.d.ts +1 -1
  5. package/dist/{config → cjs/config}/loader.js +8 -8
  6. package/dist/{core → cjs/core}/checks/dependencies/banned-imports.d.ts +1 -1
  7. package/dist/{core → cjs/core}/checks/dependencies/banned-imports.js +10 -10
  8. package/dist/{core → cjs/core}/checks/dependencies/circular-deps.d.ts +1 -1
  9. package/dist/{core → cjs/core}/checks/dependencies/circular-deps.js +27 -27
  10. package/dist/{core → cjs/core}/checks/dependencies/dependency-check.d.ts +1 -1
  11. package/dist/{core → cjs/core}/checks/dependencies/dependency-check.js +17 -17
  12. package/dist/{core → cjs/core}/checks/dependencies/grype-scan.d.ts +1 -1
  13. package/dist/{core → cjs/core}/checks/dependencies/grype-scan.js +18 -18
  14. package/dist/{core → cjs/core}/checks/dependencies/license-check.d.ts +1 -1
  15. package/dist/{core → cjs/core}/checks/dependencies/license-check.js +12 -12
  16. package/dist/{core → cjs/core}/checks/dependencies/npm-audit.d.ts +1 -1
  17. package/dist/{core → cjs/core}/checks/dependencies/npm-audit.js +14 -14
  18. package/dist/{core → cjs/core}/checks/dependencies/outdated-deps.d.ts +1 -1
  19. package/dist/{core → cjs/core}/checks/dependencies/outdated-deps.js +14 -14
  20. package/dist/{core → cjs/core}/checks/dependencies/vuln-scan.d.ts +1 -1
  21. package/dist/{core → cjs/core}/checks/dependencies/vuln-scan.js +14 -14
  22. package/dist/{core → cjs/core}/checks/findings.d.ts +1 -1
  23. package/dist/{core → cjs/core}/checks/findings.js +16 -16
  24. package/dist/{core → cjs/core}/checks/git/custom-rules.d.ts +1 -1
  25. package/dist/{core → cjs/core}/checks/git/custom-rules.js +19 -19
  26. package/dist/{core → cjs/core}/checks/git/diff-smell.d.ts +2 -2
  27. package/dist/{core → cjs/core}/checks/git/diff-smell.js +13 -13
  28. package/dist/{core → cjs/core}/checks/git/large-files.d.ts +1 -1
  29. package/dist/{core → cjs/core}/checks/git/large-files.js +15 -15
  30. package/dist/{core → cjs/core}/checks/git/leftover-debug.d.ts +1 -1
  31. package/dist/{core → cjs/core}/checks/git/leftover-debug.js +13 -13
  32. package/dist/{core → cjs/core}/checks/git/lockfile-drift.d.ts +1 -1
  33. package/dist/{core → cjs/core}/checks/git/lockfile-drift.js +12 -12
  34. package/dist/{core → cjs/core}/checks/git/merge-conflict.d.ts +1 -1
  35. package/dist/{core → cjs/core}/checks/git/merge-conflict.js +15 -15
  36. package/dist/{core → cjs/core}/checks/git/missing-tests.d.ts +1 -1
  37. package/dist/{core → cjs/core}/checks/git/missing-tests.js +15 -15
  38. package/dist/{core → cjs/core}/checks/git/todo-fixme.d.ts +1 -1
  39. package/dist/{core → cjs/core}/checks/git/todo-fixme.js +11 -11
  40. package/dist/{core → cjs/core}/checks/languages/cpp-format.d.ts +1 -1
  41. package/dist/{core → cjs/core}/checks/languages/cpp-format.js +18 -18
  42. package/dist/{core → cjs/core}/checks/languages/external-checks.d.ts +9 -9
  43. package/dist/{core → cjs/core}/checks/languages/external-checks.js +10 -10
  44. package/dist/{core → cjs/core}/checks/languages/external-runner.d.ts +2 -2
  45. package/dist/{core → cjs/core}/checks/languages/external-runner.js +21 -21
  46. package/dist/{core → cjs/core}/checks/languages/go-format.d.ts +1 -1
  47. package/dist/cjs/core/checks/languages/go-format.js +202 -0
  48. package/dist/cjs/core/checks/languages/lint.d.ts +2 -0
  49. package/dist/{core → cjs/core}/checks/languages/lint.js +21 -21
  50. package/dist/{core → cjs/core}/checks/languages/prettier.d.ts +1 -1
  51. package/dist/{core → cjs/core}/checks/languages/prettier.js +18 -18
  52. package/dist/{core → cjs/core}/checks/languages/python-format.d.ts +1 -1
  53. package/dist/{core → cjs/core}/checks/languages/python-format.js +14 -14
  54. package/dist/{core → cjs/core}/checks/languages/python-lint.d.ts +1 -1
  55. package/dist/{core → cjs/core}/checks/languages/python-lint.js +13 -13
  56. package/dist/{core → cjs/core}/checks/languages/python-typecheck.d.ts +1 -1
  57. package/dist/{core → cjs/core}/checks/languages/python-typecheck.js +29 -29
  58. package/dist/{core → cjs/core}/checks/languages/typecheck.d.ts +1 -1
  59. package/dist/{core → cjs/core}/checks/languages/typecheck.js +13 -13
  60. package/dist/{core → cjs/core}/checks/pr/commitlint.d.ts +1 -1
  61. package/dist/{core → cjs/core}/checks/pr/commitlint.js +12 -12
  62. package/dist/{core → cjs/core}/checks/pr/pr-body.d.ts +1 -1
  63. package/dist/{core → cjs/core}/checks/pr/pr-body.js +8 -8
  64. package/dist/{core → cjs/core}/checks/pr/pr-size-check.d.ts +1 -1
  65. package/dist/{core → cjs/core}/checks/pr/pr-size-check.js +10 -10
  66. package/dist/{core → cjs/core}/checks/pr/pr-title-lint.d.ts +1 -1
  67. package/dist/{core → cjs/core}/checks/pr/pr-title-lint.js +8 -8
  68. package/dist/{core → cjs/core}/checks/quality/case-collision.d.ts +1 -1
  69. package/dist/{core → cjs/core}/checks/quality/case-collision.js +7 -7
  70. package/dist/{core → cjs/core}/checks/quality/config-validation.d.ts +1 -1
  71. package/dist/{core → cjs/core}/checks/quality/config-validation.js +9 -9
  72. package/dist/{core → cjs/core}/checks/quality/coverage.d.ts +1 -1
  73. package/dist/{core → cjs/core}/checks/quality/coverage.js +4 -4
  74. package/dist/{core → cjs/core}/checks/quality/dead-code.d.ts +1 -1
  75. package/dist/{core → cjs/core}/checks/quality/dead-code.js +23 -23
  76. package/dist/{core → cjs/core}/checks/quality/duplicate-check.d.ts +1 -1
  77. package/dist/{core → cjs/core}/checks/quality/duplicate-check.js +22 -22
  78. package/dist/{core → cjs/core}/checks/quality/license-header.d.ts +1 -1
  79. package/dist/{core → cjs/core}/checks/quality/license-header.js +16 -16
  80. package/dist/{core → cjs/core}/checks/quality/markdown-lint.d.ts +1 -1
  81. package/dist/{core → cjs/core}/checks/quality/markdown-lint.js +17 -17
  82. package/dist/{core → cjs/core}/checks/quality/package-size.d.ts +1 -1
  83. package/dist/{core → cjs/core}/checks/quality/package-size.js +12 -12
  84. package/dist/{core → cjs/core}/checks/quality/spellcheck.d.ts +2 -2
  85. package/dist/{core → cjs/core}/checks/quality/spellcheck.js +18 -18
  86. package/dist/{core → cjs/core}/checks/quality/symlinks.d.ts +1 -1
  87. package/dist/{core → cjs/core}/checks/quality/symlinks.js +8 -8
  88. package/dist/{core → cjs/core}/checks/quality/yaml-lint.d.ts +1 -1
  89. package/dist/{core → cjs/core}/checks/quality/yaml-lint.js +12 -12
  90. package/dist/{core → cjs/core}/checks/security/diff-security.d.ts +1 -1
  91. package/dist/{core → cjs/core}/checks/security/diff-security.js +15 -15
  92. package/dist/{core → cjs/core}/checks/security/dockerfile-security.d.ts +1 -1
  93. package/dist/{core → cjs/core}/checks/security/dockerfile-security.js +16 -16
  94. package/dist/{core → cjs/core}/checks/security/migration-safety.d.ts +1 -1
  95. package/dist/{core → cjs/core}/checks/security/migration-safety.js +17 -17
  96. package/dist/{core → cjs/core}/checks/security/security.d.ts +1 -1
  97. package/dist/{core → cjs/core}/checks/security/security.js +21 -21
  98. package/dist/{core → cjs/core}/checks/security/sensitive-file-guard.d.ts +1 -1
  99. package/dist/{core → cjs/core}/checks/security/sensitive-file-guard.js +14 -14
  100. package/dist/{core → cjs/core}/checks/security/workflow-security.d.ts +2 -2
  101. package/dist/{core → cjs/core}/checks/security/workflow-security.js +14 -14
  102. package/dist/{core → cjs/core}/checks/tool-install.d.ts +1 -1
  103. package/dist/{core → cjs/core}/checks/tool-install.js +2 -2
  104. package/dist/{core → cjs/core}/context.d.ts +1 -1
  105. package/dist/{core → cjs/core}/context.js +16 -16
  106. package/dist/cjs/core/index.d.ts +4 -0
  107. package/dist/{core → cjs/core}/index.js +7 -7
  108. package/dist/{core → cjs/core}/install/cache.js +2 -2
  109. package/dist/{core → cjs/core}/install/doctor.d.ts +4 -4
  110. package/dist/{core → cjs/core}/install/doctor.js +34 -34
  111. package/dist/{core → cjs/core}/install/ensure.d.ts +2 -2
  112. package/dist/{core → cjs/core}/install/ensure.js +15 -14
  113. package/dist/{core → cjs/core}/install/lock.js +4 -4
  114. package/dist/{core → cjs/core}/install/prepare.d.ts +4 -4
  115. package/dist/{core → cjs/core}/install/prepare.js +13 -13
  116. package/dist/{core → cjs/core}/install/profiles.d.ts +2 -2
  117. package/dist/{core → cjs/core}/install/reuse.d.ts +1 -1
  118. package/dist/{core → cjs/core}/install/reuse.js +4 -4
  119. package/dist/{core → cjs/core}/registry.d.ts +1 -1
  120. package/dist/cjs/core/registry.js +112 -0
  121. package/dist/{core → cjs/core}/reporters.d.ts +1 -1
  122. package/dist/{core → cjs/core}/reporters.js +28 -28
  123. package/dist/{core → cjs/core}/run-checks.d.ts +2 -2
  124. package/dist/{core → cjs/core}/run-checks.js +31 -31
  125. package/dist/{core → cjs/core}/targets.d.ts +1 -1
  126. package/dist/{core → cjs/core}/targets.js +20 -20
  127. package/dist/{core → cjs/core}/types.d.ts +3 -3
  128. package/dist/cjs/index.d.ts +12 -0
  129. package/dist/{index.js → cjs/index.js} +18 -18
  130. package/dist/{init.js → cjs/init.js} +68 -56
  131. package/dist/{interfaces → cjs/interfaces}/index.d.ts +3 -3
  132. package/dist/cjs/package.json +1 -0
  133. package/dist/{scripts → cjs/scripts}/copy-configs.js +22 -7
  134. package/dist/{scripts → cjs/scripts}/generate-install-manifests.js +2 -2
  135. package/dist/{scripts → cjs/scripts}/publish-github.js +4 -4
  136. package/dist/{utils → cjs/utils}/detect-language.js +12 -12
  137. package/dist/cjs/utils/execa.js +46 -0
  138. package/dist/{utils → cjs/utils}/git.js +2 -2
  139. package/dist/{utils → cjs/utils}/http.js +2 -2
  140. package/dist/cjs/utils/index.d.ts +15 -0
  141. package/dist/{utils → cjs/utils}/index.js +13 -13
  142. package/dist/{utils → cjs/utils}/own-deps.d.ts +2 -0
  143. package/dist/{utils → cjs/utils}/own-deps.js +1 -0
  144. package/dist/{utils → cjs/utils}/package-version.js +2 -1
  145. package/dist/{utils → cjs/utils}/resolve-bin.js +2 -1
  146. package/dist/{utils → cjs/utils}/update-notifier.js +4 -4
  147. package/dist/esm/cli.d.ts +2 -0
  148. package/dist/esm/cli.js +137 -0
  149. package/dist/esm/config/constants.d.ts +153 -0
  150. package/dist/esm/config/constants.js +360 -0
  151. package/dist/esm/config/index.d.ts +40 -0
  152. package/dist/esm/config/index.js +60 -0
  153. package/dist/esm/config/loader.d.ts +6 -0
  154. package/dist/esm/config/loader.js +191 -0
  155. package/dist/esm/config/pr-checkmate-workflow-docker.yml +79 -0
  156. package/dist/esm/config/pr-checkmate-workflow.yml +92 -0
  157. package/dist/esm/core/checks/dependencies/banned-imports.d.ts +2 -0
  158. package/dist/esm/core/checks/dependencies/banned-imports.js +70 -0
  159. package/dist/esm/core/checks/dependencies/circular-deps.d.ts +2 -0
  160. package/dist/esm/core/checks/dependencies/circular-deps.js +155 -0
  161. package/dist/esm/core/checks/dependencies/dependency-check.d.ts +43 -0
  162. package/dist/esm/core/checks/dependencies/dependency-check.js +174 -0
  163. package/dist/esm/core/checks/dependencies/grype-scan.d.ts +22 -0
  164. package/dist/esm/core/checks/dependencies/grype-scan.js +112 -0
  165. package/dist/esm/core/checks/dependencies/license-check.d.ts +2 -0
  166. package/dist/esm/core/checks/dependencies/license-check.js +61 -0
  167. package/dist/esm/core/checks/dependencies/npm-audit.d.ts +6 -0
  168. package/dist/esm/core/checks/dependencies/npm-audit.js +80 -0
  169. package/dist/esm/core/checks/dependencies/outdated-deps.d.ts +2 -0
  170. package/dist/esm/core/checks/dependencies/outdated-deps.js +66 -0
  171. package/dist/esm/core/checks/dependencies/vuln-scan.d.ts +2 -0
  172. package/dist/esm/core/checks/dependencies/vuln-scan.js +54 -0
  173. package/dist/esm/core/checks/findings.d.ts +299 -0
  174. package/dist/esm/core/checks/findings.js +701 -0
  175. package/dist/esm/core/checks/git/custom-rules.d.ts +2 -0
  176. package/dist/esm/core/checks/git/custom-rules.js +106 -0
  177. package/dist/esm/core/checks/git/diff-smell.d.ts +19 -0
  178. package/dist/esm/core/checks/git/diff-smell.js +69 -0
  179. package/dist/esm/core/checks/git/large-files.d.ts +2 -0
  180. package/dist/esm/core/checks/git/large-files.js +112 -0
  181. package/dist/esm/core/checks/git/leftover-debug.d.ts +2 -0
  182. package/dist/esm/core/checks/git/leftover-debug.js +89 -0
  183. package/dist/esm/core/checks/git/lockfile-drift.d.ts +2 -0
  184. package/dist/esm/core/checks/git/lockfile-drift.js +114 -0
  185. package/dist/esm/core/checks/git/merge-conflict.d.ts +2 -0
  186. package/dist/esm/core/checks/git/merge-conflict.js +117 -0
  187. package/dist/esm/core/checks/git/missing-tests.d.ts +2 -0
  188. package/dist/esm/core/checks/git/missing-tests.js +105 -0
  189. package/dist/esm/core/checks/git/todo-fixme.d.ts +7 -0
  190. package/dist/esm/core/checks/git/todo-fixme.js +80 -0
  191. package/dist/esm/core/checks/languages/cpp-format.d.ts +7 -0
  192. package/dist/esm/core/checks/languages/cpp-format.js +91 -0
  193. package/dist/esm/core/checks/languages/external-checks.d.ts +77 -0
  194. package/dist/esm/core/checks/languages/external-checks.js +197 -0
  195. package/dist/esm/core/checks/languages/external-runner.d.ts +119 -0
  196. package/dist/esm/core/checks/languages/external-runner.js +138 -0
  197. package/dist/esm/core/checks/languages/go-format.d.ts +8 -0
  198. package/dist/{core → esm/core}/checks/languages/go-format.js +29 -35
  199. package/dist/esm/core/checks/languages/lint.d.ts +2 -0
  200. package/dist/esm/core/checks/languages/lint.js +92 -0
  201. package/dist/esm/core/checks/languages/prettier.d.ts +2 -0
  202. package/dist/esm/core/checks/languages/prettier.js +85 -0
  203. package/dist/esm/core/checks/languages/python-format.d.ts +7 -0
  204. package/dist/esm/core/checks/languages/python-format.js +61 -0
  205. package/dist/esm/core/checks/languages/python-lint.d.ts +9 -0
  206. package/dist/esm/core/checks/languages/python-lint.js +55 -0
  207. package/dist/esm/core/checks/languages/python-typecheck.d.ts +14 -0
  208. package/dist/esm/core/checks/languages/python-typecheck.js +184 -0
  209. package/dist/esm/core/checks/languages/ruff-shared.d.ts +10 -0
  210. package/dist/esm/core/checks/languages/ruff-shared.js +35 -0
  211. package/dist/esm/core/checks/languages/typecheck.d.ts +2 -0
  212. package/dist/esm/core/checks/languages/typecheck.js +61 -0
  213. package/dist/esm/core/checks/pr/commitlint.d.ts +2 -0
  214. package/dist/esm/core/checks/pr/commitlint.js +102 -0
  215. package/dist/esm/core/checks/pr/pr-body.d.ts +2 -0
  216. package/dist/esm/core/checks/pr/pr-body.js +43 -0
  217. package/dist/esm/core/checks/pr/pr-size-check.d.ts +2 -0
  218. package/dist/esm/core/checks/pr/pr-size-check.js +42 -0
  219. package/dist/esm/core/checks/pr/pr-title-lint.d.ts +2 -0
  220. package/dist/esm/core/checks/pr/pr-title-lint.js +31 -0
  221. package/dist/esm/core/checks/quality/case-collision.d.ts +8 -0
  222. package/dist/esm/core/checks/quality/case-collision.js +39 -0
  223. package/dist/esm/core/checks/quality/config-validation.d.ts +11 -0
  224. package/dist/esm/core/checks/quality/config-validation.js +188 -0
  225. package/dist/esm/core/checks/quality/coverage.d.ts +2 -0
  226. package/dist/esm/core/checks/quality/coverage.js +62 -0
  227. package/dist/esm/core/checks/quality/dead-code.d.ts +2 -0
  228. package/dist/esm/core/checks/quality/dead-code.js +124 -0
  229. package/dist/esm/core/checks/quality/duplicate-check.d.ts +2 -0
  230. package/dist/esm/core/checks/quality/duplicate-check.js +141 -0
  231. package/dist/esm/core/checks/quality/license-header.d.ts +7 -0
  232. package/dist/esm/core/checks/quality/license-header.js +81 -0
  233. package/dist/esm/core/checks/quality/markdown-lint.d.ts +2 -0
  234. package/dist/esm/core/checks/quality/markdown-lint.js +104 -0
  235. package/dist/esm/core/checks/quality/package-size.d.ts +36 -0
  236. package/dist/esm/core/checks/quality/package-size.js +196 -0
  237. package/dist/esm/core/checks/quality/spellcheck.d.ts +77 -0
  238. package/dist/esm/core/checks/quality/spellcheck.js +296 -0
  239. package/dist/esm/core/checks/quality/symlinks.d.ts +16 -0
  240. package/dist/esm/core/checks/quality/symlinks.js +57 -0
  241. package/dist/esm/core/checks/quality/yaml-lint.d.ts +20 -0
  242. package/dist/esm/core/checks/quality/yaml-lint.js +116 -0
  243. package/dist/esm/core/checks/security/diff-security.d.ts +2 -0
  244. package/dist/esm/core/checks/security/diff-security.js +354 -0
  245. package/dist/esm/core/checks/security/dockerfile-security.d.ts +2 -0
  246. package/dist/esm/core/checks/security/dockerfile-security.js +98 -0
  247. package/dist/esm/core/checks/security/migration-safety.d.ts +2 -0
  248. package/dist/esm/core/checks/security/migration-safety.js +137 -0
  249. package/dist/esm/core/checks/security/security.d.ts +63 -0
  250. package/dist/esm/core/checks/security/security.js +201 -0
  251. package/dist/esm/core/checks/security/sensitive-file-guard.d.ts +2 -0
  252. package/dist/esm/core/checks/security/sensitive-file-guard.js +160 -0
  253. package/dist/esm/core/checks/security/workflow-security.d.ts +12 -0
  254. package/dist/esm/core/checks/security/workflow-security.js +100 -0
  255. package/dist/esm/core/checks/tool-install.d.ts +102 -0
  256. package/dist/esm/core/checks/tool-install.js +66 -0
  257. package/dist/esm/core/commands.d.ts +27 -0
  258. package/dist/esm/core/commands.js +89 -0
  259. package/dist/esm/core/context.d.ts +62 -0
  260. package/dist/esm/core/context.js +241 -0
  261. package/dist/esm/core/index.d.ts +4 -0
  262. package/dist/esm/core/index.js +4 -0
  263. package/dist/esm/core/install/cache.d.ts +58 -0
  264. package/dist/esm/core/install/cache.js +142 -0
  265. package/dist/esm/core/install/doctor.d.ts +35 -0
  266. package/dist/esm/core/install/doctor.js +164 -0
  267. package/dist/esm/core/install/ensure.d.ts +77 -0
  268. package/dist/esm/core/install/ensure.js +269 -0
  269. package/dist/esm/core/install/lock.d.ts +34 -0
  270. package/dist/esm/core/install/lock.js +92 -0
  271. package/dist/esm/core/install/merge.d.ts +47 -0
  272. package/dist/esm/core/install/merge.js +85 -0
  273. package/dist/esm/core/install/prepare.d.ts +76 -0
  274. package/dist/esm/core/install/prepare.js +142 -0
  275. package/dist/esm/core/install/profiles.d.ts +78 -0
  276. package/dist/esm/core/install/profiles.js +192 -0
  277. package/dist/esm/core/install/reuse.d.ts +41 -0
  278. package/dist/esm/core/install/reuse.js +100 -0
  279. package/dist/esm/core/registry.d.ts +6 -0
  280. package/dist/esm/core/registry.js +109 -0
  281. package/dist/esm/core/reporters.d.ts +18 -0
  282. package/dist/esm/core/reporters.js +266 -0
  283. package/dist/esm/core/run-checks.d.ts +33 -0
  284. package/dist/esm/core/run-checks.js +293 -0
  285. package/dist/esm/core/targets.d.ts +140 -0
  286. package/dist/esm/core/targets.js +213 -0
  287. package/dist/esm/core/types.d.ts +195 -0
  288. package/dist/esm/core/types.js +38 -0
  289. package/dist/esm/index.d.ts +12 -0
  290. package/dist/esm/index.js +15 -0
  291. package/dist/esm/init.d.ts +38 -0
  292. package/dist/esm/init.js +421 -0
  293. package/dist/esm/interfaces/index.d.ts +432 -0
  294. package/dist/esm/interfaces/index.js +2 -0
  295. package/dist/esm/package.json +1 -0
  296. package/dist/esm/scripts/copy-configs.d.ts +1 -0
  297. package/dist/esm/scripts/copy-configs.js +64 -0
  298. package/dist/esm/scripts/generate-install-manifests.d.ts +39 -0
  299. package/dist/esm/scripts/generate-install-manifests.js +115 -0
  300. package/dist/esm/scripts/publish-github.d.ts +1 -0
  301. package/dist/esm/scripts/publish-github.js +45 -0
  302. package/dist/esm/utils/ci.d.ts +11 -0
  303. package/dist/esm/utils/ci.js +40 -0
  304. package/dist/esm/utils/detect-language.d.ts +48 -0
  305. package/dist/esm/utils/detect-language.js +234 -0
  306. package/dist/esm/utils/direct-deps.d.ts +21 -0
  307. package/dist/esm/utils/direct-deps.js +220 -0
  308. package/dist/esm/utils/execa.d.ts +22 -0
  309. package/dist/{utils → esm/utils}/execa.js +1 -4
  310. package/dist/esm/utils/git.d.ts +14 -0
  311. package/dist/esm/utils/git.js +21 -0
  312. package/dist/esm/utils/glob.d.ts +24 -0
  313. package/dist/esm/utils/glob.js +40 -0
  314. package/dist/esm/utils/http.d.ts +59 -0
  315. package/dist/esm/utils/http.js +115 -0
  316. package/dist/esm/utils/index.d.ts +15 -0
  317. package/dist/esm/utils/index.js +26 -0
  318. package/dist/esm/utils/logger.d.ts +65 -0
  319. package/dist/esm/utils/logger.js +157 -0
  320. package/dist/esm/utils/own-deps.d.ts +16 -0
  321. package/dist/esm/utils/own-deps.js +107 -0
  322. package/dist/esm/utils/package-version.d.ts +4 -0
  323. package/dist/esm/utils/package-version.js +38 -0
  324. package/dist/esm/utils/pool.d.ts +49 -0
  325. package/dist/esm/utils/pool.js +113 -0
  326. package/dist/esm/utils/resolve-bin.d.ts +67 -0
  327. package/dist/esm/utils/resolve-bin.js +156 -0
  328. package/dist/esm/utils/result-collector.d.ts +33 -0
  329. package/dist/esm/utils/result-collector.js +44 -0
  330. package/dist/esm/utils/update-notifier.d.ts +19 -0
  331. package/dist/esm/utils/update-notifier.js +108 -0
  332. package/install-manifests/core/package-lock.json +4 -4
  333. package/install-manifests/core/package.json +1 -1
  334. package/package.json +15 -13
  335. package/dist/core/checks/languages/lint.d.ts +0 -2
  336. package/dist/core/index.d.ts +0 -4
  337. package/dist/core/registry.js +0 -112
  338. package/dist/index.d.ts +0 -12
  339. package/dist/utils/index.d.ts +0 -15
  340. /package/dist/{cli.d.ts → cjs/cli.d.ts} +0 -0
  341. /package/dist/{config → cjs/config}/constants.d.ts +0 -0
  342. /package/dist/{config → cjs/config}/constants.js +0 -0
  343. /package/dist/{config → cjs/config}/pr-checkmate-workflow-docker.yml +0 -0
  344. /package/dist/{config → cjs/config}/pr-checkmate-workflow.yml +0 -0
  345. /package/dist/{core → cjs/core}/checks/languages/ruff-shared.d.ts +0 -0
  346. /package/dist/{core → cjs/core}/checks/languages/ruff-shared.js +0 -0
  347. /package/dist/{core → cjs/core}/commands.d.ts +0 -0
  348. /package/dist/{core → cjs/core}/commands.js +0 -0
  349. /package/dist/{core → cjs/core}/install/cache.d.ts +0 -0
  350. /package/dist/{core → cjs/core}/install/lock.d.ts +0 -0
  351. /package/dist/{core → cjs/core}/install/merge.d.ts +0 -0
  352. /package/dist/{core → cjs/core}/install/merge.js +0 -0
  353. /package/dist/{core → cjs/core}/install/profiles.js +0 -0
  354. /package/dist/{core → cjs/core}/types.js +0 -0
  355. /package/dist/{init.d.ts → cjs/init.d.ts} +0 -0
  356. /package/dist/{interfaces → cjs/interfaces}/index.js +0 -0
  357. /package/dist/{scripts → cjs/scripts}/copy-configs.d.ts +0 -0
  358. /package/dist/{scripts → cjs/scripts}/generate-install-manifests.d.ts +0 -0
  359. /package/dist/{scripts → cjs/scripts}/publish-github.d.ts +0 -0
  360. /package/dist/{utils → cjs/utils}/ci.d.ts +0 -0
  361. /package/dist/{utils → cjs/utils}/ci.js +0 -0
  362. /package/dist/{utils → cjs/utils}/detect-language.d.ts +0 -0
  363. /package/dist/{utils → cjs/utils}/direct-deps.d.ts +0 -0
  364. /package/dist/{utils → cjs/utils}/direct-deps.js +0 -0
  365. /package/dist/{utils → cjs/utils}/execa.d.ts +0 -0
  366. /package/dist/{utils → cjs/utils}/git.d.ts +0 -0
  367. /package/dist/{utils → cjs/utils}/glob.d.ts +0 -0
  368. /package/dist/{utils → cjs/utils}/glob.js +0 -0
  369. /package/dist/{utils → cjs/utils}/http.d.ts +0 -0
  370. /package/dist/{utils → cjs/utils}/logger.d.ts +0 -0
  371. /package/dist/{utils → cjs/utils}/logger.js +0 -0
  372. /package/dist/{utils → cjs/utils}/package-version.d.ts +0 -0
  373. /package/dist/{utils → cjs/utils}/pool.d.ts +0 -0
  374. /package/dist/{utils → cjs/utils}/pool.js +0 -0
  375. /package/dist/{utils → cjs/utils}/resolve-bin.d.ts +0 -0
  376. /package/dist/{utils → cjs/utils}/result-collector.d.ts +0 -0
  377. /package/dist/{utils → cjs/utils}/result-collector.js +0 -0
  378. /package/dist/{utils → cjs/utils}/update-notifier.d.ts +0 -0
@@ -0,0 +1,79 @@
1
+ name: PR CheckMate
2
+
3
+ # The container variant, scaffolded because this repository does not carry
4
+ # pr-checkmate as a dependency.
5
+ #
6
+ # The alternative would be `npx pr-checkmate`, and with no node_modules to reuse
7
+ # that resolves to whatever is newest on the registry and downloads it again on
8
+ # every job: 547 MB and about five minutes, measured. Worse, a major release
9
+ # would land on you without a line changing here — and a major release of a gate
10
+ # can start failing builds that passed yesterday.
11
+ #
12
+ # The image is pulled once and cached by the runner, and the tag below pins the
13
+ # major so nothing moves under you.
14
+
15
+ on:
16
+ pull_request:
17
+ branches: [main, master, develop]
18
+ types: [opened, synchronize, reopened]
19
+
20
+ # Least privilege. `pull-requests: write` is what lets the run upsert its summary
21
+ # comment on the PR; drop it and the checks still run, they just report to the log.
22
+ permissions:
23
+ contents: read
24
+ pull-requests: write
25
+
26
+ # Push three times in a minute and the first two runs become answers to questions
27
+ # nobody is asking any more — they still hold a runner, and they still race to
28
+ # upsert the summary comment, so a stale verdict can land on top of a fresh one.
29
+ # Keyed per PR, so runs on different pull requests never cancel each other.
30
+ concurrency:
31
+ group: pr-checkmate-${{ github.workflow }}-${{ github.ref }}
32
+ cancel-in-progress: true
33
+
34
+ jobs:
35
+ pr-checkmate:
36
+ name: PR CheckMate
37
+ runs-on: ubuntu-latest
38
+ # A hung step otherwise runs to GitHub's six-hour default before anyone hears
39
+ # about it. Every check has its own internal timeout; this is the backstop.
40
+ timeout-minutes: 20
41
+
42
+ steps:
43
+ - name: Checkout code
44
+ uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
45
+ with:
46
+ # Required, not optional. Without the full history the PR base commit is
47
+ # not in the clone, no diff range can be built, and every diff-based
48
+ # check skips itself. The run then says `Scan Scope: … set
49
+ # fetch-depth: 0`, which is this line.
50
+ fetch-depth: 0
51
+
52
+ # One job runs the whole registry. Which checks run is decided in
53
+ # pr-checkmate.json (`severity`), not by splitting this into jobs.
54
+ #
55
+ # `--user` is not a detail: without it every file a formatter rewrites comes
56
+ # back owned by root, and the next step in your pipeline fails on
57
+ # permissions long after this one reported success.
58
+ #
59
+ # The environment variables are passed through by name rather than by value:
60
+ # the run reads them to find the PR, and interpolating them into the command
61
+ # line would put their contents into a shell.
62
+ - name: Run PR CheckMate
63
+ env:
64
+ # Not injected automatically: without this the run cannot authenticate,
65
+ # and the summary comment silently never reaches the PR.
66
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
67
+ run: |
68
+ docker run --rm \
69
+ -v "$PWD:/repo" \
70
+ --user "$(id -u):$(id -g)" \
71
+ -e GITHUB_TOKEN \
72
+ -e GITHUB_REPOSITORY \
73
+ -e GITHUB_EVENT_NAME \
74
+ -e GITHUB_EVENT_PATH \
75
+ -e GITHUB_REF \
76
+ -e GITHUB_SHA \
77
+ -e CI \
78
+ -v "$GITHUB_EVENT_PATH:$GITHUB_EVENT_PATH:ro" \
79
+ ghcr.io/mybono/pr-checkmate:__IMAGE_TAG__ all
@@ -0,0 +1,92 @@
1
+ name: PR CheckMate
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main, master, develop]
6
+ types: [opened, synchronize, reopened]
7
+
8
+ # Least privilege. `pull-requests: write` is what lets the run upsert its summary
9
+ # comment on the PR; drop it and the checks still run, they just report to the log.
10
+ permissions:
11
+ contents: read
12
+ pull-requests: write
13
+
14
+ # Push three times in a minute and the first two runs become answers to questions
15
+ # nobody is asking any more — they still hold a runner, and they still race to
16
+ # upsert the summary comment, so a stale verdict can land on top of a fresh one.
17
+ # Keyed per PR, so runs on different pull requests never cancel each other.
18
+ concurrency:
19
+ group: pr-checkmate-${{ github.workflow }}-${{ github.ref }}
20
+ cancel-in-progress: true
21
+
22
+ jobs:
23
+ pr-checkmate:
24
+ name: PR CheckMate
25
+ runs-on: ubuntu-latest
26
+ # A hung step otherwise runs to GitHub's six-hour default before anyone hears
27
+ # about it. Every check here has its own internal timeout; this is the backstop
28
+ # for the ones that cannot fail themselves — a wedged network fetch, a tool
29
+ # waiting on stdin. Raise it for a large monorepo.
30
+ timeout-minutes: 20
31
+ steps:
32
+ - name: Checkout code
33
+ uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
34
+ with:
35
+ # Required, not optional. Without the full history the PR base commit is
36
+ # not in the clone, no diff range can be built, and every diff-based
37
+ # check — Diff Security, Workflow Security, Dockerfile Security,
38
+ # Sensitive Files and a dozen others — skips itself. The run then says
39
+ # `Scan Scope: … set fetch-depth: 0`, which is this line.
40
+ fetch-depth: 0
41
+
42
+ - name: Setup Node.js
43
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
44
+ with:
45
+ node-version: 24
46
+ cache: 'npm'
47
+
48
+ - name: Install dependencies
49
+ run: npm ci
50
+
51
+ # PR CheckMate fetches only the tooling this repository turns out to need
52
+ # (`npx pr-checkmate doctor` prints what and why). Without this step that
53
+ # tooling is fetched again on every run: the download shrinks, the wait
54
+ # does not. The key carries the pr-checkmate version, so an upgrade fetches
55
+ # afresh instead of reusing tooling meant for the previous one.
56
+ - name: Cache PR CheckMate tooling
57
+ uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
58
+ with:
59
+ path: ~/.cache/pr-checkmate
60
+ key: pr-checkmate-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
61
+ restore-keys: |
62
+ pr-checkmate-${{ runner.os }}-
63
+
64
+ # Grype keeps its own vulnerability database, and it is the single largest
65
+ # download in the whole run: 134 MB compressed, 1.9 GB unpacked, refreshed
66
+ # daily upstream. Without this step every job pays for it again. The key is
67
+ # dated rather than content-hashed, because the thing that changes is the
68
+ # upstream database, not anything in this repository — a stale entry is
69
+ # restored by the prefix and grype updates it in place.
70
+ - name: Cache Grype vulnerability database
71
+ uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
72
+ with:
73
+ path: ~/.cache/grype
74
+ key: grype-db-${{ runner.os }}-${{ github.run_id }}
75
+ restore-keys: |
76
+ grype-db-${{ runner.os }}-
77
+
78
+ # One job runs the whole registry. Splitting it per check would repeat the
79
+ # checkout and install for every one of them, and the selection of what runs
80
+ # belongs in pr-checkmate.json (`severity`), not in copied YAML.
81
+ #
82
+ # This template is the one `init` scaffolds when pr-checkmate IS a
83
+ # dependency: `npm ci` above installs it, so npx runs that copy at the
84
+ # version your lockfile pins. A repository that does not install it gets
85
+ # the container variant instead, because bare `npx` would resolve to the
86
+ # newest release and download it on every job.
87
+ - name: Run PR CheckMate
88
+ env:
89
+ # Not injected automatically: without this the run cannot authenticate,
90
+ # and the summary comment silently never reaches the PR.
91
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
92
+ run: npx pr-checkmate all
@@ -0,0 +1,2 @@
1
+ import { Check } from '../../types.js';
2
+ export declare const bannedImportsCheck: Check;
@@ -0,0 +1,70 @@
1
+ import { logger } from '../../../utils/index.js';
2
+ import { pass, skip } from '../../types.js';
3
+ import { clientFindingOptions, reportSeverityBuckets, reviewLines, } from '../findings.js';
4
+ const PREFIX = 'Banned Imports';
5
+ const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
6
+ /**
7
+ * Compile `bannedImports` into matchers that catch a banned package via an ES
8
+ * import, a CommonJS require, or its addition to a manifest dependency list.
9
+ */
10
+ function compileBans(ctx) {
11
+ const list = ctx.config.bannedImports ?? [];
12
+ return list
13
+ .filter(b => b?.name)
14
+ .map(b => {
15
+ const n = escapeRe(b.name);
16
+ const re = new RegExp(`from\\s+['"]${n}(?:/[^'"]*)?['"]|require\\(\\s*['"]${n}(?:/[^'"]*)?['"]|import\\s+['"]${n}['"]|["']${n}["']\\s*:`);
17
+ return {
18
+ message: b.message ?? `banned dependency: ${b.name}`,
19
+ re,
20
+ severity: b.severity === 'error' ? 'error' : 'warn',
21
+ };
22
+ });
23
+ }
24
+ export const bannedImportsCheck = {
25
+ name: 'Banned Imports',
26
+ phase: 'informational',
27
+ // No `requiresDiff`: a banned import is banned wherever it is, not only where
28
+ // it was just introduced (ticket 067).
29
+ applies(ctx) {
30
+ return (ctx.config.bannedImports?.length ?? 0) > 0;
31
+ },
32
+ async run(ctx) {
33
+ const bans = compileBans(ctx);
34
+ if (bans.length === 0)
35
+ return pass('no banned imports configured');
36
+ try {
37
+ const errors = {};
38
+ const warnings = {};
39
+ const reviewed = await reviewLines(ctx, ['*'], stdout => {
40
+ var _a;
41
+ for (const raw of stdout.split('\n')) {
42
+ if (!raw.startsWith('+') || raw.startsWith('+++'))
43
+ continue;
44
+ const content = raw.slice(1);
45
+ for (const ban of bans) {
46
+ if (ban.re.test(content)) {
47
+ const bucket = ban.severity === 'error' ? errors : warnings;
48
+ (bucket[_a = ban.message] ?? (bucket[_a] = [])).push(content.trim().substring(0, 100));
49
+ }
50
+ }
51
+ }
52
+ });
53
+ // An unreadable file list is not "no banned imports" (ticket 072).
54
+ if (!reviewed)
55
+ return skip('git unavailable');
56
+ // A ban configured as "error" blocks the run, regardless of phase — that
57
+ // is the default `failOn`, and the client can still relax it per repo.
58
+ return reportSeverityBuckets(errors, warnings, {
59
+ prefix: PREFIX,
60
+ errorSummary: n => `${n} banned (error)`,
61
+ warningSummary: n => `${n} banned (warn)`,
62
+ ...clientFindingOptions(ctx),
63
+ });
64
+ }
65
+ catch (err) {
66
+ logger.warn(`[Banned Imports]: ⚠️ Could not analyze diff\n${err}`);
67
+ return skip('diff unavailable');
68
+ }
69
+ },
70
+ };
@@ -0,0 +1,2 @@
1
+ import { Check } from '../../types.js';
2
+ export declare const circularDepsCheck: Check;
@@ -0,0 +1,155 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { getSourcePaths } from '../../../config/index.js';
4
+ import { execa } from '../../../utils/execa.js';
5
+ import { cleanupTempFile, logger, matchesAnyGlob, resolvePackageBin, } from '../../../utils/index.js';
6
+ import { clientToolPaths } from '../../install/reuse.js';
7
+ import { listTrackedFiles } from '../../targets.js';
8
+ import { pass, skip } from '../../types.js';
9
+ import { severityEmitter } from '../findings.js';
10
+ /**
11
+ * Cap for the analysis. dpdm builds the whole module graph, which on a large repo
12
+ * is the slowest part of a run — an uncapped analysis looks like a hung commit.
13
+ */
14
+ const DEFAULT_TIMEOUT_MS = 120000;
15
+ /**
16
+ * Ceiling for the assembled argument list. Passing every tracked source file as a
17
+ * separate argument overflows the OS argument limit (`E2BIG`) on a large repo, and
18
+ * a spawn that never starts writes no report. Past the ceiling dpdm gets globs
19
+ * instead — it expands them itself, over the same source paths.
20
+ */
21
+ const MAX_ARGV_CHARS = 100000;
22
+ /** Extensions dpdm resolves for us; also the globs used in the fallback. */
23
+ const SOURCE_GLOBS = ['*.ts', '*.tsx', '*.js', '*.jsx'];
24
+ /**
25
+ * Resolve dpdm, preferring the consumer project's own copy (so a repo pinned to a
26
+ * different major keeps its own behaviour) and falling back to the copy bundled
27
+ * with pr-checkmate — the order `lint` and `typecheck` use for eslint/tsc.
28
+ *
29
+ * Returns null instead of throwing: an unresolvable analyzer is a skip, never a
30
+ * failed PR. This check used to shell out to `npx dpdm`, which silently fetched
31
+ * dpdm from the registry on first use — and when that fetch could not happen
32
+ * (offline or locked-down CI, private registry, exit 127) nothing was analyzed.
33
+ */
34
+ function resolveDpdm(ctx) {
35
+ // No configuration of its own — dpdm reads the module graph — so the version
36
+ // check is the right question here and `clientOwnsConfig` stays off.
37
+ for (const options of [{ paths: clientToolPaths('dpdm', ctx) }, undefined]) {
38
+ try {
39
+ return resolvePackageBin('dpdm', 'lib/bin/dpdm.js', options);
40
+ }
41
+ catch {
42
+ // Try the next location; both failing is a skip, handled by the caller.
43
+ }
44
+ }
45
+ return null;
46
+ }
47
+ /**
48
+ * Build the file arguments for dpdm, falling back to globs when the explicit list
49
+ * would overflow the OS argument limit. `sourcePaths` scopes the globs the same way
50
+ * `listTrackedFiles` scopes the explicit list.
51
+ */
52
+ function toFileArgs(files, sourcePaths) {
53
+ const explicitLength = files.reduce((sum, file) => sum + file.length + 1, 0);
54
+ if (explicitLength <= MAX_ARGV_CHARS)
55
+ return files;
56
+ const roots = sourcePaths.length > 0 ? sourcePaths : ['.'];
57
+ const globs = roots.flatMap(root => SOURCE_GLOBS.map(ext => `${root.replace(/\/+$/, '')}/**/${ext}`));
58
+ logger.info(`[Circular Deps]: ${files.length} files exceed the argument limit — analyzing via globs (${globs.join(', ')})`);
59
+ return globs;
60
+ }
61
+ /** Read dpdm's report file; null when it is absent or unparseable. */
62
+ function readReport(reportPath) {
63
+ try {
64
+ return JSON.parse(fs.readFileSync(reportPath, 'utf-8'));
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ }
70
+ export const circularDepsCheck = {
71
+ name: 'Circular Deps',
72
+ phase: 'blocking',
73
+ weight: 'heavy',
74
+ applies(ctx) {
75
+ if (ctx.config.circularDeps?.enabled === false)
76
+ return false;
77
+ return ctx.languages.includes('typescript') || ctx.languages.includes('javascript');
78
+ },
79
+ async run(ctx) {
80
+ const allFiles = await listTrackedFiles(ctx, SOURCE_GLOBS, getSourcePaths(ctx.cwd));
81
+ // A cycle detector needs the WHOLE graph, so an unreadable file list is the
82
+ // one case where passing would be worst: half a graph produces confident
83
+ // nonsense, and no graph reported as `pass` says the repository is acyclic
84
+ // when nobody looked (ticket 072).
85
+ if (allFiles === null)
86
+ return skip('git unavailable');
87
+ if (allFiles.length === 0)
88
+ return pass();
89
+ // Files the client exempted (generated code, vendored bundles) are dropped
90
+ // before analysis — and again from the cycles below, since the graph can reach
91
+ // an ignored file by following imports from one that is analyzed.
92
+ const ignore = ctx.config.circularDeps?.ignore ?? [];
93
+ const files = ignore.length > 0 ? allFiles.filter(f => !matchesAnyGlob(f, ignore)) : allFiles;
94
+ if (files.length === 0)
95
+ return skip('all files ignored');
96
+ const dpdmBin = resolveDpdm(ctx);
97
+ if (!dpdmBin) {
98
+ logger.warn('[Circular Deps]: ⚠️ dpdm could not be resolved — skipping');
99
+ return skip('dpdm unavailable');
100
+ }
101
+ const timeout = ctx.config.circularDeps?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
102
+ const reportPath = path.join(ctx.cwd, '.dpdm.temp.json');
103
+ try {
104
+ // Read the cycles from dpdm's JSON report rather than its console output.
105
+ // The console shapes this check used to grep for ("Circular Dependencies:",
106
+ // "[1] a -> b") are not what dpdm 4 prints ("• Circular Dependencies",
107
+ // "1) a -> b"), so no cycle ever matched and the check passed every repo,
108
+ // including one built solely out of a cycle. `--exit-code circular:1` gives
109
+ // the same answer independently: dpdm otherwise exits 0 even when it finds
110
+ // cycles, so the exit code alone cannot tell a clean repo from a broken run.
111
+ const result = await execa(process.execPath, [
112
+ dpdmBin,
113
+ '--no-warning',
114
+ '--no-tree',
115
+ '--no-circular',
116
+ '--exit-code',
117
+ 'circular:1',
118
+ '-o',
119
+ reportPath,
120
+ ...toFileArgs(files, getSourcePaths(ctx.cwd)),
121
+ ], { cwd: ctx.cwd, reject: false, timeout });
122
+ if (result.timedOut) {
123
+ logger.warn(`[Circular Deps]: ⚠️ dpdm timed out after ${timeout}ms — skipping`);
124
+ return skip('dpdm timed out');
125
+ }
126
+ const report = readReport(reportPath);
127
+ // No report means dpdm never got far enough to write one (a tsconfig it
128
+ // cannot read, a file it cannot parse, a killed process). Skip: reporting
129
+ // that as "no cycles" hides a check that did not run, and failing on it
130
+ // blocks a PR that may have no cycle at all.
131
+ if (!report) {
132
+ const output = [result.stdout, result.stderr].filter(Boolean).join('\n').trim();
133
+ logger.warn(`[Circular Deps]: ⚠️ dpdm wrote no report (exit ${result.exitCode ?? 'killed'})${output ? `:\n${output}` : ''}`);
134
+ return skip(`dpdm failed to run (exit ${result.exitCode ?? 'killed'})`);
135
+ }
136
+ const cycles = (report.circulars ?? []).filter(cycle => ignore.length === 0 || !cycle.some(file => matchesAnyGlob(file, ignore)));
137
+ if (cycles.length === 0)
138
+ return pass();
139
+ // Advisory by default. This check reported nothing for its whole existence
140
+ // (see the note above), so switching it on turns every long-standing cycle
141
+ // in every client repo into a finding at once — barrel files alone account
142
+ // for most of them. Warning first lets a repo see its cycles before they
143
+ // gate anything; promote with `circularDeps.severity: "error"`.
144
+ const sev = severityEmitter(ctx.config.circularDeps?.severity, 'warn');
145
+ sev.log(`[Circular Deps]: ${sev.icon} ${cycles.length} circular dependency(ies):`);
146
+ cycles.slice(0, 10).forEach((cycle, i) => sev.log(` ${i + 1}) ${cycle.join(' -> ')}`));
147
+ if (cycles.length > 10)
148
+ sev.log(` ... and ${cycles.length - 10} more`);
149
+ return sev.emit(`${cycles.length} circular dependency(ies) found`);
150
+ }
151
+ finally {
152
+ cleanupTempFile(reportPath);
153
+ }
154
+ },
155
+ };
@@ -0,0 +1,43 @@
1
+ import { Check } from '../../types.js';
2
+ /** One entry of knip's JSON reporter — a file plus the issues found for it. */
3
+ interface KnipIssue {
4
+ file: string;
5
+ dependencies?: {
6
+ name: string;
7
+ }[];
8
+ unlisted?: {
9
+ name: string;
10
+ }[];
11
+ }
12
+ interface KnipReport {
13
+ issues?: KnipIssue[];
14
+ }
15
+ /**
16
+ * Compile one `dependency.ignore` entry into a pattern knip matches the way this
17
+ * config documents it — a glob over the whole dependency name.
18
+ *
19
+ * knip turns any value containing `* + \ ( | { ^ $` into an *unanchored* `RegExp`
20
+ * and compares everything else by string equality. A glob passed straight through
21
+ * would therefore silence far more than it names: `eslint-*` reads as "eslint
22
+ * followed by zero or more dashes", tested as a substring, so it also swallows
23
+ * `eslint` itself. Escaping first and anchoring the result keeps `eslint-*` matching
24
+ * only `eslint-…`, and keeps a plain name matching exactly that name.
25
+ */
26
+ export declare function toKnipIgnorePattern(entry: string): string;
27
+ /**
28
+ * Pull knip's report out of a stdout stream that may carry unrelated output.
29
+ *
30
+ * knip imports the project's own config files while analyzing (a `wdio.conf.ts`
31
+ * for its WebdriverIO plugin, say), so any top-level side effect in them —
32
+ * a dotenv banner, a `console.log` in a config module — is printed before the
33
+ * report. Slicing from the first `{` to the last `}` therefore captured that
34
+ * noise instead: a dotenvx tip ending in `{ path: '…/.env' }` made the whole
35
+ * check fail on a repo whose report was perfectly valid.
36
+ *
37
+ * The json reporter writes the report as a single line (`JSON.stringify` with no
38
+ * indentation), so the last line that parses AND carries `issues` is the report.
39
+ * Anything else on stdout is noise, whatever braces it happens to contain.
40
+ */
41
+ export declare function parseKnipReport(stdout: string): KnipReport | null;
42
+ export declare const dependencyCheck: Check;
43
+ export {};
@@ -0,0 +1,174 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { hasLocalConfig } from '../../../config/index.js';
4
+ import { execa } from '../../../utils/execa.js';
5
+ import { logger, cleanupTempFile, resolvePackageBin } from '../../../utils/index.js';
6
+ import { isNpmProject, pass, fail, warn, skip } from '../../types.js';
7
+ /**
8
+ * Config files knip discovers on its own. When a client ships one, it is the source
9
+ * of truth and pr-checkmate passes no config of its own — the same rule spellcheck
10
+ * follows for cspell.json.
11
+ *
12
+ * Mirrors knip's own `KNIP_CONFIG_LOCATIONS` exactly. Listing a name knip does not
13
+ * read (`knip.config.mjs`, say) would be worse than useless: the repo would count as
14
+ * "configures knip itself", so `dependency.ignore` would be dropped, while knip
15
+ * ignored that file too — leaving the client with warnings they had silenced.
16
+ */
17
+ const KNIP_CONFIG_FILES = [
18
+ 'knip.json',
19
+ 'knip.jsonc',
20
+ '.knip.json',
21
+ '.knip.jsonc',
22
+ 'knip.ts',
23
+ 'knip.js',
24
+ 'knip.config.ts',
25
+ 'knip.config.js',
26
+ ];
27
+ /** Regex metacharacters to neutralise before a glob is compiled. */
28
+ const REGEX_SPECIALS = /[.*+?^${}()|[\]\\]/g;
29
+ /**
30
+ * Compile one `dependency.ignore` entry into a pattern knip matches the way this
31
+ * config documents it — a glob over the whole dependency name.
32
+ *
33
+ * knip turns any value containing `* + \ ( | { ^ $` into an *unanchored* `RegExp`
34
+ * and compares everything else by string equality. A glob passed straight through
35
+ * would therefore silence far more than it names: `eslint-*` reads as "eslint
36
+ * followed by zero or more dashes", tested as a substring, so it also swallows
37
+ * `eslint` itself. Escaping first and anchoring the result keeps `eslint-*` matching
38
+ * only `eslint-…`, and keeps a plain name matching exactly that name.
39
+ */
40
+ export function toKnipIgnorePattern(entry) {
41
+ const escaped = entry.replace(REGEX_SPECIALS, '\\$&');
42
+ return `^${escaped.replace(/\\\*/g, '.*').replace(/\\\?/g, '.')}$`;
43
+ }
44
+ /** knip also reads a `knip` key from package.json. */
45
+ function hasPackageJsonConfig(cwd) {
46
+ try {
47
+ return 'knip' in JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf-8'));
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ }
53
+ /**
54
+ * Pull knip's report out of a stdout stream that may carry unrelated output.
55
+ *
56
+ * knip imports the project's own config files while analyzing (a `wdio.conf.ts`
57
+ * for its WebdriverIO plugin, say), so any top-level side effect in them —
58
+ * a dotenv banner, a `console.log` in a config module — is printed before the
59
+ * report. Slicing from the first `{` to the last `}` therefore captured that
60
+ * noise instead: a dotenvx tip ending in `{ path: '…/.env' }` made the whole
61
+ * check fail on a repo whose report was perfectly valid.
62
+ *
63
+ * The json reporter writes the report as a single line (`JSON.stringify` with no
64
+ * indentation), so the last line that parses AND carries `issues` is the report.
65
+ * Anything else on stdout is noise, whatever braces it happens to contain.
66
+ */
67
+ export function parseKnipReport(stdout) {
68
+ const lines = stdout.split('\n');
69
+ for (let i = lines.length - 1; i >= 0; i--) {
70
+ const line = lines[i].trim();
71
+ if (!line.startsWith('{'))
72
+ continue;
73
+ try {
74
+ const parsed = JSON.parse(line);
75
+ if (Array.isArray(parsed.issues))
76
+ return parsed;
77
+ }
78
+ catch {
79
+ // A noise line that merely looks like JSON — keep scanning upwards.
80
+ }
81
+ }
82
+ return null;
83
+ }
84
+ /** Collect the names reported for one issue type across every file in the report. */
85
+ function collectNames(issues, key) {
86
+ return [...new Set(issues.flatMap(issue => (issue[key] ?? []).map(entry => entry.name)))];
87
+ }
88
+ /** Files a given unlisted dependency is imported from, for the failure message. */
89
+ function filesUsing(issues, name) {
90
+ return issues
91
+ .filter(issue => (issue.unlisted ?? []).some(entry => entry.name === name))
92
+ .map(issue => issue.file);
93
+ }
94
+ export const dependencyCheck = {
95
+ name: 'Dependencies',
96
+ phase: 'blocking',
97
+ weight: 'heavy',
98
+ applies(ctx) {
99
+ if (ctx.config.dependency?.enabled === false)
100
+ return false;
101
+ return isNpmProject(ctx);
102
+ },
103
+ async run(ctx) {
104
+ // Resolve the bundled knip binary and run it via the current node — never
105
+ // shell out to `npx`, which fails (exit 127) when knip isn't on the path.
106
+ let knipBin;
107
+ try {
108
+ knipBin = resolvePackageBin('knip', 'bin/knip.js');
109
+ }
110
+ catch {
111
+ return skip('knip unavailable');
112
+ }
113
+ // Dependency names to skip, configured in pr-checkmate.json. knip takes these
114
+ // from a config file only, so they go into a temp one — but a client's own knip
115
+ // config wins outright, exactly as it does for cspell.
116
+ const ignore = ctx.config.dependency?.ignore ?? [];
117
+ const clientOwnsConfig = hasLocalConfig(KNIP_CONFIG_FILES, ctx.cwd) || hasPackageJsonConfig(ctx.cwd);
118
+ let tempConfigPath = null;
119
+ if (ignore.length > 0 && clientOwnsConfig) {
120
+ // Say so out loud: a silently ignored `ignore` list looks like a broken check.
121
+ logger.info(`[Dependencies]: ℹ️ this repo has its own knip config, so dependency.ignore (${ignore.join(', ')}) is not applied — add those names to knip's ignoreDependencies instead.`);
122
+ }
123
+ if (ignore.length > 0 && !clientOwnsConfig) {
124
+ tempConfigPath = path.join(ctx.cwd, '.knip.temp.json');
125
+ fs.writeFileSync(tempConfigPath, JSON.stringify({ ignoreDependencies: ignore.map(toKnipIgnorePattern) }, null, 2));
126
+ }
127
+ // Only unused prod dependencies and imports missing from package.json are
128
+ // reported. knip's other issue types (unused devDependencies, binaries,
129
+ // unresolved paths) are noise here: CLI tools and shell commands legitimately
130
+ // have no import to find.
131
+ const args = [
132
+ knipBin,
133
+ '--reporter',
134
+ 'json',
135
+ '--include',
136
+ 'dependencies,unlisted',
137
+ '--no-config-hints',
138
+ '--no-exit-code',
139
+ '--no-progress',
140
+ ];
141
+ if (tempConfigPath)
142
+ args.push('--config', tempConfigPath);
143
+ try {
144
+ // reject:false — knip can still exit non-zero (e.g. config hints) while
145
+ // writing a perfectly good report to stdout.
146
+ const { stdout } = await execa(process.execPath, args, {
147
+ cwd: ctx.cwd,
148
+ reject: false,
149
+ });
150
+ const result = parseKnipReport(stdout);
151
+ // No report on stdout → the tool couldn't produce a result; skip rather than
152
+ // fail the client's PR. Never fail here: a check that blocks a PR because a
153
+ // tool misbehaved reports our problem as the client's.
154
+ if (!result)
155
+ return skip('knip produced no report');
156
+ const issues = result.issues ?? [];
157
+ const unused = collectNames(issues, 'dependencies');
158
+ const missing = collectNames(issues, 'unlisted');
159
+ if (missing.length > 0) {
160
+ missing.forEach(dep => logger.error(`[Dependencies]: ❌ missing ${dep} (used in: ${filesUsing(issues, dep).join(', ')})`));
161
+ return fail(`missing: ${missing.join(', ')}`);
162
+ }
163
+ if (unused.length > 0) {
164
+ unused.forEach(dep => logger.warn(`[Dependencies]: ⚠️ unused ${dep}`));
165
+ return warn(`${unused.length} unused dependency(ies)`);
166
+ }
167
+ return pass();
168
+ }
169
+ finally {
170
+ if (tempConfigPath)
171
+ cleanupTempFile(tempConfigPath);
172
+ }
173
+ },
174
+ };
@@ -0,0 +1,22 @@
1
+ import { Check } from '../../types.js';
2
+ /**
3
+ * Dependency vulnerability scan via Anchore's `grype`. Non-blocking and ON by
4
+ * default — runs unless `grypeScan.enabled` is explicitly `false`. grype is a
5
+ * runner-dependency: it must be on the runner, and the check skips gracefully
6
+ * (not fails) when it is absent.
7
+ *
8
+ * grype resolves versions from lockfiles, so its raw output includes the entire
9
+ * transitive tree — and, because pr-checkmate installs into the consumer's
10
+ * node_modules, its own bundled dependencies too. Neither is something the
11
+ * consumer can fix. We therefore report ONLY vulnerabilities in DIRECT
12
+ * dependencies (those declared in the project's manifests, see
13
+ * `collectDirectDeps`): the set the maintainer actually controls. Findings whose
14
+ * ecosystem has no manifest we can parse are suppressed too, and the count of
15
+ * everything dropped is logged so nothing is hidden silently.
16
+ *
17
+ * The scan is confined to the project's own files: `ignoreDirs` is passed to grype
18
+ * as `--exclude`, and a timeout backstops the run. Both matter — cataloguing an
19
+ * installed `node_modules` is minutes of work whose every finding this check then
20
+ * throws away as third-party.
21
+ */
22
+ export declare const grypeScanCheck: Check;