@opensip-tools/fitness 1.0.4

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 (461) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-typecheck.log +4 -0
  3. package/LICENSE +21 -0
  4. package/dist/__tests__/gate.test.d.ts +13 -0
  5. package/dist/__tests__/gate.test.d.ts.map +1 -0
  6. package/dist/__tests__/gate.test.js +422 -0
  7. package/dist/__tests__/gate.test.js.map +1 -0
  8. package/dist/__tests__/sarif.test.d.ts +2 -0
  9. package/dist/__tests__/sarif.test.d.ts.map +1 -0
  10. package/dist/__tests__/sarif.test.js +169 -0
  11. package/dist/__tests__/sarif.test.js.map +1 -0
  12. package/dist/cli/dashboard.d.ts +6 -0
  13. package/dist/cli/dashboard.d.ts.map +1 -0
  14. package/dist/cli/dashboard.js +77 -0
  15. package/dist/cli/dashboard.js.map +1 -0
  16. package/dist/cli/fit.d.ts +37 -0
  17. package/dist/cli/fit.d.ts.map +1 -0
  18. package/dist/cli/fit.js +539 -0
  19. package/dist/cli/fit.js.map +1 -0
  20. package/dist/cli/list-checks.d.ts +6 -0
  21. package/dist/cli/list-checks.d.ts.map +1 -0
  22. package/dist/cli/list-checks.js +23 -0
  23. package/dist/cli/list-checks.js.map +1 -0
  24. package/dist/cli/list-recipes.d.ts +6 -0
  25. package/dist/cli/list-recipes.d.ts.map +1 -0
  26. package/dist/cli/list-recipes.js +31 -0
  27. package/dist/cli/list-recipes.js.map +1 -0
  28. package/dist/framework/__tests__/ast-utilities.test.d.ts +2 -0
  29. package/dist/framework/__tests__/ast-utilities.test.d.ts.map +1 -0
  30. package/dist/framework/__tests__/ast-utilities.test.js +153 -0
  31. package/dist/framework/__tests__/ast-utilities.test.js.map +1 -0
  32. package/dist/framework/__tests__/check-config.test.d.ts +2 -0
  33. package/dist/framework/__tests__/check-config.test.d.ts.map +1 -0
  34. package/dist/framework/__tests__/check-config.test.js +56 -0
  35. package/dist/framework/__tests__/check-config.test.js.map +1 -0
  36. package/dist/framework/__tests__/command-executor.test.d.ts +2 -0
  37. package/dist/framework/__tests__/command-executor.test.d.ts.map +1 -0
  38. package/dist/framework/__tests__/command-executor.test.js +71 -0
  39. package/dist/framework/__tests__/command-executor.test.js.map +1 -0
  40. package/dist/framework/__tests__/content-filter-dispatch.test.d.ts +2 -0
  41. package/dist/framework/__tests__/content-filter-dispatch.test.d.ts.map +1 -0
  42. package/dist/framework/__tests__/content-filter-dispatch.test.js +104 -0
  43. package/dist/framework/__tests__/content-filter-dispatch.test.js.map +1 -0
  44. package/dist/framework/__tests__/content-filter.test.d.ts +2 -0
  45. package/dist/framework/__tests__/content-filter.test.d.ts.map +1 -0
  46. package/dist/framework/__tests__/content-filter.test.js +126 -0
  47. package/dist/framework/__tests__/content-filter.test.js.map +1 -0
  48. package/dist/framework/__tests__/define-check.test.d.ts +2 -0
  49. package/dist/framework/__tests__/define-check.test.d.ts.map +1 -0
  50. package/dist/framework/__tests__/define-check.test.js +155 -0
  51. package/dist/framework/__tests__/define-check.test.js.map +1 -0
  52. package/dist/framework/__tests__/directive-inventory.test.d.ts +2 -0
  53. package/dist/framework/__tests__/directive-inventory.test.d.ts.map +1 -0
  54. package/dist/framework/__tests__/directive-inventory.test.js +44 -0
  55. package/dist/framework/__tests__/directive-inventory.test.js.map +1 -0
  56. package/dist/framework/__tests__/execution-context.test.d.ts +2 -0
  57. package/dist/framework/__tests__/execution-context.test.d.ts.map +1 -0
  58. package/dist/framework/__tests__/execution-context.test.js +62 -0
  59. package/dist/framework/__tests__/execution-context.test.js.map +1 -0
  60. package/dist/framework/__tests__/file-accessor.test.d.ts +2 -0
  61. package/dist/framework/__tests__/file-accessor.test.d.ts.map +1 -0
  62. package/dist/framework/__tests__/file-accessor.test.js +106 -0
  63. package/dist/framework/__tests__/file-accessor.test.js.map +1 -0
  64. package/dist/framework/__tests__/file-cache.test.d.ts +2 -0
  65. package/dist/framework/__tests__/file-cache.test.d.ts.map +1 -0
  66. package/dist/framework/__tests__/file-cache.test.js +122 -0
  67. package/dist/framework/__tests__/file-cache.test.js.map +1 -0
  68. package/dist/framework/__tests__/import-graph.test.d.ts +15 -0
  69. package/dist/framework/__tests__/import-graph.test.d.ts.map +1 -0
  70. package/dist/framework/__tests__/import-graph.test.js +164 -0
  71. package/dist/framework/__tests__/import-graph.test.js.map +1 -0
  72. package/dist/framework/__tests__/path-matcher.test.d.ts +2 -0
  73. package/dist/framework/__tests__/path-matcher.test.d.ts.map +1 -0
  74. package/dist/framework/__tests__/path-matcher.test.js +113 -0
  75. package/dist/framework/__tests__/path-matcher.test.js.map +1 -0
  76. package/dist/framework/__tests__/register-helpers.test.d.ts +2 -0
  77. package/dist/framework/__tests__/register-helpers.test.d.ts.map +1 -0
  78. package/dist/framework/__tests__/register-helpers.test.js +42 -0
  79. package/dist/framework/__tests__/register-helpers.test.js.map +1 -0
  80. package/dist/framework/__tests__/registry.test.d.ts +2 -0
  81. package/dist/framework/__tests__/registry.test.d.ts.map +1 -0
  82. package/dist/framework/__tests__/registry.test.js +208 -0
  83. package/dist/framework/__tests__/registry.test.js.map +1 -0
  84. package/dist/framework/__tests__/result-builder.test.d.ts +2 -0
  85. package/dist/framework/__tests__/result-builder.test.d.ts.map +1 -0
  86. package/dist/framework/__tests__/result-builder.test.js +153 -0
  87. package/dist/framework/__tests__/result-builder.test.js.map +1 -0
  88. package/dist/framework/__tests__/scope-resolver.test.d.ts +2 -0
  89. package/dist/framework/__tests__/scope-resolver.test.d.ts.map +1 -0
  90. package/dist/framework/__tests__/scope-resolver.test.js +140 -0
  91. package/dist/framework/__tests__/scope-resolver.test.js.map +1 -0
  92. package/dist/framework/__tests__/severity-mapping.test.d.ts +2 -0
  93. package/dist/framework/__tests__/severity-mapping.test.d.ts.map +1 -0
  94. package/dist/framework/__tests__/severity-mapping.test.js +42 -0
  95. package/dist/framework/__tests__/severity-mapping.test.js.map +1 -0
  96. package/dist/framework/__tests__/strip-literals.test.d.ts +2 -0
  97. package/dist/framework/__tests__/strip-literals.test.d.ts.map +1 -0
  98. package/dist/framework/__tests__/strip-literals.test.js +87 -0
  99. package/dist/framework/__tests__/strip-literals.test.js.map +1 -0
  100. package/dist/framework/abortable-exec.d.ts +34 -0
  101. package/dist/framework/abortable-exec.d.ts.map +1 -0
  102. package/dist/framework/abortable-exec.js +136 -0
  103. package/dist/framework/abortable-exec.js.map +1 -0
  104. package/dist/framework/ast-utilities.d.ts +41 -0
  105. package/dist/framework/ast-utilities.d.ts.map +1 -0
  106. package/dist/framework/ast-utilities.js +106 -0
  107. package/dist/framework/ast-utilities.js.map +1 -0
  108. package/dist/framework/check-config.d.ts +171 -0
  109. package/dist/framework/check-config.d.ts.map +1 -0
  110. package/dist/framework/check-config.js +114 -0
  111. package/dist/framework/check-config.js.map +1 -0
  112. package/dist/framework/check-types.d.ts +57 -0
  113. package/dist/framework/check-types.d.ts.map +1 -0
  114. package/dist/framework/check-types.js +35 -0
  115. package/dist/framework/check-types.js.map +1 -0
  116. package/dist/framework/command-executor.d.ts +25 -0
  117. package/dist/framework/command-executor.d.ts.map +1 -0
  118. package/dist/framework/command-executor.js +63 -0
  119. package/dist/framework/command-executor.js.map +1 -0
  120. package/dist/framework/constants.d.ts +9 -0
  121. package/dist/framework/constants.d.ts.map +1 -0
  122. package/dist/framework/constants.js +16 -0
  123. package/dist/framework/constants.js.map +1 -0
  124. package/dist/framework/content-filter.d.ts +33 -0
  125. package/dist/framework/content-filter.d.ts.map +1 -0
  126. package/dist/framework/content-filter.js +236 -0
  127. package/dist/framework/content-filter.js.map +1 -0
  128. package/dist/framework/define-check.d.ts +38 -0
  129. package/dist/framework/define-check.d.ts.map +1 -0
  130. package/dist/framework/define-check.js +252 -0
  131. package/dist/framework/define-check.js.map +1 -0
  132. package/dist/framework/directive-inventory.d.ts +34 -0
  133. package/dist/framework/directive-inventory.d.ts.map +1 -0
  134. package/dist/framework/directive-inventory.js +77 -0
  135. package/dist/framework/directive-inventory.js.map +1 -0
  136. package/dist/framework/directive-parsing.d.ts +20 -0
  137. package/dist/framework/directive-parsing.d.ts.map +1 -0
  138. package/dist/framework/directive-parsing.js +121 -0
  139. package/dist/framework/directive-parsing.js.map +1 -0
  140. package/dist/framework/execution-context.d.ts +95 -0
  141. package/dist/framework/execution-context.d.ts.map +1 -0
  142. package/dist/framework/execution-context.js +122 -0
  143. package/dist/framework/execution-context.js.map +1 -0
  144. package/dist/framework/file-accessor.d.ts +20 -0
  145. package/dist/framework/file-accessor.d.ts.map +1 -0
  146. package/dist/framework/file-accessor.js +122 -0
  147. package/dist/framework/file-accessor.js.map +1 -0
  148. package/dist/framework/file-cache.d.ts +70 -0
  149. package/dist/framework/file-cache.d.ts.map +1 -0
  150. package/dist/framework/file-cache.js +178 -0
  151. package/dist/framework/file-cache.js.map +1 -0
  152. package/dist/framework/file-type-filter.d.ts +11 -0
  153. package/dist/framework/file-type-filter.d.ts.map +1 -0
  154. package/dist/framework/file-type-filter.js +21 -0
  155. package/dist/framework/file-type-filter.js.map +1 -0
  156. package/dist/framework/ignore-processing.d.ts +22 -0
  157. package/dist/framework/ignore-processing.d.ts.map +1 -0
  158. package/dist/framework/ignore-processing.js +241 -0
  159. package/dist/framework/ignore-processing.js.map +1 -0
  160. package/dist/framework/import-graph.d.ts +51 -0
  161. package/dist/framework/import-graph.d.ts.map +1 -0
  162. package/dist/framework/import-graph.js +216 -0
  163. package/dist/framework/import-graph.js.map +1 -0
  164. package/dist/framework/memory-profiler.d.ts +53 -0
  165. package/dist/framework/memory-profiler.d.ts.map +1 -0
  166. package/dist/framework/memory-profiler.js +92 -0
  167. package/dist/framework/memory-profiler.js.map +1 -0
  168. package/dist/framework/parse-cache.d.ts +23 -0
  169. package/dist/framework/parse-cache.d.ts.map +1 -0
  170. package/dist/framework/parse-cache.js +37 -0
  171. package/dist/framework/parse-cache.js.map +1 -0
  172. package/dist/framework/path-matcher.d.ts +86 -0
  173. package/dist/framework/path-matcher.d.ts.map +1 -0
  174. package/dist/framework/path-matcher.js +138 -0
  175. package/dist/framework/path-matcher.js.map +1 -0
  176. package/dist/framework/register-helpers.d.ts +10 -0
  177. package/dist/framework/register-helpers.d.ts.map +1 -0
  178. package/dist/framework/register-helpers.js +17 -0
  179. package/dist/framework/register-helpers.js.map +1 -0
  180. package/dist/framework/registry.d.ts +41 -0
  181. package/dist/framework/registry.d.ts.map +1 -0
  182. package/dist/framework/registry.js +103 -0
  183. package/dist/framework/registry.js.map +1 -0
  184. package/dist/framework/result-builder.d.ts +74 -0
  185. package/dist/framework/result-builder.d.ts.map +1 -0
  186. package/dist/framework/result-builder.js +154 -0
  187. package/dist/framework/result-builder.js.map +1 -0
  188. package/dist/framework/scope-resolver.d.ts +23 -0
  189. package/dist/framework/scope-resolver.d.ts.map +1 -0
  190. package/dist/framework/scope-resolver.js +201 -0
  191. package/dist/framework/scope-resolver.js.map +1 -0
  192. package/dist/framework/severity-mapping.d.ts +13 -0
  193. package/dist/framework/severity-mapping.d.ts.map +1 -0
  194. package/dist/framework/severity-mapping.js +51 -0
  195. package/dist/framework/severity-mapping.js.map +1 -0
  196. package/dist/framework/strip-literals.d.ts +48 -0
  197. package/dist/framework/strip-literals.d.ts.map +1 -0
  198. package/dist/framework/strip-literals.js +188 -0
  199. package/dist/framework/strip-literals.js.map +1 -0
  200. package/dist/gate.d.ts +74 -0
  201. package/dist/gate.d.ts.map +1 -0
  202. package/dist/gate.js +257 -0
  203. package/dist/gate.js.map +1 -0
  204. package/dist/index.d.ts +47 -0
  205. package/dist/index.d.ts.map +1 -0
  206. package/dist/index.js +51 -0
  207. package/dist/index.js.map +1 -0
  208. package/dist/plugins/__tests__/check-package-discovery.test.d.ts +2 -0
  209. package/dist/plugins/__tests__/check-package-discovery.test.d.ts.map +1 -0
  210. package/dist/plugins/__tests__/check-package-discovery.test.js +170 -0
  211. package/dist/plugins/__tests__/check-package-discovery.test.js.map +1 -0
  212. package/dist/plugins/__tests__/lang-domain.test.d.ts +2 -0
  213. package/dist/plugins/__tests__/lang-domain.test.d.ts.map +1 -0
  214. package/dist/plugins/__tests__/lang-domain.test.js +171 -0
  215. package/dist/plugins/__tests__/lang-domain.test.js.map +1 -0
  216. package/dist/plugins/__tests__/loader.test.d.ts +2 -0
  217. package/dist/plugins/__tests__/loader.test.d.ts.map +1 -0
  218. package/dist/plugins/__tests__/loader.test.js +194 -0
  219. package/dist/plugins/__tests__/loader.test.js.map +1 -0
  220. package/dist/plugins/check-package-discovery.d.ts +73 -0
  221. package/dist/plugins/check-package-discovery.d.ts.map +1 -0
  222. package/dist/plugins/check-package-discovery.js +212 -0
  223. package/dist/plugins/check-package-discovery.js.map +1 -0
  224. package/dist/plugins/loader.d.ts +31 -0
  225. package/dist/plugins/loader.d.ts.map +1 -0
  226. package/dist/plugins/loader.js +290 -0
  227. package/dist/plugins/loader.js.map +1 -0
  228. package/dist/plugins/types.d.ts +23 -0
  229. package/dist/plugins/types.d.ts.map +1 -0
  230. package/dist/plugins/types.js +9 -0
  231. package/dist/plugins/types.js.map +1 -0
  232. package/dist/recipes/__tests__/built-in-recipes.test.d.ts +2 -0
  233. package/dist/recipes/__tests__/built-in-recipes.test.d.ts.map +1 -0
  234. package/dist/recipes/__tests__/built-in-recipes.test.js +93 -0
  235. package/dist/recipes/__tests__/built-in-recipes.test.js.map +1 -0
  236. package/dist/recipes/__tests__/check-config.test.d.ts +5 -0
  237. package/dist/recipes/__tests__/check-config.test.d.ts.map +1 -0
  238. package/dist/recipes/__tests__/check-config.test.js +37 -0
  239. package/dist/recipes/__tests__/check-config.test.js.map +1 -0
  240. package/dist/recipes/__tests__/check-resolution.test.d.ts +2 -0
  241. package/dist/recipes/__tests__/check-resolution.test.d.ts.map +1 -0
  242. package/dist/recipes/__tests__/check-resolution.test.js +135 -0
  243. package/dist/recipes/__tests__/check-resolution.test.js.map +1 -0
  244. package/dist/recipes/__tests__/registry.test.d.ts +2 -0
  245. package/dist/recipes/__tests__/registry.test.d.ts.map +1 -0
  246. package/dist/recipes/__tests__/registry.test.js +97 -0
  247. package/dist/recipes/__tests__/registry.test.js.map +1 -0
  248. package/dist/recipes/__tests__/retry.test.d.ts +2 -0
  249. package/dist/recipes/__tests__/retry.test.d.ts.map +1 -0
  250. package/dist/recipes/__tests__/retry.test.js +75 -0
  251. package/dist/recipes/__tests__/retry.test.js.map +1 -0
  252. package/dist/recipes/__tests__/service.test.d.ts +11 -0
  253. package/dist/recipes/__tests__/service.test.d.ts.map +1 -0
  254. package/dist/recipes/__tests__/service.test.js +482 -0
  255. package/dist/recipes/__tests__/service.test.js.map +1 -0
  256. package/dist/recipes/built-in-recipes.d.ts +14 -0
  257. package/dist/recipes/built-in-recipes.d.ts.map +1 -0
  258. package/dist/recipes/built-in-recipes.js +247 -0
  259. package/dist/recipes/built-in-recipes.js.map +1 -0
  260. package/dist/recipes/check-config.d.ts +40 -0
  261. package/dist/recipes/check-config.d.ts.map +1 -0
  262. package/dist/recipes/check-config.js +61 -0
  263. package/dist/recipes/check-config.js.map +1 -0
  264. package/dist/recipes/check-resolution.d.ts +21 -0
  265. package/dist/recipes/check-resolution.d.ts.map +1 -0
  266. package/dist/recipes/check-resolution.js +121 -0
  267. package/dist/recipes/check-resolution.js.map +1 -0
  268. package/dist/recipes/check-result-processor.d.ts +51 -0
  269. package/dist/recipes/check-result-processor.d.ts.map +1 -0
  270. package/dist/recipes/check-result-processor.js +158 -0
  271. package/dist/recipes/check-result-processor.js.map +1 -0
  272. package/dist/recipes/parallel-execution.d.ts +33 -0
  273. package/dist/recipes/parallel-execution.d.ts.map +1 -0
  274. package/dist/recipes/parallel-execution.js +142 -0
  275. package/dist/recipes/parallel-execution.js.map +1 -0
  276. package/dist/recipes/registry.d.ts +81 -0
  277. package/dist/recipes/registry.d.ts.map +1 -0
  278. package/dist/recipes/registry.js +131 -0
  279. package/dist/recipes/registry.js.map +1 -0
  280. package/dist/recipes/retry.d.ts +25 -0
  281. package/dist/recipes/retry.d.ts.map +1 -0
  282. package/dist/recipes/retry.js +44 -0
  283. package/dist/recipes/retry.js.map +1 -0
  284. package/dist/recipes/sequential-execution.d.ts +10 -0
  285. package/dist/recipes/sequential-execution.d.ts.map +1 -0
  286. package/dist/recipes/sequential-execution.js +122 -0
  287. package/dist/recipes/sequential-execution.js.map +1 -0
  288. package/dist/recipes/service-types.d.ts +84 -0
  289. package/dist/recipes/service-types.d.ts.map +1 -0
  290. package/dist/recipes/service-types.js +8 -0
  291. package/dist/recipes/service-types.js.map +1 -0
  292. package/dist/recipes/service.d.ts +71 -0
  293. package/dist/recipes/service.d.ts.map +1 -0
  294. package/dist/recipes/service.js +331 -0
  295. package/dist/recipes/service.js.map +1 -0
  296. package/dist/recipes/types.d.ts +154 -0
  297. package/dist/recipes/types.d.ts.map +1 -0
  298. package/dist/recipes/types.js +54 -0
  299. package/dist/recipes/types.js.map +1 -0
  300. package/dist/sarif.d.ts +34 -0
  301. package/dist/sarif.d.ts.map +1 -0
  302. package/dist/sarif.js +192 -0
  303. package/dist/sarif.js.map +1 -0
  304. package/dist/signalers/__tests__/loader.test.d.ts +2 -0
  305. package/dist/signalers/__tests__/loader.test.d.ts.map +1 -0
  306. package/dist/signalers/__tests__/loader.test.js +74 -0
  307. package/dist/signalers/__tests__/loader.test.js.map +1 -0
  308. package/dist/signalers/index.d.ts +8 -0
  309. package/dist/signalers/index.d.ts.map +1 -0
  310. package/dist/signalers/index.js +9 -0
  311. package/dist/signalers/index.js.map +1 -0
  312. package/dist/signalers/loader.d.ts +24 -0
  313. package/dist/signalers/loader.d.ts.map +1 -0
  314. package/dist/signalers/loader.js +108 -0
  315. package/dist/signalers/loader.js.map +1 -0
  316. package/dist/signalers/schema.d.ts +288 -0
  317. package/dist/signalers/schema.d.ts.map +1 -0
  318. package/dist/signalers/schema.js +99 -0
  319. package/dist/signalers/schema.js.map +1 -0
  320. package/dist/signalers/types.d.ts +13 -0
  321. package/dist/signalers/types.d.ts.map +1 -0
  322. package/dist/signalers/types.js +5 -0
  323. package/dist/signalers/types.js.map +1 -0
  324. package/dist/targets/__tests__/loader.test.d.ts +2 -0
  325. package/dist/targets/__tests__/loader.test.d.ts.map +1 -0
  326. package/dist/targets/__tests__/loader.test.js +127 -0
  327. package/dist/targets/__tests__/loader.test.js.map +1 -0
  328. package/dist/targets/__tests__/resolver.test.d.ts +2 -0
  329. package/dist/targets/__tests__/resolver.test.d.ts.map +1 -0
  330. package/dist/targets/__tests__/resolver.test.js +54 -0
  331. package/dist/targets/__tests__/resolver.test.js.map +1 -0
  332. package/dist/targets/__tests__/target-registry.test.d.ts +2 -0
  333. package/dist/targets/__tests__/target-registry.test.d.ts.map +1 -0
  334. package/dist/targets/__tests__/target-registry.test.js +89 -0
  335. package/dist/targets/__tests__/target-registry.test.js.map +1 -0
  336. package/dist/targets/index.d.ts +10 -0
  337. package/dist/targets/index.d.ts.map +1 -0
  338. package/dist/targets/index.js +12 -0
  339. package/dist/targets/index.js.map +1 -0
  340. package/dist/targets/loader.d.ts +19 -0
  341. package/dist/targets/loader.d.ts.map +1 -0
  342. package/dist/targets/loader.js +159 -0
  343. package/dist/targets/loader.js.map +1 -0
  344. package/dist/targets/resolver.d.ts +19 -0
  345. package/dist/targets/resolver.d.ts.map +1 -0
  346. package/dist/targets/resolver.js +37 -0
  347. package/dist/targets/resolver.js.map +1 -0
  348. package/dist/targets/target-registry.d.ts +61 -0
  349. package/dist/targets/target-registry.d.ts.map +1 -0
  350. package/dist/targets/target-registry.js +93 -0
  351. package/dist/targets/target-registry.js.map +1 -0
  352. package/dist/targets/types.d.ts +85 -0
  353. package/dist/targets/types.d.ts.map +1 -0
  354. package/dist/targets/types.js +5 -0
  355. package/dist/targets/types.js.map +1 -0
  356. package/dist/tool.d.ts +17 -0
  357. package/dist/tool.d.ts.map +1 -0
  358. package/dist/tool.js +282 -0
  359. package/dist/tool.js.map +1 -0
  360. package/dist/types/findings.d.ts +117 -0
  361. package/dist/types/findings.d.ts.map +1 -0
  362. package/dist/types/findings.js +93 -0
  363. package/dist/types/findings.js.map +1 -0
  364. package/dist/types/severity.d.ts +15 -0
  365. package/dist/types/severity.d.ts.map +1 -0
  366. package/dist/types/severity.js +36 -0
  367. package/dist/types/severity.js.map +1 -0
  368. package/package.json +45 -0
  369. package/src/__tests__/gate.test.ts +537 -0
  370. package/src/__tests__/sarif.test.ts +201 -0
  371. package/src/cli/dashboard.ts +93 -0
  372. package/src/cli/fit.ts +612 -0
  373. package/src/cli/list-checks.ts +32 -0
  374. package/src/cli/list-recipes.ts +38 -0
  375. package/src/framework/__tests__/ast-utilities.test.ts +157 -0
  376. package/src/framework/__tests__/check-config.test.ts +65 -0
  377. package/src/framework/__tests__/command-executor.test.ts +79 -0
  378. package/src/framework/__tests__/content-filter-dispatch.test.ts +132 -0
  379. package/src/framework/__tests__/content-filter.test.ts +136 -0
  380. package/src/framework/__tests__/define-check.test.ts +180 -0
  381. package/src/framework/__tests__/directive-inventory.test.ts +53 -0
  382. package/src/framework/__tests__/execution-context.test.ts +80 -0
  383. package/src/framework/__tests__/file-accessor.test.ts +121 -0
  384. package/src/framework/__tests__/file-cache.test.ts +142 -0
  385. package/src/framework/__tests__/import-graph.test.ts +282 -0
  386. package/src/framework/__tests__/path-matcher.test.ts +130 -0
  387. package/src/framework/__tests__/register-helpers.test.ts +51 -0
  388. package/src/framework/__tests__/registry.test.ts +243 -0
  389. package/src/framework/__tests__/result-builder.test.ts +178 -0
  390. package/src/framework/__tests__/scope-resolver.test.ts +208 -0
  391. package/src/framework/__tests__/severity-mapping.test.ts +50 -0
  392. package/src/framework/__tests__/strip-literals.test.ts +109 -0
  393. package/src/framework/abortable-exec.ts +177 -0
  394. package/src/framework/ast-utilities.ts +112 -0
  395. package/src/framework/check-config.ts +339 -0
  396. package/src/framework/check-types.ts +77 -0
  397. package/src/framework/command-executor.ts +100 -0
  398. package/src/framework/constants.ts +16 -0
  399. package/src/framework/content-filter.ts +288 -0
  400. package/src/framework/define-check.ts +336 -0
  401. package/src/framework/directive-inventory.ts +110 -0
  402. package/src/framework/directive-parsing.ts +152 -0
  403. package/src/framework/execution-context.ts +247 -0
  404. package/src/framework/file-accessor.ts +171 -0
  405. package/src/framework/file-cache.ts +220 -0
  406. package/src/framework/file-type-filter.ts +25 -0
  407. package/src/framework/ignore-processing.ts +350 -0
  408. package/src/framework/import-graph.ts +280 -0
  409. package/src/framework/memory-profiler.ts +145 -0
  410. package/src/framework/parse-cache.ts +38 -0
  411. package/src/framework/path-matcher.ts +191 -0
  412. package/src/framework/register-helpers.ts +20 -0
  413. package/src/framework/registry.ts +125 -0
  414. package/src/framework/result-builder.ts +225 -0
  415. package/src/framework/scope-resolver.ts +262 -0
  416. package/src/framework/severity-mapping.ts +56 -0
  417. package/src/framework/strip-literals.ts +200 -0
  418. package/src/gate.ts +337 -0
  419. package/src/index.ts +110 -0
  420. package/src/plugins/__tests__/check-package-discovery.test.ts +204 -0
  421. package/src/plugins/__tests__/lang-domain.test.ts +198 -0
  422. package/src/plugins/__tests__/loader.test.ts +226 -0
  423. package/src/plugins/check-package-discovery.ts +242 -0
  424. package/src/plugins/loader.ts +327 -0
  425. package/src/plugins/types.ts +25 -0
  426. package/src/recipes/__tests__/built-in-recipes.test.ts +107 -0
  427. package/src/recipes/__tests__/check-config.test.ts +51 -0
  428. package/src/recipes/__tests__/check-resolution.test.ts +185 -0
  429. package/src/recipes/__tests__/registry.test.ts +115 -0
  430. package/src/recipes/__tests__/retry.test.ts +83 -0
  431. package/src/recipes/__tests__/service.test.ts +572 -0
  432. package/src/recipes/built-in-recipes.ts +273 -0
  433. package/src/recipes/check-config.ts +64 -0
  434. package/src/recipes/check-resolution.ts +169 -0
  435. package/src/recipes/check-result-processor.ts +258 -0
  436. package/src/recipes/parallel-execution.ts +220 -0
  437. package/src/recipes/registry.ts +192 -0
  438. package/src/recipes/retry.ts +69 -0
  439. package/src/recipes/sequential-execution.ts +139 -0
  440. package/src/recipes/service-types.ts +105 -0
  441. package/src/recipes/service.ts +400 -0
  442. package/src/recipes/types.ts +247 -0
  443. package/src/sarif.ts +232 -0
  444. package/src/signalers/__tests__/loader.test.ts +99 -0
  445. package/src/signalers/index.ts +9 -0
  446. package/src/signalers/loader.ts +141 -0
  447. package/src/signalers/schema.ts +117 -0
  448. package/src/signalers/types.ts +15 -0
  449. package/src/targets/__tests__/loader.test.ts +170 -0
  450. package/src/targets/__tests__/resolver.test.ts +74 -0
  451. package/src/targets/__tests__/target-registry.test.ts +103 -0
  452. package/src/targets/index.ts +13 -0
  453. package/src/targets/loader.ts +214 -0
  454. package/src/targets/resolver.ts +44 -0
  455. package/src/targets/target-registry.ts +111 -0
  456. package/src/targets/types.ts +89 -0
  457. package/src/tool.ts +302 -0
  458. package/src/types/findings.ts +239 -0
  459. package/src/types/severity.ts +39 -0
  460. package/tsconfig.json +8 -0
  461. package/vitest.config.ts +33 -0
