@c9up/helix 0.1.3 → 0.1.4
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/dist/container/override.d.ts +46 -0
- 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/dist/container/spy.d.ts +21 -0
- 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/dist/index.js +19 -0
- 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/dist/runtime/index.d.ts +28 -0
- 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/dist/runtime/lifecycle.d.ts +11 -0
- 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 +65 -0
- package/dist/runtime/suite.d.ts.map +1 -0
- package/dist/runtime/suite.js +203 -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/dist/time/index.d.ts +16 -0
- 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/package.json +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aggregation: merge N raw coverage entries (possibly for the same file
|
|
3
|
+
* from different workers) into a single `CoverageSummary` with per-file
|
|
4
|
+
* and total line / function counts.
|
|
5
|
+
*
|
|
6
|
+
* Range merging strategy mirrors `v8-to-istanbul`:
|
|
7
|
+
* - Walk ranges OUTERMOST-first so inner ranges OVERWRITE the outer
|
|
8
|
+
* count for the lines they cover. A `count: 0` inner range carved
|
|
9
|
+
* out of a `count: 5` outer correctly marks those inner lines as
|
|
10
|
+
* uncovered, matching V8's block-coverage semantics. The previous
|
|
11
|
+
* `Math.max` strategy hid uncovered branches behind their outer
|
|
12
|
+
* function's hit count.
|
|
13
|
+
* - V8 emits BYTE offsets (UTF-8); we convert via Buffer.byteLength
|
|
14
|
+
* so non-ASCII source code maps lines correctly.
|
|
15
|
+
* - When two workers cover the same file:
|
|
16
|
+
* - if their `source` differs (cache-busting query loaded different
|
|
17
|
+
* content), we keep the longer source (best-effort) but emit a
|
|
18
|
+
* warning — offsets are only consistent within one source.
|
|
19
|
+
* - functions are deduplicated by `(name, startOffset)` so the
|
|
20
|
+
* lcov FNF count doesn't double.
|
|
21
|
+
*/
|
|
22
|
+
import type { CoverageSummary, RawFileCoverage } from "./types.js";
|
|
23
|
+
export declare function aggregate(raw: RawFileCoverage[]): CoverageSummary;
|
|
24
|
+
//# sourceMappingURL=aggregate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../../../src/cli/coverage/aggregate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EACX,eAAe,EAEf,eAAe,EAGf,MAAM,YAAY,CAAC;AA4JpB,wBAAgB,SAAS,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,eAAe,CA8CjE"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aggregation: merge N raw coverage entries (possibly for the same file
|
|
3
|
+
* from different workers) into a single `CoverageSummary` with per-file
|
|
4
|
+
* and total line / function counts.
|
|
5
|
+
*
|
|
6
|
+
* Range merging strategy mirrors `v8-to-istanbul`:
|
|
7
|
+
* - Walk ranges OUTERMOST-first so inner ranges OVERWRITE the outer
|
|
8
|
+
* count for the lines they cover. A `count: 0` inner range carved
|
|
9
|
+
* out of a `count: 5` outer correctly marks those inner lines as
|
|
10
|
+
* uncovered, matching V8's block-coverage semantics. The previous
|
|
11
|
+
* `Math.max` strategy hid uncovered branches behind their outer
|
|
12
|
+
* function's hit count.
|
|
13
|
+
* - V8 emits BYTE offsets (UTF-8); we convert via Buffer.byteLength
|
|
14
|
+
* so non-ASCII source code maps lines correctly.
|
|
15
|
+
* - When two workers cover the same file:
|
|
16
|
+
* - if their `source` differs (cache-busting query loaded different
|
|
17
|
+
* content), we keep the longer source (best-effort) but emit a
|
|
18
|
+
* warning — offsets are only consistent within one source.
|
|
19
|
+
* - functions are deduplicated by `(name, startOffset)` so the
|
|
20
|
+
* lcov FNF count doesn't double.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Build a function `byteOffset → 1-based line number` over `source`.
|
|
24
|
+
* V8 offsets are UTF-8 byte offsets, so we walk the string code-unit by
|
|
25
|
+
* code-unit and accumulate byte length to keep both indices in sync.
|
|
26
|
+
*
|
|
27
|
+
* Returns `[mapper, totalBytes]`. `totalBytes` is needed so callers can
|
|
28
|
+
* detect offsets pointing past EOF (corrupt input) and clamp.
|
|
29
|
+
*/
|
|
30
|
+
function buildOffsetToLine(source) {
|
|
31
|
+
const lineStarts = [0];
|
|
32
|
+
let byteIndex = 0;
|
|
33
|
+
for (let i = 0; i < source.length; i += 1) {
|
|
34
|
+
const code = source.charCodeAt(i);
|
|
35
|
+
// UTF-16 surrogate pair → encodes a single 4-byte UTF-8 char.
|
|
36
|
+
if (code >= 0xd800 && code <= 0xdbff && i + 1 < source.length) {
|
|
37
|
+
const next = source.charCodeAt(i + 1);
|
|
38
|
+
if (next >= 0xdc00 && next <= 0xdfff) {
|
|
39
|
+
byteIndex += 4;
|
|
40
|
+
i += 1;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Lone surrogate or BMP char — Buffer.byteLength of one code unit:
|
|
45
|
+
// < 0x80 → 1 byte
|
|
46
|
+
// < 0x800 → 2 bytes
|
|
47
|
+
// else → 3 bytes (BMP non-surrogate)
|
|
48
|
+
if (code < 0x80) {
|
|
49
|
+
byteIndex += 1;
|
|
50
|
+
if (code === 10 /* \n */)
|
|
51
|
+
lineStarts.push(byteIndex);
|
|
52
|
+
}
|
|
53
|
+
else if (code < 0x800) {
|
|
54
|
+
byteIndex += 2;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
byteIndex += 3;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const totalBytes = byteIndex;
|
|
61
|
+
const mapper = (offset) => {
|
|
62
|
+
const clamped = Math.max(0, Math.min(offset, totalBytes));
|
|
63
|
+
// Binary search for the largest lineStart <= clamped.
|
|
64
|
+
let lo = 0;
|
|
65
|
+
let hi = lineStarts.length - 1;
|
|
66
|
+
while (lo < hi) {
|
|
67
|
+
const mid = (lo + hi + 1) >>> 1;
|
|
68
|
+
if (lineStarts[mid] <= clamped)
|
|
69
|
+
lo = mid;
|
|
70
|
+
else
|
|
71
|
+
hi = mid - 1;
|
|
72
|
+
}
|
|
73
|
+
return lo + 1;
|
|
74
|
+
};
|
|
75
|
+
return [mapper, totalBytes];
|
|
76
|
+
}
|
|
77
|
+
function computeFileSummary(entry) {
|
|
78
|
+
const [offsetToLine] = buildOffsetToLine(entry.source);
|
|
79
|
+
const lineHitsMap = new Map();
|
|
80
|
+
const functionHits = [];
|
|
81
|
+
let fnCovered = 0;
|
|
82
|
+
// Apply ranges across ALL functions in one global pass, sorted by
|
|
83
|
+
// span DESC. The whole-file pseudo-function (largest span) lands
|
|
84
|
+
// first; inner functions and their inner ranges overwrite — so a
|
|
85
|
+
// never-called inner function correctly drops its lines back to
|
|
86
|
+
// count=0 even though the script itself executed at count=1.
|
|
87
|
+
const allRanges = [];
|
|
88
|
+
for (const fn of entry.functions) {
|
|
89
|
+
for (const r of fn.ranges) {
|
|
90
|
+
if (r.endOffset > r.startOffset)
|
|
91
|
+
allRanges.push(r);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
allRanges.sort((a, b) => {
|
|
95
|
+
const spanA = a.endOffset - a.startOffset;
|
|
96
|
+
const spanB = b.endOffset - b.startOffset;
|
|
97
|
+
if (spanA !== spanB)
|
|
98
|
+
return spanB - spanA;
|
|
99
|
+
return a.startOffset - b.startOffset;
|
|
100
|
+
});
|
|
101
|
+
for (const r of allRanges) {
|
|
102
|
+
const startLine = offsetToLine(r.startOffset);
|
|
103
|
+
const endLine = offsetToLine(r.endOffset - 1);
|
|
104
|
+
for (let line = startLine; line <= endLine; line += 1) {
|
|
105
|
+
lineHitsMap.set(line, r.count);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
for (const fn of entry.functions) {
|
|
109
|
+
const firstRange = fn.ranges[0];
|
|
110
|
+
// Skip pseudo-functions / synthetic entries with no usable range so
|
|
111
|
+
// reports don't carry `FN:0,name` (lcov rejects line < 1).
|
|
112
|
+
if (!firstRange)
|
|
113
|
+
continue;
|
|
114
|
+
const fnCount = firstRange.count;
|
|
115
|
+
const fnLine = offsetToLine(firstRange.startOffset);
|
|
116
|
+
if (fnCount > 0)
|
|
117
|
+
fnCovered += 1;
|
|
118
|
+
functionHits.push({
|
|
119
|
+
name: fn.functionName || "(anonymous)",
|
|
120
|
+
line: Math.max(1, fnLine),
|
|
121
|
+
count: fnCount,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
const lineHits = Array.from(lineHitsMap.entries())
|
|
125
|
+
.map(([line, count]) => ({ line, count }))
|
|
126
|
+
.sort((a, b) => a.line - b.line);
|
|
127
|
+
const linesCovered = lineHits.filter((h) => h.count > 0).length;
|
|
128
|
+
const linesTotal = lineHits.length;
|
|
129
|
+
const fnTotal = functionHits.length;
|
|
130
|
+
return {
|
|
131
|
+
file: entry.file,
|
|
132
|
+
lines: { covered: linesCovered, total: linesTotal },
|
|
133
|
+
// Statements ≈ lines (V8 doesn't expose AST statement boundaries —
|
|
134
|
+
// matches Vitest's v8 provider).
|
|
135
|
+
statements: { covered: linesCovered, total: linesTotal },
|
|
136
|
+
functions: { covered: fnCovered, total: fnTotal },
|
|
137
|
+
// Branches deferred; report 0/0 so reporters / thresholds can still
|
|
138
|
+
// format the field consistently.
|
|
139
|
+
branches: { covered: 0, total: 0 },
|
|
140
|
+
lineHits,
|
|
141
|
+
functionHits,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Merge two raw entries for the same file. Functions are deduplicated by
|
|
146
|
+
* `(name, startOffset)` so concatenation doesn't double FNF in lcov.
|
|
147
|
+
* If `source` differs, we keep the longer one (best effort) and emit a
|
|
148
|
+
* stderr advisory — offsets only line up within one source.
|
|
149
|
+
*/
|
|
150
|
+
function mergeRaw(a, b) {
|
|
151
|
+
if (a.source && b.source && a.source !== b.source) {
|
|
152
|
+
process.stderr.write(`helix-coverage: ${a.file} has divergent source content across workers — line attribution may be off\n`);
|
|
153
|
+
}
|
|
154
|
+
const seen = new Set();
|
|
155
|
+
const merged = [];
|
|
156
|
+
for (const fn of [...a.functions, ...b.functions]) {
|
|
157
|
+
const startOffset = fn.ranges[0]?.startOffset ?? -1;
|
|
158
|
+
const key = `${fn.functionName}@${startOffset}`;
|
|
159
|
+
if (seen.has(key))
|
|
160
|
+
continue;
|
|
161
|
+
seen.add(key);
|
|
162
|
+
merged.push(fn);
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
file: a.file,
|
|
166
|
+
source: a.source.length >= b.source.length ? a.source : b.source,
|
|
167
|
+
functions: merged,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function pct(covered, total) {
|
|
171
|
+
if (total === 0)
|
|
172
|
+
return 100;
|
|
173
|
+
return Math.round((covered / total) * 10000) / 100;
|
|
174
|
+
}
|
|
175
|
+
export function aggregate(raw) {
|
|
176
|
+
const byFile = new Map();
|
|
177
|
+
for (const entry of raw) {
|
|
178
|
+
// Skip files we couldn't read source for — emitting a 1-line ghost
|
|
179
|
+
// summary based on collapsed line=1 mapping is worse than omission.
|
|
180
|
+
if (!entry.source) {
|
|
181
|
+
process.stderr.write(`helix-coverage: skipping ${entry.file} — source unreadable\n`);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const prev = byFile.get(entry.file);
|
|
185
|
+
byFile.set(entry.file, prev ? mergeRaw(prev, entry) : entry);
|
|
186
|
+
}
|
|
187
|
+
const files = Array.from(byFile.values())
|
|
188
|
+
.map(computeFileSummary)
|
|
189
|
+
// Files that ended up with 0 lines / 0 functions (no V8 data) are
|
|
190
|
+
// dropped — they distort per-file averages and clutter the table.
|
|
191
|
+
.filter((f) => f.lines.total > 0 || f.functions.total > 0)
|
|
192
|
+
.sort((a, b) => a.file.localeCompare(b.file));
|
|
193
|
+
const totals = {
|
|
194
|
+
lines: { covered: 0, total: 0, pct: 0 },
|
|
195
|
+
statements: { covered: 0, total: 0, pct: 0 },
|
|
196
|
+
functions: { covered: 0, total: 0, pct: 0 },
|
|
197
|
+
branches: { covered: 0, total: 0, pct: 0 },
|
|
198
|
+
};
|
|
199
|
+
for (const f of files) {
|
|
200
|
+
totals.lines.covered += f.lines.covered;
|
|
201
|
+
totals.lines.total += f.lines.total;
|
|
202
|
+
totals.statements.covered += f.statements.covered;
|
|
203
|
+
totals.statements.total += f.statements.total;
|
|
204
|
+
totals.functions.covered += f.functions.covered;
|
|
205
|
+
totals.functions.total += f.functions.total;
|
|
206
|
+
totals.branches.covered += f.branches.covered;
|
|
207
|
+
totals.branches.total += f.branches.total;
|
|
208
|
+
}
|
|
209
|
+
totals.lines.pct = pct(totals.lines.covered, totals.lines.total);
|
|
210
|
+
totals.statements.pct = pct(totals.statements.covered, totals.statements.total);
|
|
211
|
+
totals.functions.pct = pct(totals.functions.covered, totals.functions.total);
|
|
212
|
+
totals.branches.pct = pct(totals.branches.covered, totals.branches.total);
|
|
213
|
+
return { files, total: totals };
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=aggregate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate.js","sourceRoot":"","sources":["../../../src/cli/coverage/aggregate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads every `coverage-*.json` produced by the V8 profiler in a given
|
|
3
|
+
* directory, decodes `file://` URLs, and returns a normalised list of
|
|
4
|
+
* `RawFileCoverage` entries (one per unique script URL).
|
|
5
|
+
*
|
|
6
|
+
* Workers write coverage via `NODE_V8_COVERAGE=<dir>` — the orchestrator
|
|
7
|
+
* sets this env var on every spawn and reads the directory after all
|
|
8
|
+
* workers exit. Multiple workers may record the same file; we return ALL
|
|
9
|
+
* entries here and let `aggregate.ts` merge.
|
|
10
|
+
*/
|
|
11
|
+
import type { RawFileCoverage } from "./types.js";
|
|
12
|
+
export declare function collect(dir: string): Promise<RawFileCoverage[]>;
|
|
13
|
+
//# sourceMappingURL=collect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../../../src/cli/coverage/collect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,YAAY,CAAC;AAElE,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CA8CrE"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads every `coverage-*.json` produced by the V8 profiler in a given
|
|
3
|
+
* directory, decodes `file://` URLs, and returns a normalised list of
|
|
4
|
+
* `RawFileCoverage` entries (one per unique script URL).
|
|
5
|
+
*
|
|
6
|
+
* Workers write coverage via `NODE_V8_COVERAGE=<dir>` — the orchestrator
|
|
7
|
+
* sets this env var on every spawn and reads the directory after all
|
|
8
|
+
* workers exit. Multiple workers may record the same file; we return ALL
|
|
9
|
+
* entries here and let `aggregate.ts` merge.
|
|
10
|
+
*/
|
|
11
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
export async function collect(dir) {
|
|
15
|
+
let entries;
|
|
16
|
+
try {
|
|
17
|
+
entries = await readdir(dir);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
const jsonFiles = entries.filter((e) => e.endsWith(".json"));
|
|
23
|
+
const all = [];
|
|
24
|
+
for (const name of jsonFiles) {
|
|
25
|
+
const p = path.join(dir, name);
|
|
26
|
+
let parsed;
|
|
27
|
+
try {
|
|
28
|
+
const raw = await readFile(p, "utf8");
|
|
29
|
+
parsed = JSON.parse(raw);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
for (const script of parsed.result ?? []) {
|
|
35
|
+
if (!script.url?.startsWith("file://"))
|
|
36
|
+
continue;
|
|
37
|
+
// V8 sometimes appends `?query` params (our worker uses them as
|
|
38
|
+
// cache-busters) — strip them so the same file from two workers
|
|
39
|
+
// merges correctly.
|
|
40
|
+
const cleanUrl = script.url.split("?")[0];
|
|
41
|
+
let file;
|
|
42
|
+
try {
|
|
43
|
+
file = fileURLToPath(cleanUrl);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
let source = "";
|
|
49
|
+
try {
|
|
50
|
+
source = await readFile(file, "utf8");
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Source read may fail for transient temp files or modules that
|
|
54
|
+
// have been GC'd — leave empty; downstream stages fall back to
|
|
55
|
+
// offset-only computation.
|
|
56
|
+
}
|
|
57
|
+
all.push({
|
|
58
|
+
file,
|
|
59
|
+
source,
|
|
60
|
+
functions: script.functions ?? [],
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return all;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=collect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect.js","sourceRoot":"","sources":["../../../src/cli/coverage/collect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAW;IACxC,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACJ,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,CAAC;IACX,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/B,IAAI,MAAsB,CAAC;QAC3B,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YACtC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACR,SAAS;QACV,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,SAAS,CAAC;gBAAE,SAAS;YACjD,gEAAgE;YAChE,gEAAgE;YAChE,oBAAoB;YACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1C,IAAI,IAAY,CAAC;YACjB,IAAI,CAAC;gBACJ,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACR,SAAS;YACV,CAAC;YACD,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC;gBACJ,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACR,gEAAgE;gBAChE,+DAA+D;gBAC/D,2BAA2B;YAC5B,CAAC;YACD,GAAG,CAAC,IAAI,CAAC;gBACR,IAAI;gBACJ,MAAM;gBACN,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE;aACjC,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the default base ref to diff against. Tries, in order:
|
|
3
|
+
* 1. `origin/main`
|
|
4
|
+
* 2. `origin/master`
|
|
5
|
+
* 3. local `main`
|
|
6
|
+
* 4. local `master`
|
|
7
|
+
*
|
|
8
|
+
* Returns `undefined` if none of those exist (so the caller can warn
|
|
9
|
+
* instead of failing the run). Throws when the `git` binary itself is
|
|
10
|
+
* missing — the caller distinguishes "no repo / no ref" (skip
|
|
11
|
+
* gracefully) from "git not installed" (configuration error).
|
|
12
|
+
*/
|
|
13
|
+
export declare class GitMissingError extends Error {
|
|
14
|
+
constructor();
|
|
15
|
+
}
|
|
16
|
+
export declare function resolveBaseRef(cwd: string): string | undefined;
|
|
17
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/cli/coverage/diff/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,qBAAa,eAAgB,SAAQ,KAAK;;CAKzC;AAiBD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAM9D"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the default base ref to diff against. Tries, in order:
|
|
3
|
+
* 1. `origin/main`
|
|
4
|
+
* 2. `origin/master`
|
|
5
|
+
* 3. local `main`
|
|
6
|
+
* 4. local `master`
|
|
7
|
+
*
|
|
8
|
+
* Returns `undefined` if none of those exist (so the caller can warn
|
|
9
|
+
* instead of failing the run). Throws when the `git` binary itself is
|
|
10
|
+
* missing — the caller distinguishes "no repo / no ref" (skip
|
|
11
|
+
* gracefully) from "git not installed" (configuration error).
|
|
12
|
+
*/
|
|
13
|
+
import { spawnSync } from "node:child_process";
|
|
14
|
+
const CANDIDATES = ["origin/main", "origin/master", "main", "master"];
|
|
15
|
+
export class GitMissingError extends Error {
|
|
16
|
+
constructor() {
|
|
17
|
+
super("git binary not found on PATH");
|
|
18
|
+
this.name = "GitMissingError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function runGit(cwd, args) {
|
|
22
|
+
const result = spawnSync("git", args, {
|
|
23
|
+
cwd,
|
|
24
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
25
|
+
});
|
|
26
|
+
const err = result.error;
|
|
27
|
+
if (err?.code === "ENOENT")
|
|
28
|
+
throw new GitMissingError();
|
|
29
|
+
return { ok: result.status === 0 };
|
|
30
|
+
}
|
|
31
|
+
function refExists(cwd, ref) {
|
|
32
|
+
return runGit(cwd, ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`])
|
|
33
|
+
.ok;
|
|
34
|
+
}
|
|
35
|
+
export function resolveBaseRef(cwd) {
|
|
36
|
+
if (!runGit(cwd, ["rev-parse", "--git-dir"]).ok)
|
|
37
|
+
return undefined;
|
|
38
|
+
for (const cand of CANDIDATES) {
|
|
39
|
+
if (refExists(cwd, cand))
|
|
40
|
+
return cand;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../src/cli/coverage/diff/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,UAAU,GAAG,CAAC,aAAa,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEtE,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACzC;QACC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAC/B,CAAC;CACD;AAED,SAAS,MAAM,CAAC,GAAW,EAAE,IAAc;IAC1C,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;QACrC,GAAG;QACH,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;KACjC,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,MAAM,CAAC,KAA0C,CAAC;IAC9D,IAAI,GAAG,EAAE,IAAI,KAAK,QAAQ;QAAE,MAAM,IAAI,eAAe,EAAE,CAAC;IACxD,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;AACpC,CAAC;AAED,SAAS,SAAS,CAAC,GAAW,EAAE,GAAW;IAC1C,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,GAAG,WAAW,CAAC,CAAC;SACzE,EAAE,CAAC;AACN,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACzC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE;QAAE,OAAO,SAAS,CAAC;IAClE,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACvC,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff-coverage facade — wires base resolution → git diff → parser →
|
|
3
|
+
* overlay → reporters → thresholds. Called by `run.ts` after the
|
|
4
|
+
* full-tree finalise.
|
|
5
|
+
*/
|
|
6
|
+
import type { CoverageSummary, ThresholdViolation } from "../types.js";
|
|
7
|
+
import type { DiffOptions, DiffSummary } from "./types.js";
|
|
8
|
+
export type { DiffOptions, DiffSummary } from "./types.js";
|
|
9
|
+
export interface DiffFinaliseInput extends DiffOptions {
|
|
10
|
+
root: string;
|
|
11
|
+
coverage: CoverageSummary;
|
|
12
|
+
}
|
|
13
|
+
export interface DiffFinaliseResult {
|
|
14
|
+
summary: DiffSummary;
|
|
15
|
+
violations: ThresholdViolation[];
|
|
16
|
+
textReport: string;
|
|
17
|
+
reportFiles: string[];
|
|
18
|
+
/** When `undefined`, the diff stage was skipped (not in a repo, no
|
|
19
|
+
* base ref, etc.) — callers should print `warning` and move on. */
|
|
20
|
+
warning?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function finaliseDiff(input: DiffFinaliseInput): Promise<DiffFinaliseResult>;
|
|
23
|
+
/** Reformat threshold violations with the `coverage-diff:` prefix. */
|
|
24
|
+
export declare function diffViolationSummary(violations: ThresholdViolation[]): string;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/coverage/diff/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EACX,eAAe,EAEf,kBAAkB,EAClB,MAAM,aAAa,CAAC;AAKrB,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE3D,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,eAAe,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IAClC,OAAO,EAAE,WAAW,CAAC;IACrB,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB;wEACoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAuDD,wBAAsB,YAAY,CACjC,KAAK,EAAE,iBAAiB,GACtB,OAAO,CAAC,kBAAkB,CAAC,CA4D7B;AAED,sEAAsE;AACtE,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAI7E"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff-coverage facade — wires base resolution → git diff → parser →
|
|
3
|
+
* overlay → reporters → thresholds. Called by `run.ts` after the
|
|
4
|
+
* full-tree finalise.
|
|
5
|
+
*/
|
|
6
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { enforce } from "../thresholds.js";
|
|
9
|
+
import { GitMissingError, resolveBaseRef } from "./base.js";
|
|
10
|
+
import { overlay } from "./overlay.js";
|
|
11
|
+
import { parseDiff } from "./parse.js";
|
|
12
|
+
import { diffJson, diffTextSummary } from "./reporters.js";
|
|
13
|
+
/**
|
|
14
|
+
* Wrap the diff totals into a `CoverageSummary`-shaped object so we can
|
|
15
|
+
* reuse the full-tree `enforce()` helper. Only `lines`/`statements` are
|
|
16
|
+
* populated; `functions`/`branches` are unsupported in diff mode and are
|
|
17
|
+
* rejected upfront in `validateDiffThresholds`.
|
|
18
|
+
*/
|
|
19
|
+
function toCoverageSummary(diff) {
|
|
20
|
+
return {
|
|
21
|
+
files: [],
|
|
22
|
+
total: {
|
|
23
|
+
lines: {
|
|
24
|
+
covered: diff.total.covered,
|
|
25
|
+
total: diff.total.added,
|
|
26
|
+
pct: diff.total.pct,
|
|
27
|
+
},
|
|
28
|
+
statements: {
|
|
29
|
+
covered: diff.total.covered,
|
|
30
|
+
total: diff.total.added,
|
|
31
|
+
pct: diff.total.pct,
|
|
32
|
+
},
|
|
33
|
+
functions: { covered: 0, total: 0, pct: 100 },
|
|
34
|
+
branches: { covered: 0, total: 0, pct: 100 },
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function violationLine(metric, actual, threshold) {
|
|
39
|
+
return `coverage-diff: ${metric} ${actual.toFixed(1)} < threshold ${threshold}`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Reject `functions`/`branches` thresholds in diff mode — we only track
|
|
43
|
+
* line-level diff coverage today, so silently passing those metrics
|
|
44
|
+
* would let users gate on metrics that always read 100%.
|
|
45
|
+
*/
|
|
46
|
+
function validateDiffThresholds(t) {
|
|
47
|
+
if (!t)
|
|
48
|
+
return;
|
|
49
|
+
const unsupported = [];
|
|
50
|
+
if (typeof t.functions === "number" && t.functions > 0)
|
|
51
|
+
unsupported.push("functions");
|
|
52
|
+
if (typeof t.branches === "number" && t.branches > 0)
|
|
53
|
+
unsupported.push("branches");
|
|
54
|
+
if (unsupported.length > 0) {
|
|
55
|
+
throw new Error(`diff-cov thresholds: ${unsupported.join(", ")} are not supported (line-only). Drop those keys.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function finaliseDiff(input) {
|
|
59
|
+
validateDiffThresholds(input.thresholds);
|
|
60
|
+
const cwd = input.cwd ?? input.root;
|
|
61
|
+
let base;
|
|
62
|
+
try {
|
|
63
|
+
base = input.base ?? resolveBaseRef(cwd);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
if (err instanceof GitMissingError) {
|
|
67
|
+
return {
|
|
68
|
+
summary: { files: [], total: { added: 0, covered: 0, pct: 100 } },
|
|
69
|
+
violations: [],
|
|
70
|
+
textReport: "",
|
|
71
|
+
reportFiles: [],
|
|
72
|
+
warning: "diff-cov: git binary not found on PATH. Skipping.",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
77
|
+
if (!base) {
|
|
78
|
+
return {
|
|
79
|
+
summary: { files: [], total: { added: 0, covered: 0, pct: 100 } },
|
|
80
|
+
violations: [],
|
|
81
|
+
textReport: "",
|
|
82
|
+
reportFiles: [],
|
|
83
|
+
warning: "diff-cov: no git base ref resolved (origin/main, main, master). Skipping.",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
let diffMap;
|
|
87
|
+
try {
|
|
88
|
+
diffMap = parseDiff({ cwd, base });
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
return {
|
|
92
|
+
summary: { files: [], total: { added: 0, covered: 0, pct: 100 } },
|
|
93
|
+
violations: [],
|
|
94
|
+
textReport: "",
|
|
95
|
+
reportFiles: [],
|
|
96
|
+
warning: `diff-cov: ${err instanceof Error ? err.message : String(err)}`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const summary = overlay(input.coverage, diffMap);
|
|
100
|
+
const reportFiles = [];
|
|
101
|
+
const outputDir = input.outputDir ?? path.join(input.root, "coverage");
|
|
102
|
+
await mkdir(outputDir, { recursive: true });
|
|
103
|
+
const file = path.join(outputDir, "coverage-diff.json");
|
|
104
|
+
await writeFile(file, diffJson(summary, input.root), "utf8");
|
|
105
|
+
reportFiles.push(file);
|
|
106
|
+
const textReport = diffTextSummary(summary, input.root);
|
|
107
|
+
let violations = [];
|
|
108
|
+
if (input.thresholds) {
|
|
109
|
+
violations = enforce(toCoverageSummary(summary), input.thresholds);
|
|
110
|
+
}
|
|
111
|
+
return { summary, violations, textReport, reportFiles };
|
|
112
|
+
}
|
|
113
|
+
/** Reformat threshold violations with the `coverage-diff:` prefix. */
|
|
114
|
+
export function diffViolationSummary(violations) {
|
|
115
|
+
return violations
|
|
116
|
+
.map((v) => violationLine(v.metric, v.actual, v.threshold))
|
|
117
|
+
.join("\n");
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/cli/coverage/diff/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
import type { CoverageSummary } from "../types.js";
|
|
17
|
+
import type { DiffMap, DiffSummary } from "./types.js";
|
|
18
|
+
export declare function overlay(coverage: CoverageSummary, diff: DiffMap): DiffSummary;
|
|
19
|
+
//# sourceMappingURL=overlay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../../../src/cli/coverage/diff/overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAmB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAOxE,wBAAgB,OAAO,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,GAAG,WAAW,CAqC7E"}
|