@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,157 @@
1
+ import * as ts from 'typescript';
2
+ import { describe, expect, it } from 'vitest';
3
+
4
+ import {
5
+ getIdentifierName,
6
+ getLineNumber,
7
+ getPropertyChain,
8
+ isInStringLiteral,
9
+ isLiteral,
10
+ isPropertyAccess,
11
+ parseSource,
12
+ walkNodes,
13
+ } from '../ast-utilities.js';
14
+
15
+ const parse = (content: string) => parseSource(content, 'x.ts');
16
+
17
+ describe('parseSource', () => {
18
+ it('parses valid TypeScript', () => {
19
+ expect(parse('const x = 1;')).not.toBeNull();
20
+ });
21
+
22
+ it('returns null on parse failure', () => {
23
+ expect(parseSource(undefined as unknown as string, 'x.ts')).toBeNull();
24
+ });
25
+ });
26
+
27
+ describe('walkNodes', () => {
28
+ it('visits every descendant node', () => {
29
+ const sf = parse('const x = 1; const y = 2;');
30
+ if (!sf) throw new Error('parse failed');
31
+ let count = 0;
32
+ walkNodes(sf, () => count++);
33
+ expect(count).toBeGreaterThan(2);
34
+ });
35
+ });
36
+
37
+ describe('getIdentifierName / getPropertyChain', () => {
38
+ it('returns identifier text', () => {
39
+ const sf = parse('foo;');
40
+ if (!sf) throw new Error('parse failed');
41
+ let leaf = '';
42
+ walkNodes(sf, (n) => {
43
+ if (ts.isIdentifier(n) && leaf === '') leaf = getIdentifierName(n);
44
+ });
45
+ expect(leaf).toBe('foo');
46
+ });
47
+
48
+ it('returns property chain', () => {
49
+ const sf = parse('a.b.c;');
50
+ if (!sf) throw new Error('parse failed');
51
+ let result = '';
52
+ walkNodes(sf, (n) => {
53
+ if (ts.isPropertyAccessExpression(n) && result === '') result = getPropertyChain(n);
54
+ });
55
+ expect(result).toBe('a.b.c');
56
+ });
57
+
58
+ it('returns empty for non-identifier non-property nodes', () => {
59
+ const sf = parse('1 + 2;');
60
+ if (!sf) throw new Error('parse failed');
61
+ let result = '';
62
+ walkNodes(sf, (n) => {
63
+ if (ts.isBinaryExpression(n)) {
64
+ result = getIdentifierName(n);
65
+ }
66
+ });
67
+ expect(result).toBe('');
68
+ });
69
+
70
+ it('getPropertyChain returns empty for non-identifier non-property', () => {
71
+ const sf = parse('1 + 2;');
72
+ if (!sf) throw new Error('parse failed');
73
+ let result = '';
74
+ walkNodes(sf, (n) => {
75
+ if (ts.isBinaryExpression(n) && result === '') result = getPropertyChain(n);
76
+ });
77
+ expect(result).toBe('');
78
+ });
79
+ });
80
+
81
+ describe('getLineNumber', () => {
82
+ it('returns 1-based line numbers', () => {
83
+ const sf = parse('\n\nconst x = 1;');
84
+ if (!sf) throw new Error('parse failed');
85
+ let line = 0;
86
+ walkNodes(sf, (n) => {
87
+ if (ts.isVariableDeclaration(n)) {
88
+ line = getLineNumber(n, sf);
89
+ }
90
+ });
91
+ expect(line).toBe(3);
92
+ });
93
+ });
94
+
95
+ describe('isPropertyAccess', () => {
96
+ it('matches the right property name', () => {
97
+ const sf = parse('foo.bar();');
98
+ if (!sf) throw new Error('parse failed');
99
+ let matched = false;
100
+ walkNodes(sf, (n) => {
101
+ if (ts.isPropertyAccessExpression(n) && isPropertyAccess(n, 'bar')) matched = true;
102
+ });
103
+ expect(matched).toBe(true);
104
+ });
105
+
106
+ it('returns false for the wrong property name', () => {
107
+ const sf = parse('foo.bar();');
108
+ if (!sf) throw new Error('parse failed');
109
+ let matched = false;
110
+ walkNodes(sf, (n) => {
111
+ if (ts.isPropertyAccessExpression(n) && isPropertyAccess(n, 'baz')) matched = true;
112
+ });
113
+ expect(matched).toBe(false);
114
+ });
115
+ });
116
+
117
+ describe('isLiteral', () => {
118
+ it.each([
119
+ ['"hi"', true],
120
+ ['42', true],
121
+ ['true', true],
122
+ ['false', true],
123
+ ['null', true],
124
+ ['undefined', true],
125
+ ['x', false],
126
+ ])('isLiteral(%s) === %s', (src, expected) => {
127
+ const sf = parse(`(${src});`);
128
+ if (!sf) throw new Error('parse failed');
129
+ let result: boolean | null = null;
130
+ walkNodes(sf, (n) => {
131
+ if (ts.isParenthesizedExpression(n) && result === null) result = isLiteral(n.expression);
132
+ });
133
+ expect(result).toBe(expected);
134
+ });
135
+ });
136
+
137
+ describe('isInStringLiteral', () => {
138
+ it('returns true for nodes inside a template', () => {
139
+ const sf = parse('const x = `${foo}`;');
140
+ if (!sf) throw new Error('parse failed');
141
+ let found = false;
142
+ walkNodes(sf, (n) => {
143
+ if (ts.isIdentifier(n) && n.text === 'foo' && isInStringLiteral(n)) found = true;
144
+ });
145
+ expect(found).toBe(true);
146
+ });
147
+
148
+ it('returns false for nodes outside any string', () => {
149
+ const sf = parse('const x = 1; const y = x;');
150
+ if (!sf) throw new Error('parse failed');
151
+ let found = false;
152
+ walkNodes(sf, (n) => {
153
+ if (ts.isIdentifier(n) && n.text === 'y' && !isInStringLiteral(n)) found = true;
154
+ });
155
+ expect(found).toBe(true);
156
+ });
157
+ });
@@ -0,0 +1,65 @@
1
+ import { describe, it, expect } from 'vitest'
2
+
3
+ import { validateCheckConfig } from '../check-config.js'
4
+
5
+ const BASE_CONFIG = {
6
+ id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
7
+ slug: 'test-check',
8
+ description: 'A test check',
9
+ tags: ['quality'],
10
+ analyze: () => [],
11
+ }
12
+
13
+ describe('validateCheckConfig', () => {
14
+ it('accepts a check with tags array', () => {
15
+ expect(() => validateCheckConfig(BASE_CONFIG)).not.toThrow()
16
+ })
17
+
18
+ it('rejects a check without tags', () => {
19
+ const config = { ...BASE_CONFIG, tags: undefined }
20
+ expect(() => validateCheckConfig(config)).toThrow()
21
+ })
22
+
23
+ it('rejects a check with empty tags array', () => {
24
+ const config = { ...BASE_CONFIG, tags: [] }
25
+ expect(() => validateCheckConfig(config)).toThrow()
26
+ })
27
+
28
+ it('accepts arbitrary tag strings', () => {
29
+ const config = { ...BASE_CONFIG, tags: ['custom-tag', 'another-one', 'cwe-89'] }
30
+ expect(() => validateCheckConfig(config)).not.toThrow()
31
+ })
32
+
33
+ it('validates all three analysis modes with tags', () => {
34
+ // analyze mode
35
+ expect(() => validateCheckConfig({
36
+ ...BASE_CONFIG,
37
+ analyze: (_content: string) => [],
38
+ })).not.toThrow()
39
+
40
+ // analyzeAll mode
41
+ // eslint-disable-next-line sonarjs/no-unused-vars -- destructure-omit pattern: drop `analyze` from spread copy
42
+ const { analyze: _, ...noAnalyze } = BASE_CONFIG
43
+ expect(() => validateCheckConfig({
44
+ ...noAnalyze,
45
+ // eslint-disable-next-line @typescript-eslint/require-await -- arrow must match `(files: FileAccessor) => Promise<CheckViolation[]>`
46
+ analyzeAll: async () => [],
47
+ })).not.toThrow()
48
+
49
+ // command mode
50
+ expect(() => validateCheckConfig({
51
+ ...noAnalyze,
52
+ command: {
53
+ bin: 'echo',
54
+ args: [],
55
+ parseOutput: () => [],
56
+ },
57
+ })).not.toThrow()
58
+ })
59
+
60
+ it('rejects config without any analysis mode', () => {
61
+ // eslint-disable-next-line sonarjs/no-unused-vars -- destructure-omit pattern: drop `analyze` from spread copy
62
+ const { analyze: _, ...noMode } = BASE_CONFIG
63
+ expect(() => validateCheckConfig(noMode)).toThrow()
64
+ })
65
+ })
@@ -0,0 +1,79 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { executeCommand } from '../command-executor.js';
4
+
5
+ import type { CommandConfig } from '../check-config.js';
6
+
7
+ const cwd = process.cwd();
8
+
9
+ describe('executeCommand', () => {
10
+ it('runs a command with array args and parses stdout', async () => {
11
+ const config: CommandConfig = {
12
+ bin: 'echo',
13
+ args: ['hello'],
14
+ parseOutput: (stdout) => [{
15
+ line: 1,
16
+ message: stdout.trim(),
17
+ severity: 'warning',
18
+ }],
19
+ };
20
+ const result = await executeCommand(config, [], { cwd });
21
+ expect(result.aborted).toBe(false);
22
+ expect(result.exitCode).toBe(0);
23
+ expect(result.violations).toHaveLength(1);
24
+ expect(result.violations[0]?.message).toBe('hello');
25
+ });
26
+
27
+ it('runs a command with function args derived from files', async () => {
28
+ const config: CommandConfig = {
29
+ bin: 'echo',
30
+ args: (files) => [`got-${files.length}`],
31
+ parseOutput: (stdout) => [{
32
+ line: 1,
33
+ message: stdout.trim(),
34
+ severity: 'warning',
35
+ }],
36
+ };
37
+ const result = await executeCommand(config, ['a', 'b', 'c'], { cwd });
38
+ expect(result.violations[0]?.message).toBe('got-3');
39
+ });
40
+
41
+ it('returns an error when the bin is not installed (ENOENT)', async () => {
42
+ const config: CommandConfig = {
43
+ bin: 'definitely-not-a-real-binary-xyz123',
44
+ args: [],
45
+ parseOutput: () => [],
46
+ };
47
+ const result = await executeCommand(config, [], { cwd });
48
+ expect(result.error).toContain('not installed');
49
+ expect(result.violations).toEqual([]);
50
+ });
51
+
52
+ it('returns an error when exit code is unexpected', async () => {
53
+ const config: CommandConfig = {
54
+ bin: 'sh',
55
+ args: ['-c', 'exit 5'],
56
+ parseOutput: () => [],
57
+ expectedExitCodes: [0],
58
+ };
59
+ const result = await executeCommand(config, [], { cwd });
60
+ expect(result.error).toContain('unexpected code 5');
61
+ expect(result.violations).toEqual([]);
62
+ });
63
+
64
+ it('honors expectedExitCodes when set', async () => {
65
+ const config: CommandConfig = {
66
+ bin: 'sh',
67
+ args: ['-c', 'echo done; exit 1'],
68
+ parseOutput: (stdout) => [{
69
+ line: 1,
70
+ message: stdout.trim(),
71
+ severity: 'warning',
72
+ }],
73
+ expectedExitCodes: [0, 1],
74
+ };
75
+ const result = await executeCommand(config, [], { cwd });
76
+ expect(result.violations).toHaveLength(1);
77
+ expect(result.exitCode).toBe(1);
78
+ });
79
+ });
@@ -0,0 +1,132 @@
1
+ /**
2
+ * @fileoverview Pin the contentFilter dispatch in define-check.ts and
3
+ * file-accessor.ts. Two modes are intentional and distinct:
4
+ *
5
+ * - `strip-strings` → strings blanked, COMMENTS PRESERVED.
6
+ * Use when a rule reads comment markers
7
+ * (e.g. `// @swallow-ok`).
8
+ * - `strip-strings-and-comments` → both blanked. Use when the same
9
+ * forbidden phrase could appear in a
10
+ * comment and would false-fire.
11
+ *
12
+ * Mixing them was the bug behind a 2026-05-05 mis-fix that mapped both
13
+ * modes to codeNoComments, breaking every rule that scans comments for
14
+ * directives. This test pins the contract.
15
+ *
16
+ * The legacy `'code-only'` / `'no-strings-no-comments'` aliases were
17
+ * removed in 0.5.0; this file used to assert the alias mapping and now
18
+ * just asserts the canonical names.
19
+ */
20
+ import { mkdtemp, writeFile } from 'node:fs/promises'
21
+ import { tmpdir } from 'node:os'
22
+ import { join } from 'node:path'
23
+
24
+
25
+ import { defaultLanguageRegistry } from '@opensip-tools/core'
26
+ import { afterAll, beforeAll, describe, expect, it } from 'vitest'
27
+
28
+ import { filterContent } from '../content-filter.js'
29
+ import { createFileAccessor } from '../file-accessor.js'
30
+
31
+ import type { LanguageAdapter } from '@opensip-tools/core'
32
+
33
+ // FileAccessor.read dispatches strip via the registered LanguageAdapter
34
+ // for the file's extension. Register a minimal TS adapter for the test
35
+ // scope so the dispatch resolves and the existing core filterContent
36
+ // implementation produces the expected output. Lang packages live in
37
+ // their own workspaces and core can't depend on @opensip-tools/lang-typescript
38
+ // directly without creating a cycle.
39
+ const inProcessTypescriptAdapter: LanguageAdapter = {
40
+ id: 'typescript-test-shim',
41
+ fileExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'],
42
+ parse: () => null,
43
+ stripStrings: (s) => filterContent(s).code,
44
+ stripComments: (s) => filterContent(s).codeNoComments,
45
+ }
46
+
47
+ beforeAll(() => {
48
+ defaultLanguageRegistry.register(inProcessTypescriptAdapter)
49
+ })
50
+
51
+ afterAll(() => {
52
+ defaultLanguageRegistry.clear()
53
+ })
54
+
55
+ async function writeTempFile(content: string): Promise<string> {
56
+ const dir = await mkdtemp(join(tmpdir(), 'cf-dispatch-'))
57
+ const filePath = join(dir, 'sample.ts')
58
+ await writeFile(filePath, content, 'utf8')
59
+ return filePath
60
+ }
61
+
62
+ describe('FileAccessor contentFilter dispatch', () => {
63
+ describe('strip-strings — strings blanked, comments preserved', () => {
64
+ it('preserves line-comment text so rules can scan markers', async () => {
65
+ const filePath = await writeTempFile(
66
+ `const a = 1\n// @swallow-ok intentional fallthrough\nconst b = 2`,
67
+ )
68
+ const accessor = createFileAccessor([filePath], { contentFilter: 'strip-strings' })
69
+ const content = await accessor.read(filePath)
70
+
71
+ expect(content).toContain('@swallow-ok')
72
+ expect(content).toContain('const a = 1')
73
+ expect(content).toContain('const b = 2')
74
+ })
75
+
76
+ it('preserves block-comment text including JSDoc directives', async () => {
77
+ const filePath = await writeTempFile(
78
+ `/** @deprecated use Y instead */\nexport function legacy() {}`,
79
+ )
80
+ const accessor = createFileAccessor([filePath], { contentFilter: 'strip-strings' })
81
+ const content = await accessor.read(filePath)
82
+
83
+ expect(content).toContain('@deprecated')
84
+ expect(content).toContain('export function legacy')
85
+ })
86
+
87
+ it('blanks string-literal contents', async () => {
88
+ const filePath = await writeTempFile(`const url = 'phrase_in_string'`)
89
+ const accessor = createFileAccessor([filePath], { contentFilter: 'strip-strings' })
90
+ const content = await accessor.read(filePath)
91
+
92
+ expect(content).not.toContain('phrase_in_string')
93
+ expect(content).toContain('const url = ')
94
+ })
95
+ })
96
+
97
+ describe('strip-strings-and-comments — both blanked', () => {
98
+ it('blanks comment text so rules don\'t false-fire on prose', async () => {
99
+ const filePath = await writeTempFile(
100
+ `const a = 1\n// forbidden_phrase_in_comment\nconst b = 2`,
101
+ )
102
+ const accessor = createFileAccessor([filePath], { contentFilter: 'strip-strings-and-comments' })
103
+ const content = await accessor.read(filePath)
104
+
105
+ expect(content).not.toContain('forbidden_phrase_in_comment')
106
+ expect(content).toContain('const a = 1')
107
+ expect(content).toContain('const b = 2')
108
+ })
109
+
110
+ it('blanks both strings and comments in the same content', async () => {
111
+ const filePath = await writeTempFile(
112
+ `const url = 'phrase_in_string' // phrase_in_comment`,
113
+ )
114
+ const accessor = createFileAccessor([filePath], { contentFilter: 'strip-strings-and-comments' })
115
+ const content = await accessor.read(filePath)
116
+
117
+ expect(content).not.toContain('phrase_in_string')
118
+ expect(content).not.toContain('phrase_in_comment')
119
+ })
120
+ })
121
+
122
+ describe('default (raw) — no filter applied', () => {
123
+ it('preserves both strings and comments verbatim', async () => {
124
+ const src = `const url = 'phrase'\n// also phrase`
125
+ const filePath = await writeTempFile(src)
126
+ const accessor = createFileAccessor([filePath]) // no contentFilter → raw passthrough
127
+ const content = await accessor.read(filePath)
128
+
129
+ expect(content).toBe(src)
130
+ })
131
+ })
132
+ })
@@ -0,0 +1,136 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { clearFilterCache, filterContent } from '../content-filter.js'
4
+
5
+ describe('filterContent', () => {
6
+ describe('string and comment masking', () => {
7
+ it('replaces string-literal content with spaces but preserves length', () => {
8
+ clearFilterCache()
9
+ const src = `const x = 'hello'`
10
+ const { code } = filterContent(src)
11
+ expect(code.length).toBe(src.length)
12
+ expect(code).toBe(`const x = ' '`)
13
+ })
14
+
15
+ it('preserves comment content verbatim (comments tracked, not masked)', () => {
16
+ clearFilterCache()
17
+ const src = `const x = 1 // loadConfig() mentioned here\nconst y = 2`
18
+ const { code } = filterContent(src)
19
+ // Line comments are left intact — directives live in comments
20
+ expect(code).toContain('loadConfig() mentioned here')
21
+ })
22
+ })
23
+
24
+ describe('template literals', () => {
25
+ it('masks simple template body text', () => {
26
+ clearFilterCache()
27
+ const src = `const x = \`hello world\``
28
+ const { code } = filterContent(src)
29
+ expect(code).toBe(`const x = \` \``)
30
+ })
31
+
32
+ it('masks template-head and template-tail text, preserves expressions', () => {
33
+ clearFilterCache()
34
+ const src = `const x = \`pre \${value} post\``
35
+ const { code } = filterContent(src)
36
+ // Expression `value` is code — preserved. Text around `${ ... }` is masked.
37
+ expect(code).toContain('value')
38
+ expect(code).not.toContain('pre ')
39
+ expect(code).not.toContain(' post')
40
+ })
41
+
42
+ // Regression: nested templates inside `${...}` expressions used to desync the
43
+ // scanner state (a plain `inTemplate` boolean flipped off by the inner
44
+ // TemplateTail left the outer's CloseBrace unrescanned, which caused every
45
+ // token after the inner template to be misinterpreted as part of a string).
46
+ // The symptom was that real code — `loadConfig(process.cwd())`, type
47
+ // annotations, anything — below the nested template got wiped to whitespace
48
+ // silently, producing false negatives in every `contentFilter: 'strip-strings'`
49
+ // check that scanned the affected file. Fix replaced the boolean with a
50
+ // depth counter; this test keeps it fixed.
51
+ it('handles nested templates inside ${} expressions — code below is preserved', () => {
52
+ clearFilterCache()
53
+ const src = [
54
+ 'const lines = items.map(f => `- ${sanitize(f)}`).join("\\n")',
55
+ 'const after = loadConfig(process.cwd())',
56
+ 'export function helper(cfg: ReturnType<typeof loadConfig>): string { return "" }',
57
+ ].join('\n')
58
+ const { code } = filterContent(src)
59
+ // The nested template's inner text `- ` should be masked, but sanitize(f),
60
+ // the .map/.join chain, and everything below must survive intact.
61
+ expect(code).toContain('sanitize(f)')
62
+ expect(code).toContain('loadConfig(process.cwd())')
63
+ expect(code).toContain('ReturnType<typeof loadConfig>')
64
+ })
65
+
66
+ it('handles doubly-nested templates', () => {
67
+ clearFilterCache()
68
+ const src = [
69
+ 'const s = `a ${`b ${c}`} d`',
70
+ 'const survives = loadConfig(process.cwd())',
71
+ ].join('\n')
72
+ const { code } = filterContent(src)
73
+ expect(code).toContain('survives')
74
+ expect(code).toContain('loadConfig(process.cwd())')
75
+ // The identifier `c` inside the innermost expression is code and must survive
76
+ expect(code).toContain('${c}')
77
+ })
78
+ })
79
+
80
+ describe('codeNoComments — strings AND comments masked', () => {
81
+ it('masks line comments while preserving line/column offsets', () => {
82
+ clearFilterCache()
83
+ const src = `const x = 1 // calls getDatabase() somewhere\nconst y = 2`
84
+ const { code, codeNoComments } = filterContent(src)
85
+ // `code` (strings-only) leaves the line comment intact
86
+ expect(code).toContain('getDatabase()')
87
+ // `codeNoComments` masks the comment text but keeps length
88
+ expect(codeNoComments.length).toBe(src.length)
89
+ expect(codeNoComments).not.toContain('getDatabase')
90
+ // Code BEFORE the comment survives
91
+ expect(codeNoComments).toContain('const x = 1')
92
+ // Newlines are preserved so line numbers stay accurate
93
+ expect(codeNoComments.split('\n')).toHaveLength(2)
94
+ expect(codeNoComments.split('\n')[1]).toBe('const y = 2')
95
+ })
96
+
97
+ it('masks block / JSDoc comments across multiple lines', () => {
98
+ clearFilterCache()
99
+ const src = [
100
+ '/**',
101
+ ' * Replace getDatabase() with the constructor StoreDeps.',
102
+ ' * The check guards against process-wide tenant accessors.',
103
+ ' */',
104
+ 'export class TicketStore {}',
105
+ ].join('\n')
106
+ const { codeNoComments } = filterContent(src)
107
+ expect(codeNoComments).not.toContain('getDatabase')
108
+ expect(codeNoComments).not.toContain('StoreDeps')
109
+ expect(codeNoComments).not.toContain('process-wide')
110
+ // Code AFTER the JSDoc survives
111
+ expect(codeNoComments).toContain('export class TicketStore')
112
+ // Line count preserved
113
+ expect(codeNoComments.split('\n')).toHaveLength(5)
114
+ })
115
+
116
+ it('masks both strings and comments in the same content', () => {
117
+ clearFilterCache()
118
+ const src = `const url = 'https://api.example.com' // call openai.messages.create() here`
119
+ const { codeNoComments } = filterContent(src)
120
+ expect(codeNoComments).not.toContain('https')
121
+ expect(codeNoComments).not.toContain('messages.create')
122
+ expect(codeNoComments).toContain('const url = ')
123
+ })
124
+
125
+ it('does not strip comments when only `code` is requested', () => {
126
+ // Regression guard: codeNoComments is a sibling field, not a replacement.
127
+ // `code` must continue to leave comments intact (some checks scan
128
+ // comments for `@deprecated` / `@fitness-ignore` directives).
129
+ clearFilterCache()
130
+ const src = `const x = 1 // @deprecated — use Y instead`
131
+ const { code, codeNoComments } = filterContent(src)
132
+ expect(code).toContain('@deprecated')
133
+ expect(codeNoComments).not.toContain('@deprecated')
134
+ })
135
+ })
136
+ })