apex-code-coverage-transformer 2.13.4 → 2.14.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 (47) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +276 -9
  3. package/lib/handlers/BaseHandler.d.ts +51 -0
  4. package/lib/handlers/BaseHandler.js +63 -0
  5. package/lib/handlers/BaseHandler.js.map +1 -0
  6. package/lib/handlers/HandlerRegistry.d.ts +90 -0
  7. package/lib/handlers/HandlerRegistry.js +103 -0
  8. package/lib/handlers/HandlerRegistry.js.map +1 -0
  9. package/lib/handlers/clover.d.ts +16 -2
  10. package/lib/handlers/clover.js +35 -16
  11. package/lib/handlers/clover.js.map +1 -1
  12. package/lib/handlers/cobertura.d.ts +11 -2
  13. package/lib/handlers/cobertura.js +23 -11
  14. package/lib/handlers/cobertura.js.map +1 -1
  15. package/lib/handlers/getHandler.d.ts +24 -0
  16. package/lib/handlers/getHandler.js +27 -19
  17. package/lib/handlers/getHandler.js.map +1 -1
  18. package/lib/handlers/istanbulJson.d.ts +18 -2
  19. package/lib/handlers/istanbulJson.js +28 -1
  20. package/lib/handlers/istanbulJson.js.map +1 -1
  21. package/lib/handlers/jacoco.d.ts +18 -2
  22. package/lib/handlers/jacoco.js +27 -1
  23. package/lib/handlers/jacoco.js.map +1 -1
  24. package/lib/handlers/jsonSummary.d.ts +49 -0
  25. package/lib/handlers/jsonSummary.js +103 -0
  26. package/lib/handlers/jsonSummary.js.map +1 -0
  27. package/lib/handlers/lcov.d.ts +17 -2
  28. package/lib/handlers/lcov.js +29 -9
  29. package/lib/handlers/lcov.js.map +1 -1
  30. package/lib/handlers/opencover.d.ts +71 -0
  31. package/lib/handlers/opencover.js +165 -0
  32. package/lib/handlers/opencover.js.map +1 -0
  33. package/lib/handlers/simplecov.d.ts +50 -0
  34. package/lib/handlers/simplecov.js +83 -0
  35. package/lib/handlers/simplecov.js.map +1 -0
  36. package/lib/handlers/sonar.d.ts +10 -2
  37. package/lib/handlers/sonar.js +20 -2
  38. package/lib/handlers/sonar.js.map +1 -1
  39. package/lib/transformers/reportGenerator.d.ts +2 -2
  40. package/lib/transformers/reportGenerator.js +7 -8
  41. package/lib/transformers/reportGenerator.js.map +1 -1
  42. package/lib/utils/constants.d.ts +5 -0
  43. package/lib/utils/constants.js +8 -1
  44. package/lib/utils/constants.js.map +1 -1
  45. package/lib/utils/types.d.ts +78 -1
  46. package/oclif.manifest.json +8 -5
  47. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@
5
5
 
6
6
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
7
7
 
