@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,1072 @@
1
+ // @fitness-ignore-file file-length-limit -- behavior fixture suite; related scenarios stay together while checks are split into focused tests.
2
+ /**
3
+ * @fileoverview Branch-behavior fixture suite: targets high-impact uncovered branches
4
+ * across many checks via rich, realistic source fixtures.
5
+ */
6
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
7
+ import { tmpdir } from 'node:os';
8
+ import { dirname, join } from 'node:path';
9
+ import { LanguageRegistry, RunScope, runWithScope } from '@opensip-cli/core';
10
+ import { fileCache } from '@opensip-cli/fitness';
11
+ import { typescriptAdapter } from '@opensip-cli/lang-typescript';
12
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
13
+ import { checks } from '../index.js';
14
+ // Production simulation: register the TS adapter (see behavior-fixtures.test.ts).
15
+ const langRegistry = new LanguageRegistry();
16
+ langRegistry.register(typescriptAdapter);
17
+ const testScope = new RunScope({ languages: langRegistry });
18
+ let cwd;
19
+ let written = [];
20
+ function fx(rel, content) {
21
+ const abs = join(cwd, rel);
22
+ mkdirSync(dirname(abs), { recursive: true });
23
+ writeFileSync(abs, content);
24
+ written.push(abs);
25
+ return abs;
26
+ }
27
+ function findCheck(slug) {
28
+ const c = checks.find((x) => x.config.slug === slug);
29
+ if (!c)
30
+ throw new Error(`check not found: ${slug}`);
31
+ return c;
32
+ }
33
+ async function runCheck(slug) {
34
+ const check = findCheck(slug);
35
+ await fileCache.prewarm(cwd, ['**/*']);
36
+ return runWithScope(testScope, () => check.run(cwd, { targetFiles: written }));
37
+ }
38
+ beforeEach(() => {
39
+ cwd = mkdtempSync(join(tmpdir(), 'opensip-cov-branch-'));
40
+ written = [];
41
+ });
42
+ afterEach(() => {
43
+ fileCache.clear();
44
+ rmSync(cwd, { recursive: true, force: true });
45
+ });
46
+ // ---------------------------------------------------------------------------
47
+ // detached-promises (resilience/async-patterns) — drive sync-call branches
48
+ // ---------------------------------------------------------------------------
49
+ describe('detached-promises — many sync-call branches', () => {
50
+ it('exercises super(), this.method(), nested receivers, sync receivers, sync prefixes/suffixes', async () => {
51
+ fx('src/svc/detached.ts', [
52
+ 'class Base {',
53
+ ' init() { this.helper() }',
54
+ ' helper() {}',
55
+ '}',
56
+ 'export class Svc extends Base {',
57
+ ' async run(input: string) {',
58
+ ' super.init()',
59
+ ' this.syncMethod()',
60
+ ' this.helper()',
61
+ ' logger.info("hello")',
62
+ ' this.logger.warn("nested")',
63
+ ' Pyroscope.default.start()',
64
+ ' myLogger.error("pattern receiver")',
65
+ ' setupRoute(input)',
66
+ ' teardownClient()',
67
+ ' isReady()',
68
+ ' fs.readFileSync("/tmp/x")',
69
+ ' process.nextTick(() => undefined)',
70
+ ' void doStuff()',
71
+ ' apiCall().then(() => undefined)',
72
+ ' apiCall().catch(() => undefined)',
73
+ ' apiCall().finally(() => undefined)',
74
+ ' unwrap(await apiCall())',
75
+ ' (await apiCall()).chain()',
76
+ ' apiCall() // <-- detached',
77
+ ' }',
78
+ ' syncMethod() { return 1 }',
79
+ '}',
80
+ ].join('\n'));
81
+ const result = await runCheck('detached-promises');
82
+ expect(result).toBeDefined();
83
+ });
84
+ it('handles non-async function with calls (skip), test files (skip)', async () => {
85
+ fx('src/util/sync.ts', ['export function notAsync() { doStuff() }'].join('\n'));
86
+ fx('src/x.test.ts', ['export async function t() { doStuff() }'].join('\n'));
87
+ const result = await runCheck('detached-promises');
88
+ expect(result).toBeDefined();
89
+ });
90
+ it('handles cli/script file skip patterns', async () => {
91
+ fx('src/cli/cmd.ts', ['export async function run() { doStuff(); other(); }'].join('\n'));
92
+ const result = await runCheck('detached-promises');
93
+ expect(result).toBeDefined();
94
+ });
95
+ it('exercises super-call kind branch', async () => {
96
+ fx('src/svc/super.ts', [
97
+ 'class Parent {}',
98
+ 'export class Child extends Parent {',
99
+ ' constructor() { super() }',
100
+ '}',
101
+ ].join('\n'));
102
+ const result = await runCheck('detached-promises');
103
+ expect(result).toBeDefined();
104
+ });
105
+ });
106
+ // ---------------------------------------------------------------------------
107
+ // no-unbounded-concurrency — bounded-pattern branches
108
+ // ---------------------------------------------------------------------------
109
+ describe('no-unbounded-concurrency — bounded-pattern branches', () => {
110
+ it('skips when content has p-limit, plimit, allSettled, concurrency:N, batch, throttle, rateLimit', async () => {
111
+ const variants = [
112
+ 'import pLimit from "p-limit"\nawait Promise.all(items.map(fn))',
113
+ 'const limit = plimit(4)\nawait Promise.all(arr.map(fn))',
114
+ 'await Promise.allSettled(items.map(fn))',
115
+ 'await Promise.all(items.map(fn)) // concurrency: 4',
116
+ 'await Promise.all(items.map(fn)) // batch chunked',
117
+ 'await Promise.all(items.map(fn)) // throttle 10/s',
118
+ 'await Promise.all(items.map(fn)) // rateLimit 5',
119
+ ];
120
+ for (const [i, src] of variants.entries()) {
121
+ fx(`src/api/u${i}.ts`, src);
122
+ }
123
+ fx('src/api/raw.ts', 'await Promise.all(items.map(fn))');
124
+ const result = await runCheck('no-unbounded-concurrency');
125
+ expect(result).toBeDefined();
126
+ });
127
+ });
128
+ // ---------------------------------------------------------------------------
129
+ // no-raw-fetch — many skip paths
130
+ // ---------------------------------------------------------------------------
131
+ describe('no-raw-fetch — skip-path branches', () => {
132
+ it('skips resilient-fetch, fitness/checks paths, llm paths, streaming files, test files', async () => {
133
+ fx('src/lib/resilient-fetch.ts', 'await fetch("/x")');
134
+ fx('src/llm/openai.ts', 'await fetch("/x")');
135
+ fx('src/llm-adapter/openai.ts', 'await fetch("/x")');
136
+ fx('src/sse/stream.ts', 'const r = new ReadableStream(); await fetch("/x")');
137
+ fx('src/sse/event.ts', 'const r = new EventSource(""); await fetch("/x")');
138
+ fx('src/sse/r.ts', 'const reader = body.getReader(); await fetch("/x")');
139
+ fx('src/x.test.ts', 'await fetch("/x")');
140
+ fx('src/x.spec.ts', 'await fetch("/x")');
141
+ fx('src/__tests__/y.ts', 'await fetch("/x")');
142
+ fx('src/api/legit.ts', '// uses fetch\nawait fetch("/legit")');
143
+ fx('src/api/comment.ts', '// fetch( comment\nawait fetch("/legit")');
144
+ const result = await runCheck('no-raw-fetch');
145
+ expect(result).toBeDefined();
146
+ });
147
+ });
148
+ // ---------------------------------------------------------------------------
149
+ // toctou-race-condition — exercise local/shared/atomic SQL/cache branches
150
+ // ---------------------------------------------------------------------------
151
+ describe('toctou-race-condition — many classification branches', () => {
152
+ it('local Map/Set, this.cache, drizzle update/insert/delete, sql template, shared, unknown receiver', async () => {
153
+ fx('src/svc/toc.ts', [
154
+ 'class StringCache {',
155
+ ' get(k: string): string | undefined { return undefined }',
156
+ ' set(k: string, v: string): void {}',
157
+ '}',
158
+ 'export class Service {',
159
+ ' private headerCache: Map<string, string> = new Map()',
160
+ ' #cache = new Map<string, number>()',
161
+ ' cache: StringCache = new StringCache()',
162
+ ' async fetchAndUpdate(id: string) {',
163
+ ' const local = new Map<string, number>()',
164
+ ' local.get(id)',
165
+ ' local.set(id, 1)',
166
+ ' this.headerCache.get(id)',
167
+ ' this.headerCache.set(id, "x")',
168
+ ' this.#cache.get(id)',
169
+ ' this.#cache.set(id, 1)',
170
+ ' this.cache.get(id)',
171
+ ' this.cache.set(id, "x")',
172
+ ' db.update(tableX)',
173
+ ' db.insert(tableX)',
174
+ ' db.delete(tableX)',
175
+ ' tx.execute(sql`UPDATE x SET y=1`)',
176
+ ' chain.foo().get(id)',
177
+ ' chain.foo().update(id)',
178
+ ' repo.findOne(id)',
179
+ ' repo.put(id, 2)', // shared read+update
180
+ ' return 1',
181
+ ' }',
182
+ ' async noPair(id: string) {',
183
+ ' repo.find(id)',
184
+ ' return null',
185
+ ' }',
186
+ '}',
187
+ ].join('\n'));
188
+ const result = await runCheck('toctou-race-condition');
189
+ expect(result).toBeDefined();
190
+ });
191
+ it('skips safe paths and atomic-comment files', async () => {
192
+ fx('src/cache/foo.ts', 'export function f() { repo.find(); repo.set(1) }');
193
+ fx('src/cli/cmd.ts', 'export function f() { repo.find(); repo.set(1) }');
194
+ fx('src/scripts/x.ts', 'export function f() { repo.find(); repo.set(1) }');
195
+ fx('src/testing/y.ts', 'export function f() { repo.find(); repo.set(1) }');
196
+ fx('src/test-utils/y.ts', 'export function f() { repo.find(); repo.set(1) }');
197
+ fx('src/config/y.ts', 'export function f() { repo.find(); repo.set(1) }');
198
+ fx('src/registry/y.ts', 'export function f() { repo.find(); repo.set(1) }');
199
+ fx('src/factories/y.ts', 'export function f() { repo.find(); repo.set(1) }');
200
+ fx('src/routes/y.ts', 'export function f() { repo.find(); repo.set(1) }');
201
+ fx('src/di/y.ts', 'export function f() { repo.find(); repo.set(1) }');
202
+ fx('src/schema/y.ts', 'export function f() { repo.find(); repo.set(1) }');
203
+ fx('src/whatever/x-cache.ts', 'export function f() { repo.find(); repo.set(1) }');
204
+ fx('src/whatever/x-prefetcher.ts', 'export function f() { repo.find(); repo.set(1) }');
205
+ fx('src/svc/atomic.ts', '// transaction wrapper\nexport function f() { repo.find(); repo.set(1) }');
206
+ fx('src/svc/version.ts', 'export function f() { repo.find({version: 1}); repo.update({expectedVersion: 1}) }');
207
+ const result = await runCheck('toctou-race-condition');
208
+ expect(result).toBeDefined();
209
+ });
210
+ });
211
+ // ---------------------------------------------------------------------------
212
+ // async-waterfall-detection — many branches
213
+ // ---------------------------------------------------------------------------
214
+ describe('async-waterfall-detection — branches', () => {
215
+ it('handles independent awaits, dependent awaits, await in for/while, mixed', async () => {
216
+ fx('src/svc/waterfall.ts', [
217
+ 'export async function independent(): Promise<void> {',
218
+ ' const a = await fetchA()',
219
+ ' const b = await fetchB()',
220
+ ' const c = await fetchC()',
221
+ ' console.log(a, b, c)',
222
+ '}',
223
+ 'export async function dependent(): Promise<void> {',
224
+ ' const a = await fetchA()',
225
+ ' const b = await fetchB(a)',
226
+ ' console.log(b)',
227
+ '}',
228
+ 'export async function inLoop(items: number[]): Promise<void> {',
229
+ ' for (const it of items) {',
230
+ ' await process(it)',
231
+ ' }',
232
+ '}',
233
+ 'export async function inWhileLoop(): Promise<void> {',
234
+ ' while (true) {',
235
+ ' const r = await tick()',
236
+ ' if (!r) break',
237
+ ' }',
238
+ '}',
239
+ 'export async function tryCatch(): Promise<void> {',
240
+ ' try {',
241
+ ' const a = await fetchA()',
242
+ ' const b = await fetchB()',
243
+ ' return a + b',
244
+ ' } catch (e) { return 0 }',
245
+ '}',
246
+ 'export async function withReturnAwait(): Promise<number> {',
247
+ ' return await fetchOne()',
248
+ '}',
249
+ 'export async function singleAwait(): Promise<number> {',
250
+ ' return await fetchOne()',
251
+ '}',
252
+ ].join('\n'));
253
+ const result = await runCheck('async-waterfall-detection');
254
+ expect(result).toBeDefined();
255
+ });
256
+ it('handles non-async functions and files without await', async () => {
257
+ fx('src/svc/nowait.ts', 'export function f() { return 1 }');
258
+ fx('src/svc/empty.ts', '// no await here');
259
+ const result = await runCheck('async-waterfall-detection');
260
+ expect(result).toBeDefined();
261
+ });
262
+ });
263
+ // ---------------------------------------------------------------------------
264
+ // memo-list-items — exercise visit branches deeply
265
+ // ---------------------------------------------------------------------------
266
+ // ---------------------------------------------------------------------------
267
+ // no-inline-functions — exercise trivial-callback branches
268
+ // ---------------------------------------------------------------------------
269
+ // ---------------------------------------------------------------------------
270
+ // missing-type-exports
271
+ // ---------------------------------------------------------------------------
272
+ describe('missing-type-exports — branches', () => {
273
+ it('exercises declared-but-unexported types, exported types, type-only imports, ambient declarations', async () => {
274
+ fx('src/types/lib.ts', [
275
+ 'export interface Public { id: string }',
276
+ 'interface Internal { id: string }',
277
+ 'export type T1 = string',
278
+ 'type T2 = number',
279
+ 'export class C { x = 1 }',
280
+ 'class D { x = 1 }',
281
+ 'export enum E { A, B }',
282
+ 'enum F { A, B }',
283
+ 'declare const G: unknown',
284
+ 'export { Internal as RenamedInternal }',
285
+ ].join('\n'));
286
+ fx('src/types/uses.ts', [
287
+ 'import type { Public, T1 } from "./lib.js"',
288
+ 'export const x: Public = { id: "1" }',
289
+ 'export const y: T1 = "ok"',
290
+ ].join('\n'));
291
+ fx('src/types/index.ts', 'export * from "./lib.js"');
292
+ const result = await runCheck('missing-type-exports');
293
+ expect(result).toBeDefined();
294
+ });
295
+ });
296
+ // ---------------------------------------------------------------------------
297
+ // throws-documentation
298
+ // ---------------------------------------------------------------------------
299
+ describe('throws-documentation — branches', () => {
300
+ it('flags throws without @throws JSDoc, accepts documented throws', async () => {
301
+ fx('src/svc/throws.ts', [
302
+ '/** @throws {RangeError} when bad */',
303
+ 'export function documented() { throw new RangeError("bad") }',
304
+ 'export function undocumented() { throw new Error("oops") }',
305
+ 'export function nested() {',
306
+ ' if (true) {',
307
+ ' if (Math.random() > 0.5) throw new Error("inner")',
308
+ ' }',
309
+ '}',
310
+ 'export function throwsNonError() { throw "string" }',
311
+ 'export async function asyncThrows(): Promise<void> { throw new Error("a") }',
312
+ 'export class Klass {',
313
+ ' /** @throws Error */',
314
+ ' m() { throw new Error("m") }',
315
+ ' n() { throw new Error("n") }',
316
+ '}',
317
+ 'export const arr = () => { throw new Error("a") }',
318
+ 'export const exp = function() { throw new Error("e") }',
319
+ 'export function caught() { try { throw new Error() } catch (_e) { return 1 } }',
320
+ 'export function caughtRethrows() { try { return 1 } catch (e) { throw e } }',
321
+ ].join('\n'));
322
+ const result = await runCheck('throws-documentation');
323
+ expect(result).toBeDefined();
324
+ });
325
+ });
326
+ // ---------------------------------------------------------------------------
327
+ // array-validation
328
+ // ---------------------------------------------------------------------------
329
+ describe('array-validation — branches', () => {
330
+ it('flags array.length, [0], unsafe destructuring, allows guards', async () => {
331
+ fx('src/api/handler.ts', [
332
+ 'export function handle(items: number[]) {',
333
+ ' const a = items[0]',
334
+ ' const b = items[items.length - 1]',
335
+ ' const [first] = items',
336
+ ' if (items.length === 0) return null',
337
+ ' if (items.length > 0) return items[0]',
338
+ ' if (Array.isArray(items)) return items[0]',
339
+ ' return a + b + first',
340
+ '}',
341
+ 'export function safeUse(items?: number[]) {',
342
+ ' return items?.[0]',
343
+ '}',
344
+ 'export function nestedArr(rows: { items: number[] }[]) {',
345
+ ' return rows[0].items[0]',
346
+ '}',
347
+ ].join('\n'));
348
+ const result = await runCheck('array-validation');
349
+ expect(result).toBeDefined();
350
+ });
351
+ });
352
+ // ---------------------------------------------------------------------------
353
+ // numeric-validation
354
+ // ---------------------------------------------------------------------------
355
+ describe('numeric-validation — branches', () => {
356
+ it('flags missing isFinite/isNaN, allows guards', async () => {
357
+ fx('src/svc/num.ts', [
358
+ 'export function calc(price: number, qty: number) {',
359
+ ' return price * qty',
360
+ '}',
361
+ 'export function safeCalc(price: number, qty: number) {',
362
+ ' if (!Number.isFinite(price) || !Number.isFinite(qty)) return 0',
363
+ ' if (Number.isNaN(price)) return 0',
364
+ ' return price * qty',
365
+ '}',
366
+ 'export function divide(a: number, b: number) {',
367
+ ' return a / b',
368
+ '}',
369
+ 'export function divideSafe(a: number, b: number) {',
370
+ ' if (b === 0) throw new RangeError("div by zero")',
371
+ ' return a / b',
372
+ '}',
373
+ 'export function parseInt2(s: string) {',
374
+ ' return parseInt(s, 10)',
375
+ '}',
376
+ 'export function parseFloat2(s: string) {',
377
+ ' return parseFloat(s)',
378
+ '}',
379
+ 'export function modulo(a: number, b: number) { return a % b }',
380
+ ].join('\n'));
381
+ const result = await runCheck('numeric-validation');
382
+ expect(result).toBeDefined();
383
+ });
384
+ });
385
+ // ---------------------------------------------------------------------------
386
+ // null-safety
387
+ // ---------------------------------------------------------------------------
388
+ describe('null-safety — branches', () => {
389
+ it('flags unchecked null, allows ?., ??, ===null guards', async () => {
390
+ fx('src/svc/ns.ts', [
391
+ 'export function f1(x: { name: string } | null) {',
392
+ ' return x.name', // unsafe
393
+ '}',
394
+ 'export function f2(x: { name: string } | null) {',
395
+ ' return x?.name', // safe
396
+ '}',
397
+ 'export function f3(x: { name: string } | null) {',
398
+ ' if (x === null) return ""',
399
+ ' return x.name', // safe
400
+ '}',
401
+ 'export function f4(x: { name: string } | undefined) {',
402
+ ' return x?.name ?? "anon"', // safe
403
+ '}',
404
+ 'export function f5(x: any) {',
405
+ ' return x.name', // any-typed, may or may not flag
406
+ '}',
407
+ 'export function f6(x?: { items?: string[] }) {',
408
+ ' return x?.items?.length ?? 0',
409
+ '}',
410
+ 'export class C {',
411
+ ' private name?: string',
412
+ ' greet() { return this.name?.toUpperCase() }',
413
+ ' unsafeGreet() { return this.name!.toUpperCase() }',
414
+ '}',
415
+ ].join('\n'));
416
+ const result = await runCheck('null-safety');
417
+ expect(result).toBeDefined();
418
+ });
419
+ });
420
+ // ---------------------------------------------------------------------------
421
+ // stubbed-implementation-detection
422
+ // ---------------------------------------------------------------------------
423
+ describe('stubbed-implementation-detection — branches', () => {
424
+ it('flags TODO bodies, throw not implemented, return null/[]/empty', async () => {
425
+ fx('src/svc/stub.ts', [
426
+ 'export function todo() { /* TODO: implement me */ return null }',
427
+ 'export function notImpl() { throw new Error("not implemented") }',
428
+ 'export function notImpl2() { throw new Error("Not yet implemented") }',
429
+ 'export function emptyArr() { return [] }',
430
+ 'export function emptyObj() { return {} }',
431
+ 'export function returnNull(): null { return null }',
432
+ 'export async function asyncStub() { return null }',
433
+ 'export function realImpl(a: number, b: number) { return a + b }',
434
+ 'export class S {',
435
+ ' // TODO finish me',
436
+ ' m() { return null }',
437
+ ' n() { throw new Error("TODO") }',
438
+ '}',
439
+ ].join('\n'));
440
+ const result = await runCheck('stubbed-implementation-detection');
441
+ expect(result).toBeDefined();
442
+ });
443
+ });
444
+ // ---------------------------------------------------------------------------
445
+ // incomplete-regex-escaping
446
+ // ---------------------------------------------------------------------------
447
+ describe('incomplete-regex-escaping — branches', () => {
448
+ it('flags unescaped specials in user-input regex, allows escaped ones', async () => {
449
+ fx('src/util/re.ts', [
450
+ 'export function bad(input: string) {',
451
+ ' return new RegExp(input)',
452
+ '}',
453
+ 'export function good(input: string) {',
454
+ ' const escaped = input.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\\\$&")',
455
+ ' return new RegExp(escaped)',
456
+ '}',
457
+ String.raw `export function literal() { return /foo\.bar/ }`,
458
+ 'export function fromTemplate(input: string) {',
459
+ ' return new RegExp(`prefix-${input}-suffix`)',
460
+ '}',
461
+ 'export const dyn = (i: string) => new RegExp("[" + i + "]")',
462
+ 'export function strReplace(s: string, p: string) {',
463
+ ' return s.replace(new RegExp(p, "g"), "")',
464
+ '}',
465
+ ].join('\n'));
466
+ const result = await runCheck('incomplete-regex-escaping');
467
+ expect(result).toBeDefined();
468
+ });
469
+ });
470
+ // ---------------------------------------------------------------------------
471
+ // silent-early-returns
472
+ // ---------------------------------------------------------------------------
473
+ describe('silent-early-returns — branches', () => {
474
+ it('flags early returns without logging in business logic', async () => {
475
+ fx('src/svc/silent.ts', [
476
+ 'export function f1(x: { id: string } | null) {',
477
+ ' if (!x) return null',
478
+ ' return x.id',
479
+ '}',
480
+ 'export function f2(x: { id: string } | null) {',
481
+ ' if (!x) {',
482
+ ' logger.warn("missing x")',
483
+ ' return null',
484
+ ' }',
485
+ ' return x.id',
486
+ '}',
487
+ 'export function f3(items: number[]) {',
488
+ ' if (items.length === 0) return',
489
+ ' return items.reduce((a,b) => a+b)',
490
+ '}',
491
+ 'export function f4(input?: string) {',
492
+ ' return input ?? null',
493
+ '}',
494
+ 'export async function f5(x?: string) {',
495
+ ' if (!x) throw new Error("required")',
496
+ ' return await fetchData(x)',
497
+ '}',
498
+ ].join('\n'));
499
+ const result = await runCheck('silent-early-returns');
500
+ expect(result).toBeDefined();
501
+ });
502
+ });
503
+ // ---------------------------------------------------------------------------
504
+ // missing-input-validation
505
+ // ---------------------------------------------------------------------------
506
+ describe('missing-input-validation — branches', () => {
507
+ it('handlers with and without zod parse', async () => {
508
+ fx('src/api/h.ts', [
509
+ 'import { z } from "zod"',
510
+ 'const Body = z.object({ id: z.string() })',
511
+ 'export async function safeHandler(req: any) {',
512
+ ' const body = Body.parse(req.body)',
513
+ ' return body',
514
+ '}',
515
+ 'export async function unsafeHandler(req: any) {',
516
+ ' return req.body.id',
517
+ '}',
518
+ 'export async function partialHandler(req: any) {',
519
+ ' const x = z.string().safeParse(req.params.id)',
520
+ ' return x',
521
+ '}',
522
+ ].join('\n'));
523
+ const result = await runCheck('missing-input-validation');
524
+ expect(result).toBeDefined();
525
+ });
526
+ });
527
+ // ---------------------------------------------------------------------------
528
+ // api-response-validation
529
+ // ---------------------------------------------------------------------------
530
+ describe('api-response-validation — branches', () => {
531
+ it('routes that return raw data vs validated', async () => {
532
+ fx('src/api/route.ts', [
533
+ 'import { z } from "zod"',
534
+ 'const RespSchema = z.object({ ok: z.boolean() })',
535
+ 'export async function ok(): Promise<unknown> { return RespSchema.parse({ ok: true }) }',
536
+ 'export async function leak(): Promise<unknown> { return rawDb.query() }',
537
+ 'export async function unionRet(x: number): Promise<unknown> {',
538
+ ' if (x > 0) return { ok: true }',
539
+ ' return { ok: false }',
540
+ '}',
541
+ ].join('\n'));
542
+ const result = await runCheck('api-response-validation');
543
+ expect(result).toBeDefined();
544
+ });
545
+ });
546
+ // ---------------------------------------------------------------------------
547
+ // fastify-route-validation
548
+ // ---------------------------------------------------------------------------
549
+ describe('fastify-route-validation — branches', () => {
550
+ it('routes with and without schema option', async () => {
551
+ fx('src/routes/users.ts', [
552
+ 'import type { FastifyInstance } from "fastify"',
553
+ 'export async function register(app: FastifyInstance) {',
554
+ ' app.get("/users", { schema: { response: { 200: { type: "object" } } } }, async () => [])',
555
+ ' app.post("/users", async (req) => req.body)',
556
+ ' app.put("/users/:id", { schema: { params: { type: "object" } } }, async () => ({}))',
557
+ ' app.delete("/users/:id", async () => ({}))',
558
+ ' app.route({ method: "GET", url: "/x", handler: async () => ({}) })',
559
+ ' app.route({ method: "POST", url: "/y", schema: { body: {} }, handler: async () => ({}) })',
560
+ '}',
561
+ ].join('\n'));
562
+ const result = await runCheck('fastify-route-validation');
563
+ expect(result).toBeDefined();
564
+ });
565
+ });
566
+ // ---------------------------------------------------------------------------
567
+ // api-contract-validation
568
+ // ---------------------------------------------------------------------------
569
+ describe('api-contract-validation — branches', () => {
570
+ it('handlers with missing/with return types and try/catch', async () => {
571
+ fx('src/api/handlers.ts', [
572
+ 'export async function noTypes(req: unknown, _res: unknown) {',
573
+ ' const body = (req as any).body',
574
+ ' return body',
575
+ '}',
576
+ 'export async function withTypes(req: { body: string }): Promise<{ ok: boolean }> {',
577
+ ' try {',
578
+ ' return { ok: req.body !== "" }',
579
+ ' } catch (e) {',
580
+ ' return { ok: false }',
581
+ ' }',
582
+ '}',
583
+ 'export function nonAsync(req: any) { return req }',
584
+ 'export const arrowHandler = async (req: any): Promise<unknown> => req',
585
+ 'export class Ctrl {',
586
+ ' async handle(req: any): Promise<unknown> { return req }',
587
+ ' syncMethod(req: any) { return req }',
588
+ '}',
589
+ ].join('\n'));
590
+ const result = await runCheck('api-contract-validation');
591
+ expect(result).toBeDefined();
592
+ });
593
+ });
594
+ // ---------------------------------------------------------------------------
595
+ // di-static-inject-usage
596
+ // ---------------------------------------------------------------------------
597
+ // ---------------------------------------------------------------------------
598
+ // duplicate-utility-functions
599
+ // ---------------------------------------------------------------------------
600
+ describe('duplicate-utility-functions — branches', () => {
601
+ it('multiple files with duplicate functions vs unique', async () => {
602
+ fx('src/util/a.ts', [
603
+ 'export function add(a: number, b: number): number { return a + b }',
604
+ 'export function uniqueA() { return 1 }',
605
+ 'export function helper(s: string) { return s.toUpperCase() }',
606
+ ].join('\n'));
607
+ fx('src/util/b.ts', [
608
+ 'export function add(a: number, b: number): number { return a + b }', // duplicate
609
+ 'export function uniqueB() { return 2 }',
610
+ 'export function helper(s: string) { return s.toUpperCase() }', // duplicate
611
+ ].join('\n'));
612
+ fx('src/util/c.ts', [
613
+ 'export function add(a: number, b: number): number { return a + b }', // triple
614
+ ].join('\n'));
615
+ const result = await runCheck('duplicate-utility-functions');
616
+ expect(result).toBeDefined();
617
+ });
618
+ });
619
+ // ---------------------------------------------------------------------------
620
+ // no-any-types
621
+ // ---------------------------------------------------------------------------
622
+ describe('no-any-types — branches', () => {
623
+ it('detects various any forms', async () => {
624
+ fx('src/types/anys.ts', [
625
+ 'export const a: any = 1',
626
+ 'export function f(x: any): any { return x }',
627
+ 'export const obj: { [k: string]: any } = {}',
628
+ 'export type T<T = any> = T',
629
+ 'export const arr: any[] = []',
630
+ 'export const cast = (x: unknown) => x as any',
631
+ 'export interface I { x: any; y: unknown }',
632
+ ].join('\n'));
633
+ const result = await runCheck('no-any-types');
634
+ expect(result).toBeDefined();
635
+ });
636
+ });
637
+ // ---------------------------------------------------------------------------
638
+ // pii-exposure-in-logs
639
+ // ---------------------------------------------------------------------------
640
+ describe('pii-exposure-in-logs — branches', () => {
641
+ it('logs that include PII keywords vs safe logs', async () => {
642
+ fx('src/svc/log.ts', [
643
+ 'export function f(req: any) {',
644
+ ' logger.info({ email: req.email })',
645
+ ' logger.warn({ password: req.password })',
646
+ ' logger.error({ ssn: req.ssn })',
647
+ ' logger.info({ requestId: req.requestId })',
648
+ ' logger.info("processing request")',
649
+ ' console.log(req.body)',
650
+ ' console.log({ ip: req.ip })',
651
+ ' console.error(req)',
652
+ '}',
653
+ ].join('\n'));
654
+ const result = await runCheck('pii-exposure-in-logs');
655
+ expect(result).toBeDefined();
656
+ });
657
+ });
658
+ // ---------------------------------------------------------------------------
659
+ // logger-event-name-format
660
+ // ---------------------------------------------------------------------------
661
+ describe('logger-event-name-format — branches', () => {
662
+ it('various event-name shapes (snake, kebab, camelCase, with periods, missing)', async () => {
663
+ fx('src/svc/events.ts', [
664
+ 'logger.info("event_emitted")',
665
+ 'logger.info("event-emitted")',
666
+ 'logger.info("eventEmitted")',
667
+ 'logger.info("Event Emitted")',
668
+ 'logger.info("module.event_emitted")',
669
+ 'logger.info({ event: "payment.processed", amount: 1 })',
670
+ 'logger.info({ event: "WrongCase", x: 1 })',
671
+ 'logger.warn({ a: 1 })',
672
+ 'logger.error("simple")',
673
+ ].join('\n'));
674
+ const result = await runCheck('logger-event-name-format');
675
+ expect(result).toBeDefined();
676
+ });
677
+ });
678
+ // ---------------------------------------------------------------------------
679
+ // platform-checks
680
+ // ---------------------------------------------------------------------------
681
+ // ---------------------------------------------------------------------------
682
+ // lazy-loading
683
+ // ---------------------------------------------------------------------------
684
+ // ---------------------------------------------------------------------------
685
+ // flashlist-enforcement
686
+ // ---------------------------------------------------------------------------
687
+ // ---------------------------------------------------------------------------
688
+ // client-boundary-placement
689
+ // ---------------------------------------------------------------------------
690
+ // ---------------------------------------------------------------------------
691
+ // test-only-frontend-modules
692
+ // ---------------------------------------------------------------------------
693
+ describe('test-only-frontend-modules — branches', () => {
694
+ it('mocks vs real implementations', async () => {
695
+ fx('src/api/__mocks__/users.ts', 'export const fetchUsers = () => []');
696
+ fx('src/api/users.ts', 'export const fetchUsers = async () => fetch("/users")');
697
+ fx('src/api/test.helpers.ts', 'export const mockUser = () => ({ id: "1" })');
698
+ const result = await runCheck('test-only-frontend-modules');
699
+ expect(result).toBeDefined();
700
+ });
701
+ });
702
+ // ---------------------------------------------------------------------------
703
+ // stream-buffer-size-limits
704
+ // ---------------------------------------------------------------------------
705
+ describe('stream-buffer-size-limits — branches', () => {
706
+ it('bounded vs unbounded streams', async () => {
707
+ fx('src/svc/stream.ts', [
708
+ 'import { Readable } from "stream"',
709
+ 'export const limited = new Readable({ highWaterMark: 1024 })',
710
+ 'export const unlimited = new Readable({})',
711
+ 'export const buffered = (s: Readable) => s.pipe(somethingElse, { highWaterMark: 4096 })',
712
+ ].join('\n'));
713
+ const result = await runCheck('stream-buffer-size-limits');
714
+ expect(result).toBeDefined();
715
+ });
716
+ });
717
+ // ---------------------------------------------------------------------------
718
+ // dispose-pattern-completeness
719
+ // ---------------------------------------------------------------------------
720
+ describe('dispose-pattern-completeness — branches', () => {
721
+ it('classes with/without proper dispose impl', async () => {
722
+ fx('src/svc/disp.ts', [
723
+ 'export class A {',
724
+ ' private timer: NodeJS.Timer | null = null',
725
+ ' start() { this.timer = setInterval(() => undefined, 1000) }',
726
+ ' dispose() { if (this.timer) clearInterval(this.timer) }',
727
+ '}',
728
+ 'export class B {',
729
+ ' private timer: NodeJS.Timer | null = null',
730
+ ' start() { this.timer = setInterval(() => undefined, 1000) }',
731
+ '}',
732
+ 'export class C {',
733
+ ' [Symbol.asyncDispose]() {}',
734
+ '}',
735
+ 'export class D implements Disposable {',
736
+ ' [Symbol.dispose]() {}',
737
+ '}',
738
+ ].join('\n'));
739
+ const result = await runCheck('dispose-pattern-completeness');
740
+ expect(result).toBeDefined();
741
+ });
742
+ });
743
+ // ---------------------------------------------------------------------------
744
+ // typeorm-n-plus-one
745
+ // ---------------------------------------------------------------------------
746
+ // ---------------------------------------------------------------------------
747
+ // postgres-n-plus-one
748
+ // ---------------------------------------------------------------------------
749
+ // ---------------------------------------------------------------------------
750
+ // financial-transaction-ordering
751
+ // ---------------------------------------------------------------------------
752
+ // ---------------------------------------------------------------------------
753
+ // database-index-coverage
754
+ // ---------------------------------------------------------------------------
755
+ describe('database-index-coverage — branches', () => {
756
+ it('drizzle table with and without indexes', async () => {
757
+ fx('src/db/schema/users.ts', [
758
+ 'import { pgTable, serial, text, varchar, integer, index } from "drizzle-orm/pg-core"',
759
+ 'export const users = pgTable("users", {',
760
+ ' id: serial("id").primaryKey(),',
761
+ ' email: varchar("email", { length: 255 }),',
762
+ ' tenantId: integer("tenant_id"),',
763
+ '}, (t) => ({ emailIdx: index("email_idx").on(t.email) }))',
764
+ 'export const posts = pgTable("posts", {',
765
+ ' id: serial("id").primaryKey(),',
766
+ ' userId: integer("user_id"),',
767
+ ' title: text("title"),',
768
+ '})',
769
+ ].join('\n'));
770
+ const result = await runCheck('database-index-coverage');
771
+ expect(result).toBeDefined();
772
+ });
773
+ });
774
+ // ---------------------------------------------------------------------------
775
+ // database-schema-validation
776
+ // ---------------------------------------------------------------------------
777
+ describe('database-schema-validation — branches', () => {
778
+ it('drizzle types with and without notNull, unique, default', async () => {
779
+ fx('src/db/schema/all.ts', [
780
+ 'import { pgTable, serial, text, varchar, timestamp, integer } from "drizzle-orm/pg-core"',
781
+ 'export const t1 = pgTable("t1", {',
782
+ ' id: serial("id").primaryKey(),',
783
+ ' name: text("name").notNull(),',
784
+ ' email: varchar("email", { length: 255 }).notNull().unique(),',
785
+ ' createdAt: timestamp("created_at").defaultNow().notNull(),',
786
+ ' optional: text("optional"),',
787
+ ' count: integer("count").default(0),',
788
+ '})',
789
+ ].join('\n'));
790
+ const result = await runCheck('database-schema-validation');
791
+ expect(result).toBeDefined();
792
+ });
793
+ });
794
+ // ---------------------------------------------------------------------------
795
+ // in-memory-repository-detection
796
+ // ---------------------------------------------------------------------------
797
+ describe('in-memory-repository-detection — extra branches', () => {
798
+ it('multiple Repository classes with different storage shapes', async () => {
799
+ fx('src/repos/multi.ts', [
800
+ 'export class FooRepository {',
801
+ ' private byMap = new Map<string, number>()',
802
+ ' private bySet = new Set<string>()',
803
+ ' private byArray: { id: string }[] = []',
804
+ ' private byObject: Record<string, unknown> = {}',
805
+ ' async listAll() { return [...this.byMap.values()] }',
806
+ '}',
807
+ '// FooRepository',
808
+ ].join('\n'));
809
+ fx('src/repos/Cache.ts', ['export class CacheRepository {', ' private byMap = new Map<string, number>()', '}'].join('\n'));
810
+ fx('src/repos/Mock.ts', ['export class MockRepository {', ' private byMap = new Map<string, number>()', '}'].join('\n'));
811
+ const result = await runCheck('in-memory-repository-detection');
812
+ expect(result).toBeDefined();
813
+ });
814
+ });
815
+ // ---------------------------------------------------------------------------
816
+ // sql-injection
817
+ // ---------------------------------------------------------------------------
818
+ describe('sql-injection — branches', () => {
819
+ it('template injection vs parameterized', async () => {
820
+ fx('src/api/db.ts', [
821
+ 'export async function bad(id: string) {',
822
+ ' return await db.query(`SELECT * FROM users WHERE id = ${id}`)',
823
+ '}',
824
+ 'export async function good(id: string) {',
825
+ ' return await db.query("SELECT * FROM users WHERE id = $1", [id])',
826
+ '}',
827
+ 'export async function bad2(name: string) {',
828
+ ' const sql = "SELECT * FROM users WHERE name = \'" + name + "\'"',
829
+ ' return await db.query(sql)',
830
+ '}',
831
+ 'export async function good2(name: string) {',
832
+ ' const stmt = db.prepare("SELECT * FROM users WHERE name = ?")',
833
+ ' return stmt.execute([name])',
834
+ '}',
835
+ ].join('\n'));
836
+ const result = await runCheck('sql-injection');
837
+ expect(result).toBeDefined();
838
+ });
839
+ });
840
+ // ---------------------------------------------------------------------------
841
+ // input-sanitization
842
+ // ---------------------------------------------------------------------------
843
+ describe('input-sanitization — branches', () => {
844
+ it('html, fs, exec, and url cases', async () => {
845
+ fx('src/api/risk.ts', [
846
+ 'import { exec } from "child_process"',
847
+ 'import * as fs from "fs"',
848
+ 'export function htmlBad(req: any) {',
849
+ ' return `<div>${req.body.html}</div>`',
850
+ '}',
851
+ 'export function fsBad(req: any) {',
852
+ ' return fs.readFileSync("/etc/" + req.params.file)',
853
+ '}',
854
+ 'export function execBad(req: any) {',
855
+ ' exec("ls " + req.body.dir, () => undefined)',
856
+ '}',
857
+ 'export function urlBad(req: any) {',
858
+ ' return fetch("https://api.com/" + req.params.id)',
859
+ '}',
860
+ 'export function safe() {',
861
+ ' return fs.readFileSync("/etc/hosts")',
862
+ '}',
863
+ ].join('\n'));
864
+ const result = await runCheck('input-sanitization');
865
+ expect(result).toBeDefined();
866
+ });
867
+ });
868
+ // ---------------------------------------------------------------------------
869
+ // unsafe-secret-comparison
870
+ // ---------------------------------------------------------------------------
871
+ describe('unsafe-secret-comparison — branches', () => {
872
+ it('detects ===, ==, .equals, allows timingSafeEqual', async () => {
873
+ fx('src/auth/x.ts', [
874
+ 'import { timingSafeEqual } from "crypto"',
875
+ 'export function bad1(secret: string, given: string) { return secret === given }',
876
+ 'export function bad2(secret: string, given: string) { return secret == given }',
877
+ 'export function bad3(a: Buffer, b: Buffer) { return a.equals(b) }',
878
+ 'export function good(a: Buffer, b: Buffer) { return timingSafeEqual(a, b) }',
879
+ 'export function notSecret(a: number, b: number) { return a === b }',
880
+ ].join('\n'));
881
+ const result = await runCheck('unsafe-secret-comparison');
882
+ expect(result).toBeDefined();
883
+ });
884
+ });
885
+ // ---------------------------------------------------------------------------
886
+ // observability-coverage (helper) — covered via direct unit tests
887
+ // ---------------------------------------------------------------------------
888
+ // ---------------------------------------------------------------------------
889
+ // error-handling-quality
890
+ // ---------------------------------------------------------------------------
891
+ describe('error-handling-quality — branches', () => {
892
+ it('try/catch shapes and rethrow patterns', async () => {
893
+ fx('src/svc/eh.ts', [
894
+ 'export function f1() { try { return 1 } catch { return 0 } }',
895
+ 'export function f2() { try { return 1 } catch (e) { console.log(e); throw e } }',
896
+ 'export function f3() { try { return 1 } catch (e) { logger.error({ err: e }); throw new Error("wrap") } }',
897
+ 'export async function f4() { try { return await x() } catch { } }', // empty catch
898
+ 'export function f5() { try { return 1 } catch (e: any) { return e.message } }',
899
+ 'export function f6() { try { return 1 } catch (_e) { return null } }',
900
+ ].join('\n'));
901
+ const result = await runCheck('error-handling-quality');
902
+ expect(result).toBeDefined();
903
+ });
904
+ });
905
+ // ---------------------------------------------------------------------------
906
+ // result-pattern-consistency
907
+ // ---------------------------------------------------------------------------
908
+ describe('result-pattern-consistency — branches', () => {
909
+ it('mixed Result and throws', async () => {
910
+ fx('src/svc/res.ts', [
911
+ 'type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }',
912
+ 'export function ok<T>(v: T): Result<T, never> { return { ok: true, value: v } }',
913
+ 'export function err<E>(e: E): Result<never, E> { return { ok: false, error: e } }',
914
+ 'export function viaResult(): Result<number, string> { return ok(1) }',
915
+ 'export function viaThrow(): number { throw new Error("oops") }',
916
+ 'export function mixedKind(x: number) {',
917
+ ' if (x < 0) return err("neg")',
918
+ ' if (x === 0) throw new Error("zero")',
919
+ ' return ok(x)',
920
+ '}',
921
+ ].join('\n'));
922
+ const result = await runCheck('result-pattern-consistency');
923
+ expect(result).toBeDefined();
924
+ });
925
+ });
926
+ // ---------------------------------------------------------------------------
927
+ // lifecycle-cleanup-enforcement
928
+ // ---------------------------------------------------------------------------
929
+ describe('lifecycle-cleanup-enforcement — branches', () => {
930
+ it('useEffect with and without cleanup', async () => {
931
+ fx('src/components/Eff.tsx', [
932
+ 'import { useEffect } from "react"',
933
+ 'export function A() {',
934
+ ' useEffect(() => {',
935
+ ' const id = setInterval(() => undefined, 100)',
936
+ ' return () => clearInterval(id)',
937
+ ' }, [])',
938
+ ' return null',
939
+ '}',
940
+ 'export function B() {',
941
+ ' useEffect(() => {',
942
+ ' setInterval(() => undefined, 100)',
943
+ ' }, [])',
944
+ ' return null',
945
+ '}',
946
+ 'export function C() {',
947
+ ' useEffect(() => {',
948
+ ' const sub = src.subscribe(() => undefined)',
949
+ ' return () => sub.unsubscribe()',
950
+ ' }, [])',
951
+ ' return null',
952
+ '}',
953
+ ].join('\n'));
954
+ const result = await runCheck('lifecycle-cleanup-enforcement');
955
+ expect(result).toBeDefined();
956
+ });
957
+ });
958
+ // ---------------------------------------------------------------------------
959
+ // openapi-response-coverage
960
+ // ---------------------------------------------------------------------------
961
+ // ---------------------------------------------------------------------------
962
+ // broad fixture — many checks
963
+ // ---------------------------------------------------------------------------
964
+ describe('broad fixture — many checks', () => {
965
+ it('exercises a wide-shape fixture across many files', async () => {
966
+ fx('package.json', JSON.stringify({
967
+ name: 'demo',
968
+ version: '1.0.0',
969
+ type: 'module',
970
+ main: './dist/index.js',
971
+ types: './dist/index.d.ts',
972
+ exports: { '.': { import: './dist/index.js', types: './dist/index.d.ts' } },
973
+ dependencies: { 'drizzle-orm': '^0.30.0', react: '^18.0.0', 'typed-inject': '^4.0.0' },
974
+ }, null, 2));
975
+ fx('tsconfig.json', JSON.stringify({
976
+ extends: './tsconfig.base.json',
977
+ compilerOptions: { target: 'es2022', module: 'esnext', strict: true },
978
+ include: ['src/**/*'],
979
+ }, null, 2));
980
+ fx('tsconfig.base.json', JSON.stringify({ compilerOptions: { strict: true } }, null, 2));
981
+ fx('src/index.ts', 'export * from "./svc.js"');
982
+ fx('src/svc.ts', [
983
+ 'export interface UserRequest { id: string }',
984
+ 'export interface UserResponse { ok: boolean }',
985
+ 'export type UserDTO = { id: string }',
986
+ 'export interface ApiUserList { users: UserDTO[] }',
987
+ 'export async function getUsers(req: UserRequest): Promise<UserResponse> {',
988
+ ' if (!req.id) return { ok: false }',
989
+ ' try { return { ok: true } } catch (e) { return { ok: false } }',
990
+ '}',
991
+ ].join('\n'));
992
+ fx('src/observability/m.ts', [
993
+ 'export function record(name: string, value: number) {',
994
+ ' // no logger here',
995
+ ' return { name, value }',
996
+ '}',
997
+ ].join('\n'));
998
+ fx('src/observability/with.ts', [
999
+ 'import logger from "./logger.js"',
1000
+ 'export function recordLogged(name: string, value: number) {',
1001
+ ' logger.info({ event: "metric.recorded", name, value })',
1002
+ ' return { name, value }',
1003
+ '}',
1004
+ ].join('\n'));
1005
+ fx('src/observability/logger.ts', [
1006
+ 'export const logger = {',
1007
+ ' info: (..._args: unknown[]) => undefined,',
1008
+ ' warn: (..._args: unknown[]) => undefined,',
1009
+ ' error: (..._args: unknown[]) => undefined,',
1010
+ ' child: () => logger,',
1011
+ '}',
1012
+ 'export default logger',
1013
+ ].join('\n'));
1014
+ // Run a handful of checks to exercise broader branches.
1015
+ const slugs = [
1016
+ 'detached-promises',
1017
+ 'no-unbounded-concurrency',
1018
+ 'no-raw-fetch',
1019
+ 'array-validation',
1020
+ 'numeric-validation',
1021
+ 'null-safety',
1022
+ 'incomplete-regex-escaping',
1023
+ 'missing-input-validation',
1024
+ 'fastify-route-validation',
1025
+ 'api-contract-validation',
1026
+ 'api-response-validation',
1027
+ 'silent-early-returns',
1028
+ 'throws-documentation',
1029
+ 'error-handling-quality',
1030
+ 'logger-event-name-format',
1031
+ 'pii-exposure-in-logs',
1032
+ 'sql-injection',
1033
+ 'unsafe-secret-comparison',
1034
+ 'input-sanitization',
1035
+ 'no-any-types',
1036
+ 'duplicate-utility-functions',
1037
+ 'stubbed-implementation-detection',
1038
+ 'missing-type-exports',
1039
+ 'toctou-race-condition',
1040
+ 'lifecycle-cleanup-enforcement',
1041
+ 'dispose-pattern-completeness',
1042
+ 'stream-buffer-size-limits',
1043
+ 'result-pattern-consistency',
1044
+ 'database-schema-validation',
1045
+ 'database-index-coverage',
1046
+ 'in-memory-repository-detection',
1047
+ ];
1048
+ for (const slug of slugs) {
1049
+ const result = await runCheck(slug);
1050
+ expect(result).toBeDefined();
1051
+ }
1052
+ });
1053
+ });
1054
+ // ---------------------------------------------------------------------------
1055
+ // path-matching utility — exercise both string and regex branches
1056
+ // ---------------------------------------------------------------------------
1057
+ describe('path-matching utility — branches', () => {
1058
+ it('exercises string includes and regex test patterns', async () => {
1059
+ const { createPathMatcher } = await import('@opensip-cli/fitness');
1060
+ const stringOnly = createPathMatcher(['/__tests__/']);
1061
+ expect(stringOnly('/src/__tests__/foo.ts')).toBe(true);
1062
+ expect(stringOnly('/src/main.ts')).toBe(false);
1063
+ const regexOnly = createPathMatcher([/\.test\.ts$/]);
1064
+ expect(regexOnly('foo.test.ts')).toBe(true);
1065
+ expect(regexOnly('foo.ts')).toBe(false);
1066
+ const mixed = createPathMatcher(['/dist/', /node_modules/]);
1067
+ expect(mixed('/proj/dist/x.js')).toBe(true);
1068
+ expect(mixed('/proj/node_modules/lib/index.js')).toBe(true);
1069
+ expect(mixed('/proj/src/x.ts')).toBe(false);
1070
+ });
1071
+ });
1072
+ //# sourceMappingURL=branch-fixtures.test.js.map