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,51 @@
1
+ import { CoverageResult } from './reporting';
2
+ import { CoverageConfig } from './config';
3
+ /**
4
+ * Context object passed to every plugin's `analyze` function.
5
+ */
6
+ export interface PluginContext {
7
+ /** Raw OpenAPI / Swagger spec object (already parsed). May be undefined if not available. */
8
+ spec?: unknown;
9
+ /** Glob patterns that were used to locate test files */
10
+ testPatterns: string[];
11
+ /** Coverage results produced by the built-in analysers */
12
+ results: CoverageResult[];
13
+ /** The resolved configuration that the analyser is running with */
14
+ config: CoverageConfig;
15
+ }
16
+ /**
17
+ * The shape a plugin module must export.
18
+ */
19
+ export interface Plugin {
20
+ /**
21
+ * Main entry-point of the plugin.
22
+ *
23
+ * @param context Analysis context (spec, tests, results, config)
24
+ * @returns A `CoverageResult` (or array of `CoverageResult`s) to append to the report.
25
+ */
26
+ analyze: (context: PluginContext) => Promise<CoverageResult | CoverageResult[]>;
27
+ }
28
+ /**
29
+ * Dynamically load a plugin module from the given path.
30
+ *
31
+ * Plugin paths may be:
32
+ * - Absolute paths
33
+ * - Relative paths (resolved against `basedir`, default: `process.cwd()`)
34
+ * - Node module names (resolved normally)
35
+ *
36
+ * Errors during loading are caught and logged as warnings; `null` is returned.
37
+ */
38
+ export declare function loadPlugin(pluginPath: string, basedir?: string): Promise<Plugin | null>;
39
+ /**
40
+ * Run all plugins listed in `config.plugins`, collect their results, and
41
+ * return them as an array of `CoverageResult` objects.
42
+ *
43
+ * Errors thrown by individual plugins are caught, logged as warnings, and
44
+ * do not prevent other plugins from running.
45
+ *
46
+ * @param config Resolved configuration containing the `plugins` list
47
+ * @param context Context passed to each plugin's `analyze` function
48
+ * @param basedir Directory used to resolve relative plugin paths (default: cwd)
49
+ */
50
+ export declare function runPlugins(config: CoverageConfig, context: PluginContext, basedir?: string): Promise<CoverageResult[]>;
51
+ //# sourceMappingURL=pluginLoader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pluginLoader.d.ts","sourceRoot":"","sources":["../../src/pluginLoader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAI1C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,6FAA6F;IAC7F,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,wDAAwD;IACxD,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,0DAA0D;IAC1D,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,mEAAmE;IACnE,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB;;;;;OAKG;IACH,OAAO,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,cAAc,GAAG,cAAc,EAAE,CAAC,CAAC;CACjF;AAID;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwB7F;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,EAAE,CAAC,CAsB3B"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadPlugin = loadPlugin;
4
+ exports.runPlugins = runPlugins;
5
+ // ─── Loader ───────────────────────────────────────────────────────────────────
6
+ /**
7
+ * Dynamically load a plugin module from the given path.
8
+ *
9
+ * Plugin paths may be:
10
+ * - Absolute paths
11
+ * - Relative paths (resolved against `basedir`, default: `process.cwd()`)
12
+ * - Node module names (resolved normally)
13
+ *
14
+ * Errors during loading are caught and logged as warnings; `null` is returned.
15
+ */
16
+ async function loadPlugin(pluginPath, basedir) {
17
+ const base = basedir !== null && basedir !== void 0 ? basedir : process.cwd();
18
+ let resolvedPath = pluginPath;
19
+ // Resolve relative paths against the base directory
20
+ if (pluginPath.startsWith('./') || pluginPath.startsWith('../')) {
21
+ resolvedPath = require('path').resolve(base, pluginPath);
22
+ }
23
+ try {
24
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
25
+ const mod = require(resolvedPath);
26
+ if (typeof mod.analyze !== 'function') {
27
+ console.warn(`[plugin] Warning: plugin "${pluginPath}" does not export an "analyze" function – skipping.`);
28
+ return null;
29
+ }
30
+ return mod;
31
+ }
32
+ catch (err) {
33
+ const message = err instanceof Error ? err.message : String(err);
34
+ console.warn(`[plugin] Warning: failed to load plugin "${pluginPath}": ${message}`);
35
+ return null;
36
+ }
37
+ }
38
+ /**
39
+ * Run all plugins listed in `config.plugins`, collect their results, and
40
+ * return them as an array of `CoverageResult` objects.
41
+ *
42
+ * Errors thrown by individual plugins are caught, logged as warnings, and
43
+ * do not prevent other plugins from running.
44
+ *
45
+ * @param config Resolved configuration containing the `plugins` list
46
+ * @param context Context passed to each plugin's `analyze` function
47
+ * @param basedir Directory used to resolve relative plugin paths (default: cwd)
48
+ */
49
+ async function runPlugins(config, context, basedir) {
50
+ var _a;
51
+ const pluginPaths = (_a = config.plugins) !== null && _a !== void 0 ? _a : [];
52
+ const allResults = [];
53
+ for (const pluginPath of pluginPaths) {
54
+ const plugin = await loadPlugin(pluginPath, basedir);
55
+ if (!plugin)
56
+ continue;
57
+ try {
58
+ const pluginResult = await plugin.analyze(context);
59
+ if (Array.isArray(pluginResult)) {
60
+ allResults.push(...pluginResult);
61
+ }
62
+ else {
63
+ allResults.push(pluginResult);
64
+ }
65
+ }
66
+ catch (err) {
67
+ const message = err instanceof Error ? err.message : String(err);
68
+ console.warn(`[plugin] Warning: plugin "${pluginPath}" threw an error during analysis: ${message}`);
69
+ }
70
+ }
71
+ return allResults;
72
+ }
@@ -0,0 +1,63 @@
1
+ import type { CoverageResult } from './reporting';
2
+ import type { QualityGateResult } from './qualityGate';
3
+ import type { PublishingConfig } from './config';
4
+ /** Metadata attached to each generated build bundle */
5
+ export interface BuildMetadata {
6
+ buildId: string;
7
+ projectName: string;
8
+ repositoryName: string | null;
9
+ branch: string | null;
10
+ commitSha: string | null;
11
+ runId: string | null;
12
+ buildTimestamp: string;
13
+ thresholds: Record<string, number | undefined>;
14
+ actualCoverage: Record<string, number>;
15
+ passed: boolean;
16
+ }
17
+ /** All generated files for a single build */
18
+ export interface GeneratedReports {
19
+ buildId: string;
20
+ bundleDir: string;
21
+ siteDir: string;
22
+ files: string[];
23
+ metadata: BuildMetadata;
24
+ }
25
+ /**
26
+ * Resolve the build ID from the publishing configuration and environment.
27
+ *
28
+ * Supported patterns:
29
+ * - "timestamp" → ISO timestamp (default)
30
+ * - "commit-sha" → GITHUB_SHA env var
31
+ * - "run-number" → GITHUB_RUN_NUMBER env var
32
+ * - "branch-timestamp" → branch name + timestamp
33
+ * - any other string → used as-is (custom naming)
34
+ */
35
+ export declare function resolveBuildId(config: PublishingConfig): string;
36
+ /** Build the metadata object for the current run */
37
+ export declare function buildBuildMetadata(results: CoverageResult[], qualityGate: QualityGateResult, config: PublishingConfig, buildId: string, thresholds: Record<string, number | undefined>): BuildMetadata;
38
+ /** Generate an AI-friendly markdown summary */
39
+ export declare function generateMarkdownSummary(results: CoverageResult[], qualityGate: QualityGateResult, metadata: BuildMetadata): string;
40
+ /** Generate the central index.html landing page */
41
+ export declare function generateLandingPage(results: CoverageResult[], qualityGate: QualityGateResult, metadata: BuildMetadata, config: PublishingConfig, screenshotPaths: string[]): string;
42
+ /**
43
+ * Generate a complete publishable build bundle.
44
+ *
45
+ * The bundle is written to:
46
+ * `<outputDir>/builds/<buildId>/`
47
+ *
48
+ * And the static site root is:
49
+ * `<outputDir>/`
50
+ */
51
+ export declare function generateBuildBundle(results: CoverageResult[], qualityGate: QualityGateResult, config: PublishingConfig, thresholds: Record<string, number | undefined>, screenshotPaths?: string[]): GeneratedReports;
52
+ /**
53
+ * Copy existing report files from `reportsDir` into the bundle and site directories.
54
+ * Useful to include the standard multi-format reports in the static site.
55
+ */
56
+ export declare function copyReportFilesToBundle(reportsDir: string, bundleDir: string, siteDir: string, artifacts?: {
57
+ includeJson?: boolean;
58
+ includeHtml?: boolean;
59
+ includeCsv?: boolean;
60
+ includeJunit?: boolean;
61
+ includeMarkdown?: boolean;
62
+ }): string[];
63
+ //# sourceMappingURL=publishing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publishing.d.ts","sourceRoot":"","sources":["../../src/publishing.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAIjD,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/C,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,aAAa,CAAC;CACzB;AAID;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAuB/D;AAID,oDAAoD;AACpD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,cAAc,EAAE,EACzB,WAAW,EAAE,iBAAiB,EAC9B,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAC7C,aAAa,CAkBf;AAID,+CAA+C;AAC/C,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,cAAc,EAAE,EACzB,WAAW,EAAE,iBAAiB,EAC9B,QAAQ,EAAE,aAAa,GACtB,MAAM,CA0ER;AAID,mDAAmD;AACnD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,cAAc,EAAE,EACzB,WAAW,EAAE,iBAAiB,EAC9B,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,gBAAgB,EACxB,eAAe,EAAE,MAAM,EAAE,GACxB,MAAM,CAoHR;AAWD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,cAAc,EAAE,EACzB,WAAW,EAAE,iBAAiB,EAC9B,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EAC9C,eAAe,CAAC,EAAE,MAAM,EAAE,GACzB,gBAAgB,CA4ClB;AAID;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,GAAE;IACT,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;CACtB,GACL,MAAM,EAAE,CAwCV"}
@@ -0,0 +1,379 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.resolveBuildId = resolveBuildId;
37
+ exports.buildBuildMetadata = buildBuildMetadata;
38
+ exports.generateMarkdownSummary = generateMarkdownSummary;
39
+ exports.generateLandingPage = generateLandingPage;
40
+ exports.generateBuildBundle = generateBuildBundle;
41
+ exports.copyReportFilesToBundle = copyReportFilesToBundle;
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ // ─── Build ID resolution ──────────────────────────────────────────────────────
45
+ /**
46
+ * Resolve the build ID from the publishing configuration and environment.
47
+ *
48
+ * Supported patterns:
49
+ * - "timestamp" → ISO timestamp (default)
50
+ * - "commit-sha" → GITHUB_SHA env var
51
+ * - "run-number" → GITHUB_RUN_NUMBER env var
52
+ * - "branch-timestamp" → branch name + timestamp
53
+ * - any other string → used as-is (custom naming)
54
+ */
55
+ function resolveBuildId(config) {
56
+ var _a, _b, _c, _d;
57
+ const pattern = (_a = config.buildId) !== null && _a !== void 0 ? _a : 'timestamp';
58
+ switch (pattern) {
59
+ case 'timestamp':
60
+ return new Date().toISOString().replace(/[:.]/g, '-');
61
+ case 'commit-sha':
62
+ return (_b = process.env['GITHUB_SHA']) !== null && _b !== void 0 ? _b : new Date().toISOString().replace(/[:.]/g, '-');
63
+ case 'run-number':
64
+ return (_c = process.env['GITHUB_RUN_NUMBER']) !== null && _c !== void 0 ? _c : new Date().toISOString().replace(/[:.]/g, '-');
65
+ case 'branch-timestamp': {
66
+ const branch = ((_d = process.env['GITHUB_REF_NAME']) !== null && _d !== void 0 ? _d : 'local').replace(/[^a-zA-Z0-9-_]/g, '-');
67
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
68
+ return `${branch}-${ts}`;
69
+ }
70
+ default:
71
+ // Custom or environment-variable pattern
72
+ return pattern;
73
+ }
74
+ }
75
+ // ─── Metadata builder ─────────────────────────────────────────────────────────
76
+ /** Build the metadata object for the current run */
77
+ function buildBuildMetadata(results, qualityGate, config, buildId, thresholds) {
78
+ var _a, _b, _c, _d, _e, _f;
79
+ const actualCoverage = {};
80
+ for (const r of results) {
81
+ actualCoverage[r.type] = r.coveragePercent;
82
+ }
83
+ return {
84
+ buildId,
85
+ projectName: (_b = (_a = process.env['GITHUB_REPOSITORY']) === null || _a === void 0 ? void 0 : _a.split('/')[1]) !== null && _b !== void 0 ? _b : 'api-coverage',
86
+ repositoryName: (_c = process.env['GITHUB_REPOSITORY']) !== null && _c !== void 0 ? _c : null,
87
+ branch: (_d = process.env['GITHUB_REF_NAME']) !== null && _d !== void 0 ? _d : null,
88
+ commitSha: (_e = process.env['GITHUB_SHA']) !== null && _e !== void 0 ? _e : null,
89
+ runId: (_f = process.env['GITHUB_RUN_ID']) !== null && _f !== void 0 ? _f : null,
90
+ buildTimestamp: new Date().toISOString(),
91
+ thresholds,
92
+ actualCoverage,
93
+ passed: qualityGate.passed,
94
+ };
95
+ }
96
+ // ─── Markdown report generator ────────────────────────────────────────────────
97
+ /** Generate an AI-friendly markdown summary */
98
+ function generateMarkdownSummary(results, qualityGate, metadata) {
99
+ var _a, _b, _c;
100
+ const statusEmoji = metadata.passed ? '✅' : '❌';
101
+ const lines = [
102
+ `# API Coverage Report — ${statusEmoji} ${metadata.passed ? 'PASSED' : 'FAILED'}`,
103
+ '',
104
+ `**Project:** ${metadata.projectName}`,
105
+ `**Repository:** ${(_a = metadata.repositoryName) !== null && _a !== void 0 ? _a : 'N/A'}`,
106
+ `**Branch:** ${(_b = metadata.branch) !== null && _b !== void 0 ? _b : 'N/A'}`,
107
+ `**Commit:** ${(_c = metadata.commitSha) !== null && _c !== void 0 ? _c : 'N/A'}`,
108
+ `**Build ID:** ${metadata.buildId}`,
109
+ `**Timestamp:** ${metadata.buildTimestamp}`,
110
+ '',
111
+ '## Coverage Summary',
112
+ '',
113
+ '| Category | Total | Covered | % |',
114
+ '|---|---|---|---|',
115
+ ];
116
+ for (const r of results) {
117
+ const pct = r.coveragePercent.toFixed(2);
118
+ const status = qualityGate.failures.some((f) => f.category === r.type) ? '❌' : '✅';
119
+ lines.push(`| ${r.type} ${status} | ${r.totalItems} | ${r.coveredItems} | ${pct}% |`);
120
+ }
121
+ lines.push('');
122
+ lines.push('## Quality Gate');
123
+ lines.push('');
124
+ if (qualityGate.failures.length === 0) {
125
+ lines.push('✅ All coverage thresholds met.');
126
+ }
127
+ else {
128
+ lines.push('❌ The following categories did not meet their thresholds:');
129
+ lines.push('');
130
+ for (const f of qualityGate.failures) {
131
+ lines.push(`- **${f.category}**: expected ≥ ${f.expected}%, actual ${f.actual}%, gap ${f.gap}%`);
132
+ }
133
+ }
134
+ lines.push('');
135
+ lines.push('## AI-Friendly Analysis');
136
+ lines.push('');
137
+ lines.push('<details>');
138
+ lines.push('<summary>Expand for AI-friendly analysis</summary>');
139
+ lines.push('');
140
+ lines.push('### Coverage Gaps');
141
+ lines.push('');
142
+ const gaps = results.filter((r) => r.coveragePercent < 100);
143
+ if (gaps.length === 0) {
144
+ lines.push('No coverage gaps found.');
145
+ }
146
+ else {
147
+ for (const g of gaps) {
148
+ lines.push(`- **${g.type}**: ${g.coveredItems}/${g.totalItems} covered (${g.coveragePercent.toFixed(2)}%)`);
149
+ }
150
+ }
151
+ lines.push('');
152
+ lines.push('### Recommended Next Steps');
153
+ lines.push('');
154
+ if (qualityGate.failures.length > 0) {
155
+ for (const f of qualityGate.failures) {
156
+ lines.push(`- Increase **${f.category}** coverage by at least ${f.gap}% to meet the configured threshold.`);
157
+ }
158
+ }
159
+ else {
160
+ lines.push('- Coverage meets all configured thresholds. Consider increasing thresholds to maintain quality.');
161
+ }
162
+ lines.push('');
163
+ lines.push('</details>');
164
+ return lines.join('\n');
165
+ }
166
+ // ─── Landing page generator ───────────────────────────────────────────────────
167
+ /** Generate the central index.html landing page */
168
+ function generateLandingPage(results, qualityGate, metadata, config, screenshotPaths) {
169
+ var _a, _b, _c, _d, _e;
170
+ const basePath = (_b = (_a = config.githubPages) === null || _a === void 0 ? void 0 : _a.basePath) !== null && _b !== void 0 ? _b : '/';
171
+ const statusClass = metadata.passed ? 'passed' : 'failed';
172
+ const statusText = metadata.passed ? '✅ PASSED' : '❌ FAILED';
173
+ const coverageRows = results.map((r) => {
174
+ const pct = r.coveragePercent.toFixed(2);
175
+ const rowStatus = qualityGate.failures.some((f) => f.category === r.type)
176
+ ? 'below'
177
+ : 'above';
178
+ return `<tr class="${rowStatus}">
179
+ <td>${r.type}</td>
180
+ <td>${r.totalItems}</td>
181
+ <td>${r.coveredItems}</td>
182
+ <td>${pct}%</td>
183
+ </tr>`;
184
+ }).join('\n');
185
+ const failureRows = qualityGate.failures.map((f) => `
186
+ <li><strong>${f.category}</strong>: expected ≥ ${f.expected}%, actual ${f.actual}%, gap ${f.gap}%</li>
187
+ `).join('');
188
+ const screenshotSection = screenshotPaths.length > 0
189
+ ? `<section class="screenshots">
190
+ <h2>Dashboard Screenshots</h2>
191
+ <div class="screenshot-grid">
192
+ ${screenshotPaths.map((p) => `<figure>
193
+ <img src="${p}" alt="Dashboard screenshot" loading="lazy">
194
+ </figure>`).join('\n')}
195
+ </div>
196
+ </section>`
197
+ : `<section class="screenshots">
198
+ <p class="notice">No screenshots available. Run with screenshot capture enabled.</p>
199
+ </section>`;
200
+ return `<!DOCTYPE html>
201
+ <html lang="en">
202
+ <head>
203
+ <meta charset="UTF-8">
204
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
205
+ <title>API Coverage Report — ${metadata.projectName}</title>
206
+ <style>
207
+ body { font-family: system-ui, sans-serif; max-width: 1100px; margin: 0 auto; padding: 1rem; }
208
+ h1 { border-bottom: 2px solid #333; padding-bottom: .5rem; }
209
+ .status { display: inline-block; padding: .25rem .75rem; border-radius: 4px; font-weight: bold; }
210
+ .passed { background: #d4edda; color: #155724; }
211
+ .failed { background: #f8d7da; color: #721c24; }
212
+ table { border-collapse: collapse; width: 100%; margin: 1rem 0; }
213
+ th, td { border: 1px solid #dee2e6; padding: .5rem .75rem; text-align: left; }
214
+ th { background: #f8f9fa; }
215
+ tr.above td:last-child { color: #155724; }
216
+ tr.below { background: #fff3cd; }
217
+ tr.below td:last-child { color: #856404; font-weight: bold; }
218
+ .meta { background: #f8f9fa; padding: 1rem; border-radius: 4px; margin: 1rem 0; }
219
+ .meta p { margin: .25rem 0; }
220
+ details summary { cursor: pointer; font-weight: bold; padding: .5rem 0; }
221
+ .screenshot-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1rem; }
222
+ .screenshot-grid img { width: 100%; border: 1px solid #dee2e6; border-radius: 4px; }
223
+ .notice { color: #6c757d; font-style: italic; }
224
+ ul { padding-left: 1.5rem; }
225
+ </style>
226
+ </head>
227
+ <body>
228
+ <h1>API Coverage Report <span class="status ${statusClass}">${statusText}</span></h1>
229
+
230
+ <div class="meta">
231
+ <p><strong>Project:</strong> ${metadata.projectName}</p>
232
+ <p><strong>Repository:</strong> ${(_c = metadata.repositoryName) !== null && _c !== void 0 ? _c : 'N/A'}</p>
233
+ <p><strong>Branch:</strong> ${(_d = metadata.branch) !== null && _d !== void 0 ? _d : 'N/A'}</p>
234
+ <p><strong>Commit:</strong> ${(_e = metadata.commitSha) !== null && _e !== void 0 ? _e : 'N/A'}</p>
235
+ <p><strong>Build ID:</strong> ${metadata.buildId}</p>
236
+ <p><strong>Timestamp:</strong> ${metadata.buildTimestamp}</p>
237
+ </div>
238
+
239
+ <h2>Coverage Summary</h2>
240
+ <table>
241
+ <thead><tr><th>Category</th><th>Total</th><th>Covered</th><th>%</th></tr></thead>
242
+ <tbody>${coverageRows}</tbody>
243
+ </table>
244
+
245
+ <h2>Quality Gate</h2>
246
+ ${qualityGate.failures.length === 0
247
+ ? '<p class="status passed">✅ All coverage thresholds met.</p>'
248
+ : `<p class="status failed">❌ ${qualityGate.failures.length} threshold(s) not met:</p>
249
+ <ul>${failureRows}</ul>`}
250
+
251
+ ${screenshotSection}
252
+
253
+ <details>
254
+ <summary>AI-Friendly Analysis</summary>
255
+ <h3>Coverage Gaps</h3>
256
+ <ul>
257
+ ${results
258
+ .filter((r) => r.coveragePercent < 100)
259
+ .map((r) => `<li><strong>${r.type}</strong>: ${r.coveredItems}/${r.totalItems} covered (${r.coveragePercent.toFixed(2)}%)</li>`)
260
+ .join('\n') || '<li>No coverage gaps found.</li>'}
261
+ </ul>
262
+ <h3>Recommended Next Steps</h3>
263
+ <ul>
264
+ ${qualityGate.failures.length > 0
265
+ ? qualityGate.failures.map((f) => `<li>Increase <strong>${f.category}</strong> coverage by at least ${f.gap}% to meet the configured threshold.</li>`).join('\n')
266
+ : '<li>Coverage meets all configured thresholds. Consider increasing thresholds to maintain quality.</li>'}
267
+ </ul>
268
+ </details>
269
+
270
+ <h2>Report Links</h2>
271
+ <ul>
272
+ ${results.map((r) => `<li><a href="${basePath}${r.type}-coverage.html">${r.type} coverage report</a></li>`).join('\n')}
273
+ <li><a href="${basePath}coverage-summary.json">coverage-summary.json</a></li>
274
+ <li><a href="${basePath}coverage-summary.csv">coverage-summary.csv</a></li>
275
+ <li><a href="${basePath}coverage-summary-junit.xml">coverage-summary-junit.xml</a></li>
276
+ <li><a href="${basePath}ai-summary.md">AI-Friendly Markdown Summary</a></li>
277
+ </ul>
278
+ </body>
279
+ </html>`;
280
+ }
281
+ // ─── Bundle generator ─────────────────────────────────────────────────────────
282
+ /** Write the build metadata JSON file */
283
+ function writeBuildMetadata(bundleDir, metadata) {
284
+ const metaPath = path.join(bundleDir, 'build-metadata.json');
285
+ fs.writeFileSync(metaPath, JSON.stringify(metadata, null, 2), 'utf-8');
286
+ return metaPath;
287
+ }
288
+ /**
289
+ * Generate a complete publishable build bundle.
290
+ *
291
+ * The bundle is written to:
292
+ * `<outputDir>/builds/<buildId>/`
293
+ *
294
+ * And the static site root is:
295
+ * `<outputDir>/`
296
+ */
297
+ function generateBuildBundle(results, qualityGate, config, thresholds, screenshotPaths) {
298
+ var _a;
299
+ const outputDir = (_a = config.outputDir) !== null && _a !== void 0 ? _a : 'site';
300
+ const buildId = resolveBuildId(config);
301
+ const bundleDir = path.join(outputDir, 'builds', buildId);
302
+ const screenshots = screenshotPaths !== null && screenshotPaths !== void 0 ? screenshotPaths : [];
303
+ fs.mkdirSync(bundleDir, { recursive: true });
304
+ const metadata = buildBuildMetadata(results, qualityGate, config, buildId, thresholds);
305
+ const files = [];
306
+ // ── Build metadata ───────────────────────────────────────────────────────
307
+ files.push(writeBuildMetadata(bundleDir, metadata));
308
+ // ── Markdown summary (AI-friendly) ───────────────────────────────────────
309
+ const mdSummary = generateMarkdownSummary(results, qualityGate, metadata);
310
+ const mdPath = path.join(bundleDir, 'ai-summary.md');
311
+ fs.writeFileSync(mdPath, mdSummary, 'utf-8');
312
+ files.push(mdPath);
313
+ // ── Landing page ─────────────────────────────────────────────────────────
314
+ const landingHtml = generateLandingPage(results, qualityGate, metadata, config, screenshots);
315
+ const indexPath = path.join(bundleDir, 'index.html');
316
+ fs.writeFileSync(indexPath, landingHtml, 'utf-8');
317
+ files.push(indexPath);
318
+ // ── Site root index (always points to latest build) ──────────────────────
319
+ fs.mkdirSync(outputDir, { recursive: true });
320
+ const siteIndexPath = path.join(outputDir, 'index.html');
321
+ fs.writeFileSync(siteIndexPath, landingHtml, 'utf-8');
322
+ files.push(siteIndexPath);
323
+ // ── AI-friendly markdown at site root ────────────────────────────────────
324
+ const siteAiMdPath = path.join(outputDir, 'ai-summary.md');
325
+ fs.writeFileSync(siteAiMdPath, mdSummary, 'utf-8');
326
+ files.push(siteAiMdPath);
327
+ return {
328
+ buildId,
329
+ bundleDir,
330
+ siteDir: outputDir,
331
+ files,
332
+ metadata,
333
+ };
334
+ }
335
+ // ─── Site copyover ────────────────────────────────────────────────────────────
336
+ /**
337
+ * Copy existing report files from `reportsDir` into the bundle and site directories.
338
+ * Useful to include the standard multi-format reports in the static site.
339
+ */
340
+ function copyReportFilesToBundle(reportsDir, bundleDir, siteDir, artifacts = {}) {
341
+ const copied = [];
342
+ const defaults = {
343
+ includeJson: true,
344
+ includeHtml: true,
345
+ includeCsv: true,
346
+ includeJunit: true,
347
+ includeMarkdown: true,
348
+ ...artifacts,
349
+ };
350
+ const extensions = [];
351
+ if (defaults.includeJson)
352
+ extensions.push('.json');
353
+ if (defaults.includeHtml)
354
+ extensions.push('.html');
355
+ if (defaults.includeCsv)
356
+ extensions.push('.csv');
357
+ if (defaults.includeJunit)
358
+ extensions.push('.xml');
359
+ if (defaults.includeMarkdown)
360
+ extensions.push('.md');
361
+ if (!fs.existsSync(reportsDir))
362
+ return copied;
363
+ for (const file of fs.readdirSync(reportsDir)) {
364
+ const ext = path.extname(file);
365
+ if (!extensions.includes(ext))
366
+ continue;
367
+ const src = path.join(reportsDir, file);
368
+ if (!fs.statSync(src).isFile())
369
+ continue;
370
+ const content = fs.readFileSync(src);
371
+ const bundleDest = path.join(bundleDir, file);
372
+ fs.writeFileSync(bundleDest, content);
373
+ copied.push(bundleDest);
374
+ const siteDest = path.join(siteDir, file);
375
+ fs.writeFileSync(siteDest, content);
376
+ copied.push(siteDest);
377
+ }
378
+ return copied;
379
+ }
@@ -0,0 +1,58 @@
1
+ import type { CoverageResult } from './reporting';
2
+ /** Details of a single category that failed its threshold check */
3
+ export interface QualityGateFailure {
4
+ category: string;
5
+ expected: number;
6
+ actual: number;
7
+ gap: number;
8
+ }
9
+ /** Structured result of a quality gate evaluation */
10
+ export interface QualityGateResult {
11
+ passed: boolean;
12
+ /** The effective threshold applied (global scalar or per-category map) */
13
+ threshold: number | Record<string, number>;
14
+ /** Actual coverage per category */
15
+ actual: Record<string, number>;
16
+ /** Details of every category that did not meet its threshold */
17
+ failures: QualityGateFailure[];
18
+ }
19
+ /** Configuration accepted by evaluateQualityGate */
20
+ export interface QualityGateConfig {
21
+ /** Per-category thresholds; a 'global' key sets the default for all categories */
22
+ thresholds?: Record<string, number | undefined>;
23
+ /** Branch-aware thresholds keyed by branch glob (e.g. "main", "feature/*") */
24
+ thresholdsByBranch?: Record<string, Record<string, number | undefined>>;
25
+ qualityGate?: {
26
+ enabled?: boolean;
27
+ failBuildOnThresholdMiss?: boolean;
28
+ /** "strict" = all categories must pass; "warn" = log but do not fail */
29
+ mode?: 'strict' | 'warn';
30
+ };
31
+ }
32
+ /**
33
+ * Determine whether a branch name matches a glob-style pattern.
34
+ * Supports `*` (single segment) and `**` (any segments).
35
+ */
36
+ export declare function matchesBranchPattern(branchName: string, pattern: string): boolean;
37
+ /**
38
+ * Resolve the effective threshold map for the given branch, merging
39
+ * branch-aware overrides on top of the global threshold config.
40
+ */
41
+ export declare function resolveThresholdsForBranch(config: QualityGateConfig, branchName?: string): Record<string, number>;
42
+ /**
43
+ * Compute the effective per-category threshold for a given category,
44
+ * using the 'global' key as the default when no category-specific value exists.
45
+ */
46
+ export declare function effectiveThresholdForCategory(thresholds: Record<string, number>, category: string): number | undefined;
47
+ /**
48
+ * Evaluate all coverage results against configured thresholds.
49
+ *
50
+ * Default behaviour when no thresholds are configured: every category must
51
+ * reach 100% (spec requirement: "default threshold = 100%").
52
+ *
53
+ * @param results Coverage results from one or more analysis passes.
54
+ * @param config Quality-gate / threshold configuration.
55
+ * @param branchName Current git branch name (used for branch-aware thresholds).
56
+ */
57
+ export declare function evaluateQualityGate(results: CoverageResult[], config: QualityGateConfig, branchName?: string): QualityGateResult;
58
+ //# sourceMappingURL=qualityGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qualityGate.d.ts","sourceRoot":"","sources":["../../src/qualityGate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,0EAA0E;IAC1E,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,gEAAgE;IAChE,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAChC;AAED,oDAAoD;AACpD,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAChD,8EAA8E;IAC9E,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IACxE,WAAW,CAAC,EAAE;QACZ,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,wBAAwB,CAAC,EAAE,OAAO,CAAC;QACnC,wEAAwE;QACxE,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;KAC1B,CAAC;CACH;AAID;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAMjF;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,iBAAiB,EACzB,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA2BxB;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,QAAQ,EAAE,MAAM,GACf,MAAM,GAAG,SAAS,CAIpB;AAID;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,cAAc,EAAE,EACzB,MAAM,EAAE,iBAAiB,EACzB,UAAU,CAAC,EAAE,MAAM,GAClB,iBAAiB,CAuDnB"}