@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,16 @@
1
+ /**
2
+ * @fileoverview Result Pattern Consistency Check
3
+ *
4
+ * Enforces consistent use of Result<T,E> vs throw based on error type:
5
+ * - Result<T,E> for expected failures (validation, not found, business rules)
6
+ * - throw for unexpected failures (system errors, security issues)
7
+ *
8
+ * @see CLAUDE.md Error Handling Policy
9
+ */
10
+ /**
11
+ * Check: quality/result-pattern-consistency
12
+ *
13
+ * Ensures consistent use of Result<T,E> for expected failures and throw for unexpected failures.
14
+ */
15
+ export declare const resultPatternConsistency: import("@opensip-cli/fitness").Check;
16
+ //# sourceMappingURL=result-pattern-consistency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-pattern-consistency.d.ts","sourceRoot":"","sources":["../../../../src/checks/quality/patterns/result-pattern-consistency.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AA8SH;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,sCAsEnC,CAAC"}
@@ -0,0 +1,328 @@
1
+ // @fitness-ignore-file canonical-result-usage -- References Result pattern in JSDoc for check documentation, not actual Result usage
2
+ /**
3
+ * @fileoverview Result Pattern Consistency Check
4
+ *
5
+ * Enforces consistent use of Result<T,E> vs throw based on error type:
6
+ * - Result<T,E> for expected failures (validation, not found, business rules)
7
+ * - throw for unexpected failures (system errors, security issues)
8
+ *
9
+ * @see CLAUDE.md Error Handling Policy
10
+ */
11
+ import { defineCheck } from '@opensip-cli/fitness';
12
+ import { getSharedSourceFile } from '@opensip-cli/lang-typescript';
13
+ import * as ts from 'typescript';
14
+ /**
15
+ * Expected error types that should use Result pattern
16
+ */
17
+ const EXPECTED_ERROR_TYPES = [
18
+ 'ValidationError',
19
+ 'NotFoundError',
20
+ 'BusinessRuleError',
21
+ 'ConflictError',
22
+ 'InvalidInputError',
23
+ 'DuplicateError',
24
+ ];
25
+ /**
26
+ * Function name patterns where throwing is legitimate (validation/guard helpers
27
+ * + infrastructure-boundary factories, resolvers, loaders, parsers, mappers).
28
+ *
29
+ * Factory/resolver/loader helpers (`defineX`, `resolveX`, `loadX`, `parseX`,
30
+ * `mapXTo…`) are startup-time configuration entry points: a malformed input
31
+ * is a programmer error caught once at boot rather than a recoverable
32
+ * business-logic failure, so they throw eagerly. Forcing them to return
33
+ * `Result` would push a startup-error branch into every call site — a
34
+ * usability regression, not consistency.
35
+ */
36
+ const LEGITIMATE_THROW_FUNCTION_PATTERNS = [
37
+ /^validate[A-Z]/,
38
+ /^assert[A-Z]/,
39
+ /^ensure[A-Z]/,
40
+ /^require[A-Z]/,
41
+ /^check[A-Z]/,
42
+ /^verify[A-Z]/,
43
+ /^must[A-Z]/,
44
+ /^define[A-Z]/,
45
+ /^resolve[A-Z]/,
46
+ /^load[A-Z]/,
47
+ /^parse[A-Z]/,
48
+ /^map[A-Z]\w*To[A-Z]/,
49
+ /Guard$/,
50
+ /Validator$/,
51
+ /Assertion$/,
52
+ ];
53
+ /**
54
+ * Paths where throwing is expected (infrastructure boundaries per DEC-015).
55
+ * These are entry points that bridge external systems, CLI, or pipeline layers
56
+ * where callers can't meaningfully recover — throw is the correct pattern.
57
+ */
58
+ const THROW_ALLOWED_PATHS = [
59
+ /\/routes\//,
60
+ /\/handlers\//,
61
+ /\/controllers\//,
62
+ /\/middleware\//,
63
+ /\/plugins?\//,
64
+ /\/bootstrap/,
65
+ /\/providers\//,
66
+ // Internal services
67
+ /\/services\/internal\//,
68
+ // Validation utilities
69
+ /\/utils\/validation/,
70
+ // LLM and external API adapters (bridge external services)
71
+ /\/llm\//,
72
+ /\/adapters\//,
73
+ /\/embeddings\//,
74
+ // CLI command entry points (bridge CLI to domain)
75
+ /\/commands\//,
76
+ // Pipeline governance and orchestration boundaries
77
+ /\/governor\//,
78
+ /\/prompt\//,
79
+ // ID parsing/validation (infrastructure boundary for data integrity)
80
+ /\/ids\//,
81
+ // Infrastructure boundary packages and patterns (DEC-015: throw is correct)
82
+ /packages\/infrastructure\//,
83
+ /\/stores\//,
84
+ /\/registry\//,
85
+ ];
86
+ /**
87
+ * File name patterns where throwing is legitimate (infrastructure boundary classes)
88
+ */
89
+ const INFRASTRUCTURE_FILE_PATTERNS = [/registry/i, /-registry/i, /store/i, /-store/i, /adapter/i];
90
+ /**
91
+ * Check if a file path is in a throw-allowed context
92
+ */
93
+ function isThrowAllowedPath(filePath) {
94
+ if (THROW_ALLOWED_PATHS.some((pattern) => pattern.test(filePath))) {
95
+ return true;
96
+ }
97
+ // Check file name against infrastructure patterns (registries, stores, adapters)
98
+ /* v8 ignore next -- defensive nullish fallback */
99
+ const fileName = filePath.split('/').pop() ?? '';
100
+ return INFRASTRUCTURE_FILE_PATTERNS.some((pattern) => pattern.test(fileName));
101
+ }
102
+ /**
103
+ * Check if a function name indicates it's a validation/guard helper
104
+ */
105
+ function isValidationHelper(funcName) {
106
+ return LEGITIMATE_THROW_FUNCTION_PATTERNS.some((pattern) => pattern.test(funcName));
107
+ }
108
+ /**
109
+ * Check if a throw statement is inside a catch block (re-throw pattern)
110
+ */
111
+ function isInCatchBlock(node) {
112
+ let current = node.parent;
113
+ while (current) {
114
+ if (ts.isCatchClause(current)) {
115
+ return true;
116
+ }
117
+ current = current.parent;
118
+ }
119
+ return false;
120
+ }
121
+ /**
122
+ * Get the containing function name for a node
123
+ */
124
+ function getContainingFunctionName(node, sourceFile) {
125
+ let current = node.parent;
126
+ while (current) {
127
+ if (ts.isFunctionDeclaration(current) && current.name) {
128
+ return current.name.getText(sourceFile);
129
+ }
130
+ /* v8 ignore next -- defensive AST/type guard */
131
+ if (ts.isMethodDeclaration(current) && current.name) {
132
+ return current.name.getText(sourceFile);
133
+ }
134
+ /* v8 ignore next -- defensive AST/type guard */
135
+ if (ts.isArrowFunction(current) || ts.isFunctionExpression(current)) {
136
+ const parent = current.parent;
137
+ if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) {
138
+ return parent.name.getText(sourceFile);
139
+ }
140
+ }
141
+ current = current.parent;
142
+ }
143
+ return undefined;
144
+ }
145
+ /**
146
+ * Check if a node is inside a constructor (constructors should throw, not return Result)
147
+ */
148
+ function isInConstructor(node) {
149
+ let current = node.parent;
150
+ while (current) {
151
+ if (ts.isConstructorDeclaration(current)) {
152
+ return true;
153
+ }
154
+ current = current.parent;
155
+ }
156
+ return false;
157
+ }
158
+ /**
159
+ * Check if a node is inside a private method (private methods may throw for internal consistency)
160
+ */
161
+ function isInPrivateMethod(node) {
162
+ let current = node.parent;
163
+ while (current) {
164
+ if (ts.isMethodDeclaration(current)) {
165
+ const modifiers = ts.getModifiers(current);
166
+ if (modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword)) {
167
+ return true;
168
+ }
169
+ }
170
+ current = current.parent;
171
+ }
172
+ return false;
173
+ }
174
+ /**
175
+ * Checks a throw statement for expected error types that should use Result pattern
176
+ */
177
+ function checkThrowStatement(options) {
178
+ const { node, sourceFile, filePath } = options;
179
+ // Skip files in throw-allowed paths (routes, handlers, plugins)
180
+ if (isThrowAllowedPath(filePath)) {
181
+ return null;
182
+ }
183
+ // Skip re-throws in catch blocks (error wrapping is legitimate)
184
+ if (isInCatchBlock(node)) {
185
+ return null;
186
+ }
187
+ // Skip constructors (constructor validation should throw, not return Result)
188
+ if (isInConstructor(node)) {
189
+ return null;
190
+ }
191
+ // Skip private methods (internal consistency checks may throw)
192
+ if (isInPrivateMethod(node)) {
193
+ return null;
194
+ }
195
+ // Skip validation/guard helper functions
196
+ const funcName = getContainingFunctionName(node, sourceFile);
197
+ if (funcName && isValidationHelper(funcName)) {
198
+ return null;
199
+ }
200
+ const throwText = node.expression.getText(sourceFile);
201
+ // Find the first matching expected error type
202
+ const matchedErrorType = EXPECTED_ERROR_TYPES.find((errorType) => throwText.includes(errorType));
203
+ if (!matchedErrorType) {
204
+ return null;
205
+ }
206
+ const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
207
+ const lineNum = line + 1;
208
+ const matchText = node.getText(sourceFile);
209
+ return {
210
+ line: lineNum,
211
+ column: character + 1,
212
+ message: `Throwing ${matchedErrorType} instead of returning Result`,
213
+ severity: 'warning',
214
+ suggestion: `Replace 'throw new ${matchedErrorType}(...)' with 'return err(new ${matchedErrorType}(...))' and update the function return type to Result<T, ${matchedErrorType}>`,
215
+ match: matchText,
216
+ };
217
+ }
218
+ /**
219
+ * Checks function body for thrown expected errors when return type is Result
220
+ */
221
+ function checkResultFunctionBody(options) {
222
+ const { bodyText, node, sourceFile, filePath } = options;
223
+ // Skip files in throw-allowed paths
224
+ if (isThrowAllowedPath(filePath)) {
225
+ return null;
226
+ }
227
+ // Skip private methods (internal consistency checks may throw)
228
+ /* v8 ignore next -- defensive AST/type guard */
229
+ if (ts.isMethodDeclaration(node)) {
230
+ const modifiers = ts.getModifiers(node);
231
+ if (modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword)) {
232
+ return null;
233
+ }
234
+ }
235
+ // Get function name
236
+ const funcName = ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)
237
+ ? node.name?.getText(sourceFile)
238
+ : undefined;
239
+ // Skip validation helper functions
240
+ if (funcName && isValidationHelper(funcName)) {
241
+ return null;
242
+ }
243
+ for (const errorType of EXPECTED_ERROR_TYPES) {
244
+ if (!bodyText.includes(`throw new ${errorType}`))
245
+ continue;
246
+ const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
247
+ const lineNum = line + 1;
248
+ const matchText = `throw new ${errorType}`;
249
+ return {
250
+ line: lineNum,
251
+ column: character + 1,
252
+ message: `Function returns Result but throws ${errorType}`,
253
+ severity: 'error',
254
+ suggestion: `This function declares Result<T,E> return type but throws ${errorType}. Replace 'throw new ${errorType}(...)' with 'return err(new ${errorType}(...))' for consistency`,
255
+ match: matchText,
256
+ };
257
+ }
258
+ return null;
259
+ }
260
+ /**
261
+ * Check: quality/result-pattern-consistency
262
+ *
263
+ * Ensures consistent use of Result<T,E> for expected failures and throw for unexpected failures.
264
+ */
265
+ export const resultPatternConsistency = defineCheck({
266
+ id: '137e8d24-8b06-4d1f-b5f0-e7542d932679',
267
+ slug: 'result-pattern-consistency',
268
+ scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
269
+ contentFilter: 'strip-strings',
270
+ confidence: 'high',
271
+ description: 'Ensures consistent use of Result<T,E> for expected failures and throw for unexpected failures',
272
+ longDescription: `**Purpose:** Enforces that expected failures (validation, not-found, business rules) use \`Result<T,E>\` while \`throw\` is reserved for unexpected failures (DEC-015).
273
+
274
+ **Detects:** Analyzes each file individually using TypeScript AST. Checks for:
275
+ - \`throw new\` statements using expected error types (\`ValidationError\`, \`NotFoundError\`, \`BusinessRuleError\`, \`ConflictError\`, \`InvalidInputError\`, \`DuplicateError\`) outside catch blocks and non-validation helper functions
276
+ - Functions with \`Result\` return type that also contain \`throw new <ExpectedError>\` statements
277
+
278
+ **Why it matters:** Mixing throw and Result for the same error category forces callers to handle both patterns, creating inconsistent and fragile error handling.
279
+
280
+ **Scope:** Codebase-specific convention (see CLAUDE.md Error Handling Policy)`,
281
+ tags: ['error-handling', 'quality', 'best-practices'],
282
+ fileTypes: ['ts'],
283
+ analyze(content, filePath) {
284
+ // Quick filter: skip files without error patterns
285
+ const hasErrorPatterns = content.includes('throw') || content.includes('Result');
286
+ if (!hasErrorPatterns) {
287
+ return [];
288
+ }
289
+ const violations = [];
290
+ const sourceFile = getSharedSourceFile(filePath, content);
291
+ /* v8 ignore next -- defensive guard */
292
+ if (!sourceFile)
293
+ return [];
294
+ const visit = (node) => {
295
+ ts.forEachChild(node, visit);
296
+ // Check throw statements for expected error types
297
+ if (ts.isThrowStatement(node)) {
298
+ const violation = checkThrowStatement({ node, sourceFile, filePath });
299
+ if (violation) {
300
+ violations.push(violation);
301
+ }
302
+ return;
303
+ }
304
+ // Check functions that return Result but also throw expected errors
305
+ if (!ts.isFunctionDeclaration(node) && !ts.isMethodDeclaration(node))
306
+ return;
307
+ const returnType = node.type?.getText(sourceFile);
308
+ // Require the canonical generic form `Result<…>` (also matches
309
+ // `Promise<Result<…>>`). A bare substring match for "Result"
310
+ // misclassifies domain types like `GateCompareResult`, `AnalyzeResult`,
311
+ // or `ParseResult` as Result-returning and produces false positives
312
+ // wherever such a function throws on a legitimate infrastructure
313
+ // boundary. Word-boundary + `<` preserves the intent without matching
314
+ // unrelated trailing-token names.
315
+ if (!returnType || !/\bResult\s*</.test(returnType))
316
+ return;
317
+ /* v8 ignore next -- defensive nullish fallback */
318
+ const bodyText = node.body?.getText(sourceFile) ?? '';
319
+ const violation = checkResultFunctionBody({ bodyText, node, sourceFile, filePath });
320
+ if (violation) {
321
+ violations.push(violation);
322
+ }
323
+ };
324
+ visit(sourceFile);
325
+ return violations;
326
+ },
327
+ });
328
+ //# sourceMappingURL=result-pattern-consistency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-pattern-consistency.js","sourceRoot":"","sources":["../../../../src/checks/quality/patterns/result-pattern-consistency.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @fileoverview Silent Early Returns Check
3
+ *
4
+ * Detects validation/guard paths that return silently without logging.
5
+ * These patterns make debugging difficult by hiding why code paths weren't executed.
6
+ */
7
+ /**
8
+ * Check: quality/silent-early-returns
9
+ *
10
+ * Detects single-line early returns (if (!x) return null/false) without logging.
11
+ * These patterns make it impossible to know why a code path wasn't executed.
12
+ *
13
+ * Exceptions:
14
+ * - Type guards (functions that return `x is T`)
15
+ * - Boolean predicate functions (isXxx, hasXxx, canXxx, shouldXxx)
16
+ * - Predicate callbacks (filter, find, some, every, map, etc.) where false/null means "skip item"
17
+ * - Validation/utility functions (validate, verify, parse, check, get, test, compare, supports, etc.)
18
+ * - Code with `// @silent-ok` marker
19
+ * - Code with nearby logging
20
+ * - Fitness check and framework source files (excluded from scanning)
21
+ */
22
+ export declare const silentEarlyReturns: import("@opensip-cli/fitness").Check;
23
+ //# sourceMappingURL=silent-early-returns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"silent-early-returns.d.ts","sourceRoot":"","sources":["../../../../src/checks/quality/patterns/silent-early-returns.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuQH;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,sCAgD7B,CAAC"}
@@ -0,0 +1,266 @@
1
+ /**
2
+ * @fileoverview Silent Early Returns Check
3
+ *
4
+ * Detects validation/guard paths that return silently without logging.
5
+ * These patterns make debugging difficult by hiding why code paths weren't executed.
6
+ */
7
+ import { logger } from '@opensip-cli/core';
8
+ import { defineCheck } from '@opensip-cli/fitness';
9
+ import { getSharedSourceFile } from '@opensip-cli/lang-typescript';
10
+ import * as ts from 'typescript';
11
+ /**
12
+ * Patterns that indicate logging is present
13
+ */
14
+ const LOGGING_PATTERNS = [/logger\./, /console\./, /\.log\(/];
15
+ /**
16
+ * Patterns that indicate intentional silent return
17
+ */
18
+ const MARKER_PATTERNS = [/@silent-ok/, /\/\/\s*type\s*guard/i];
19
+ /**
20
+ * Sentinel return value kinds
21
+ */
22
+ const SENTINEL_KINDS = new Set([ts.SyntaxKind.NullKeyword, ts.SyntaxKind.FalseKeyword]);
23
+ // =============================================================================
24
+ // HELPER FUNCTIONS
25
+ // =============================================================================
26
+ /**
27
+ * Find the enclosing function for a node.
28
+ *
29
+ * Intentionally narrower than `lang-typescript`'s `findEnclosingFunction` —
30
+ * skips past `ConstructorDeclaration` and `FunctionExpression` parents to
31
+ * find the next enclosing declaration/method/arrow whose name (if any) the
32
+ * downstream predicates (`isTypeGuard`, `isValidationOrParserFunction`) can
33
+ * inspect. Switching to the canonical helper would change behavior for
34
+ * `if (!x) return null` directly inside a constructor body.
35
+ */
36
+ function findFunction(node) {
37
+ let current = node.parent;
38
+ while (current) {
39
+ if (ts.isFunctionDeclaration(current) ||
40
+ ts.isMethodDeclaration(current) ||
41
+ ts.isArrowFunction(current)) {
42
+ return current;
43
+ }
44
+ current = current.parent;
45
+ }
46
+ return null;
47
+ }
48
+ /**
49
+ * Check if a function is a type guard or boolean predicate
50
+ * - Type guards: functions that return `x is T`
51
+ * - Predicate functions: isXxx, hasXxx, canXxx, shouldXxx
52
+ */
53
+ function isTypeGuard(fn, sourceFile) {
54
+ // Check return type predicate
55
+ if (fn.type?.getText(sourceFile).includes(' is ')) {
56
+ return true;
57
+ }
58
+ // Check function name matches predicate patterns
59
+ if ((ts.isFunctionDeclaration(fn) || ts.isMethodDeclaration(fn)) && fn.name) {
60
+ const name = fn.name.getText(sourceFile);
61
+ // Predicate function patterns: isXxx, hasXxx, canXxx, shouldXxx
62
+ if (/^(is|has|can|should)[A-Z]/.test(name)) {
63
+ return true;
64
+ }
65
+ }
66
+ return false;
67
+ }
68
+ /**
69
+ * Check if a function is a validation/parsing function where silent returns are expected.
70
+ * These functions legitimately return null/false for invalid input.
71
+ */
72
+ function isValidationOrParserFunction(fn, sourceFile) {
73
+ // Get function name if available
74
+ if ((ts.isFunctionDeclaration(fn) || ts.isMethodDeclaration(fn)) && fn.name) {
75
+ const name = fn.name.getText(sourceFile);
76
+ // Validation/parsing function patterns: validate*, verify*, parse*, check*, extract*, get*OrNull, etc.
77
+ if (
78
+ // eslint-disable-next-line sonarjs/regex-complexity -- exhaustive list of known validator/parser prefixes; readable as written
79
+ /^(validate|verify|parse|check|extract|try|attempt|find|get\w*OrNull|get|lookup|resolve|match|unregister|acquire|release|test|compare|supports)[A-Z]?/.test(name)) {
80
+ return true;
81
+ }
82
+ }
83
+ // Check return type - functions returning T | null or T | undefined are validators
84
+ if (fn.type) {
85
+ const returnType = fn.type.getText(sourceFile);
86
+ if (returnType.includes('| null') || returnType.includes('| undefined')) {
87
+ return true;
88
+ }
89
+ }
90
+ return false;
91
+ }
92
+ /**
93
+ * Check if a return is a guard clause at the start of a function (first 3 statements).
94
+ * Early guard clauses are a common defensive coding pattern.
95
+ */
96
+ function isEarlyGuardClause(returnNode, fn) {
97
+ const body = fn.body;
98
+ /* v8 ignore next -- defensive AST/type guard */
99
+ if (!body || !ts.isBlock(body))
100
+ return false;
101
+ const statements = body.statements;
102
+ for (let i = 0; i < Math.min(statements.length, 3); i++) {
103
+ if (statements[i] === returnNode) {
104
+ return true;
105
+ }
106
+ }
107
+ return false;
108
+ }
109
+ /**
110
+ * Array predicate methods where returning false is intentional filtering
111
+ */
112
+ const PREDICATE_METHODS = new Set([
113
+ 'filter',
114
+ 'find',
115
+ 'findIndex',
116
+ 'findLast',
117
+ 'findLastIndex',
118
+ 'some',
119
+ 'every',
120
+ 'map',
121
+ ]);
122
+ /**
123
+ * Check if a function is a callback in an array predicate method
124
+ * Example: arr.filter(x => { if (!x) return false; ... })
125
+ */
126
+ function isPredicateCallback(fn) {
127
+ // Only arrow functions can be predicate callbacks
128
+ if (!ts.isArrowFunction(fn))
129
+ return false;
130
+ // Check if parent is a call expression argument
131
+ const parent = fn.parent;
132
+ /* v8 ignore next -- defensive AST/type guard */
133
+ if (!ts.isCallExpression(parent))
134
+ return false;
135
+ // Check if the call is a method call
136
+ const callee = parent.expression;
137
+ /* v8 ignore next -- defensive AST/type guard */
138
+ if (!ts.isPropertyAccessExpression(callee))
139
+ return false;
140
+ // Check if method name is a predicate method
141
+ const methodName = callee.name.getText();
142
+ return PREDICATE_METHODS.has(methodName);
143
+ }
144
+ function extractReturnStatement(node) {
145
+ if (ts.isReturnStatement(node.thenStatement)) {
146
+ return node.thenStatement;
147
+ }
148
+ /* v8 ignore next -- defensive AST/type guard */
149
+ if (ts.isBlock(node.thenStatement) && node.thenStatement.statements.length === 1) {
150
+ const statement = node.thenStatement.statements[0];
151
+ if (statement && ts.isReturnStatement(statement)) {
152
+ return statement;
153
+ }
154
+ }
155
+ return null;
156
+ }
157
+ function isSentinelReturn(returnStatement) {
158
+ return Boolean(returnStatement?.expression && SENTINEL_KINDS.has(returnStatement.expression.kind));
159
+ }
160
+ function shouldSkipForFunction(node, sourceFile) {
161
+ const fn = findFunction(node);
162
+ /* v8 ignore next -- defensive AST/type guard */
163
+ if (!fn)
164
+ return false;
165
+ return (isTypeGuard(fn, sourceFile) ||
166
+ isPredicateCallback(fn) ||
167
+ isValidationOrParserFunction(fn, sourceFile) ||
168
+ isEarlyGuardClause(node, fn));
169
+ }
170
+ function hasLoggingOrMarkerInContext(node, content) {
171
+ /* v8 ignore next -- defensive non-negative guard */
172
+ const start = Math.max(0, node.getStart() - 200);
173
+ const context = content.slice(start, node.getEnd());
174
+ return (LOGGING_PATTERNS.some((p) => p.test(context)) || MARKER_PATTERNS.some((p) => p.test(context)));
175
+ }
176
+ function createSilentReturnViolation(node, returnStatement, sourceFile) {
177
+ const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
178
+ /* v8 ignore next -- defensive AST/type guard */
179
+ const val = returnStatement.expression.kind === ts.SyntaxKind.NullKeyword ? 'null' : 'false';
180
+ return {
181
+ line: line + 1,
182
+ column: 0,
183
+ message: `Silent early return (${val}) without logging`,
184
+ severity: 'error',
185
+ // @fitness-ignore-next-line logging-standards -- String literal in suggestion text, not actual logger call
186
+ suggestion: `Add logging: \`if (cond) { logger.info({ evt: 'validation.failed' }); return ${val}; }\``,
187
+ match: `return ${val}`,
188
+ };
189
+ }
190
+ function checkSilentReturn(node, sourceFile, content) {
191
+ const returnStatement = extractReturnStatement(node);
192
+ if (!isSentinelReturn(returnStatement)) {
193
+ return null;
194
+ }
195
+ if (shouldSkipForFunction(node, sourceFile)) {
196
+ return null;
197
+ }
198
+ if (hasLoggingOrMarkerInContext(node, content)) {
199
+ return null;
200
+ }
201
+ return createSilentReturnViolation(node, returnStatement, sourceFile);
202
+ }
203
+ // =============================================================================
204
+ // CHECK IMPLEMENTATION
205
+ // =============================================================================
206
+ /**
207
+ * Check: quality/silent-early-returns
208
+ *
209
+ * Detects single-line early returns (if (!x) return null/false) without logging.
210
+ * These patterns make it impossible to know why a code path wasn't executed.
211
+ *
212
+ * Exceptions:
213
+ * - Type guards (functions that return `x is T`)
214
+ * - Boolean predicate functions (isXxx, hasXxx, canXxx, shouldXxx)
215
+ * - Predicate callbacks (filter, find, some, every, map, etc.) where false/null means "skip item"
216
+ * - Validation/utility functions (validate, verify, parse, check, get, test, compare, supports, etc.)
217
+ * - Code with `// @silent-ok` marker
218
+ * - Code with nearby logging
219
+ * - Fitness check and framework source files (excluded from scanning)
220
+ */
221
+ export const silentEarlyReturns = defineCheck({
222
+ id: '9585ae15-45ea-404c-91b5-91baad7b4de0',
223
+ slug: 'silent-early-returns',
224
+ scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
225
+ contentFilter: 'strip-strings',
226
+ description: 'Detect single-line early returns without logging',
227
+ longDescription: `**Purpose:** Detects validation/guard paths that return sentinel values (\`null\` or \`false\`) without logging, making debugging difficult.
228
+
229
+ **Detects:** Analyzes each file individually using TypeScript AST. Finds \`if\` statements (without \`else\`) whose then-branch is a single \`return null\` or \`return false\` with no nearby logging (\`logger.\`, \`console.\`) or \`@silent-ok\` marker. Excludes type guards (\`is/has/can/should\` prefixes), predicate callbacks (\`filter\`, \`find\`, \`some\`, \`every\`, \`map\`), validation/parser/utility functions (validate, verify, parse, check, extract, try, attempt, find, get, lookup, resolve, match, unregister, acquire, release, test, compare, supports), early guard clauses (first 3 statements), and fitness check/framework source files.
230
+
231
+ **Why it matters:** Silent early returns make it impossible to diagnose why a code path was not executed, turning simple issues into hours-long debugging sessions.
232
+
233
+ **Scope:** General best practice`,
234
+ tags: ['quality', 'observability', 'validation'],
235
+ fileTypes: ['ts'],
236
+ confidence: 'medium',
237
+ analyze(content, filePath) {
238
+ logger.debug({
239
+ evt: 'fitness.check.silent_early_returns.analyze',
240
+ msg: 'Analyzing file for silent early return patterns',
241
+ filePath,
242
+ });
243
+ // Quick filter: must have potential silent returns
244
+ if (!content.includes('return null') && !content.includes('return false')) {
245
+ return [];
246
+ }
247
+ const violations = [];
248
+ const sourceFile = getSharedSourceFile(filePath, content);
249
+ /* v8 ignore next -- defensive guard */
250
+ if (!sourceFile)
251
+ return [];
252
+ const visit = (node) => {
253
+ // Only check if statements without else (single-line guards)
254
+ if (ts.isIfStatement(node) && !node.elseStatement) {
255
+ const violation = checkSilentReturn(node, sourceFile, content);
256
+ if (violation) {
257
+ violations.push(violation);
258
+ }
259
+ }
260
+ ts.forEachChild(node, visit);
261
+ };
262
+ visit(sourceFile);
263
+ return violations;
264
+ },
265
+ });
266
+ //# sourceMappingURL=silent-early-returns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"silent-early-returns.js","sourceRoot":"","sources":["../../../../src/checks/quality/patterns/silent-early-returns.ts"],"names":[],"mappings":"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"}