api-tests-coverage 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/README.md +703 -0
  2. package/config.yaml.example +227 -0
  3. package/dist/action/src/index.d.ts +2 -0
  4. package/dist/action/src/index.d.ts.map +1 -0
  5. package/dist/action/src/index.js +349 -0
  6. package/dist/action/src/prComment.d.ts +34 -0
  7. package/dist/action/src/prComment.d.ts.map +1 -0
  8. package/dist/action/src/prComment.js +146 -0
  9. package/dist/src/ast/astAnalysisOrchestrator.d.ts +36 -0
  10. package/dist/src/ast/astAnalysisOrchestrator.d.ts.map +1 -0
  11. package/dist/src/ast/astAnalysisOrchestrator.js +123 -0
  12. package/dist/src/ast/astTypes.d.ts +105 -0
  13. package/dist/src/ast/astTypes.d.ts.map +1 -0
  14. package/dist/src/ast/astTypes.js +9 -0
  15. package/dist/src/ast/languageAnalyzer.d.ts +46 -0
  16. package/dist/src/ast/languageAnalyzer.d.ts.map +1 -0
  17. package/dist/src/ast/languageAnalyzer.js +9 -0
  18. package/dist/src/ast/languageCapabilities.d.ts +24 -0
  19. package/dist/src/ast/languageCapabilities.d.ts.map +1 -0
  20. package/dist/src/ast/languageCapabilities.js +92 -0
  21. package/dist/src/ast/parseFile.d.ts +16 -0
  22. package/dist/src/ast/parseFile.d.ts.map +1 -0
  23. package/dist/src/ast/parseFile.js +65 -0
  24. package/dist/src/ast/parserRegistry.d.ts +39 -0
  25. package/dist/src/ast/parserRegistry.d.ts.map +1 -0
  26. package/dist/src/ast/parserRegistry.js +66 -0
  27. package/dist/src/buildSummary.d.ts +26 -0
  28. package/dist/src/buildSummary.d.ts.map +1 -0
  29. package/dist/src/buildSummary.js +193 -0
  30. package/dist/src/businessCoverage.d.ts +68 -0
  31. package/dist/src/businessCoverage.d.ts.map +1 -0
  32. package/dist/src/businessCoverage.js +290 -0
  33. package/dist/src/compatibilityCoverage.d.ts +83 -0
  34. package/dist/src/compatibilityCoverage.d.ts.map +1 -0
  35. package/dist/src/compatibilityCoverage.js +501 -0
  36. package/dist/src/config/defaultConfig.d.ts +9 -0
  37. package/dist/src/config/defaultConfig.d.ts.map +1 -0
  38. package/dist/src/config/defaultConfig.js +97 -0
  39. package/dist/src/config/index.d.ts +12 -0
  40. package/dist/src/config/index.d.ts.map +1 -0
  41. package/dist/src/config/index.js +37 -0
  42. package/dist/src/config/loadConfig.d.ts +29 -0
  43. package/dist/src/config/loadConfig.d.ts.map +1 -0
  44. package/dist/src/config/loadConfig.js +135 -0
  45. package/dist/src/config/mergeConfig.d.ts +15 -0
  46. package/dist/src/config/mergeConfig.d.ts.map +1 -0
  47. package/dist/src/config/mergeConfig.js +57 -0
  48. package/dist/src/config/schema.d.ts +15 -0
  49. package/dist/src/config/schema.d.ts.map +1 -0
  50. package/dist/src/config/schema.js +30 -0
  51. package/dist/src/config/types.d.ts +175 -0
  52. package/dist/src/config/types.d.ts.map +1 -0
  53. package/dist/src/config/types.js +9 -0
  54. package/dist/src/config/validateConfig.d.ts +22 -0
  55. package/dist/src/config/validateConfig.d.ts.map +1 -0
  56. package/dist/src/config/validateConfig.js +171 -0
  57. package/dist/src/config.d.ts +168 -0
  58. package/dist/src/config.d.ts.map +1 -0
  59. package/dist/src/config.js +204 -0
  60. package/dist/src/coverage/deep-analysis/callGraph.d.ts +67 -0
  61. package/dist/src/coverage/deep-analysis/callGraph.d.ts.map +1 -0
  62. package/dist/src/coverage/deep-analysis/callGraph.js +275 -0
  63. package/dist/src/coverage/deep-analysis/deepEndpointResolver.d.ts +23 -0
  64. package/dist/src/coverage/deep-analysis/deepEndpointResolver.d.ts.map +1 -0
  65. package/dist/src/coverage/deep-analysis/deepEndpointResolver.js +394 -0
  66. package/dist/src/coverage/deep-analysis/index.d.ts +17 -0
  67. package/dist/src/coverage/deep-analysis/index.d.ts.map +1 -0
  68. package/dist/src/coverage/deep-analysis/index.js +63 -0
  69. package/dist/src/coverage/deep-analysis/resolveAssertions.d.ts +60 -0
  70. package/dist/src/coverage/deep-analysis/resolveAssertions.d.ts.map +1 -0
  71. package/dist/src/coverage/deep-analysis/resolveAssertions.js +121 -0
  72. package/dist/src/coverage/deep-analysis/resolveConstants.d.ts +36 -0
  73. package/dist/src/coverage/deep-analysis/resolveConstants.d.ts.map +1 -0
  74. package/dist/src/coverage/deep-analysis/resolveConstants.js +92 -0
  75. package/dist/src/coverage/deep-analysis/resolveEnums.d.ts +55 -0
  76. package/dist/src/coverage/deep-analysis/resolveEnums.d.ts.map +1 -0
  77. package/dist/src/coverage/deep-analysis/resolveEnums.js +152 -0
  78. package/dist/src/coverage/deep-analysis/resolveMethodChains.d.ts +70 -0
  79. package/dist/src/coverage/deep-analysis/resolveMethodChains.d.ts.map +1 -0
  80. package/dist/src/coverage/deep-analysis/resolveMethodChains.js +152 -0
  81. package/dist/src/coverage/deep-analysis/resolvePaths.d.ts +80 -0
  82. package/dist/src/coverage/deep-analysis/resolvePaths.d.ts.map +1 -0
  83. package/dist/src/coverage/deep-analysis/resolvePaths.js +216 -0
  84. package/dist/src/coverage/deep-analysis/resolveRequestWrappers.d.ts +71 -0
  85. package/dist/src/coverage/deep-analysis/resolveRequestWrappers.d.ts.map +1 -0
  86. package/dist/src/coverage/deep-analysis/resolveRequestWrappers.js +226 -0
  87. package/dist/src/coverage/deep-analysis/symbolTable.d.ts +58 -0
  88. package/dist/src/coverage/deep-analysis/symbolTable.d.ts.map +1 -0
  89. package/dist/src/coverage/deep-analysis/symbolTable.js +230 -0
  90. package/dist/src/coverage/deep-analysis/types.d.ts +122 -0
  91. package/dist/src/coverage/deep-analysis/types.d.ts.map +1 -0
  92. package/dist/src/coverage/deep-analysis/types.js +21 -0
  93. package/dist/src/discovery/fileClassifier.d.ts +50 -0
  94. package/dist/src/discovery/fileClassifier.d.ts.map +1 -0
  95. package/dist/src/discovery/fileClassifier.js +238 -0
  96. package/dist/src/discovery/projectDiscovery.d.ts +66 -0
  97. package/dist/src/discovery/projectDiscovery.d.ts.map +1 -0
  98. package/dist/src/discovery/projectDiscovery.js +287 -0
  99. package/dist/src/endpointCoverage.d.ts +70 -0
  100. package/dist/src/endpointCoverage.d.ts.map +1 -0
  101. package/dist/src/endpointCoverage.js +381 -0
  102. package/dist/src/errorCoverage.d.ts +93 -0
  103. package/dist/src/errorCoverage.d.ts.map +1 -0
  104. package/dist/src/errorCoverage.js +698 -0
  105. package/dist/src/index.d.ts +3 -0
  106. package/dist/src/index.d.ts.map +1 -0
  107. package/dist/src/index.js +1441 -0
  108. package/dist/src/inference/businessRuleInference.d.ts +63 -0
  109. package/dist/src/inference/businessRuleInference.d.ts.map +1 -0
  110. package/dist/src/inference/businessRuleInference.js +268 -0
  111. package/dist/src/inference/integrationFlowInference.d.ts +56 -0
  112. package/dist/src/inference/integrationFlowInference.d.ts.map +1 -0
  113. package/dist/src/inference/integrationFlowInference.js +266 -0
  114. package/dist/src/integrationCoverage.d.ts +72 -0
  115. package/dist/src/integrationCoverage.d.ts.map +1 -0
  116. package/dist/src/integrationCoverage.js +317 -0
  117. package/dist/src/intelligence/index.d.ts +20 -0
  118. package/dist/src/intelligence/index.d.ts.map +1 -0
  119. package/dist/src/intelligence/index.js +105 -0
  120. package/dist/src/intelligence/linkageEngine.d.ts +20 -0
  121. package/dist/src/intelligence/linkageEngine.d.ts.map +1 -0
  122. package/dist/src/intelligence/linkageEngine.js +522 -0
  123. package/dist/src/intelligence/markdownReporter.d.ts +12 -0
  124. package/dist/src/intelligence/markdownReporter.d.ts.map +1 -0
  125. package/dist/src/intelligence/markdownReporter.js +265 -0
  126. package/dist/src/intelligence/riskScoring.d.ts +53 -0
  127. package/dist/src/intelligence/riskScoring.d.ts.map +1 -0
  128. package/dist/src/intelligence/riskScoring.js +181 -0
  129. package/dist/src/intelligence/types.d.ts +121 -0
  130. package/dist/src/intelligence/types.d.ts.map +1 -0
  131. package/dist/src/intelligence/types.js +8 -0
  132. package/dist/src/languageDetection.d.ts +100 -0
  133. package/dist/src/languageDetection.d.ts.map +1 -0
  134. package/dist/src/languageDetection.js +349 -0
  135. package/dist/src/languages/java/index.d.ts +16 -0
  136. package/dist/src/languages/java/index.d.ts.map +1 -0
  137. package/dist/src/languages/java/index.js +103 -0
  138. package/dist/src/languages/java/parser.d.ts +7 -0
  139. package/dist/src/languages/java/parser.d.ts.map +1 -0
  140. package/dist/src/languages/java/parser.js +50 -0
  141. package/dist/src/languages/java/semanticBuilder.d.ts +21 -0
  142. package/dist/src/languages/java/semanticBuilder.d.ts.map +1 -0
  143. package/dist/src/languages/java/semanticBuilder.js +358 -0
  144. package/dist/src/languages/javascript/annotationExtractor.d.ts +20 -0
  145. package/dist/src/languages/javascript/annotationExtractor.d.ts.map +1 -0
  146. package/dist/src/languages/javascript/annotationExtractor.js +94 -0
  147. package/dist/src/languages/javascript/assertionResolver.d.ts +18 -0
  148. package/dist/src/languages/javascript/assertionResolver.d.ts.map +1 -0
  149. package/dist/src/languages/javascript/assertionResolver.js +150 -0
  150. package/dist/src/languages/javascript/callResolver.d.ts +23 -0
  151. package/dist/src/languages/javascript/callResolver.d.ts.map +1 -0
  152. package/dist/src/languages/javascript/callResolver.js +236 -0
  153. package/dist/src/languages/javascript/httpInteractionExtractor.d.ts +23 -0
  154. package/dist/src/languages/javascript/httpInteractionExtractor.d.ts.map +1 -0
  155. package/dist/src/languages/javascript/httpInteractionExtractor.js +205 -0
  156. package/dist/src/languages/javascript/index.d.ts +20 -0
  157. package/dist/src/languages/javascript/index.d.ts.map +1 -0
  158. package/dist/src/languages/javascript/index.js +136 -0
  159. package/dist/src/languages/javascript/parser.d.ts +14 -0
  160. package/dist/src/languages/javascript/parser.d.ts.map +1 -0
  161. package/dist/src/languages/javascript/parser.js +38 -0
  162. package/dist/src/languages/javascript/symbolResolver.d.ts +31 -0
  163. package/dist/src/languages/javascript/symbolResolver.d.ts.map +1 -0
  164. package/dist/src/languages/javascript/symbolResolver.js +183 -0
  165. package/dist/src/languages/kotlin/index.d.ts +16 -0
  166. package/dist/src/languages/kotlin/index.d.ts.map +1 -0
  167. package/dist/src/languages/kotlin/index.js +151 -0
  168. package/dist/src/languages/kotlin/parser.d.ts +11 -0
  169. package/dist/src/languages/kotlin/parser.d.ts.map +1 -0
  170. package/dist/src/languages/kotlin/parser.js +74 -0
  171. package/dist/src/languages/python/index.d.ts +15 -0
  172. package/dist/src/languages/python/index.d.ts.map +1 -0
  173. package/dist/src/languages/python/index.js +293 -0
  174. package/dist/src/languages/ruby/index.d.ts +15 -0
  175. package/dist/src/languages/ruby/index.d.ts.map +1 -0
  176. package/dist/src/languages/ruby/index.js +274 -0
  177. package/dist/src/languages/shared/treeSitterUtils.d.ts +43 -0
  178. package/dist/src/languages/shared/treeSitterUtils.d.ts.map +1 -0
  179. package/dist/src/languages/shared/treeSitterUtils.js +100 -0
  180. package/dist/src/languages/typescript/index.d.ts +14 -0
  181. package/dist/src/languages/typescript/index.d.ts.map +1 -0
  182. package/dist/src/languages/typescript/index.js +25 -0
  183. package/dist/src/lib/index.d.ts +228 -0
  184. package/dist/src/lib/index.d.ts.map +1 -0
  185. package/dist/src/lib/index.js +486 -0
  186. package/dist/src/mcp/client/index.d.ts +37 -0
  187. package/dist/src/mcp/client/index.d.ts.map +1 -0
  188. package/dist/src/mcp/client/index.js +235 -0
  189. package/dist/src/mcp/config.d.ts +50 -0
  190. package/dist/src/mcp/config.d.ts.map +1 -0
  191. package/dist/src/mcp/config.js +125 -0
  192. package/dist/src/mcp/events.d.ts +24 -0
  193. package/dist/src/mcp/events.d.ts.map +1 -0
  194. package/dist/src/mcp/events.js +48 -0
  195. package/dist/src/mcp/fallback/index.d.ts +50 -0
  196. package/dist/src/mcp/fallback/index.d.ts.map +1 -0
  197. package/dist/src/mcp/fallback/index.js +216 -0
  198. package/dist/src/mcp/index.d.ts +67 -0
  199. package/dist/src/mcp/index.d.ts.map +1 -0
  200. package/dist/src/mcp/index.js +212 -0
  201. package/dist/src/mcp/normalizer.d.ts +21 -0
  202. package/dist/src/mcp/normalizer.d.ts.map +1 -0
  203. package/dist/src/mcp/normalizer.js +99 -0
  204. package/dist/src/mcp/prompts/index.d.ts +86 -0
  205. package/dist/src/mcp/prompts/index.d.ts.map +1 -0
  206. package/dist/src/mcp/prompts/index.js +304 -0
  207. package/dist/src/mcp/templates/index.d.ts +35 -0
  208. package/dist/src/mcp/templates/index.d.ts.map +1 -0
  209. package/dist/src/mcp/templates/index.js +143 -0
  210. package/dist/src/mcp/testing/mock-server/index.d.ts +47 -0
  211. package/dist/src/mcp/testing/mock-server/index.d.ts.map +1 -0
  212. package/dist/src/mcp/testing/mock-server/index.js +157 -0
  213. package/dist/src/mcp/types.d.ts +127 -0
  214. package/dist/src/mcp/types.d.ts.map +1 -0
  215. package/dist/src/mcp/types.js +8 -0
  216. package/dist/src/observability.d.ts +138 -0
  217. package/dist/src/observability.d.ts.map +1 -0
  218. package/dist/src/observability.js +519 -0
  219. package/dist/src/parameterCoverage.d.ts +75 -0
  220. package/dist/src/parameterCoverage.d.ts.map +1 -0
  221. package/dist/src/parameterCoverage.js +629 -0
  222. package/dist/src/perfResilienceCoverage.d.ts +155 -0
  223. package/dist/src/perfResilienceCoverage.d.ts.map +1 -0
  224. package/dist/src/perfResilienceCoverage.js +670 -0
  225. package/dist/src/pluginLoader.d.ts +51 -0
  226. package/dist/src/pluginLoader.d.ts.map +1 -0
  227. package/dist/src/pluginLoader.js +72 -0
  228. package/dist/src/publishing.d.ts +63 -0
  229. package/dist/src/publishing.d.ts.map +1 -0
  230. package/dist/src/publishing.js +379 -0
  231. package/dist/src/qualityGate.d.ts +58 -0
  232. package/dist/src/qualityGate.d.ts.map +1 -0
  233. package/dist/src/qualityGate.js +118 -0
  234. package/dist/src/reporting.d.ts +41 -0
  235. package/dist/src/reporting.d.ts.map +1 -0
  236. package/dist/src/reporting.js +278 -0
  237. package/dist/src/screenshots.d.ts +71 -0
  238. package/dist/src/screenshots.d.ts.map +1 -0
  239. package/dist/src/screenshots.js +141 -0
  240. package/dist/src/security/gate/index.d.ts +11 -0
  241. package/dist/src/security/gate/index.d.ts.map +1 -0
  242. package/dist/src/security/gate/index.js +65 -0
  243. package/dist/src/security/index.d.ts +30 -0
  244. package/dist/src/security/index.d.ts.map +1 -0
  245. package/dist/src/security/index.js +342 -0
  246. package/dist/src/security/normalizers/semgrep.d.ts +10 -0
  247. package/dist/src/security/normalizers/semgrep.d.ts.map +1 -0
  248. package/dist/src/security/normalizers/semgrep.js +104 -0
  249. package/dist/src/security/normalizers/trivy.d.ts +10 -0
  250. package/dist/src/security/normalizers/trivy.d.ts.map +1 -0
  251. package/dist/src/security/normalizers/trivy.js +78 -0
  252. package/dist/src/security/normalizers/zap.d.ts +10 -0
  253. package/dist/src/security/normalizers/zap.d.ts.map +1 -0
  254. package/dist/src/security/normalizers/zap.js +104 -0
  255. package/dist/src/security/scanners/semgrep.d.ts +6 -0
  256. package/dist/src/security/scanners/semgrep.d.ts.map +1 -0
  257. package/dist/src/security/scanners/semgrep.js +125 -0
  258. package/dist/src/security/scanners/trivy.d.ts +6 -0
  259. package/dist/src/security/scanners/trivy.d.ts.map +1 -0
  260. package/dist/src/security/scanners/trivy.js +115 -0
  261. package/dist/src/security/scanners/zap.d.ts +6 -0
  262. package/dist/src/security/scanners/zap.d.ts.map +1 -0
  263. package/dist/src/security/scanners/zap.js +135 -0
  264. package/dist/src/security/types.d.ts +146 -0
  265. package/dist/src/security/types.d.ts.map +1 -0
  266. package/dist/src/security/types.js +6 -0
  267. package/dist/src/securityCoverage.d.ts +116 -0
  268. package/dist/src/securityCoverage.d.ts.map +1 -0
  269. package/dist/src/securityCoverage.js +725 -0
  270. package/dist/src/summary/buildSummary.d.ts +28 -0
  271. package/dist/src/summary/buildSummary.d.ts.map +1 -0
  272. package/dist/src/summary/buildSummary.js +257 -0
  273. package/dist/src/summary/evaluateMetrics.d.ts +31 -0
  274. package/dist/src/summary/evaluateMetrics.d.ts.map +1 -0
  275. package/dist/src/summary/evaluateMetrics.js +118 -0
  276. package/dist/src/summary/index.d.ts +10 -0
  277. package/dist/src/summary/index.d.ts.map +1 -0
  278. package/dist/src/summary/index.js +22 -0
  279. package/dist/src/summary/markdownRenderer.d.ts +139 -0
  280. package/dist/src/summary/markdownRenderer.d.ts.map +1 -0
  281. package/dist/src/summary/markdownRenderer.js +459 -0
  282. package/dist/src/summary/prSummary.d.ts +24 -0
  283. package/dist/src/summary/prSummary.d.ts.map +1 -0
  284. package/dist/src/summary/prSummary.js +233 -0
  285. package/dist/src/summary/summaryTypes.d.ts +35 -0
  286. package/dist/src/summary/summaryTypes.d.ts.map +1 -0
  287. package/dist/src/summary/summaryTypes.js +27 -0
  288. package/package.json +84 -0