8
+ ## [2.14.0](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v2.13.4...v2.14.0) (2025-10-27)
9
+
10
+
11
+ ### Features
12
+
13
+ * add json-summary, simplecov, and opencover coverage formats ([#231](https://github.com/mcarvin8/apex-code-coverage-transformer/issues/231)) ([9da086f](https://github.com/mcarvin8/apex-code-coverage-transformer/commit/9da086f212cbdd98184f8c873792b8da882815db))
14
+
8
15
  ## [2.13.4](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v2.13.3...v2.13.4) (2025-10-27)
9
16
 
10
17
 
package/README.md CHANGED
@@ -12,6 +12,7 @@
12
12
  <summary>Table of Contents</summary>
13
13
 
14
14
  - [Install](#install)
15
+ - [Quick Start](#quick-start)
15
16
  - [Usage](#usage)
16
17
  - [Salesforce CLI](#salesforce-cli)
17
18
  - [SFDX Hardis](#sfdx-hardis)
@@ -19,6 +20,11 @@
19
20
  - [Command](#command)
20
21
  - [`sf acc-transformer transform`](#sf-acc-transformer-transform)
21
22
  - [Coverage Report Formats](#coverage-report-formats)
23
+ - [CI/CD Integration Examples](#cicd-integration-examples)
24
+ - [Codecov](#codecov)
25
+ - [SonarQube](#sonarqube)
26
+ - [GitHub Actions](#github-actions)
27
+ - [GitLab CI](#gitlab-ci)
22
28
  - [Hook](#hook)
23
29
  - [Troubleshooting](#troubleshooting)
24
30
  - [Issues](#issues)
@@ -26,7 +32,7 @@
26
32
  - [License](#license)
27
33
  </details>
28
34
 
29
- Transform the Salesforce Apex code coverage JSON files created during deployments and test runs into other [formats](#coverage-report-formats) accepted by SonarQube, GitHub, GitLab, Azure, Bitbucket, etc.
35
+ Transform the Salesforce Apex code coverage JSON files created during deployments and test runs into other [formats](#coverage-report-formats) accepted by SonarQube, Codecov, GitHub, GitLab, Azure, Bitbucket, etc.
30
36
 
31
37
  > If there's a coverage format not yet supported by this plugin, feel free to provide a pull request or issue for the coverage format.
32
38
 
@@ -36,6 +42,51 @@ Transform the Salesforce Apex code coverage JSON files created during deployment
36
42
  sf plugins install apex-code-coverage-transformer@x.y.z
37
43
  ```
38
44
 
45
+ ## Quick Start
46
+
47
+ 1. **Generate Salesforce code coverage in JSON format**:
48
+
49
+ **Option A - Run Apex tests directly**:
50
+
51
+ ```bash
52
+ sf apex run test --code-coverage --output-dir "coverage"
53
+ ```
54
+
55
+ **Option B - Deploy/validate with coverage**:
56
+
57
+ ```bash
58
+ sf project deploy start --coverage-formatters json --results-dir "coverage"
59
+ # or for validation
60
+ sf project deploy validate --coverage-formatters json --results-dir "coverage"
61
+ ```
62
+
63
+ 2. **Transform the coverage to your desired format**:
64
+
65
+ **For test command** (creates `coverage/test-result-codecoverage.json`):
66
+
67
+ ```bash
68
+ # For SonarQube
69
+ sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "sonar"
70
+
71
+ # For Codecov
72
+ sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "cobertura"
73
+
74
+ # For multiple formats at once
75
+ sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -f "sonar" -f "cobertura" -f "jacoco"
76
+ ```
77
+
78
+ **For deploy command** (creates `coverage/coverage/coverage.json`):
79
+
80
+ ```bash
81
+ # For SonarQube
82
+ sf acc-transformer transform -j "coverage/coverage/coverage.json" -r "coverage.xml" -f "sonar"
83
+
84
+ # For Codecov
85
+ sf acc-transformer transform -j "coverage/coverage/coverage.json" -r "coverage.xml" -f "cobertura"
86
+ ```
87
+
88
+ 3. **Upload to your coverage tool** (see [CI/CD Integration Examples](#cicd-integration-examples) for platform-specific instructions).
89
+
39
90
  ## Usage
40
91
 
41
92
  This plugin is designed for users deploying Apex or running Apex tests within Salesforce DX projects (`sfdx-project.json`). It transforms Salesforce CLI JSON coverage reports into formats recognized by external tools.
@@ -126,6 +177,18 @@ EXAMPLES
126
177
 
127
178
  $ sf acc-transformer transform -j "coverage.json" -r "coverage.info" -f "lcovonly"
128
179
 
180
+ Transform the JSON into JSON Summary format:
181
+
182
+ $ sf acc-transformer transform -j "coverage.json" -r "coverage.json" -f "json-summary"
183
+
184
+ Transform the JSON into SimpleCov format:
185
+
186
+ $ sf acc-transformer transform -j "coverage.json" -r "coverage.json" -f "simplecov"
187
+
188
+ Transform the JSON into OpenCover format:
189
+
190
+ $ sf acc-transformer transform -j "coverage.json" -r "coverage.xml" -f "opencover"
191
+
129
192
  Transform the JSON into Sonar format, ignoring Apex in the "force-app" directory:
130
193
 
131
194
  $ sf acc-transformer transform -j "coverage.json" -i "force-app"
@@ -137,14 +200,218 @@ The `-f`/`--format` flag allows you to specify the format of the transformed cov
137
200
 
138
201
  You can provide multiple `--format` flags in a single command to create multiple reports. If multiple `--format` flags are provided, each output report will have the format appended to the name. For example, if `--output-report` is set `coverage.xml` and you supply `--format sonar --format cobertura` to the command, the output reports will be `coverage-sonar.xml` and `coverage-cobertura.xml`.
139
202
 
140
- | Flag Option | Description |
141
- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
142
- | [sonar](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/sonar_baseline.xml) | Generates a SonarQube-compatible coverage report. This is the default option. |
143
- | [clover](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/clover_baseline.xml) | Produces a Clover XML report format, commonly used with Atlassian tools. |
144
- | [lcovonly](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/lcov_baseline.info) | Outputs coverage data in LCOV format, useful for integrating with LCOV-based tools. |
145
- | [cobertura](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/cobertura_baseline.xml) | Creates a Cobertura XML report, a widely used format for coverage reporting. |
146
- | [jacoco](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/jacoco_baseline.xml) | Creates a JaCoCo XML report, the standard for Java projects. |
147
- | [json](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/json_baseline.json) | Generates a Istanbul JSON report compatible with Node.js tooling and coverage visualizers. |
203
+ | Format | Description | Compatible Platforms/Tools |
204
+ | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------- |
205
+ | [sonar](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/sonar_baseline.xml) | Generates a SonarQube-compatible coverage report. This is the default option. | SonarQube, SonarCloud |
206
+ | [cobertura](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/cobertura_baseline.xml) | Creates a Cobertura XML report, a widely used format for coverage reporting. | **Codecov**, Azure DevOps, Jenkins, GitLab, GitHub Actions |
207
+ | [jacoco](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/jacoco_baseline.xml) | Creates a JaCoCo XML report, the standard for Java projects. | **Codecov**, Jenkins, Maven, Gradle |
208
+ | [lcovonly](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/lcov_baseline.info) | Outputs coverage data in LCOV format, useful for integrating with LCOV-based tools. | Codecov, Coveralls, GitHub Actions |
209
+ | [clover](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/clover_baseline.xml) | Produces a Clover XML report format, commonly used with Atlassian tools. | Bamboo, Bitbucket, Jenkins |
210
+ | [json](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/json_baseline.json) | Generates a Istanbul JSON report compatible with Node.js tooling and coverage visualizers. | Istanbul/NYC, Codecov, custom tools |
211
+ | [json-summary](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/json-summary_baseline.json) | Generates a concise JSON summary ideal for badges, PR comments, and quick analysis. | GitHub Actions, GitLab CI, Custom Dashboards |
212
+ | [simplecov](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/simplecov_baseline.json) | Generates SimpleCov JSON format compatible with Ruby coverage tools. | Codecov, SimpleCov, Ruby Tools |
213
+ | [opencover](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/baselines/opencover_baseline.xml) | Generates OpenCover XML format for .NET and Azure DevOps integration. | Azure DevOps, Visual Studio, Codecov, JetBrains Tools |
214
+
215
+ ## CI/CD Integration Examples
216
+
217
+ ### Codecov
218
+
219
+ Codecov accepts multiple formats including Cobertura, JaCoCo, and LCOV. Cobertura is recommended for its wide compatibility.
220
+
221
+ **Using Codecov CLI**:
222
+
223
+ ```bash
224
+ # Generate Salesforce coverage
225
+ sf apex run test --code-coverage --output-dir "coverage"
226
+
227
+ # Transform to Cobertura format
228
+ sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "cobertura"
229
+
230
+ # Upload to Codecov
231
+ codecovcli upload-process --file coverage.xml
232
+ ```
233
+
234
+ **Using Codecov GitHub Action**:
235
+
236
+ ```yaml
237
+ name: Salesforce CI with Codecov
238
+
239
+ on: [push, pull_request]
240
+
241
+ jobs:
242
+ test:
243
+ runs-on: ubuntu-latest
244
+ steps:
245
+ - uses: actions/checkout@v4
246
+
247
+ - name: Install Salesforce CLI
248
+ run: npm install -g @salesforce/cli
249
+
250
+ - name: Install Coverage Transformer Plugin
251
+ run: sf plugins install apex-code-coverage-transformer
252
+
253
+ - name: Authenticate to Salesforce
254
+ run: sf org login sfdx-url --sfdx-url-file ${{ secrets.SFDX_AUTH_URL }} --alias ci-org
255
+
256
+ - name: Run Apex Tests
257
+ run: sf apex run test --code-coverage --output-dir coverage --target-org ci-org
258
+
259
+ - name: Transform Coverage to Cobertura
260
+ run: sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "cobertura"
261
+
262
+ - name: Upload to Codecov
263
+ uses: codecov/codecov-action@v4
264
+ with:
265
+ files: ./coverage.xml
266
+ flags: apex
267
+ token: ${{ secrets.CODECOV_TOKEN }}
268
+ ```
269
+
270
+ ### SonarQube
271
+
272
+ SonarQube requires its own Generic Coverage format (Sonar format).
273
+
274
+ **SonarQube Scanner Example**:
275
+
276
+ ```bash
277
+ # Generate and transform coverage
278
+ sf apex run test --code-coverage --output-dir "coverage"
279
+ sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "sonar"
280
+
281
+ # Run SonarQube scanner
282
+ sonar-scanner \
283
+ -Dsonar.projectKey=your-project-key \
284
+ -Dsonar.sources=force-app \
285
+ -Dsonar.tests=force-app \
286
+ -Dsonar.test.inclusions=**/*Test.cls \
287
+ -Dsonar.apex.coverage.reportPath=coverage.xml \
288
+ -Dsonar.host.url=https://sonarqube.example.com \
289
+ -Dsonar.login=$SONAR_TOKEN
290
+ ```
291
+
292
+ **SonarCloud GitHub Action**:
293
+
294
+ ```yaml
295
+ name: SonarCloud Analysis
296
+
297
+ on: [push, pull_request]
298
+
299
+ jobs:
300
+ sonarcloud:
301
+ runs-on: ubuntu-latest
302
+ steps:
303
+ - uses: actions/checkout@v4
304
+ with:
305
+ fetch-depth: 0
306
+
307
+ - name: Install Salesforce CLI
308
+ run: npm install -g @salesforce/cli
309
+
310
+ - name: Install Coverage Transformer Plugin
311
+ run: sf plugins install apex-code-coverage-transformer
312
+
313
+ - name: Authenticate to Salesforce
314
+ run: sf org login sfdx-url --sfdx-url-file ${{ secrets.SFDX_AUTH_URL }} --alias ci-org
315
+
316
+ - name: Run Apex Tests
317
+ run: sf apex run test --code-coverage --output-dir coverage --target-org ci-org
318
+
319
+ - name: Transform Coverage to Sonar Format
320
+ run: sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "sonar"
321
+
322
+ - name: SonarCloud Scan
323
+ uses: SonarSource/sonarcloud-github-action@master
324
+ env:
325
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
326
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
327
+ with:
328
+ args: >
329
+ -Dsonar.projectKey=your-project-key
330
+ -Dsonar.organization=your-org
331
+ -Dsonar.sources=force-app
332
+ -Dsonar.tests=force-app
333
+ -Dsonar.test.inclusions=**/*Test.cls
334
+ -Dsonar.apex.coverage.reportPath=coverage.xml
335
+ ```
336
+
337
+ ### GitHub Actions
338
+
339
+ GitHub Actions can display coverage using various formats. Use Cobertura or LCOV for best compatibility.
340
+
341
+ **With Coverage Report Action**:
342
+
343
+ ```yaml
344
+ name: Salesforce CI with Coverage Report
345
+
346
+ on: [push, pull_request]
347
+
348
+ jobs:
349
+ test:
350
+ runs-on: ubuntu-latest
351
+ steps:
352
+ - uses: actions/checkout@v4
353
+
354
+ - name: Install Salesforce CLI
355
+ run: npm install -g @salesforce/cli
356
+
357
+ - name: Install Coverage Transformer Plugin
358
+ run: sf plugins install apex-code-coverage-transformer
359
+
360
+ - name: Authenticate to Salesforce
361
+ run: sf org login sfdx-url --sfdx-url-file ${{ secrets.SFDX_AUTH_URL }} --alias ci-org
362
+
363
+ - name: Run Apex Tests
364
+ run: sf apex run test --code-coverage --output-dir coverage --target-org ci-org
365
+
366
+ - name: Transform Coverage to Cobertura
367
+ run: sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "cobertura"
368
+
369
+ - name: Code Coverage Report
370
+ uses: irongut/CodeCoverageSummary@v1.3.0
371
+ with:
372
+ filename: coverage.xml
373
+ badge: true
374
+ format: markdown
375
+ output: both
376
+
377
+ - name: Add Coverage PR Comment
378
+ uses: marocchino/sticky-pull-request-comment@v2
379
+ if: github.event_name == 'pull_request'
380
+ with:
381
+ recreate: true
382
+ path: code-coverage-results.md
383
+ ```
384
+
385
+ ### GitLab CI
386
+
387
+ GitLab supports Cobertura format natively for coverage visualization.
388
+
389
+ **`.gitlab-ci.yml` Example**:
390
+
391
+ ```yaml
392
+ stages:
393
+ - test
394
+
395
+ apex-tests:
396
+ stage: test
397
+ image: node:20
398
+ before_script:
399
+ - npm install -g @salesforce/cli
400
+ - sf plugins install apex-code-coverage-transformer
401
+ - echo $SFDX_AUTH_URL | sf org login sfdx-url --sfdx-url-stdin --alias ci-org
402
+ script:
403
+ - sf apex run test --code-coverage --output-dir coverage --target-org ci-org
404
+ - sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "cobertura"
405
+ coverage: '/TOTAL.*\s+(\d+%)$/'
406
+ artifacts:
407
+ reports:
408
+ coverage_report:
409
+ coverage_format: cobertura
410
+ path: coverage.xml
411
+ paths:
412
+ - coverage/
413
+ expire_in: 30 days
414
+ ```
148
415
 
149
416
  ## Hook
150
417
 
@@ -0,0 +1,51 @@
1
+ import { CoverageHandler, SonarCoverageObject, CoberturaCoverageObject, CloverCoverageObject, LcovCoverageObject, JaCoCoCoverageObject, IstanbulCoverageObject, JsonSummaryCoverageObject, SimpleCovCoverageObject, OpenCoverCoverageObject } from '../utils/types.js';
2
+ /**
3
+ * Abstract base class for coverage handlers providing common utilities.
4
+ * Reduces code duplication across different format handlers.
5
+ */
6
+ export declare abstract class BaseHandler implements CoverageHandler {
7
+ /**
8
+ * Calculate line coverage metrics from a lines record.
9
+ *
10
+ * @param lines - Record of line numbers to hit counts
11
+ * @returns Coverage metrics including totals and rates
12
+ */
13
+ protected calculateCoverage(lines: Record<string, number>): {
14
+ totalLines: number;
15
+ coveredLines: number;
16
+ uncoveredLines: number;
17
+ lineRate: number;
18
+ };
19
+ /**
20
+ * Extract line numbers by coverage status.
21
+ *
22
+ * @param lines - Record of line numbers to hit counts
23
+ * @param covered - True to get covered lines, false for uncovered
24
+ * @returns Sorted array of line numbers
25
+ */
26
+ protected extractLinesByStatus(lines: Record<string, number>, covered: boolean): number[];
27
+ /**
28
+ * Get covered and uncovered line numbers from a lines record.
29
+ *
30
+ * @param lines - Record of line numbers to hit counts
31
+ * @returns Object with covered and uncovered line arrays
32
+ */
33
+ protected getCoveredAndUncovered(lines: Record<string, number>): {
34
+ covered: number[];
35
+ uncovered: number[];
36
+ };
37
+ /**
38
+ * Sort array of objects by their path property.
39
+ * Handles various path property names (@path, @filename, @name).
40
+ *
41
+ * @param items - Array of objects to sort
42
+ * @returns Sorted array
43
+ */
44
+ protected sortByPath<T extends {
45
+ '@path'?: string;
46
+ '@filename'?: string;
47
+ '@name'?: string;
48
+ }>(items: T[]): T[];
49
+ abstract processFile(filePath: string, fileName: string, lines: Record<string, number>): void;
50
+ abstract finalize(): SonarCoverageObject | CoberturaCoverageObject | CloverCoverageObject | LcovCoverageObject | JaCoCoCoverageObject | IstanbulCoverageObject | JsonSummaryCoverageObject | SimpleCovCoverageObject | OpenCoverCoverageObject;
51
+ }
@@ -0,0 +1,63 @@
1
+ 'use strict';
2
+ /**
3
+ * Abstract base class for coverage handlers providing common utilities.
4
+ * Reduces code duplication across different format handlers.
5
+ */
6
+ export class BaseHandler {
7
+ /**
8
+ * Calculate line coverage metrics from a lines record.
9
+ *
10
+ * @param lines - Record of line numbers to hit counts
11
+ * @returns Coverage metrics including totals and rates
12
+ */
13
+ // eslint-disable-next-line class-methods-use-this
14
+ calculateCoverage(lines) {
15
+ const uncoveredLines = Object.values(lines).filter((hits) => hits === 0).length;
16
+ const coveredLines = Object.values(lines).filter((hits) => hits > 0).length;
17
+ const totalLines = uncoveredLines + coveredLines;
18
+ const lineRate = totalLines > 0 ? coveredLines / totalLines : 0;
19
+ return { totalLines, coveredLines, uncoveredLines, lineRate };
20
+ }
21
+ /**
22
+ * Extract line numbers by coverage status.
23
+ *
24
+ * @param lines - Record of line numbers to hit counts
25
+ * @param covered - True to get covered lines, false for uncovered
26
+ * @returns Sorted array of line numbers
27
+ */
28
+ // eslint-disable-next-line class-methods-use-this
29
+ extractLinesByStatus(lines, covered) {
30
+ return Object.entries(lines)
31
+ .filter(([, hits]) => (covered ? hits > 0 : hits === 0))
32
+ .map(([line]) => Number(line))
33
+ .sort((a, b) => a - b);
34
+ }
35
+ /**
36
+ * Get covered and uncovered line numbers from a lines record.
37
+ *
38
+ * @param lines - Record of line numbers to hit counts
39
+ * @returns Object with covered and uncovered line arrays
40
+ */
41
+ getCoveredAndUncovered(lines) {
42
+ return {
43
+ covered: this.extractLinesByStatus(lines, true),
44
+ uncovered: this.extractLinesByStatus(lines, false),
45
+ };
46
+ }
47
+ /**
48
+ * Sort array of objects by their path property.
49
+ * Handles various path property names (@path, @filename, @name).
50
+ *
51
+ * @param items - Array of objects to sort
52
+ * @returns Sorted array
53
+ */
54
+ // eslint-disable-next-line class-methods-use-this
55
+ sortByPath(items) {
56
+ return items.sort((a, b) => {
57
+ const pathA = a['@path'] ?? a['@filename'] ?? a['@name'] ?? '';
58
+ const pathB = b['@path'] ?? b['@filename'] ?? b['@name'] ?? '';
59
+ return pathA.localeCompare(pathB);
60
+ });
61
+ }
62
+ }
63
+ //# sourceMappingURL=BaseHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseHandler.js","sourceRoot":"","sources":["../../src/handlers/BaseHandler.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAeb;;;GAGG;AACH,MAAM,OAAgB,WAAW;IAC/B;;;;;OAKG;IACH,kDAAkD;IACxC,iBAAiB,CAAC,KAA6B;QAMvD,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QAChF,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;QAC5E,MAAM,UAAU,GAAG,cAAc,GAAG,YAAY,CAAC;QACjD,MAAM,QAAQ,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC;IAChE,CAAC;IAED;;;;;;OAMG;IACH,kDAAkD;IACxC,oBAAoB,CAAC,KAA6B,EAAE,OAAgB;QAC5E,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;aACzB,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;aACvD,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;aAC7B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,CAAC;IAED;;;;;OAKG;IACO,sBAAsB,CAAC,KAA6B;QAI5D,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC;YAC/C,SAAS,EAAE,IAAI,CAAC,oBAAoB,CAAC,KAAK,EAAE,KAAK,CAAC;SACnD,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,kDAAkD;IACxC,UAAU,CAAyE,KAAU;QACrG,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACzB,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAC/D,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAC/D,OAAO,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC;CAcF"}
@@ -0,0 +1,90 @@
1
+ import { CoverageHandler } from '../utils/types.js';
2
+ /**
3
+ * Registration information for a coverage format handler.
4
+ */
5
+ export type HandlerRegistration = {
6
+ /** Format identifier (e.g., 'sonar', 'cobertura') */
7
+ name: string;
8
+ /** Human-readable description of the format */
9
+ description: string;
10
+ /** File extension for this format (e.g., '.xml', '.json', '.info') */
11
+ fileExtension: string;
12
+ /** Factory function to create a new handler instance */
13
+ handler: () => CoverageHandler;
14
+ /** List of platforms/tools compatible with this format */
15
+ compatibleWith?: string[];
16
+ };
17
+ /**
18
+ * Registry for coverage format handlers.
19
+ * Provides a centralized system for registering and retrieving format handlers.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // Register a handler
24
+ * HandlerRegistry.register({
25
+ * name: 'myformat',
26
+ * description: 'My custom format',
27
+ * fileExtension: '.xml',
28
+ * handler: () => new MyFormatHandler(),
29
+ * });
30
+ *
31
+ * // Retrieve a handler
32
+ * const handler = HandlerRegistry.get('myformat');
33
+ * ```
34
+ */
35
+ export declare class HandlerRegistry {
36
+ private static handlers;
37
+ /**
38
+ * Register a new format handler.
39
+ *
40
+ * @param registration - Handler registration information
41
+ * @throws Error if a handler with the same name is already registered
42
+ */
43
+ static register(registration: HandlerRegistration): void;
44
+ /**
45
+ * Get a handler instance for the specified format.
46
+ *
47
+ * @param format - Format identifier
48
+ * @returns New handler instance
49
+ * @throws Error if format is not supported
50
+ */
51
+ static get(format: string): CoverageHandler;
52
+ /**
53
+ * Get list of all registered format names.
54
+ *
55
+ * @returns Array of format identifiers
56
+ */
57
+ static getAvailableFormats(): string[];
58
+ /**
59
+ * Get file extension for a format.
60
+ *
61
+ * @param format - Format identifier
62
+ * @returns File extension including the dot (e.g., '.xml')
63
+ */
64
+ static getExtension(format: string): string;
65
+ /**
66
+ * Get description for a format.
67
+ *
68
+ * @param format - Format identifier
69
+ * @returns Human-readable description
70
+ */
71
+ static getDescription(format: string): string;
72
+ /**
73
+ * Get compatible platforms for a format.
74
+ *
75
+ * @param format - Format identifier
76
+ * @returns Array of compatible platform names
77
+ */
78
+ static getCompatiblePlatforms(format: string): string[];
79
+ /**
80
+ * Check if a format is registered.
81
+ *
82
+ * @param format - Format identifier
83
+ * @returns True if format is registered
84
+ */
85
+ static has(format: string): boolean;
86
+ /**
87
+ * Clear all registered handlers (primarily for testing).
88
+ */
89
+ static clear(): void;
90
+ }
@@ -0,0 +1,103 @@
1
+ 'use strict';
2
+ /**
3
+ * Registry for coverage format handlers.
4
+ * Provides a centralized system for registering and retrieving format handlers.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * // Register a handler
9
+ * HandlerRegistry.register({
10
+ * name: 'myformat',
11
+ * description: 'My custom format',
12
+ * fileExtension: '.xml',
13
+ * handler: () => new MyFormatHandler(),
14
+ * });
15
+ *
16
+ * // Retrieve a handler
17
+ * const handler = HandlerRegistry.get('myformat');
18
+ * ```
19
+ */
20
+ export class HandlerRegistry {
21
+ static handlers = new Map();
22
+ /**
23
+ * Register a new format handler.
24
+ *
25
+ * @param registration - Handler registration information
26
+ * @throws Error if a handler with the same name is already registered
27
+ */
28
+ static register(registration) {
29
+ if (this.handlers.has(registration.name)) {
30
+ throw new Error(`Handler for format '${registration.name}' is already registered`);
31
+ }
32
+ this.handlers.set(registration.name, registration);
33
+ }
34
+ /**
35
+ * Get a handler instance for the specified format.
36
+ *
37
+ * @param format - Format identifier
38
+ * @returns New handler instance
39
+ * @throws Error if format is not supported
40
+ */
41
+ static get(format) {
42
+ const registration = this.handlers.get(format);
43
+ if (!registration) {
44
+ const available = this.getAvailableFormats().join(', ');
45
+ throw new Error(`Unsupported format: ${format}. Available formats: ${available}`);
46
+ }
47
+ return registration.handler();
48
+ }
49
+ /**
50
+ * Get list of all registered format names.
51
+ *
52
+ * @returns Array of format identifiers
53
+ */
54
+ static getAvailableFormats() {
55
+ return Array.from(this.handlers.keys()).sort();
56
+ }
57
+ /**
58
+ * Get file extension for a format.
59
+ *
60
+ * @param format - Format identifier
61
+ * @returns File extension including the dot (e.g., '.xml')
62
+ */
63
+ static getExtension(format) {
64
+ const registration = this.handlers.get(format);
65
+ return registration?.fileExtension ?? '.xml';
66
+ }
67
+ /**
68
+ * Get description for a format.
69
+ *
70
+ * @param format - Format identifier
71
+ * @returns Human-readable description
72
+ */
73
+ static getDescription(format) {
74
+ const registration = this.handlers.get(format);
75
+ return registration?.description ?? '';
76
+ }
77
+ /**
78
+ * Get compatible platforms for a format.
79
+ *
80
+ * @param format - Format identifier
81
+ * @returns Array of compatible platform names
82
+ */
83
+ static getCompatiblePlatforms(format) {
84
+ const registration = this.handlers.get(format);
85
+ return registration?.compatibleWith ?? [];
86
+ }
87
+ /**
88
+ * Check if a format is registered.
89
+ *
90
+ * @param format - Format identifier
91
+ * @returns True if format is registered
92
+ */
93
+ static has(format) {
94
+ return this.handlers.has(format);
95
+ }
96
+ /**
97
+ * Clear all registered handlers (primarily for testing).
98
+ */
99
+ static clear() {
100
+ this.handlers.clear();
101
+ }
102
+ }
103
+ //# sourceMappingURL=HandlerRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HandlerRegistry.js","sourceRoot":"","sources":["../../src/handlers/HandlerRegistry.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAoBb;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,eAAe;IAClB,MAAM,CAAC,QAAQ,GAAG,IAAI,GAAG,EAA+B,CAAC;IAEjE;;;;;OAKG;IACI,MAAM,CAAC,QAAQ,CAAC,YAAiC;QACtD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,uBAAuB,YAAY,CAAC,IAAI,yBAAyB,CAAC,CAAC;QACrF,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACrD,CAAC;IAED;;;;;;OAMG;IACI,MAAM,CAAC,GAAG,CAAC,MAAc;QAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/C,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,SAAS,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,wBAAwB,SAAS,EAAE,CAAC,CAAC;QACpF,CAAC;QACD,OAAO,YAAY,CAAC,OAAO,EAAE,CAAC;IAChC,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,mBAAmB;QAC/B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACjD,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,YAAY,CAAC,MAAc;QACvC,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/C,OAAO,YAAY,EAAE,aAAa,IAAI,MAAM,CAAC;IAC/C,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,cAAc,CAAC,MAAc;QACzC,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/C,OAAO,YAAY,EAAE,WAAW,IAAI,EAAE,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,sBAAsB,CAAC,MAAc;QACjD,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/C,OAAO,YAAY,EAAE,cAAc,IAAI,EAAE,CAAC;IAC5C,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,GAAG,CAAC,MAAc;QAC9B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,KAAK;QACjB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC"}