@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,766 @@
1
+ // @fitness-ignore-file file-length-limit -- cohesive single-check module; splitting risks breaking the detector contract
2
+ /**
3
+ * @fileoverview Null/Undefined Safety Check
4
+ *
5
+ * Detects unsafe property and method access without null checks.
6
+ */
7
+ import { defineCheck, getCheckConfig, isTestFile } from '@opensip-cli/fitness';
8
+ import { getSharedSourceFile } from '@opensip-cli/lang-typescript';
9
+ import * as ts from 'typescript';
10
+ /**
11
+ * Patterns that indicate the access is already protected
12
+ */
13
+ const SAFE_PATTERNS = [
14
+ /\?\./, // Optional chaining
15
+ /!!/, // Double negation
16
+ /\?\?/, // Nullish coalescing
17
+ /if\s*\(/, // Conditional check
18
+ /&&/, // Logical AND guard
19
+ ];
20
+ /**
21
+ * Known builder pattern libraries whose method calls always return non-null objects.
22
+ * These are safe because the library design guarantees non-null returns.
23
+ */
24
+ const SAFE_BUILDER_PREFIXES = [
25
+ 'z.', // Zod schema builder (z.string(), z.object(), etc.)
26
+ 'createQueryBuilder', // TypeORM QueryBuilder
27
+ 'getRepository', // TypeORM Repository
28
+ 'EntityManager.', // TypeORM EntityManager
29
+ 'queryBuilder.', // TypeORM QueryBuilder variable
30
+ 'repository.', // TypeORM Repository variable
31
+ 'builder.', // Generic builder pattern
32
+ 'Result.', // Result pattern builder
33
+ 'ResultAsync.', // neverthrow ResultAsync
34
+ 'ErrorBuilder', // Error builder fluent chain
35
+ 'EscrowManagementErrorBuilder', // Escrow error builder
36
+ 'I18nErrorBuilder', // I18n error builder
37
+ 'Object.entries', // Always returns array
38
+ 'Object.values', // Always returns array
39
+ 'Object.keys', // Always returns string array
40
+ 'Object.assign', // Always returns object
41
+ 'Object.freeze', // Always returns object
42
+ 'Array.from', // Always returns array
43
+ 'Array.isArray', // Returns boolean
44
+ 'String(', // String constructor always returns string
45
+ 'Number(', // Number constructor always returns number
46
+ 'Boolean(', // Boolean constructor always returns boolean
47
+ 'Buffer.from', // Always returns Buffer
48
+ 'JSON.stringify', // Always returns string
49
+ 'JSON.parse', // Always returns value
50
+ 'process.memoryUsage', // Always returns MemoryUsage
51
+ 'getTypedEventBus', // Singleton factory always returns non-null
52
+ 'res.status', // Express/Fastify response chaining
53
+ 'response.status', // Express/Fastify response chaining
54
+ // better-sqlite3 (prepare always returns Statement)
55
+ 'prepare(', // db.prepare() always returns Statement object
56
+ // Drizzle ORM
57
+ 'drizzle(', // Drizzle instance creation
58
+ 'db.select', // Drizzle query builder
59
+ 'db.insert', // Drizzle query builder
60
+ 'db.update', // Drizzle query builder
61
+ 'db.delete', // Drizzle query builder
62
+ // TypeScript compiler API (always return valid objects)
63
+ 'sourceFile.getLineAndCharacterOfPosition',
64
+ 'node.getText',
65
+ 'node.getStart',
66
+ 'node.getEnd',
67
+ 'node.getWidth',
68
+ 'node.getFullWidth',
69
+ // Browser APIs with guaranteed non-null returns
70
+ 'window.matchMedia',
71
+ 'document.createElement',
72
+ 'document.createTextNode',
73
+ // Singleton factories that throw on failure (never return null)
74
+ 'getContextManager',
75
+ 'getCredentialConfig',
76
+ 'getLogger',
77
+ // Custom builder patterns
78
+ 'ScenarioResultBuilder.',
79
+ 'ResultBuilder.',
80
+ 'CheckResultBuilder.',
81
+ // Node.js URL helpers (always return a URL/string)
82
+ 'pathToFileURL(',
83
+ 'fileURLToPath(',
84
+ // new URL(...) constructor — returns URL or throws
85
+ 'new URL(',
86
+ // Node.js child_process (spawn always returns ChildProcess or throws)
87
+ 'spawn(',
88
+ 'fork(',
89
+ // Node.js crypto (createHash/createHmac always return Hash/Hmac)
90
+ 'createHash(',
91
+ 'createHmac(',
92
+ 'createCipheriv(',
93
+ 'createDecipheriv(',
94
+ // Intl formatters (always return formatter instances)
95
+ 'getNumberFormatter',
96
+ 'getDateFormatter',
97
+ 'new Intl.',
98
+ 'Intl.NumberFormat',
99
+ 'Intl.DateTimeFormat',
100
+ // Project-specific safe functions (always return non-null)
101
+ 'loadConfig',
102
+ 'getConfig',
103
+ 'getTenantId',
104
+ 'getDatabase',
105
+ 'getSqlite',
106
+ 'getRegistry',
107
+ 'getSync',
108
+ 'formatRelative',
109
+ 'stripThinkTags',
110
+ 'getStatus',
111
+ 'ensureError',
112
+ 'extractErrorMessage',
113
+ ];
114
+ /**
115
+ * Known safe method names in fluent APIs that always return `this` or non-null values.
116
+ */
117
+ const SAFE_FLUENT_METHODS = new Set([
118
+ // Promise methods
119
+ 'then',
120
+ 'catch',
121
+ 'finally',
122
+ // Array methods (iteration)
123
+ 'map',
124
+ 'filter',
125
+ 'reduce',
126
+ 'flatMap',
127
+ 'forEach',
128
+ 'some',
129
+ 'every',
130
+ 'find',
131
+ 'findIndex',
132
+ 'findLast',
133
+ 'findLastIndex',
134
+ 'includes',
135
+ 'indexOf',
136
+ 'lastIndexOf',
137
+ 'at',
138
+ 'flat',
139
+ 'entries',
140
+ 'keys',
141
+ 'values',
142
+ // Array methods (mutation/creation)
143
+ 'slice',
144
+ 'concat',
145
+ 'sort',
146
+ 'reverse',
147
+ 'join',
148
+ 'push',
149
+ 'pop',
150
+ 'shift',
151
+ 'unshift',
152
+ 'fill',
153
+ // String methods
154
+ 'trim',
155
+ 'trimStart',
156
+ 'trimEnd',
157
+ 'toLowerCase',
158
+ 'toUpperCase',
159
+ 'toLocaleLowerCase',
160
+ 'toLocaleUpperCase',
161
+ 'split',
162
+ 'replace',
163
+ 'replaceAll',
164
+ 'substring',
165
+ 'substr',
166
+ 'slice',
167
+ 'padStart',
168
+ 'padEnd',
169
+ 'charAt',
170
+ 'charCodeAt',
171
+ 'startsWith',
172
+ 'endsWith',
173
+ 'match',
174
+ 'search',
175
+ 'normalize',
176
+ 'repeat',
177
+ // Iterator methods
178
+ 'next',
179
+ // Buffer methods
180
+ 'toString',
181
+ // HTTP response chaining (Express/Fastify)
182
+ 'json',
183
+ 'send',
184
+ 'status',
185
+ 'header',
186
+ 'type',
187
+ 'code',
188
+ // TypeORM QueryBuilder fluent methods
189
+ 'where',
190
+ 'andWhere',
191
+ 'orWhere',
192
+ 'having',
193
+ 'orderBy',
194
+ 'addOrderBy',
195
+ 'groupBy',
196
+ 'addGroupBy',
197
+ 'select',
198
+ 'addSelect',
199
+ 'leftJoin',
200
+ 'leftJoinAndSelect',
201
+ 'innerJoin',
202
+ 'innerJoinAndSelect',
203
+ 'limit',
204
+ 'offset',
205
+ 'skip',
206
+ 'take',
207
+ 'getOne',
208
+ 'getMany',
209
+ 'getRawOne',
210
+ 'getRawMany',
211
+ 'execute',
212
+ // Result/Option pattern methods
213
+ 'map',
214
+ 'mapErr',
215
+ 'andThen',
216
+ 'orElse',
217
+ 'unwrapOr',
218
+ 'match',
219
+ // Builder pattern methods
220
+ 'set',
221
+ 'with',
222
+ 'withId',
223
+ 'withCode',
224
+ 'withMessage',
225
+ 'withDetails',
226
+ 'withContext',
227
+ 'withCause',
228
+ 'build',
229
+ 'add',
230
+ 'remove',
231
+ 'update',
232
+ 'delete',
233
+ 'insert',
234
+ // Event bus / subscription methods
235
+ 'subscribe',
236
+ 'unsubscribe',
237
+ 'emit',
238
+ 'on',
239
+ 'off',
240
+ 'once',
241
+ // Pino logger methods (return this)
242
+ 'child',
243
+ 'bindings',
244
+ 'level',
245
+ 'info',
246
+ 'warn',
247
+ 'error',
248
+ 'debug',
249
+ 'trace',
250
+ 'fatal',
251
+ // Drizzle ORM column builder methods (always return updated column definition)
252
+ 'notNull',
253
+ 'default',
254
+ 'references',
255
+ 'primaryKey',
256
+ 'unique',
257
+ '$default',
258
+ '$onUpdate',
259
+ // Drizzle ORM query methods
260
+ 'from',
261
+ 'where',
262
+ 'returning',
263
+ 'onConflictDoNothing',
264
+ 'onConflictDoUpdate',
265
+ 'innerJoin',
266
+ 'leftJoin',
267
+ 'rightJoin',
268
+ 'fullJoin',
269
+ // better-sqlite3 Statement methods (always return valid results)
270
+ 'run',
271
+ 'all',
272
+ 'get',
273
+ 'pluck',
274
+ 'iterate',
275
+ 'bind',
276
+ 'columns',
277
+ 'expand',
278
+ // TypeScript compiler API methods (always return valid objects)
279
+ 'getLineAndCharacterOfPosition',
280
+ 'getText',
281
+ 'getStart',
282
+ 'getEnd',
283
+ 'getWidth',
284
+ 'getFullWidth',
285
+ 'getSourceFile',
286
+ 'getChildAt',
287
+ 'getChildren',
288
+ 'getFirstToken',
289
+ 'getLastToken',
290
+ 'forEachChild',
291
+ // Map/Set methods
292
+ 'get',
293
+ 'set',
294
+ 'has',
295
+ 'delete',
296
+ 'clear',
297
+ 'size',
298
+ // Singleton/factory return methods
299
+ 'getInstance',
300
+ 'create',
301
+ 'of',
302
+ // Immutable-combinator methods — return a new non-null value built from
303
+ // the receiver (e.g. OTel `Resource.merge`, Immutable.js `.merge`,
304
+ // builder `.concat`/`.assign`). The chain result is never null.
305
+ 'merge',
306
+ 'mergeWith',
307
+ // Vitest/Jest assertion methods (expect() always returns Assertion object)
308
+ 'toBe',
309
+ 'toEqual',
310
+ 'toStrictEqual',
311
+ 'toBeDefined',
312
+ 'toBeUndefined',
313
+ 'toBeNull',
314
+ 'toBeTruthy',
315
+ 'toBeFalsy',
316
+ 'toBeGreaterThan',
317
+ 'toBeGreaterThanOrEqual',
318
+ 'toBeLessThan',
319
+ 'toBeLessThanOrEqual',
320
+ 'toBeCloseTo',
321
+ 'toBeInstanceOf',
322
+ 'toBeNaN',
323
+ 'toContain',
324
+ 'toContainEqual',
325
+ 'toHaveLength',
326
+ 'toHaveProperty',
327
+ 'toHaveBeenCalled',
328
+ 'toHaveBeenCalledTimes',
329
+ 'toHaveBeenCalledWith',
330
+ 'toHaveBeenLastCalledWith',
331
+ 'toHaveBeenNthCalledWith',
332
+ 'toHaveReturned',
333
+ 'toHaveReturnedTimes',
334
+ 'toHaveReturnedWith',
335
+ 'toHaveLastReturnedWith',
336
+ 'toHaveNthReturnedWith',
337
+ 'toThrow',
338
+ 'toThrowError',
339
+ 'toMatch',
340
+ 'toMatchObject',
341
+ 'toMatchSnapshot',
342
+ 'toMatchInlineSnapshot',
343
+ 'resolves',
344
+ 'rejects',
345
+ 'not',
346
+ // Vitest/Jest mock methods (vi.fn() always returns Mock object)
347
+ 'mockResolvedValue',
348
+ 'mockResolvedValueOnce',
349
+ 'mockRejectedValue',
350
+ 'mockRejectedValueOnce',
351
+ 'mockReturnValue',
352
+ 'mockReturnValueOnce',
353
+ 'mockImplementation',
354
+ 'mockImplementationOnce',
355
+ 'mockClear',
356
+ 'mockReset',
357
+ 'mockRestore',
358
+ 'mockReturnThis',
359
+ 'mockName',
360
+ // Node.js crypto Hash/Hmac fluent methods (always return this or string)
361
+ 'update',
362
+ 'digest',
363
+ 'final',
364
+ // Node.js ChildProcess methods (always exist on ChildProcess)
365
+ 'unref',
366
+ 'ref',
367
+ 'kill',
368
+ // Intl formatter methods (always return formatted string)
369
+ 'format',
370
+ 'formatToParts',
371
+ 'resolvedOptions',
372
+ // neverthrow Result methods (safe after isOk/isErr guard)
373
+ 'unwrapOr',
374
+ 'unwrapErr',
375
+ '_unsafeUnwrap',
376
+ '_unsafeUnwrapErr',
377
+ // typed-inject Injector chain — every .provide* call returns a new Injector<T>, never null
378
+ 'provideValue',
379
+ 'provideClass',
380
+ 'provideFactory',
381
+ 'provide',
382
+ // Drizzle column builder — column.$type<T>() always returns the same column reference
383
+ '$type',
384
+ // Commander.js Command builder — every chained method returns the Command instance
385
+ 'command',
386
+ 'description',
387
+ 'option',
388
+ 'requiredOption',
389
+ 'action',
390
+ 'argument',
391
+ 'version',
392
+ 'name',
393
+ 'alias',
394
+ 'aliases',
395
+ 'addCommand',
396
+ 'addOption',
397
+ 'addArgument',
398
+ 'hook',
399
+ 'usage',
400
+ 'summary',
401
+ 'helpOption',
402
+ 'addHelpText',
403
+ 'showHelpAfterError',
404
+ 'showSuggestionAfterError',
405
+ 'exitOverride',
406
+ 'configureOutput',
407
+ 'configureHelp',
408
+ 'allowExcessArguments',
409
+ 'allowUnknownOption',
410
+ 'enablePositionalOptions',
411
+ 'passThroughOptions',
412
+ 'storeOptionsAsProperties',
413
+ 'copyInheritedSettings',
414
+ 'combineFlagAndOptionalValue',
415
+ ]);
416
+ /**
417
+ * Common method name prefixes that indicate safe (non-null) return values.
418
+ * Methods starting with these prefixes are conventionally designed to always
419
+ * return a value or throw, never return null/undefined.
420
+ */
421
+ const SAFE_METHOD_PREFIXES = [
422
+ 'get',
423
+ 'set',
424
+ 'is',
425
+ 'has',
426
+ 'to',
427
+ 'with',
428
+ 'from',
429
+ 'of',
430
+ 'create',
431
+ 'build',
432
+ 'add',
433
+ 'remove',
434
+ 'update',
435
+ 'delete',
436
+ 'find',
437
+ 'load',
438
+ 'save',
439
+ 'parse',
440
+ 'format',
441
+ 'validate',
442
+ 'check',
443
+ 'resolve',
444
+ 'register',
445
+ 'unregister',
446
+ // Reading conventions (returns a value or throws — never null)
447
+ 'read',
448
+ 'open',
449
+ 'compute',
450
+ 'make',
451
+ 'render',
452
+ 'ensure',
453
+ // Functional conventions — pure transforms / current-scope accessors that
454
+ // always return a value (never null). Matches helpers like `classifyCatalog`,
455
+ // `filterContent`, `currentScenarioRegistry`, `pickAdapter`.
456
+ 'classify',
457
+ 'filter',
458
+ 'current',
459
+ 'pick',
460
+ 'select',
461
+ ];
462
+ /**
463
+ * Check if a call expression is a known safe builder pattern.
464
+ *
465
+ * Two paths:
466
+ * 1. Explicit allowlist (`SAFE_BUILDER_PREFIXES`) — exact-prefix match on the
467
+ * full call text (e.g. `z.string(`, `pathToFileURL(`).
468
+ * 2. Convention heuristic — when the callee is a bare identifier whose name
469
+ * starts with a recognised safe verb (`get*`, `read*`, `resolve*`,
470
+ * `current*`, `create*`, `build*`, etc.). This is the same convention that
471
+ * already covers fluent-chain methods via `isSafeFluentMethod`; applying it
472
+ * to standalone calls closes the gap for helpers like `resolveProjectPaths`,
473
+ * `readScope`, `currentScenarioRegistry`, etc. whose names convey the same
474
+ * "returns a value or throws" contract.
475
+ */
476
+ function isSafeBuilderPattern(expression, sourceFile) {
477
+ const text = expression.getText(sourceFile);
478
+ if (SAFE_BUILDER_PREFIXES.some((prefix) => text.startsWith(prefix)))
479
+ return true;
480
+ if (ts.isIdentifier(expression.expression)) {
481
+ return isSafeFluentMethod(expression.expression.text);
482
+ }
483
+ return false;
484
+ }
485
+ /**
486
+ * Check if a method name is a known safe fluent API method.
487
+ * Matches either an exact entry in SAFE_FLUENT_METHODS or a method whose name
488
+ * starts with a common safe prefix (get, set, is, has, to, etc.).
489
+ */
490
+ function isSafeFluentMethod(methodName) {
491
+ if (SAFE_FLUENT_METHODS.has(methodName))
492
+ return true;
493
+ return SAFE_METHOD_PREFIXES.some((prefix) => methodName.startsWith(prefix));
494
+ }
495
+ /**
496
+ * Walk ancestors to find an enclosing truthiness guard whose condition
497
+ * references the access's base expression — an `if (...)`, a `cond ? … : …`,
498
+ * or the left side of a `&&` chain (e.g. `if (candidates.length === 1 &&
499
+ * candidates[0]) { … candidates[0].bodyHash … }`).
500
+ *
501
+ * The line-local {@link SAFE_PATTERNS} scan only inspects the physical line
502
+ * of the access, so a guard placed on a *previous* line is missed. This
503
+ * closes that cross-line gap. Substring matching is intentionally lenient:
504
+ * the check errs toward treating a guarded access as safe (fewer false
505
+ * positives), consistent with the existing line-local guard handling.
506
+ */
507
+ function isGuardedByEnclosingCondition(node, sourceFile) {
508
+ const baseText = node.expression.getText(sourceFile);
509
+ let current = node;
510
+ let parent = node.parent;
511
+ while (parent) {
512
+ if (ts.isIfStatement(parent) && parent.expression.getText(sourceFile).includes(baseText)) {
513
+ return true;
514
+ }
515
+ if (ts.isConditionalExpression(parent) &&
516
+ parent.condition.getText(sourceFile).includes(baseText)) {
517
+ return true;
518
+ }
519
+ if (ts.isBinaryExpression(parent) &&
520
+ parent.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken &&
521
+ parent.right === current &&
522
+ parent.left.getText(sourceFile).includes(baseText)) {
523
+ return true;
524
+ }
525
+ current = parent;
526
+ parent = parent.parent;
527
+ }
528
+ return false;
529
+ }
530
+ /**
531
+ * Check if a property access originates from `this`.
532
+ * Accessing properties on `this` is always safe — the object exists within its own methods.
533
+ */
534
+ function isThisAccess(node) {
535
+ let current = node.expression;
536
+ while (ts.isCallExpression(current) || ts.isPropertyAccessExpression(current)) {
537
+ current = current.expression;
538
+ }
539
+ return current.kind === ts.SyntaxKind.ThisKeyword;
540
+ }
541
+ /**
542
+ * Count the depth of a method chain (number of chained property accesses / calls).
543
+ * e.g. `a.b().c().d` has depth 3.
544
+ */
545
+ function getChainDepth(node) {
546
+ let depth = 0;
547
+ let current = node.expression;
548
+ while (ts.isCallExpression(current) || ts.isPropertyAccessExpression(current)) {
549
+ if (ts.isCallExpression(current)) {
550
+ depth++;
551
+ current = current.expression;
552
+ }
553
+ else {
554
+ current = current.expression;
555
+ }
556
+ }
557
+ return depth;
558
+ }
559
+ /**
560
+ * Check if a property access chain is on a Zod method call
561
+ * Handles chained calls like z.string().min(1).optional()
562
+ */
563
+ function isZodBuilderChain(node, sourceFile) {
564
+ // Walk the full expression chain to find if it originates from z.xxx()
565
+ // Handles arbitrary depth: z.string().regex().optional().superRefine().pipe()
566
+ let current = node.expression;
567
+ while (current) {
568
+ if (ts.isCallExpression(current)) {
569
+ const result = checkZodCallExpression(current, sourceFile);
570
+ if (result.resolved)
571
+ return result.isZod;
572
+ current = result.next;
573
+ continue;
574
+ }
575
+ if (ts.isPropertyAccessExpression(current)) {
576
+ if (current.expression.getText(sourceFile) === 'z')
577
+ return true;
578
+ current = current.expression;
579
+ continue;
580
+ }
581
+ if (ts.isIdentifier(current)) {
582
+ return current.text === 'z';
583
+ }
584
+ break;
585
+ }
586
+ return false;
587
+ }
588
+ /** Check if a call expression callee originates from z.xxx() */
589
+ function checkZodCallExpression(node, sourceFile) {
590
+ const callee = node.expression;
591
+ if (ts.isPropertyAccessExpression(callee)) {
592
+ if (callee.getText(sourceFile).startsWith('z.'))
593
+ return { resolved: true, isZod: true };
594
+ return { resolved: false, next: callee.expression };
595
+ }
596
+ if (ts.isIdentifier(callee)) {
597
+ return { resolved: true, isZod: callee.text === 'z' };
598
+ }
599
+ return { resolved: false, next: callee };
600
+ }
601
+ /**
602
+ * Check if a property access is part of a fluent API chain
603
+ * Handles patterns like promise.then().catch() or queryBuilder.where().orderBy()
604
+ */
605
+ function isFluentChain(node) {
606
+ const expression = node.expression;
607
+ // Check if we're accessing a property on a call expression
608
+ if (!ts.isCallExpression(expression))
609
+ return false;
610
+ // Walk the chain — if ANY method in the chain is a known fluent method, the chain is safe
611
+ let current = expression;
612
+ while (ts.isCallExpression(current)) {
613
+ if (ts.isPropertyAccessExpression(current.expression)) {
614
+ const methodName = current.expression.name.text;
615
+ if (isSafeFluentMethod(methodName)) {
616
+ return true;
617
+ }
618
+ // Walk deeper into the chain
619
+ current = current.expression.expression;
620
+ continue;
621
+ }
622
+ break;
623
+ }
624
+ return false;
625
+ }
626
+ /**
627
+ * Path patterns where null-safety findings are dominated by safe-by-construction
628
+ * builders that the AST analyzer cannot fully resolve:
629
+ *
630
+ * - `**\/di/fragment.ts`, `**\/di/fragments/*.ts` — typed-inject Injector chains
631
+ * (`.provideValue/.provideClass/...` always return Injector<T>); the chain
632
+ * is split across many lines so the AST chain-depth heuristic does not always
633
+ * apply. The whole-file safe-list captures the convention.
634
+ * - `**\/schema/*.ts`, `**\/*-schema.ts`, `**\/dbos/schema*.ts` — Drizzle/Zod
635
+ * schema declarations are pure column/shape builders. No runtime null-access
636
+ * surface to protect.
637
+ */
638
+ const SAFE_NULL_PATHS = [
639
+ /\/di\/fragment\.ts$/,
640
+ /\/di\/fragments\//,
641
+ /\/schema\//,
642
+ /-schema\.ts$/,
643
+ // NOTE: opensip's `/dbos/schema` path is NOT a default. DBOS is a
644
+ // published library, but the path layout is opensip's convention. It
645
+ // lives in opensip's recipe under
646
+ // `checks.config['null-safety'].additionalSafeNullPaths`.
647
+ ];
648
+ /** Merge built-in defaults with the recipe-config slice. */
649
+ function buildEffectiveSafePaths() {
650
+ const cfg = getCheckConfig('null-safety');
651
+ const extras = (cfg.additionalSafeNullPaths ?? []).map((src) => new RegExp(src, 'i'));
652
+ return [...SAFE_NULL_PATHS, ...extras];
653
+ }
654
+ function isSafeNullPath(filePath, paths) {
655
+ return paths.some((p) => p.test(filePath));
656
+ }
657
+ /**
658
+ * @param {*} content
659
+ * @param {*} filePath
660
+ * @returns {*}
661
+ * Analyze a file for null safety issues. Exported for the FP-regression
662
+ * suite (see `__tests__/null-safety-fp.test.ts`).
663
+ */
664
+ export function analyzeNullSafety(content, filePath) {
665
+ const violations = [];
666
+ // Skip safe-by-construction path families (DI fragments + schema declarations).
667
+ // Built-in defaults are merged with the recipe-config slice once per file.
668
+ const safePaths = buildEffectiveSafePaths();
669
+ if (isSafeNullPath(filePath, safePaths))
670
+ return violations;
671
+ try {
672
+ const sourceFile = getSharedSourceFile(filePath, content);
673
+ if (!sourceFile)
674
+ return [];
675
+ const visit = (node) => {
676
+ ts.forEachChild(node, visit);
677
+ // Only check property access expressions that aren't optional chains
678
+ if (!ts.isPropertyAccessExpression(node) || ts.isOptionalChain(node))
679
+ return;
680
+ const expression = node.expression;
681
+ // Only flag call expressions or element access (potentially nullable)
682
+ if (!ts.isCallExpression(expression) && !ts.isElementAccessExpression(expression))
683
+ return;
684
+ // Skip property access on `this` — the object always exists in its own methods
685
+ if (isThisAccess(node))
686
+ return;
687
+ // Skip method chains longer than 2 — fluent APIs are designed to return non-null
688
+ if (getChainDepth(node) > 2)
689
+ return;
690
+ // Skip Zod builder pattern chains (z.string().min(1).optional())
691
+ if (isZodBuilderChain(node, sourceFile))
692
+ return;
693
+ // Skip known safe builder patterns
694
+ if (ts.isCallExpression(expression) && isSafeBuilderPattern(expression, sourceFile))
695
+ return;
696
+ // Skip fluent API chains (promise.then().catch(), queryBuilder.where().orderBy())
697
+ if (isFluentChain(node))
698
+ return;
699
+ const propName = node.name.text;
700
+ // Skip if accessing a known safe fluent method
701
+ if (isSafeFluentMethod(propName))
702
+ return;
703
+ const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
704
+ const lineText = content.split('\n')[line] ?? '';
705
+ // Skip if line has safety patterns
706
+ if (SAFE_PATTERNS.some((p) => p.test(lineText)))
707
+ return;
708
+ // Skip if guarded by an enclosing if / ternary / && condition on a
709
+ // previous line (the line-local scan above only sees this line).
710
+ if (isGuardedByEnclosingCondition(node, sourceFile))
711
+ return;
712
+ // Skip common safe cases
713
+ if (['length', 'toString', 'valueOf'].includes(propName))
714
+ return;
715
+ const lineNum = line + 1;
716
+ const matchText = node.getText(sourceFile);
717
+ violations.push({
718
+ line: lineNum,
719
+ column: character + 1,
720
+ message: `Potentially unsafe property access '.${propName}' without null check`,
721
+ severity: 'warning',
722
+ type: 'unsafe-access',
723
+ suggestion: `Use optional chaining: change '.${propName}' to '?.${propName}', or add an explicit null/undefined check before accessing the property`,
724
+ match: matchText,
725
+ });
726
+ };
727
+ visit(sourceFile);
728
+ }
729
+ catch {
730
+ // @swallow-ok Skip files that fail to parse
731
+ }
732
+ return violations;
733
+ }
734
+ /**
735
+ * Check: quality/null-safety
736
+ *
737
+ * Detects unsafe property and method access without null checks.
738
+ */
739
+ export const nullSafety = defineCheck({
740
+ id: '011c993e-829b-4423-8032-0b7c9baa22bf',
741
+ slug: 'null-safety',
742
+ scope: { languages: ['typescript'], concerns: ['backend', 'frontend', 'cli'] },
743
+ contentFilter: 'strip-strings',
744
+ confidence: 'high',
745
+ description: 'Detect unsafe property and method access without null checks',
746
+ longDescription: `**Purpose:** Detects property access on potentially nullable expressions (call results, element access) that lack null/undefined guards, preventing runtime \`TypeError\` crashes.
747
+
748
+ **Detects:**
749
+ - Property access (\`.foo\`) on call expression or element access results without optional chaining (\`?.\`), nullish coalescing (\`??\`), \`&&\` guards, or \`if\` checks
750
+ - Skips known safe patterns: Zod builder chains (\`z.string().min()\`), TypeORM QueryBuilder fluent chains, Promise \`.then().catch()\`, Result pattern methods, and Pino logger chains
751
+ - Skips safe property names: \`length\`, \`toString\`, \`valueOf\`
752
+ - Excludes contracts, schemas, types, CLI/internal tools, and foundation infrastructure files
753
+
754
+ **Why it matters:** Accessing a property on a \`null\` or \`undefined\` value causes runtime \`TypeError\` exceptions that crash the process if uncaught.
755
+
756
+ **Scope:** General best practice. Analyzes each file individually.`,
757
+ tags: ['quality', 'code-quality', 'type-safety'],
758
+ fileTypes: ['ts', 'tsx'],
759
+ analyze(content, filePath) {
760
+ // Skip test files — null safety in tests is low-risk due to controlled inputs
761
+ if (isTestFile(filePath))
762
+ return [];
763
+ return analyzeNullSafety(content, filePath);
764
+ },
765
+ });
766
+ //# sourceMappingURL=null-safety.js.map