@@ -0,0 +1,522 @@
1
+ "use strict";
2
+ /**
3
+ * Coverage Intelligence – Linkage Engine.
4
+ *
5
+ * Inspects coverage results and security findings to produce FunctionalFinding
6
+ * objects and link them to MissingTestRecommendation records.
7
+ *
8
+ * The engine is deterministic and does not require MCP to run.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.buildRecommendationFromFinding = buildRecommendationFromFinding;
12
+ exports.runLinkageEngine = runLinkageEngine;
13
+ const riskScoring_1 = require("./riskScoring");
14
+ // ─── Simple UUID stub (avoid external dependency) ─────────────────────────────
15
+ let _counter = 0;
16
+ function makeId(prefix) {
17
+ _counter++;
18
+ return `${prefix}-${Date.now()}-${_counter}`;
19
+ }
20
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
21
+ function normalizeSeverity(raw) {
22
+ switch (raw.toUpperCase()) {
23
+ case 'CRITICAL': return 'CRITICAL';
24
+ case 'HIGH': return 'HIGH';
25
+ case 'MEDIUM': return 'MEDIUM';
26
+ default: return 'LOW';
27
+ }
28
+ }
29
+ function isMoneyPath(path) {
30
+ if (!path)
31
+ return false;
32
+ const lower = path.toLowerCase();
33
+ return (lower.includes('payment') ||
34
+ lower.includes('wallet') ||
35
+ lower.includes('transfer') ||
36
+ lower.includes('refund') ||
37
+ lower.includes('debit') ||
38
+ lower.includes('charge') ||
39
+ lower.includes('fund') ||
40
+ lower.includes('payout'));
41
+ }
42
+ function isAuthPath(path) {
43
+ if (!path)
44
+ return false;
45
+ const lower = path.toLowerCase();
46
+ return (lower.includes('auth') ||
47
+ lower.includes('login') ||
48
+ lower.includes('token') ||
49
+ lower.includes('oauth') ||
50
+ lower.includes('session') ||
51
+ lower.includes('password'));
52
+ }
53
+ function frameworkHintsForLanguages(languages) {
54
+ const hints = [];
55
+ if (!(languages === null || languages === void 0 ? void 0 : languages.length))
56
+ return hints;
57
+ for (const lang of languages) {
58
+ switch (lang.toLowerCase()) {
59
+ case 'typescript':
60
+ case 'javascript':
61
+ hints.push('jest', 'supertest');
62
+ break;
63
+ case 'java':
64
+ hints.push('junit', 'testng', 'rest-assured', 'spring-mockmvc');
65
+ break;
66
+ case 'kotlin':
67
+ hints.push('kotest', 'junit', 'ktor-test');
68
+ break;
69
+ case 'python':
70
+ hints.push('pytest', 'httpx', 'requests');
71
+ break;
72
+ case 'ruby':
73
+ hints.push('rspec', 'minitest', 'rails-request-specs');
74
+ break;
75
+ case 'cucumber':
76
+ hints.push('cucumber', 'gherkin');
77
+ break;
78
+ }
79
+ }
80
+ return [...new Set(hints)];
81
+ }
82
+ function recommendationHint(testType, language, framework) {
83
+ const lang = (language || '').toLowerCase();
84
+ const fw = (framework || '').toLowerCase();
85
+ if (lang === 'java' || fw.includes('rest-assured')) {
86
+ switch (testType) {
87
+ case 'auth-test': return 'RestAssured authz scenario: .auth().oauth2(token) chain';
88
+ case 'negative-api-test': return 'RestAssured negative test: expect 4xx status with .statusCode(403)';
89
+ case 'boundary-test': return 'RestAssured boundary: parameterize with @ParameterizedTest';
90
+ default: return 'RestAssured test case';
91
+ }
92
+ }
93
+ if (lang === 'python' || fw.includes('pytest')) {
94
+ switch (testType) {
95
+ case 'auth-test': return 'pytest fixture: add missing auth header, assert 401/403';
96
+ case 'negative-api-test': return 'pytest parametrize with invalid inputs, assert HTTP 4xx';
97
+ case 'boundary-test': return 'pytest @pytest.mark.parametrize with boundary values';
98
+ default: return 'pytest test function';
99
+ }
100
+ }
101
+ if (lang === 'ruby' || fw.includes('rspec')) {
102
+ switch (testType) {
103
+ case 'auth-test': return 'RSpec request spec: without_auth context block';
104
+ case 'negative-api-test': return 'RSpec: context "with invalid input" do ... expect(response).to have_http_status(422)';
105
+ case 'boundary-test': return 'RSpec shared_examples with boundary parameter values';
106
+ default: return 'RSpec request spec';
107
+ }
108
+ }
109
+ if (fw.includes('cucumber') || fw.includes('gherkin')) {
110
+ return `Scenario: missing coverage – add Gherkin scenario for ${testType}`;
111
+ }
112
+ // default JS/TS
113
+ switch (testType) {
114
+ case 'auth-test': return 'Jest + supertest: describe("unauthorized") { it("returns 401") }';
115
+ case 'negative-api-test': return 'Jest + supertest: test invalid inputs → 4xx responses';
116
+ case 'boundary-test': return 'Jest test.each with boundary value arrays';
117
+ default: return 'Jest test case';
118
+ }
119
+ }
120
+ function buildEndpointFindings(details, languages, frameworks) {
121
+ var _a, _b, _c;
122
+ const findings = [];
123
+ if (!Array.isArray(details))
124
+ return findings;
125
+ const fwHints = frameworkHintsForLanguages(languages);
126
+ for (const item of details) {
127
+ const ep = item.endpoint;
128
+ const covered = (_a = item.covered) !== null && _a !== void 0 ? _a : false;
129
+ if (!covered) {
130
+ findings.push({
131
+ id: makeId('ff-ep'),
132
+ source: 'coverage-gap-analysis',
133
+ category: 'uncovered-endpoint',
134
+ severity: isMoneyPath(ep === null || ep === void 0 ? void 0 : ep.path) ? 'HIGH' : 'MEDIUM',
135
+ title: `Uncovered endpoint: ${(_b = ep === null || ep === void 0 ? void 0 : ep.method) !== null && _b !== void 0 ? _b : 'UNKNOWN'} ${(_c = ep === null || ep === void 0 ? void 0 : ep.path) !== null && _c !== void 0 ? _c : '/'}`,
136
+ description: `Endpoint ${ep === null || ep === void 0 ? void 0 : ep.method} ${ep === null || ep === void 0 ? void 0 : ep.path} has no test coverage.`,
137
+ endpoint: ep,
138
+ missingTestTypes: ['positive-api-test', 'negative-api-test'],
139
+ frameworkHints: fwHints,
140
+ languageHints: languages,
141
+ tags: ['endpoint-coverage', 'zero-coverage'],
142
+ });
143
+ }
144
+ }
145
+ return findings;
146
+ }
147
+ function buildErrorCoverageFindings(details, languages) {
148
+ var _a, _b, _c;
149
+ const findings = [];
150
+ if (!Array.isArray(details))
151
+ return findings;
152
+ const fwHints = frameworkHintsForLanguages(languages);
153
+ for (const item of details) {
154
+ if (!item.covered && ((_a = item.errorCodes) === null || _a === void 0 ? void 0 : _a.length)) {
155
+ findings.push({
156
+ id: makeId('ff-err'),
157
+ source: 'error-coverage',
158
+ category: 'error-scenario-gap',
159
+ severity: 'MEDIUM',
160
+ title: `Missing error scenario tests for ${(_c = (_b = item.endpoint) === null || _b === void 0 ? void 0 : _b.path) !== null && _c !== void 0 ? _c : 'endpoint'}`,
161
+ description: `Error codes ${item.errorCodes.join(', ')} are documented but have no matching test.`,
162
+ endpoint: item.endpoint,
163
+ missingTestTypes: ['negative-api-test'],
164
+ frameworkHints: fwHints,
165
+ languageHints: languages,
166
+ tags: ['error-coverage', 'negative-test'],
167
+ });
168
+ }
169
+ }
170
+ return findings;
171
+ }
172
+ function buildBusinessCoverageFindings(details, languages) {
173
+ var _a;
174
+ const findings = [];
175
+ if (!Array.isArray(details))
176
+ return findings;
177
+ const fwHints = frameworkHintsForLanguages(languages);
178
+ for (const item of details) {
179
+ if (!item.covered) {
180
+ findings.push({
181
+ id: makeId('ff-biz'),
182
+ source: 'business-coverage',
183
+ category: 'missing-business-rule-test',
184
+ severity: 'MEDIUM',
185
+ title: `Uncovered business rule: ${(_a = item.name) !== null && _a !== void 0 ? _a : 'unknown'}`,
186
+ description: `Business rule "${item.name}" has no test coverage.`,
187
+ relatedRules: item.name ? [item.name] : [],
188
+ missingTestTypes: ['business-rule-test'],
189
+ frameworkHints: fwHints,
190
+ languageHints: languages,
191
+ tags: ['business-coverage'],
192
+ });
193
+ }
194
+ }
195
+ return findings;
196
+ }
197
+ function buildIntegrationFlowFindings(details, languages) {
198
+ var _a, _b;
199
+ const findings = [];
200
+ if (!Array.isArray(details))
201
+ return findings;
202
+ const fwHints = frameworkHintsForLanguages(languages);
203
+ for (const flow of details) {
204
+ if (!flow.steps)
205
+ continue;
206
+ for (const step of flow.steps) {
207
+ if (!step.covered) {
208
+ findings.push({
209
+ id: makeId('ff-flow'),
210
+ source: 'integration-flow',
211
+ category: 'missing-flow-step-test',
212
+ severity: 'MEDIUM',
213
+ title: `Uncovered flow step: ${(_a = step.name) !== null && _a !== void 0 ? _a : 'unknown'} in ${(_b = flow.name) !== null && _b !== void 0 ? _b : 'flow'}`,
214
+ description: `Integration flow step "${step.name}" has no test coverage.`,
215
+ missingTestTypes: ['integration-flow-test'],
216
+ frameworkHints: fwHints,
217
+ languageHints: languages,
218
+ tags: ['integration-flow'],
219
+ });
220
+ }
221
+ }
222
+ }
223
+ return findings;
224
+ }
225
+ function buildSecurityCoverageFindings(details, languages) {
226
+ var _a, _b, _c, _d, _e;
227
+ const findings = [];
228
+ if (!Array.isArray(details))
229
+ return findings;
230
+ const fwHints = frameworkHintsForLanguages(languages);
231
+ for (const item of details) {
232
+ if (!item.covered) {
233
+ findings.push({
234
+ id: makeId('ff-sec-cov'),
235
+ source: 'security-coverage',
236
+ category: 'missing-auth-test',
237
+ severity: 'HIGH',
238
+ title: `Missing auth/security test: ${(_c = (_b = (_a = item.endpoint) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : item.name) !== null && _c !== void 0 ? _c : 'unknown'}`,
239
+ description: `Security scenario for ${(_e = (_d = item.endpoint) === null || _d === void 0 ? void 0 : _d.path) !== null && _e !== void 0 ? _e : item.name} has no test coverage.`,
240
+ endpoint: item.endpoint,
241
+ missingTestTypes: ['auth-test', 'authz-test', 'security-test'],
242
+ frameworkHints: fwHints,
243
+ languageHints: languages,
244
+ tags: ['security-coverage', 'auth-test'],
245
+ });
246
+ }
247
+ }
248
+ return findings;
249
+ }
250
+ function buildSecurityScanFindings(securityFindings, languages) {
251
+ var _a, _b;
252
+ const findings = [];
253
+ if (!(securityFindings === null || securityFindings === void 0 ? void 0 : securityFindings.length))
254
+ return findings;
255
+ const fwHints = frameworkHintsForLanguages(languages);
256
+ for (const sf of securityFindings) {
257
+ const severity = normalizeSeverity(sf.severity);
258
+ findings.push({
259
+ id: makeId('ff-scan'),
260
+ source: 'security-scan',
261
+ category: 'security-finding-unprotected',
262
+ severity,
263
+ title: `Scanner finding: ${sf.title}`,
264
+ description: (_a = sf.description) !== null && _a !== void 0 ? _a : sf.title,
265
+ endpoint: sf.endpoint,
266
+ filePaths: sf.filePath ? [sf.filePath] : [],
267
+ relatedScanners: sf.scanner ? [sf.scanner] : [],
268
+ missingTestTypes: ['security-test', 'negative-api-test'],
269
+ frameworkHints: fwHints,
270
+ languageHints: languages,
271
+ tags: ['security-scan', (_b = sf.scanner) !== null && _b !== void 0 ? _b : 'scanner', severity.toLowerCase()],
272
+ });
273
+ }
274
+ return findings;
275
+ }
276
+ function buildParameterCoverageFindings(details, languages) {
277
+ var _a, _b, _c;
278
+ const findings = [];
279
+ if (!Array.isArray(details))
280
+ return findings;
281
+ const fwHints = frameworkHintsForLanguages(languages);
282
+ for (const item of details) {
283
+ if (!item.covered && ((_a = item.missingCategories) === null || _a === void 0 ? void 0 : _a.length)) {
284
+ const hasBoundary = item.missingCategories.includes('boundary');
285
+ const hasInvalid = item.missingCategories.includes('invalid');
286
+ if (hasBoundary) {
287
+ findings.push({
288
+ id: makeId('ff-param-boundary'),
289
+ source: 'parameter-coverage',
290
+ category: 'missing-boundary-test',
291
+ severity: 'MEDIUM',
292
+ title: `Missing boundary tests for parameter: ${(_b = item.name) !== null && _b !== void 0 ? _b : 'unknown'}`,
293
+ description: `Parameter "${item.name}" is missing boundary value test coverage.`,
294
+ endpoint: item.endpoint,
295
+ missingTestTypes: ['boundary-test'],
296
+ frameworkHints: fwHints,
297
+ languageHints: languages,
298
+ tags: ['parameter-coverage', 'boundary-test'],
299
+ });
300
+ }
301
+ if (hasInvalid) {
302
+ findings.push({
303
+ id: makeId('ff-param-invalid'),
304
+ source: 'parameter-coverage',
305
+ category: 'high-risk-parameter-gap',
306
+ severity: 'MEDIUM',
307
+ title: `Missing invalid-input tests for parameter: ${(_c = item.name) !== null && _c !== void 0 ? _c : 'unknown'}`,
308
+ description: `Parameter "${item.name}" is missing invalid input test coverage.`,
309
+ endpoint: item.endpoint,
310
+ missingTestTypes: ['negative-api-test'],
311
+ frameworkHints: fwHints,
312
+ languageHints: languages,
313
+ tags: ['parameter-coverage', 'negative-test'],
314
+ });
315
+ }
316
+ }
317
+ }
318
+ return findings;
319
+ }
320
+ function buildCompatibilityFindings(details, languages) {
321
+ var _a, _b;
322
+ const findings = [];
323
+ if (!Array.isArray(details))
324
+ return findings;
325
+ const fwHints = frameworkHintsForLanguages(languages);
326
+ for (const item of details) {
327
+ if (item.breakingChange) {
328
+ findings.push({
329
+ id: makeId('ff-compat'),
330
+ source: 'compatibility',
331
+ category: 'compatibility-risk',
332
+ severity: 'HIGH',
333
+ title: `Breaking change risk: ${(_a = item.description) !== null && _a !== void 0 ? _a : 'API contract change'}`,
334
+ description: (_b = item.description) !== null && _b !== void 0 ? _b : 'A breaking API change was detected with no contract test.',
335
+ endpoint: item.endpoint,
336
+ missingTestTypes: ['compatibility-test'],
337
+ frameworkHints: fwHints,
338
+ languageHints: languages,
339
+ tags: ['compatibility', 'breaking-change'],
340
+ });
341
+ }
342
+ }
343
+ return findings;
344
+ }
345
+ function buildPerfResilienceFindings(details, languages) {
346
+ var _a, _b, _c, _d, _e, _f;
347
+ const findings = [];
348
+ if (!Array.isArray(details))
349
+ return findings;
350
+ const fwHints = frameworkHintsForLanguages(languages);
351
+ for (const item of details) {
352
+ if (!item.covered) {
353
+ if (item.hasThreshold) {
354
+ findings.push({
355
+ id: makeId('ff-perf'),
356
+ source: 'performance-resilience',
357
+ category: 'performance-risk',
358
+ severity: 'MEDIUM',
359
+ title: `Missing performance test: ${(_c = (_b = (_a = item.endpoint) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : item.name) !== null && _c !== void 0 ? _c : 'unknown'}`,
360
+ description: `Endpoint has performance thresholds defined but no performance test exists.`,
361
+ endpoint: item.endpoint,
362
+ missingTestTypes: ['performance-test'],
363
+ frameworkHints: fwHints,
364
+ languageHints: languages,
365
+ tags: ['performance', 'perf-test'],
366
+ });
367
+ }
368
+ if (item.resilience) {
369
+ findings.push({
370
+ id: makeId('ff-resilience'),
371
+ source: 'performance-resilience',
372
+ category: 'performance-risk',
373
+ severity: 'MEDIUM',
374
+ title: `Missing resilience test: ${(_f = (_e = (_d = item.endpoint) === null || _d === void 0 ? void 0 : _d.path) !== null && _e !== void 0 ? _e : item.name) !== null && _f !== void 0 ? _f : 'unknown'}`,
375
+ description: `Resilience scenario has no test coverage.`,
376
+ endpoint: item.endpoint,
377
+ missingTestTypes: ['resilience-test'],
378
+ frameworkHints: fwHints,
379
+ languageHints: languages,
380
+ tags: ['resilience', 'resilience-test'],
381
+ });
382
+ }
383
+ }
384
+ }
385
+ return findings;
386
+ }
387
+ // ─── Deduplication ────────────────────────────────────────────────────────────
388
+ function deduplicateFindings(findings) {
389
+ const seen = new Set();
390
+ return findings.filter((f) => {
391
+ var _a, _b, _c, _d;
392
+ const key = `${f.category}|${(_b = (_a = f.endpoint) === null || _a === void 0 ? void 0 : _a.method) !== null && _b !== void 0 ? _b : ''}|${(_d = (_c = f.endpoint) === null || _c === void 0 ? void 0 : _c.path) !== null && _d !== void 0 ? _d : ''}|${f.title}`;
393
+ if (seen.has(key))
394
+ return false;
395
+ seen.add(key);
396
+ return true;
397
+ });
398
+ }
399
+ // ─── Recommendation generation ────────────────────────────────────────────────
400
+ function categoryToTestType(category) {
401
+ switch (category) {
402
+ case 'uncovered-endpoint': return 'positive-api-test';
403
+ case 'missing-negative-test': return 'negative-api-test';
404
+ case 'missing-auth-test': return 'auth-test';
405
+ case 'missing-boundary-test': return 'boundary-test';
406
+ case 'missing-business-rule-test': return 'business-rule-test';
407
+ case 'missing-flow-step-test': return 'integration-flow-test';
408
+ case 'security-finding-unprotected': return 'security-test';
409
+ case 'high-risk-parameter-gap': return 'negative-api-test';
410
+ case 'compatibility-risk': return 'compatibility-test';
411
+ case 'performance-risk': return 'performance-test';
412
+ case 'error-scenario-gap': return 'negative-api-test';
413
+ default: return 'positive-api-test';
414
+ }
415
+ }
416
+ function buildRecommendationFromFinding(finding, primaryLanguage, primaryFramework) {
417
+ var _a, _b, _c, _d, _e, _f, _g;
418
+ const testType = categoryToTestType(finding.category);
419
+ const language = primaryLanguage !== null && primaryLanguage !== void 0 ? primaryLanguage : (_a = finding.languageHints) === null || _a === void 0 ? void 0 : _a[0];
420
+ const framework = primaryFramework !== null && primaryFramework !== void 0 ? primaryFramework : (_b = finding.frameworkHints) === null || _b === void 0 ? void 0 : _b[0];
421
+ const hasSecuritySignal = finding.source === 'security-scan' ||
422
+ finding.category === 'security-finding-unprotected' ||
423
+ finding.category === 'missing-auth-test';
424
+ const isMoneyEp = isMoneyPath((_c = finding.endpoint) === null || _c === void 0 ? void 0 : _c.path);
425
+ const isAuthGap = finding.category === 'missing-auth-test' ||
426
+ finding.category === 'security-finding-unprotected';
427
+ const isZeroCoverage = (_e = (_d = finding.tags) === null || _d === void 0 ? void 0 : _d.includes('zero-coverage')) !== null && _e !== void 0 ? _e : false;
428
+ const score = (0, riskScoring_1.computeRiskScore)({
429
+ severity: finding.severity,
430
+ category: finding.category,
431
+ endpointPath: (_f = finding.endpoint) === null || _f === void 0 ? void 0 : _f.path,
432
+ hasSecuritySignal,
433
+ zeroCoverage: isZeroCoverage,
434
+ });
435
+ const priority = (0, riskScoring_1.scoreToPriority)(score, {
436
+ isCriticalSecurityFinding: finding.severity === 'CRITICAL' && hasSecuritySignal,
437
+ isMoneyMovementEndpoint: isMoneyEp,
438
+ isAuthGap,
439
+ isZeroCoverageCriticalFlow: isZeroCoverage &&
440
+ (0, riskScoring_1.defaultCriticalityWeight)(finding.category, (_g = finding.endpoint) === null || _g === void 0 ? void 0 : _g.path) >= 75,
441
+ });
442
+ const hint = recommendationHint(testType, language, framework);
443
+ return {
444
+ id: makeId('rec'),
445
+ priority,
446
+ title: `Add ${testType.replace(/-/g, ' ')} for: ${finding.title}`,
447
+ rationale: `${finding.description} ${hint}`,
448
+ recommendedTestType: testType,
449
+ endpoint: finding.endpoint,
450
+ likelyFramework: framework,
451
+ likelyLanguage: language,
452
+ linkedFindingIds: [finding.id],
453
+ riskScore: score,
454
+ confidence: hasSecuritySignal ? 'high' : isZeroCoverage ? 'high' : 'medium',
455
+ };
456
+ }
457
+ function deduplicateRecommendations(recs) {
458
+ var _a, _b, _c, _d, _e;
459
+ const byKey = new Map();
460
+ for (const r of recs) {
461
+ const key = `${r.recommendedTestType}|${(_b = (_a = r.endpoint) === null || _a === void 0 ? void 0 : _a.method) !== null && _b !== void 0 ? _b : ''}|${(_d = (_c = r.endpoint) === null || _c === void 0 ? void 0 : _c.path) !== null && _d !== void 0 ? _d : ''}`;
462
+ const existing = byKey.get(key);
463
+ if (!existing || r.riskScore > existing.riskScore) {
464
+ byKey.set(key, {
465
+ ...r,
466
+ linkedFindingIds: [
467
+ ...((_e = existing === null || existing === void 0 ? void 0 : existing.linkedFindingIds) !== null && _e !== void 0 ? _e : []),
468
+ ...r.linkedFindingIds,
469
+ ].filter((v, i, a) => a.indexOf(v) === i),
470
+ });
471
+ }
472
+ }
473
+ return Array.from(byKey.values()).sort((a, b) => b.riskScore - a.riskScore);
474
+ }
475
+ /**
476
+ * Run the full linkage engine over coverage + security results.
477
+ * Returns all functional findings and deduplicated recommendations.
478
+ */
479
+ function runLinkageEngine(input) {
480
+ var _a, _b;
481
+ const languages = (_a = input.languages) !== null && _a !== void 0 ? _a : [];
482
+ const frameworks = (_b = input.frameworks) !== null && _b !== void 0 ? _b : [];
483
+ const primaryLanguage = languages[0];
484
+ const primaryFramework = frameworks[0];
485
+ let allFindings = [];
486
+ for (const result of input.coverageResults) {
487
+ switch (result.type) {
488
+ case 'endpoint':
489
+ allFindings.push(...buildEndpointFindings(result.details, languages, frameworks));
490
+ break;
491
+ case 'error':
492
+ allFindings.push(...buildErrorCoverageFindings(result.details, languages));
493
+ break;
494
+ case 'business':
495
+ allFindings.push(...buildBusinessCoverageFindings(result.details, languages));
496
+ break;
497
+ case 'integration':
498
+ allFindings.push(...buildIntegrationFlowFindings(result.details, languages));
499
+ break;
500
+ case 'security':
501
+ allFindings.push(...buildSecurityCoverageFindings(result.details, languages));
502
+ break;
503
+ case 'parameter':
504
+ allFindings.push(...buildParameterCoverageFindings(result.details, languages));
505
+ break;
506
+ case 'compatibility':
507
+ allFindings.push(...buildCompatibilityFindings(result.details, languages));
508
+ break;
509
+ case 'performance':
510
+ allFindings.push(...buildPerfResilienceFindings(result.details, languages));
511
+ break;
512
+ }
513
+ }
514
+ // Add security scanner findings
515
+ allFindings.push(...buildSecurityScanFindings(input.securityFindings, languages));
516
+ // Deduplicate
517
+ const findings = deduplicateFindings(allFindings);
518
+ // Build recommendations from each finding
519
+ const rawRecs = findings.map((f) => buildRecommendationFromFinding(f, primaryLanguage, primaryFramework));
520
+ const recommendations = deduplicateRecommendations(rawRecs);
521
+ return { findings, recommendations };
522
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Coverage Intelligence – AI-Friendly Markdown Reporter.
3
+ *
4
+ * Generates structured, concise markdown and JSON reports from
5
+ * IntelligenceReport data. All outputs are deterministic.
6
+ */
7
+ import type { IntelligenceReport } from './types';
8
+ export declare function renderCoverageIntelligenceMd(report: IntelligenceReport): string;
9
+ export declare function renderMissingTestsMd(report: IntelligenceReport): string;
10
+ export declare function renderRiskPrioritizationMd(report: IntelligenceReport): string;
11
+ export declare function writeIntelligenceReports(report: IntelligenceReport, outDir: string): void;
12
+ //# sourceMappingURL=markdownReporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownReporter.d.ts","sourceRoot":"","sources":["../../../src/intelligence/markdownReporter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EACV,kBAAkB,EAMnB,MAAM,SAAS,CAAC;AAwCjB,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAsG/E;AAID,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAyCvE;AAID,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CA8E7E;AAID,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,MAAM,GACb,IAAI,CAsDN"}