apex-code-coverage-transformer 2.22.0 → 2.23.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 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
+ ## [2.23.0](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v2.22.1...v2.23.0) (2026-06-17)
9
+
10
+
11
+ ### Features
12
+
13
+ * support multiple coverage JSON inputs with union merge ([#317](https://github.com/mcarvin8/apex-code-coverage-transformer/issues/317)) ([43ccda6](https://github.com/mcarvin8/apex-code-coverage-transformer/commit/43ccda6c2542cbb0be36faba37682a23b76758b8))
14
+
15
+ ## [2.22.1](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v2.22.0...v2.22.1) (2026-06-15)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **deps:** replace minimatch with in-house glob matcher ([#312](https://github.com/mcarvin8/apex-code-coverage-transformer/issues/312)) ([c1ec8c8](https://github.com/mcarvin8/apex-code-coverage-transformer/commit/c1ec8c81673f47bf22f2cbe68294ce75a59d0873))
21
+
8
22
  ## [2.22.0](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v2.21.0...v2.22.0) (2026-06-12)
9
23
 
10
24
 
package/README.md CHANGED
@@ -69,6 +69,9 @@ sf plugins install apex-code-coverage-transformer@latest
69
69
 
70
70
  # Multiple formats at once
71
71
  sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -f "sonar" -f "cobertura" -f "jacoco"
72
+
73
+ # Merge multiple coverage JSONs of the same type (e.g. two deploy runs)
74
+ sf acc-transformer transform -j "coverage/coverage/coverage.json" -j "coverage2/coverage/coverage.json" -r "coverage.xml" -f "sonar"
72
75
  ```
73
76
 
74
77
  3. **Upload to your tool** — see [CI/CD Integration](#cicd-integration).
@@ -111,11 +114,16 @@ Works with [sfdx-hardis](https://github.com/hardisgroupcom/sfdx-hardis):
111
114
 
112
115
  ```
113
116
  USAGE
114
- $ sf acc-transformer transform -j <value> [-r <value>] [-f <value>] [-i <value>] [-e <value>]
115
- [--min-coverage <value>] [--max-annotations <value>] [--json]
117
+ $ sf acc-transformer transform -j <value>... [-r <value>] [-f <value>] [-i <value>] [-e <value>]
118
+ [--min-coverage <value>] [--max-annotations <value>] [--json]
116
119
 
117
120
  FLAGS
118
- -j, --coverage-json=<value> Path to the code coverage JSON from deploy or test.
121
+ -j, --coverage-json=<value>... Path to a code coverage JSON from deploy or test. Repeat to merge
122
+ multiple files. When the same Apex file appears in more than one
123
+ input, covered lines are unioned across all inputs — if a line is
124
+ covered in any input it is counted as covered in the final report,
125
+ even if it is uncovered in others. All files must be the same type
126
+ (deploy or test).
119
127
  -r, --output-report=<value> Output path (e.g. coverage.xml). Default: coverage.[xml|info] by format.
120
128
  -f, --format=<value> Output format (repeat for multiple). Default: sonar.
121
129
  Multiple formats append to filename, e.g. coverage-sonar.xml.
@@ -154,18 +162,34 @@ Use `-f` / `--format` to choose the output format. Multiple `-f` values produce
154
162
 
155
163
  ### Shared setup (GitHub Actions)
156
164
 
157
- All GitHub Actions examples below assume these steps run first:
165
+ All GitHub Actions examples below assume these steps run first for deployments (update `sf project deploy start` command to `sf apex run test` to invoke tests directly in an org):
158
166
 
159
167
  ```yaml
160
- - uses: actions/checkout@v4
161
- - name: Install Salesforce CLI
162
- run: npm install -g @salesforce/cli
163
- - name: Install Coverage Transformer Plugin
164
- run: echo y | sf plugins install apex-code-coverage-transformer
165
- - name: Authenticate to Salesforce
166
- run: sf org login sfdx-url --sfdx-url-file ${{ secrets.SFDX_AUTH_URL }} --alias ci-org
167
- - name: Run Apex Tests
168
- run: sf apex run test --code-coverage --output-dir coverage --target-org ci-org
168
+ jobs:
169
+ deploy:
170
+ runs-on: ubuntu-latest
171
+ steps:
172
+ - name: Checkout
173
+ uses: actions/checkout@v4
174
+ with:
175
+ fetch-depth: 0
176
+
177
+ - name: Set up Node.js
178
+ uses: actions/setup-node@v4
179
+ with:
180
+ node-version: '20'
181
+
182
+ - name: Install Salesforce CLI
183
+ run: npm install -g @salesforce/cli@latest
184
+
185
+ - name: Install Apex Code Coverage Transformer plugin
186
+ run: echo y | sf plugins install apex-code-coverage-transformer
187
+
188
+ - name: Authenticate to Salesforce
189
+ run: sf org login sfdx-url --sfdx-url-file ${{ secrets.SFDX_AUTH_URL }} --alias ci-org
190
+
191
+ - name: Deploy with Apex Tests
192
+ run: sf project deploy start --test-level RunLocalTests --coverage-formatters json --results-dir "coverage"
169
193
  ```
170
194
 
171
195
  ### Codecov
@@ -295,6 +319,8 @@ Create `.apexcodecovtransformer.config.json` in the project root to transform co
295
319
  - `sf hardis project deploy smart` (if sfdx-hardis installed and `COVERAGE_FORMATTER_JSON=true`)
296
320
  - `sf hardis org test apex` (if sfdx-hardis installed)
297
321
 
322
+ > **Note:** The hook fires once per command and always processes a single coverage JSON. It cannot merge multiple inputs. If you need to merge coverage from multiple runs (e.g. split test batches), run the `sf acc-transformer transform` command manually with multiple `-j` flags after all runs complete.
323
+
298
324
  Sample configs: [Salesforce CLI](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/defaults/salesforce-cli/.apexcodecovtransformer.config.json), [SFDX Hardis](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/defaults/sfdx-hardis/.apexcodecovtransformer.config.json).
299
325
 
300
326
  | Key | Required | Description |
@@ -330,6 +356,12 @@ Resolve by renaming one of the files or using `--ignore-package-directory` to ex
330
356
  Warning: None of the files listed in the coverage JSON were processed. The coverage report will be empty.
331
357
  ```
332
358
 
359
+ **Mixed coverage types** — All `-j` inputs must be the same type (either all deploy or all test):
360
+
361
+ ```
362
+ Error (1): All coverage JSON files must be the same type (deploy or test).
363
+ ```
364
+
333
365
  **Unknown JSON structure** — Input is not from deploy or test coverage:
334
366
 
335
367
  ```
@@ -372,4 +404,4 @@ The coverage report has been written to: coverage.xml
372
404
 
373
405
  ## License
374
406
 
375
- [MIT](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/LICENSE.md)
407
+ [MIT](LICENSE.md)
@@ -5,7 +5,7 @@ export default class TransformerTransform extends SfCommand<TransformerTransform
5
5
  static readonly description: string;
6
6
  static readonly examples: string[];
7
7
  static readonly flags: {
8
- 'coverage-json': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ 'coverage-json': import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
9
9
  'output-report': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
10
  format: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
11
  'ignore-package-directory': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -15,6 +15,7 @@ export default class TransformerTransform extends SfCommand {
15
15
  summary: messages.getMessage('flags.coverage-json.summary'),
16
16
  char: 'j',
17
17
  required: true,
18
+ multiple: true,
18
19
  }),
19
20
  'output-report': Flags.file({
20
21
  summary: messages.getMessage('flags.output-report.summary'),
@@ -1 +1 @@
1
- {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../src/commands/acc-transformer/transform.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../src/commands/acc-transformer/transform.ts"],"names":[],"mappings":"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"}
@@ -27,10 +27,11 @@ export class BaseHandler {
27
27
  */
28
28
  // eslint-disable-next-line class-methods-use-this
29
29
  extractLinesByStatus(lines, covered) {
30
- return Object.entries(lines)
30
+ const filtered = Object.entries(lines)
31
31
  .filter(([, hits]) => (covered ? hits > 0 : hits === 0))
32
- .map(([line]) => Number(line))
33
- .sort((a, b) => a - b);
32
+ .map(([line]) => Number(line));
33
+ // Stryker disable next-line MethodExpression,ArithmeticOperator -- equivalent mutants: Object.entries already returns integer keys ascending; a+b never negative so insertion sort never swaps
34
+ return filtered.sort((a, b) => a - b);
34
35
  }
35
36
  /**
36
37
  * Get covered and uncovered line numbers from a lines record.
@@ -1 +1 @@
1
- {"version":3,"file":"BaseHandler.js","sourceRoot":"","sources":["../../src/handlers/BaseHandler.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAkBb;;;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;CAsBF"}
1
+ {"version":3,"file":"BaseHandler.js","sourceRoot":"","sources":["../../src/handlers/BaseHandler.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAkBb;;;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,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;aACnC,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,CAAC;QACjC,+LAA+L;QAC/L,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACxC,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;CAsBF"}
@@ -0,0 +1,3 @@
1
+ import { DeployCoverageData, TestCoverageData } from '../utils/types.js';
2
+ export declare function mergeDeployCoverageData(inputs: DeployCoverageData[]): DeployCoverageData;
3
+ export declare function mergeTestCoverageData(inputs: TestCoverageData[][]): TestCoverageData[];
@@ -0,0 +1,38 @@
1
+ 'use strict';
2
+ export function mergeDeployCoverageData(inputs) {
3
+ const merged = {};
4
+ for (const input of inputs) {
5
+ for (const [className, fileInfo] of Object.entries(input)) {
6
+ if (!merged[className]) {
7
+ merged[className] = { ...fileInfo, s: { ...fileInfo.s } };
8
+ }
9
+ else {
10
+ for (const [line, hit] of Object.entries(fileInfo.s)) {
11
+ merged[className].s[line] = Math.max(merged[className].s[line] ?? 0, hit);
12
+ }
13
+ }
14
+ }
15
+ }
16
+ return merged;
17
+ }
18
+ export function mergeTestCoverageData(inputs) {
19
+ const byName = new Map();
20
+ for (const input of inputs) {
21
+ for (const entry of input) {
22
+ if (!byName.has(entry.name)) {
23
+ byName.set(entry.name, { ...entry, lines: { ...entry.lines } });
24
+ }
25
+ else {
26
+ const existing = byName.get(entry.name);
27
+ for (const [line, hit] of Object.entries(entry.lines)) {
28
+ existing.lines[line] = Math.max(existing.lines[line] ?? 0, hit);
29
+ }
30
+ existing.totalLines = Object.keys(existing.lines).length;
31
+ existing.totalCovered = Object.values(existing.lines).filter((v) => v === 1).length;
32
+ existing.coveredPercent = existing.totalLines > 0 ? (existing.totalCovered / existing.totalLines) * 100 : 0;
33
+ }
34
+ }
35
+ }
36
+ return [...byName.values()];
37
+ }
38
+ //# sourceMappingURL=coverageDataMerger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverageDataMerger.js","sourceRoot":"","sources":["../../src/transformers/coverageDataMerger.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAIb,MAAM,UAAU,uBAAuB,CAAC,MAA4B;IAClE,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;gBACvB,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC;YAC5D,CAAC;iBAAM,CAAC;gBACN,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;oBACrD,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;gBAC5E,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAA4B;IAChE,MAAM,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;IACnD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAClE,CAAC;iBAAM,CAAC;gBACN,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAE,CAAC;gBACzC,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;oBACtD,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;gBAClE,CAAC;gBACD,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;gBACzD,QAAQ,CAAC,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;gBACpF,QAAQ,CAAC,cAAc,GAAG,QAAQ,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9G,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { getCoverageHandler } from '../handlers/getHandler.js';
2
+ import { DeployCoverageData, TestCoverageData, CoverageProcessingContext, LineTotals, ProcessResult } from '../utils/types.js';
3
+ export declare function createHandlers(formats: string[]): Map<string, ReturnType<typeof getCoverageHandler>>;
4
+ export declare function countLines(lines: Record<string, number>): LineTotals;
5
+ export declare function processDeployCoverage(data: DeployCoverageData, context: CoverageProcessingContext): Promise<ProcessResult>;
6
+ export declare function processTestCoverage(data: TestCoverageData[], context: CoverageProcessingContext): Promise<ProcessResult>;
@@ -0,0 +1,87 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ 'use strict';
3
+ import { readFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { matchesGlob } from '../utils/globMatcher.js';
6
+ import { getCoverageHandler } from '../handlers/getHandler.js';
7
+ import { findFilePath } from '../utils/findFilePath.js';
8
+ import { setCoveredLines } from '../utils/setCoveredLines.js';
9
+ import { mapLimit } from '../utils/mapLimit.js';
10
+ export function createHandlers(formats) {
11
+ const handlers = new Map();
12
+ for (const format of formats) {
13
+ handlers.set(format, getCoverageHandler(format));
14
+ }
15
+ return handlers;
16
+ }
17
+ function hasSourceContent(result) {
18
+ return typeof result === 'object' && result !== null && 'sourceContent' in result;
19
+ }
20
+ async function readSourceFile(absolutePath) {
21
+ try {
22
+ return await readFile(absolutePath, 'utf-8');
23
+ }
24
+ catch {
25
+ return undefined;
26
+ }
27
+ }
28
+ export function countLines(lines) {
29
+ const totalLines = Object.keys(lines).length;
30
+ const coveredLines = Object.values(lines).filter((v) => v === 1).length;
31
+ return { totalLines, coveredLines };
32
+ }
33
+ export async function processDeployCoverage(data, context) {
34
+ let processed = 0;
35
+ let totalLines = 0;
36
+ let coveredLines = 0;
37
+ await mapLimit(Object.keys(data), context.concurrencyLimit, async (fileName) => {
38
+ const fileInfo = data[fileName];
39
+ const formattedName = fileName.replace(/no-map[\\/]+/, '');
40
+ const path = findFilePath(formattedName, context.filePathCache);
41
+ if (!path) {
42
+ context.warnings.push(`The file name ${formattedName} was not found in any package directory.`);
43
+ return;
44
+ }
45
+ if (context.excludePatterns.some((pattern) => matchesGlob(path, pattern, { matchBase: true }))) {
46
+ return;
47
+ }
48
+ const setCoveredResult = await setCoveredLines(path, context.repoRoot, fileInfo.s, context.handlers.has('html'));
49
+ const updatedLines = hasSourceContent(setCoveredResult) ? setCoveredResult.updatedLines : setCoveredResult;
50
+ const sourceContent = hasSourceContent(setCoveredResult) ? setCoveredResult.sourceContent : undefined;
51
+ fileInfo.s = updatedLines;
52
+ const counts = countLines(updatedLines);
53
+ totalLines += counts.totalLines;
54
+ coveredLines += counts.coveredLines;
55
+ for (const handler of context.handlers.values()) {
56
+ handler.processFile(path, formattedName, updatedLines, sourceContent);
57
+ }
58
+ processed++;
59
+ });
60
+ return { processed, totalLines, coveredLines };
61
+ }
62
+ export async function processTestCoverage(data, context) {
63
+ let processed = 0;
64
+ let totalLines = 0;
65
+ let coveredLines = 0;
66
+ await mapLimit(data, context.concurrencyLimit, async (entry) => {
67
+ const formattedName = entry.name.replace(/no-map[\\/]+/, '');
68
+ const path = findFilePath(formattedName, context.filePathCache);
69
+ if (!path) {
70
+ context.warnings.push(`The file name ${formattedName} was not found in any package directory.`);
71
+ return;
72
+ }
73
+ if (context.excludePatterns.some((pattern) => matchesGlob(path, pattern, { matchBase: true }))) {
74
+ return;
75
+ }
76
+ const counts = countLines(entry.lines);
77
+ totalLines += counts.totalLines;
78
+ coveredLines += counts.coveredLines;
79
+ const sourceContent = context.handlers.has('html') ? await readSourceFile(join(context.repoRoot, path)) : undefined;
80
+ for (const handler of context.handlers.values()) {
81
+ handler.processFile(path, formattedName, entry.lines, sourceContent);
82
+ }
83
+ processed++;
84
+ });
85
+ return { processed, totalLines, coveredLines };
86
+ }
87
+ //# sourceMappingURL=coverageProcessor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverageProcessor.js","sourceRoot":"","sources":["../../src/transformers/coverageProcessor.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,6 @@
1
- export type TransformOptions = {
2
- minCoverage?: number;
3
- maxAnnotations?: number;
4
- excludePatterns?: string[];
5
- };
6
- export declare function transformCoverageReport(jsonFilePath: string, outputReportPath: string, formats: string[], ignoreDirs: string[], options?: TransformOptions): Promise<{
1
+ import { TransformOptions } from '../utils/types.js';
2
+ export { TransformOptions };
3
+ export declare function transformCoverageReport(jsonFilePaths: string[], outputReportPath: string, formats: string[], ignoreDirs: string[], options?: TransformOptions): Promise<{
7
4
  finalPaths: string[];
8
5
  warnings: string[];
9
6
  lineRate: number;
@@ -1,27 +1,33 @@
1
1
  /* eslint-disable no-await-in-loop */
2
- import { readFile } from 'node:fs/promises';
3
- import { join } from 'node:path';
4
- import { minimatch } from 'minimatch';
5
- import { getCoverageHandler } from '../handlers/getHandler.js';
2
+ 'use strict';
6
3
  import { getPackageDirectories } from '../utils/getPackageDirectories.js';
7
- import { findFilePath } from '../utils/findFilePath.js';
8
4
  import { buildFilePathCache } from '../utils/buildFilePathCache.js';
9
- import { setCoveredLines } from '../utils/setCoveredLines.js';
10
5
  import { getConcurrencyThreshold } from '../utils/getConcurrencyThreshold.js';
11
6
  import { checkCoverageDataType } from '../utils/setCoverageDataType.js';
12
- import { mapLimit } from '../utils/mapLimit.js';
7
+ import { tryReadJson } from '../utils/readJson.js';
13
8
  import { generateAndWriteReport } from './reportGenerator.js';
14
- export async function transformCoverageReport(jsonFilePath, outputReportPath, formats, ignoreDirs, options) {
9
+ import { mergeDeployCoverageData, mergeTestCoverageData } from './coverageDataMerger.js';
10
+ import { createHandlers, processDeployCoverage, processTestCoverage } from './coverageProcessor.js';
11
+ export async function transformCoverageReport(jsonFilePaths, outputReportPath, formats, ignoreDirs, options) {
15
12
  const warnings = [];
16
13
  const finalPaths = [];
17
14
  const formatAmount = formats.length;
18
- const jsonData = await tryReadJson(jsonFilePath, warnings);
19
- if (!jsonData)
15
+ const jsonDataItems = await Promise.all(jsonFilePaths.map((p) => tryReadJson(p, warnings)));
16
+ const validData = jsonDataItems.filter((d) => d !== null);
17
+ if (validData.length === 0)
20
18
  return { finalPaths: [outputReportPath], warnings, lineRate: 0 };
21
- const parsedData = JSON.parse(jsonData);
19
+ const parsedItems = validData.map((d) => JSON.parse(d));
20
+ const types = parsedItems.map(checkCoverageDataType);
21
+ if (types.some((t) => t === 'Unknown')) {
22
+ throw new Error('The provided JSON does not match a known coverage data format from the Salesforce deploy or test command.');
23
+ }
24
+ const uniqueTypes = [...new Set(types)];
25
+ if (uniqueTypes.length > 1) {
26
+ throw new Error('All coverage JSON files must be the same type (deploy or test).');
27
+ }
28
+ const commandType = uniqueTypes[0];
22
29
  const { repoRoot, packageDirectories } = await getPackageDirectories(ignoreDirs);
23
30
  const handlers = createHandlers(formats);
24
- const commandType = checkCoverageDataType(parsedData);
25
31
  const concurrencyLimit = getConcurrencyThreshold();
26
32
  // Build file path cache upfront to avoid O(n*m) directory traversals
27
33
  const { cache: filePathCache, warnings: cacheWarnings } = await buildFilePathCache(packageDirectories, repoRoot);
@@ -35,16 +41,9 @@ export async function transformCoverageReport(jsonFilePath, outputReportPath, fo
35
41
  filePathCache,
36
42
  excludePatterns: options?.excludePatterns ?? [],
37
43
  };
38
- let processResult;
39
- if (commandType === 'DeployCoverageData') {
40
- processResult = await processDeployCoverage(parsedData, context);
41
- }
42
- else if (commandType === 'TestCoverageData') {
43
- processResult = await processTestCoverage(parsedData, context);
44
- }
45
- else {
46
- throw new Error('The provided JSON does not match a known coverage data format from the Salesforce deploy or test command.');
47
- }
44
+ const processResult = commandType === 'DeployCoverageData'
45
+ ? await processDeployCoverage(mergeDeployCoverageData(parsedItems), context)
46
+ : await processTestCoverage(mergeTestCoverageData(parsedItems), context);
48
47
  if (processResult.processed === 0) {
49
48
  warnings.push('None of the files listed in the coverage JSON were processed. The coverage report will be empty.');
50
49
  }
@@ -60,90 +59,4 @@ export async function transformCoverageReport(jsonFilePath, outputReportPath, fo
60
59
  }
61
60
  return { finalPaths, warnings, lineRate };
62
61
  }
63
- function hasSourceContent(result) {
64
- return typeof result === 'object' && result !== null && 'sourceContent' in result;
65
- }
66
- async function readSourceFile(absolutePath) {
67
- try {
68
- return await readFile(absolutePath, 'utf-8');
69
- }
70
- catch {
71
- return undefined;
72
- }
73
- }
74
- async function tryReadJson(path, warnings) {
75
- try {
76
- return await readFile(path, 'utf-8');
77
- }
78
- catch {
79
- warnings.push(`Failed to read ${path}. Confirm file exists.`);
80
- return null;
81
- }
82
- }
83
- function createHandlers(formats) {
84
- const handlers = new Map();
85
- for (const format of formats) {
86
- handlers.set(format, getCoverageHandler(format));
87
- }
88
- return handlers;
89
- }
90
- function countLines(lines) {
91
- const totalLines = Object.keys(lines).length;
92
- const coveredLines = Object.values(lines).filter((v) => v === 1).length;
93
- return { totalLines, coveredLines };
94
- }
95
- async function processDeployCoverage(data, context) {
96
- let processed = 0;
97
- let totalLines = 0;
98
- let coveredLines = 0;
99
- await mapLimit(Object.keys(data), context.concurrencyLimit, async (fileName) => {
100
- const fileInfo = data[fileName];
101
- const formattedName = fileName.replace(/no-map[\\/]+/, '');
102
- const path = findFilePath(formattedName, context.filePathCache);
103
- if (!path) {
104
- context.warnings.push(`The file name ${formattedName} was not found in any package directory.`);
105
- return;
106
- }
107
- if (context.excludePatterns.some((pattern) => minimatch(path, pattern, { matchBase: true }))) {
108
- return;
109
- }
110
- const setCoveredResult = await setCoveredLines(path, context.repoRoot, fileInfo.s, context.handlers.has('html'));
111
- const updatedLines = hasSourceContent(setCoveredResult) ? setCoveredResult.updatedLines : setCoveredResult;
112
- const sourceContent = hasSourceContent(setCoveredResult) ? setCoveredResult.sourceContent : undefined;
113
- fileInfo.s = updatedLines;
114
- const counts = countLines(updatedLines);
115
- totalLines += counts.totalLines;
116
- coveredLines += counts.coveredLines;
117
- for (const handler of context.handlers.values()) {
118
- handler.processFile(path, formattedName, updatedLines, sourceContent);
119
- }
120
- processed++;
121
- });
122
- return { processed, totalLines, coveredLines };
123
- }
124
- async function processTestCoverage(data, context) {
125
- let processed = 0;
126
- let totalLines = 0;
127
- let coveredLines = 0;
128
- await mapLimit(data, context.concurrencyLimit, async (entry) => {
129
- const formattedName = entry.name.replace(/no-map[\\/]+/, '');
130
- const path = findFilePath(formattedName, context.filePathCache);
131
- if (!path) {
132
- context.warnings.push(`The file name ${formattedName} was not found in any package directory.`);
133
- return;
134
- }
135
- if (context.excludePatterns.some((pattern) => minimatch(path, pattern, { matchBase: true }))) {
136
- return;
137
- }
138
- const counts = countLines(entry.lines);
139
- totalLines += counts.totalLines;
140
- coveredLines += counts.coveredLines;
141
- const sourceContent = context.handlers.has('html') ? await readSourceFile(join(context.repoRoot, path)) : undefined;
142
- for (const handler of context.handlers.values()) {
143
- handler.processFile(path, formattedName, entry.lines, sourceContent);
144
- }
145
- processed++;
146
- });
147
- return { processed, totalLines, coveredLines };
148
- }
149
62
  //# sourceMappingURL=coverageTransformer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"coverageTransformer.js","sourceRoot":"","sources":["../../src/transformers/coverageTransformer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coverageTransformer.js","sourceRoot":"","sources":["../../src/transformers/coverageTransformer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function matchesGlob(filePath: string, pattern: string, options?: {
2
+ matchBase?: boolean;
3
+ }): boolean;
@@ -0,0 +1,57 @@
1
+ import { basename } from 'node:path';
2
+ function parseCharClass(pattern, start) {
3
+ let j = start + 1;
4
+ let cls = '[';
5
+ // Stryker disable next-line ConditionalExpression,EqualityOperator -- equivalent mutant: undefined !== '!' so bounds check is undetectable via char comparison
6
+ if (j < pattern.length && pattern[j] === '!') {
7
+ cls += '^';
8
+ j++;
9
+ }
10
+ // Stryker disable next-line ConditionalExpression,EqualityOperator -- equivalent mutant: undefined !== ']' so bounds check is undetectable via char comparison
11
+ if (j < pattern.length && pattern[j] === ']') {
12
+ cls += '\\]';
13
+ j++;
14
+ }
15
+ // Stryker disable next-line EqualityOperator -- equivalent mutant: extra iteration appends undefined to cls but unmatched-[ path still returns \\[
16
+ while (j < pattern.length && pattern[j] !== ']') {
17
+ cls += pattern[j++];
18
+ }
19
+ if (j < pattern.length) {
20
+ return { fragment: cls + ']', advance: j + 1 - start };
21
+ }
22
+ // unmatched '[', treat as literal
23
+ return { fragment: '\\[', advance: 1 };
24
+ }
25
+ function parseDoubleStar(pattern, i) {
26
+ if (pattern[i + 2] === '/') {
27
+ return { fragment: '(.*\\/)?', advance: 3 };
28
+ }
29
+ return { fragment: '.*', advance: 2 };
30
+ }
31
+ function nextToken(pattern, i) {
32
+ const c = pattern[i];
33
+ if (c === '*' && pattern[i + 1] === '*')
34
+ return parseDoubleStar(pattern, i);
35
+ if (c === '*')
36
+ return { fragment: '[^/]*', advance: 1 };
37
+ if (c === '?')
38
+ return { fragment: '[^/]', advance: 1 };
39
+ if (c === '[')
40
+ return parseCharClass(pattern, i);
41
+ return { fragment: c.replace(/[.+^${}()|\\]/g, '\\$&'), advance: 1 };
42
+ }
43
+ function globToRegex(pattern) {
44
+ let re = '';
45
+ let i = 0;
46
+ while (i < pattern.length) {
47
+ const { fragment, advance } = nextToken(pattern, i);
48
+ re += fragment;
49
+ i += advance;
50
+ }
51
+ return new RegExp('^' + re + '$');
52
+ }
53
+ export function matchesGlob(filePath, pattern, options) {
54
+ const subject = options?.matchBase && !pattern.includes('/') ? basename(filePath) : filePath;
55
+ return globToRegex(pattern).test(subject);
56
+ }
57
+ //# sourceMappingURL=globMatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"globMatcher.js","sourceRoot":"","sources":["../../src/utils/globMatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function tryReadJson(path: string, warnings: string[]): Promise<string | null>;
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+ import { readFile } from 'node:fs/promises';
3
+ export async function tryReadJson(path, warnings) {
4
+ try {
5
+ return await readFile(path, 'utf-8');
6
+ }
7
+ catch {
8
+ warnings.push(`Failed to read ${path}. Confirm file exists.`);
9
+ return null;
10
+ }
11
+ }
12
+ //# sourceMappingURL=readJson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readJson.js","sourceRoot":"","sources":["../../src/utils/readJson.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,QAAkB;IAChE,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,QAAQ,CAAC,IAAI,CAAC,kBAAkB,IAAI,wBAAwB,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -44,6 +44,19 @@ export type CoverageProcessingContext = {
44
44
  filePathCache: Map<string, string>;
45
45
  excludePatterns: string[];
46
46
  };
47
+ export type CoverageInput = DeployCoverageData | TestCoverageData[];
48
+ export type LineTotals = {
49
+ totalLines: number;
50
+ coveredLines: number;
51
+ };
52
+ export type ProcessResult = {
53
+ processed: number;
54
+ } & LineTotals;
55
+ export type TransformOptions = {
56
+ minCoverage?: number;
57
+ maxAnnotations?: number;
58
+ excludePatterns?: string[];
59
+ };
47
60
  type SonarLine = {
48
61
  '@lineNumber': number;
49
62
  '@covered': boolean;
@@ -15,10 +15,11 @@ Transform Salesforce Apex code coverage JSONs created during deployments and tes
15
15
  - `sf acc-transformer transform -j "coverage.json" -r "coverage.md" -f "markdown"`
16
16
  - `sf acc-transformer transform -j "coverage.json" -r "coverage.txt" -f "github-actions"`
17
17
  - `sf acc-transformer transform -j "coverage.json" -i "force-app"`
18
+ - `sf acc-transformer transform -j "coverage1.json" -j "coverage2.json" -r "coverage.xml" -f "sonar"`
18
19
 
19
20
  # flags.coverage-json.summary
20
21
 
21
- Path to the code coverage JSON file created by the Salesforce CLI deploy or test command.
22
+ Path to a code coverage JSON file created by the Salesforce CLI deploy or test command. Repeat the flag to merge multiple files. When the same Apex file appears in multiple inputs, covered lines are unioned across all inputs — if a line is covered in any input it is counted as covered in the final report, even if it is uncovered in others.
22
23
 
23
24
  # flags.output-report.summary
24
25
 
@@ -11,7 +11,8 @@
11
11
  "`sf acc-transformer transform -j \"coverage.json\" -r \"coverage.info\" -f \"lcovonly\"`",
12
12
  "`sf acc-transformer transform -j \"coverage.json\" -r \"coverage.md\" -f \"markdown\"`",
13
13
  "`sf acc-transformer transform -j \"coverage.json\" -r \"coverage.txt\" -f \"github-actions\"`",
14
- "`sf acc-transformer transform -j \"coverage.json\" -i \"force-app\"`"
14
+ "`sf acc-transformer transform -j \"coverage.json\" -i \"force-app\"`",
15
+ "`sf acc-transformer transform -j \"coverage1.json\" -j \"coverage2.json\" -r \"coverage.xml\" -f \"sonar\"`"
15
16
  ],
16
17
  "flags": {
17
18
  "json": {
@@ -33,9 +34,9 @@
33
34
  "char": "j",
34
35
  "name": "coverage-json",
35
36
  "required": true,
36
- "summary": "Path to the code coverage JSON file created by the Salesforce CLI deploy or test command.",
37
+ "summary": "Path to a code coverage JSON file created by the Salesforce CLI deploy or test command. Repeat the flag to merge multiple files. When the same Apex file appears in multiple inputs, covered lines are unioned across all inputs — if a line is covered in any input it is counted as covered in the final report, even if it is uncovered in others.",
37
38
  "hasDynamicHelp": false,
38
- "multiple": false,
39
+ "multiple": true,
39
40
  "type": "option"
40
41
  },
41
42
  "output-report": {
@@ -130,5 +131,5 @@
130
131
  ]
131
132
  }
132
133
  },
133
- "version": "2.22.0"
134
+ "version": "2.23.0"
134
135
  }
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "apex-code-coverage-transformer",
3
3
  "description": "Transform Salesforce Apex code coverage JSONs into other formats accepted by SonarQube, GitHub, GitLab, Azure, Bitbucket, etc.",
4
- "version": "2.22.0",
4
+ "version": "2.23.0",
5
5
  "dependencies": {
6
6
  "@oclif/core": "4.8.3",
7
7
  "@salesforce/core": "8.26.3",
8
8
  "@salesforce/sf-plugins-core": "12.2.6",
9
- "fast-xml-builder": "1.2.0",
10
- "minimatch": "10.2.5"
9
+ "fast-xml-builder": "1.2.0"
11
10
  },
12
11
  "devDependencies": {
13
12
  "@commitlint/cli": "19.8.1",