@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,572 @@
1
+ /**
2
+ * @fileoverview Integration tests for FitnessRecipeService.
3
+ *
4
+ * Drives the full orchestration path (parallel/sequential execution,
5
+ * file cache prewarm, AST parse cache, directive application,
6
+ * disabled-checks filtering) against fixture projects so coverage
7
+ * reflects the orchestrator code, not just the per-check pure
8
+ * analyzer functions.
9
+ */
10
+
11
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
12
+ import { tmpdir } from 'node:os';
13
+ import { dirname, join } from 'node:path';
14
+
15
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
16
+
17
+ import { defineCheck } from '../../framework/define-check.js';
18
+ import { CheckRegistry } from '../../framework/registry.js';
19
+ import { FitnessRecipeRegistry } from '../registry.js';
20
+ import { FitnessRecipeService } from '../service.js';
21
+
22
+ import type { Check } from '../../framework/check-types.js';
23
+ import type { FitnessRecipe } from '../types.js';
24
+
25
+ // =============================================================================
26
+ // FIXTURE HELPERS
27
+ // =============================================================================
28
+
29
+ let testDir: string;
30
+
31
+ function writeFixture(relPath: string, content: string): string {
32
+ const abs = join(testDir, relPath);
33
+ mkdirSync(dirname(abs), { recursive: true });
34
+ writeFileSync(abs, content);
35
+ return abs;
36
+ }
37
+
38
+ beforeEach(() => {
39
+
40
+ testDir = mkdtempSync(join(tmpdir(), 'opensip-recipe-svc-'));
41
+ });
42
+
43
+ afterEach(() => {
44
+ rmSync(testDir, { recursive: true, force: true });
45
+ });
46
+
47
+ // =============================================================================
48
+ // CHECK FIXTURES
49
+ // =============================================================================
50
+
51
+ let nextId = 0;
52
+ function uid(): string {
53
+ // Deterministic UUID v4 shape per test run, unique per call.
54
+ nextId++;
55
+ const id = nextId.toString(16).padStart(12, '0');
56
+ return `00000000-0000-4000-8000-${id}`;
57
+ }
58
+
59
+ /** A simple check that flags any line containing the marker. */
60
+ function makeMarkerCheck(slug: string, marker: string, severity: 'error' | 'warning' = 'warning', tags: string[] = ['quality']): Check {
61
+ return defineCheck({
62
+ id: uid(),
63
+ slug,
64
+ description: `Flag any line containing ${marker}`,
65
+ tags,
66
+ analyze: (content, filePath) => {
67
+ const out: { line: number; message: string; severity: 'error' | 'warning'; filePath: string }[] = [];
68
+ const lines = content.split('\n');
69
+ for (const [i, line] of lines.entries()) {
70
+ if (line.includes(marker)) {
71
+ out.push({ line: i + 1, message: `Found ${marker}`, severity, filePath });
72
+ }
73
+ }
74
+ return out;
75
+ },
76
+ });
77
+ }
78
+
79
+ function makeRecipe(overrides: Partial<FitnessRecipe> = {}): FitnessRecipe {
80
+ return {
81
+ id: 'URCP_test',
82
+ name: 'test',
83
+ displayName: 'Test',
84
+ description: 'integration test recipe',
85
+ checks: { type: 'all', exclude: [] },
86
+ execution: { mode: 'parallel', stopOnFirstFailure: false, timeout: 30_000, maxParallel: 4 },
87
+ reporting: { format: 'table', verbose: false },
88
+ ...overrides,
89
+ };
90
+ }
91
+
92
+ // =============================================================================
93
+ // CONSTRUCTOR + CONFIG
94
+ // =============================================================================
95
+
96
+ describe('FitnessRecipeService — construction', () => {
97
+ it('builds with no config', () => {
98
+ const svc = new FitnessRecipeService();
99
+ expect(svc.getActiveSession()).toBeNull();
100
+ });
101
+
102
+ it('uses provided check + recipe registries', async () => {
103
+ const checkRegistry = new CheckRegistry();
104
+ checkRegistry.register(makeMarkerCheck('flag-foo', 'FOO'));
105
+ const recipeRegistry = new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false });
106
+
107
+ const svc = new FitnessRecipeService({ cwd: testDir, checkRegistry, recipeRegistry, prewarmCache: false });
108
+ writeFixture('a.ts', 'const x = "FOO";');
109
+
110
+ const result = await svc.start(makeRecipe());
111
+ expect(result.summary.totalChecks).toBe(1);
112
+ });
113
+
114
+ it('listRecipes exposes the recipe registry contents', () => {
115
+ const recipeRegistry = new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false });
116
+ const svc = new FitnessRecipeService({ recipeRegistry });
117
+ expect(svc.listRecipes().length).toBeGreaterThan(0);
118
+ });
119
+
120
+ it('getRecipe resolves a recipe by name and ID', () => {
121
+ const recipeRegistry = new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false });
122
+ const svc = new FitnessRecipeService({ recipeRegistry });
123
+ expect(svc.getRecipe('default')).toBeDefined();
124
+ expect(svc.getRecipe('NOT_REAL')).toBeUndefined();
125
+ });
126
+ });
127
+
128
+ // =============================================================================
129
+ // EXECUTION — PARALLEL
130
+ // =============================================================================
131
+
132
+ describe('FitnessRecipeService — parallel execution', () => {
133
+ it('runs every registered check against fixture files', async () => {
134
+ const checkRegistry = new CheckRegistry();
135
+ checkRegistry.register(makeMarkerCheck('flag-foo', 'FOO'));
136
+ checkRegistry.register(makeMarkerCheck('flag-bar', 'BAR'));
137
+
138
+ writeFixture('a.ts', 'const x = "FOO";\nconst y = "BAR";');
139
+
140
+ const svc = new FitnessRecipeService({
141
+ cwd: testDir,
142
+ checkRegistry,
143
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
144
+ prewarmCache: true,
145
+ });
146
+
147
+ const result = await svc.start(makeRecipe());
148
+ expect(result.summary.totalChecks).toBe(2);
149
+ expect(result.summary.totalViolations).toBeGreaterThanOrEqual(2);
150
+ });
151
+
152
+ it('calls onCheckStart / onCheckComplete / onComplete callbacks', async () => {
153
+ const starts: string[] = [];
154
+ const completes: string[] = [];
155
+ let onComplete = false;
156
+
157
+ const checkRegistry = new CheckRegistry();
158
+ checkRegistry.register(makeMarkerCheck('flag-x', 'X'));
159
+ writeFixture('a.ts', 'const x = "X";');
160
+
161
+ const svc = new FitnessRecipeService({
162
+ cwd: testDir,
163
+ checkRegistry,
164
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
165
+ prewarmCache: false,
166
+ callbacks: {
167
+ onCheckStart: (slug) => starts.push(slug),
168
+ onCheckComplete: (slug) => completes.push(slug),
169
+ onComplete: () => { onComplete = true; },
170
+ },
171
+ });
172
+
173
+ await svc.start(makeRecipe());
174
+ expect(starts).toContain('flag-x');
175
+ expect(completes).toContain('flag-x');
176
+ expect(onComplete).toBe(true);
177
+ });
178
+
179
+ it('returns a result with success=false when score < threshold', async () => {
180
+ const checkRegistry = new CheckRegistry();
181
+ checkRegistry.register(makeMarkerCheck('flag-fail', 'FAIL', 'error'));
182
+ writeFixture('a.ts', 'const x = "FAIL";');
183
+
184
+ const svc = new FitnessRecipeService({
185
+ cwd: testDir,
186
+ checkRegistry,
187
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
188
+ prewarmCache: true,
189
+ });
190
+
191
+ const result = await svc.start(makeRecipe({
192
+ execution: { mode: 'parallel', successThreshold: 100, stopOnFirstFailure: false, timeout: 30_000 },
193
+ }));
194
+ expect(result.success).toBe(false);
195
+ expect(result.summary.failedChecks).toBe(1);
196
+ });
197
+
198
+ it('completes a run with no registered checks', async () => {
199
+ const svc = new FitnessRecipeService({
200
+ cwd: testDir,
201
+ checkRegistry: new CheckRegistry(),
202
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
203
+ prewarmCache: false,
204
+ });
205
+
206
+ const result = await svc.start(makeRecipe());
207
+ expect(result.summary.totalChecks).toBe(0);
208
+ expect(result.summary.failedChecks).toBe(0);
209
+ expect(result.summary.totalViolations).toBe(0);
210
+ });
211
+ });
212
+
213
+ // =============================================================================
214
+ // EXECUTION — SEQUENTIAL
215
+ // =============================================================================
216
+
217
+ describe('FitnessRecipeService — sequential execution', () => {
218
+ it('runs checks one at a time when execution.mode === "sequential"', async () => {
219
+ const order: string[] = [];
220
+
221
+ const checkRegistry = new CheckRegistry();
222
+ checkRegistry.register(defineCheck({
223
+ id: uid(), slug: 'first', description: 'first', tags: ['demo'],
224
+ analyze: () => { order.push('first'); return []; },
225
+ }));
226
+ checkRegistry.register(defineCheck({
227
+ id: uid(), slug: 'second', description: 'second', tags: ['demo'],
228
+ analyze: () => { order.push('second'); return []; },
229
+ }));
230
+ writeFixture('a.ts', 'export const x = 1;');
231
+
232
+ const svc = new FitnessRecipeService({
233
+ cwd: testDir,
234
+ checkRegistry,
235
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
236
+ prewarmCache: true,
237
+ });
238
+
239
+ await svc.start(makeRecipe({
240
+ execution: { mode: 'sequential', stopOnFirstFailure: false, timeout: 30_000 },
241
+ }));
242
+ expect(order).toEqual(['first', 'second']);
243
+ });
244
+ });
245
+
246
+ // =============================================================================
247
+ // SELECTOR TYPES
248
+ // =============================================================================
249
+
250
+ describe('FitnessRecipeService — selector types', () => {
251
+ it('selector type=explicit runs only the listed checks', async () => {
252
+ const checkRegistry = new CheckRegistry();
253
+ checkRegistry.register(makeMarkerCheck('selected', 'A'));
254
+ checkRegistry.register(makeMarkerCheck('not-selected', 'B'));
255
+ writeFixture('a.ts', '');
256
+
257
+ const svc = new FitnessRecipeService({
258
+ cwd: testDir,
259
+ checkRegistry,
260
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
261
+ prewarmCache: false,
262
+ });
263
+
264
+ const result = await svc.start(makeRecipe({
265
+ checks: { type: 'explicit', checkIds: ['selected'] },
266
+ }));
267
+ expect(result.summary.totalChecks).toBe(1);
268
+ expect(result.checkResults[0]?.checkSlug).toBe('selected');
269
+ });
270
+
271
+ it('selector type=tags filters by tag', async () => {
272
+ const checkRegistry = new CheckRegistry();
273
+ checkRegistry.register(makeMarkerCheck('q1', 'A', 'warning', ['quality']));
274
+ checkRegistry.register(makeMarkerCheck('s1', 'B', 'warning', ['security']));
275
+ writeFixture('a.ts', '');
276
+
277
+ const svc = new FitnessRecipeService({
278
+ cwd: testDir,
279
+ checkRegistry,
280
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
281
+ prewarmCache: false,
282
+ });
283
+
284
+ const result = await svc.start(makeRecipe({
285
+ checks: { type: 'tags', include: ['security'] },
286
+ }));
287
+ expect(result.summary.totalChecks).toBe(1);
288
+ expect(result.checkResults[0]?.checkSlug).toBe('s1');
289
+ });
290
+
291
+ it('selector type=all with exclude removes listed checks', async () => {
292
+ const checkRegistry = new CheckRegistry();
293
+ checkRegistry.register(makeMarkerCheck('keep-me', 'A'));
294
+ checkRegistry.register(makeMarkerCheck('drop-me', 'B'));
295
+ writeFixture('a.ts', '');
296
+
297
+ const svc = new FitnessRecipeService({
298
+ cwd: testDir,
299
+ checkRegistry,
300
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
301
+ prewarmCache: false,
302
+ });
303
+
304
+ const result = await svc.start(makeRecipe({
305
+ checks: { type: 'all', exclude: ['drop-me'] },
306
+ }));
307
+ expect(result.summary.totalChecks).toBe(1);
308
+ expect(result.checkResults[0]?.checkSlug).toBe('keep-me');
309
+ });
310
+ });
311
+
312
+ // =============================================================================
313
+ // DISABLED CHECKS
314
+ // =============================================================================
315
+
316
+ describe('FitnessRecipeService — disabled checks', () => {
317
+ it('skips checks listed in disabledChecks config', async () => {
318
+ const checkRegistry = new CheckRegistry();
319
+ checkRegistry.register(makeMarkerCheck('runs', 'A'));
320
+ checkRegistry.register(makeMarkerCheck('disabled', 'B'));
321
+ writeFixture('a.ts', '');
322
+
323
+ const svc = new FitnessRecipeService({
324
+ cwd: testDir,
325
+ checkRegistry,
326
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
327
+ prewarmCache: false,
328
+ disabledChecks: ['disabled'],
329
+ });
330
+
331
+ const result = await svc.start(makeRecipe());
332
+ expect(result.summary.totalChecks).toBe(1);
333
+ expect(result.checkResults[0]?.checkSlug).toBe('runs');
334
+ });
335
+
336
+ it('runs checks in disabledChecks when listed in recipe.includeDisabled', async () => {
337
+ const checkRegistry = new CheckRegistry();
338
+ checkRegistry.register(makeMarkerCheck('forced', 'A'));
339
+ writeFixture('a.ts', '');
340
+
341
+ const svc = new FitnessRecipeService({
342
+ cwd: testDir,
343
+ checkRegistry,
344
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
345
+ prewarmCache: false,
346
+ disabledChecks: ['forced'],
347
+ });
348
+
349
+ const result = await svc.start(makeRecipe({ includeDisabled: ['forced'] }));
350
+ expect(result.summary.totalChecks).toBe(1);
351
+ });
352
+ });
353
+
354
+ // =============================================================================
355
+ // ERRORS + EDGE CASES
356
+ // =============================================================================
357
+
358
+ describe('FitnessRecipeService — errors', () => {
359
+ it('throws NotFoundError when run() receives an unknown recipe name', async () => {
360
+ const svc = new FitnessRecipeService({
361
+ cwd: testDir,
362
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
363
+ prewarmCache: false,
364
+ });
365
+ await expect(svc.start('does-not-exist')).rejects.toThrow(/Recipe not found/);
366
+ });
367
+
368
+ it('throws SystemError when start() is called twice in parallel', async () => {
369
+ const checkRegistry = new CheckRegistry();
370
+ checkRegistry.register(defineCheck({
371
+ id: uid(), slug: 'slow', description: 's', tags: ['demo'],
372
+ analyzeAll: async () => {
373
+ await new Promise((r) => setTimeout(r, 50));
374
+ return [];
375
+ },
376
+ }));
377
+ writeFixture('a.ts', '');
378
+
379
+ const svc = new FitnessRecipeService({
380
+ cwd: testDir,
381
+ checkRegistry,
382
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
383
+ prewarmCache: false,
384
+ });
385
+
386
+ const p1 = svc.start(makeRecipe());
387
+ await expect(svc.start(makeRecipe())).rejects.toThrow(/already in progress/);
388
+ await p1;
389
+ });
390
+
391
+ it('captures errors thrown inside a check without aborting the run', async () => {
392
+ const checkRegistry = new CheckRegistry();
393
+ checkRegistry.register(defineCheck({
394
+ id: uid(), slug: 'crashes', description: 'c', tags: ['demo'],
395
+ analyze: () => { throw new Error('check exploded'); },
396
+ }));
397
+ checkRegistry.register(makeMarkerCheck('survives', 'X'));
398
+ writeFixture('a.ts', 'export const x = "X";');
399
+
400
+ const svc = new FitnessRecipeService({
401
+ cwd: testDir,
402
+ checkRegistry,
403
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
404
+ prewarmCache: true,
405
+ });
406
+
407
+ const result = await svc.start(makeRecipe());
408
+ expect(result.summary.totalChecks).toBe(2);
409
+ // The crash is contained: "survives" still completes
410
+ const survives = result.checkResults.find((r) => r.checkSlug === 'survives');
411
+ expect(survives?.error).toBeUndefined();
412
+ });
413
+ });
414
+
415
+ // =============================================================================
416
+ // AD-HOC RECIPE FACTORY
417
+ // =============================================================================
418
+
419
+ describe('FitnessRecipeService.createAdHocRecipe', () => {
420
+ it('builds an explicit-selector recipe when --check is passed', () => {
421
+ const recipe = FitnessRecipeService.createAdHocRecipe({ check: 'no-console-log' });
422
+ expect(recipe.checks.type).toBe('explicit');
423
+ if (recipe.checks.type === 'explicit') {
424
+ expect(recipe.checks.checkIds).toEqual(['no-console-log']);
425
+ }
426
+ expect(recipe.includeDisabled).toEqual(['no-console-log']);
427
+ });
428
+
429
+ it('builds a pattern-selector recipe when --check contains wildcard', () => {
430
+ const recipe = FitnessRecipeService.createAdHocRecipe({ check: 'no-*' });
431
+ expect(recipe.checks.type).toBe('pattern');
432
+ });
433
+
434
+ it('builds a tags-selector recipe when --tags is passed', () => {
435
+ const recipe = FitnessRecipeService.createAdHocRecipe({ tagFilters: ['security', 'quality'] });
436
+ expect(recipe.checks.type).toBe('tags');
437
+ if (recipe.checks.type === 'tags') {
438
+ expect(recipe.checks.include).toEqual(['security', 'quality']);
439
+ }
440
+ });
441
+
442
+ it('falls back to all-selector when nothing is passed', () => {
443
+ const recipe = FitnessRecipeService.createAdHocRecipe({});
444
+ expect(recipe.checks.type).toBe('all');
445
+ });
446
+
447
+ it('honors --parallel=false', () => {
448
+ const recipe = FitnessRecipeService.createAdHocRecipe({ parallel: false });
449
+ expect(recipe.execution.mode).toBe('sequential');
450
+ });
451
+
452
+ it('respects --json + --unified for reporting format', () => {
453
+ const json = FitnessRecipeService.createAdHocRecipe({ json: true });
454
+ expect(json.reporting.format).toBe('json');
455
+ const unified = FitnessRecipeService.createAdHocRecipe({ json: true, unified: true });
456
+ expect(unified.reporting.format).toBe('unified');
457
+ });
458
+ });
459
+
460
+ // =============================================================================
461
+ // ABORT
462
+ // =============================================================================
463
+
464
+ describe('FitnessRecipeService — abort', () => {
465
+ it('abort() while no session is running is a no-op', () => {
466
+ const svc = new FitnessRecipeService();
467
+ expect(() => svc.abort()).not.toThrow();
468
+ });
469
+
470
+ it('abort() during a run cancels remaining checks', async () => {
471
+ const checkRegistry = new CheckRegistry();
472
+ let secondRan = false;
473
+ checkRegistry.register(defineCheck({
474
+ id: uid(), slug: 'first', description: 'first', tags: ['demo'],
475
+ analyzeAll: async () => {
476
+ await new Promise((r) => setTimeout(r, 10));
477
+ return [];
478
+ },
479
+ }));
480
+ checkRegistry.register(defineCheck({
481
+ id: uid(), slug: 'second', description: 'second', tags: ['demo'],
482
+ analyze: () => { secondRan = true; return []; },
483
+ }));
484
+ writeFixture('a.ts', '');
485
+
486
+ const svc = new FitnessRecipeService({
487
+ cwd: testDir,
488
+ checkRegistry,
489
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
490
+ prewarmCache: false,
491
+ });
492
+
493
+ // sequential mode lets us reliably interrupt mid-run
494
+ const promise = svc.start(makeRecipe({
495
+ execution: { mode: 'sequential', stopOnFirstFailure: false, timeout: 30_000 },
496
+ }));
497
+ setTimeout(() => svc.abort(), 5);
498
+ await promise;
499
+
500
+ // Whether or not the second ran is timing-dependent, but abort()
501
+ // should not throw and the run should complete.
502
+ expect(typeof secondRan).toBe('boolean');
503
+ });
504
+ });
505
+
506
+ // =============================================================================
507
+ // PER-CHECK TIMEOUT
508
+ // =============================================================================
509
+
510
+ describe('FitnessRecipeService — timeout', () => {
511
+ it('exposes a per-check timeout option in the recipe execution config', async () => {
512
+ const checkRegistry = new CheckRegistry();
513
+ checkRegistry.register(makeMarkerCheck('q', 'X'));
514
+ writeFixture('a.ts', 'const a = "X";');
515
+
516
+ const svc = new FitnessRecipeService({
517
+ cwd: testDir,
518
+ checkRegistry,
519
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
520
+ prewarmCache: true,
521
+ });
522
+
523
+ // A non-timing-out run still completes cleanly when timeout is set.
524
+ const result = await svc.start(makeRecipe({
525
+ execution: { mode: 'parallel', stopOnFirstFailure: false, timeout: 5000 },
526
+ }));
527
+ expect(result.summary.totalChecks).toBe(1);
528
+ expect(result.checkResults[0]?.timedOut).not.toBe(true);
529
+ });
530
+ });
531
+
532
+ // =============================================================================
533
+ // includeViolations CONFIG
534
+ // =============================================================================
535
+
536
+ describe('FitnessRecipeService — includeViolations', () => {
537
+ it('omits per-violation detail by default', async () => {
538
+ const checkRegistry = new CheckRegistry();
539
+ checkRegistry.register(makeMarkerCheck('flag-x', 'X'));
540
+ writeFixture('a.ts', 'const a = "X";');
541
+
542
+ const svc = new FitnessRecipeService({
543
+ cwd: testDir,
544
+ checkRegistry,
545
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
546
+ prewarmCache: true,
547
+ });
548
+
549
+ const result = await svc.start(makeRecipe());
550
+ const cr = result.checkResults[0];
551
+ expect(cr?.violations).toBeUndefined();
552
+ });
553
+
554
+ it('carries violation detail when includeViolations is true', async () => {
555
+ const checkRegistry = new CheckRegistry();
556
+ checkRegistry.register(makeMarkerCheck('flag-x', 'X'));
557
+ writeFixture('a.ts', 'const a = "X";');
558
+
559
+ const svc = new FitnessRecipeService({
560
+ cwd: testDir,
561
+ checkRegistry,
562
+ recipeRegistry: new FitnessRecipeRegistry({ loadUserRecipes: false, logWarnings: false }),
563
+ prewarmCache: true,
564
+ includeViolations: true,
565
+ });
566
+
567
+ const result = await svc.start(makeRecipe());
568
+ const cr = result.checkResults[0];
569
+ expect(cr?.violations).toBeDefined();
570
+ expect(cr?.violations?.length).toBeGreaterThan(0);
571
+ });
572
+ });