@c9up/helix 0.1.3 → 0.1.5
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/dist/cli/coverage/aggregate.d.ts +24 -0
- package/dist/cli/coverage/aggregate.d.ts.map +1 -0
- package/dist/cli/coverage/aggregate.js +215 -0
- package/dist/cli/coverage/aggregate.js.map +1 -0
- package/dist/cli/coverage/collect.d.ts +13 -0
- package/dist/cli/coverage/collect.d.ts.map +1 -0
- package/dist/cli/coverage/collect.js +66 -0
- package/dist/cli/coverage/collect.js.map +1 -0
- package/dist/cli/coverage/diff/base.d.ts +17 -0
- package/dist/cli/coverage/diff/base.d.ts.map +1 -0
- package/dist/cli/coverage/diff/base.js +44 -0
- package/dist/cli/coverage/diff/base.js.map +1 -0
- package/dist/cli/coverage/diff/index.d.ts +25 -0
- package/dist/cli/coverage/diff/index.d.ts.map +1 -0
- package/dist/cli/coverage/diff/index.js +119 -0
- package/dist/cli/coverage/diff/index.js.map +1 -0
- package/dist/cli/coverage/diff/overlay.d.ts +19 -0
- package/dist/cli/coverage/diff/overlay.d.ts.map +1 -0
- package/dist/cli/coverage/diff/overlay.js +58 -0
- package/dist/cli/coverage/diff/overlay.js.map +1 -0
- package/dist/cli/coverage/diff/parse.d.ts +27 -0
- package/dist/cli/coverage/diff/parse.d.ts.map +1 -0
- package/dist/cli/coverage/diff/parse.js +105 -0
- package/dist/cli/coverage/diff/parse.js.map +1 -0
- package/dist/cli/coverage/diff/reporters.d.ts +12 -0
- package/dist/cli/coverage/diff/reporters.d.ts.map +1 -0
- package/dist/cli/coverage/diff/reporters.js +59 -0
- package/dist/cli/coverage/diff/reporters.js.map +1 -0
- package/dist/cli/coverage/diff/types.d.ts +46 -0
- package/dist/cli/coverage/diff/types.d.ts.map +1 -0
- package/dist/cli/coverage/diff/types.js +15 -0
- package/dist/cli/coverage/diff/types.js.map +1 -0
- package/dist/cli/coverage/filter.d.ts +13 -0
- package/dist/cli/coverage/filter.d.ts.map +1 -0
- package/dist/cli/coverage/filter.js +60 -0
- package/dist/cli/coverage/filter.js.map +1 -0
- package/dist/cli/coverage/glob.d.ts +4 -0
- package/dist/cli/coverage/glob.d.ts.map +1 -0
- package/dist/cli/coverage/glob.js +0 -0
- package/dist/cli/coverage/glob.js.map +1 -0
- package/dist/cli/coverage/index.d.ts +40 -0
- package/dist/cli/coverage/index.d.ts.map +1 -0
- package/dist/cli/coverage/index.js +85 -0
- package/dist/cli/coverage/index.js.map +1 -0
- package/dist/cli/coverage/reporters/json.d.ts +13 -0
- package/dist/cli/coverage/reporters/json.d.ts.map +1 -0
- package/dist/cli/coverage/reporters/json.js +37 -0
- package/dist/cli/coverage/reporters/json.js.map +1 -0
- package/dist/cli/coverage/reporters/lcov.d.ts +13 -0
- package/dist/cli/coverage/reporters/lcov.d.ts.map +1 -0
- package/dist/cli/coverage/reporters/lcov.js +51 -0
- package/dist/cli/coverage/reporters/lcov.js.map +1 -0
- package/dist/cli/coverage/reporters/text.d.ts +8 -0
- package/dist/cli/coverage/reporters/text.d.ts.map +1 -0
- package/dist/cli/coverage/reporters/text.js +39 -0
- package/dist/cli/coverage/reporters/text.js.map +1 -0
- package/dist/cli/coverage/thresholds.d.ts +14 -0
- package/dist/cli/coverage/thresholds.d.ts.map +1 -0
- package/dist/cli/coverage/thresholds.js +58 -0
- package/dist/cli/coverage/thresholds.js.map +1 -0
- package/dist/cli/coverage/types.d.ts +118 -0
- package/dist/cli/coverage/types.d.ts.map +1 -0
- package/dist/cli/coverage/types.js +8 -0
- package/dist/cli/coverage/types.js.map +1 -0
- package/dist/cli/discover.d.ts +27 -0
- package/dist/cli/discover.d.ts.map +1 -0
- package/dist/cli/discover.js +142 -0
- package/dist/cli/discover.js.map +1 -0
- package/dist/cli/native.d.ts +43 -0
- package/dist/cli/native.d.ts.map +1 -0
- package/dist/cli/native.js +64 -0
- package/dist/cli/native.js.map +1 -0
- package/dist/cli/pool.d.ts +55 -0
- package/dist/cli/pool.d.ts.map +1 -0
- package/dist/cli/pool.js +404 -0
- package/dist/cli/pool.js.map +1 -0
- package/dist/cli/reporter.d.ts +51 -0
- package/dist/cli/reporter.d.ts.map +1 -0
- package/dist/cli/reporter.js +124 -0
- package/dist/cli/reporter.js.map +1 -0
- package/dist/cli/run.d.ts +61 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +302 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/summary.d.ts +18 -0
- package/dist/cli/summary.d.ts.map +1 -0
- package/dist/cli/summary.js +20 -0
- package/dist/cli/summary.js.map +1 -0
- package/dist/cli/watch/loop.d.ts +26 -0
- package/dist/cli/watch/loop.d.ts.map +1 -0
- package/dist/cli/watch/loop.js +133 -0
- package/dist/cli/watch/loop.js.map +1 -0
- package/dist/cli/watch/types.d.ts +22 -0
- package/dist/cli/watch/types.d.ts.map +1 -0
- package/dist/cli/watch/types.js +6 -0
- package/dist/cli/watch/types.js.map +1 -0
- package/dist/cli/watch/watcher.d.ts +25 -0
- package/dist/cli/watch/watcher.d.ts.map +1 -0
- package/dist/cli/watch/watcher.js +122 -0
- package/dist/cli/watch/watcher.js.map +1 -0
- package/dist/container/index.d.ts +7 -0
- package/dist/container/index.d.ts.map +1 -0
- package/dist/container/index.js +6 -0
- package/dist/container/index.js.map +1 -0
- package/{src/container/override.ts → dist/container/override.d.ts} +6 -46
- package/dist/container/override.d.ts.map +1 -0
- package/dist/container/override.js +67 -0
- package/dist/container/override.js.map +1 -0
- package/{src/container/spy.ts → dist/container/spy.d.ts} +2 -6
- package/dist/container/spy.d.ts.map +1 -0
- package/dist/container/spy.js +23 -0
- package/dist/container/spy.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/{src/index.ts → dist/index.js} +2 -25
- package/dist/index.js.map +1 -0
- package/dist/runtime/assertion-error.d.ts +20 -0
- package/dist/runtime/assertion-error.d.ts.map +1 -0
- package/dist/runtime/assertion-error.js +23 -0
- package/dist/runtime/assertion-error.js.map +1 -0
- package/dist/runtime/cli-worker.d.ts +25 -0
- package/dist/runtime/cli-worker.d.ts.map +1 -0
- package/dist/runtime/cli-worker.js +128 -0
- package/dist/runtime/cli-worker.js.map +1 -0
- package/dist/runtime/equals.d.ts +25 -0
- package/dist/runtime/equals.d.ts.map +1 -0
- package/dist/runtime/equals.js +343 -0
- package/dist/runtime/equals.js.map +1 -0
- package/dist/runtime/expect.d.ts +32 -0
- package/dist/runtime/expect.d.ts.map +1 -0
- package/dist/runtime/expect.js +121 -0
- package/dist/runtime/expect.js.map +1 -0
- package/{src/runtime/index.ts → dist/runtime/index.d.ts} +5 -27
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +17 -0
- package/dist/runtime/index.js.map +1 -0
- package/{src/runtime/lifecycle.ts → dist/runtime/lifecycle.d.ts} +2 -8
- package/dist/runtime/lifecycle.d.ts.map +1 -0
- package/dist/runtime/lifecycle.js +10 -0
- package/dist/runtime/lifecycle.js.map +1 -0
- package/dist/runtime/matchers.d.ts +42 -0
- package/dist/runtime/matchers.d.ts.map +1 -0
- package/dist/runtime/matchers.js +375 -0
- package/dist/runtime/matchers.js.map +1 -0
- package/dist/runtime/run.d.ts +55 -0
- package/dist/runtime/run.d.ts.map +1 -0
- package/dist/runtime/run.js +456 -0
- package/dist/runtime/run.js.map +1 -0
- package/dist/runtime/suite.d.ts +91 -0
- package/dist/runtime/suite.d.ts.map +1 -0
- package/dist/runtime/suite.js +206 -0
- package/dist/runtime/suite.js.map +1 -0
- package/dist/runtime/test-context.d.ts +25 -0
- package/dist/runtime/test-context.d.ts.map +1 -0
- package/dist/runtime/test-context.js +52 -0
- package/dist/runtime/test-context.js.map +1 -0
- package/dist/runtime/vi/fake-timers.d.ts +48 -0
- package/dist/runtime/vi/fake-timers.d.ts.map +1 -0
- package/dist/runtime/vi/fake-timers.js +317 -0
- package/dist/runtime/vi/fake-timers.js.map +1 -0
- package/dist/runtime/vi/index.d.ts +70 -0
- package/dist/runtime/vi/index.d.ts.map +1 -0
- package/dist/runtime/vi/index.js +209 -0
- package/dist/runtime/vi/index.js.map +1 -0
- package/dist/runtime/vi/spy.d.ts +54 -0
- package/dist/runtime/vi/spy.d.ts.map +1 -0
- package/dist/runtime/vi/spy.js +159 -0
- package/dist/runtime/vi/spy.js.map +1 -0
- package/dist/runtime/vi/spyOn.d.ts +28 -0
- package/dist/runtime/vi/spyOn.d.ts.map +1 -0
- package/dist/runtime/vi/spyOn.js +121 -0
- package/dist/runtime/vi/spyOn.js.map +1 -0
- package/dist/runtime/vi/system-time.d.ts +30 -0
- package/dist/runtime/vi/system-time.d.ts.map +1 -0
- package/dist/runtime/vi/system-time.js +100 -0
- package/dist/runtime/vi/system-time.js.map +1 -0
- package/dist/runtime/worker.d.ts +26 -0
- package/dist/runtime/worker.d.ts.map +1 -0
- package/dist/runtime/worker.js +195 -0
- package/dist/runtime/worker.js.map +1 -0
- package/dist/time/freeze.d.ts +80 -0
- package/dist/time/freeze.d.ts.map +1 -0
- package/dist/time/freeze.js +184 -0
- package/dist/time/freeze.js.map +1 -0
- package/{src/time/index.ts → dist/time/index.d.ts} +1 -1
- package/dist/time/index.d.ts.map +1 -0
- package/dist/time/index.js +15 -0
- package/dist/time/index.js.map +1 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +2 -2
- package/src/cli/coverage/aggregate.ts +0 -231
- package/src/cli/coverage/collect.ts +0 -63
- package/src/cli/coverage/diff/base.ts +0 -46
- package/src/cli/coverage/diff/index.ts +0 -160
- package/src/cli/coverage/diff/overlay.ts +0 -62
- package/src/cli/coverage/diff/parse.ts +0 -121
- package/src/cli/coverage/diff/reporters.ts +0 -82
- package/src/cli/coverage/diff/types.ts +0 -46
- package/src/cli/coverage/filter.ts +0 -71
- package/src/cli/coverage/glob.ts +0 -0
- package/src/cli/coverage/index.ts +0 -126
- package/src/cli/coverage/reporters/json.ts +0 -40
- package/src/cli/coverage/reporters/lcov.ts +0 -54
- package/src/cli/coverage/reporters/text.ts +0 -48
- package/src/cli/coverage/thresholds.ts +0 -73
- package/src/cli/coverage/types.ts +0 -93
- package/src/cli/discover.ts +0 -174
- package/src/cli/native.ts +0 -104
- package/src/cli/pool.ts +0 -486
- package/src/cli/reporter.ts +0 -155
- package/src/cli/run.ts +0 -440
- package/src/cli/summary.ts +0 -42
- package/src/cli/watch/loop.ts +0 -159
- package/src/cli/watch/types.ts +0 -22
- package/src/cli/watch/watcher.ts +0 -145
- package/src/container/index.ts +0 -16
- package/src/runtime/assertion-error.ts +0 -38
- package/src/runtime/cli-worker.ts +0 -140
- package/src/runtime/equals.ts +0 -400
- package/src/runtime/expect.ts +0 -173
- package/src/runtime/matchers.ts +0 -452
- package/src/runtime/run.ts +0 -573
- package/src/runtime/suite.ts +0 -310
- package/src/runtime/test-context.ts +0 -59
- package/src/runtime/vi/fake-timers.ts +0 -410
- package/src/runtime/vi/index.ts +0 -254
- package/src/runtime/vi/spy.ts +0 -224
- package/src/runtime/vi/spyOn.ts +0 -155
- package/src/runtime/vi/system-time.ts +0 -121
- package/src/runtime/worker.ts +0 -239
- package/src/time/freeze.ts +0 -229
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Overlay the diff map onto a `CoverageSummary` to compute per-file
|
|
3
|
+
* "added vs covered" totals.
|
|
4
|
+
*
|
|
5
|
+
* For each file in the diff:
|
|
6
|
+
* - find the matching coverage entry by absolute path
|
|
7
|
+
* - intersect the added line numbers with `lineHits` (count > 0 means
|
|
8
|
+
* covered)
|
|
9
|
+
* - emit a `DiffFileSummary`
|
|
10
|
+
*
|
|
11
|
+
* Files in the diff with no coverage entry are still reported (added
|
|
12
|
+
* lines, 0 covered) so a freshly-added module without any tests shows
|
|
13
|
+
* up red. Files in coverage but not in the diff are skipped (the PR
|
|
14
|
+
* didn't touch them, so they don't move the diff-coverage needle).
|
|
15
|
+
*/
|
|
16
|
+
function pct(covered, added) {
|
|
17
|
+
if (added === 0)
|
|
18
|
+
return 100;
|
|
19
|
+
return Math.round((covered / added) * 10000) / 100;
|
|
20
|
+
}
|
|
21
|
+
export function overlay(coverage, diff) {
|
|
22
|
+
const coverageByFile = new Map(coverage.files.map((f) => [f.file, f]));
|
|
23
|
+
const files = [];
|
|
24
|
+
let totalAdded = 0;
|
|
25
|
+
let totalCovered = 0;
|
|
26
|
+
for (const [file, addedLines] of diff) {
|
|
27
|
+
if (addedLines.size === 0)
|
|
28
|
+
continue;
|
|
29
|
+
const cov = coverageByFile.get(file);
|
|
30
|
+
const hitsByLine = cov
|
|
31
|
+
? new Map(cov.lineHits.map((h) => [h.line, h.count]))
|
|
32
|
+
: undefined;
|
|
33
|
+
const sortedAdded = [...addedLines].sort((a, b) => a - b);
|
|
34
|
+
const lineHits = sortedAdded.map((line) => {
|
|
35
|
+
const count = hitsByLine?.get(line);
|
|
36
|
+
return { line, covered: typeof count === "number" && count > 0 };
|
|
37
|
+
});
|
|
38
|
+
const covered = lineHits.filter((h) => h.covered).length;
|
|
39
|
+
files.push({
|
|
40
|
+
file,
|
|
41
|
+
added: addedLines.size,
|
|
42
|
+
covered,
|
|
43
|
+
lineHits,
|
|
44
|
+
});
|
|
45
|
+
totalAdded += addedLines.size;
|
|
46
|
+
totalCovered += covered;
|
|
47
|
+
}
|
|
48
|
+
files.sort((a, b) => a.file.localeCompare(b.file));
|
|
49
|
+
return {
|
|
50
|
+
files,
|
|
51
|
+
total: {
|
|
52
|
+
added: totalAdded,
|
|
53
|
+
covered: totalCovered,
|
|
54
|
+
pct: pct(totalCovered, totalAdded),
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=overlay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../../../src/cli/coverage/diff/overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,SAAS,GAAG,CAAC,OAAe,EAAE,KAAa;IAC1C,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,QAAyB,EAAE,IAAa;IAC/D,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,MAAM,KAAK,GAAsB,EAAE,CAAC;IACpC,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,EAAE,CAAC;QACvC,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC;YAAE,SAAS;QACpC,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,UAAU,GAAG,GAAG;YACrB,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACrD,CAAC,CAAC,SAAS,CAAC;QACb,MAAM,WAAW,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1D,MAAM,QAAQ,GAAgC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACtE,MAAM,KAAK,GAAG,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YACpC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAClE,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;QACzD,KAAK,CAAC,IAAI,CAAC;YACV,IAAI;YACJ,KAAK,EAAE,UAAU,CAAC,IAAI;YACtB,OAAO;YACP,QAAQ;SACR,CAAC,CAAC;QACH,UAAU,IAAI,UAAU,CAAC,IAAI,CAAC;QAC9B,YAAY,IAAI,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACnD,OAAO;QACN,KAAK;QACL,KAAK,EAAE;YACN,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,YAAY;YACrB,GAAG,EAAE,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC;SAClC;KACD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse `git diff --unified=0 --no-color <base>...HEAD` output into a
|
|
3
|
+
* `DiffMap`. Why three-dot: it computes the diff at the merge-base, so
|
|
4
|
+
* commits made on `base` AFTER our branch diverged are excluded. That's
|
|
5
|
+
* the "what this PR contributes" semantic users expect.
|
|
6
|
+
*
|
|
7
|
+
* We force `--src-prefix=a/ --dst-prefix=b/` and `core.quotepath=false`
|
|
8
|
+
* so the parser doesn't have to guess at user-side `diff.noprefix` or
|
|
9
|
+
* non-ASCII path quoting.
|
|
10
|
+
*
|
|
11
|
+
* Renames produce `+++ b/<new path>` so they're picked up at the new
|
|
12
|
+
* location. Deletes produce `+++ /dev/null` and are skipped. Binary
|
|
13
|
+
* files produce no `+` lines so they contribute nothing.
|
|
14
|
+
*/
|
|
15
|
+
import type { DiffMap } from "./types.js";
|
|
16
|
+
export interface ParseOptions {
|
|
17
|
+
cwd: string;
|
|
18
|
+
base: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function parseDiff(opts: ParseOptions): DiffMap;
|
|
21
|
+
/**
|
|
22
|
+
* Pure parser — exposed separately so tests can feed canned diff
|
|
23
|
+
* strings without spawning git. Keys are canonicalised via realpath so
|
|
24
|
+
* they line up with V8 coverage paths (which `filter.ts` realpaths).
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseDiffString(diff: string, cwd: string): DiffMap;
|
|
27
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../../src/cli/coverage/diff/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAK1C,MAAM,WAAW,YAAY;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACb;AAUD,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAqCrD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAwClE"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse `git diff --unified=0 --no-color <base>...HEAD` output into a
|
|
3
|
+
* `DiffMap`. Why three-dot: it computes the diff at the merge-base, so
|
|
4
|
+
* commits made on `base` AFTER our branch diverged are excluded. That's
|
|
5
|
+
* the "what this PR contributes" semantic users expect.
|
|
6
|
+
*
|
|
7
|
+
* We force `--src-prefix=a/ --dst-prefix=b/` and `core.quotepath=false`
|
|
8
|
+
* so the parser doesn't have to guess at user-side `diff.noprefix` or
|
|
9
|
+
* non-ASCII path quoting.
|
|
10
|
+
*
|
|
11
|
+
* Renames produce `+++ b/<new path>` so they're picked up at the new
|
|
12
|
+
* location. Deletes produce `+++ /dev/null` and are skipped. Binary
|
|
13
|
+
* files produce no `+` lines so they contribute nothing.
|
|
14
|
+
*/
|
|
15
|
+
import { spawnSync } from "node:child_process";
|
|
16
|
+
import { realpathSync } from "node:fs";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
const HUNK_HEADER = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/;
|
|
19
|
+
const FILE_HEADER_PLUS = /^\+\+\+ (?:b\/(.*)|\/dev\/null)$/;
|
|
20
|
+
function tryRealpath(p) {
|
|
21
|
+
try {
|
|
22
|
+
return realpathSync(p);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return p;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function parseDiff(opts) {
|
|
29
|
+
const result = spawnSync("git", [
|
|
30
|
+
"-c",
|
|
31
|
+
"core.quotepath=false",
|
|
32
|
+
"diff",
|
|
33
|
+
"--unified=0",
|
|
34
|
+
"--no-color",
|
|
35
|
+
"--src-prefix=a/",
|
|
36
|
+
"--dst-prefix=b/",
|
|
37
|
+
`${opts.base}...HEAD`,
|
|
38
|
+
], {
|
|
39
|
+
cwd: opts.cwd,
|
|
40
|
+
encoding: "utf8",
|
|
41
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
42
|
+
});
|
|
43
|
+
if (result.error) {
|
|
44
|
+
const err = result.error;
|
|
45
|
+
if (err.code === "ENOENT") {
|
|
46
|
+
throw new Error("git binary not found on PATH");
|
|
47
|
+
}
|
|
48
|
+
if (err.code === "ENOBUFS") {
|
|
49
|
+
throw new Error("diff output exceeded 64 MB — branch is too divergent to overlay");
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`git diff failed: ${err.message}`);
|
|
52
|
+
}
|
|
53
|
+
if (result.status !== 0) {
|
|
54
|
+
throw new Error(`git diff exited ${result.status}: ${result.stderr?.trim() || "(no stderr — likely shallow clone or pruned ref)"}`);
|
|
55
|
+
}
|
|
56
|
+
return parseDiffString(result.stdout, opts.cwd);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Pure parser — exposed separately so tests can feed canned diff
|
|
60
|
+
* strings without spawning git. Keys are canonicalised via realpath so
|
|
61
|
+
* they line up with V8 coverage paths (which `filter.ts` realpaths).
|
|
62
|
+
*/
|
|
63
|
+
export function parseDiffString(diff, cwd) {
|
|
64
|
+
const map = new Map();
|
|
65
|
+
let currentFile;
|
|
66
|
+
let nextAddedLine = 0;
|
|
67
|
+
const lines = diff.split(/\r?\n/);
|
|
68
|
+
for (const line of lines) {
|
|
69
|
+
const fileMatch = line.match(FILE_HEADER_PLUS);
|
|
70
|
+
if (fileMatch) {
|
|
71
|
+
const newPath = fileMatch[1];
|
|
72
|
+
if (!newPath) {
|
|
73
|
+
currentFile = undefined;
|
|
74
|
+
nextAddedLine = 0;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
currentFile = tryRealpath(path.resolve(cwd, newPath));
|
|
78
|
+
nextAddedLine = 0;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (!currentFile)
|
|
82
|
+
continue;
|
|
83
|
+
const hunkMatch = line.match(HUNK_HEADER);
|
|
84
|
+
if (hunkMatch) {
|
|
85
|
+
nextAddedLine = Number.parseInt(hunkMatch[1], 10);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
89
|
+
if (nextAddedLine < 1) {
|
|
90
|
+
// `+0,0` deletion-only hunks set nextAddedLine = 0; ignore stray
|
|
91
|
+
// `+` lines rather than emit invalid line numbers.
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
let set = map.get(currentFile);
|
|
95
|
+
if (!set) {
|
|
96
|
+
set = new Set();
|
|
97
|
+
map.set(currentFile, set);
|
|
98
|
+
}
|
|
99
|
+
set.add(nextAddedLine);
|
|
100
|
+
nextAddedLine += 1;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return map;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../../src/cli/coverage/diff/parse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff-coverage reporters: text summary + JSON.
|
|
3
|
+
*
|
|
4
|
+
* The text reporter mirrors the full-tree text format so users can read
|
|
5
|
+
* both side-by-side. JSON is namespaced under `files` to avoid
|
|
6
|
+
* collisions with the literal `total` key (in case a file is named
|
|
7
|
+
* `total`).
|
|
8
|
+
*/
|
|
9
|
+
import type { DiffSummary } from "./types.js";
|
|
10
|
+
export declare function diffTextSummary(summary: DiffSummary, root: string): string;
|
|
11
|
+
export declare function diffJson(summary: DiffSummary, root: string): string;
|
|
12
|
+
//# sourceMappingURL=reporters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporters.d.ts","sourceRoot":"","sources":["../../../../src/cli/coverage/diff/reporters.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAmB,WAAW,EAAE,MAAM,YAAY,CAAC;AAiB/D,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CA2B1E;AAaD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAcnE"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff-coverage reporters: text summary + JSON.
|
|
3
|
+
*
|
|
4
|
+
* The text reporter mirrors the full-tree text format so users can read
|
|
5
|
+
* both side-by-side. JSON is namespaced under `files` to avoid
|
|
6
|
+
* collisions with the literal `total` key (in case a file is named
|
|
7
|
+
* `total`).
|
|
8
|
+
*/
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
function rel(file, root) {
|
|
11
|
+
const r = path.relative(root, file).split(path.sep).join("/");
|
|
12
|
+
return r.length > 0 && !r.startsWith("..") ? r : file;
|
|
13
|
+
}
|
|
14
|
+
function padRight(s, w) {
|
|
15
|
+
if (s.length === w)
|
|
16
|
+
return s;
|
|
17
|
+
if (s.length > w)
|
|
18
|
+
return `…${s.slice(s.length - w + 1)}`;
|
|
19
|
+
return s + " ".repeat(w - s.length);
|
|
20
|
+
}
|
|
21
|
+
function fmtPct(n) {
|
|
22
|
+
return `${n.toFixed(2).padStart(6)}%`;
|
|
23
|
+
}
|
|
24
|
+
export function diffTextSummary(summary, root) {
|
|
25
|
+
const lines = [];
|
|
26
|
+
lines.push("");
|
|
27
|
+
lines.push("── Diff coverage ───────────────────────────────────────────");
|
|
28
|
+
if (summary.files.length === 0) {
|
|
29
|
+
lines.push(" No instrumented files were touched by the diff.");
|
|
30
|
+
lines.push(` ${summary.total.covered}/${summary.total.added} lines covered`);
|
|
31
|
+
return `${lines.join("\n")}\n`;
|
|
32
|
+
}
|
|
33
|
+
lines.push(`${padRight("File", 50)} ${"Covered".padStart(10)} ${"%".padStart(8)}`);
|
|
34
|
+
lines.push("─".repeat(72));
|
|
35
|
+
for (const f of summary.files) {
|
|
36
|
+
const ratio = `${f.covered}/${f.added}`;
|
|
37
|
+
const pct = f.added > 0 ? (f.covered / f.added) * 100 : 100;
|
|
38
|
+
lines.push(`${padRight(rel(f.file, root), 50)} ${ratio.padStart(10)} ${fmtPct(pct)}`);
|
|
39
|
+
}
|
|
40
|
+
lines.push("─".repeat(72));
|
|
41
|
+
lines.push(`${padRight("Total", 50)} ${`${summary.total.covered}/${summary.total.added}`.padStart(10)} ${fmtPct(summary.total.pct)}`);
|
|
42
|
+
return `${lines.join("\n")}\n`;
|
|
43
|
+
}
|
|
44
|
+
export function diffJson(summary, root) {
|
|
45
|
+
const filesOut = Object.create(null);
|
|
46
|
+
for (const f of summary.files) {
|
|
47
|
+
filesOut[rel(f.file, root)] = {
|
|
48
|
+
added: f.added,
|
|
49
|
+
covered: f.covered,
|
|
50
|
+
lineHits: f.lineHits,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const out = {
|
|
54
|
+
total: summary.total,
|
|
55
|
+
files: filesOut,
|
|
56
|
+
};
|
|
57
|
+
return `${JSON.stringify(out, null, 2)}\n`;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=reporters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporters.js","sourceRoot":"","sources":["../../../../src/cli/coverage/diff/reporters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the diff-coverage pipeline.
|
|
3
|
+
*
|
|
4
|
+
* `DiffMap` is the output of `parse.ts` — for every file changed in
|
|
5
|
+
* `<base>...HEAD`, the set of 1-based line numbers added or modified
|
|
6
|
+
* (i.e. lines starting with `+` in unified diff, excluding the `+++`
|
|
7
|
+
* header). Deleted lines aren't relevant: we only care whether NEW
|
|
8
|
+
* code is covered.
|
|
9
|
+
*
|
|
10
|
+
* `DiffFileSummary` and `DiffSummary` mirror the shape of the full-tree
|
|
11
|
+
* `FileSummary` / `CoverageSummary` so the existing threshold
|
|
12
|
+
* enforcement machinery applies unchanged.
|
|
13
|
+
*/
|
|
14
|
+
export type DiffMap = Map<string, Set<number>>;
|
|
15
|
+
export interface DiffFileSummary {
|
|
16
|
+
file: string;
|
|
17
|
+
/** Lines added by the PR (1-based). */
|
|
18
|
+
added: number;
|
|
19
|
+
/** Subset of `added` that have a hit count > 0 in the coverage summary. */
|
|
20
|
+
covered: number;
|
|
21
|
+
/** Per-line breakdown for reporters. */
|
|
22
|
+
lineHits: Array<{
|
|
23
|
+
line: number;
|
|
24
|
+
covered: boolean;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
export interface DiffSummary {
|
|
28
|
+
files: DiffFileSummary[];
|
|
29
|
+
total: {
|
|
30
|
+
added: number;
|
|
31
|
+
covered: number;
|
|
32
|
+
pct: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export interface DiffOptions {
|
|
36
|
+
enabled: boolean;
|
|
37
|
+
/** Git revision to diff against. Default: resolved by `base.ts`. */
|
|
38
|
+
base?: string;
|
|
39
|
+
/** Inline thresholds. Reuses the full-tree shape. */
|
|
40
|
+
thresholds?: import("../types.js").Thresholds;
|
|
41
|
+
/** Output dir for `coverage-diff.json`. Defaults to coverage outputDir. */
|
|
42
|
+
outputDir?: string;
|
|
43
|
+
/** Where to spawn `git diff`. Defaults to `process.cwd()`. */
|
|
44
|
+
cwd?: string;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/cli/coverage/diff/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAE/C,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,KAAK,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;KACZ,CAAC;CACF;AAED,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,UAAU,CAAC,EAAE,OAAO,aAAa,EAAE,UAAU,CAAC;IAC9C,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,GAAG,CAAC,EAAE,MAAM,CAAC;CACb"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the diff-coverage pipeline.
|
|
3
|
+
*
|
|
4
|
+
* `DiffMap` is the output of `parse.ts` — for every file changed in
|
|
5
|
+
* `<base>...HEAD`, the set of 1-based line numbers added or modified
|
|
6
|
+
* (i.e. lines starting with `+` in unified diff, excluding the `+++`
|
|
7
|
+
* header). Deleted lines aren't relevant: we only care whether NEW
|
|
8
|
+
* code is covered.
|
|
9
|
+
*
|
|
10
|
+
* `DiffFileSummary` and `DiffSummary` mirror the shape of the full-tree
|
|
11
|
+
* `FileSummary` / `CoverageSummary` so the existing threshold
|
|
12
|
+
* enforcement machinery applies unchanged.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/cli/coverage/diff/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { globToRegex } from "./glob.js";
|
|
2
|
+
import type { RawFileCoverage } from "./types.js";
|
|
3
|
+
export interface FilterConfig {
|
|
4
|
+
root: string;
|
|
5
|
+
include?: string[];
|
|
6
|
+
exclude?: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function filter(raw: RawFileCoverage[], config: FilterConfig): RawFileCoverage[];
|
|
9
|
+
/** Exposed for tests. */
|
|
10
|
+
export declare const __test__: {
|
|
11
|
+
globToRegex: typeof globToRegex;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../src/cli/coverage/filter.ts"],"names":[],"mappings":"AAUA,OAAO,EAAgB,WAAW,EAAkB,MAAM,WAAW,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAkBlD,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAeD,wBAAgB,MAAM,CACrB,GAAG,EAAE,eAAe,EAAE,EACtB,MAAM,EAAE,YAAY,GAClB,eAAe,EAAE,CAgBnB;AAED,yBAAyB;AACzB,eAAO,MAAM,QAAQ;;CAAkB,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Include / exclude filter for coverage files. Glob subset is
|
|
2
|
+
// implemented in `./glob.ts` (shared with the watch-mode filter).
|
|
3
|
+
//
|
|
4
|
+
// Symlinks are NOT followed: `path.realpath` is used to verify the file
|
|
5
|
+
// actually lives under `root`. Anything pointing outside (off-tree
|
|
6
|
+
// symlinks) is dropped — defence in depth against a malicious source
|
|
7
|
+
// tree dragging unrelated files into the coverage report.
|
|
8
|
+
import { realpathSync } from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { compileGlobs, globToRegex, matchesAnyGlob } from "./glob.js";
|
|
11
|
+
const DEFAULT_INCLUDE = ["src/**/*.{ts,tsx,js,mjs,cjs}"];
|
|
12
|
+
const DEFAULT_EXCLUDE = [
|
|
13
|
+
"node_modules/**",
|
|
14
|
+
"dist/**",
|
|
15
|
+
"build/**",
|
|
16
|
+
"coverage/**",
|
|
17
|
+
".git/**",
|
|
18
|
+
".wolf/**",
|
|
19
|
+
"target/**",
|
|
20
|
+
".next/**",
|
|
21
|
+
"tests/**",
|
|
22
|
+
"test/**",
|
|
23
|
+
"**/*.test.*",
|
|
24
|
+
"**/*.spec.*",
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a path's real (canonical) absolute location. Falls back to
|
|
28
|
+
* the lexical path if the file no longer exists (already deleted by the
|
|
29
|
+
* worker exit). Symlinks point at the target's real path.
|
|
30
|
+
*/
|
|
31
|
+
function tryRealpath(p) {
|
|
32
|
+
try {
|
|
33
|
+
return realpathSync(p);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return p;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function filter(raw, config) {
|
|
40
|
+
const include = compileGlobs(config.include ?? DEFAULT_INCLUDE);
|
|
41
|
+
const exclude = compileGlobs(config.exclude ?? DEFAULT_EXCLUDE);
|
|
42
|
+
const root = tryRealpath(path.resolve(config.root));
|
|
43
|
+
const out = [];
|
|
44
|
+
for (const entry of raw) {
|
|
45
|
+
const real = tryRealpath(entry.file);
|
|
46
|
+
const rel = path.relative(root, real).split(path.sep).join("/");
|
|
47
|
+
if (rel.length === 0 || rel.startsWith("..") || path.isAbsolute(rel)) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (!matchesAnyGlob(include, rel))
|
|
51
|
+
continue;
|
|
52
|
+
if (matchesAnyGlob(exclude, rel))
|
|
53
|
+
continue;
|
|
54
|
+
out.push({ ...entry, file: real });
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
/** Exposed for tests. */
|
|
59
|
+
export const __test__ = { globToRegex };
|
|
60
|
+
//# sourceMappingURL=filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../src/cli/coverage/filter.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,kEAAkE;AAClE,EAAE;AACF,wEAAwE;AACxE,mEAAmE;AACnE,qEAAqE;AACrE,0DAA0D;AAE1D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGtE,MAAM,eAAe,GAAG,CAAC,8BAA8B,CAAC,CAAC;AACzD,MAAM,eAAe,GAAG;IACvB,iBAAiB;IACjB,SAAS;IACT,UAAU;IACV,aAAa;IACb,SAAS;IACT,UAAU;IACV,WAAW;IACX,UAAU;IACV,UAAU;IACV,SAAS;IACT,aAAa;IACb,aAAa;CACb,CAAC;AAQF;;;;GAIG;AACH,SAAS,WAAW,CAAC,CAAS;IAC7B,IAAI,CAAC;QACJ,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,CAAC,CAAC;IACV,CAAC;AACF,CAAC;AAED,MAAM,UAAU,MAAM,CACrB,GAAsB,EACtB,MAAoB;IAEpB,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,IAAI,eAAe,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,IAAI,eAAe,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACpD,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChE,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACtE,SAAS;QACV,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC;YAAE,SAAS;QAC5C,IAAI,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC;YAAE,SAAS;QAC3C,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,yBAAyB;AACzB,MAAM,CAAC,MAAM,QAAQ,GAAG,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../../src/cli/coverage/glob.ts"],"names":[],"mappings":"AAyBA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA6ChD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAEzD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAEtE"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.js","sourceRoot":"","sources":["../../../src/cli/coverage/glob.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coverage facade — wires collect → filter → aggregate → reporters →
|
|
3
|
+
* thresholds. Called by `run.ts` after the worker pool finishes.
|
|
4
|
+
*/
|
|
5
|
+
import type { CoverageOptions, CoverageSummary, ThresholdViolation } from "./types.js";
|
|
6
|
+
export { textSummary } from "./reporters/text.js";
|
|
7
|
+
export { enforce, violationSummary } from "./thresholds.js";
|
|
8
|
+
export type { CoverageOptions, CoverageSummary, ThresholdViolation, } from "./types.js";
|
|
9
|
+
export interface CoverageSession {
|
|
10
|
+
/** Temp dir passed as `NODE_V8_COVERAGE` to every worker. */
|
|
11
|
+
envDir: string;
|
|
12
|
+
/** Inject into the child environment. */
|
|
13
|
+
env: NodeJS.ProcessEnv;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create a unique temp directory for a run. The orchestrator passes its
|
|
17
|
+
* path via `NODE_V8_COVERAGE`; every spawned worker writes its own
|
|
18
|
+
* `coverage-*.json` on exit. Returns an env bag the pool forwards.
|
|
19
|
+
*/
|
|
20
|
+
export declare function openSession(baseDir?: string): Promise<CoverageSession>;
|
|
21
|
+
export interface FinaliseOptions extends CoverageOptions {
|
|
22
|
+
root: string;
|
|
23
|
+
session: CoverageSession;
|
|
24
|
+
}
|
|
25
|
+
export interface FinaliseResult {
|
|
26
|
+
summary: CoverageSummary;
|
|
27
|
+
violations: ThresholdViolation[];
|
|
28
|
+
textReport: string;
|
|
29
|
+
/** Absolute paths of written report files (lcov + json-summary). */
|
|
30
|
+
reportFiles: string[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* After all workers have exited, read the raw v8 output, aggregate, emit
|
|
34
|
+
* reporters + enforce thresholds.
|
|
35
|
+
*
|
|
36
|
+
* The temp dir is removed in `finally` so a write/aggregate failure
|
|
37
|
+
* doesn't leak gigabytes of raw V8 JSON under `.helix-coverage/`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function finalise(opts: FinaliseOptions): Promise<FinaliseResult>;
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/coverage/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,OAAO,KAAK,EACX,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EACX,eAAe,EACf,eAAe,EACf,kBAAkB,GAClB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,eAAe;IAC/B,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAW5E;AAED,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,eAAe,CAAC;IACzB,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,WAAW,EAAE,MAAM,EAAE,CAAC;CACtB;AAID;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAkD7E"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coverage facade — wires collect → filter → aggregate → reporters →
|
|
3
|
+
* thresholds. Called by `run.ts` after the worker pool finishes.
|
|
4
|
+
*/
|
|
5
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { aggregate } from "./aggregate.js";
|
|
8
|
+
import { collect } from "./collect.js";
|
|
9
|
+
import { filter } from "./filter.js";
|
|
10
|
+
import { jsonSummary } from "./reporters/json.js";
|
|
11
|
+
import { lcov } from "./reporters/lcov.js";
|
|
12
|
+
import { textSummary } from "./reporters/text.js";
|
|
13
|
+
import { enforce } from "./thresholds.js";
|
|
14
|
+
export { textSummary } from "./reporters/text.js";
|
|
15
|
+
export { enforce, violationSummary } from "./thresholds.js";
|
|
16
|
+
/**
|
|
17
|
+
* Create a unique temp directory for a run. The orchestrator passes its
|
|
18
|
+
* path via `NODE_V8_COVERAGE`; every spawned worker writes its own
|
|
19
|
+
* `coverage-*.json` on exit. Returns an env bag the pool forwards.
|
|
20
|
+
*/
|
|
21
|
+
export async function openSession(baseDir) {
|
|
22
|
+
const root = baseDir ?? path.join(process.cwd(), ".helix-coverage");
|
|
23
|
+
const unique = `run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
24
|
+
const envDir = path.join(root, unique);
|
|
25
|
+
await mkdir(envDir, { recursive: true });
|
|
26
|
+
return {
|
|
27
|
+
envDir,
|
|
28
|
+
env: {
|
|
29
|
+
NODE_V8_COVERAGE: envDir,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const KNOWN_REPORTERS = new Set(["text-summary", "lcov", "json-summary"]);
|
|
34
|
+
/**
|
|
35
|
+
* After all workers have exited, read the raw v8 output, aggregate, emit
|
|
36
|
+
* reporters + enforce thresholds.
|
|
37
|
+
*
|
|
38
|
+
* The temp dir is removed in `finally` so a write/aggregate failure
|
|
39
|
+
* doesn't leak gigabytes of raw V8 JSON under `.helix-coverage/`.
|
|
40
|
+
*/
|
|
41
|
+
export async function finalise(opts) {
|
|
42
|
+
try {
|
|
43
|
+
const raw = await collect(opts.session.envDir);
|
|
44
|
+
const filtered = filter(raw, {
|
|
45
|
+
root: opts.root,
|
|
46
|
+
include: opts.include,
|
|
47
|
+
exclude: opts.exclude,
|
|
48
|
+
});
|
|
49
|
+
const summary = aggregate(filtered);
|
|
50
|
+
// Treat empty array as "use defaults" — same as undefined.
|
|
51
|
+
const requested = opts.reporters && opts.reporters.length > 0
|
|
52
|
+
? opts.reporters
|
|
53
|
+
: ["text-summary", "lcov"];
|
|
54
|
+
// Warn on unknown reporter names so typos surface (instead of the
|
|
55
|
+
// reporter silently being skipped).
|
|
56
|
+
for (const r of requested) {
|
|
57
|
+
if (!KNOWN_REPORTERS.has(r)) {
|
|
58
|
+
process.stderr.write(`helix-coverage: unknown reporter "${r}" — known: ${[...KNOWN_REPORTERS].join(", ")}\n`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const outputDir = opts.outputDir ?? path.join(opts.root, "coverage");
|
|
62
|
+
await mkdir(outputDir, { recursive: true });
|
|
63
|
+
const reportFiles = [];
|
|
64
|
+
if (requested.includes("lcov")) {
|
|
65
|
+
const file = path.join(outputDir, "lcov.info");
|
|
66
|
+
await writeFile(file, lcov(summary, opts.root), "utf8");
|
|
67
|
+
reportFiles.push(file);
|
|
68
|
+
}
|
|
69
|
+
if (requested.includes("json-summary")) {
|
|
70
|
+
const file = path.join(outputDir, "coverage-summary.json");
|
|
71
|
+
await writeFile(file, jsonSummary(summary, opts.root), "utf8");
|
|
72
|
+
reportFiles.push(file);
|
|
73
|
+
}
|
|
74
|
+
const textReport = requested.includes("text-summary")
|
|
75
|
+
? textSummary(summary, opts.root)
|
|
76
|
+
: "";
|
|
77
|
+
const violations = opts.thresholds ? enforce(summary, opts.thresholds) : [];
|
|
78
|
+
return { summary, violations, textReport, reportFiles };
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
// Always tidy the temp dir — even on aggregate / writeFile failure.
|
|
82
|
+
await rm(opts.session.envDir, { recursive: true, force: true });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/coverage/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `coverage-summary.json` — Istanbul-compatible shape consumed by CI
|
|
3
|
+
* tooling (lcov-reporter-action, Codecov uploaders that prefer JSON).
|
|
4
|
+
*
|
|
5
|
+
* File keys are emitted as paths RELATIVE to `root` so the artifact is
|
|
6
|
+
* portable across machines. The reserved `total` key holds the
|
|
7
|
+
* aggregate; if a real file path collides with it (extraordinarily
|
|
8
|
+
* unlikely after relativisation), we keep the totals row and skip the
|
|
9
|
+
* collision rather than overwrite — protecting the consumer's invariant.
|
|
10
|
+
*/
|
|
11
|
+
import type { CoverageSummary } from "../types.js";
|
|
12
|
+
export declare function jsonSummary(summary: CoverageSummary, root: string): string;
|
|
13
|
+
//# sourceMappingURL=json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../../src/cli/coverage/reporters/json.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAOnD,wBAAgB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAoB1E"}
|