apex-code-coverage-transformer 2.18.2 → 2.19.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 (48) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +71 -24
  3. package/lib/handlers/BaseHandler.d.ts +2 -2
  4. package/lib/handlers/BaseHandler.js.map +1 -1
  5. package/lib/handlers/clover.js +1 -3
  6. package/lib/handlers/clover.js.map +1 -1
  7. package/lib/handlers/cobertura.js +1 -3
  8. package/lib/handlers/cobertura.js.map +1 -1
  9. package/lib/handlers/getHandler.d.ts +2 -0
  10. package/lib/handlers/getHandler.js +2 -0
  11. package/lib/handlers/getHandler.js.map +1 -1
  12. package/lib/handlers/githubActions.d.ts +33 -0
  13. package/lib/handlers/githubActions.js +82 -0
  14. package/lib/handlers/githubActions.js.map +1 -0
  15. package/lib/handlers/istanbulJson.d.ts +1 -1
  16. package/lib/handlers/istanbulJson.js +1 -1
  17. package/lib/handlers/istanbulJson.js.map +1 -1
  18. package/lib/handlers/jacoco.d.ts +1 -1
  19. package/lib/handlers/jacoco.js +1 -1
  20. package/lib/handlers/jacoco.js.map +1 -1
  21. package/lib/handlers/lcov.d.ts +1 -1
  22. package/lib/handlers/lcov.js +2 -4
  23. package/lib/handlers/lcov.js.map +1 -1
  24. package/lib/handlers/markdown.d.ts +28 -0
  25. package/lib/handlers/markdown.js +105 -0
  26. package/lib/handlers/markdown.js.map +1 -0
  27. package/lib/handlers/sonar.js +1 -3
  28. package/lib/handlers/sonar.js.map +1 -1
  29. package/lib/transformers/generators/generateGitHubActions.d.ts +2 -0
  30. package/lib/transformers/generators/generateGitHubActions.js +27 -0
  31. package/lib/transformers/generators/generateGitHubActions.js.map +1 -0
  32. package/lib/transformers/generators/generateHtml.d.ts +2 -0
  33. package/lib/transformers/generators/generateHtml.js +399 -0
  34. package/lib/transformers/generators/generateHtml.js.map +1 -0
  35. package/lib/transformers/generators/generateMarkdown.d.ts +2 -0
  36. package/lib/transformers/generators/generateMarkdown.js +39 -0
  37. package/lib/transformers/generators/generateMarkdown.js.map +1 -0
  38. package/lib/transformers/reportGenerator.d.ts +2 -2
  39. package/lib/transformers/reportGenerator.js +28 -449
  40. package/lib/transformers/reportGenerator.js.map +1 -1
  41. package/lib/utils/constants.d.ts +17 -0
  42. package/lib/utils/constants.js +31 -0
  43. package/lib/utils/constants.js.map +1 -1
  44. package/lib/utils/types.d.ts +48 -1
  45. package/messages/transformer.transform.md +2 -0
  46. package/oclif.manifest.json +5 -1
  47. package/package.json +30 -18
  48. package/oclif.lock +0 -10078
