apex-code-coverage-transformer 4.0.0 → 4.2.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.
- package/CHANGELOG.md +14 -0
- package/README.md +48 -8
- package/lib/commands/acc-transformer/transform.js +19 -11
- package/lib/commands/acc-transformer/transform.js.map +1 -1
- package/lib/handlers/html.js +32 -13
- package/lib/handlers/html.js.map +1 -1
- package/lib/index.d.ts +7 -2
- package/lib/index.js +12 -1
- package/lib/index.js.map +1 -1
- package/lib/transformers/coverageProcessor.js +25 -6
- package/lib/transformers/coverageProcessor.js.map +1 -1
- package/lib/transformers/coverageTransformer.d.ts +16 -1
- package/lib/transformers/coverageTransformer.js +98 -19
- package/lib/transformers/coverageTransformer.js.map +1 -1
- package/lib/transformers/generators/generateHtml.js +11 -1
- package/lib/transformers/generators/generateHtml.js.map +1 -1
- package/lib/transformers/reportGenerator.d.ts +2 -0
- package/lib/transformers/reportGenerator.js +10 -13
- package/lib/transformers/reportGenerator.js.map +1 -1
- package/lib/utils/errors.d.ts +12 -0
- package/lib/utils/errors.js +14 -0
- package/lib/utils/errors.js.map +1 -0
- package/lib/utils/getPackageDirectories.d.ts +1 -1
- package/lib/utils/getPackageDirectories.js +2 -2
- package/lib/utils/getPackageDirectories.js.map +1 -1
- package/lib/utils/getRepoRoot.d.ts +1 -1
- package/lib/utils/getRepoRoot.js +8 -5
- package/lib/utils/getRepoRoot.js.map +1 -1
- package/lib/utils/types.d.ts +80 -6
- package/oclif.manifest.json +1 -2
- package/package.json +13 -6
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@
|
|
|
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
|
+
## [4.2.0](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v4.1.0...v4.2.0) (2026-11-09)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add programmatic API for library consumers ([#438](https://github.com/mcarvin8/apex-code-coverage-transformer/issues/438)) ([13679cd](https://github.com/mcarvin8/apex-code-coverage-transformer/commit/13679cd98ea71f3f077ccf17d594cd512b9a0878))
|
|
14
|
+
|
|
15
|
+
## [4.1.0](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v4.0.0...v4.1.0) (2026-11-05)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* **html:** render full source file with coverage overlay ([#435](https://github.com/mcarvin8/apex-code-coverage-transformer/issues/435)) ([6cdc757](https://github.com/mcarvin8/apex-code-coverage-transformer/commit/6cdc757aeee44dbb58d7fb2546951357626be55b))
|
|
21
|
+
|
|
8
22
|
## [4.0.0](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v3.1.12...v4.0.0) (2026-11-05)
|
|
9
23
|
|
|
10
24
|
|
package/README.md
CHANGED
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
[](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/LICENSE.md)
|
|
7
7
|
[](https://codecov.io/gh/mcarvin8/apex-code-coverage-transformer)
|
|
8
8
|
[](https://dashboard.stryker-mutator.io/reports/github.com/mcarvin8/apex-code-coverage-transformer/main)
|
|
9
|
-
<!-- gh-dependents-info-used-by-start -->
|
|
10
|
-
[](https://github.com/mcarvin8/apex-code-coverage-transformer/blob/main/docs/github-dependents-info.md)<!-- gh-dependents-info-used-by-end -->
|
|
11
9
|
|
|
12
10
|
Transforms (and optionally merges) Apex code coverage JSON from Salesforce deployments or test runs into formats used by SonarQube, Codecov, GitHub, GitLab, Azure DevOps, Bitbucket, and other tools, keeping coverage visible across pull requests, CI/CD pipelines, and code quality platforms. Available as a **Salesforce CLI plugin** for any provider, and as a **native GitHub Action** for GitHub Actions users who want to skip installing the CLI.
|
|
13
11
|
|
|
@@ -26,6 +24,7 @@ Transforms (and optionally merges) Apex code coverage JSON from Salesforce deplo
|
|
|
26
24
|
- [Coverage Report Formats](#coverage-report-formats)
|
|
27
25
|
- [CI/CD Integration](#cicd-integration)
|
|
28
26
|
- [Automatic Transformation (Hook)](#automatic-transformation-hook)
|
|
27
|
+
- [Programmatic Usage](#programmatic-usage)
|
|
29
28
|
- [Troubleshooting](#troubleshooting)
|
|
30
29
|
- [Questions or Issues?](#questions-or-issues)
|
|
31
30
|
- [License](#license)
|
|
@@ -51,7 +50,7 @@ For GitHub Actions, this is also available as a [native Action](https://github.c
|
|
|
51
50
|
|
|
52
51
|
```yaml
|
|
53
52
|
- name: Transform Coverage
|
|
54
|
-
uses: mcarvin8/apex-code-coverage-transformer@
|
|
53
|
+
uses: mcarvin8/apex-code-coverage-transformer@v4
|
|
55
54
|
with:
|
|
56
55
|
coverage-json: coverage/test-result-codecoverage.json
|
|
57
56
|
output-report: coverage.xml
|
|
@@ -197,7 +196,7 @@ EXAMPLES
|
|
|
197
196
|
`sf acc-transformer transform -j "coverage1.json" -j "coverage2.json" -r "coverage.xml" -f "sonar"`
|
|
198
197
|
```
|
|
199
198
|
|
|
200
|
-
_See code: [src/commands/acc-transformer/transform.ts](https://github.com/mcarvin8/apex-code-coverage-transformer/blob/v4.
|
|
199
|
+
_See code: [src/commands/acc-transformer/transform.ts](https://github.com/mcarvin8/apex-code-coverage-transformer/blob/v4.2.0/src/commands/acc-transformer/transform.ts)_
|
|
201
200
|
<!-- commandsstop -->
|
|
202
201
|
|
|
203
202
|
## Coverage Report Formats
|
|
@@ -215,7 +214,7 @@ Use `-f` / `--format` to choose the output format. Multiple `-f` values produce
|
|
|
215
214
|
| json-summary | JSON summary | Badges, PR comments | `sf acc-transformer transform -j "coverage.json" -r "coverage.json" -f "json-summary"` |
|
|
216
215
|
| simplecov | SimpleCov JSON | Codecov, Ruby tools | `sf acc-transformer transform -j "coverage.json" -r "coverage.json" -f "simplecov"` |
|
|
217
216
|
| opencover | OpenCover XML | Azure DevOps, VS, Codecov | `sf acc-transformer transform -j "coverage.json" -r "coverage.xml" -f "opencover"` |
|
|
218
|
-
| html | HTML report
|
|
217
|
+
| html | Full-source HTML report | Browsers, CI artifacts | `sf acc-transformer transform -j "coverage.json" -r "coverage.html" -f "html"` |
|
|
219
218
|
| markdown | Markdown summary | PR/MR comments, CI job summaries | `sf acc-transformer transform -j "coverage.json" -r "coverage.md" -f "markdown"` |
|
|
220
219
|
| github-actions | GitHub Actions annotations | GitHub Actions PR diff annotations | `sf acc-transformer transform -j "coverage.json" -r "coverage.txt" -f "github-actions"` |
|
|
221
220
|
|
|
@@ -307,7 +306,7 @@ For GitHub Actions specifically, the transform step can run as a native Action i
|
|
|
307
306
|
|
|
308
307
|
```yaml
|
|
309
308
|
- name: Transform Coverage
|
|
310
|
-
uses: mcarvin8/apex-code-coverage-transformer@
|
|
309
|
+
uses: mcarvin8/apex-code-coverage-transformer@v4
|
|
311
310
|
with:
|
|
312
311
|
coverage-json: coverage/test-result-codecoverage.json
|
|
313
312
|
output-report: coverage.xml
|
|
@@ -319,7 +318,7 @@ Repeatable inputs (`coverage-json`, `format`, `ignore-package-directory`, `exclu
|
|
|
319
318
|
```yaml
|
|
320
319
|
- name: Transform Coverage
|
|
321
320
|
id: transform
|
|
322
|
-
uses: mcarvin8/apex-code-coverage-transformer@
|
|
321
|
+
uses: mcarvin8/apex-code-coverage-transformer@v4
|
|
323
322
|
with:
|
|
324
323
|
coverage-json: coverage/test-result-codecoverage.json
|
|
325
324
|
format: |
|
|
@@ -546,6 +545,47 @@ Sample configs: [Salesforce CLI](https://raw.githubusercontent.com/mcarvin8/apex
|
|
|
546
545
|
| `maxAnnotations` | No | Maximum `::warning` annotations emitted when `format` includes `github-actions` (default: `50`). |
|
|
547
546
|
| `excludePatterns` | No | Comma-separated glob patterns for file paths to exclude (e.g. `**/*Test*,**/mock/**`). Matched against the relative path from the repo root. |
|
|
548
547
|
|
|
548
|
+
## Programmatic Usage
|
|
549
|
+
|
|
550
|
+
Other Node.js tools (CLI plugins, scripts, CI wrappers) can call the transformer directly instead of shelling out to `sf acc-transformer transform`. The package is ESM-only.
|
|
551
|
+
|
|
552
|
+
```bash
|
|
553
|
+
npm install apex-code-coverage-transformer
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
```ts
|
|
557
|
+
import { transformCoverage, CoverageError } from 'apex-code-coverage-transformer';
|
|
558
|
+
|
|
559
|
+
const { summary, reports, warnings, passed } = await transformCoverage({
|
|
560
|
+
inputs: ['coverage/coverage/coverage.json'], // file paths and/or already-parsed coverage JSON
|
|
561
|
+
formats: ['cobertura', 'markdown'],
|
|
562
|
+
write: false, // return report contents without writing files
|
|
563
|
+
cwd: '/path/to/sfdx/project', // where to look for sfdx-project.json (default: process.cwd())
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
console.log(`${(summary.lineRate * 100).toFixed(2)}% across ${summary.fileCount} files`);
|
|
567
|
+
for (const file of summary.files) {
|
|
568
|
+
console.log(file.path, file.coveredLines, '/', file.totalLines, 'uncovered:', file.uncoveredLines);
|
|
569
|
+
}
|
|
570
|
+
const markdown = reports.find((r) => r.format === 'markdown')?.content;
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
| Option | Default | Description |
|
|
574
|
+
| -------------------------- | --------------- | ------------------------------------------------------------------------------------------- |
|
|
575
|
+
| `inputs` | (required) | Coverage JSON file paths and/or parsed objects. All must be the same type (deploy or test). |
|
|
576
|
+
| `formats` | `['sonar']` | Output formats. `COVERAGE_FORMATS` lists every supported value. |
|
|
577
|
+
| `outputReport` | `coverage.xml` | Base path for written reports. Multiple formats add a suffix (e.g. `coverage-sonar.xml`). |
|
|
578
|
+
| `write` | `true` | When `false`, nothing is written and each report's `path` is `undefined`. |
|
|
579
|
+
| `cwd` | `process.cwd()` | Directory to search upward from for `sfdx-project.json`. |
|
|
580
|
+
| `ignorePackageDirectories` | `[]` | Package directories to skip. |
|
|
581
|
+
| `excludePatterns` | `[]` | Glob patterns for repo-relative file paths to exclude. |
|
|
582
|
+
| `minCoverage` | none | Sets `passed: false` when overall coverage is below this percentage. Nothing is thrown. |
|
|
583
|
+
| `maxAnnotations` | `50` | Annotation limit for the `github-actions` format. |
|
|
584
|
+
|
|
585
|
+
Known failures throw a `CoverageError` with a `code`: `UNKNOWN_INPUT_FORMAT`, `MIXED_INPUT_TYPES`, `UNSUPPORTED_FORMAT`, or `NO_SFDX_PROJECT`. Unreadable input files are skipped with a warning.
|
|
586
|
+
|
|
587
|
+
Everything exported from the package root follows semver. Deep imports are not supported.
|
|
588
|
+
|
|
549
589
|
## Troubleshooting
|
|
550
590
|
|
|
551
591
|
**File not in package directory** — File is omitted from the report:
|
|
@@ -592,7 +632,7 @@ Error (1): sfdx-project.json not found in any parent directory.
|
|
|
592
632
|
Error (1): ENOENT: no such file or directory: {packageDir}
|
|
593
633
|
```
|
|
594
634
|
|
|
595
|
-
**Deploy coverage line numbers** — Older Salesforce deploy command coverage reports could contain covered lines numbered past the end of a file ([forcedotcom/salesforcedx-vscode#5511](https://github.com/forcedotcom/salesforcedx-vscode/issues/5511), [forcedotcom/cli#1568](https://github.com/forcedotcom/cli/issues/1568)). Salesforce fixed this server-side in Winter '27 (API v68.0), and the fix applies regardless of the `--api-version` requested on the deploy. Versions 3.x and earlier of this plugin re-numbered those lines; starting with v4, deploy coverage lines are passed through as reported by Salesforce. If you still see out-of-range lines in deploy coverage, please [open an issue](https://github.com/mcarvin8/apex-code-coverage-transformer/issues
|
|
635
|
+
**Deploy coverage line numbers** — Older Salesforce deploy command coverage reports could contain covered lines numbered past the end of a file ([forcedotcom/salesforcedx-vscode#5511](https://github.com/forcedotcom/salesforcedx-vscode/issues/5511), [forcedotcom/cli#1568](https://github.com/forcedotcom/cli/issues/1568)). Salesforce fixed this server-side in Winter '27 (API v68.0), and the fix applies regardless of the `--api-version` requested on the deploy. Versions 3.x and earlier of this plugin re-numbered those lines; starting with v4, deploy coverage lines are passed through as reported by Salesforce. If you still see out-of-range lines in deploy coverage, please [open an issue](https://github.com/mcarvin8/apex-code-coverage-transformer/issues).
|
|
596
636
|
|
|
597
637
|
## Questions or Issues?
|
|
598
638
|
|
|
@@ -4,6 +4,7 @@ import { Flags, SfCommand } from '@salesforce/sf-plugins-core';
|
|
|
4
4
|
import { transformCoverageReport } from '../../transformers/coverageTransformer.js';
|
|
5
5
|
import { DEFAULT_MAX_ANNOTATIONS } from '../../transformers/generators/generateGitHubActions.js';
|
|
6
6
|
import { formatOptions } from '../../utils/constants.js';
|
|
7
|
+
import { CoverageError } from '../../utils/errors.js';
|
|
7
8
|
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
|
|
8
9
|
const messages = Messages.loadMessages('apex-code-coverage-transformer', 'transformer.transform');
|
|
9
10
|
export default class TransformerTransform extends SfCommand {
|
|
@@ -45,7 +46,6 @@ export default class TransformerTransform extends SfCommand {
|
|
|
45
46
|
}),
|
|
46
47
|
'max-annotations': Flags.integer({
|
|
47
48
|
summary: messages.getMessage('flags.max-annotations.summary'),
|
|
48
|
-
required: false,
|
|
49
49
|
min: 1,
|
|
50
50
|
default: DEFAULT_MAX_ANNOTATIONS,
|
|
51
51
|
}),
|
|
@@ -59,18 +59,26 @@ export default class TransformerTransform extends SfCommand {
|
|
|
59
59
|
async run() {
|
|
60
60
|
const { flags } = await this.parse(TransformerTransform);
|
|
61
61
|
const warnings = [];
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
this.log(`The coverage report has been written to: ${result.finalPaths.join(', ')}`);
|
|
69
|
-
if (warnings.length > 0) {
|
|
70
|
-
warnings.forEach((warning) => {
|
|
71
|
-
this.warn(warning);
|
|
62
|
+
let result;
|
|
63
|
+
try {
|
|
64
|
+
result = await transformCoverageReport(flags['coverage-json'], flags['output-report'], flags['format'] ?? ['sonar'], flags['ignore-package-directory'] ?? [], {
|
|
65
|
+
minCoverage: flags['min-coverage'],
|
|
66
|
+
maxAnnotations: flags['max-annotations'],
|
|
67
|
+
excludePatterns: flags['exclude-pattern'],
|
|
72
68
|
});
|
|
73
69
|
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
// SfCommand prints an error's `code` in place of the exit code ("Error (UNKNOWN_INPUT_FORMAT)").
|
|
72
|
+
// Rethrow as a plain Error so CLI output stays "Error (1): ..." as documented.
|
|
73
|
+
if (error instanceof CoverageError)
|
|
74
|
+
throw new Error(error.message, { cause: error });
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
warnings.push(...result.warnings);
|
|
78
|
+
this.log(`The coverage report has been written to: ${result.finalPaths.join(', ')}`);
|
|
79
|
+
warnings.forEach((warning) => {
|
|
80
|
+
this.warn(warning);
|
|
81
|
+
});
|
|
74
82
|
if (!result.success) {
|
|
75
83
|
this.error(`Coverage of ${(result.lineRate * 100).toFixed(2)}% is below the required minimum of ${flags['min-coverage']}%.`);
|
|
76
84
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../src/commands/acc-transformer/transform.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AACpF,OAAO,EAAE,uBAAuB,EAAE,MAAM,wDAAwD,CAAC;AACjG,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../src/commands/acc-transformer/transform.ts"],"names":[],"mappings":"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"}
|
package/lib/handlers/html.js
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import { BaseHandler } from './BaseHandler.js';
|
|
3
3
|
import { HandlerRegistry } from './HandlerRegistry.js';
|
|
4
|
+
function toExecutableLine(lineNumber, hitCount, content) {
|
|
5
|
+
return { lineNumber, hitCount, covered: hitCount > 0, content, executable: true };
|
|
6
|
+
}
|
|
7
|
+
/** Rows for coverage-data lines only. Used when the source file could not be read. */
|
|
8
|
+
function buildCoverageOnlyLines(lines) {
|
|
9
|
+
return Object.entries(lines)
|
|
10
|
+
.map(([lineNumber, hitCount]) => toExecutableLine(Number(lineNumber), hitCount, ''))
|
|
11
|
+
.sort((a, b) => a.lineNumber - b.lineNumber);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Rows for every line of the source file, with coverage overlaid on executable lines.
|
|
15
|
+
* Coverage lines numbered past the end of the file are still listed (with empty content)
|
|
16
|
+
* so no reported coverage is dropped from the view.
|
|
17
|
+
*/
|
|
18
|
+
function buildFullSourceLines(lines, sourceContent) {
|
|
19
|
+
const sourceLines = sourceContent.split(/\r\n|\r|\n/);
|
|
20
|
+
if (sourceLines.at(-1) === '') {
|
|
21
|
+
sourceLines.pop();
|
|
22
|
+
}
|
|
23
|
+
const lastCoverageLine = Object.keys(lines).reduce((max, key) => Math.max(max, Number(key) || 0), 0);
|
|
24
|
+
const lineCount = Math.max(sourceLines.length, lastCoverageLine);
|
|
25
|
+
const rows = [];
|
|
26
|
+
for (let lineNumber = 1; lineNumber <= lineCount; lineNumber++) {
|
|
27
|
+
const content = sourceLines[lineNumber - 1] ?? '';
|
|
28
|
+
const hitCount = lines[String(lineNumber)];
|
|
29
|
+
rows.push(hitCount === undefined
|
|
30
|
+
? { lineNumber, hitCount: 0, covered: false, content, executable: false }
|
|
31
|
+
: toExecutableLine(lineNumber, hitCount, content));
|
|
32
|
+
}
|
|
33
|
+
return rows;
|
|
34
|
+
}
|
|
4
35
|
/**
|
|
5
36
|
* Handler for generating HTML coverage reports.
|
|
6
37
|
*
|
|
@@ -39,19 +70,7 @@ export class HtmlCoverageHandler extends BaseHandler {
|
|
|
39
70
|
}
|
|
40
71
|
processFile(filePath, fileName, lines, sourceContent) {
|
|
41
72
|
const { totalLines, coveredLines, uncoveredLines, lineRate } = this.calculateCoverage(lines);
|
|
42
|
-
const
|
|
43
|
-
const fileLines = Object.entries(lines)
|
|
44
|
-
.map(([lineNumber, hitCount]) => {
|
|
45
|
-
const num = Number(lineNumber);
|
|
46
|
-
const content = sourceLines[num - 1] ?? '';
|
|
47
|
-
return {
|
|
48
|
-
lineNumber: num,
|
|
49
|
-
hitCount,
|
|
50
|
-
covered: hitCount > 0,
|
|
51
|
-
content,
|
|
52
|
-
};
|
|
53
|
-
})
|
|
54
|
-
.sort((a, b) => a.lineNumber - b.lineNumber);
|
|
73
|
+
const fileLines = sourceContent === undefined ? buildCoverageOnlyLines(lines) : buildFullSourceLines(lines, sourceContent);
|
|
55
74
|
const fileCoverage = {
|
|
56
75
|
filePath,
|
|
57
76
|
fileName,
|
package/lib/handlers/html.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/handlers/html.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAGb,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAKvD
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/handlers/html.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
import { CoverageFormat } from './utils/types.js';
|
|
2
|
+
export { transformCoverage } from './transformers/coverageTransformer.js';
|
|
3
|
+
export type { CoverageErrorCode } from './utils/errors.js';
|
|
4
|
+
export { CoverageError } from './utils/errors.js';
|
|
5
|
+
export type { CoverageFormat, CoverageInput, CoverageSummary, DeployCoverageData, FileCoverageSummary, GeneratedReport, TestCoverageData, TransformCoverageOptions, TransformCoverageResult, } from './utils/types.js';
|
|
6
|
+
/** All supported output formats, sorted alphabetically. */
|
|
7
|
+
export declare const COVERAGE_FORMATS: readonly CoverageFormat[];
|
package/lib/index.js
CHANGED
|
@@ -1,2 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* Public programmatic API.
|
|
4
|
+
*
|
|
5
|
+
* Everything exported from this module follows semver. Anything imported from deeper paths
|
|
6
|
+
* is internal and may change in any release.
|
|
7
|
+
*/
|
|
8
|
+
import { formatOptions } from './utils/constants.js';
|
|
9
|
+
export { transformCoverage } from './transformers/coverageTransformer.js';
|
|
10
|
+
export { CoverageError } from './utils/errors.js';
|
|
11
|
+
/** All supported output formats, sorted alphabetically. */
|
|
12
|
+
export const COVERAGE_FORMATS = Object.freeze([...formatOptions]);
|
|
2
13
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;GAKG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAE1E,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAalD,2DAA2D;AAC3D,MAAM,CAAC,MAAM,gBAAgB,GAA8B,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,aAAa,CAAqB,CAAC,CAAC"}
|
|
@@ -13,17 +13,18 @@ export function createHandlers(formats) {
|
|
|
13
13
|
}
|
|
14
14
|
return handlers;
|
|
15
15
|
}
|
|
16
|
-
async function
|
|
16
|
+
async function loadSourceContent(path, context) {
|
|
17
|
+
if (!context.handlers.has('html')) {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
17
20
|
try {
|
|
18
|
-
return await readFile(
|
|
21
|
+
return await readFile(join(context.repoRoot, path), 'utf-8');
|
|
19
22
|
}
|
|
20
23
|
catch {
|
|
24
|
+
context.warnings.push(`Could not read source file ${path}; the HTML report will show coverage for this file without line contents.`);
|
|
21
25
|
return undefined;
|
|
22
26
|
}
|
|
23
27
|
}
|
|
24
|
-
function loadSourceContent(path, context) {
|
|
25
|
-
return context.handlers.has('html') ? readSourceFile(join(context.repoRoot, path)) : Promise.resolve(undefined);
|
|
26
|
-
}
|
|
27
28
|
export function countLines(lines) {
|
|
28
29
|
const totalLines = Object.keys(lines).length;
|
|
29
30
|
const coveredLines = Object.values(lines).filter((v) => v === 1).length;
|
|
@@ -33,6 +34,7 @@ async function processEntries(items, context, getName, resolveLines) {
|
|
|
33
34
|
let processed = 0;
|
|
34
35
|
let totalLines = 0;
|
|
35
36
|
let coveredLines = 0;
|
|
37
|
+
const files = [];
|
|
36
38
|
await mapLimit(items, context.concurrencyLimit, async (item) => {
|
|
37
39
|
const formattedName = getName(item).replace(/no-map[\\/]+/, '');
|
|
38
40
|
const path = findFilePath(formattedName, context.filePathCache);
|
|
@@ -47,12 +49,29 @@ async function processEntries(items, context, getName, resolveLines) {
|
|
|
47
49
|
const counts = countLines(lines);
|
|
48
50
|
totalLines += counts.totalLines;
|
|
49
51
|
coveredLines += counts.coveredLines;
|
|
52
|
+
files.push(summarizeFile(path, formattedName, lines, counts));
|
|
50
53
|
for (const handler of context.handlers.values()) {
|
|
51
54
|
handler.processFile(path, formattedName, lines, sourceContent);
|
|
52
55
|
}
|
|
53
56
|
processed++;
|
|
54
57
|
});
|
|
55
|
-
|
|
58
|
+
files.sort((a, b) => a.path.localeCompare(b.path));
|
|
59
|
+
return { processed, totalLines, coveredLines, files };
|
|
60
|
+
}
|
|
61
|
+
function summarizeFile(path, name, lines, counts) {
|
|
62
|
+
// Line numbers are integer-like keys, which JavaScript always enumerates in ascending
|
|
63
|
+
// numeric order, so no explicit sort is needed.
|
|
64
|
+
const uncoveredLines = Object.entries(lines)
|
|
65
|
+
.filter(([, hit]) => hit !== 1)
|
|
66
|
+
.map(([line]) => Number(line));
|
|
67
|
+
return {
|
|
68
|
+
path,
|
|
69
|
+
name,
|
|
70
|
+
totalLines: counts.totalLines,
|
|
71
|
+
coveredLines: counts.coveredLines,
|
|
72
|
+
lineRate: counts.totalLines > 0 ? counts.coveredLines / counts.totalLines : 0,
|
|
73
|
+
uncoveredLines,
|
|
74
|
+
};
|
|
56
75
|
}
|
|
57
76
|
export function processDeployCoverage(data, context) {
|
|
58
77
|
return processEntries(Object.keys(data), context, (fileName) => fileName, async (fileName, path) => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverageProcessor.js","sourceRoot":"","sources":["../../src/transformers/coverageProcessor.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"coverageProcessor.js","sourceRoot":"","sources":["../../src/transformers/coverageProcessor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
import { TransformOptions } from '../utils/types.js';
|
|
1
|
+
import { TransformCoverageOptions, TransformCoverageResult, TransformOptions } from '../utils/types.js';
|
|
2
2
|
export { TransformOptions };
|
|
3
|
+
/**
|
|
4
|
+
* Transform Salesforce CLI Apex coverage JSON into one or more report formats.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const { summary, reports } = await transformCoverage({
|
|
8
|
+
* inputs: ['coverage/coverage/coverage.json'],
|
|
9
|
+
* formats: ['cobertura', 'markdown'],
|
|
10
|
+
* write: false,
|
|
11
|
+
* });
|
|
12
|
+
*/
|
|
13
|
+
export declare function transformCoverage(options: TransformCoverageOptions): Promise<TransformCoverageResult>;
|
|
14
|
+
/**
|
|
15
|
+
* Positional-argument wrapper used by the CLI command and GitHub Action.
|
|
16
|
+
* Library consumers should use {@link transformCoverage}.
|
|
17
|
+
*/
|
|
3
18
|
export declare function transformCoverageReport(jsonFilePaths: string[], outputReportPath: string, formats: string[], ignoreDirs: string[], options?: TransformOptions): Promise<{
|
|
4
19
|
finalPaths: string[];
|
|
5
20
|
warnings: string[];
|
|
@@ -1,32 +1,72 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
2
|
'use strict';
|
|
3
|
+
import { writeFile } from 'node:fs/promises';
|
|
4
|
+
import { HandlerRegistry } from '../handlers/HandlerRegistry.js';
|
|
3
5
|
import { buildFilePathCache } from '../utils/buildFilePathCache.js';
|
|
6
|
+
import { CoverageError } from '../utils/errors.js';
|
|
4
7
|
import { getConcurrencyThreshold } from '../utils/getConcurrencyThreshold.js';
|
|
5
8
|
import { getPackageDirectories } from '../utils/getPackageDirectories.js';
|
|
6
9
|
import { tryReadJson } from '../utils/readJson.js';
|
|
7
10
|
import { checkCoverageDataType } from '../utils/setCoverageDataType.js';
|
|
8
11
|
import { mergeDeployCoverageData, mergeTestCoverageData } from './coverageDataMerger.js';
|
|
9
12
|
import { createHandlers, processDeployCoverage, processTestCoverage } from './coverageProcessor.js';
|
|
10
|
-
import {
|
|
11
|
-
|
|
13
|
+
import { generateReportContent, getReportPath } from './reportGenerator.js';
|
|
14
|
+
const DEFAULT_OUTPUT_REPORT = 'coverage.xml';
|
|
15
|
+
async function loadInputs(inputs, warnings) {
|
|
16
|
+
const loaded = await Promise.all(inputs.map(async (input) => {
|
|
17
|
+
if (typeof input !== 'string')
|
|
18
|
+
return input;
|
|
19
|
+
const raw = await tryReadJson(input, warnings);
|
|
20
|
+
return raw === null ? null : JSON.parse(raw);
|
|
21
|
+
}));
|
|
22
|
+
return loaded.filter((item) => item !== null);
|
|
23
|
+
}
|
|
24
|
+
function validateFormats(formats) {
|
|
25
|
+
for (const format of formats) {
|
|
26
|
+
if (!HandlerRegistry.has(format)) {
|
|
27
|
+
throw new CoverageError(`Unsupported format: ${format}. Available formats: ${HandlerRegistry.getAvailableFormats().join(', ')}`, { code: 'UNSUPPORTED_FORMAT' });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function emptyResult(warnings) {
|
|
32
|
+
return {
|
|
33
|
+
reports: [],
|
|
34
|
+
summary: { lineRate: 0, coveredLines: 0, totalLines: 0, fileCount: 0, files: [] },
|
|
35
|
+
warnings,
|
|
36
|
+
passed: true,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Transform Salesforce CLI Apex coverage JSON into one or more report formats.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const { summary, reports } = await transformCoverage({
|
|
44
|
+
* inputs: ['coverage/coverage/coverage.json'],
|
|
45
|
+
* formats: ['cobertura', 'markdown'],
|
|
46
|
+
* write: false,
|
|
47
|
+
* });
|
|
48
|
+
*/
|
|
49
|
+
export async function transformCoverage(options) {
|
|
50
|
+
const formats = options.formats && options.formats.length > 0 ? options.formats : ['sonar'];
|
|
51
|
+
const outputReport = options.outputReport ?? DEFAULT_OUTPUT_REPORT;
|
|
52
|
+
const write = options.write ?? true;
|
|
12
53
|
const warnings = [];
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (validData.length === 0)
|
|
18
|
-
return { finalPaths: [outputReportPath], warnings, lineRate: 0, success: true };
|
|
19
|
-
const parsedItems = validData.map((d) => JSON.parse(d));
|
|
54
|
+
validateFormats(formats);
|
|
55
|
+
const parsedItems = await loadInputs(options.inputs, warnings);
|
|
56
|
+
if (parsedItems.length === 0)
|
|
57
|
+
return emptyResult(warnings);
|
|
20
58
|
const types = parsedItems.map(checkCoverageDataType);
|
|
21
59
|
if (types.some((t) => t === 'Unknown')) {
|
|
22
|
-
throw new
|
|
60
|
+
throw new CoverageError('The provided JSON does not match a known coverage data format from the Salesforce deploy or test command.', { code: 'UNKNOWN_INPUT_FORMAT' });
|
|
23
61
|
}
|
|
24
62
|
const uniqueTypes = [...new Set(types)];
|
|
25
63
|
if (uniqueTypes.length > 1) {
|
|
26
|
-
throw new
|
|
64
|
+
throw new CoverageError('All coverage JSON files must be the same type (deploy or test).', {
|
|
65
|
+
code: 'MIXED_INPUT_TYPES',
|
|
66
|
+
});
|
|
27
67
|
}
|
|
28
68
|
const commandType = uniqueTypes[0];
|
|
29
|
-
const { repoRoot, packageDirectories } = await getPackageDirectories(
|
|
69
|
+
const { repoRoot, packageDirectories } = await getPackageDirectories(options.ignorePackageDirectories ?? [], options.cwd);
|
|
30
70
|
const handlers = createHandlers(formats);
|
|
31
71
|
const concurrencyLimit = getConcurrencyThreshold();
|
|
32
72
|
// Build file path cache upfront to avoid O(n*m) directory traversals
|
|
@@ -39,7 +79,7 @@ export async function transformCoverageReport(jsonFilePaths, outputReportPath, f
|
|
|
39
79
|
concurrencyLimit,
|
|
40
80
|
warnings,
|
|
41
81
|
filePathCache,
|
|
42
|
-
excludePatterns: options
|
|
82
|
+
excludePatterns: options.excludePatterns ?? [],
|
|
43
83
|
};
|
|
44
84
|
const processResult = commandType === 'DeployCoverageData'
|
|
45
85
|
? await processDeployCoverage(mergeDeployCoverageData(parsedItems), context)
|
|
@@ -48,13 +88,52 @@ export async function transformCoverageReport(jsonFilePaths, outputReportPath, f
|
|
|
48
88
|
warnings.push('None of the files listed in the coverage JSON were processed. The coverage report will be empty.');
|
|
49
89
|
}
|
|
50
90
|
const lineRate = processResult.totalLines > 0 ? processResult.coveredLines / processResult.totalLines : 0;
|
|
51
|
-
const renderOptions = options
|
|
91
|
+
const renderOptions = options.maxAnnotations !== undefined ? { maxAnnotations: options.maxAnnotations } : undefined;
|
|
92
|
+
const reports = [];
|
|
52
93
|
for (const [format, handler] of handlers.entries()) {
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
94
|
+
const content = generateReportContent(handler.finalize(), format, renderOptions);
|
|
95
|
+
const report = { format: format, content };
|
|
96
|
+
if (write) {
|
|
97
|
+
report.path = getReportPath(outputReport, format, formats.length);
|
|
98
|
+
await writeFile(report.path, content);
|
|
99
|
+
}
|
|
100
|
+
reports.push(report);
|
|
56
101
|
}
|
|
57
|
-
|
|
58
|
-
|
|
102
|
+
return {
|
|
103
|
+
reports,
|
|
104
|
+
summary: {
|
|
105
|
+
lineRate,
|
|
106
|
+
coveredLines: processResult.coveredLines,
|
|
107
|
+
totalLines: processResult.totalLines,
|
|
108
|
+
fileCount: processResult.files.length,
|
|
109
|
+
files: processResult.files,
|
|
110
|
+
},
|
|
111
|
+
warnings,
|
|
112
|
+
passed: options.minCoverage === undefined || lineRate * 100 >= options.minCoverage,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Positional-argument wrapper used by the CLI command and GitHub Action.
|
|
117
|
+
* Library consumers should use {@link transformCoverage}.
|
|
118
|
+
*/
|
|
119
|
+
export async function transformCoverageReport(jsonFilePaths, outputReportPath, formats, ignoreDirs, options) {
|
|
120
|
+
const result = await transformCoverage({
|
|
121
|
+
inputs: jsonFilePaths,
|
|
122
|
+
outputReport: outputReportPath,
|
|
123
|
+
formats: formats,
|
|
124
|
+
ignorePackageDirectories: ignoreDirs,
|
|
125
|
+
minCoverage: options?.minCoverage,
|
|
126
|
+
maxAnnotations: options?.maxAnnotations,
|
|
127
|
+
excludePatterns: options?.excludePatterns,
|
|
128
|
+
});
|
|
129
|
+
// The wrapper always writes (write defaults to true), so every report has a path.
|
|
130
|
+
const finalPaths = result.reports.map((r) => r.path);
|
|
131
|
+
return {
|
|
132
|
+
// Preserve historical behavior: report the requested path even when no inputs could be read.
|
|
133
|
+
finalPaths: finalPaths.length > 0 ? finalPaths : [outputReportPath],
|
|
134
|
+
warnings: result.warnings,
|
|
135
|
+
lineRate: result.summary.lineRate,
|
|
136
|
+
success: result.passed,
|
|
137
|
+
};
|
|
59
138
|
}
|
|
60
139
|
//# sourceMappingURL=coverageTransformer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverageTransformer.js","sourceRoot":"","sources":["../../src/transformers/coverageTransformer.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,YAAY,CAAC;AAEb,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"coverageTransformer.js","sourceRoot":"","sources":["../../src/transformers/coverageTransformer.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,9 +48,16 @@ function groupFilesByDir(files) {
|
|
|
48
48
|
return filesByDir;
|
|
49
49
|
}
|
|
50
50
|
function buildLineRow(line) {
|
|
51
|
+
const codeContent = line.content !== undefined ? escapeHtml(line.content) : '';
|
|
52
|
+
if (line.executable === false) {
|
|
53
|
+
return `<tr class="neutral">
|
|
54
|
+
<td class="line-number">${line.lineNumber}</td>
|
|
55
|
+
<td class="hit-count"></td>
|
|
56
|
+
<td class="line-content">${codeContent}</td>
|
|
57
|
+
</tr>`;
|
|
58
|
+
}
|
|
51
59
|
const lineClass = line.covered ? 'covered' : 'uncovered';
|
|
52
60
|
const lineColor = line.covered ? '#c8e6c9' : '#ffcdd2';
|
|
53
|
-
const codeContent = line.content !== undefined ? escapeHtml(line.content) : '';
|
|
54
61
|
return `<tr class="${lineClass}" style="background-color: ${lineColor}">
|
|
55
62
|
<td class="line-number">${line.lineNumber}</td>
|
|
56
63
|
<td class="hit-count">${line.hitCount}</td>
|
|
@@ -267,6 +274,9 @@ export function generateHtml(coverageObj) {
|
|
|
267
274
|
.uncovered {
|
|
268
275
|
background-color: #ffcdd2 !important;
|
|
269
276
|
}
|
|
277
|
+
.neutral .line-content {
|
|
278
|
+
color: #666;
|
|
279
|
+
}
|
|
270
280
|
.package-summary {
|
|
271
281
|
margin-bottom: 30px;
|
|
272
282
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateHtml.js","sourceRoot":"","sources":["../../../src/transformers/generators/generateHtml.ts"],"names":[],"mappings":"AAEA,SAAS,gBAAgB,CAAC,QAAgB;IACxC,IAAI,QAAQ,IAAI,GAAG;QAAE,OAAO,SAAS,CAAC;IACtC,IAAI,QAAQ,IAAI,GAAG;QAAE,OAAO,SAAS,CAAC;IACtC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB;IACrC,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,GAAG,GAA2B;QAClC,GAAG,EAAE,OAAO;QACZ,GAAG,EAAE,MAAM;QACX,GAAG,EAAE,MAAM;QACX,GAAG,EAAE,QAAQ;QACb,GAAG,EAAE,QAAQ;KACd,CAAC;IACF,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,uBAAuB,CAAC,gBAAwD;IACvF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC7C,OAAO,gBAAgB;SACpB,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACX,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChD,OAAO;wCAC2B,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC;yCACxB,GAAG,CAAC,SAAS;yCACb,GAAG,CAAC,UAAU;yCACd,GAAG,CAAC,YAAY;yCAChB,GAAG,CAAC,cAAc;sDACL,QAAQ,KAAK,UAAU;wEACL,QAAQ,YAAY,UAAU;kBACpF,CAAC;IACf,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,eAAe,CAAC,KAAkC;IACzD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAuC,CAAC;IAClE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"generateHtml.js","sourceRoot":"","sources":["../../../src/transformers/generators/generateHtml.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,4 +3,6 @@ export type ReportRenderOptions = {
|
|
|
3
3
|
maxAnnotations?: number;
|
|
4
4
|
};
|
|
5
5
|
export declare function generateAndWriteReport(outputPath: string, coverageObj: AnyCoverageObject, format: string, formatAmount: number, options?: ReportRenderOptions): Promise<string>;
|
|
6
|
+
export declare function getReportPath(outputPath: string, format: string, formatAmount: number): string;
|
|
7
|
+
export declare function generateReportContent(coverageObj: AnyCoverageObject, format: string, options?: ReportRenderOptions): string;
|
|
6
8
|
export declare function getExtensionForFormat(format: string): string;
|
|
@@ -29,25 +29,24 @@ const STRING_FORMAT_RENDERERS = {
|
|
|
29
29
|
};
|
|
30
30
|
export async function generateAndWriteReport(outputPath, coverageObj, format, formatAmount, options) {
|
|
31
31
|
const content = generateReportContent(coverageObj, format, options);
|
|
32
|
+
const filePath = getReportPath(outputPath, format, formatAmount);
|
|
33
|
+
await writeFile(filePath, content);
|
|
34
|
+
return filePath;
|
|
35
|
+
}
|
|
36
|
+
export function getReportPath(outputPath, format, formatAmount) {
|
|
32
37
|
const extension = HandlerRegistry.getExtension(format);
|
|
33
38
|
const base = basename(outputPath, extname(outputPath)); // e.g., 'coverage'
|
|
34
39
|
const dir = dirname(outputPath);
|
|
35
40
|
const suffix = formatAmount > 1 ? `-${format}` : '';
|
|
36
|
-
|
|
37
|
-
await writeFile(filePath, content, 'utf-8');
|
|
38
|
-
return filePath;
|
|
41
|
+
return join(dir, `${base}${suffix}${extension}`);
|
|
39
42
|
}
|
|
40
|
-
function generateReportContent(coverageObj, format, options) {
|
|
43
|
+
export function generateReportContent(coverageObj, format, options) {
|
|
41
44
|
const renderer = STRING_FORMAT_RENDERERS[format];
|
|
42
45
|
return renderer ? renderer(coverageObj, options) : generateXmlContent(coverageObj, format);
|
|
43
46
|
}
|
|
44
47
|
function generateXmlContent(coverageObj, format) {
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
let xml = builder.build(coverageObj);
|
|
48
|
-
if (isHeadless) {
|
|
49
|
-
xml = xml.replace(/^<\?xml[^>]*>\s*/i, '');
|
|
50
|
-
}
|
|
48
|
+
// XmlBuilder never emits an XML declaration, so the format's header is simply prepended.
|
|
49
|
+
const xml = new XmlBuilder(builderOptions).build(coverageObj);
|
|
51
50
|
return prependXmlHeader(xml, format).trimEnd();
|
|
52
51
|
}
|
|
53
52
|
function generateLcov(coverageObj) {
|
|
@@ -70,10 +69,8 @@ function generateLcov(coverageObj) {
|
|
|
70
69
|
.join('\n');
|
|
71
70
|
}
|
|
72
71
|
function prependXmlHeader(xml, format) {
|
|
73
|
-
// Remove any existing XML declaration to avoid duplicates
|
|
74
|
-
const stripped = xml.replace(/^<\?xml[^>]*>\s*/i, '');
|
|
75
72
|
const config = isXmlReportFormat(format) ? XML_HEADER_CONFIG[format] : undefined;
|
|
76
|
-
return [config?.xmlDecl ?? '<?xml version="1.0"?>', config?.doctype,
|
|
73
|
+
return [config?.xmlDecl ?? '<?xml version="1.0"?>', config?.doctype, xml].filter(Boolean).join('\n');
|
|
77
74
|
}
|
|
78
75
|
export function getExtensionForFormat(format) {
|
|
79
76
|
return HandlerRegistry.getExtension(format);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reportGenerator.js","sourceRoot":"","sources":["../../src/transformers/reportGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAS1E,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAMpE,SAAS,iBAAiB,CAAC,MAAc;IACvC,OAAO,MAAM,IAAI,iBAAiB,CAAC;AACrC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,uBAAuB,GAAmF;IAC9G,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,GAAyB,CAAC;IAC1D,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,GAAyB,CAAC;IACtD,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAA6B,CAAC;IAClE,gBAAgB,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,qBAAqB,CAAC,GAAkC,EAAE,IAAI,EAAE,cAAc,CAAC;IAChH,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,cAAc,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;CACjD,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,UAAkB,EAClB,WAA8B,EAC9B,MAAc,EACd,YAAoB,EACpB,OAA6B;IAE7B,MAAM,OAAO,GAAG,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACpE,MAAM,SAAS,GAAG,eAAe,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"reportGenerator.js","sourceRoot":"","sources":["../../src/transformers/reportGenerator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type CoverageErrorCode = 'UNKNOWN_INPUT_FORMAT' | 'MIXED_INPUT_TYPES' | 'UNSUPPORTED_FORMAT' | 'NO_SFDX_PROJECT';
|
|
2
|
+
/**
|
|
3
|
+
* Error thrown by the transformer for known failure cases.
|
|
4
|
+
* Check `code` instead of matching on `message`.
|
|
5
|
+
*/
|
|
6
|
+
export declare class CoverageError extends Error {
|
|
7
|
+
readonly code: CoverageErrorCode;
|
|
8
|
+
constructor(message: string, options: {
|
|
9
|
+
code: CoverageErrorCode;
|
|
10
|
+
cause?: unknown;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* Error thrown by the transformer for known failure cases.
|
|
4
|
+
* Check `code` instead of matching on `message`.
|
|
5
|
+
*/
|
|
6
|
+
export class CoverageError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
constructor(message, options) {
|
|
9
|
+
super(message, { cause: options.cause });
|
|
10
|
+
this.name = 'CoverageError';
|
|
11
|
+
this.code = options.code;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAIb;;;GAGG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtB,IAAI,CAAoB;IAExC,YAAmB,OAAe,EAAE,OAAqD;QACvF,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;CACF"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { getRepoRoot } from './getRepoRoot.js';
|
|
5
|
-
export async function getPackageDirectories(ignoreDirectories) {
|
|
6
|
-
const { repoRoot, dxConfigFilePath } = (await getRepoRoot());
|
|
5
|
+
export async function getPackageDirectories(ignoreDirectories, cwd) {
|
|
6
|
+
const { repoRoot, dxConfigFilePath } = (await getRepoRoot(cwd));
|
|
7
7
|
const sfdxProjectRaw = await readFile(dxConfigFilePath, 'utf-8');
|
|
8
8
|
const sfdxProject = JSON.parse(sfdxProjectRaw);
|
|
9
9
|
const packageDirectories = sfdxProject.packageDirectories
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPackageDirectories.js","sourceRoot":"","sources":["../../src/utils/getPackageDirectories.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,iBAA2B;
|
|
1
|
+
{"version":3,"file":"getPackageDirectories.js","sourceRoot":"","sources":["../../src/utils/getPackageDirectories.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,iBAA2B,EAC3B,GAAY;IAEZ,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,CAAC,MAAM,WAAW,CAAC,GAAG,CAAC,CAG7D,CAAC;IAEF,MAAM,cAAc,GAAW,MAAM,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IACzE,MAAM,WAAW,GAAgB,IAAI,CAAC,KAAK,CAAC,cAAc,CAAgB,CAAC;IAE3E,MAAM,kBAAkB,GAAG,WAAW,CAAC,kBAAkB;SACtD,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,4BAA4B;SAC/F,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAEzD,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,CAAC;AAC1C,CAAC"}
|
package/lib/utils/getRepoRoot.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import { access } from 'node:fs/promises';
|
|
3
|
-
import { dirname, join } from 'node:path';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
import { CoverageError } from './errors.js';
|
|
4
5
|
async function findRepoRoot(dir) {
|
|
5
6
|
const filePath = join(dir, 'sfdx-project.json');
|
|
6
7
|
try {
|
|
@@ -12,14 +13,16 @@ async function findRepoRoot(dir) {
|
|
|
12
13
|
const parentDir = dirname(dir);
|
|
13
14
|
if (dir === parentDir) {
|
|
14
15
|
// Reached the root without finding the file, throw an error
|
|
15
|
-
throw new
|
|
16
|
+
throw new CoverageError('sfdx-project.json not found in any parent directory.', {
|
|
17
|
+
code: 'NO_SFDX_PROJECT',
|
|
18
|
+
cause: error,
|
|
19
|
+
});
|
|
16
20
|
}
|
|
17
21
|
// Recursively search in the parent directory
|
|
18
22
|
return findRepoRoot(parentDir);
|
|
19
23
|
}
|
|
20
24
|
}
|
|
21
|
-
export async function getRepoRoot() {
|
|
22
|
-
|
|
23
|
-
return findRepoRoot(currentDir);
|
|
25
|
+
export async function getRepoRoot(cwd) {
|
|
26
|
+
return findRepoRoot(cwd === undefined ? process.cwd() : resolve(cwd));
|
|
24
27
|
}
|
|
25
28
|
//# sourceMappingURL=getRepoRoot.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getRepoRoot.js","sourceRoot":"","sources":["../../src/utils/getRepoRoot.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"getRepoRoot.js","sourceRoot":"","sources":["../../src/utils/getRepoRoot.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,KAAK,UAAU,YAAY,CAAC,GAAW;IACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;IAChD,IAAI,CAAC;QACH,6DAA6D;QAC7D,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvB,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,4DAA4D;YAC5D,MAAM,IAAI,aAAa,CAAC,sDAAsD,EAAE;gBAC9E,IAAI,EAAE,iBAAiB;gBACvB,KAAK,EAAE,KAAK;aACb,CAAC,CAAC;QACL,CAAC;QACD,6CAA6C;QAC7C,OAAO,YAAY,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAY;IAEZ,OAAO,YAAY,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AACxE,CAAC"}
|
package/lib/utils/types.d.ts
CHANGED
|
@@ -49,14 +49,80 @@ export type LineTotals = {
|
|
|
49
49
|
totalLines: number;
|
|
50
50
|
coveredLines: number;
|
|
51
51
|
};
|
|
52
|
+
/** Per-file coverage totals returned by the programmatic API. */
|
|
53
|
+
export type FileCoverageSummary = {
|
|
54
|
+
/** Path relative to the repo root, using forward slashes. */
|
|
55
|
+
path: string;
|
|
56
|
+
/** Apex class or trigger name as reported by Salesforce. */
|
|
57
|
+
name: string;
|
|
58
|
+
totalLines: number;
|
|
59
|
+
coveredLines: number;
|
|
60
|
+
/** Covered lines divided by total lines (0-1). 0 when the file has no coverable lines. */
|
|
61
|
+
lineRate: number;
|
|
62
|
+
/** Line numbers with no coverage, ascending. */
|
|
63
|
+
uncoveredLines: number[];
|
|
64
|
+
};
|
|
52
65
|
export type ProcessResult = {
|
|
53
66
|
processed: number;
|
|
67
|
+
files: FileCoverageSummary[];
|
|
54
68
|
} & LineTotals;
|
|
55
69
|
export type TransformOptions = {
|
|
56
70
|
minCoverage?: number;
|
|
57
71
|
maxAnnotations?: number;
|
|
58
72
|
excludePatterns?: string[];
|
|
59
73
|
};
|
|
74
|
+
/** Output formats supported by the transformer. */
|
|
75
|
+
export type CoverageFormat = 'clover' | 'cobertura' | 'github-actions' | 'html' | 'jacoco' | 'json' | 'json-summary' | 'lcovonly' | 'markdown' | 'opencover' | 'simplecov' | 'sonar';
|
|
76
|
+
/** Options for {@link transformCoverage}. */
|
|
77
|
+
export type TransformCoverageOptions = {
|
|
78
|
+
/**
|
|
79
|
+
* Coverage inputs: paths to Salesforce CLI coverage JSON files and/or already-parsed JSON.
|
|
80
|
+
* All inputs must be the same type (deploy or test). Covered lines are unioned across inputs.
|
|
81
|
+
*/
|
|
82
|
+
inputs: Array<string | CoverageInput>;
|
|
83
|
+
/** Output formats. Defaults to `['sonar']`. */
|
|
84
|
+
formats?: CoverageFormat[];
|
|
85
|
+
/**
|
|
86
|
+
* Base path for written reports. Defaults to `coverage.xml`. With multiple formats, the format
|
|
87
|
+
* name is appended (e.g. `coverage-sonar.xml`). Ignored when `write` is false.
|
|
88
|
+
*/
|
|
89
|
+
outputReport?: string;
|
|
90
|
+
/** Write reports to disk. Defaults to true. When false, report contents are only returned. */
|
|
91
|
+
write?: boolean;
|
|
92
|
+
/** Directory to search upward from for `sfdx-project.json`. Defaults to `process.cwd()`. */
|
|
93
|
+
cwd?: string;
|
|
94
|
+
/** Package directory paths (as written in `sfdx-project.json`) to skip. */
|
|
95
|
+
ignorePackageDirectories?: string[];
|
|
96
|
+
/** Glob patterns matched against repo-relative file paths to exclude. */
|
|
97
|
+
excludePatterns?: string[];
|
|
98
|
+
/** Minimum overall line coverage percentage (0-100). Sets `passed` to false when not met. */
|
|
99
|
+
minCoverage?: number;
|
|
100
|
+
/** Maximum annotations for the `github-actions` format. */
|
|
101
|
+
maxAnnotations?: number;
|
|
102
|
+
};
|
|
103
|
+
export type GeneratedReport = {
|
|
104
|
+
format: CoverageFormat;
|
|
105
|
+
/** Path the report was written to. Undefined when `write` is false. */
|
|
106
|
+
path?: string;
|
|
107
|
+
content: string;
|
|
108
|
+
};
|
|
109
|
+
export type CoverageSummary = {
|
|
110
|
+
/** Overall covered lines divided by total lines (0-1). */
|
|
111
|
+
lineRate: number;
|
|
112
|
+
coveredLines: number;
|
|
113
|
+
totalLines: number;
|
|
114
|
+
fileCount: number;
|
|
115
|
+
/** Per-file totals, sorted by path. */
|
|
116
|
+
files: FileCoverageSummary[];
|
|
117
|
+
};
|
|
118
|
+
/** Result of {@link transformCoverage}. */
|
|
119
|
+
export type TransformCoverageResult = {
|
|
120
|
+
reports: GeneratedReport[];
|
|
121
|
+
summary: CoverageSummary;
|
|
122
|
+
warnings: string[];
|
|
123
|
+
/** False only when `minCoverage` is set and overall coverage is below it. */
|
|
124
|
+
passed: boolean;
|
|
125
|
+
};
|
|
60
126
|
type SonarLine = {
|
|
61
127
|
'@lineNumber': number;
|
|
62
128
|
'@covered': boolean;
|
|
@@ -334,12 +400,20 @@ export type HtmlFileCoverage = {
|
|
|
334
400
|
coveredLines: number;
|
|
335
401
|
uncoveredLines: number;
|
|
336
402
|
lineRate: number;
|
|
337
|
-
lines:
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
403
|
+
lines: HtmlLineCoverage[];
|
|
404
|
+
};
|
|
405
|
+
/**
|
|
406
|
+
* One row in the HTML line view. When source content is available, every
|
|
407
|
+
* line of the file is listed; lines absent from the coverage data are marked
|
|
408
|
+
* `executable: false` (comments, signatures, braces, blank lines).
|
|
409
|
+
*/
|
|
410
|
+
export type HtmlLineCoverage = {
|
|
411
|
+
lineNumber: number;
|
|
412
|
+
hitCount: number;
|
|
413
|
+
covered: boolean;
|
|
414
|
+
content?: string;
|
|
415
|
+
/** False for non-executable lines. Omitted or true for lines in the coverage data. */
|
|
416
|
+
executable?: boolean;
|
|
343
417
|
};
|
|
344
418
|
/** Summary for a package directory (e.g. force-app) in the HTML report */
|
|
345
419
|
export type HtmlPackageSummary = {
|
package/oclif.manifest.json
CHANGED
|
@@ -91,7 +91,6 @@
|
|
|
91
91
|
},
|
|
92
92
|
"max-annotations": {
|
|
93
93
|
"name": "max-annotations",
|
|
94
|
-
"required": false,
|
|
95
94
|
"summary": "Maximum number of GitHub Actions ::warning annotations to emit when using --format github-actions. Defaults to 50. Annotations beyond this limit are summarised in a ::notice line.",
|
|
96
95
|
"default": 50,
|
|
97
96
|
"hasDynamicHelp": false,
|
|
@@ -131,5 +130,5 @@
|
|
|
131
130
|
]
|
|
132
131
|
}
|
|
133
132
|
},
|
|
134
|
-
"version": "4.
|
|
133
|
+
"version": "4.2.0"
|
|
135
134
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apex-code-coverage-transformer",
|
|
3
3
|
"description": "Transform Salesforce Apex code coverage JSON for SonarQube, SonarCloud, GitHub, GitLab, Azure, and Bitbucket",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.2.0",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@oclif/core": "5.1.
|
|
6
|
+
"@oclif/core": "5.1.11",
|
|
7
7
|
"@salesforce/core": "9.4.4",
|
|
8
8
|
"@salesforce/sf-plugins-core": "13.0.8"
|
|
9
9
|
},
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
"@biomejs/biome": "2.6.5",
|
|
13
13
|
"@commitlint/cli": "21.2.4",
|
|
14
14
|
"@commitlint/config-conventional": "21.2.4",
|
|
15
|
-
"@salesforce/cli-plugins-testkit": "5.3.
|
|
15
|
+
"@salesforce/cli-plugins-testkit": "5.3.90",
|
|
16
16
|
"@salesforce/dev-config": "4.3.3",
|
|
17
17
|
"@stryker-mutator/core": "10.1.1",
|
|
18
18
|
"@stryker-mutator/vitest-runner": "10.1.1",
|
|
19
19
|
"@types/node": "26.6.6",
|
|
20
|
-
"@vitest/coverage-v8": "5.0
|
|
20
|
+
"@vitest/coverage-v8": "5.1.0",
|
|
21
21
|
"esbuild": "0.28.2",
|
|
22
22
|
"husky": "9.1.7",
|
|
23
23
|
"knip": "6.44.1",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"shx": "0.4.0",
|
|
28
28
|
"tsx": "4.23.15",
|
|
29
29
|
"typescript": "7.0.2",
|
|
30
|
-
"vitest": "5.0
|
|
30
|
+
"vitest": "5.1.0",
|
|
31
31
|
"wireit": "0.15.0"
|
|
32
32
|
},
|
|
33
33
|
"engines": {
|
|
@@ -324,7 +324,14 @@
|
|
|
324
324
|
"output": []
|
|
325
325
|
}
|
|
326
326
|
},
|
|
327
|
-
"exports":
|
|
327
|
+
"exports": {
|
|
328
|
+
".": {
|
|
329
|
+
"types": "./lib/index.d.ts",
|
|
330
|
+
"import": "./lib/index.js"
|
|
331
|
+
},
|
|
332
|
+
"./package.json": "./package.json"
|
|
333
|
+
},
|
|
334
|
+
"types": "./lib/index.d.ts",
|
|
328
335
|
"type": "module",
|
|
329
336
|
"author": "Matt Carvin",
|
|
330
337
|
"repository": {
|