@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,170 @@
1
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+
5
+ import { ValidationError } from '@opensip-tools/core';
6
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
7
+
8
+ import { loadTargetsConfig } from '../loader.js';
9
+
10
+ let testDir: string;
11
+
12
+ beforeEach(() => {
13
+
14
+ testDir = mkdtempSync(join(tmpdir(), 'opensip-targets-loader-'));
15
+ });
16
+
17
+ afterEach(() => {
18
+ rmSync(testDir, { recursive: true, force: true });
19
+ });
20
+
21
+ describe('loadTargetsConfig', () => {
22
+ it('loads a minimal targets config', () => {
23
+ writeFileSync(
24
+ join(testDir, 'opensip-tools.config.yml'),
25
+ `targets:
26
+ src:
27
+ description: Source
28
+ include:
29
+ - "src/**/*.ts"
30
+ `,
31
+ );
32
+ const { registry, config } = loadTargetsConfig(testDir);
33
+ expect(registry.has('src')).toBe(true);
34
+ expect(config.globalExcludes).toEqual([]);
35
+ });
36
+
37
+ it('applies default exclude patterns when none provided', () => {
38
+ writeFileSync(
39
+ join(testDir, 'opensip-tools.config.yml'),
40
+ `targets:
41
+ src:
42
+ description: Source
43
+ include: ["src/**"]
44
+ `,
45
+ );
46
+ const { registry } = loadTargetsConfig(testDir);
47
+ const target = registry.getAll().find((t) => t.config.name === 'src');
48
+ expect(target?.config.exclude).toContain('**/node_modules/**');
49
+ });
50
+
51
+ it('preserves custom exclude patterns when provided', () => {
52
+ writeFileSync(
53
+ join(testDir, 'opensip-tools.config.yml'),
54
+ `targets:
55
+ src:
56
+ description: Source
57
+ include: ["src/**"]
58
+ exclude:
59
+ - "src/legacy/**"
60
+ `,
61
+ );
62
+ const { registry } = loadTargetsConfig(testDir);
63
+ const target = registry.getAll().find((t) => t.config.name === 'src');
64
+ expect(target?.config.exclude).toEqual(['src/legacy/**']);
65
+ });
66
+
67
+ it('parses globalExcludes', () => {
68
+ writeFileSync(
69
+ join(testDir, 'opensip-tools.config.yml'),
70
+ `globalExcludes:
71
+ - "**/docs/**"
72
+ targets:
73
+ src:
74
+ description: x
75
+ include: ["src/**"]
76
+ `,
77
+ );
78
+ const { config } = loadTargetsConfig(testDir);
79
+ expect(config.globalExcludes).toEqual(['**/docs/**']);
80
+ });
81
+
82
+ it('parses checkOverrides as string and as array', () => {
83
+ writeFileSync(
84
+ join(testDir, 'opensip-tools.config.yml'),
85
+ `targets:
86
+ src:
87
+ description: x
88
+ include: ["src/**"]
89
+ tests:
90
+ description: y
91
+ include: ["test/**"]
92
+ checkOverrides:
93
+ no-console-log: src
94
+ multi-target: [src, tests]
95
+ `,
96
+ );
97
+ const { config } = loadTargetsConfig(testDir);
98
+ expect(config.checkOverrides['no-console-log']).toBe('src');
99
+ expect(config.checkOverrides['multi-target']).toEqual(['src', 'tests']);
100
+ });
101
+
102
+ it('throws when checkOverrides references an unknown target', () => {
103
+ writeFileSync(
104
+ join(testDir, 'opensip-tools.config.yml'),
105
+ `targets:
106
+ src:
107
+ description: x
108
+ include: ["src/**"]
109
+ checkOverrides:
110
+ some-check: nonexistent
111
+ `,
112
+ );
113
+ expect(() => loadTargetsConfig(testDir)).toThrow(/unknown target/);
114
+ });
115
+
116
+ it('parses plugins block with all keys', () => {
117
+ writeFileSync(
118
+ join(testDir, 'opensip-tools.config.yml'),
119
+ `targets:
120
+ src:
121
+ description: x
122
+ include: ["src/**"]
123
+ plugins:
124
+ fit: ["@a/b"]
125
+ sim: ["@c/d"]
126
+ checkPackages: ["@e/f"]
127
+ autoDiscoverChecks: false
128
+ `,
129
+ );
130
+ const { config } = loadTargetsConfig(testDir);
131
+ expect(config.plugins?.fit).toEqual(['@a/b']);
132
+ expect(config.plugins?.sim).toEqual(['@c/d']);
133
+ expect(config.plugins?.checkPackages).toEqual(['@e/f']);
134
+ expect(config.plugins?.autoDiscoverChecks).toBe(false);
135
+ });
136
+
137
+ it('throws ValidationError when target name is not kebab-case', () => {
138
+ writeFileSync(
139
+ join(testDir, 'opensip-tools.config.yml'),
140
+ `targets:
141
+ Bad_Name:
142
+ description: x
143
+ include: ["y"]
144
+ `,
145
+ );
146
+ expect(() => loadTargetsConfig(testDir)).toThrow(ValidationError);
147
+ });
148
+
149
+ it('throws when the config file is missing', () => {
150
+ expect(() => loadTargetsConfig(testDir)).toThrow();
151
+ });
152
+
153
+ it('throws ValidationError when YAML is malformed', () => {
154
+ writeFileSync(join(testDir, 'opensip-tools.config.yml'), 'targets: [unbalanced\n');
155
+ expect(() => loadTargetsConfig(testDir)).toThrow(ValidationError);
156
+ });
157
+
158
+ it('respects an explicit --config path', () => {
159
+ writeFileSync(
160
+ join(testDir, 'custom.yml'),
161
+ `targets:
162
+ custom:
163
+ description: x
164
+ include: ["x"]
165
+ `,
166
+ );
167
+ const { registry } = loadTargetsConfig(testDir, join(testDir, 'custom.yml'));
168
+ expect(registry.has('custom')).toBe(true);
169
+ });
170
+ });
@@ -0,0 +1,74 @@
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+
5
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
6
+
7
+ import { resolveTargetFiles } from '../resolver.js';
8
+
9
+ import type { Target } from '../types.js';
10
+
11
+ let testDir: string;
12
+
13
+ const stub = (include: string[], exclude: string[] = []): Target => ({
14
+ config: { name: 't', description: 't', include, exclude },
15
+ });
16
+
17
+ beforeEach(() => {
18
+
19
+ testDir = mkdtempSync(join(tmpdir(), 'opensip-resolver-'));
20
+ mkdirSync(join(testDir, 'src'), { recursive: true });
21
+ mkdirSync(join(testDir, 'src', 'sub'), { recursive: true });
22
+ mkdirSync(join(testDir, 'tests'), { recursive: true });
23
+ writeFileSync(join(testDir, 'src', 'a.ts'), '');
24
+ writeFileSync(join(testDir, 'src', 'b.ts'), '');
25
+ writeFileSync(join(testDir, 'src', 'sub', 'c.ts'), '');
26
+ writeFileSync(join(testDir, 'src', 'a.test.ts'), '');
27
+ writeFileSync(join(testDir, 'tests', 'd.ts'), '');
28
+ });
29
+
30
+ afterEach(() => {
31
+ rmSync(testDir, { recursive: true, force: true });
32
+ });
33
+
34
+ describe('resolveTargetFiles', () => {
35
+ it('expands include globs to absolute paths', () => {
36
+ const files = resolveTargetFiles([stub(['src/**/*.ts'])], testDir);
37
+ expect(files.length).toBeGreaterThan(0);
38
+ expect(files.every((f) => f.startsWith(testDir))).toBe(true);
39
+ });
40
+
41
+ it('respects exclude globs', () => {
42
+ const files = resolveTargetFiles([stub(['src/**/*.ts'], ['**/*.test.ts'])], testDir);
43
+ expect(files.some((f) => f.endsWith('.test.ts'))).toBe(false);
44
+ expect(files.some((f) => f.endsWith('a.ts'))).toBe(true);
45
+ });
46
+
47
+ it('deduplicates files matching multiple targets', () => {
48
+ const files = resolveTargetFiles(
49
+ [stub(['src/*.ts']), stub(['src/**/*.ts'])],
50
+ testDir,
51
+ );
52
+ const unique = new Set(files);
53
+ expect(files.length).toBe(unique.size);
54
+ });
55
+
56
+ it('returns sorted output', () => {
57
+ const files = resolveTargetFiles([stub(['src/**/*.ts'])], testDir);
58
+ const sorted = [...files].sort();
59
+ expect(files).toEqual(sorted);
60
+ });
61
+
62
+ it('returns empty when nothing matches', () => {
63
+ expect(resolveTargetFiles([stub(['nonexistent/**'])], testDir)).toEqual([]);
64
+ });
65
+
66
+ it('combines results across multiple targets', () => {
67
+ const files = resolveTargetFiles(
68
+ [stub(['src/a.ts']), stub(['tests/d.ts'])],
69
+ testDir,
70
+ );
71
+ expect(files.some((f) => f.endsWith('a.ts'))).toBe(true);
72
+ expect(files.some((f) => f.endsWith('d.ts'))).toBe(true);
73
+ });
74
+ });
@@ -0,0 +1,103 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { TargetRegistry } from '../target-registry.js';
4
+
5
+ import type { Target } from '../types.js';
6
+
7
+ const stub = (name: string, opts: { tags?: string[]; languages?: string[]; concerns?: string[] } = {}): Target => ({
8
+ config: {
9
+ name,
10
+ description: name,
11
+ include: [`${name}/**`],
12
+ exclude: [],
13
+ ...(opts.tags && { tags: opts.tags }),
14
+ ...(opts.languages && { languages: opts.languages }),
15
+ ...(opts.concerns && { concerns: opts.concerns }),
16
+ },
17
+ });
18
+
19
+ describe('TargetRegistry', () => {
20
+ it('register adds new targets and returns this for chaining', () => {
21
+ const reg = new TargetRegistry();
22
+ const result = reg.register(stub('a')).register(stub('b'));
23
+ expect(result).toBe(reg);
24
+ expect(reg.size).toBe(2);
25
+ });
26
+
27
+ it('register silently skips duplicate names', () => {
28
+ const reg = new TargetRegistry();
29
+ reg.register(stub('a'));
30
+ reg.register(stub('a'));
31
+ expect(reg.size).toBe(1);
32
+ });
33
+
34
+ it('getByName / has lookups', () => {
35
+ const reg = new TargetRegistry();
36
+ const a = stub('a');
37
+ reg.register(a);
38
+ expect(reg.getByName('a')).toBe(a);
39
+ expect(reg.getByName('nope')).toBeUndefined();
40
+ expect(reg.has('a')).toBe(true);
41
+ expect(reg.has('nope')).toBe(false);
42
+ });
43
+
44
+ it('getAll returns the live set, but a fresh array each call', () => {
45
+ const reg = new TargetRegistry();
46
+ reg.register(stub('a'));
47
+ const snapshot = reg.getAll();
48
+ expect(snapshot).toHaveLength(1);
49
+ (snapshot as Target[]).pop();
50
+ expect(reg.getAll()).toHaveLength(1); // not affected
51
+ });
52
+
53
+ it('getByTag filters by config.tags', () => {
54
+ const reg = new TargetRegistry();
55
+ reg.register(stub('a', { tags: ['fast'] }));
56
+ reg.register(stub('b', { tags: ['slow'] }));
57
+ reg.register(stub('c'));
58
+ expect(reg.getByTag('fast').map((t) => t.config.name)).toEqual(['a']);
59
+ });
60
+
61
+ describe('findByScope', () => {
62
+ it('returns targets whose languages intersect when both sides specify', () => {
63
+ const reg = new TargetRegistry();
64
+ reg.register(stub('ts', { languages: ['typescript'], concerns: ['backend'] }));
65
+ reg.register(stub('rs', { languages: ['rust'], concerns: ['backend'] }));
66
+ const matched = reg.findByScope(['typescript'], ['backend']);
67
+ expect(matched.map((t) => t.config.name)).toEqual(['ts']);
68
+ });
69
+
70
+ it('treats empty check languages as "matches any"', () => {
71
+ const reg = new TargetRegistry();
72
+ reg.register(stub('ts', { languages: ['typescript'], concerns: ['backend'] }));
73
+ reg.register(stub('rs', { languages: ['rust'], concerns: ['backend'] }));
74
+ expect(reg.findByScope([], ['backend'])).toHaveLength(2);
75
+ });
76
+
77
+ it('treats targets with no languages as "matches any check language"', () => {
78
+ const reg = new TargetRegistry();
79
+ reg.register(stub('any-lang', { concerns: ['backend'] })); // no languages
80
+ expect(reg.findByScope(['typescript'], ['backend'])).toHaveLength(1);
81
+ });
82
+
83
+ it('treats empty check concerns as "matches any"', () => {
84
+ const reg = new TargetRegistry();
85
+ reg.register(stub('ts', { languages: ['typescript'], concerns: ['backend'] }));
86
+ expect(reg.findByScope(['typescript'], [])).toHaveLength(1);
87
+ });
88
+
89
+ it('requires both dimensions to match', () => {
90
+ const reg = new TargetRegistry();
91
+ reg.register(stub('ts-frontend', { languages: ['typescript'], concerns: ['frontend'] }));
92
+ expect(reg.findByScope(['typescript'], ['backend'])).toEqual([]);
93
+ });
94
+ });
95
+
96
+ it('clear removes everything', () => {
97
+ const reg = new TargetRegistry();
98
+ reg.register(stub('a'));
99
+ reg.clear();
100
+ expect(reg.size).toBe(0);
101
+ expect(reg.getAll()).toEqual([]);
102
+ });
103
+ });
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @fileoverview Target system barrel export
3
+ *
4
+ * Public API for config-driven targets:
5
+ * - loadTargetsConfig() — Load from opensip-tools.config.yml
6
+ * - resolveTargetFiles() — Expand globs, deduplicate
7
+ */
8
+
9
+ // Loader
10
+ export { loadTargetsConfig } from './loader.js'
11
+
12
+ // Resolver
13
+ export { resolveTargetFiles } from './resolver.js'
@@ -0,0 +1,214 @@
1
+ // @fitness-ignore-file batch-operation-limits -- iterates bounded collections (config entries, registry items, or small analysis results)
2
+ /**
3
+ * @fileoverview Target config loader
4
+ *
5
+ * Loads target configuration from opensip-tools.config.yml in the project root.
6
+ * Validates with Zod and populates a TargetRegistry.
7
+ */
8
+
9
+ import { readFileSync, statSync } from 'node:fs'
10
+
11
+ import { PROJECT_CONFIG_FILENAME, resolveProjectConfigPath , ValidationError, SystemError } from '@opensip-tools/core'
12
+ import yaml from 'js-yaml'
13
+ import { z } from 'zod'
14
+
15
+
16
+ import { TargetRegistry } from './target-registry.js'
17
+
18
+ import type { TargetConfig, TargetsConfig } from './types.js'
19
+
20
+ const YAML_FILENAME = PROJECT_CONFIG_FILENAME
21
+ const DEFAULT_EXCLUDES: readonly string[] = ['**/node_modules/**', '**/dist/**']
22
+
23
+ // =============================================================================
24
+ // YAML schemas
25
+ // =============================================================================
26
+
27
+ const TargetEntrySchema = z.object({
28
+ description: z.string().min(1, 'description is required'),
29
+ include: z.array(z.string()).min(1, 'at least one include pattern is required'),
30
+ exclude: z.array(z.string()).optional(),
31
+ tags: z.array(z.string()).optional(),
32
+ languages: z.array(z.string()).optional(),
33
+ concerns: z.array(z.string()).optional(),
34
+ })
35
+
36
+ const CheckTargetValueSchema = z.union([
37
+ z.string(),
38
+ z.array(z.string()).min(1),
39
+ ])
40
+
41
+ const PluginsSchema = z.object({
42
+ fit: z.array(z.string()).optional(),
43
+ sim: z.array(z.string()).optional(),
44
+ asm: z.array(z.string()).optional(),
45
+ lang: z.array(z.string()).optional(),
46
+ checkPackages: z.array(z.string()).optional(),
47
+ autoDiscoverChecks: z.boolean().optional(),
48
+ }).optional()
49
+
50
+ const TargetsFileSchema = z.object({
51
+ targets: z.record(
52
+ z.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, 'target name must be kebab-case'),
53
+ TargetEntrySchema,
54
+ ),
55
+ globalExcludes: z.array(z.string()).optional(),
56
+ checkOverrides: z.record(z.string(), CheckTargetValueSchema).optional(),
57
+ plugins: PluginsSchema,
58
+ })
59
+
60
+ // =============================================================================
61
+ // Build registry + config from parsed data
62
+ // =============================================================================
63
+
64
+ /** @throws {ValidationError} When checkOverrides references an unknown target */
65
+ // eslint-disable-next-line sonarjs/cognitive-complexity -- inherent complexity: registry population + cross-validation
66
+ function buildFromParsed(
67
+ targets: Record<string, { description: string; include: readonly string[]; exclude?: readonly string[]; tags?: readonly string[]; languages?: readonly string[]; concerns?: readonly string[] }>,
68
+ rawGlobalExcludes: readonly string[] | undefined,
69
+ rawCheckOverrides: Record<string, string | readonly string[]> | undefined,
70
+ sourceLabel: string,
71
+ rawPlugins?: {
72
+ fit?: readonly string[]
73
+ sim?: readonly string[]
74
+ asm?: readonly string[]
75
+ lang?: readonly string[]
76
+ checkPackages?: readonly string[]
77
+ autoDiscoverChecks?: boolean
78
+ },
79
+ ): { registry: TargetRegistry; config: TargetsConfig } {
80
+ const registry = new TargetRegistry()
81
+
82
+ for (const [name, entry] of Object.entries(targets)) {
83
+ const config: TargetConfig = Object.freeze({
84
+ name,
85
+ description: entry.description,
86
+ include: Object.freeze([...entry.include]),
87
+ exclude: Object.freeze([...(entry.exclude ?? DEFAULT_EXCLUDES)]),
88
+ ...(entry.tags && { tags: Object.freeze([...entry.tags]) }),
89
+ ...(entry.languages && { languages: Object.freeze([...entry.languages]) }),
90
+ ...(entry.concerns && { concerns: Object.freeze([...entry.concerns]) }),
91
+ })
92
+ registry.register(Object.freeze({ config }))
93
+ }
94
+
95
+ const checkOverrides: Record<string, string | readonly string[]> = {}
96
+ if (rawCheckOverrides) {
97
+ for (const [checkSlug, targetRef] of Object.entries(rawCheckOverrides)) {
98
+ const targetNames = typeof targetRef === 'string' ? [targetRef] : targetRef
99
+ for (const name of targetNames) {
100
+ if (!registry.has(name)) {
101
+ // @fitness-ignore-next-line result-pattern-consistency -- infrastructure boundary, throw is appropriate
102
+ throw new ValidationError(
103
+ `${sourceLabel}: checkOverrides['${checkSlug}'] references unknown target '${name}'. ` +
104
+ `Available targets: ${registry.getAll().map((t) => t.config.name).join(', ')}`,
105
+ { code: 'ERRORS.TARGETS.UNKNOWN_TARGET' },
106
+ )
107
+ }
108
+ }
109
+ checkOverrides[checkSlug] = typeof targetRef === 'string' ? targetRef : Object.freeze([...targetRef])
110
+ }
111
+ }
112
+
113
+ const plugins = rawPlugins
114
+ ? Object.freeze({
115
+ ...(rawPlugins.fit && { fit: Object.freeze([...rawPlugins.fit]) }),
116
+ ...(rawPlugins.sim && { sim: Object.freeze([...rawPlugins.sim]) }),
117
+ ...(rawPlugins.asm && { asm: Object.freeze([...rawPlugins.asm]) }),
118
+ ...(rawPlugins.lang && { lang: Object.freeze([...rawPlugins.lang]) }),
119
+ ...(rawPlugins.checkPackages && { checkPackages: Object.freeze([...rawPlugins.checkPackages]) }),
120
+ ...(rawPlugins.autoDiscoverChecks !== undefined && { autoDiscoverChecks: rawPlugins.autoDiscoverChecks }),
121
+ })
122
+ : undefined
123
+
124
+ const config: TargetsConfig = Object.freeze({
125
+ globalExcludes: Object.freeze(rawGlobalExcludes ? [...rawGlobalExcludes] : []),
126
+ checkOverrides: Object.freeze(checkOverrides),
127
+ ...(plugins && { plugins }),
128
+ })
129
+
130
+ return { registry, config }
131
+ }
132
+
133
+ // =============================================================================
134
+ // YAML config loader
135
+ // =============================================================================
136
+
137
+ const MAX_FILE_SIZE = 10 * 1024 * 1024 // 10 MB
138
+
139
+ /** @throws {ValidationError} When the file is too large, missing, or unreadable */
140
+ function readYamlFile(filePath: string): string {
141
+ try {
142
+ const stats = statSync(filePath)
143
+ if (stats.size > MAX_FILE_SIZE) {
144
+ throw new SystemError(`File too large (${stats.size} bytes, max ${MAX_FILE_SIZE}): ${filePath}`, { code: 'SYSTEM.FILE.TOO_LARGE' })
145
+ }
146
+ return readFileSync(filePath, 'utf8')
147
+ } catch (error) {
148
+ if (error instanceof ValidationError || error instanceof SystemError) throw error
149
+ throw new ValidationError(
150
+ `${YAML_FILENAME} not found at ${filePath}. Create one to define your targets.`,
151
+ { operation: 'load', loader: 'targets' },
152
+ )
153
+ }
154
+ }
155
+
156
+ /** @throws {ValidationError} When the YAML is malformed */
157
+ function parseYamlContent(raw: string): unknown {
158
+ try {
159
+ return yaml.load(raw)
160
+ } catch (error) {
161
+ const message = error instanceof Error ? error.message : String(error)
162
+ throw new ValidationError(`${YAML_FILENAME} contains invalid YAML: ${message}`, {
163
+ operation: 'load',
164
+ loader: 'targets',
165
+ cause: error instanceof Error ? error : undefined,
166
+ })
167
+ }
168
+ }
169
+
170
+ /**
171
+ * @throws {ValidationError} When the file is missing or contains invalid YAML
172
+ * @throws {ValidationError} When the file fails schema validation
173
+ */
174
+ function loadYamlConfig(filePath: string): { registry: TargetRegistry; config: TargetsConfig } {
175
+ const raw = readYamlFile(filePath)
176
+ const parsed = parseYamlContent(raw)
177
+
178
+ const result = TargetsFileSchema.safeParse(parsed)
179
+ if (!result.success) {
180
+ const issues = result.error.issues
181
+ .map((i) => ` ${i.path.join('.')}: ${i.message}`)
182
+ .join('\n')
183
+ // @fitness-ignore-next-line result-pattern-consistency -- infrastructure boundary, throw is appropriate
184
+ throw new ValidationError(`${YAML_FILENAME} validation failed:\n${issues}`, {
185
+ code: 'ERRORS.TARGETS.VALIDATION_FAILED',
186
+ })
187
+ }
188
+
189
+ return buildFromParsed(
190
+ result.data.targets,
191
+ result.data.globalExcludes,
192
+ result.data.checkOverrides,
193
+ YAML_FILENAME,
194
+ result.data.plugins,
195
+ )
196
+ }
197
+
198
+ // =============================================================================
199
+ // Public API
200
+ // =============================================================================
201
+
202
+ /**
203
+ * Load full targets config including per-check target overrides.
204
+ * Resolves via the shared project-config resolver.
205
+ * @throws {ValidationError} When no targets config file is found or it cannot be loaded
206
+ * @throws {ValidationError} When the config file fails schema validation
207
+ */
208
+ export function loadTargetsConfig(
209
+ rootDir: string,
210
+ explicitPath?: string,
211
+ ): { registry: TargetRegistry; config: TargetsConfig } {
212
+ const yamlPath = resolveProjectConfigPath(rootDir, explicitPath)
213
+ return loadYamlConfig(yamlPath)
214
+ }
@@ -0,0 +1,44 @@
1
+ // @fitness-ignore-file batch-operation-limits -- iterates bounded collections (config entries, registry items, or small analysis results)
2
+ /**
3
+ * @fileoverview Target file resolver
4
+ *
5
+ * Expands target glob patterns to concrete file paths,
6
+ * deduplicating across multiple targets.
7
+ */
8
+
9
+ import { resolve } from 'node:path'
10
+
11
+ import { globSync } from 'glob'
12
+
13
+ import type { Target } from './types.js'
14
+
15
+ /**
16
+ * Resolve multiple targets to a deduplicated list of file paths.
17
+ *
18
+ * Expands include globs, filters out exclude globs, and deduplicates
19
+ * across all targets so no file is processed twice.
20
+ *
21
+ * @param targets - Targets to resolve
22
+ * @param rootDir - Project root for glob resolution
23
+ * @returns Sorted, deduplicated array of absolute file paths
24
+ */
25
+ export function resolveTargetFiles(targets: readonly Target[], rootDir: string): string[] {
26
+ const files = new Set<string>()
27
+
28
+ for (const target of targets) {
29
+ const { include, exclude } = target.config
30
+
31
+ for (const pattern of include) {
32
+ const matches = globSync(pattern, {
33
+ cwd: rootDir,
34
+ ignore: [...exclude],
35
+ absolute: true,
36
+ })
37
+ for (const match of matches) {
38
+ files.add(resolve(match))
39
+ }
40
+ }
41
+ }
42
+
43
+ return [...files].sort()
44
+ }