@@ -0,0 +1,105 @@
1
+ 'use strict';
2
+ import { BaseHandler } from './BaseHandler.js';
3
+ import { HandlerRegistry } from './HandlerRegistry.js';
4
+ /**
5
+ * Handler for generating Markdown coverage summaries.
6
+ *
7
+ * Designed for pipeline PR / MR comments and job summary blocks
8
+ * (e.g. `$GITHUB_STEP_SUMMARY`, GitLab MR widgets, Bitbucket comments).
9
+ *
10
+ * The report includes:
11
+ * - An overall coverage summary block
12
+ * - A per-package-directory coverage table
13
+ * - A file coverage table sorted with the lowest coverage first
14
+ *
15
+ * Compatible with:
16
+ * - GitHub Actions (job summary, sticky PR comments)
17
+ * - GitLab CI (MR comments)
18
+ * - Bitbucket / Azure DevOps PR comments
19
+ * - Any tool that renders GitHub-flavored Markdown
20
+ */
21
+ export class MarkdownCoverageHandler extends BaseHandler {
22
+ coverageObj;
23
+ totalLinesAccumulator = 0;
24
+ coveredLinesAccumulator = 0;
25
+ packageMap = new Map();
26
+ constructor() {
27
+ super();
28
+ this.coverageObj = {
29
+ summary: {
30
+ totalLines: 0,
31
+ coveredLines: 0,
32
+ uncoveredLines: 0,
33
+ lineRate: 0,
34
+ fileCount: 0,
35
+ },
36
+ packages: [],
37
+ files: [],
38
+ };
39
+ }
40
+ processFile(filePath, _fileName, lines) {
41
+ const { totalLines, coveredLines, uncoveredLines, lineRate } = this.calculateCoverage(lines);
42
+ const fileRow = {
43
+ filePath,
44
+ totalLines,
45
+ coveredLines,
46
+ uncoveredLines,
47
+ lineRate,
48
+ };
49
+ this.coverageObj.files.push(fileRow);
50
+ this.totalLinesAccumulator += totalLines;
51
+ this.coveredLinesAccumulator += coveredLines;
52
+ const directory = filePath.split('/')[0];
53
+ const existing = this.packageMap.get(directory);
54
+ if (existing) {
55
+ existing.totalLines += totalLines;
56
+ existing.coveredLines += coveredLines;
57
+ existing.fileCount += 1;
58
+ }
59
+ else {
60
+ this.packageMap.set(directory, { totalLines, coveredLines, fileCount: 1 });
61
+ }
62
+ }
63
+ finalize() {
64
+ const totalLines = this.totalLinesAccumulator;
65
+ const coveredLines = this.coveredLinesAccumulator;
66
+ const uncoveredLines = totalLines - coveredLines;
67
+ const lineRate = totalLines > 0 ? coveredLines / totalLines : 0;
68
+ this.coverageObj.summary = {
69
+ totalLines,
70
+ coveredLines,
71
+ uncoveredLines,
72
+ lineRate,
73
+ fileCount: this.coverageObj.files.length,
74
+ };
75
+ this.coverageObj.packages = Array.from(this.packageMap.entries())
76
+ .map(([directory, acc]) => {
77
+ const pkgUncovered = acc.totalLines - acc.coveredLines;
78
+ const pkgLineRate = acc.totalLines > 0 ? acc.coveredLines / acc.totalLines : 0;
79
+ return {
80
+ directory,
81
+ fileCount: acc.fileCount,
82
+ totalLines: acc.totalLines,
83
+ coveredLines: acc.coveredLines,
84
+ uncoveredLines: pkgUncovered,
85
+ lineRate: pkgLineRate,
86
+ };
87
+ })
88
+ .sort((a, b) => a.directory.localeCompare(b.directory));
89
+ // Worst-covered files first (most actionable in a PR comment), tiebreak by path
90
+ this.coverageObj.files.sort((a, b) => {
91
+ if (a.lineRate !== b.lineRate)
92
+ return a.lineRate - b.lineRate;
93
+ return a.filePath.localeCompare(b.filePath);
94
+ });
95
+ return this.coverageObj;
96
+ }
97
+ }
98
+ HandlerRegistry.register({
99
+ name: 'markdown',
100
+ description: 'Markdown summary for PR comments and CI job summaries',
101
+ fileExtension: '.md',
102
+ handler: () => new MarkdownCoverageHandler(),
103
+ compatibleWith: ['GitHub Actions', 'GitLab CI', 'Bitbucket', 'Azure DevOps'],
104
+ });
105
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/handlers/markdown.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAGb,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAIvD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,uBAAwB,SAAQ,WAAW;IACrC,WAAW,CAAyB;IAC7C,qBAAqB,GAAG,CAAC,CAAC;IAC1B,uBAAuB,GAAG,CAAC,CAAC;IACnB,UAAU,GAAG,IAAI,GAAG,EAA8B,CAAC;IAEpE;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,WAAW,GAAG;YACjB,OAAO,EAAE;gBACP,UAAU,EAAE,CAAC;gBACb,YAAY,EAAE,CAAC;gBACf,cAAc,EAAE,CAAC;gBACjB,QAAQ,EAAE,CAAC;gBACX,SAAS,EAAE,CAAC;aACb;YACD,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,EAAE;SACV,CAAC;IACJ,CAAC;IAEM,WAAW,CAAC,QAAgB,EAAE,SAAiB,EAAE,KAA6B;QACnF,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAE7F,MAAM,OAAO,GAAoB;YAC/B,QAAQ;YACR,UAAU;YACV,YAAY;YACZ,cAAc;YACd,QAAQ;SACT,CAAC;QAEF,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAErC,IAAI,CAAC,qBAAqB,IAAI,UAAU,CAAC;QACzC,IAAI,CAAC,uBAAuB,IAAI,YAAY,CAAC;QAE7C,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,UAAU,IAAI,UAAU,CAAC;YAClC,QAAQ,CAAC,YAAY,IAAI,YAAY,CAAC;YACtC,QAAQ,CAAC,SAAS,IAAI,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IAEM,QAAQ;QACb,MAAM,UAAU,GAAG,IAAI,CAAC,qBAAqB,CAAC;QAC9C,MAAM,YAAY,GAAG,IAAI,CAAC,uBAAuB,CAAC;QAClD,MAAM,cAAc,GAAG,UAAU,GAAG,YAAY,CAAC;QACjD,MAAM,QAAQ,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhE,IAAI,CAAC,WAAW,CAAC,OAAO,GAAG;YACzB,UAAU;YACV,YAAY;YACZ,cAAc;YACd,QAAQ;YACR,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM;SACzC,CAAC;QAEF,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;aAC9D,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,EAAsB,EAAE;YAC5C,MAAM,YAAY,GAAG,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC;YACvD,MAAM,WAAW,GAAG,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/E,OAAO;gBACL,SAAS;gBACT,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,YAAY,EAAE,GAAG,CAAC,YAAY;gBAC9B,cAAc,EAAE,YAAY;gBAC5B,QAAQ,EAAE,WAAW;aACtB,CAAC;QACJ,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QAE1D,gFAAgF;QAChF,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACnC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ;gBAAE,OAAO,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;YAC9D,OAAO,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,eAAe,CAAC,QAAQ,CAAC;IACvB,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,uDAAuD;IACpE,aAAa,EAAE,KAAK;IACpB,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,uBAAuB,EAAE;IAC5C,cAAc,EAAE,CAAC,gBAAgB,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,CAAC;CAC7E,CAAC,CAAC"}
@@ -29,9 +29,7 @@ export class SonarCoverageHandler extends BaseHandler {
29
29
  this.coverageObj.coverage.file.push(fileObj);
30
30
  }
