@code-pushup/coverage-plugin 0.44.4 → 0.45.1
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/README.md +6 -1
- package/bin.js +506 -355
- package/index.js +981 -970
- package/package.json +3 -3
- package/src/lib/nx/coverage-paths.d.ts +6 -1
- package/src/lib/runner/constants.d.ts +1 -0
- package/src/lib/runner/lcov/lcov-runner.d.ts +7 -0
- package/src/lib/runner/lcov/merge-lcov.d.ts +6 -0
package/bin.js
CHANGED
|
@@ -3,301 +3,6 @@ import chalk5 from "chalk";
|
|
|
3
3
|
import { writeFile } from "node:fs/promises";
|
|
4
4
|
import { dirname } from "node:path";
|
|
5
5
|
|
|
6
|
-
// packages/utils/src/lib/text-formats/constants.ts
|
|
7
|
-
var NEW_LINE = "\n";
|
|
8
|
-
var TAB = " ";
|
|
9
|
-
|
|
10
|
-
// packages/utils/src/lib/text-formats/html/details.ts
|
|
11
|
-
function details(title, content, cfg = { open: false }) {
|
|
12
|
-
return `<details${cfg.open ? " open" : ""}>${NEW_LINE}<summary>${title}</summary>${NEW_LINE}${// ⚠️ The blank line is needed to ensure Markdown in content is rendered correctly.
|
|
13
|
-
NEW_LINE}${content}${NEW_LINE}${// @TODO in the future we could consider adding it only if the content ends with a code block
|
|
14
|
-
// ⚠️ The blank line ensure Markdown in content is rendered correctly.
|
|
15
|
-
NEW_LINE}</details>${// ⚠️ The blank line is needed to ensure Markdown after details is rendered correctly.
|
|
16
|
-
NEW_LINE}`;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// packages/utils/src/lib/text-formats/html/font-style.ts
|
|
20
|
-
var boldElement = "b";
|
|
21
|
-
function bold(text) {
|
|
22
|
-
return `<${boldElement}>${text}</${boldElement}>`;
|
|
23
|
-
}
|
|
24
|
-
var italicElement = "i";
|
|
25
|
-
function italic(text) {
|
|
26
|
-
return `<${italicElement}>${text}</${italicElement}>`;
|
|
27
|
-
}
|
|
28
|
-
var codeElement = "code";
|
|
29
|
-
function code(text) {
|
|
30
|
-
return `<${codeElement}>${text}</${codeElement}>`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// packages/utils/src/lib/text-formats/html/link.ts
|
|
34
|
-
function link(href, text) {
|
|
35
|
-
return `<a href="${href}">${text || href}"</a>`;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// packages/utils/src/lib/transform.ts
|
|
39
|
-
import { platform } from "node:os";
|
|
40
|
-
function toUnixNewlines(text) {
|
|
41
|
-
return platform() === "win32" ? text.replace(/\r\n/g, "\n") : text;
|
|
42
|
-
}
|
|
43
|
-
function capitalize(text) {
|
|
44
|
-
return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
|
|
45
|
-
1
|
|
46
|
-
)}`;
|
|
47
|
-
}
|
|
48
|
-
function toNumberPrecision(value, decimalPlaces) {
|
|
49
|
-
return Number(
|
|
50
|
-
`${Math.round(
|
|
51
|
-
Number.parseFloat(`${value}e${decimalPlaces}`)
|
|
52
|
-
)}e-${decimalPlaces}`
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
function toOrdinal(value) {
|
|
56
|
-
if (value % 10 === 1 && value % 100 !== 11) {
|
|
57
|
-
return `${value}st`;
|
|
58
|
-
}
|
|
59
|
-
if (value % 10 === 2 && value % 100 !== 12) {
|
|
60
|
-
return `${value}nd`;
|
|
61
|
-
}
|
|
62
|
-
if (value % 10 === 3 && value % 100 !== 13) {
|
|
63
|
-
return `${value}rd`;
|
|
64
|
-
}
|
|
65
|
-
return `${value}th`;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// packages/utils/src/lib/table.ts
|
|
69
|
-
function rowToStringArray({ rows, columns = [] }) {
|
|
70
|
-
if (Array.isArray(rows.at(0)) && typeof columns.at(0) === "object") {
|
|
71
|
-
throw new TypeError(
|
|
72
|
-
"Column can`t be object when rows are primitive values"
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
return rows.map((row) => {
|
|
76
|
-
if (Array.isArray(row)) {
|
|
77
|
-
return row.map(String);
|
|
78
|
-
}
|
|
79
|
-
const objectRow = row;
|
|
80
|
-
if (columns.length === 0 || typeof columns.at(0) === "string") {
|
|
81
|
-
return Object.values(objectRow).map(String);
|
|
82
|
-
}
|
|
83
|
-
return columns.map(
|
|
84
|
-
({ key }) => String(objectRow[key])
|
|
85
|
-
);
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
function columnsToStringArray({ rows, columns = [] }) {
|
|
89
|
-
const firstRow = rows.at(0);
|
|
90
|
-
const primitiveRows = Array.isArray(firstRow);
|
|
91
|
-
if (typeof columns.at(0) === "string" && !primitiveRows) {
|
|
92
|
-
throw new Error("invalid union type. Caught by model parsing.");
|
|
93
|
-
}
|
|
94
|
-
if (columns.length === 0) {
|
|
95
|
-
if (Array.isArray(firstRow)) {
|
|
96
|
-
return firstRow.map((_, idx) => String(idx));
|
|
97
|
-
}
|
|
98
|
-
return Object.keys(firstRow);
|
|
99
|
-
}
|
|
100
|
-
if (typeof columns.at(0) === "string") {
|
|
101
|
-
return columns.map(String);
|
|
102
|
-
}
|
|
103
|
-
const cols = columns;
|
|
104
|
-
return cols.map(({ label, key }) => label ?? capitalize(key));
|
|
105
|
-
}
|
|
106
|
-
function getColumnAlignmentForKeyAndIndex(targetKey, targetIdx, columns = []) {
|
|
107
|
-
const column = columns.at(targetIdx) ?? columns.find((col) => col.key === targetKey);
|
|
108
|
-
if (typeof column === "string") {
|
|
109
|
-
return column;
|
|
110
|
-
} else if (typeof column === "object") {
|
|
111
|
-
return column.align ?? "center";
|
|
112
|
-
} else {
|
|
113
|
-
return "center";
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
function getColumnAlignmentForIndex(targetIdx, columns = []) {
|
|
117
|
-
const column = columns.at(targetIdx);
|
|
118
|
-
if (column == null) {
|
|
119
|
-
return "center";
|
|
120
|
-
} else if (typeof column === "string") {
|
|
121
|
-
return column;
|
|
122
|
-
} else if (typeof column === "object") {
|
|
123
|
-
return column.align ?? "center";
|
|
124
|
-
} else {
|
|
125
|
-
return "center";
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
function getColumnAlignments({
|
|
129
|
-
rows,
|
|
130
|
-
columns = []
|
|
131
|
-
}) {
|
|
132
|
-
if (rows.at(0) == null) {
|
|
133
|
-
throw new Error("first row can`t be undefined.");
|
|
134
|
-
}
|
|
135
|
-
if (Array.isArray(rows.at(0))) {
|
|
136
|
-
const firstPrimitiveRow = rows.at(0);
|
|
137
|
-
return Array.from({ length: firstPrimitiveRow.length }).map(
|
|
138
|
-
(_, idx) => getColumnAlignmentForIndex(idx, columns)
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
const firstObject = rows.at(0);
|
|
142
|
-
return Object.keys(firstObject).map(
|
|
143
|
-
(key, idx) => getColumnAlignmentForKeyAndIndex(key, idx, columns)
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// packages/utils/src/lib/text-formats/html/table.ts
|
|
148
|
-
function wrap(elem, content) {
|
|
149
|
-
return `<${elem}>${content}</${elem}>${NEW_LINE}`;
|
|
150
|
-
}
|
|
151
|
-
function wrapRow(content) {
|
|
152
|
-
const elem = "tr";
|
|
153
|
-
return `<${elem}>${NEW_LINE}${content}</${elem}>${NEW_LINE}`;
|
|
154
|
-
}
|
|
155
|
-
function table(tableData) {
|
|
156
|
-
if (tableData.rows.length === 0) {
|
|
157
|
-
throw new Error("Data can't be empty");
|
|
158
|
-
}
|
|
159
|
-
const tableHeaderCols = columnsToStringArray(tableData).map((s) => wrap("th", s)).join("");
|
|
160
|
-
const tableHeaderRow = wrapRow(tableHeaderCols);
|
|
161
|
-
const tableBody = rowToStringArray(tableData).map((arr) => {
|
|
162
|
-
const columns = arr.map((s) => wrap("td", s)).join("");
|
|
163
|
-
return wrapRow(columns);
|
|
164
|
-
}).join("");
|
|
165
|
-
return wrap("table", `${NEW_LINE}${tableHeaderRow}${tableBody}`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// packages/utils/src/lib/text-formats/md/font-style.ts
|
|
169
|
-
var boldWrap = "**";
|
|
170
|
-
function bold2(text) {
|
|
171
|
-
return `${boldWrap}${text}${boldWrap}`;
|
|
172
|
-
}
|
|
173
|
-
var italicWrap = "_";
|
|
174
|
-
function italic2(text) {
|
|
175
|
-
return `${italicWrap}${text}${italicWrap}`;
|
|
176
|
-
}
|
|
177
|
-
var strikeThroughWrap = "~";
|
|
178
|
-
function strikeThrough(text) {
|
|
179
|
-
return `${strikeThroughWrap}${text}${strikeThroughWrap}`;
|
|
180
|
-
}
|
|
181
|
-
var codeWrap = "`";
|
|
182
|
-
function code2(text) {
|
|
183
|
-
return `${codeWrap}${text}${codeWrap}`;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// packages/utils/src/lib/text-formats/md/headline.ts
|
|
187
|
-
function headline(text, hierarchy = 1) {
|
|
188
|
-
return `${"#".repeat(hierarchy)} ${text}${NEW_LINE}`;
|
|
189
|
-
}
|
|
190
|
-
function h(text, hierarchy = 1) {
|
|
191
|
-
return headline(text, hierarchy);
|
|
192
|
-
}
|
|
193
|
-
function h1(text) {
|
|
194
|
-
return headline(text, 1);
|
|
195
|
-
}
|
|
196
|
-
function h2(text) {
|
|
197
|
-
return headline(text, 2);
|
|
198
|
-
}
|
|
199
|
-
function h3(text) {
|
|
200
|
-
return headline(text, 3);
|
|
201
|
-
}
|
|
202
|
-
function h4(text) {
|
|
203
|
-
return headline(text, 4);
|
|
204
|
-
}
|
|
205
|
-
function h5(text) {
|
|
206
|
-
return headline(text, 5);
|
|
207
|
-
}
|
|
208
|
-
function h6(text) {
|
|
209
|
-
return headline(text, 6);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// packages/utils/src/lib/text-formats/md/image.ts
|
|
213
|
-
function image(src, alt) {
|
|
214
|
-
return ``;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// packages/utils/src/lib/text-formats/md/link.ts
|
|
218
|
-
function link2(href, text) {
|
|
219
|
-
return `[${text || href}](${href})`;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// packages/utils/src/lib/text-formats/md/list.ts
|
|
223
|
-
function li(text, order = "unordered") {
|
|
224
|
-
const style = order === "unordered" ? "-" : "- [ ]";
|
|
225
|
-
return `${style} ${text}`;
|
|
226
|
-
}
|
|
227
|
-
function indentation(text, level = 1) {
|
|
228
|
-
return `${TAB.repeat(level)}${text}`;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// packages/utils/src/lib/text-formats/md/paragraphs.ts
|
|
232
|
-
function paragraphs(...sections) {
|
|
233
|
-
return sections.filter(Boolean).join(`${NEW_LINE}${NEW_LINE}`);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// packages/utils/src/lib/text-formats/md/section.ts
|
|
237
|
-
function section(...contents) {
|
|
238
|
-
return `${lines(...contents)}${NEW_LINE}`;
|
|
239
|
-
}
|
|
240
|
-
function lines(...contents) {
|
|
241
|
-
return `${contents.filter(Boolean).join(NEW_LINE)}`;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// packages/utils/src/lib/text-formats/md/table.ts
|
|
245
|
-
var alignString = /* @__PURE__ */ new Map([
|
|
246
|
-
["left", ":--"],
|
|
247
|
-
["center", ":--:"],
|
|
248
|
-
["right", "--:"]
|
|
249
|
-
]);
|
|
250
|
-
function tableRow(rows) {
|
|
251
|
-
return `|${rows.join("|")}|`;
|
|
252
|
-
}
|
|
253
|
-
function table2(data) {
|
|
254
|
-
if (data.rows.length === 0) {
|
|
255
|
-
throw new Error("Data can't be empty");
|
|
256
|
-
}
|
|
257
|
-
const alignmentRow = getColumnAlignments(data).map(
|
|
258
|
-
(s) => alignString.get(s) ?? String(alignString.get("center"))
|
|
259
|
-
);
|
|
260
|
-
return section(
|
|
261
|
-
`${lines(
|
|
262
|
-
tableRow(columnsToStringArray(data)),
|
|
263
|
-
tableRow(alignmentRow),
|
|
264
|
-
...rowToStringArray(data).map(tableRow)
|
|
265
|
-
)}`
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// packages/utils/src/lib/text-formats/index.ts
|
|
270
|
-
var md = {
|
|
271
|
-
bold: bold2,
|
|
272
|
-
italic: italic2,
|
|
273
|
-
strikeThrough,
|
|
274
|
-
code: code2,
|
|
275
|
-
link: link2,
|
|
276
|
-
image,
|
|
277
|
-
headline,
|
|
278
|
-
h,
|
|
279
|
-
h1,
|
|
280
|
-
h2,
|
|
281
|
-
h3,
|
|
282
|
-
h4,
|
|
283
|
-
h5,
|
|
284
|
-
h6,
|
|
285
|
-
indentation,
|
|
286
|
-
lines,
|
|
287
|
-
li,
|
|
288
|
-
section,
|
|
289
|
-
paragraphs,
|
|
290
|
-
table: table2
|
|
291
|
-
};
|
|
292
|
-
var html = {
|
|
293
|
-
bold,
|
|
294
|
-
italic,
|
|
295
|
-
code,
|
|
296
|
-
link,
|
|
297
|
-
details,
|
|
298
|
-
table
|
|
299
|
-
};
|
|
300
|
-
|
|
301
6
|
// packages/models/src/lib/implementation/schemas.ts
|
|
302
7
|
import { MATERIAL_ICONS } from "vscode-material-icons";
|
|
303
8
|
import { z } from "zod";
|
|
@@ -407,6 +112,7 @@ var fileNameSchema = z.string().trim().regex(filenameRegex, {
|
|
|
407
112
|
}).min(1, { message: "file name is invalid" });
|
|
408
113
|
var positiveIntSchema = z.number().int().positive();
|
|
409
114
|
var nonnegativeIntSchema = z.number().int().nonnegative();
|
|
115
|
+
var nonnegativeNumberSchema = z.number().nonnegative();
|
|
410
116
|
function packageVersionSchema(options) {
|
|
411
117
|
const { versionDescription = "NPM version of the package", required } = options ?? {};
|
|
412
118
|
const packageSchema = z.string({ description: "NPM package name" });
|
|
@@ -419,7 +125,7 @@ function packageVersionSchema(options) {
|
|
|
419
125
|
{ description: "NPM package name and version of a published package" }
|
|
420
126
|
);
|
|
421
127
|
}
|
|
422
|
-
var weightSchema =
|
|
128
|
+
var weightSchema = nonnegativeNumberSchema.describe(
|
|
423
129
|
"Coefficient for the given score (use weight 0 if only for display)"
|
|
424
130
|
);
|
|
425
131
|
function weightedRefSchema(description, slugDescription) {
|
|
@@ -561,7 +267,7 @@ var tableObjectSchema = tableSharedSchema.merge(
|
|
|
561
267
|
var tableSchema = (description = "Table information") => z4.union([tablePrimitiveSchema, tableObjectSchema], { description });
|
|
562
268
|
|
|
563
269
|
// packages/models/src/lib/audit-output.ts
|
|
564
|
-
var auditValueSchema =
|
|
270
|
+
var auditValueSchema = nonnegativeNumberSchema.describe("Raw numeric value");
|
|
565
271
|
var auditDisplayValueSchema = z5.string({ description: "Formatted value (e.g. '0.9 s', '2.1 MB')" }).optional();
|
|
566
272
|
var auditDetailsSchema = z5.object(
|
|
567
273
|
{
|
|
@@ -992,71 +698,366 @@ var reportsDiffSchema = z15.object({
|
|
|
992
698
|
})
|
|
993
699
|
);
|
|
994
700
|
|
|
995
|
-
// packages/utils/src/lib/execute-process.ts
|
|
996
|
-
import { spawn } from "node:child_process";
|
|
701
|
+
// packages/utils/src/lib/execute-process.ts
|
|
702
|
+
import { spawn } from "node:child_process";
|
|
703
|
+
|
|
704
|
+
// packages/utils/src/lib/file-system.ts
|
|
705
|
+
import { bundleRequire } from "bundle-require";
|
|
706
|
+
import chalk2 from "chalk";
|
|
707
|
+
import { mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
|
|
708
|
+
import { join } from "node:path";
|
|
709
|
+
|
|
710
|
+
// packages/utils/src/lib/logging.ts
|
|
711
|
+
import isaacs_cliui from "@isaacs/cliui";
|
|
712
|
+
import { cliui } from "@poppinss/cliui";
|
|
713
|
+
import chalk from "chalk";
|
|
714
|
+
|
|
715
|
+
// packages/utils/src/lib/reports/constants.ts
|
|
716
|
+
var TERMINAL_WIDTH = 80;
|
|
717
|
+
|
|
718
|
+
// packages/utils/src/lib/logging.ts
|
|
719
|
+
var singletonUiInstance;
|
|
720
|
+
function ui() {
|
|
721
|
+
if (singletonUiInstance === void 0) {
|
|
722
|
+
singletonUiInstance = cliui();
|
|
723
|
+
}
|
|
724
|
+
return {
|
|
725
|
+
...singletonUiInstance,
|
|
726
|
+
row: (args) => {
|
|
727
|
+
logListItem(args);
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
var singletonisaacUi;
|
|
732
|
+
function logListItem(args) {
|
|
733
|
+
if (singletonisaacUi === void 0) {
|
|
734
|
+
singletonisaacUi = isaacs_cliui({ width: TERMINAL_WIDTH });
|
|
735
|
+
}
|
|
736
|
+
singletonisaacUi.div(...args);
|
|
737
|
+
const content = singletonisaacUi.toString();
|
|
738
|
+
singletonisaacUi.rows = [];
|
|
739
|
+
singletonUiInstance?.logger.log(content);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// packages/utils/src/lib/file-system.ts
|
|
743
|
+
async function readTextFile(path) {
|
|
744
|
+
const buffer = await readFile(path);
|
|
745
|
+
return buffer.toString();
|
|
746
|
+
}
|
|
747
|
+
async function readJsonFile(path) {
|
|
748
|
+
const text = await readTextFile(path);
|
|
749
|
+
return JSON.parse(text);
|
|
750
|
+
}
|
|
751
|
+
async function ensureDirectoryExists(baseDir) {
|
|
752
|
+
try {
|
|
753
|
+
await mkdir(baseDir, { recursive: true });
|
|
754
|
+
return;
|
|
755
|
+
} catch (error) {
|
|
756
|
+
ui().logger.info(error.message);
|
|
757
|
+
if (error.code !== "EEXIST") {
|
|
758
|
+
throw error;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
function pluginWorkDir(slug) {
|
|
763
|
+
return join("node_modules", ".code-pushup", slug);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// packages/utils/src/lib/text-formats/constants.ts
|
|
767
|
+
var NEW_LINE = "\n";
|
|
768
|
+
var TAB = " ";
|
|
769
|
+
|
|
770
|
+
// packages/utils/src/lib/text-formats/html/details.ts
|
|
771
|
+
function details(title, content, cfg = { open: false }) {
|
|
772
|
+
return `<details${cfg.open ? " open" : ""}>${NEW_LINE}<summary>${title}</summary>${NEW_LINE}${// ⚠️ The blank line is needed to ensure Markdown in content is rendered correctly.
|
|
773
|
+
NEW_LINE}${content}${NEW_LINE}${// @TODO in the future we could consider adding it only if the content ends with a code block
|
|
774
|
+
// ⚠️ The blank line ensure Markdown in content is rendered correctly.
|
|
775
|
+
NEW_LINE}</details>${// ⚠️ The blank line is needed to ensure Markdown after details is rendered correctly.
|
|
776
|
+
NEW_LINE}`;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// packages/utils/src/lib/text-formats/html/font-style.ts
|
|
780
|
+
var boldElement = "b";
|
|
781
|
+
function bold(text) {
|
|
782
|
+
return `<${boldElement}>${text}</${boldElement}>`;
|
|
783
|
+
}
|
|
784
|
+
var italicElement = "i";
|
|
785
|
+
function italic(text) {
|
|
786
|
+
return `<${italicElement}>${text}</${italicElement}>`;
|
|
787
|
+
}
|
|
788
|
+
var codeElement = "code";
|
|
789
|
+
function code(text) {
|
|
790
|
+
return `<${codeElement}>${text}</${codeElement}>`;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// packages/utils/src/lib/text-formats/html/link.ts
|
|
794
|
+
function link(href, text) {
|
|
795
|
+
return `<a href="${href}">${text || href}"</a>`;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// packages/utils/src/lib/transform.ts
|
|
799
|
+
import { platform } from "node:os";
|
|
800
|
+
function toUnixNewlines(text) {
|
|
801
|
+
return platform() === "win32" ? text.replace(/\r\n/g, "\n") : text;
|
|
802
|
+
}
|
|
803
|
+
function capitalize(text) {
|
|
804
|
+
return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
|
|
805
|
+
1
|
|
806
|
+
)}`;
|
|
807
|
+
}
|
|
808
|
+
function toNumberPrecision(value, decimalPlaces) {
|
|
809
|
+
return Number(
|
|
810
|
+
`${Math.round(
|
|
811
|
+
Number.parseFloat(`${value}e${decimalPlaces}`)
|
|
812
|
+
)}e-${decimalPlaces}`
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
function toOrdinal(value) {
|
|
816
|
+
if (value % 10 === 1 && value % 100 !== 11) {
|
|
817
|
+
return `${value}st`;
|
|
818
|
+
}
|
|
819
|
+
if (value % 10 === 2 && value % 100 !== 12) {
|
|
820
|
+
return `${value}nd`;
|
|
821
|
+
}
|
|
822
|
+
if (value % 10 === 3 && value % 100 !== 13) {
|
|
823
|
+
return `${value}rd`;
|
|
824
|
+
}
|
|
825
|
+
return `${value}th`;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// packages/utils/src/lib/table.ts
|
|
829
|
+
function rowToStringArray({ rows, columns = [] }) {
|
|
830
|
+
if (Array.isArray(rows.at(0)) && typeof columns.at(0) === "object") {
|
|
831
|
+
throw new TypeError(
|
|
832
|
+
"Column can`t be object when rows are primitive values"
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
return rows.map((row) => {
|
|
836
|
+
if (Array.isArray(row)) {
|
|
837
|
+
return row.map(String);
|
|
838
|
+
}
|
|
839
|
+
const objectRow = row;
|
|
840
|
+
if (columns.length === 0 || typeof columns.at(0) === "string") {
|
|
841
|
+
return Object.values(objectRow).map(String);
|
|
842
|
+
}
|
|
843
|
+
return columns.map(
|
|
844
|
+
({ key }) => String(objectRow[key])
|
|
845
|
+
);
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
function columnsToStringArray({ rows, columns = [] }) {
|
|
849
|
+
const firstRow = rows.at(0);
|
|
850
|
+
const primitiveRows = Array.isArray(firstRow);
|
|
851
|
+
if (typeof columns.at(0) === "string" && !primitiveRows) {
|
|
852
|
+
throw new Error("invalid union type. Caught by model parsing.");
|
|
853
|
+
}
|
|
854
|
+
if (columns.length === 0) {
|
|
855
|
+
if (Array.isArray(firstRow)) {
|
|
856
|
+
return firstRow.map((_, idx) => String(idx));
|
|
857
|
+
}
|
|
858
|
+
return Object.keys(firstRow);
|
|
859
|
+
}
|
|
860
|
+
if (typeof columns.at(0) === "string") {
|
|
861
|
+
return columns.map(String);
|
|
862
|
+
}
|
|
863
|
+
const cols = columns;
|
|
864
|
+
return cols.map(({ label, key }) => label ?? capitalize(key));
|
|
865
|
+
}
|
|
866
|
+
function getColumnAlignmentForKeyAndIndex(targetKey, targetIdx, columns = []) {
|
|
867
|
+
const column = columns.at(targetIdx) ?? columns.find((col) => col.key === targetKey);
|
|
868
|
+
if (typeof column === "string") {
|
|
869
|
+
return column;
|
|
870
|
+
} else if (typeof column === "object") {
|
|
871
|
+
return column.align ?? "center";
|
|
872
|
+
} else {
|
|
873
|
+
return "center";
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
function getColumnAlignmentForIndex(targetIdx, columns = []) {
|
|
877
|
+
const column = columns.at(targetIdx);
|
|
878
|
+
if (column == null) {
|
|
879
|
+
return "center";
|
|
880
|
+
} else if (typeof column === "string") {
|
|
881
|
+
return column;
|
|
882
|
+
} else if (typeof column === "object") {
|
|
883
|
+
return column.align ?? "center";
|
|
884
|
+
} else {
|
|
885
|
+
return "center";
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
function getColumnAlignments({
|
|
889
|
+
rows,
|
|
890
|
+
columns = []
|
|
891
|
+
}) {
|
|
892
|
+
if (rows.at(0) == null) {
|
|
893
|
+
throw new Error("first row can`t be undefined.");
|
|
894
|
+
}
|
|
895
|
+
if (Array.isArray(rows.at(0))) {
|
|
896
|
+
const firstPrimitiveRow = rows.at(0);
|
|
897
|
+
return Array.from({ length: firstPrimitiveRow.length }).map(
|
|
898
|
+
(_, idx) => getColumnAlignmentForIndex(idx, columns)
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
const firstObject = rows.at(0);
|
|
902
|
+
return Object.keys(firstObject).map(
|
|
903
|
+
(key, idx) => getColumnAlignmentForKeyAndIndex(key, idx, columns)
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// packages/utils/src/lib/text-formats/html/table.ts
|
|
908
|
+
function wrap(elem, content) {
|
|
909
|
+
return `<${elem}>${content}</${elem}>${NEW_LINE}`;
|
|
910
|
+
}
|
|
911
|
+
function wrapRow(content) {
|
|
912
|
+
const elem = "tr";
|
|
913
|
+
return `<${elem}>${NEW_LINE}${content}</${elem}>${NEW_LINE}`;
|
|
914
|
+
}
|
|
915
|
+
function table(tableData) {
|
|
916
|
+
if (tableData.rows.length === 0) {
|
|
917
|
+
throw new Error("Data can't be empty");
|
|
918
|
+
}
|
|
919
|
+
const tableHeaderCols = columnsToStringArray(tableData).map((s) => wrap("th", s)).join("");
|
|
920
|
+
const tableHeaderRow = wrapRow(tableHeaderCols);
|
|
921
|
+
const tableBody = rowToStringArray(tableData).map((arr) => {
|
|
922
|
+
const columns = arr.map((s) => wrap("td", s)).join("");
|
|
923
|
+
return wrapRow(columns);
|
|
924
|
+
}).join("");
|
|
925
|
+
return wrap("table", `${NEW_LINE}${tableHeaderRow}${tableBody}`);
|
|
926
|
+
}
|
|
997
927
|
|
|
998
|
-
// packages/utils/src/lib/
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
928
|
+
// packages/utils/src/lib/text-formats/md/font-style.ts
|
|
929
|
+
var boldWrap = "**";
|
|
930
|
+
function bold2(text) {
|
|
931
|
+
return `${boldWrap}${text}${boldWrap}`;
|
|
932
|
+
}
|
|
933
|
+
var italicWrap = "_";
|
|
934
|
+
function italic2(text) {
|
|
935
|
+
return `${italicWrap}${text}${italicWrap}`;
|
|
936
|
+
}
|
|
937
|
+
var strikeThroughWrap = "~";
|
|
938
|
+
function strikeThrough(text) {
|
|
939
|
+
return `${strikeThroughWrap}${text}${strikeThroughWrap}`;
|
|
940
|
+
}
|
|
941
|
+
var codeWrap = "`";
|
|
942
|
+
function code2(text) {
|
|
943
|
+
return `${codeWrap}${text}${codeWrap}`;
|
|
944
|
+
}
|
|
1003
945
|
|
|
1004
|
-
// packages/utils/src/lib/
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
946
|
+
// packages/utils/src/lib/text-formats/md/headline.ts
|
|
947
|
+
function headline(text, hierarchy = 1) {
|
|
948
|
+
return `${"#".repeat(hierarchy)} ${text}${NEW_LINE}`;
|
|
949
|
+
}
|
|
950
|
+
function h(text, hierarchy = 1) {
|
|
951
|
+
return headline(text, hierarchy);
|
|
952
|
+
}
|
|
953
|
+
function h1(text) {
|
|
954
|
+
return headline(text, 1);
|
|
955
|
+
}
|
|
956
|
+
function h2(text) {
|
|
957
|
+
return headline(text, 2);
|
|
958
|
+
}
|
|
959
|
+
function h3(text) {
|
|
960
|
+
return headline(text, 3);
|
|
961
|
+
}
|
|
962
|
+
function h4(text) {
|
|
963
|
+
return headline(text, 4);
|
|
964
|
+
}
|
|
965
|
+
function h5(text) {
|
|
966
|
+
return headline(text, 5);
|
|
967
|
+
}
|
|
968
|
+
function h6(text) {
|
|
969
|
+
return headline(text, 6);
|
|
970
|
+
}
|
|
1008
971
|
|
|
1009
|
-
// packages/utils/src/lib/
|
|
1010
|
-
|
|
972
|
+
// packages/utils/src/lib/text-formats/md/image.ts
|
|
973
|
+
function image(src, alt) {
|
|
974
|
+
return ``;
|
|
975
|
+
}
|
|
1011
976
|
|
|
1012
|
-
// packages/utils/src/lib/
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
if (singletonUiInstance === void 0) {
|
|
1016
|
-
singletonUiInstance = cliui();
|
|
1017
|
-
}
|
|
1018
|
-
return {
|
|
1019
|
-
...singletonUiInstance,
|
|
1020
|
-
row: (args) => {
|
|
1021
|
-
logListItem(args);
|
|
1022
|
-
}
|
|
1023
|
-
};
|
|
977
|
+
// packages/utils/src/lib/text-formats/md/link.ts
|
|
978
|
+
function link2(href, text) {
|
|
979
|
+
return `[${text || href}](${href})`;
|
|
1024
980
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
singletonUiInstance?.logger.log(content);
|
|
981
|
+
|
|
982
|
+
// packages/utils/src/lib/text-formats/md/list.ts
|
|
983
|
+
function li(text, order = "unordered") {
|
|
984
|
+
const style = order === "unordered" ? "-" : "- [ ]";
|
|
985
|
+
return `${style} ${text}`;
|
|
986
|
+
}
|
|
987
|
+
function indentation(text, level = 1) {
|
|
988
|
+
return `${TAB.repeat(level)}${text}`;
|
|
1034
989
|
}
|
|
1035
990
|
|
|
1036
|
-
// packages/utils/src/lib/
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
return buffer.toString();
|
|
991
|
+
// packages/utils/src/lib/text-formats/md/paragraphs.ts
|
|
992
|
+
function paragraphs(...sections) {
|
|
993
|
+
return sections.filter(Boolean).join(`${NEW_LINE}${NEW_LINE}`);
|
|
1040
994
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
995
|
+
|
|
996
|
+
// packages/utils/src/lib/text-formats/md/section.ts
|
|
997
|
+
function section(...contents) {
|
|
998
|
+
return `${lines(...contents)}${NEW_LINE}`;
|
|
1044
999
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
await mkdir(baseDir, { recursive: true });
|
|
1048
|
-
return;
|
|
1049
|
-
} catch (error) {
|
|
1050
|
-
ui().logger.info(error.message);
|
|
1051
|
-
if (error.code !== "EEXIST") {
|
|
1052
|
-
throw error;
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1000
|
+
function lines(...contents) {
|
|
1001
|
+
return `${contents.filter(Boolean).join(NEW_LINE)}`;
|
|
1055
1002
|
}
|
|
1056
|
-
|
|
1057
|
-
|
|
1003
|
+
|
|
1004
|
+
// packages/utils/src/lib/text-formats/md/table.ts
|
|
1005
|
+
var alignString = /* @__PURE__ */ new Map([
|
|
1006
|
+
["left", ":--"],
|
|
1007
|
+
["center", ":--:"],
|
|
1008
|
+
["right", "--:"]
|
|
1009
|
+
]);
|
|
1010
|
+
function tableRow(rows) {
|
|
1011
|
+
return `|${rows.join("|")}|`;
|
|
1012
|
+
}
|
|
1013
|
+
function table2(data) {
|
|
1014
|
+
if (data.rows.length === 0) {
|
|
1015
|
+
throw new Error("Data can't be empty");
|
|
1016
|
+
}
|
|
1017
|
+
const alignmentRow = getColumnAlignments(data).map(
|
|
1018
|
+
(s) => alignString.get(s) ?? String(alignString.get("center"))
|
|
1019
|
+
);
|
|
1020
|
+
return section(
|
|
1021
|
+
`${lines(
|
|
1022
|
+
tableRow(columnsToStringArray(data)),
|
|
1023
|
+
tableRow(alignmentRow),
|
|
1024
|
+
...rowToStringArray(data).map(tableRow)
|
|
1025
|
+
)}`
|
|
1026
|
+
);
|
|
1058
1027
|
}
|
|
1059
1028
|
|
|
1029
|
+
// packages/utils/src/lib/text-formats/index.ts
|
|
1030
|
+
var md = {
|
|
1031
|
+
bold: bold2,
|
|
1032
|
+
italic: italic2,
|
|
1033
|
+
strikeThrough,
|
|
1034
|
+
code: code2,
|
|
1035
|
+
link: link2,
|
|
1036
|
+
image,
|
|
1037
|
+
headline,
|
|
1038
|
+
h,
|
|
1039
|
+
h1,
|
|
1040
|
+
h2,
|
|
1041
|
+
h3,
|
|
1042
|
+
h4,
|
|
1043
|
+
h5,
|
|
1044
|
+
h6,
|
|
1045
|
+
indentation,
|
|
1046
|
+
lines,
|
|
1047
|
+
li,
|
|
1048
|
+
section,
|
|
1049
|
+
paragraphs,
|
|
1050
|
+
table: table2
|
|
1051
|
+
};
|
|
1052
|
+
var html = {
|
|
1053
|
+
bold,
|
|
1054
|
+
italic,
|
|
1055
|
+
code,
|
|
1056
|
+
link,
|
|
1057
|
+
details,
|
|
1058
|
+
table
|
|
1059
|
+
};
|
|
1060
|
+
|
|
1060
1061
|
// packages/utils/src/lib/reports/utils.ts
|
|
1061
1062
|
var { image: image2, bold: boldMd } = md;
|
|
1062
1063
|
function calcDuration(start, stop) {
|
|
@@ -1156,10 +1157,134 @@ var PLUGIN_CONFIG_PATH = join2(
|
|
|
1156
1157
|
WORKDIR,
|
|
1157
1158
|
"plugin-config.json"
|
|
1158
1159
|
);
|
|
1160
|
+
var INVALID_FUNCTION_NAME = "(empty-report)";
|
|
1159
1161
|
|
|
1160
1162
|
// packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.ts
|
|
1161
1163
|
import { join as join3 } from "node:path";
|
|
1162
1164
|
|
|
1165
|
+
// packages/plugin-coverage/src/lib/runner/lcov/merge-lcov.ts
|
|
1166
|
+
function mergeLcovResults(records) {
|
|
1167
|
+
const allFilenames = records.map((record) => record.file);
|
|
1168
|
+
if (allFilenames.length === new Set(allFilenames).size) {
|
|
1169
|
+
return records;
|
|
1170
|
+
}
|
|
1171
|
+
return records.reduce((accMerged, currRecord, currIndex) => {
|
|
1172
|
+
const filePath = currRecord.file;
|
|
1173
|
+
const lines6 = currRecord.lines.found;
|
|
1174
|
+
const duplicates = records.reduce(
|
|
1175
|
+
(acc, candidateRecord, candidateIndex) => {
|
|
1176
|
+
if (candidateRecord.file === filePath && candidateRecord.lines.found === lines6 && candidateIndex !== currIndex) {
|
|
1177
|
+
return [...acc, [candidateRecord, candidateIndex]];
|
|
1178
|
+
}
|
|
1179
|
+
return acc;
|
|
1180
|
+
},
|
|
1181
|
+
[]
|
|
1182
|
+
);
|
|
1183
|
+
if (duplicates.map((duplicate) => duplicate[1]).some((index) => index < currIndex)) {
|
|
1184
|
+
return accMerged;
|
|
1185
|
+
}
|
|
1186
|
+
if (duplicates.length === 0) {
|
|
1187
|
+
return [...accMerged, currRecord];
|
|
1188
|
+
}
|
|
1189
|
+
return [
|
|
1190
|
+
...accMerged,
|
|
1191
|
+
mergeDuplicateLcovRecords([
|
|
1192
|
+
currRecord,
|
|
1193
|
+
...duplicates.map((duplicate) => duplicate[0])
|
|
1194
|
+
])
|
|
1195
|
+
];
|
|
1196
|
+
}, []);
|
|
1197
|
+
}
|
|
1198
|
+
function mergeDuplicateLcovRecords(records) {
|
|
1199
|
+
const linesDetails = mergeLcovLineDetails(
|
|
1200
|
+
records.map((record) => record.lines.details)
|
|
1201
|
+
);
|
|
1202
|
+
const linesHit = linesDetails.reduce(
|
|
1203
|
+
(acc, line) => acc + (line.hit > 0 ? 1 : 0),
|
|
1204
|
+
0
|
|
1205
|
+
);
|
|
1206
|
+
const branchesDetails = mergeLcovBranchesDetails(
|
|
1207
|
+
records.map((record) => record.branches.details)
|
|
1208
|
+
);
|
|
1209
|
+
const branchesHit = branchesDetails.reduce(
|
|
1210
|
+
(acc, branch) => acc + (branch.taken > 0 ? 1 : 0),
|
|
1211
|
+
0
|
|
1212
|
+
);
|
|
1213
|
+
const functionsDetails = mergeLcovFunctionsDetails(
|
|
1214
|
+
records.map((record) => record.functions.details)
|
|
1215
|
+
);
|
|
1216
|
+
const functionsHit = functionsDetails.reduce(
|
|
1217
|
+
(acc, func) => acc + (func.hit != null && func.hit > 0 ? 1 : 0),
|
|
1218
|
+
0
|
|
1219
|
+
);
|
|
1220
|
+
const mergedRecord = {
|
|
1221
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1222
|
+
file: records[0].file,
|
|
1223
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1224
|
+
title: records[0].title,
|
|
1225
|
+
lines: {
|
|
1226
|
+
found: linesDetails.length,
|
|
1227
|
+
hit: linesHit,
|
|
1228
|
+
details: linesDetails
|
|
1229
|
+
},
|
|
1230
|
+
branches: {
|
|
1231
|
+
found: branchesDetails.length,
|
|
1232
|
+
hit: branchesHit,
|
|
1233
|
+
details: branchesDetails
|
|
1234
|
+
},
|
|
1235
|
+
functions: {
|
|
1236
|
+
found: functionsDetails.length,
|
|
1237
|
+
hit: functionsHit,
|
|
1238
|
+
details: functionsDetails
|
|
1239
|
+
}
|
|
1240
|
+
};
|
|
1241
|
+
return mergedRecord;
|
|
1242
|
+
}
|
|
1243
|
+
function mergeLcovLineDetails(details4) {
|
|
1244
|
+
const flatDetails = details4.flat();
|
|
1245
|
+
const uniqueLines = [
|
|
1246
|
+
...new Set(flatDetails.map((flatDetail) => flatDetail.line))
|
|
1247
|
+
];
|
|
1248
|
+
return uniqueLines.map((line) => {
|
|
1249
|
+
const hitSum = flatDetails.filter((lineDetail) => lineDetail.line === line).reduce((acc, lineDetail) => acc + lineDetail.hit, 0);
|
|
1250
|
+
return { line, hit: hitSum };
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
function mergeLcovBranchesDetails(details4) {
|
|
1254
|
+
const flatDetails = details4.flat();
|
|
1255
|
+
const uniqueBranches = [
|
|
1256
|
+
...new Set(
|
|
1257
|
+
flatDetails.map(
|
|
1258
|
+
({ line, block, branch }) => JSON.stringify({ line, block, branch })
|
|
1259
|
+
)
|
|
1260
|
+
)
|
|
1261
|
+
].map(
|
|
1262
|
+
(functionJSON) => JSON.parse(functionJSON)
|
|
1263
|
+
);
|
|
1264
|
+
return uniqueBranches.map(({ line, block, branch }) => {
|
|
1265
|
+
const takenSum = flatDetails.filter(
|
|
1266
|
+
(branchDetail) => branchDetail.line === line && branchDetail.block === block && branchDetail.branch === branch
|
|
1267
|
+
).reduce((acc, branchDetail) => acc + branchDetail.taken, 0);
|
|
1268
|
+
return { line, block, branch, taken: takenSum };
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
function mergeLcovFunctionsDetails(details4) {
|
|
1272
|
+
const flatDetails = details4.flat();
|
|
1273
|
+
const uniqueFunctions = [
|
|
1274
|
+
...new Set(
|
|
1275
|
+
flatDetails.map(({ line, name }) => JSON.stringify({ line, name }))
|
|
1276
|
+
)
|
|
1277
|
+
].map(
|
|
1278
|
+
(functionJSON) => JSON.parse(functionJSON)
|
|
1279
|
+
);
|
|
1280
|
+
return uniqueFunctions.map(({ line, name }) => {
|
|
1281
|
+
const hitSum = flatDetails.filter(
|
|
1282
|
+
(functionDetail) => functionDetail.line === line && functionDetail.name === name
|
|
1283
|
+
).reduce((acc, functionDetail) => acc + (functionDetail.hit ?? 0), 0);
|
|
1284
|
+
return { line, name, hit: hitSum };
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1163
1288
|
// packages/plugin-coverage/src/lib/runner/lcov/parse-lcov.ts
|
|
1164
1289
|
import parseLcovExport from "parse-lcov";
|
|
1165
1290
|
var godKnows = parseLcovExport;
|
|
@@ -1184,21 +1309,41 @@ function mergeConsecutiveNumbers(numberArr) {
|
|
|
1184
1309
|
|
|
1185
1310
|
// packages/plugin-coverage/src/lib/runner/lcov/transform.ts
|
|
1186
1311
|
function lcovReportToFunctionStat(record) {
|
|
1312
|
+
const validRecord = removeEmptyReport(record);
|
|
1187
1313
|
return {
|
|
1188
|
-
totalFound:
|
|
1189
|
-
totalHit:
|
|
1190
|
-
issues:
|
|
1314
|
+
totalFound: validRecord.functions.found,
|
|
1315
|
+
totalHit: validRecord.functions.hit,
|
|
1316
|
+
issues: validRecord.functions.hit < validRecord.functions.found ? validRecord.functions.details.filter((detail) => !detail.hit).map(
|
|
1191
1317
|
(detail) => ({
|
|
1192
1318
|
message: `Function ${detail.name} is not called in any test case.`,
|
|
1193
1319
|
severity: "error",
|
|
1194
1320
|
source: {
|
|
1195
|
-
file:
|
|
1321
|
+
file: validRecord.file,
|
|
1196
1322
|
position: { startLine: detail.line }
|
|
1197
1323
|
}
|
|
1198
1324
|
})
|
|
1199
1325
|
) : []
|
|
1200
1326
|
};
|
|
1201
1327
|
}
|
|
1328
|
+
function removeEmptyReport(record) {
|
|
1329
|
+
const validFunctions = record.functions.details.filter(
|
|
1330
|
+
(detail) => detail.name !== INVALID_FUNCTION_NAME
|
|
1331
|
+
);
|
|
1332
|
+
if (validFunctions.length === record.functions.found) {
|
|
1333
|
+
return record;
|
|
1334
|
+
}
|
|
1335
|
+
return {
|
|
1336
|
+
...record,
|
|
1337
|
+
functions: {
|
|
1338
|
+
details: validFunctions,
|
|
1339
|
+
found: validFunctions.length,
|
|
1340
|
+
hit: validFunctions.reduce(
|
|
1341
|
+
(acc, fn) => acc + (fn.hit != null && fn.hit > 0 ? 1 : 0),
|
|
1342
|
+
0
|
|
1343
|
+
)
|
|
1344
|
+
}
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1202
1347
|
function lcovReportToLineStat(record) {
|
|
1203
1348
|
const missingCoverage = record.lines.hit < record.lines.found;
|
|
1204
1349
|
const lines6 = missingCoverage ? record.lines.details.filter((detail) => !detail.hit).map((detail) => detail.line) : [];
|
|
@@ -1263,8 +1408,9 @@ function lcovCoverageToAuditOutput(stat2, coverageType) {
|
|
|
1263
1408
|
// packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.ts
|
|
1264
1409
|
async function lcovResultsToAuditOutputs(results, coverageTypes) {
|
|
1265
1410
|
const lcovResults = await parseLcovFiles(results);
|
|
1411
|
+
const mergedResults = mergeLcovResults(lcovResults);
|
|
1266
1412
|
const totalCoverageStats = getTotalCoverageFromLcovRecords(
|
|
1267
|
-
|
|
1413
|
+
mergedResults,
|
|
1268
1414
|
coverageTypes
|
|
1269
1415
|
);
|
|
1270
1416
|
return coverageTypes.map((coverageType) => {
|
|
@@ -1280,6 +1426,11 @@ async function parseLcovFiles(results) {
|
|
|
1280
1426
|
results.map(async (result) => {
|
|
1281
1427
|
const resultsPath = typeof result === "string" ? result : result.resultsPath;
|
|
1282
1428
|
const lcovFileContent = await readTextFile(resultsPath);
|
|
1429
|
+
if (lcovFileContent.trim() === "") {
|
|
1430
|
+
ui().logger.warning(
|
|
1431
|
+
`Coverage plugin: Empty lcov report file detected at ${resultsPath}.`
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1283
1434
|
const parsedRecords = parseLcov(toUnixNewlines(lcovFileContent));
|
|
1284
1435
|
return parsedRecords.map((record) => ({
|
|
1285
1436
|
...record,
|