@opensip-cli/checks-typescript 0.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 (404) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +31 -0
  4. package/dist/__tests__/all-checks-execute.test.d.ts +12 -0
  5. package/dist/__tests__/all-checks-execute.test.d.ts.map +1 -0
  6. package/dist/__tests__/all-checks-execute.test.js +846 -0
  7. package/dist/__tests__/all-checks-execute.test.js.map +1 -0
  8. package/dist/__tests__/behavior-fixtures-2.test.d.ts +9 -0
  9. package/dist/__tests__/behavior-fixtures-2.test.d.ts.map +1 -0
  10. package/dist/__tests__/behavior-fixtures-2.test.js +625 -0
  11. package/dist/__tests__/behavior-fixtures-2.test.js.map +1 -0
  12. package/dist/__tests__/behavior-fixtures-3.test.d.ts +7 -0
  13. package/dist/__tests__/behavior-fixtures-3.test.d.ts.map +1 -0
  14. package/dist/__tests__/behavior-fixtures-3.test.js +658 -0
  15. package/dist/__tests__/behavior-fixtures-3.test.js.map +1 -0
  16. package/dist/__tests__/behavior-fixtures-4.test.d.ts +8 -0
  17. package/dist/__tests__/behavior-fixtures-4.test.d.ts.map +1 -0
  18. package/dist/__tests__/behavior-fixtures-4.test.js +590 -0
  19. package/dist/__tests__/behavior-fixtures-4.test.js.map +1 -0
  20. package/dist/__tests__/behavior-fixtures-5.test.d.ts +7 -0
  21. package/dist/__tests__/behavior-fixtures-5.test.d.ts.map +1 -0
  22. package/dist/__tests__/behavior-fixtures-5.test.js +548 -0
  23. package/dist/__tests__/behavior-fixtures-5.test.js.map +1 -0
  24. package/dist/__tests__/behavior-fixtures-6.test.d.ts +18 -0
  25. package/dist/__tests__/behavior-fixtures-6.test.d.ts.map +1 -0
  26. package/dist/__tests__/behavior-fixtures-6.test.js +1700 -0
  27. package/dist/__tests__/behavior-fixtures-6.test.js.map +1 -0
  28. package/dist/__tests__/behavior-fixtures.test.d.ts +10 -0
  29. package/dist/__tests__/behavior-fixtures.test.d.ts.map +1 -0
  30. package/dist/__tests__/behavior-fixtures.test.js +812 -0
  31. package/dist/__tests__/behavior-fixtures.test.js.map +1 -0
  32. package/dist/__tests__/branch-fixtures-2.test.d.ts +6 -0
  33. package/dist/__tests__/branch-fixtures-2.test.d.ts.map +1 -0
  34. package/dist/__tests__/branch-fixtures-2.test.js +1369 -0
  35. package/dist/__tests__/branch-fixtures-2.test.js.map +1 -0
  36. package/dist/__tests__/branch-fixtures-3.test.d.ts +7 -0
  37. package/dist/__tests__/branch-fixtures-3.test.d.ts.map +1 -0
  38. package/dist/__tests__/branch-fixtures-3.test.js +877 -0
  39. package/dist/__tests__/branch-fixtures-3.test.js.map +1 -0
  40. package/dist/__tests__/branch-fixtures.test.d.ts +6 -0
  41. package/dist/__tests__/branch-fixtures.test.d.ts.map +1 -0
  42. package/dist/__tests__/branch-fixtures.test.js +1072 -0
  43. package/dist/__tests__/branch-fixtures.test.js.map +1 -0
  44. package/dist/__tests__/checks.test.d.ts +2 -0
  45. package/dist/__tests__/checks.test.d.ts.map +1 -0
  46. package/dist/__tests__/checks.test.js +39 -0
  47. package/dist/__tests__/checks.test.js.map +1 -0
  48. package/dist/__tests__/fixture-coverage.allowlist.d.ts +19 -0
  49. package/dist/__tests__/fixture-coverage.allowlist.d.ts.map +1 -0
  50. package/dist/__tests__/fixture-coverage.allowlist.js +27 -0
  51. package/dist/__tests__/fixture-coverage.allowlist.js.map +1 -0
  52. package/dist/__tests__/fixture-coverage.test.d.ts +13 -0
  53. package/dist/__tests__/fixture-coverage.test.d.ts.map +1 -0
  54. package/dist/__tests__/fixture-coverage.test.js +57 -0
  55. package/dist/__tests__/fixture-coverage.test.js.map +1 -0
  56. package/dist/__tests__/no-bootstrap-tool-import.test.d.ts +2 -0
  57. package/dist/__tests__/no-bootstrap-tool-import.test.d.ts.map +1 -0
  58. package/dist/__tests__/no-bootstrap-tool-import.test.js +75 -0
  59. package/dist/__tests__/no-bootstrap-tool-import.test.js.map +1 -0
  60. package/dist/__tests__/phantom-dependency-detection.test.d.ts +12 -0
  61. package/dist/__tests__/phantom-dependency-detection.test.d.ts.map +1 -0
  62. package/dist/__tests__/phantom-dependency-detection.test.js +112 -0
  63. package/dist/__tests__/phantom-dependency-detection.test.js.map +1 -0
  64. package/dist/__tests__/typescript-frontend.test.d.ts +8 -0
  65. package/dist/__tests__/typescript-frontend.test.d.ts.map +1 -0
  66. package/dist/__tests__/typescript-frontend.test.js +57 -0
  67. package/dist/__tests__/typescript-frontend.test.js.map +1 -0
  68. package/dist/checks/architecture/circular-import-detection.d.ts +14 -0
  69. package/dist/checks/architecture/circular-import-detection.d.ts.map +1 -0
  70. package/dist/checks/architecture/circular-import-detection.js +55 -0
  71. package/dist/checks/architecture/circular-import-detection.js.map +1 -0
  72. package/dist/checks/architecture/contracts-schema-consistency.d.ts +11 -0
  73. package/dist/checks/architecture/contracts-schema-consistency.d.ts.map +1 -0
  74. package/dist/checks/architecture/contracts-schema-consistency.js +75 -0
  75. package/dist/checks/architecture/contracts-schema-consistency.js.map +1 -0
  76. package/dist/checks/architecture/drizzle-orm-migration-guardrails.d.ts +12 -0
  77. package/dist/checks/architecture/drizzle-orm-migration-guardrails.d.ts.map +1 -0
  78. package/dist/checks/architecture/drizzle-orm-migration-guardrails.js +92 -0
  79. package/dist/checks/architecture/drizzle-orm-migration-guardrails.js.map +1 -0
  80. package/dist/checks/architecture/index.d.ts +10 -0
  81. package/dist/checks/architecture/index.d.ts.map +1 -0
  82. package/dist/checks/architecture/index.js +10 -0
  83. package/dist/checks/architecture/index.js.map +1 -0
  84. package/dist/checks/architecture/missing-type-exports.d.ts +13 -0
  85. package/dist/checks/architecture/missing-type-exports.d.ts.map +1 -0
  86. package/dist/checks/architecture/missing-type-exports.js +245 -0
  87. package/dist/checks/architecture/missing-type-exports.js.map +1 -0
  88. package/dist/checks/architecture/module-coupling-fan-out.d.ts +20 -0
  89. package/dist/checks/architecture/module-coupling-fan-out.d.ts.map +1 -0
  90. package/dist/checks/architecture/module-coupling-fan-out.js +120 -0
  91. package/dist/checks/architecture/module-coupling-fan-out.js.map +1 -0
  92. package/dist/checks/architecture/no-bootstrap-tool-import.d.ts +38 -0
  93. package/dist/checks/architecture/no-bootstrap-tool-import.d.ts.map +1 -0
  94. package/dist/checks/architecture/no-bootstrap-tool-import.js +95 -0
  95. package/dist/checks/architecture/no-bootstrap-tool-import.js.map +1 -0
  96. package/dist/checks/architecture/package-json-exports-field.d.ts +10 -0
  97. package/dist/checks/architecture/package-json-exports-field.d.ts.map +1 -0
  98. package/dist/checks/architecture/package-json-exports-field.js +56 -0
  99. package/dist/checks/architecture/package-json-exports-field.js.map +1 -0
  100. package/dist/checks/architecture/phantom-dependency-detection.d.ts +22 -0
  101. package/dist/checks/architecture/phantom-dependency-detection.d.ts.map +1 -0
  102. package/dist/checks/architecture/phantom-dependency-detection.js +330 -0
  103. package/dist/checks/architecture/phantom-dependency-detection.js.map +1 -0
  104. package/dist/checks/architecture/tsconfig-extends-validation.d.ts +10 -0
  105. package/dist/checks/architecture/tsconfig-extends-validation.d.ts.map +1 -0
  106. package/dist/checks/architecture/tsconfig-extends-validation.js +78 -0
  107. package/dist/checks/architecture/tsconfig-extends-validation.js.map +1 -0
  108. package/dist/checks/index.d.ts +6 -0
  109. package/dist/checks/index.d.ts.map +1 -0
  110. package/dist/checks/index.js +6 -0
  111. package/dist/checks/index.js.map +1 -0
  112. package/dist/checks/quality/api/api-contract-validation.d.ts +15 -0
  113. package/dist/checks/quality/api/api-contract-validation.d.ts.map +1 -0
  114. package/dist/checks/quality/api/api-contract-validation.js +316 -0
  115. package/dist/checks/quality/api/api-contract-validation.js.map +1 -0
  116. package/dist/checks/quality/api/api-response-validation.d.ts +14 -0
  117. package/dist/checks/quality/api/api-response-validation.d.ts.map +1 -0
  118. package/dist/checks/quality/api/api-response-validation.js +209 -0
  119. package/dist/checks/quality/api/api-response-validation.js.map +1 -0
  120. package/dist/checks/quality/api/fastify-route-validation.d.ts +14 -0
  121. package/dist/checks/quality/api/fastify-route-validation.d.ts.map +1 -0
  122. package/dist/checks/quality/api/fastify-route-validation.js +298 -0
  123. package/dist/checks/quality/api/fastify-route-validation.js.map +1 -0
  124. package/dist/checks/quality/api/fastify-schema-coverage.d.ts +11 -0
  125. package/dist/checks/quality/api/fastify-schema-coverage.d.ts.map +1 -0
  126. package/dist/checks/quality/api/fastify-schema-coverage.js +261 -0
  127. package/dist/checks/quality/api/fastify-schema-coverage.js.map +1 -0
  128. package/dist/checks/quality/api/index.d.ts +5 -0
  129. package/dist/checks/quality/api/index.d.ts.map +1 -0
  130. package/dist/checks/quality/api/index.js +5 -0
  131. package/dist/checks/quality/api/index.js.map +1 -0
  132. package/dist/checks/quality/code-structure/duplicate-utility-functions.d.ts +32 -0
  133. package/dist/checks/quality/code-structure/duplicate-utility-functions.d.ts.map +1 -0
  134. package/dist/checks/quality/code-structure/duplicate-utility-functions.js +451 -0
  135. package/dist/checks/quality/code-structure/duplicate-utility-functions.js.map +1 -0
  136. package/dist/checks/quality/code-structure/index.d.ts +3 -0
  137. package/dist/checks/quality/code-structure/index.d.ts.map +1 -0
  138. package/dist/checks/quality/code-structure/index.js +3 -0
  139. package/dist/checks/quality/code-structure/index.js.map +1 -0
  140. package/dist/checks/quality/code-structure/no-any-types.d.ts +13 -0
  141. package/dist/checks/quality/code-structure/no-any-types.d.ts.map +1 -0
  142. package/dist/checks/quality/code-structure/no-any-types.js +116 -0
  143. package/dist/checks/quality/code-structure/no-any-types.js.map +1 -0
  144. package/dist/checks/quality/data-integrity/__tests__/null-safety-fp.test.d.ts +15 -0
  145. package/dist/checks/quality/data-integrity/__tests__/null-safety-fp.test.d.ts.map +1 -0
  146. package/dist/checks/quality/data-integrity/__tests__/null-safety-fp.test.js +51 -0
  147. package/dist/checks/quality/data-integrity/__tests__/null-safety-fp.test.js.map +1 -0
  148. package/dist/checks/quality/data-integrity/array-validation.d.ts +16 -0
  149. package/dist/checks/quality/data-integrity/array-validation.d.ts.map +1 -0
  150. package/dist/checks/quality/data-integrity/array-validation.js +508 -0
  151. package/dist/checks/quality/data-integrity/array-validation.js.map +1 -0
  152. package/dist/checks/quality/data-integrity/database-index-coverage.d.ts +14 -0
  153. package/dist/checks/quality/data-integrity/database-index-coverage.d.ts.map +1 -0
  154. package/dist/checks/quality/data-integrity/database-index-coverage.js +235 -0
  155. package/dist/checks/quality/data-integrity/database-index-coverage.js.map +1 -0
  156. package/dist/checks/quality/data-integrity/database-schema-validation.d.ts +16 -0
  157. package/dist/checks/quality/data-integrity/database-schema-validation.d.ts.map +1 -0
  158. package/dist/checks/quality/data-integrity/database-schema-validation.js +328 -0
  159. package/dist/checks/quality/data-integrity/database-schema-validation.js.map +1 -0
  160. package/dist/checks/quality/data-integrity/in-memory-repository-detection.d.ts +14 -0
  161. package/dist/checks/quality/data-integrity/in-memory-repository-detection.d.ts.map +1 -0
  162. package/dist/checks/quality/data-integrity/in-memory-repository-detection.js +157 -0
  163. package/dist/checks/quality/data-integrity/in-memory-repository-detection.js.map +1 -0
  164. package/dist/checks/quality/data-integrity/index.d.ts +8 -0
  165. package/dist/checks/quality/data-integrity/index.d.ts.map +1 -0
  166. package/dist/checks/quality/data-integrity/index.js +8 -0
  167. package/dist/checks/quality/data-integrity/index.js.map +1 -0
  168. package/dist/checks/quality/data-integrity/missing-input-validation.d.ts +12 -0
  169. package/dist/checks/quality/data-integrity/missing-input-validation.d.ts.map +1 -0
  170. package/dist/checks/quality/data-integrity/missing-input-validation.js +180 -0
  171. package/dist/checks/quality/data-integrity/missing-input-validation.js.map +1 -0
  172. package/dist/checks/quality/data-integrity/null-safety.d.ts +33 -0
  173. package/dist/checks/quality/data-integrity/null-safety.d.ts.map +1 -0
  174. package/dist/checks/quality/data-integrity/null-safety.js +766 -0
  175. package/dist/checks/quality/data-integrity/null-safety.js.map +1 -0
  176. package/dist/checks/quality/data-integrity/numeric-validation.d.ts +12 -0
  177. package/dist/checks/quality/data-integrity/numeric-validation.d.ts.map +1 -0
  178. package/dist/checks/quality/data-integrity/numeric-validation.js +409 -0
  179. package/dist/checks/quality/data-integrity/numeric-validation.js.map +1 -0
  180. package/dist/checks/quality/frontend/a11y-form-labels.d.ts +14 -0
  181. package/dist/checks/quality/frontend/a11y-form-labels.d.ts.map +1 -0
  182. package/dist/checks/quality/frontend/a11y-form-labels.js +93 -0
  183. package/dist/checks/quality/frontend/a11y-form-labels.js.map +1 -0
  184. package/dist/checks/quality/frontend/a11y-semantic-html.d.ts +14 -0
  185. package/dist/checks/quality/frontend/a11y-semantic-html.d.ts.map +1 -0
  186. package/dist/checks/quality/frontend/a11y-semantic-html.js +88 -0
  187. package/dist/checks/quality/frontend/a11y-semantic-html.js.map +1 -0
  188. package/dist/checks/quality/frontend/index.d.ts +4 -0
  189. package/dist/checks/quality/frontend/index.d.ts.map +1 -0
  190. package/dist/checks/quality/frontend/index.js +4 -0
  191. package/dist/checks/quality/frontend/index.js.map +1 -0
  192. package/dist/checks/quality/frontend/test-only-frontend-modules.d.ts +13 -0
  193. package/dist/checks/quality/frontend/test-only-frontend-modules.d.ts.map +1 -0
  194. package/dist/checks/quality/frontend/test-only-frontend-modules.js +159 -0
  195. package/dist/checks/quality/frontend/test-only-frontend-modules.js.map +1 -0
  196. package/dist/checks/quality/incomplete-regex-escaping.d.ts +13 -0
  197. package/dist/checks/quality/incomplete-regex-escaping.d.ts.map +1 -0
  198. package/dist/checks/quality/incomplete-regex-escaping.js +207 -0
  199. package/dist/checks/quality/incomplete-regex-escaping.js.map +1 -0
  200. package/dist/checks/quality/index.d.ts +11 -0
  201. package/dist/checks/quality/index.d.ts.map +1 -0
  202. package/dist/checks/quality/index.js +11 -0
  203. package/dist/checks/quality/index.js.map +1 -0
  204. package/dist/checks/quality/linting/index.d.ts +2 -0
  205. package/dist/checks/quality/linting/index.d.ts.map +1 -0
  206. package/dist/checks/quality/linting/index.js +2 -0
  207. package/dist/checks/quality/linting/index.js.map +1 -0
  208. package/dist/checks/quality/linting/typescript-frontend.d.ts +25 -0
  209. package/dist/checks/quality/linting/typescript-frontend.d.ts.map +1 -0
  210. package/dist/checks/quality/linting/typescript-frontend.js +159 -0
  211. package/dist/checks/quality/linting/typescript-frontend.js.map +1 -0
  212. package/dist/checks/quality/observability/index.d.ts +5 -0
  213. package/dist/checks/quality/observability/index.d.ts.map +1 -0
  214. package/dist/checks/quality/observability/index.js +5 -0
  215. package/dist/checks/quality/observability/index.js.map +1 -0
  216. package/dist/checks/quality/observability/logger-event-name-format.d.ts +12 -0
  217. package/dist/checks/quality/observability/logger-event-name-format.d.ts.map +1 -0
  218. package/dist/checks/quality/observability/logger-event-name-format.js +124 -0
  219. package/dist/checks/quality/observability/logger-event-name-format.js.map +1 -0
  220. package/dist/checks/quality/observability/no-hardcoded-correlation-id.d.ts +5 -0
  221. package/dist/checks/quality/observability/no-hardcoded-correlation-id.d.ts.map +1 -0
  222. package/dist/checks/quality/observability/no-hardcoded-correlation-id.js +77 -0
  223. package/dist/checks/quality/observability/no-hardcoded-correlation-id.js.map +1 -0
  224. package/dist/checks/quality/observability/observability-coverage/__tests__/analyzer.test.d.ts +11 -0
  225. package/dist/checks/quality/observability/observability-coverage/__tests__/analyzer.test.d.ts.map +1 -0
  226. package/dist/checks/quality/observability/observability-coverage/__tests__/analyzer.test.js +107 -0
  227. package/dist/checks/quality/observability/observability-coverage/__tests__/analyzer.test.js.map +1 -0
  228. package/dist/checks/quality/observability/observability-coverage/__tests__/logger-detector.test.d.ts +12 -0
  229. package/dist/checks/quality/observability/observability-coverage/__tests__/logger-detector.test.d.ts.map +1 -0
  230. package/dist/checks/quality/observability/observability-coverage/__tests__/logger-detector.test.js +94 -0
  231. package/dist/checks/quality/observability/observability-coverage/__tests__/logger-detector.test.js.map +1 -0
  232. package/dist/checks/quality/observability/observability-coverage/analyzer.d.ts +13 -0
  233. package/dist/checks/quality/observability/observability-coverage/analyzer.d.ts.map +1 -0
  234. package/dist/checks/quality/observability/observability-coverage/analyzer.js +117 -0
  235. package/dist/checks/quality/observability/observability-coverage/analyzer.js.map +1 -0
  236. package/dist/checks/quality/observability/observability-coverage/index.d.ts +4 -0
  237. package/dist/checks/quality/observability/observability-coverage/index.d.ts.map +1 -0
  238. package/dist/checks/quality/observability/observability-coverage/index.js +4 -0
  239. package/dist/checks/quality/observability/observability-coverage/index.js.map +1 -0
  240. package/dist/checks/quality/observability/observability-coverage/logger-detector.d.ts +29 -0
  241. package/dist/checks/quality/observability/observability-coverage/logger-detector.d.ts.map +1 -0
  242. package/dist/checks/quality/observability/observability-coverage/logger-detector.js +111 -0
  243. package/dist/checks/quality/observability/observability-coverage/logger-detector.js.map +1 -0
  244. package/dist/checks/quality/observability/observability-coverage/types.d.ts +64 -0
  245. package/dist/checks/quality/observability/observability-coverage/types.d.ts.map +1 -0
  246. package/dist/checks/quality/observability/observability-coverage/types.js +6 -0
  247. package/dist/checks/quality/observability/observability-coverage/types.js.map +1 -0
  248. package/dist/checks/quality/observability/pii-exposure-in-logs.d.ts +22 -0
  249. package/dist/checks/quality/observability/pii-exposure-in-logs.d.ts.map +1 -0
  250. package/dist/checks/quality/observability/pii-exposure-in-logs.js +212 -0
  251. package/dist/checks/quality/observability/pii-exposure-in-logs.js.map +1 -0
  252. package/dist/checks/quality/observability/pii-exposure-in-logs.test.d.ts +11 -0
  253. package/dist/checks/quality/observability/pii-exposure-in-logs.test.d.ts.map +1 -0
  254. package/dist/checks/quality/observability/pii-exposure-in-logs.test.js +46 -0
  255. package/dist/checks/quality/observability/pii-exposure-in-logs.test.js.map +1 -0
  256. package/dist/checks/quality/patterns/__tests__/toctou-fp.test.d.ts +14 -0
  257. package/dist/checks/quality/patterns/__tests__/toctou-fp.test.d.ts.map +1 -0
  258. package/dist/checks/quality/patterns/__tests__/toctou-fp.test.js +61 -0
  259. package/dist/checks/quality/patterns/__tests__/toctou-fp.test.js.map +1 -0
  260. package/dist/checks/quality/patterns/async-waterfall-detection.d.ts +26 -0
  261. package/dist/checks/quality/patterns/async-waterfall-detection.d.ts.map +1 -0
  262. package/dist/checks/quality/patterns/async-waterfall-detection.js +410 -0
  263. package/dist/checks/quality/patterns/async-waterfall-detection.js.map +1 -0
  264. package/dist/checks/quality/patterns/dispose-pattern-completeness.d.ts +13 -0
  265. package/dist/checks/quality/patterns/dispose-pattern-completeness.d.ts.map +1 -0
  266. package/dist/checks/quality/patterns/dispose-pattern-completeness.js +220 -0
  267. package/dist/checks/quality/patterns/dispose-pattern-completeness.js.map +1 -0
  268. package/dist/checks/quality/patterns/error-handling-quality.d.ts +17 -0
  269. package/dist/checks/quality/patterns/error-handling-quality.d.ts.map +1 -0
  270. package/dist/checks/quality/patterns/error-handling-quality.js +335 -0
  271. package/dist/checks/quality/patterns/error-handling-quality.js.map +1 -0
  272. package/dist/checks/quality/patterns/index.d.ts +10 -0
  273. package/dist/checks/quality/patterns/index.d.ts.map +1 -0
  274. package/dist/checks/quality/patterns/index.js +10 -0
  275. package/dist/checks/quality/patterns/index.js.map +1 -0
  276. package/dist/checks/quality/patterns/lifecycle-cleanup-enforcement.d.ts +16 -0
  277. package/dist/checks/quality/patterns/lifecycle-cleanup-enforcement.d.ts.map +1 -0
  278. package/dist/checks/quality/patterns/lifecycle-cleanup-enforcement.js +205 -0
  279. package/dist/checks/quality/patterns/lifecycle-cleanup-enforcement.js.map +1 -0
  280. package/dist/checks/quality/patterns/result-pattern-consistency.d.ts +16 -0
  281. package/dist/checks/quality/patterns/result-pattern-consistency.d.ts.map +1 -0
  282. package/dist/checks/quality/patterns/result-pattern-consistency.js +328 -0
  283. package/dist/checks/quality/patterns/result-pattern-consistency.js.map +1 -0
  284. package/dist/checks/quality/patterns/silent-early-returns.d.ts +23 -0
  285. package/dist/checks/quality/patterns/silent-early-returns.d.ts.map +1 -0
  286. package/dist/checks/quality/patterns/silent-early-returns.js +266 -0
  287. package/dist/checks/quality/patterns/silent-early-returns.js.map +1 -0
  288. package/dist/checks/quality/patterns/stream-buffer-size-limits.d.ts +13 -0
  289. package/dist/checks/quality/patterns/stream-buffer-size-limits.d.ts.map +1 -0
  290. package/dist/checks/quality/patterns/stream-buffer-size-limits.js +163 -0
  291. package/dist/checks/quality/patterns/stream-buffer-size-limits.js.map +1 -0
  292. package/dist/checks/quality/patterns/throws-documentation.d.ts +23 -0
  293. package/dist/checks/quality/patterns/throws-documentation.d.ts.map +1 -0
  294. package/dist/checks/quality/patterns/throws-documentation.js +519 -0
  295. package/dist/checks/quality/patterns/throws-documentation.js.map +1 -0
  296. package/dist/checks/quality/patterns/toctou-race-condition.d.ts +48 -0
  297. package/dist/checks/quality/patterns/toctou-race-condition.d.ts.map +1 -0
  298. package/dist/checks/quality/patterns/toctou-race-condition.js +639 -0
  299. package/dist/checks/quality/patterns/toctou-race-condition.js.map +1 -0
  300. package/dist/checks/quality/stubbed-implementation-detection.d.ts +24 -0
  301. package/dist/checks/quality/stubbed-implementation-detection.d.ts.map +1 -0
  302. package/dist/checks/quality/stubbed-implementation-detection.js +355 -0
  303. package/dist/checks/quality/stubbed-implementation-detection.js.map +1 -0
  304. package/dist/checks/quality/unused-config-options.d.ts +12 -0
  305. package/dist/checks/quality/unused-config-options.d.ts.map +1 -0
  306. package/dist/checks/quality/unused-config-options.js +245 -0
  307. package/dist/checks/quality/unused-config-options.js.map +1 -0
  308. package/dist/checks/resilience/__tests__/callback-invocation-safe.test.d.ts +2 -0
  309. package/dist/checks/resilience/__tests__/callback-invocation-safe.test.d.ts.map +1 -0
  310. package/dist/checks/resilience/__tests__/callback-invocation-safe.test.js +79 -0
  311. package/dist/checks/resilience/__tests__/callback-invocation-safe.test.js.map +1 -0
  312. package/dist/checks/resilience/__tests__/context-leakage-fp.test.d.ts +12 -0
  313. package/dist/checks/resilience/__tests__/context-leakage-fp.test.d.ts.map +1 -0
  314. package/dist/checks/resilience/__tests__/context-leakage-fp.test.js +34 -0
  315. package/dist/checks/resilience/__tests__/context-leakage-fp.test.js.map +1 -0
  316. package/dist/checks/resilience/__tests__/context-mutation.test.d.ts +11 -0
  317. package/dist/checks/resilience/__tests__/context-mutation.test.d.ts.map +1 -0
  318. package/dist/checks/resilience/__tests__/context-mutation.test.js +54 -0
  319. package/dist/checks/resilience/__tests__/context-mutation.test.js.map +1 -0
  320. package/dist/checks/resilience/callback-invocation-safe.d.ts +34 -0
  321. package/dist/checks/resilience/callback-invocation-safe.d.ts.map +1 -0
  322. package/dist/checks/resilience/callback-invocation-safe.js +247 -0
  323. package/dist/checks/resilience/callback-invocation-safe.js.map +1 -0
  324. package/dist/checks/resilience/context-leakage.d.ts +25 -0
  325. package/dist/checks/resilience/context-leakage.d.ts.map +1 -0
  326. package/dist/checks/resilience/context-leakage.js +435 -0
  327. package/dist/checks/resilience/context-leakage.js.map +1 -0
  328. package/dist/checks/resilience/context-mutation.d.ts +21 -0
  329. package/dist/checks/resilience/context-mutation.d.ts.map +1 -0
  330. package/dist/checks/resilience/context-mutation.js +368 -0
  331. package/dist/checks/resilience/context-mutation.js.map +1 -0
  332. package/dist/checks/resilience/detached-promises.d.ts +40 -0
  333. package/dist/checks/resilience/detached-promises.d.ts.map +1 -0
  334. package/dist/checks/resilience/detached-promises.js +646 -0
  335. package/dist/checks/resilience/detached-promises.js.map +1 -0
  336. package/dist/checks/resilience/index.d.ts +7 -0
  337. package/dist/checks/resilience/index.d.ts.map +1 -0
  338. package/dist/checks/resilience/index.js +7 -0
  339. package/dist/checks/resilience/index.js.map +1 -0
  340. package/dist/checks/resilience/no-raw-fetch.d.ts +11 -0
  341. package/dist/checks/resilience/no-raw-fetch.d.ts.map +1 -0
  342. package/dist/checks/resilience/no-raw-fetch.js +110 -0
  343. package/dist/checks/resilience/no-raw-fetch.js.map +1 -0
  344. package/dist/checks/resilience/no-unbounded-concurrency.d.ts +11 -0
  345. package/dist/checks/resilience/no-unbounded-concurrency.d.ts.map +1 -0
  346. package/dist/checks/resilience/no-unbounded-concurrency.js +117 -0
  347. package/dist/checks/resilience/no-unbounded-concurrency.js.map +1 -0
  348. package/dist/checks/security/__tests__/sql-injection.test.d.ts +17 -0
  349. package/dist/checks/security/__tests__/sql-injection.test.d.ts.map +1 -0
  350. package/dist/checks/security/__tests__/sql-injection.test.js +97 -0
  351. package/dist/checks/security/__tests__/sql-injection.test.js.map +1 -0
  352. package/dist/checks/security/index.d.ts +4 -0
  353. package/dist/checks/security/index.d.ts.map +1 -0
  354. package/dist/checks/security/index.js +4 -0
  355. package/dist/checks/security/index.js.map +1 -0
  356. package/dist/checks/security/input-sanitization.d.ts +20 -0
  357. package/dist/checks/security/input-sanitization.d.ts.map +1 -0
  358. package/dist/checks/security/input-sanitization.js +255 -0
  359. package/dist/checks/security/input-sanitization.js.map +1 -0
  360. package/dist/checks/security/sql-injection.d.ts +24 -0
  361. package/dist/checks/security/sql-injection.d.ts.map +1 -0
  362. package/dist/checks/security/sql-injection.js +330 -0
  363. package/dist/checks/security/sql-injection.js.map +1 -0
  364. package/dist/checks/security/unsafe-secret-comparison.d.ts +17 -0
  365. package/dist/checks/security/unsafe-secret-comparison.d.ts.map +1 -0
  366. package/dist/checks/security/unsafe-secret-comparison.js +227 -0
  367. package/dist/checks/security/unsafe-secret-comparison.js.map +1 -0
  368. package/dist/checks/testing/index.d.ts +2 -0
  369. package/dist/checks/testing/index.d.ts.map +1 -0
  370. package/dist/checks/testing/index.js +2 -0
  371. package/dist/checks/testing/index.js.map +1 -0
  372. package/dist/checks/testing/mock-implementations-in-production.d.ts +12 -0
  373. package/dist/checks/testing/mock-implementations-in-production.d.ts.map +1 -0
  374. package/dist/checks/testing/mock-implementations-in-production.js +211 -0
  375. package/dist/checks/testing/mock-implementations-in-production.js.map +1 -0
  376. package/dist/display/architecture.d.ts +9 -0
  377. package/dist/display/architecture.d.ts.map +1 -0
  378. package/dist/display/architecture.js +18 -0
  379. package/dist/display/architecture.js.map +1 -0
  380. package/dist/display/index.d.ts +20 -0
  381. package/dist/display/index.d.ts.map +1 -0
  382. package/dist/display/index.js +30 -0
  383. package/dist/display/index.js.map +1 -0
  384. package/dist/display/quality.d.ts +7 -0
  385. package/dist/display/quality.d.ts.map +1 -0
  386. package/dist/display/quality.js +39 -0
  387. package/dist/display/quality.js.map +1 -0
  388. package/dist/display/resilience.d.ts +7 -0
  389. package/dist/display/resilience.d.ts.map +1 -0
  390. package/dist/display/resilience.js +13 -0
  391. package/dist/display/resilience.js.map +1 -0
  392. package/dist/display/security-testing.d.ts +9 -0
  393. package/dist/display/security-testing.d.ts.map +1 -0
  394. package/dist/display/security-testing.js +14 -0
  395. package/dist/display/security-testing.js.map +1 -0
  396. package/dist/display/types.d.ts +6 -0
  397. package/dist/display/types.d.ts.map +1 -0
  398. package/dist/display/types.js +6 -0
  399. package/dist/display/types.js.map +1 -0
  400. package/dist/index.d.ts +19 -0
  401. package/dist/index.d.ts.map +1 -0
  402. package/dist/index.js +21 -0
  403. package/dist/index.js.map +1 -0
  404. package/package.json +55 -0