31
31
  finalize() {
32
- if (this.coverageObj.coverage?.file) {
33
- this.coverageObj.coverage.file = this.sortByPath(this.coverageObj.coverage.file);
34
- }
32
+ this.coverageObj.coverage.file = this.sortByPath(this.coverageObj.coverage.file);
35
33
  return this.coverageObj;
36
34
  }
37
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sonar.js","sourceRoot":"","sources":["../../src/handlers/sonar.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAGb,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,OAAO,oBAAqB,SAAQ,WAAW;IAClC,WAAW,CAAsB;IAElD;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,WAAW,GAAG,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC;IACjE,CAAC;IAEM,WAAW,CAAC,QAAgB,EAAE,SAAiB,EAAE,KAA6B;QACnF,MAAM,OAAO,GAAe;YAC1B,OAAO,EAAE,QAAQ;YACjB,WAAW,EAAE,EAAE;SAChB,CAAC;QACF,KAAK,MAAM,CAAC,gBAAgB,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9D,MAAM,OAAO,GAAG,KAAK,KAAK,CAAC,CAAC;YAC5B,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;gBACvB,aAAa,EAAE,MAAM,CAAC,gBAAgB,CAAC;gBACvC,UAAU,EAAE,OAAO;aACpB,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAEM,QAAQ;QACb,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;YACpC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACnF,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,6BAA6B;AAC7B,eAAe,CAAC,QAAQ,CAAC;IACvB,IAAI,EAAE,OAAO;IACb,WAAW,EAAE,mCAAmC;IAChD,aAAa,EAAE,MAAM;IACrB,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,oBAAoB,EAAE;IACzC,cAAc,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC;CAC5C,CAAC,CAAC"}
1
+ {"version":3,"file":"sonar.js","sourceRoot":"","sources":["../../src/handlers/sonar.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAGb,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,OAAO,oBAAqB,SAAQ,WAAW;IAClC,WAAW,CAAsB;IAElD;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,WAAW,GAAG,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC;IACjE,CAAC;IAEM,WAAW,CAAC,QAAgB,EAAE,SAAiB,EAAE,KAA6B;QACnF,MAAM,OAAO,GAAe;YAC1B,OAAO,EAAE,QAAQ;YACjB,WAAW,EAAE,EAAE;SAChB,CAAC;QACF,KAAK,MAAM,CAAC,gBAAgB,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9D,MAAM,OAAO,GAAG,KAAK,KAAK,CAAC,CAAC;YAC5B,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;gBACvB,aAAa,EAAE,MAAM,CAAC,gBAAgB,CAAC;gBACvC,UAAU,EAAE,OAAO;aACpB,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAEM,QAAQ;QACb,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACjF,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,6BAA6B;AAC7B,eAAe,CAAC,QAAQ,CAAC;IACvB,IAAI,EAAE,OAAO;IACb,WAAW,EAAE,mCAAmC;IAChD,aAAa,EAAE,MAAM;IACrB,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,oBAAoB,EAAE;IACzC,cAAc,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC;CAC5C,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { GitHubActionsCoverageObject } from '../../utils/types.js';
2
+ export declare function generateGitHubActions(coverageObj: GitHubActionsCoverageObject): string;
@@ -0,0 +1,27 @@
1
+ function formatPercent(lineRate) {
2
+ return `${(lineRate * 100).toFixed(2)}%`;
3
+ }
4
+ /**
5
+ * Escape a string for use as a GitHub Actions workflow command property value.
6
+ *
7
+ * @see https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#example-setting-a-warning-message
8
+ */
9
+ function escapeProperty(value) {
10
+ return value
11
+ .replace(/%/g, '%25')
12
+ .replace(/\r/g, '%0D')
13
+ .replace(/\n/g, '%0A')
14
+ .replace(/:/g, '%3A')
15
+ .replace(/,/g, '%2C');
16
+ }
17
+ function escapeData(value) {
18
+ return value.replace(/%/g, '%25').replace(/\r/g, '%0D').replace(/\n/g, '%0A');
19
+ }
20
+ export function generateGitHubActions(coverageObj) {
21
+ const { summary, uncoveredLines } = coverageObj;
22
+ const overall = formatPercent(summary.lineRate);
23
+ const summaryLine = `::notice title=Apex Code Coverage::Overall coverage ${escapeData(overall)} (${summary.coveredLines}/${summary.totalLines} lines, ${summary.uncoveredLines} uncovered across ${summary.fileCount} file${summary.fileCount === 1 ? '' : 's'})`;
24
+ const annotations = uncoveredLines.map(({ filePath, lineNumber }) => `::warning file=${escapeProperty(filePath)},line=${lineNumber},title=Uncovered Apex line::Line ${lineNumber} is not covered by any Apex test`);
25
+ return [summaryLine, ...annotations].join('\n');
26
+ }
27
+ //# sourceMappingURL=generateGitHubActions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateGitHubActions.js","sourceRoot":"","sources":["../../../src/transformers/generators/generateGitHubActions.ts"],"names":[],"mappings":"AAEA,SAAS,aAAa,CAAC,QAAgB;IACrC,OAAO,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAC3C,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,WAAwC;IAC5E,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,WAAW,CAAC;IAChD,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEhD,MAAM,WAAW,GAAG,uDAAuD,UAAU,CACnF,OAAO,CACR,KAAK,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,UAAU,WAAW,OAAO,CAAC,cAAc,qBAC/E,OAAO,CAAC,SACV,QAAQ,OAAO,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IAE9C,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,CACpC,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,CAC3B,kBAAkB,cAAc,CAAC,QAAQ,CAAC,SAAS,UAAU,oCAAoC,UAAU,kCAAkC,CAChJ,CAAC;IAEF,OAAO,CAAC,WAAW,EAAE,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { HtmlCoverageObject } from '../../utils/types.js';
2
+ export declare function generateHtml(coverageObj: HtmlCoverageObject): string;
@@ -0,0 +1,399 @@
1
+ function getCoverageColor(lineRate) {
2
+ if (lineRate >= 0.8)
3
+ return '#4caf50';
4
+ if (lineRate >= 0.6)
5
+ return '#ff9800';
6
+ return '#f44336';
7
+ }
8
+ function formatPercent(lineRate) {
9
+ return (lineRate * 100).toFixed(2);
10
+ }
11
+ function escapeHtml(text) {
12
+ const map = {
13
+ '&': '&',
14
+ '<': '&lt;',
15
+ '>': '&gt;',
16
+ '"': '&quot;',
17
+ "'": '&#039;',
18
+ };
19
+ return text.replace(/[&<>"']/g, (m) => map[m]);
20
+ }
21
+ function buildPackageSummaryRows(packageSummaries) {
22
+ if (packageSummaries.length === 0)
23
+ return '';
24
+ return packageSummaries
25
+ .map((pkg) => {
26
+ const pkgPercent = formatPercent(pkg.lineRate);
27
+ const pkgColor = getCoverageColor(pkg.lineRate);
28
+ return `<tr>
29
+ <td class="package-dir">${escapeHtml(pkg.directory)}</td>
30
+ <td class="package-stat">${pkg.fileCount}</td>
31
+ <td class="package-stat">${pkg.totalLines}</td>
32
+ <td class="package-stat">${pkg.coveredLines}</td>
33
+ <td class="package-stat">${pkg.uncoveredLines}</td>
34
+ <td class="package-pct" style="color: ${pkgColor}">${pkgPercent}%</td>
35
+ <td><span class="coverage-bar" style="background-color: ${pkgColor}; width: ${pkgPercent}%"></span></td>
36
+ </tr>`;
37
+ })
38
+ .join('\n');
39
+ }
40
+ function groupFilesByDir(files) {
41
+ const filesByDir = new Map();
42
+ for (const file of files) {
43
+ const dir = file.filePath.split('/')[0];
44
+ const list = filesByDir.get(dir) ?? [];
45
+ list.push(file);
46
+ filesByDir.set(dir, list);
47
+ }
48
+ return filesByDir;
49
+ }
50
+ function buildLineRow(line) {
51
+ const lineClass = line.covered ? 'covered' : 'uncovered';
52
+ const lineColor = line.covered ? '#c8e6c9' : '#ffcdd2';
53
+ const codeContent = line.content !== undefined ? escapeHtml(line.content) : '';
54
+ return `<tr class="${lineClass}" style="background-color: ${lineColor}">
55
+ <td class="line-number">${line.lineNumber}</td>
56
+ <td class="hit-count">${line.hitCount}</td>
57
+ <td class="line-content">${codeContent}</td>
58
+ </tr>`;
59
+ }
60
+ function buildFileSection(file) {
61
+ const filePercent = formatPercent(file.lineRate);
62
+ const fileColor = getCoverageColor(file.lineRate);
63
+ const lineDetails = file.lines.map(buildLineRow).join('\n');
64
+ const fileId = file.filePath.replace(/[^a-zA-Z0-9]/g, '-');
65
+ const escapedPath = file.filePath.replace(/'/g, "\\'");
66
+ return `
67
+ <div class="file-section">
68
+ <h3 class="file-header" onclick="toggleFile('${escapedPath}')">
69
+ <span class="file-name">${escapeHtml(file.filePath)}</span>
70
+ <span class="file-stats">
71
+ ${file.coveredLines}/${file.totalLines} lines (${filePercent}%)
72
+ <span class="coverage-bar" style="background-color: ${fileColor}; width: ${filePercent}%"></span>
73
+ </span>
74
+ </h3>
75
+ <div id="file-${fileId}" class="file-details" style="display: none;">
76
+ <table class="line-coverage">
77
+ <thead>
78
+ <tr>
79
+ <th>Line</th>
80
+ <th>Hits</th>
81
+ <th>Code</th>
82
+ </tr>
83
+ </thead>
84
+ <tbody>
85
+ ${lineDetails}
86
+ </tbody>
87
+ </table>
88
+ </div>
89
+ </div>
90
+ `;
91
+ }
92
+ function buildFileRows(files) {
93
+ const filesByDir = groupFilesByDir(files);
94
+ const sortedDirs = [...filesByDir.keys()].sort((a, b) => a.localeCompare(b));
95
+ return sortedDirs
96
+ .map((dir) => {
97
+ const dirFiles = filesByDir.get(dir);
98
+ const dirFileSections = dirFiles.map(buildFileSection).join('\n');
99
+ return `
100
+ <div class="package-files-group">
101
+ <h3 class="package-dir-header">${escapeHtml(dir)}/</h3>
102
+ ${dirFileSections}
103
+ </div>
104
+ `;
105
+ })
106
+ .join('\n');
107
+ }
108
+ export function generateHtml(coverageObj) {
109
+ const { summary, packageSummaries, files } = coverageObj;
110
+ const coveragePercent = formatPercent(summary.lineRate);
111
+ const coverageColor = getCoverageColor(summary.lineRate);
112
+ const packageSummaryRows = buildPackageSummaryRows(packageSummaries);
113
+ const fileRows = buildFileRows(files);
114
+ return `<!DOCTYPE html>
115
+ <html lang="en">
116
+ <head>
117
+ <meta charset="UTF-8">
118
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
119
+ <title>Code Coverage Report</title>
120
+ <style>
121
+ * {
122
+ margin: 0;
123
+ padding: 0;
124
+ box-sizing: border-box;
125
+ }
126
+ body {
127
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
128
+ line-height: 1.6;
129
+ color: #333;
130
+ background-color: #f5f5f5;
131
+ padding: 20px;
132
+ }
133
+ .container {
134
+ max-width: 1200px;
135
+ margin: 0 auto;
136
+ background: white;
137
+ border-radius: 8px;
138
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
139
+ padding: 30px;
140
+ }
141
+ h1 {
142
+ color: #2c3e50;
143
+ margin-bottom: 30px;
144
+ border-bottom: 3px solid #3498db;
145
+ padding-bottom: 10px;
146
+ }
147
+ .summary {
148
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
149
+ color: white;
150
+ padding: 25px;
151
+ border-radius: 8px;
152
+ margin-bottom: 30px;
153
+ }
154
+ .summary h2 {
155
+ margin-bottom: 15px;
156
+ font-size: 1.5em;
157
+ }
158
+ .summary-stats {
159
+ display: grid;
160
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
161
+ gap: 20px;
162
+ margin-top: 15px;
163
+ }
164
+ .stat-item {
165
+ background: rgba(255, 255, 255, 0.2);
166
+ padding: 15px;
167
+ border-radius: 6px;
168
+ }
169
+ .stat-label {
170
+ font-size: 0.9em;
171
+ opacity: 0.9;
172
+ margin-bottom: 5px;
173
+ }
174
+ .stat-value {
175
+ font-size: 1.8em;
176
+ font-weight: bold;
177
+ }
178
+ .coverage-percent {
179
+ font-size: 3em;
180
+ font-weight: bold;
181
+ margin: 10px 0;
182
+ }
183
+ .package-files-group {
184
+ margin-bottom: 28px;
185
+ }
186
+ .package-dir-header {
187
+ font-size: 1.1em;
188
+ color: #2c3e50;
189
+ margin-bottom: 12px;
190
+ padding-bottom: 6px;
191
+ border-bottom: 2px solid #3498db;
192
+ font-weight: 600;
193
+ }
194
+ .file-section {
195
+ margin-bottom: 20px;
196
+ border: 1px solid #ddd;
197
+ border-radius: 6px;
198
+ overflow: hidden;
199
+ }
200
+ .file-header {
201
+ background: #f8f9fa;
202
+ padding: 15px;
203
+ cursor: pointer;
204
+ display: flex;
205
+ justify-content: space-between;
206
+ align-items: center;
207
+ transition: background-color 0.2s;
208
+ }
209
+ .file-header:hover {
210
+ background: #e9ecef;
211
+ }
212
+ .file-name {
213
+ font-weight: 600;
214
+ color: #2c3e50;
215
+ }
216
+ .file-stats {
217
+ display: flex;
218
+ align-items: center;
219
+ gap: 10px;
220
+ }
221
+ .coverage-bar {
222
+ height: 20px;
223
+ min-width: 100px;
224
+ border-radius: 4px;
225
+ display: inline-block;
226
+ }
227
+ .file-details {
228
+ padding: 0;
229
+ }
230
+ .line-coverage {
231
+ width: 100%;
232
+ border-collapse: collapse;
233
+ font-family: 'Courier New', monospace;
234
+ font-size: 0.9em;
235
+ }
236
+ .line-coverage thead {
237
+ background: #34495e;
238
+ color: white;
239
+ }
240
+ .line-coverage th {
241
+ padding: 10px;
242
+ text-align: left;
243
+ font-weight: 600;
244
+ }
245
+ .line-coverage td {
246
+ padding: 5px 10px;
247
+ border-bottom: 1px solid #eee;
248
+ }
249
+ .line-number {
250
+ text-align: right;
251
+ width: 80px;
252
+ color: #666;
253
+ font-weight: 600;
254
+ }
255
+ .hit-count {
256
+ text-align: right;
257
+ width: 80px;
258
+ color: #666;
259
+ }
260
+ .line-content {
261
+ width: auto;
262
+ white-space: pre;
263
+ }
264
+ .covered {
265
+ background-color: #c8e6c9 !important;
266
+ }
267
+ .uncovered {
268
+ background-color: #ffcdd2 !important;
269
+ }
270
+ .package-summary {
271
+ margin-bottom: 30px;
272
+ }
273
+ .package-summary h2 {
274
+ margin-bottom: 15px;
275
+ color: #2c3e50;
276
+ font-size: 1.25em;
277
+ }
278
+ .package-summary table {
279
+ width: 100%;
280
+ border-collapse: collapse;
281
+ border: 1px solid #ddd;
282
+ border-radius: 6px;
283
+ overflow: hidden;
284
+ }
285
+ .package-summary th {
286
+ background: #34495e;
287
+ color: white;
288
+ padding: 12px;
289
+ text-align: left;
290
+ font-weight: 600;
291
+ }
292
+ .package-summary td {
293
+ padding: 10px 12px;
294
+ border-bottom: 1px solid #eee;
295
+ }
296
+ .package-summary tr:last-child td {
297
+ border-bottom: none;
298
+ }
299
+ .package-summary tr:hover {
300
+ background: #f8f9fa;
301
+ }
302
+ .package-dir {
303
+ font-weight: 600;
304
+ color: #2c3e50;
305
+ }
306
+ .package-stat {
307
+ text-align: right;
308
+ }
309
+ .package-pct {
310
+ font-weight: 600;
311
+ text-align: right;
312
+ }
313
+ .package-summary .coverage-bar {
314
+ display: block;
315
+ min-width: 60px;
316
+ height: 14px;
317
+ border-radius: 4px;
318
+ }
319
+ @media (max-width: 768px) {
320
+ .file-header {
321
+ flex-direction: column;
322
+ align-items: flex-start;
323
+ gap: 10px;
324
+ }
325
+ .summary-stats {
326
+ grid-template-columns: 1fr;
327
+ }
328
+ }
329
+ </style>
330
+ </head>
331
+ <body>
332
+ <div class="container">
333
+ <h1>Code Coverage Report</h1>
334
+
335
+ <div class="summary">
336
+ <h2>Summary</h2>
337
+ <div class="coverage-percent" style="color: ${coverageColor}">${coveragePercent}%</div>
338
+ <div class="summary-stats">
339
+ <div class="stat-item">
340
+ <div class="stat-label">Total Lines</div>
341
+ <div class="stat-value">${summary.totalLines}</div>
342
+ </div>
343
+ <div class="stat-item">
344
+ <div class="stat-label">Covered Lines</div>
345
+ <div class="stat-value">${summary.coveredLines}</div>
346
+ </div>
347
+ <div class="stat-item">
348
+ <div class="stat-label">Uncovered Lines</div>
349
+ <div class="stat-value">${summary.uncoveredLines}</div>
350
+ </div>
351
+ <div class="stat-item">
352
+ <div class="stat-label">Files</div>
353
+ <div class="stat-value">${files.length}</div>
354
+ </div>
355
+ </div>
356
+ </div>
357
+
358
+ ${packageSummaryRows
359
+ ? `
360
+ <div class="package-summary">
361
+ <h2>Package directory coverage</h2>
362
+ <table>
363
+ <thead>
364
+ <tr>
365
+ <th>Directory</th>
366
+ <th>Files</th>
367
+ <th>Total lines</th>
368
+ <th>Covered</th>
369
+ <th>Uncovered</th>
370
+ <th>Coverage</th>
371
+ <th></th>
372
+ </tr>
373
+ </thead>
374
+ <tbody>
375
+ ${packageSummaryRows}
376
+ </tbody>
377
+ </table>
378
+ </div>
379
+ `
380
+ : ''}
381
+
382
+ <h2 style="margin: 30px 0 20px 0; color: #2c3e50;">File Coverage Details</h2>
383
+
384
+ ${fileRows}
385
+ </div>
386
+
387
+ <script>
388
+ function toggleFile(filePath) {
389
+ const id = 'file-' + filePath.replace(/[^a-zA-Z0-9]/g, '-');
390
+ const element = document.getElementById(id);
391
+ if (element) {
392
+ element.style.display = element.style.display === 'none' ? 'block' : 'none';
393
+ }
394
+ }
395
+ </script>
396
+ </body>
397
+ </html>`;
398
+ }
399
+ //# sourceMappingURL=generateHtml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateHtml.js","sourceRoot":"","sources":["../../../src/transformers/generators/generateHtml.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { MarkdownCoverageObject } from '../../utils/types.js';
2
+ export declare function generateMarkdown(coverageObj: MarkdownCoverageObject): string;
@@ -0,0 +1,39 @@
1
+ function formatPercent(lineRate) {
2
+ return `${(lineRate * 100).toFixed(2)}%`;
3
+ }
4
+ function escapePipes(value) {
5
+ return value.replace(/\|/g, '\\|');
6
+ }
7
+ function buildPackageTable(packages) {
8
+ if (packages.length === 0)
9
+ return '';
10
+ const header = [
11
+ '| Directory | Files | Lines | Covered | Uncovered | Coverage |',
12
+ '| --- | ---: | ---: | ---: | ---: | ---: |',
13
+ ].join('\n');
14
+ const rows = packages
15
+ .map((pkg) => `| ${escapePipes(pkg.directory)} | ${pkg.fileCount} | ${pkg.totalLines} | ${pkg.coveredLines} | ${pkg.uncoveredLines} | ${formatPercent(pkg.lineRate)} |`)
16
+ .join('\n');
17
+ return `## Package directory coverage\n\n${header}\n${rows}`;
18
+ }
19
+ function buildFileTable(files) {
20
+ if (files.length === 0)
21
+ return '';
22
+ const header = ['| File | Lines | Covered | Uncovered | Coverage |', '| --- | ---: | ---: | ---: | ---: |'].join('\n');
23
+ const rows = files
24
+ .map((file) => `| ${escapePipes(file.filePath)} | ${file.totalLines} | ${file.coveredLines} | ${file.uncoveredLines} | ${formatPercent(file.lineRate)} |`)
25
+ .join('\n');
26
+ return `## File coverage\n\nFiles are sorted with the lowest coverage first.\n\n${header}\n${rows}`;
27
+ }
28
+ export function generateMarkdown(coverageObj) {
29
+ const { summary, packages, files } = coverageObj;
30
+ const overall = formatPercent(summary.lineRate);
31
+ const summaryBlock = [
32
+ '# Apex Code Coverage Report',
33
+ '',
34
+ `**Overall coverage:** ${overall} (${summary.coveredLines} / ${summary.totalLines} lines across ${summary.fileCount} file${summary.fileCount === 1 ? '' : 's'})`,
35
+ ].join('\n');
36
+ const sections = [summaryBlock, buildPackageTable(packages), buildFileTable(files)].filter(Boolean);
37
+ return sections.join('\n\n');
38
+ }
39
+ //# sourceMappingURL=generateMarkdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateMarkdown.js","sourceRoot":"","sources":["../../../src/transformers/generators/generateMarkdown.ts"],"names":[],"mappings":"AAEA,SAAS,aAAa,CAAC,QAAgB;IACrC,OAAO,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAC3C,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,iBAAiB,CAAC,QAA4C;IACrE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG;QACb,gEAAgE;QAChE,4CAA4C;KAC7C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,MAAM,IAAI,GAAG,QAAQ;SAClB,GAAG,CACF,CAAC,GAAG,EAAE,EAAE,CACN,KAAK,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,SAAS,MAAM,GAAG,CAAC,UAAU,MAAM,GAAG,CAAC,YAAY,MAC1F,GAAG,CAAC,cACN,MAAM,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CACxC;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,OAAO,oCAAoC,MAAM,KAAK,IAAI,EAAE,CAAC;AAC/D,CAAC;AAED,SAAS,cAAc,CAAC,KAAsC;IAC5D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,CAAC,mDAAmD,EAAE,qCAAqC,CAAC,CAAC,IAAI,CAC9G,IAAI,CACL,CAAC;IACF,MAAM,IAAI,GAAG,KAAK;SACf,GAAG,CACF,CAAC,IAAI,EAAE,EAAE,CACP,KAAK,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC,YAAY,MACzE,IAAI,CAAC,cACP,MAAM,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CACzC;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,OAAO,2EAA2E,MAAM,KAAK,IAAI,EAAE,CAAC;AACtG,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,WAAmC;IAClE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC;IACjD,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,YAAY,GAAG;QACnB,6BAA6B;QAC7B,EAAE;QACF,yBAAyB,OAAO,KAAK,OAAO,CAAC,YAAY,MAAM,OAAO,CAAC,UAAU,iBAAiB,OAAO,CAAC,SAAS,QACjH,OAAO,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GACjC,GAAG;KACJ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,QAAQ,GAAG,CAAC,YAAY,EAAE,iBAAiB,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACpG,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC"}
@@ -1,3 +1,3 @@
1
- import { SonarCoverageObject, CoberturaCoverageObject, CloverCoverageObject, LcovCoverageObject, JaCoCoCoverageObject, IstanbulCoverageObject, JsonSummaryCoverageObject, SimpleCovCoverageObject, OpenCoverCoverageObject, HtmlCoverageObject } from '../utils/types.js';
2
- export declare function generateAndWriteReport(outputPath: string, coverageObj: SonarCoverageObject | CoberturaCoverageObject | CloverCoverageObject | LcovCoverageObject | JaCoCoCoverageObject | IstanbulCoverageObject | JsonSummaryCoverageObject | SimpleCovCoverageObject | OpenCoverCoverageObject | HtmlCoverageObject, format: string, formatAmount: number): Promise<string>;
1
+ import { AnyCoverageObject } from '../utils/types.js';
2
+ export declare function generateAndWriteReport(outputPath: string, coverageObj: AnyCoverageObject, format: string, formatAmount: number): Promise<string>;
3
3
  export declare function getExtensionForFormat(format: string): string;