@@ -0,0 +1,220 @@
1
+ // @fitness-ignore-file public-api-jsdoc -- internal framework module; public API documented at package level
2
+ /**
3
+ * @fileoverview In-memory file cache for fitness checks
4
+ *
5
+ * Simple file content cache with optional prewarming.
6
+ * Used by all checks during a run for efficient file access.
7
+ */
8
+
9
+ import * as fs from 'node:fs/promises'
10
+ import * as path from 'node:path'
11
+
12
+ import { ValidationError } from '@opensip-tools/core'
13
+ import { glob } from 'glob'
14
+
15
+ /**
16
+ * Prewarm statistics.
17
+ */
18
+ interface PrewarmStats {
19
+ /** Number of files loaded */
20
+ readonly filesLoaded: number
21
+ /** Duration in milliseconds */
22
+ readonly durationMs: number
23
+ /** Total bytes loaded */
24
+ readonly totalBytes: number
25
+ }
26
+
27
+ /**
28
+ * Simple in-memory file cache.
29
+ *
30
+ * Usage:
31
+ * 1. Call prewarm() before running checks (loads file contents)
32
+ * 2. Use get() to read file contents (falls back to disk if not cached)
33
+ * 3. Call clear() after checks complete
34
+ */
35
+ const PREWARM_BATCH_SIZE = 100
36
+
37
+ class FileCache {
38
+ private readonly cache = new Map<string, string>()
39
+ private _prewarmed = false
40
+ private _cleared = false
41
+ private _autoClearTimer: ReturnType<typeof setTimeout> | null = null
42
+
43
+ /**
44
+ * Prewarm the cache by loading all files matching patterns.
45
+ * @param cwd - Working directory for file resolution
46
+ * @param patterns - Glob patterns to prewarm file contents for
47
+ * @returns Prewarm statistics
48
+ */
49
+ async prewarm(cwd: string, patterns: readonly string[]): Promise<PrewarmStats> {
50
+ const start = Date.now()
51
+ let totalBytes = 0
52
+
53
+ // Find all matching files for content caching
54
+ const allFiles = new Set<string>()
55
+ for (const pattern of patterns) {
56
+ // @fitness-ignore-next-line performance-anti-patterns -- sequential glob calls: each pattern must resolve before deduplication
57
+ const files = await glob(pattern, {
58
+ cwd,
59
+ absolute: true,
60
+ nodir: true,
61
+ ignore: ['**/node_modules/**', '**/dist/**', '**/.git/**'],
62
+ })
63
+ for (const file of files) {
64
+ allFiles.add(file)
65
+ }
66
+ }
67
+
68
+ // Load file contents in parallel batches
69
+ const files = [...allFiles]
70
+
71
+ for (let i = 0; i < files.length; i += PREWARM_BATCH_SIZE) {
72
+ const batch = files.slice(i, i + PREWARM_BATCH_SIZE)
73
+ // @fitness-ignore-next-line performance-anti-patterns -- intentional batching: limits concurrent file reads to control memory pressure
74
+ const results = await Promise.allSettled(
75
+ batch.map(async (filePath) => {
76
+ const stats = await fs.stat(filePath)
77
+ if (stats.isDirectory()) {
78
+ return null
79
+ }
80
+ const content = await fs.readFile(filePath, 'utf8')
81
+ return { filePath, content }
82
+ }),
83
+ )
84
+
85
+ for (const result of results) {
86
+ if (result.status === 'fulfilled' && result.value !== null) {
87
+ this.cache.set(result.value.filePath, result.value.content)
88
+ totalBytes += result.value.content.length
89
+ }
90
+ }
91
+ }
92
+
93
+ this._prewarmed = true
94
+ this._cleared = false
95
+ this.scheduleAutoClear()
96
+ const durationMs = Date.now() - start
97
+
98
+ return {
99
+ filesLoaded: this.cache.size,
100
+ durationMs,
101
+ totalBytes,
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Get file content from cache, falling back to disk if not cached.
107
+ * @throws {Error} If the path is a directory instead of a file
108
+ */
109
+ /** Synchronously check if a file is in cache. Returns content or undefined. */
110
+ getCached(filePath: string): string | undefined {
111
+ const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath)
112
+ return this.cache.get(absolutePath)
113
+ }
114
+
115
+ async get(filePath: string): Promise<string> {
116
+ const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath)
117
+
118
+ const cached = this.cache.get(absolutePath)
119
+ if (cached !== undefined) {
120
+ return cached
121
+ }
122
+
123
+ const stats = await fs.stat(absolutePath)
124
+ if (stats.isDirectory()) {
125
+ // @fitness-ignore-next-line result-pattern-consistency -- internal method, exceptions propagate to public Result boundary
126
+ throw new ValidationError(`Cannot read directory as file: ${absolutePath}`, { code: 'VALIDATION.FITNESS.DIRECTORY_AS_FILE' })
127
+ }
128
+ const content = await fs.readFile(absolutePath, 'utf8')
129
+
130
+ this.cache.set(absolutePath, content)
131
+
132
+ return content
133
+ }
134
+
135
+ /**
136
+ * Check if a file exists (in cache or on disk).
137
+ */
138
+ async exists(filePath: string): Promise<boolean> {
139
+ const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath)
140
+
141
+ if (this.cache.has(absolutePath)) {
142
+ return true
143
+ }
144
+
145
+ try {
146
+ await fs.access(absolutePath)
147
+ return true
148
+ } catch {
149
+ // @swallow-ok File access check failed — treat as not accessible
150
+ return false
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Clear the cache. Must be called after checks complete.
156
+ */
157
+ clear(): void {
158
+ this.cache.clear()
159
+ this._prewarmed = false
160
+ this._cleared = true
161
+ if (this._autoClearTimer) {
162
+ clearTimeout(this._autoClearTimer)
163
+ this._autoClearTimer = null
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Get all cached file paths.
169
+ * Returns the paths of all files loaded during prewarm or on-demand reads.
170
+ */
171
+ paths(): readonly string[] {
172
+ return [...this.cache.keys()].sort()
173
+ }
174
+
175
+ /**
176
+ * Get cache statistics.
177
+ */
178
+ /** Auto-clear after timeout to prevent memory leaks from missed lifecycle cleanup */
179
+ private scheduleAutoClear(): void {
180
+ if (this._autoClearTimer) {
181
+ clearTimeout(this._autoClearTimer)
182
+ }
183
+ this._autoClearTimer = setTimeout(() => {
184
+ if (this.cache.size > 0) {
185
+ this.clear()
186
+ }
187
+ }, 10 * 60 * 1000) // 10 minutes
188
+ // Unref so the timer doesn't keep the process alive
189
+ this._autoClearTimer.unref()
190
+ }
191
+
192
+ get stats(): {
193
+ size: number
194
+ prewarmed: boolean
195
+ cleared: boolean
196
+ } {
197
+ return {
198
+ size: this.cache.size,
199
+ prewarmed: this._prewarmed,
200
+ cleared: this._cleared,
201
+ }
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Shared file cache instance.
207
+ */
208
+ export const fileCache = new FileCache()
209
+
210
+ /**
211
+ * Default patterns to prewarm for fitness checks.
212
+ */
213
+ export const DEFAULT_PREWARM_PATTERNS = [
214
+ '**/*.ts',
215
+ '**/*.tsx',
216
+ '**/*.js',
217
+ '**/*.jsx',
218
+ '**/*.json',
219
+ '**/*.md',
220
+ ] as const
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @fileoverview File type filtering for per-check file extension matching
3
+ *
4
+ * Filters matched files by extension based on a check's declared fileTypes.
5
+ */
6
+
7
+ import * as path from 'node:path'
8
+
9
+ /**
10
+ * Filter files by extension based on a check's declared fileTypes.
11
+ * If fileTypes is undefined or empty, returns all files (universal).
12
+ */
13
+ export function filterFilesByType(
14
+ files: readonly string[],
15
+ fileTypes: readonly string[] | undefined,
16
+ ): string[] {
17
+ if (!fileTypes || fileTypes.length === 0) {
18
+ return [...files]
19
+ }
20
+ const extensions = new Set(fileTypes)
21
+ return files.filter((f) => {
22
+ const ext = path.extname(f).slice(1) // remove leading dot
23
+ return extensions.has(ext)
24
+ })
25
+ }
@@ -0,0 +1,350 @@
1
+ // @fitness-ignore-file batch-operation-limits -- iterates bounded collections (config entries, registry items, or small analysis results)
2
+ // @fitness-ignore-file concurrency-safety -- Single-threaded Node.js; Map-based caches are safe without synchronization
3
+ /**
4
+ * @fileoverview Ignore directive processing for fitness checks
5
+ *
6
+ * Filters signals based on file-level and line-level ignore directives.
7
+ * Signals pointing at lines that contain @fitness-ignore directives are
8
+ * never suppressed — this prevents recursive suppression loops where
9
+ * directive-auditing checks would otherwise flag their own suppressions.
10
+ */
11
+
12
+ import { logger } from '@opensip-tools/core'
13
+
14
+
15
+ import { countErrors, countWarnings } from '../types/severity.js'
16
+
17
+ import { extractGroup, isWeakReason, parseDirectiveLine } from './directive-inventory.js'
18
+ import { parseFileIgnoreDirective, parseIgnoreDirectives } from './directive-parsing.js'
19
+ import { fileCache } from './file-cache.js'
20
+
21
+ import type { DirectiveEntry } from './directive-inventory.js'
22
+ import type { CheckResult } from '../types/findings.js'
23
+ import type { Signal } from '@opensip-tools/core'
24
+
25
+ // =============================================================================
26
+ // DIRECTIVE LINE DETECTION
27
+ // =============================================================================
28
+
29
+ /**
30
+ * Scan file content and return the set of 1-based line numbers that contain
31
+ * @fitness-ignore directives. These lines are framework infrastructure and
32
+ * must never be suppressed by other directives (prevents recursive loops).
33
+ */
34
+ function findDirectiveLines(content: string): Set<number> {
35
+ const directiveLines = new Set<number>()
36
+ const lines = content.split('\n')
37
+ for (const [i, line] of lines.entries()) {
38
+ const trimmed = (line ?? '').trimStart()
39
+ if (
40
+ (trimmed.startsWith('//') || trimmed.startsWith('/*')) &&
41
+ trimmed.includes('@fitness-ignore')
42
+ ) {
43
+ directiveLines.add(i + 1)
44
+ }
45
+ }
46
+ return directiveLines
47
+ }
48
+
49
+ // =============================================================================
50
+ // FILE IGNORE STATUS PROCESSING
51
+ // =============================================================================
52
+
53
+ /** Cached per-file results from directive scanning. */
54
+ interface FileIgnoreInfo {
55
+ fileIgnored: boolean
56
+ ignoredLines: Set<number> | null
57
+ directiveLines: Set<number>
58
+ }
59
+
60
+ /**
61
+ * Processes file ignore status and caches the result.
62
+ */
63
+ async function processFileIgnoreStatus(
64
+ filePath: string,
65
+ checkId: string,
66
+ fileIgnoreCache: Map<string, boolean>,
67
+ lineIgnoreCache: Map<string, Set<number>>,
68
+ directiveLineCache?: Map<string, Set<number>>,
69
+ ): Promise<FileIgnoreInfo> {
70
+ // in-memory: single-threaded Node.js access pattern
71
+ const fileIgnored = fileIgnoreCache.get(filePath)
72
+
73
+ if (fileIgnored !== undefined) {
74
+ return {
75
+ fileIgnored,
76
+ ignoredLines: lineIgnoreCache.get(filePath) ?? null,
77
+ directiveLines: directiveLineCache?.get(filePath) ?? new Set(),
78
+ }
79
+ }
80
+
81
+ try {
82
+ const content = await fileCache.get(filePath)
83
+ const isIgnored = parseFileIgnoreDirective(content, checkId)
84
+ fileIgnoreCache.set(filePath, isIgnored)
85
+
86
+ // Always scan for directive lines (needed for recursive loop prevention)
87
+ const dirLines = findDirectiveLines(content)
88
+ directiveLineCache?.set(filePath, dirLines)
89
+
90
+ let ignoredLines: Set<number> | null = null
91
+ if (!isIgnored) {
92
+ ignoredLines = parseIgnoreDirectives(content, checkId)
93
+ lineIgnoreCache.set(filePath, ignoredLines)
94
+ }
95
+
96
+ return { fileIgnored: isIgnored, ignoredLines, directiveLines: dirLines }
97
+ } catch (error) {
98
+ logger.warn('fitness.ignore.file_read.failed', { evt: 'fitness.ignore.file_read.failed', module: 'fitness:ignore-processing', filePath, err: error });
99
+ fileIgnoreCache.set(filePath, false)
100
+ return { fileIgnored: false, ignoredLines: null, directiveLines: new Set() }
101
+ }
102
+ }
103
+
104
+ // =============================================================================
105
+ // SIGNAL FILTERING
106
+ // =============================================================================
107
+
108
+ /**
109
+ * Filters signals based on ignore directives.
110
+ *
111
+ * Signals pointing at lines that contain `@fitness-ignore` directives are
112
+ * never suppressed. This is a structural guarantee that prevents recursive
113
+ * loops: a check that audits directives cannot have its findings suppressed
114
+ * by the very directives it reports on.
115
+ */
116
+ interface FilterResult {
117
+ filteredSignals: Signal[]
118
+ ignoredCount: number
119
+ appliedFileIgnores: Set<string>
120
+ appliedLineIgnores: Map<string, Set<number>>
121
+ }
122
+
123
+ function classifySignals(
124
+ signals: readonly Signal[],
125
+ initialIgnoredCount: number,
126
+ fileIgnoreCache: Map<string, boolean>,
127
+ lineIgnoreCache: Map<string, Set<number>>,
128
+ directiveLineCache: Map<string, Set<number>>,
129
+ ): FilterResult {
130
+ const filteredSignals: Signal[] = []
131
+ let ignoredCount = initialIgnoredCount
132
+ const appliedFileIgnores = new Set<string>()
133
+ const appliedLineIgnores = new Map<string, Set<number>>()
134
+
135
+ for (const signal of signals) {
136
+ if (!isSignalIgnored(signal, fileIgnoreCache, lineIgnoreCache, directiveLineCache)) {
137
+ filteredSignals.push(signal)
138
+ continue
139
+ }
140
+ ignoredCount++
141
+ const filePath = signal.code?.file
142
+ if (!filePath) continue
143
+
144
+ if (fileIgnoreCache.get(filePath)) {
145
+ appliedFileIgnores.add(filePath)
146
+ } else {
147
+ const line = signal.code?.line
148
+ if (line) {
149
+ let lineSet = appliedLineIgnores.get(filePath)
150
+ if (!lineSet) {
151
+ lineSet = new Set()
152
+ appliedLineIgnores.set(filePath, lineSet)
153
+ }
154
+ lineSet.add(line)
155
+ }
156
+ }
157
+ }
158
+
159
+ return { filteredSignals, ignoredCount, appliedFileIgnores, appliedLineIgnores }
160
+ }
161
+
162
+ /** Filter signals based on file-level and line-level @fitness-ignore directives */
163
+ export async function filterSignalsByDirectives(
164
+ signals: readonly Signal[],
165
+ checkId: string,
166
+ initialIgnoredCount: number,
167
+ ): Promise<{ filteredSignals: Signal[]; ignoredCount: number; appliedDirectives: DirectiveEntry[] }> {
168
+ const fileIgnoreCache = new Map<string, boolean>()
169
+ const lineIgnoreCache = new Map<string, Set<number>>()
170
+ const directiveLineCache = new Map<string, Set<number>>()
171
+
172
+ // Pre-populate file ignore status for all unique file paths in parallel
173
+ const uniqueFiles = new Set<string>()
174
+ for (const signal of signals) {
175
+ const filePath = signal.code?.file
176
+ if (filePath) uniqueFiles.add(filePath)
177
+ }
178
+ await Promise.all(
179
+ [...uniqueFiles].map((filePath) =>
180
+ processFileIgnoreStatus(filePath, checkId, fileIgnoreCache, lineIgnoreCache, directiveLineCache),
181
+ ),
182
+ )
183
+
184
+ const { filteredSignals, ignoredCount, appliedFileIgnores, appliedLineIgnores } =
185
+ classifySignals(signals, initialIgnoredCount, fileIgnoreCache, lineIgnoreCache, directiveLineCache)
186
+
187
+ const appliedDirectives = await collectAppliedDirectives(checkId, appliedFileIgnores, appliedLineIgnores)
188
+
189
+ return { filteredSignals, ignoredCount, appliedDirectives }
190
+ }
191
+
192
+ /**
193
+ * Determines whether a single signal should be ignored based on cached directive data.
194
+ *
195
+ * File-level ignores always apply (the entire file is suppressed).
196
+ * Line-level ignores apply unless the signal points at a directive line itself
197
+ * (prevents recursive loops where directive-auditing checks suppress their own findings).
198
+ */
199
+ function isSignalIgnored(
200
+ signal: Signal,
201
+ fileIgnoreCache: Map<string, boolean>,
202
+ lineIgnoreCache: Map<string, Set<number>>,
203
+ directiveLineCache: Map<string, Set<number>>,
204
+ ): boolean {
205
+ const filePath = signal.code?.file
206
+ if (!filePath) return false
207
+
208
+ // File-level ignores always apply — no anti-recursion needed
209
+ if (fileIgnoreCache.get(filePath)) return true
210
+
211
+ const signalLine = signal.code?.line
212
+ const dirLines = directiveLineCache.get(filePath)
213
+ // For line-level ignores: never suppress signals pointing at directive lines (anti-recursion)
214
+ if (signalLine && dirLines?.has(signalLine)) return false
215
+
216
+ const ignoredLines = lineIgnoreCache.get(filePath)
217
+ if (signalLine && ignoredLines?.has(signalLine)) return true
218
+
219
+ return false
220
+ }
221
+
222
+ // =============================================================================
223
+ // APPLIED DIRECTIVE COLLECTION
224
+ // =============================================================================
225
+
226
+ function toDirectiveEntry(
227
+ filePath: string,
228
+ lineNumber: number,
229
+ parsed: { type: 'file' | 'next-line'; checkId: string; reason: string | null },
230
+ ): DirectiveEntry {
231
+ return {
232
+ filePath,
233
+ lineNumber,
234
+ type: parsed.type,
235
+ checkId: parsed.checkId,
236
+ group: extractGroup(parsed.checkId),
237
+ reason: parsed.reason,
238
+ weakReason: isWeakReason(parsed.reason),
239
+ }
240
+ }
241
+
242
+ async function collectFileIgnoreDirectives(
243
+ checkId: string,
244
+ appliedFileIgnores: Set<string>,
245
+ ): Promise<DirectiveEntry[]> {
246
+ const results = await Promise.all(
247
+ [...appliedFileIgnores].map(async (filePath): Promise<DirectiveEntry | null> => {
248
+ try {
249
+ const content = await fileCache.get(filePath)
250
+ const lines = content.split('\n')
251
+ for (let i = 0; i < Math.min(lines.length, 50); i++) {
252
+ const parsed = parseDirectiveLine(lines[i] ?? '')
253
+ if (parsed?.type === 'file' && parsed.checkId === checkId) {
254
+ return toDirectiveEntry(filePath, i + 1, parsed)
255
+ }
256
+ }
257
+ } catch (error) {
258
+ logger.warn('fitness.ignore.directive_read.failed', { evt: 'fitness.ignore.directive_read.failed', module: 'fitness:ignore-processing', err: error });
259
+ }
260
+ return null
261
+ }),
262
+ )
263
+ return results.filter((d): d is DirectiveEntry => d !== null)
264
+ }
265
+
266
+ async function collectLineIgnoreDirectives(
267
+ checkId: string,
268
+ appliedLineIgnores: Map<string, Set<number>>,
269
+ ): Promise<DirectiveEntry[]> {
270
+ const results = await Promise.all(
271
+ [...appliedLineIgnores.entries()].map(async ([filePath, suppressedLines]): Promise<DirectiveEntry[]> => {
272
+ const found: DirectiveEntry[] = []
273
+ try {
274
+ const content = await fileCache.get(filePath)
275
+ const lines = content.split('\n')
276
+ for (let i = 0; i < lines.length; i++) {
277
+ const parsed = parseDirectiveLine(lines[i] ?? '')
278
+ if (parsed?.type !== 'next-line' || parsed.checkId !== checkId) continue
279
+ let targetLine = i + 1
280
+ while (targetLine < lines.length && (lines[targetLine] ?? '').trimStart().startsWith('//')) {
281
+ targetLine++
282
+ }
283
+ if (suppressedLines.has(targetLine + 1)) {
284
+ found.push(toDirectiveEntry(filePath, i + 1, parsed))
285
+ }
286
+ }
287
+ } catch (error) {
288
+ logger.warn('fitness.ignore.directive_read.failed', { evt: 'fitness.ignore.directive_read.failed', module: 'fitness:ignore-processing', err: error });
289
+ }
290
+ return found
291
+ }),
292
+ )
293
+ const directives: DirectiveEntry[] = []
294
+ for (const batch of results) {
295
+ for (const d of batch) {
296
+ directives.push(d)
297
+ }
298
+ }
299
+ return directives
300
+ }
301
+
302
+ async function collectAppliedDirectives(
303
+ checkId: string,
304
+ appliedFileIgnores: Set<string>,
305
+ appliedLineIgnores: Map<string, Set<number>>,
306
+ ): Promise<DirectiveEntry[]> {
307
+ const [fileDirectives, lineDirectives] = await Promise.all([
308
+ collectFileIgnoreDirectives(checkId, appliedFileIgnores),
309
+ collectLineIgnoreDirectives(checkId, appliedLineIgnores),
310
+ ])
311
+ return [...fileDirectives, ...lineDirectives]
312
+ }
313
+
314
+ // =============================================================================
315
+ // RESULT BUILDING
316
+ // =============================================================================
317
+
318
+ /**
319
+ * Builds the filtered result from the original result and filtered signals.
320
+ */
321
+ export function buildFilteredResult(
322
+ result: CheckResult,
323
+ filteredSignals: Signal[],
324
+ ignoredCount: number,
325
+ start: number,
326
+ ): CheckResult {
327
+ if (!Array.isArray(filteredSignals)) {
328
+ return result
329
+ }
330
+
331
+ const durationMs = result.metadata.durationMs ?? Date.now() - start
332
+ const filteredErrors = countErrors(filteredSignals)
333
+ const filteredWarnings = countWarnings(filteredSignals)
334
+
335
+ const filteredResult: CheckResult = {
336
+ ...result,
337
+ passed: filteredErrors === 0,
338
+ errors: filteredErrors,
339
+ warnings: filteredWarnings,
340
+ signals: filteredSignals,
341
+ metadata: {
342
+ ...result.metadata,
343
+ durationMs,
344
+ signals: filteredSignals,
345
+ },
346
+ ...(ignoredCount > 0 ? { ignoredCount } : {}),
347
+ }
348
+
349
+ return filteredResult
350
+ }