@@ -0,0 +1,316 @@
1
+ // @fitness-ignore-file correlation-id-coverage -- Fitness check implementation, not an API handler
2
+ // @fitness-ignore-file duplicate-utility-functions -- Check-specific helpers (getFunctionName, isHandlerFunction) use check-local types; extracting would couple independent checks
3
+ /**
4
+ * @fileoverview API Contract Validation Check
5
+ *
6
+ * Ensures API handlers have proper validation, typed responses, and error handling.
7
+ * Validates that request/response contracts are enforced through types and schemas.
8
+ */
9
+ import { defineCheck, isAPIFile } from '@opensip-cli/fitness';
10
+ import { getSharedSourceFile } from '@opensip-cli/lang-typescript';
11
+ import * as ts from 'typescript';
12
+ /**
13
+ * Validation detection patterns
14
+ */
15
+ const VALIDATION_METHOD_NAMES = new Set([
16
+ 'parse',
17
+ 'safeParse',
18
+ 'validate',
19
+ 'validateRequest',
20
+ 'validateBody',
21
+ 'validateParams',
22
+ 'validateQuery',
23
+ ]);
24
+ /**
25
+ * Handler name patterns
26
+ */
27
+ const HANDLER_NAME_PATTERNS = [/handler$/i, /^handle[A-Z]/, /^process[A-Z]/];
28
+ /**
29
+ * Names that match HANDLER_NAME_PATTERNS but are themselves error
30
+ * translators / classifiers — they're called from inside a catch block,
31
+ * so requiring try-catch around their body is error-handling-inception.
32
+ * Match: handleXxxError, handleStoreError, processError.
33
+ */
34
+ const ERROR_HANDLER_NAME_PATTERNS = [/^handle[A-Z].*Error$/, /^process[A-Z].*Error$/];
35
+ /**
36
+ * Get function name from node
37
+ * @returns {string} The function name or '<anonymous>' if not found
38
+ */
39
+ function getFunctionName(node) {
40
+ if (ts.isFunctionDeclaration(node) && node.name) {
41
+ return node.name.text;
42
+ }
43
+ if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) {
44
+ return node.name.text;
45
+ }
46
+ // Combined condition for arrow function with variable declaration
47
+ if (ts.isArrowFunction(node) &&
48
+ ts.isVariableDeclaration(node.parent) &&
49
+ ts.isIdentifier(node.parent.name)) {
50
+ return node.parent.name.text;
51
+ }
52
+ return '<anonymous>';
53
+ }
54
+ /**
55
+ * Check if function has Express handler signature
56
+ * @returns {boolean} True if the function has Express handler signature (req, res)
57
+ */
58
+ function getParamIdentifierName(p) {
59
+ /* v8 ignore next -- defensive AST/type guard */
60
+ return p && ts.isIdentifier(p.name) ? p.name.text : '';
61
+ }
62
+ function hasExpressHandlerSignature(node) {
63
+ const params = node.parameters;
64
+ if (params.length < 2)
65
+ return false;
66
+ const param1 = getParamIdentifierName(params[0]);
67
+ const param2 = getParamIdentifierName(params[1]);
68
+ return (param1 === 'req' || param1 === 'request') && (param2 === 'res' || param2 === 'response');
69
+ }
70
+ /**
71
+ * Check if function name suggests it's a handler
72
+ * @returns {boolean} True if the function appears to be a handler
73
+ */
74
+ function isHandlerFunction(name, filePath, node) {
75
+ /* v8 ignore next -- defensive AST/type guard */
76
+ if (!isAPIFile(filePath))
77
+ return false;
78
+ // Check if exported
79
+ let isExported = false;
80
+ if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
81
+ isExported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
82
+ }
83
+ else if (ts.isArrowFunction(node) && ts.isVariableDeclaration(node.parent)) {
84
+ const varStatement = node.parent.parent.parent;
85
+ if (ts.isVariableStatement(varStatement)) {
86
+ isExported =
87
+ varStatement.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
88
+ }
89
+ }
90
+ else {
91
+ // Other node types remain isExported = false (initial value)
92
+ }
93
+ if (!isExported)
94
+ return false;
95
+ return HANDLER_NAME_PATTERNS.some((pattern) => pattern.test(name));
96
+ }
97
+ /**
98
+ * Check if function should be skipped
99
+ * @returns {boolean} True if the function should be skipped in validation
100
+ */
101
+ function shouldSkipFunction(node, functionName, filePath) {
102
+ if (ts.isMethodDeclaration(node)) {
103
+ const isPrivate = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword);
104
+ /* v8 ignore next -- defensive AST/type guard */
105
+ if (isPrivate)
106
+ return true;
107
+ }
108
+ const isExpressHandler = hasExpressHandlerSignature(node);
109
+ if (functionName === '<anonymous>' && isExpressHandler)
110
+ return true;
111
+ if (!isExpressHandler && !isHandlerFunction(functionName, filePath, node))
112
+ return true;
113
+ return false;
114
+ }
115
+ /**
116
+ * Check if function has request parameter
117
+ * @returns {boolean} True if the function has a request parameter
118
+ */
119
+ function hasRequestParameter(node) {
120
+ return node.parameters.some((param) => {
121
+ /* v8 ignore next -- defensive AST/type guard */
122
+ if (!ts.isIdentifier(param.name))
123
+ return false;
124
+ const name = param.name.text;
125
+ /* v8 ignore next -- defensive AST/type guard */
126
+ return name === 'req' || name === 'request' || name.includes('Request');
127
+ });
128
+ }
129
+ /**
130
+ * Check if a call expression is a validation method call
131
+ */
132
+ function isValidationMethodCall(n) {
133
+ if (ts.isPropertyAccessExpression(n.expression)) {
134
+ return VALIDATION_METHOD_NAMES.has(n.expression.name.text);
135
+ }
136
+ if (ts.isIdentifier(n.expression)) {
137
+ return n.expression.text.toLowerCase().includes('validate');
138
+ }
139
+ return false;
140
+ }
141
+ /**
142
+ * Check if function has validation logic
143
+ * @returns {boolean} True if the function has validation logic
144
+ */
145
+ function hasRequestValidation(node) {
146
+ let hasValidation = false;
147
+ const visit = (n) => {
148
+ if (ts.isCallExpression(n) && isValidationMethodCall(n)) {
149
+ hasValidation = true;
150
+ }
151
+ if (!hasValidation)
152
+ ts.forEachChild(n, visit);
153
+ };
154
+ if (node.body)
155
+ visit(node.body);
156
+ return hasValidation;
157
+ }
158
+ /**
159
+ * Check if function has try-catch block
160
+ * @returns {boolean} True if the function has a try-catch block
161
+ */
162
+ function hasTryCatchBlock(node) {
163
+ let hasTryCatch = false;
164
+ const visit = (n) => {
165
+ if (ts.isTryStatement(n))
166
+ hasTryCatch = true;
167
+ if (!hasTryCatch)
168
+ ts.forEachChild(n, visit);
169
+ };
170
+ visit(node);
171
+ return hasTryCatch;
172
+ }
173
+ /**
174
+ * Check if function has untyped parameters
175
+ * @returns {boolean} True if the function has any untyped parameters
176
+ */
177
+ function hasUntypedParameters(node) {
178
+ return node.parameters.some((param) => !param.type);
179
+ }
180
+ /**
181
+ * Check if function has proper API contract
182
+ * @param {CheckFunctionContractOptions} options - The contract check options
183
+ * @returns {CheckViolation[]} Array of contract violations found
184
+ */
185
+ function checkFunctionContract(options) {
186
+ const { absolutePath, sourceFile, node } = options;
187
+ const violations = [];
188
+ const functionName = getFunctionName(node);
189
+ if (shouldSkipFunction(node, functionName, absolutePath)) {
190
+ return violations;
191
+ }
192
+ const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
193
+ const line = lineIdx + 1;
194
+ const functionSignature = node.getText(sourceFile).split('{')[0]?.trim().slice(0, 100) ?? functionName;
195
+ // Check 1: Has explicit return type
196
+ if (!node.type) {
197
+ violations.push({
198
+ line,
199
+ column: character + 1,
200
+ message: `Handler '${functionName}' missing explicit return type`,
201
+ severity: 'error',
202
+ suggestion: `Add explicit return type to '${functionName}', e.g., ': Promise<ServiceResult<T>>' or ': Promise<Response<T>>'`,
203
+ type: 'missing-response-type',
204
+ match: functionSignature,
205
+ });
206
+ }
207
+ // Check 2: Has typed parameters
208
+ if (hasUntypedParameters(node)) {
209
+ violations.push({
210
+ line,
211
+ column: character + 1,
212
+ message: `Handler '${functionName}' has untyped parameters`,
213
+ severity: 'error',
214
+ suggestion: `Add explicit TypeScript types to all parameters in '${functionName}' for type safety`,
215
+ type: 'untyped-parameters',
216
+ match: functionSignature,
217
+ });
218
+ }
219
+ // Check 3: Has validation for request parameters
220
+ if (!hasRequestValidation(node) && hasRequestParameter(node)) {
221
+ violations.push({
222
+ line,
223
+ column: character + 1,
224
+ message: `Handler '${functionName}' accepts request but has no validation`,
225
+ severity: 'error',
226
+ suggestion: `Add Zod schema validation using .parse() or .safeParse() for request body/params in '${functionName}'`,
227
+ type: 'missing-validation',
228
+ match: functionSignature,
229
+ });
230
+ }
231
+ // Check 4: Has try-catch for error handling
232
+ // Skip functions that ARE error handlers (handleXxxError) — wrapping
233
+ // them in another try-catch is error-handling-inception.
234
+ const isErrorHandler = ERROR_HANDLER_NAME_PATTERNS.some((p) => p.test(functionName));
235
+ if (!isErrorHandler && !hasTryCatchBlock(node)) {
236
+ violations.push({
237
+ line,
238
+ column: character + 1,
239
+ message: `Handler '${functionName}' missing try-catch error handling`,
240
+ severity: 'warning',
241
+ suggestion: `Wrap the body of '${functionName}' in try-catch to handle errors gracefully and return appropriate error responses`,
242
+ type: 'missing-error-handling',
243
+ match: functionSignature,
244
+ });
245
+ }
246
+ return violations;
247
+ }
248
+ /**
249
+ * Analyze a file for API contract violations
250
+ * @returns {CheckViolation[]} Array of violations found in the file
251
+ */
252
+ function analyzeFile(absolutePath, content) {
253
+ const violations = [];
254
+ const sourceFile = getSharedSourceFile(absolutePath, content);
255
+ /* v8 ignore next -- defensive guard */
256
+ if (!sourceFile)
257
+ return [];
258
+ const visit = (node) => {
259
+ if (ts.isFunctionDeclaration(node) ||
260
+ ts.isArrowFunction(node) ||
261
+ ts.isMethodDeclaration(node)) {
262
+ const nodeViolations = checkFunctionContract({
263
+ absolutePath,
264
+ sourceFile,
265
+ node,
266
+ });
267
+ violations.push(...nodeViolations);
268
+ }
269
+ ts.forEachChild(node, visit);
270
+ };
271
+ visit(sourceFile);
272
+ return violations;
273
+ }
274
+ /**
275
+ * Check: quality/api-contract-validation
276
+ *
277
+ * Validates that API handlers have proper validation, typed responses,
278
+ * and error handling for type safety and reliability.
279
+ *
280
+ */
281
+ export const apiContractValidation = defineCheck({
282
+ id: 'ef307717-de39-41d3-8344-0e6f7562367a',
283
+ slug: 'api-contract-validation',
284
+ scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
285
+ contentFilter: 'strip-strings',
286
+ confidence: 'high',
287
+ description: 'Validate API handlers have proper validation, typed responses, and error handling',
288
+ longDescription: `**Purpose:** Enforces that API handler functions have proper type contracts, input validation, and error handling.
289
+
290
+ **Detects:**
291
+ - Handlers (matching \`/handler$/i\`, \`/^handle[A-Z]/\`, \`/^process[A-Z]/\`) missing explicit return types
292
+ - Handler parameters without TypeScript type annotations
293
+ - Handlers accepting \`req\`/\`request\` params without calling \`parse\`, \`safeParse\`, \`validate\`, or similar validation methods
294
+ - Handler bodies missing try-catch error handling
295
+
296
+ **Why it matters:** Untyped or unvalidated API handlers allow malformed requests through and produce unpredictable error responses.
297
+
298
+ **Scope:** General best practice. Analyzes each file individually using TypeScript AST parsing. Only processes files identified as API files by \`isAPIFile()\`.`,
299
+ tags: ['quality', 'api', 'type-safety', 'validation'],
300
+ fileTypes: ['ts'],
301
+ analyze(content, filePath) {
302
+ // Only analyze API files
303
+ if (!isAPIFile(filePath)) {
304
+ return [];
305
+ }
306
+ try {
307
+ return analyzeFile(filePath, content);
308
+ /* v8 ignore next 1 -- defensive catch: parse failures already handled */
309
+ }
310
+ catch {
311
+ // @swallow-ok Skip files that fail to parse
312
+ return [];
313
+ }
314
+ },
315
+ });
316
+ //# sourceMappingURL=api-contract-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-contract-validation.js","sourceRoot":"","sources":["../../../../src/checks/quality/api/api-contract-validation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @fileoverview API Response Validation Check
3
+ *
4
+ * Ensures API responses are validated with Zod schemas before being sent to clients.
5
+ * Validates that response types match their Zod schema definitions.
6
+ */
7
+ /**
8
+ * Check: quality/api-response-validation
9
+ *
10
+ * Ensures API responses are validated with Zod schemas.
11
+ *
12
+ */
13
+ export declare const apiResponseValidation: import("@opensip-cli/fitness").Check;
14
+ //# sourceMappingURL=api-response-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-response-validation.d.ts","sourceRoot":"","sources":["../../../../src/checks/quality/api/api-response-validation.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AAoMH;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,sCAsChC,CAAC"}
@@ -0,0 +1,209 @@
1
+ // @fitness-ignore-file correlation-id-coverage -- Fitness check implementation, not an API handler
2
+ // @fitness-ignore-file duplicate-implementation-detection -- similar patterns across diagnostic modules
3
+ // @fitness-ignore-file no-raw-regex-on-code -- fitness check: regex patterns analyze trusted codebase content, not user input
4
+ /**
5
+ * @fileoverview API Response Validation Check
6
+ *
7
+ * Ensures API responses are validated with Zod schemas before being sent to clients.
8
+ * Validates that response types match their Zod schema definitions.
9
+ */
10
+ import { basename } from 'node:path';
11
+ import { defineCheck, isAPIFile } from '@opensip-cli/fitness';
12
+ import { getSharedSourceFile } from '@opensip-cli/lang-typescript';
13
+ import * as ts from 'typescript';
14
+ /**
15
+ * Check if a file contains Fastify route-level response schema definitions.
16
+ * Routes using `schema: { response: ... }` already validate responses at the framework level.
17
+ *
18
+ * The previous regex `\{[^}]*response\s*:` failed on real route schemas
19
+ * because real schemas contain nested object literals — once the regex
20
+ * hits the first `}` (e.g. closing a `querystring` block) it gives up
21
+ * before reaching `response:`. The lazy `.*?` form scans across nested
22
+ * braces correctly. We also accept the related forms a Zod-typed Fastify
23
+ * route uses: bare `response: {` blocks, response-status-keyed objects,
24
+ * and ResponseSchema imports paired with .send.
25
+ */
26
+ function hasRouteResponseSchema(content) {
27
+ // schema: { ... response: ... } — handles nested braces via lazy match.
28
+ if (/schema\s*:\s*\{.*?\bresponse\s*:/s.test(content))
29
+ return true;
30
+ // Direct `response: { 200: ... }` block — Fastify also accepts this
31
+ // shape outside an enclosing `schema:` wrapper inside `RouteOptions`.
32
+ if (/\bresponse\s*:\s*\{\s*[12345]\d{2}\s*:/s.test(content))
33
+ return true;
34
+ return false;
35
+ }
36
+ /**
37
+ * Check if a file only uses `reply.send()` with dynamic/passthrough payloads.
38
+ * These routes forward external API responses or computed results that have no fixed shape.
39
+ */
40
+ function isDynamicReplyOnly(content) {
41
+ // If file has reply.send() but no reply.status().send({ ... }) with object literals,
42
+ // it's likely a passthrough/dynamic endpoint
43
+ const hasSendCalls = content.includes('reply.send(') || content.includes('reply.send (');
44
+ if (!hasSendCalls)
45
+ return false;
46
+ // If there's a reply.code/status + structured object, it likely has a fixed shape
47
+ const hasStructuredResponse = /reply\s*\.\s*(?:code|status)\s*\([^)]+\)\s*\.\s*send\s*\(\s*\{/.test(content);
48
+ // If there's no structured response pattern, treat as dynamic
49
+ return !hasStructuredResponse;
50
+ }
51
+ /**
52
+ * Check if an import declaration imports schema/contracts
53
+ */
54
+ function checkSchemaImport(node, state) {
55
+ const moduleSpecifier = node.moduleSpecifier;
56
+ if (ts.isStringLiteral(moduleSpecifier)) {
57
+ const importPath = moduleSpecifier.text;
58
+ if (importPath.includes('schema') || importPath.includes('contracts')) {
59
+ state.hasResponseSchemaImport = true;
60
+ }
61
+ }
62
+ }
63
+ /**
64
+ * Check if a call expression validates a response
65
+ */
66
+ function checkValidationCall(node, sourceFile, state) {
67
+ const callText = node.expression.getText(sourceFile);
68
+ if (!callText.includes('parse') && !callText.includes('safeParse')) {
69
+ return;
70
+ }
71
+ /* v8 ignore next -- defensive nullish fallback */
72
+ const argText = node.arguments[0]?.getText(sourceFile) ?? '';
73
+ if (argText.includes('response') || argText.includes('result') || argText.includes('data')) {
74
+ state.hasResponseValidation = true;
75
+ }
76
+ }
77
+ /**
78
+ * Check if a return statement returns an API response
79
+ */
80
+ function checkApiResponseReturn(node, sourceFile, state) {
81
+ /* v8 ignore next -- defensive AST/type guard */
82
+ if (!node.expression)
83
+ return;
84
+ const returnText = node.expression.getText(sourceFile);
85
+ if (returnText.includes('res.') ||
86
+ returnText.includes('reply.') ||
87
+ returnText.includes('response.')) {
88
+ state.hasApiResponse = true;
89
+ }
90
+ }
91
+ /**
92
+ * Check if a file is an SSE/streaming endpoint.
93
+ * These routes use raw writes or event-stream content types, not structured JSON responses.
94
+ */
95
+ function isStreamingFile(content) {
96
+ return content.includes('text/event-stream') || content.includes('reply.raw.write');
97
+ }
98
+ /**
99
+ * Check if a file serves diagnostic, debug, or health endpoints.
100
+ * These routes intentionally return dynamic/unstructured payloads.
101
+ */
102
+ function isDiagnosticFile(filePath) {
103
+ const lowerPath = filePath.toLowerCase();
104
+ return (lowerPath.includes('diagnostic') || lowerPath.includes('debug') || lowerPath.includes('health'));
105
+ }
106
+ /**
107
+ * @returns {*}
108
+ * Analyze a file for response validation issues
109
+ */
110
+ function analyzeFile(absolutePath, content) {
111
+ const violations = [];
112
+ // Skip SSE/streaming routes — they don't return structured JSON
113
+ /* v8 ignore next -- defensive AST/type guard */
114
+ if (isStreamingFile(content))
115
+ return [];
116
+ // Skip diagnostic/debug/health endpoints — intentionally dynamic responses
117
+ /* v8 ignore next -- defensive AST/type guard */
118
+ if (isDiagnosticFile(absolutePath))
119
+ return [];
120
+ // Skip routes that define response schemas at the Fastify route level
121
+ /* v8 ignore next -- defensive AST/type guard */
122
+ if (hasRouteResponseSchema(content))
123
+ return [];
124
+ // Skip routes that only use reply.send() with dynamic/passthrough payloads
125
+ if (isDynamicReplyOnly(content))
126
+ return [];
127
+ const sourceFile = getSharedSourceFile(absolutePath, content);
128
+ /* v8 ignore next -- defensive guard */
129
+ if (!sourceFile)
130
+ return [];
131
+ // Track if file has response schema imports
132
+ // Use state object to track findings across callback invocations
133
+ // (TypeScript can't track primitive mutations in callbacks)
134
+ const state = {
135
+ hasResponseSchemaImport: false,
136
+ hasResponseValidation: false,
137
+ hasApiResponse: false,
138
+ };
139
+ const visit = (node) => {
140
+ if (ts.isImportDeclaration(node)) {
141
+ checkSchemaImport(node, state);
142
+ }
143
+ if (ts.isCallExpression(node)) {
144
+ checkValidationCall(node, sourceFile, state);
145
+ }
146
+ if (ts.isReturnStatement(node)) {
147
+ checkApiResponseReturn(node, sourceFile, state);
148
+ }
149
+ ts.forEachChild(node, visit);
150
+ };
151
+ visit(sourceFile);
152
+ // If file has API responses but no validation, flag it
153
+ if (state.hasApiResponse && !state.hasResponseValidation && !state.hasResponseSchemaImport) {
154
+ violations.push({
155
+ line: 1,
156
+ column: 0,
157
+ message: 'API file sends responses without schema validation',
158
+ severity: 'warning',
159
+ suggestion: 'Import a Zod response schema from shared contract schemas and use .parse() or .safeParse() to validate API responses before sending to clients',
160
+ type: 'missing-response-validation',
161
+ match: basename(absolutePath),
162
+ });
163
+ }
164
+ return violations;
165
+ }
166
+ /**
167
+ * Check: quality/api-response-validation
168
+ *
169
+ * Ensures API responses are validated with Zod schemas.
170
+ *
171
+ */
172
+ export const apiResponseValidation = defineCheck({
173
+ id: '8822fd30-bcd5-48d5-80d6-2f3abdec7f70',
174
+ slug: 'api-response-validation',
175
+ scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
176
+ confidence: 'high',
177
+ description: 'Ensure API responses are validated with Zod schemas',
178
+ longDescription: `**Purpose:** Ensures API files validate outbound responses with Zod schemas before sending them to clients.
179
+
180
+ **Detects:**
181
+ - Files that return API responses (via \`res.\`, \`reply.\`, or \`response.\`) but lack both a schema/contracts import and any \`parse\`/\`safeParse\` call on response/result/data arguments
182
+
183
+ **Skips:**
184
+ - SSE/streaming endpoints (files using \`text/event-stream\` or \`reply.raw.write\`)
185
+ - Diagnostic, debug, and health endpoints (path-based detection)
186
+ - Routes with Fastify-level response schemas (\`schema: { response: ... }\`)
187
+ - Routes that only use \`reply.send()\` with dynamic/passthrough payloads
188
+
189
+ **Why it matters:** Without response validation, API endpoints can silently send malformed or extra data to clients, breaking contracts and leaking internal fields.
190
+
191
+ **Scope:** General best practice. Analyzes each file individually using TypeScript AST parsing. Only processes files identified as API files by \`isAPIFile()\`.`,
192
+ tags: ['quality', 'api', 'validation', 'zod'],
193
+ fileTypes: ['ts'],
194
+ analyze(content, filePath) {
195
+ // Only analyze API files
196
+ if (!isAPIFile(filePath)) {
197
+ return [];
198
+ }
199
+ try {
200
+ return analyzeFile(filePath, content);
201
+ /* v8 ignore next 1 -- defensive catch: parse failures already handled */
202
+ }
203
+ catch {
204
+ // @swallow-ok Skip files that fail to parse
205
+ return [];
206
+ }
207
+ },
208
+ });
209
+ //# sourceMappingURL=api-response-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-response-validation.js","sourceRoot":"","sources":["../../../../src/checks/quality/api/api-response-validation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @fileoverview Fastify Route Validation Check
3
+ *
4
+ * Ensures all Fastify POST/PATCH/PUT route handlers validate request bodies
5
+ * using Zod schemas.
6
+ */
7
+ /**
8
+ * Check: quality/fastify-route-validation
9
+ *
10
+ * Ensures all Fastify POST/PATCH/PUT route handlers validate request bodies
11
+ * with Zod schemas.
12
+ */
13
+ export declare const fastifyRouteValidation: import("@opensip-cli/fitness").Check;
14
+ //# sourceMappingURL=fastify-route-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fastify-route-validation.d.ts","sourceRoot":"","sources":["../../../../src/checks/quality/api/fastify-route-validation.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AAkTH;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,sCAwCjC,CAAC"}