@code-pushup/utils 0.35.0 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +1087 -597
- package/package.json +6 -4
- package/src/index.d.ts +5 -1
- package/src/lib/git/git.commits-and-tags.d.ts +57 -0
- package/src/lib/{git.d.ts → git/git.d.ts} +8 -3
- package/src/lib/reports/constants.d.ts +26 -6
- package/src/lib/reports/formatting.d.ts +6 -0
- package/src/lib/reports/generate-md-report-categoy-section.d.ts +6 -0
- package/src/lib/reports/generate-md-report.d.ts +8 -0
- package/src/lib/reports/utils.d.ts +5 -3
- package/src/lib/semver.d.ts +3 -0
- package/src/lib/table.d.ts +6 -0
- package/src/lib/text-formats/constants.d.ts +3 -0
- package/src/lib/{reports/md → text-formats/html}/details.d.ts +2 -0
- package/src/lib/text-formats/html/font-style.d.ts +3 -0
- package/src/lib/text-formats/html/link.d.ts +1 -0
- package/src/lib/text-formats/html/table.d.ts +2 -0
- package/src/lib/text-formats/index.d.ts +44 -0
- package/src/lib/text-formats/md/font-style.d.ts +4 -0
- package/src/lib/{reports → text-formats}/md/headline.d.ts +1 -1
- package/src/lib/text-formats/md/link.d.ts +1 -0
- package/src/lib/{reports → text-formats}/md/list.d.ts +2 -0
- package/src/lib/text-formats/md/section.d.ts +2 -0
- package/src/lib/text-formats/md/table.d.ts +9 -0
- package/src/lib/text-formats/table.d.ts +6 -0
- package/src/lib/text-formats/types.d.ts +1 -0
- package/src/lib/types.d.ts +3 -0
- package/src/lib/reports/md/font-style.d.ts +0 -16
- package/src/lib/reports/md/index.d.ts +0 -8
- package/src/lib/reports/md/link.d.ts +0 -6
- package/src/lib/reports/md/table.d.ts +0 -10
- /package/src/lib/{reports → text-formats}/md/image.d.ts +0 -0
- /package/src/lib/{reports → text-formats}/md/paragraphs.d.ts +0 -0
package/index.js
CHANGED
|
@@ -1,5 +1,372 @@
|
|
|
1
|
-
// packages/
|
|
2
|
-
|
|
1
|
+
// packages/utils/src/lib/text-formats/constants.ts
|
|
2
|
+
var NEW_LINE = "\n";
|
|
3
|
+
var TAB = " ";
|
|
4
|
+
var SPACE = " ";
|
|
5
|
+
|
|
6
|
+
// packages/utils/src/lib/text-formats/html/details.ts
|
|
7
|
+
function details(title, content, cfg = { open: false }) {
|
|
8
|
+
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.
|
|
9
|
+
NEW_LINE}${content}${NEW_LINE}${// @TODO in the future we could consider adding it only if the content ends with a code block
|
|
10
|
+
// ⚠️ The blank line ensure Markdown in content is rendered correctly.
|
|
11
|
+
NEW_LINE}</details>${// ⚠️ The blank line is needed to ensure Markdown after details is rendered correctly.
|
|
12
|
+
NEW_LINE}`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// packages/utils/src/lib/text-formats/html/font-style.ts
|
|
16
|
+
var boldElement = "b";
|
|
17
|
+
function bold(text) {
|
|
18
|
+
return `<${boldElement}>${text}</${boldElement}>`;
|
|
19
|
+
}
|
|
20
|
+
var italicElement = "i";
|
|
21
|
+
function italic(text) {
|
|
22
|
+
return `<${italicElement}>${text}</${italicElement}>`;
|
|
23
|
+
}
|
|
24
|
+
var codeElement = "code";
|
|
25
|
+
function code(text) {
|
|
26
|
+
return `<${codeElement}>${text}</${codeElement}>`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// packages/utils/src/lib/text-formats/html/link.ts
|
|
30
|
+
function link(href, text) {
|
|
31
|
+
return `<a href="${href}">${text || href}"</a>`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// packages/utils/src/lib/transform.ts
|
|
35
|
+
import { platform } from "node:os";
|
|
36
|
+
function toArray(val) {
|
|
37
|
+
return Array.isArray(val) ? val : [val];
|
|
38
|
+
}
|
|
39
|
+
function objectToKeys(obj) {
|
|
40
|
+
return Object.keys(obj);
|
|
41
|
+
}
|
|
42
|
+
function objectToEntries(obj) {
|
|
43
|
+
return Object.entries(obj);
|
|
44
|
+
}
|
|
45
|
+
function objectFromEntries(entries) {
|
|
46
|
+
return Object.fromEntries(entries);
|
|
47
|
+
}
|
|
48
|
+
function countOccurrences(values) {
|
|
49
|
+
return values.reduce(
|
|
50
|
+
(acc, value) => ({ ...acc, [value]: (acc[value] ?? 0) + 1 }),
|
|
51
|
+
{}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
function distinct(array) {
|
|
55
|
+
return [...new Set(array)];
|
|
56
|
+
}
|
|
57
|
+
function deepClone(obj) {
|
|
58
|
+
return obj == null || typeof obj !== "object" ? obj : structuredClone(obj);
|
|
59
|
+
}
|
|
60
|
+
function factorOf(items, filterFn) {
|
|
61
|
+
const itemCount = items.length;
|
|
62
|
+
if (!itemCount) {
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
const filterCount = items.filter(filterFn).length;
|
|
66
|
+
return filterCount === 0 ? 1 : (itemCount - filterCount) / itemCount;
|
|
67
|
+
}
|
|
68
|
+
function objectToCliArgs(params) {
|
|
69
|
+
if (!params) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
return Object.entries(params).flatMap(([key, value]) => {
|
|
73
|
+
if (key === "_") {
|
|
74
|
+
return Array.isArray(value) ? value : [`${value}`];
|
|
75
|
+
}
|
|
76
|
+
const prefix = key.length === 1 ? "-" : "--";
|
|
77
|
+
if (Array.isArray(value)) {
|
|
78
|
+
return value.map((v) => `${prefix}${key}="${v}"`);
|
|
79
|
+
}
|
|
80
|
+
if (Array.isArray(value)) {
|
|
81
|
+
return value.map((v) => `${prefix}${key}="${v}"`);
|
|
82
|
+
}
|
|
83
|
+
if (typeof value === "string") {
|
|
84
|
+
return [`${prefix}${key}="${value}"`];
|
|
85
|
+
}
|
|
86
|
+
if (typeof value === "number") {
|
|
87
|
+
return [`${prefix}${key}=${value}`];
|
|
88
|
+
}
|
|
89
|
+
if (typeof value === "boolean") {
|
|
90
|
+
return [`${prefix}${value ? "" : "no-"}${key}`];
|
|
91
|
+
}
|
|
92
|
+
throw new Error(`Unsupported type ${typeof value} for key ${key}`);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function toUnixPath(path) {
|
|
96
|
+
return path.replace(/\\/g, "/");
|
|
97
|
+
}
|
|
98
|
+
function toUnixNewlines(text) {
|
|
99
|
+
return platform() === "win32" ? text.replace(/\r\n/g, "\n") : text;
|
|
100
|
+
}
|
|
101
|
+
function fromJsonLines(jsonLines) {
|
|
102
|
+
const unifiedNewLines = toUnixNewlines(jsonLines).trim();
|
|
103
|
+
return JSON.parse(`[${unifiedNewLines.split("\n").join(",")}]`);
|
|
104
|
+
}
|
|
105
|
+
function toJsonLines(json) {
|
|
106
|
+
return json.map((item) => JSON.stringify(item)).join("\n");
|
|
107
|
+
}
|
|
108
|
+
function capitalize(text) {
|
|
109
|
+
return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
|
|
110
|
+
1
|
|
111
|
+
)}`;
|
|
112
|
+
}
|
|
113
|
+
function apostrophize(text, upperCase) {
|
|
114
|
+
const lastCharMatch = text.match(/(\w)\W*$/);
|
|
115
|
+
const lastChar = lastCharMatch?.[1] ?? "";
|
|
116
|
+
return `${text}'${lastChar.toLocaleLowerCase() === "s" ? "" : upperCase ? "S" : "s"}`;
|
|
117
|
+
}
|
|
118
|
+
function toNumberPrecision(value, decimalPlaces) {
|
|
119
|
+
return Number(
|
|
120
|
+
`${Math.round(
|
|
121
|
+
Number.parseFloat(`${value}e${decimalPlaces}`)
|
|
122
|
+
)}e-${decimalPlaces}`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
function toOrdinal(value) {
|
|
126
|
+
if (value % 10 === 1 && value % 100 !== 11) {
|
|
127
|
+
return `${value}st`;
|
|
128
|
+
}
|
|
129
|
+
if (value % 10 === 2 && value % 100 !== 12) {
|
|
130
|
+
return `${value}nd`;
|
|
131
|
+
}
|
|
132
|
+
if (value % 10 === 3 && value % 100 !== 13) {
|
|
133
|
+
return `${value}rd`;
|
|
134
|
+
}
|
|
135
|
+
return `${value}th`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// packages/utils/src/lib/table.ts
|
|
139
|
+
function rowToStringArray({ rows, columns = [] }) {
|
|
140
|
+
if (Array.isArray(rows.at(0)) && typeof columns.at(0) === "object") {
|
|
141
|
+
throw new TypeError(
|
|
142
|
+
"Column can`t be object when rows are primitive values"
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return rows.map((row) => {
|
|
146
|
+
if (Array.isArray(row)) {
|
|
147
|
+
return row.map(String);
|
|
148
|
+
}
|
|
149
|
+
const objectRow = row;
|
|
150
|
+
if (columns.length === 0 || typeof columns.at(0) === "string") {
|
|
151
|
+
return Object.values(objectRow).map(String);
|
|
152
|
+
}
|
|
153
|
+
return columns.map(
|
|
154
|
+
({ key }) => String(objectRow[key])
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function columnsToStringArray({ rows, columns = [] }) {
|
|
159
|
+
const firstRow = rows.at(0);
|
|
160
|
+
const primitiveRows = Array.isArray(firstRow);
|
|
161
|
+
if (typeof columns.at(0) === "string" && !primitiveRows) {
|
|
162
|
+
throw new Error("invalid union type. Caught by model parsing.");
|
|
163
|
+
}
|
|
164
|
+
if (columns.length === 0) {
|
|
165
|
+
if (Array.isArray(firstRow)) {
|
|
166
|
+
return firstRow.map((_, idx) => String(idx));
|
|
167
|
+
}
|
|
168
|
+
return Object.keys(firstRow);
|
|
169
|
+
}
|
|
170
|
+
if (typeof columns.at(0) === "string") {
|
|
171
|
+
return columns.map(String);
|
|
172
|
+
}
|
|
173
|
+
const cols = columns;
|
|
174
|
+
return cols.map(({ label, key }) => label ?? capitalize(key));
|
|
175
|
+
}
|
|
176
|
+
function getColumnAlignmentForKeyAndIndex(targetKey, targetIdx, columns = []) {
|
|
177
|
+
const column = columns.at(targetIdx) ?? columns.find((col) => col.key === targetKey);
|
|
178
|
+
if (typeof column === "string") {
|
|
179
|
+
return column;
|
|
180
|
+
} else if (typeof column === "object") {
|
|
181
|
+
return column.align ?? "center";
|
|
182
|
+
} else {
|
|
183
|
+
return "center";
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function getColumnAlignmentForIndex(targetIdx, columns = []) {
|
|
187
|
+
const column = columns.at(targetIdx);
|
|
188
|
+
if (column == null) {
|
|
189
|
+
return "center";
|
|
190
|
+
} else if (typeof column === "string") {
|
|
191
|
+
return column;
|
|
192
|
+
} else if (typeof column === "object") {
|
|
193
|
+
return column.align ?? "center";
|
|
194
|
+
} else {
|
|
195
|
+
return "center";
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function getColumnAlignments({
|
|
199
|
+
rows,
|
|
200
|
+
columns = []
|
|
201
|
+
}) {
|
|
202
|
+
if (rows.at(0) == null) {
|
|
203
|
+
throw new Error("first row can`t be undefined.");
|
|
204
|
+
}
|
|
205
|
+
if (Array.isArray(rows.at(0))) {
|
|
206
|
+
const firstPrimitiveRow = rows.at(0);
|
|
207
|
+
return Array.from({ length: firstPrimitiveRow.length }).map(
|
|
208
|
+
(_, idx) => getColumnAlignmentForIndex(idx, columns)
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
const firstObject = rows.at(0);
|
|
212
|
+
return Object.keys(firstObject).map(
|
|
213
|
+
(key, idx) => getColumnAlignmentForKeyAndIndex(key, idx, columns)
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// packages/utils/src/lib/text-formats/html/table.ts
|
|
218
|
+
function wrap(elem, content) {
|
|
219
|
+
return `<${elem}>${content}</${elem}>${NEW_LINE}`;
|
|
220
|
+
}
|
|
221
|
+
function wrapRow(content) {
|
|
222
|
+
const elem = "tr";
|
|
223
|
+
return `<${elem}>${NEW_LINE}${content}</${elem}>${NEW_LINE}`;
|
|
224
|
+
}
|
|
225
|
+
function table(tableData) {
|
|
226
|
+
if (tableData.rows.length === 0) {
|
|
227
|
+
throw new Error("Data can't be empty");
|
|
228
|
+
}
|
|
229
|
+
const tableHeaderCols = columnsToStringArray(tableData).map((s) => wrap("th", s)).join("");
|
|
230
|
+
const tableHeaderRow = wrapRow(tableHeaderCols);
|
|
231
|
+
const tableBody = rowToStringArray(tableData).map((arr) => {
|
|
232
|
+
const columns = arr.map((s) => wrap("td", s)).join("");
|
|
233
|
+
return wrapRow(columns);
|
|
234
|
+
}).join("");
|
|
235
|
+
return wrap("table", `${NEW_LINE}${tableHeaderRow}${tableBody}`);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// packages/utils/src/lib/text-formats/md/font-style.ts
|
|
239
|
+
var boldWrap = "**";
|
|
240
|
+
function bold2(text) {
|
|
241
|
+
return `${boldWrap}${text}${boldWrap}`;
|
|
242
|
+
}
|
|
243
|
+
var italicWrap = "_";
|
|
244
|
+
function italic2(text) {
|
|
245
|
+
return `${italicWrap}${text}${italicWrap}`;
|
|
246
|
+
}
|
|
247
|
+
var strikeThroughWrap = "~";
|
|
248
|
+
function strikeThrough(text) {
|
|
249
|
+
return `${strikeThroughWrap}${text}${strikeThroughWrap}`;
|
|
250
|
+
}
|
|
251
|
+
var codeWrap = "`";
|
|
252
|
+
function code2(text) {
|
|
253
|
+
return `${codeWrap}${text}${codeWrap}`;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// packages/utils/src/lib/text-formats/md/headline.ts
|
|
257
|
+
function headline(text, hierarchy = 1) {
|
|
258
|
+
return `${"#".repeat(hierarchy)} ${text}${NEW_LINE}`;
|
|
259
|
+
}
|
|
260
|
+
function h(text, hierarchy = 1) {
|
|
261
|
+
return headline(text, hierarchy);
|
|
262
|
+
}
|
|
263
|
+
function h1(text) {
|
|
264
|
+
return headline(text, 1);
|
|
265
|
+
}
|
|
266
|
+
function h2(text) {
|
|
267
|
+
return headline(text, 2);
|
|
268
|
+
}
|
|
269
|
+
function h3(text) {
|
|
270
|
+
return headline(text, 3);
|
|
271
|
+
}
|
|
272
|
+
function h4(text) {
|
|
273
|
+
return headline(text, 4);
|
|
274
|
+
}
|
|
275
|
+
function h5(text) {
|
|
276
|
+
return headline(text, 5);
|
|
277
|
+
}
|
|
278
|
+
function h6(text) {
|
|
279
|
+
return headline(text, 6);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// packages/utils/src/lib/text-formats/md/image.ts
|
|
283
|
+
function image(src, alt) {
|
|
284
|
+
return ``;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// packages/utils/src/lib/text-formats/md/link.ts
|
|
288
|
+
function link2(href, text) {
|
|
289
|
+
return `[${text || href}](${href})`;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// packages/utils/src/lib/text-formats/md/list.ts
|
|
293
|
+
function li(text, order = "unordered") {
|
|
294
|
+
const style = order === "unordered" ? "-" : "- [ ]";
|
|
295
|
+
return `${style} ${text}`;
|
|
296
|
+
}
|
|
297
|
+
function indentation(text, level = 1) {
|
|
298
|
+
return `${TAB.repeat(level)}${text}`;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// packages/utils/src/lib/text-formats/md/paragraphs.ts
|
|
302
|
+
function paragraphs(...sections) {
|
|
303
|
+
return sections.filter(Boolean).join(`${NEW_LINE}${NEW_LINE}`);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// packages/utils/src/lib/text-formats/md/section.ts
|
|
307
|
+
function section(...contents) {
|
|
308
|
+
return `${lines(...contents)}${NEW_LINE}`;
|
|
309
|
+
}
|
|
310
|
+
function lines(...contents) {
|
|
311
|
+
return `${contents.filter(Boolean).join(NEW_LINE)}`;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// packages/utils/src/lib/text-formats/md/table.ts
|
|
315
|
+
var alignString = /* @__PURE__ */ new Map([
|
|
316
|
+
["left", ":--"],
|
|
317
|
+
["center", ":--:"],
|
|
318
|
+
["right", "--:"]
|
|
319
|
+
]);
|
|
320
|
+
function tableRow(rows) {
|
|
321
|
+
return `|${rows.join("|")}|`;
|
|
322
|
+
}
|
|
323
|
+
function table2(data) {
|
|
324
|
+
if (data.rows.length === 0) {
|
|
325
|
+
throw new Error("Data can't be empty");
|
|
326
|
+
}
|
|
327
|
+
const alignmentRow = getColumnAlignments(data).map(
|
|
328
|
+
(s) => alignString.get(s) ?? String(alignString.get("center"))
|
|
329
|
+
);
|
|
330
|
+
return section(
|
|
331
|
+
`${lines(
|
|
332
|
+
tableRow(columnsToStringArray(data)),
|
|
333
|
+
tableRow(alignmentRow),
|
|
334
|
+
...rowToStringArray(data).map(tableRow)
|
|
335
|
+
)}`
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// packages/utils/src/lib/text-formats/index.ts
|
|
340
|
+
var md = {
|
|
341
|
+
bold: bold2,
|
|
342
|
+
italic: italic2,
|
|
343
|
+
strikeThrough,
|
|
344
|
+
code: code2,
|
|
345
|
+
link: link2,
|
|
346
|
+
image,
|
|
347
|
+
headline,
|
|
348
|
+
h,
|
|
349
|
+
h1,
|
|
350
|
+
h2,
|
|
351
|
+
h3,
|
|
352
|
+
h4,
|
|
353
|
+
h5,
|
|
354
|
+
h6,
|
|
355
|
+
indentation,
|
|
356
|
+
lines,
|
|
357
|
+
li,
|
|
358
|
+
section,
|
|
359
|
+
paragraphs,
|
|
360
|
+
table: table2
|
|
361
|
+
};
|
|
362
|
+
var html = {
|
|
363
|
+
bold,
|
|
364
|
+
italic,
|
|
365
|
+
code,
|
|
366
|
+
link,
|
|
367
|
+
details,
|
|
368
|
+
table
|
|
369
|
+
};
|
|
3
370
|
|
|
4
371
|
// packages/models/src/lib/implementation/schemas.ts
|
|
5
372
|
import { MATERIAL_ICONS } from "vscode-material-icons";
|
|
@@ -66,6 +433,7 @@ function missingRefsForCategoriesErrorMsg(categories, plugins) {
|
|
|
66
433
|
}
|
|
67
434
|
|
|
68
435
|
// packages/models/src/lib/implementation/schemas.ts
|
|
436
|
+
var primitiveValueSchema = z.union([z.string(), z.number()]);
|
|
69
437
|
function executionMetaSchema(options = {
|
|
70
438
|
descriptionDate: "Execution start date and time",
|
|
71
439
|
descriptionDuration: "Execution duration in ms"
|
|
@@ -157,6 +525,7 @@ function hasNonZeroWeightedRef(refs) {
|
|
|
157
525
|
}
|
|
158
526
|
|
|
159
527
|
// packages/models/src/lib/audit.ts
|
|
528
|
+
import { z as z2 } from "zod";
|
|
160
529
|
var auditSchema = z2.object({
|
|
161
530
|
slug: slugSchema.describe("ID (unique within plugin)")
|
|
162
531
|
}).merge(
|
|
@@ -186,7 +555,7 @@ function getDuplicateSlugsInAudits(audits) {
|
|
|
186
555
|
}
|
|
187
556
|
|
|
188
557
|
// packages/models/src/lib/audit-output.ts
|
|
189
|
-
import { z as
|
|
558
|
+
import { z as z5 } from "zod";
|
|
190
559
|
|
|
191
560
|
// packages/models/src/lib/issue.ts
|
|
192
561
|
import { z as z3 } from "zod";
|
|
@@ -217,16 +586,61 @@ var issueSchema = z3.object(
|
|
|
217
586
|
{ description: "Issue information" }
|
|
218
587
|
);
|
|
219
588
|
|
|
589
|
+
// packages/models/src/lib/table.ts
|
|
590
|
+
import { z as z4 } from "zod";
|
|
591
|
+
var tableAlignmentSchema = z4.enum(["left", "center", "right"], {
|
|
592
|
+
description: "Cell alignment"
|
|
593
|
+
});
|
|
594
|
+
var tableColumnObjectSchema = z4.object({
|
|
595
|
+
key: z4.string(),
|
|
596
|
+
label: z4.string().optional(),
|
|
597
|
+
align: tableAlignmentSchema.optional()
|
|
598
|
+
});
|
|
599
|
+
var tableRowObjectSchema = z4.record(primitiveValueSchema, {
|
|
600
|
+
description: "Object row"
|
|
601
|
+
});
|
|
602
|
+
var tableRowPrimitiveSchema = z4.array(primitiveValueSchema, {
|
|
603
|
+
description: "Primitive row"
|
|
604
|
+
});
|
|
605
|
+
var tableSharedSchema = z4.object({
|
|
606
|
+
title: z4.string().optional().describe("Display title for table")
|
|
607
|
+
});
|
|
608
|
+
var tablePrimitiveSchema = tableSharedSchema.merge(
|
|
609
|
+
z4.object(
|
|
610
|
+
{
|
|
611
|
+
columns: z4.array(tableAlignmentSchema).optional(),
|
|
612
|
+
rows: z4.array(tableRowPrimitiveSchema)
|
|
613
|
+
},
|
|
614
|
+
{ description: "Table with primitive rows and optional alignment columns" }
|
|
615
|
+
)
|
|
616
|
+
);
|
|
617
|
+
var tableObjectSchema = tableSharedSchema.merge(
|
|
618
|
+
z4.object(
|
|
619
|
+
{
|
|
620
|
+
columns: z4.union([
|
|
621
|
+
z4.array(tableAlignmentSchema),
|
|
622
|
+
z4.array(tableColumnObjectSchema)
|
|
623
|
+
]).optional(),
|
|
624
|
+
rows: z4.array(tableRowObjectSchema)
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
description: "Table with object rows and optional alignment or object columns"
|
|
628
|
+
}
|
|
629
|
+
)
|
|
630
|
+
);
|
|
631
|
+
var tableSchema = (description = "Table information") => z4.union([tablePrimitiveSchema, tableObjectSchema], { description });
|
|
632
|
+
|
|
220
633
|
// packages/models/src/lib/audit-output.ts
|
|
221
634
|
var auditValueSchema = nonnegativeIntSchema.describe("Raw numeric value");
|
|
222
|
-
var auditDisplayValueSchema =
|
|
223
|
-
var auditDetailsSchema =
|
|
635
|
+
var auditDisplayValueSchema = z5.string({ description: "Formatted value (e.g. '0.9 s', '2.1 MB')" }).optional();
|
|
636
|
+
var auditDetailsSchema = z5.object(
|
|
224
637
|
{
|
|
225
|
-
issues:
|
|
638
|
+
issues: z5.array(issueSchema, { description: "List of findings" }).optional(),
|
|
639
|
+
table: tableSchema("Table of related findings").optional()
|
|
226
640
|
},
|
|
227
641
|
{ description: "Detailed information" }
|
|
228
642
|
);
|
|
229
|
-
var auditOutputSchema =
|
|
643
|
+
var auditOutputSchema = z5.object(
|
|
230
644
|
{
|
|
231
645
|
slug: slugSchema.describe("Reference to audit"),
|
|
232
646
|
displayValue: auditDisplayValueSchema,
|
|
@@ -236,7 +650,7 @@ var auditOutputSchema = z4.object(
|
|
|
236
650
|
},
|
|
237
651
|
{ description: "Audit information" }
|
|
238
652
|
);
|
|
239
|
-
var auditOutputsSchema =
|
|
653
|
+
var auditOutputsSchema = z5.array(auditOutputSchema, {
|
|
240
654
|
description: "List of JSON formatted audit output emitted by the runner process of a plugin"
|
|
241
655
|
}).refine(
|
|
242
656
|
(audits) => !getDuplicateSlugsInAudits2(audits),
|
|
@@ -253,13 +667,13 @@ function getDuplicateSlugsInAudits2(audits) {
|
|
|
253
667
|
}
|
|
254
668
|
|
|
255
669
|
// packages/models/src/lib/category-config.ts
|
|
256
|
-
import { z as
|
|
670
|
+
import { z as z6 } from "zod";
|
|
257
671
|
var categoryRefSchema = weightedRefSchema(
|
|
258
672
|
"Weighted references to audits and/or groups for the category",
|
|
259
673
|
"Slug of an audit or group (depending on `type`)"
|
|
260
674
|
).merge(
|
|
261
|
-
|
|
262
|
-
type:
|
|
675
|
+
z6.object({
|
|
676
|
+
type: z6.enum(["audit", "group"], {
|
|
263
677
|
description: "Discriminant for reference kind, affects where `slug` is looked up"
|
|
264
678
|
}),
|
|
265
679
|
plugin: slugSchema.describe(
|
|
@@ -280,8 +694,8 @@ var categoryConfigSchema = scorableSchema(
|
|
|
280
694
|
description: "Meta info for category"
|
|
281
695
|
})
|
|
282
696
|
).merge(
|
|
283
|
-
|
|
284
|
-
isBinary:
|
|
697
|
+
z6.object({
|
|
698
|
+
isBinary: z6.boolean({
|
|
285
699
|
description: 'Is this a binary category (i.e. only a perfect score considered a "pass")?'
|
|
286
700
|
}).optional()
|
|
287
701
|
})
|
|
@@ -297,7 +711,7 @@ function getDuplicateRefsInCategoryMetrics(metrics) {
|
|
|
297
711
|
metrics.map(({ slug, type, plugin }) => `${type} :: ${plugin} / ${slug}`)
|
|
298
712
|
);
|
|
299
713
|
}
|
|
300
|
-
var categoriesSchema =
|
|
714
|
+
var categoriesSchema = z6.array(categoryConfigSchema, {
|
|
301
715
|
description: "Categorization of individual audits"
|
|
302
716
|
}).refine(
|
|
303
717
|
(categoryCfg) => !getDuplicateSlugCategories(categoryCfg),
|
|
@@ -316,18 +730,18 @@ function getDuplicateSlugCategories(categories) {
|
|
|
316
730
|
}
|
|
317
731
|
|
|
318
732
|
// packages/models/src/lib/commit.ts
|
|
319
|
-
import { z as
|
|
320
|
-
var commitSchema =
|
|
733
|
+
import { z as z7 } from "zod";
|
|
734
|
+
var commitSchema = z7.object(
|
|
321
735
|
{
|
|
322
|
-
hash:
|
|
736
|
+
hash: z7.string({ description: "Commit SHA (full)" }).regex(
|
|
323
737
|
/^[\da-f]{40}$/,
|
|
324
738
|
"Commit SHA should be a 40-character hexadecimal string"
|
|
325
739
|
),
|
|
326
|
-
message:
|
|
327
|
-
date:
|
|
740
|
+
message: z7.string({ description: "Commit message" }),
|
|
741
|
+
date: z7.coerce.date({
|
|
328
742
|
description: "Date and time when commit was authored"
|
|
329
743
|
}),
|
|
330
|
-
author:
|
|
744
|
+
author: z7.string({
|
|
331
745
|
description: "Commit author name"
|
|
332
746
|
}).trim()
|
|
333
747
|
},
|
|
@@ -335,22 +749,22 @@ var commitSchema = z6.object(
|
|
|
335
749
|
);
|
|
336
750
|
|
|
337
751
|
// packages/models/src/lib/core-config.ts
|
|
338
|
-
import { z as
|
|
752
|
+
import { z as z13 } from "zod";
|
|
339
753
|
|
|
340
754
|
// packages/models/src/lib/persist-config.ts
|
|
341
|
-
import { z as
|
|
342
|
-
var formatSchema =
|
|
343
|
-
var persistConfigSchema =
|
|
755
|
+
import { z as z8 } from "zod";
|
|
756
|
+
var formatSchema = z8.enum(["json", "md"]);
|
|
757
|
+
var persistConfigSchema = z8.object({
|
|
344
758
|
outputDir: filePathSchema.describe("Artifacts folder").optional(),
|
|
345
759
|
filename: fileNameSchema.describe("Artifacts file name (without extension)").optional(),
|
|
346
|
-
format:
|
|
760
|
+
format: z8.array(formatSchema).optional()
|
|
347
761
|
});
|
|
348
762
|
|
|
349
763
|
// packages/models/src/lib/plugin-config.ts
|
|
350
|
-
import { z as
|
|
764
|
+
import { z as z11 } from "zod";
|
|
351
765
|
|
|
352
766
|
// packages/models/src/lib/group.ts
|
|
353
|
-
import { z as
|
|
767
|
+
import { z as z9 } from "zod";
|
|
354
768
|
var groupRefSchema = weightedRefSchema(
|
|
355
769
|
"Weighted reference to a group",
|
|
356
770
|
"Reference slug to a group within this plugin (e.g. 'max-lines')"
|
|
@@ -367,7 +781,7 @@ var groupSchema = scorableSchema(
|
|
|
367
781
|
getDuplicateRefsInGroups,
|
|
368
782
|
duplicateRefsInGroupsErrorMsg
|
|
369
783
|
).merge(groupMetaSchema);
|
|
370
|
-
var groupsSchema =
|
|
784
|
+
var groupsSchema = z9.array(groupSchema, {
|
|
371
785
|
description: "List of groups"
|
|
372
786
|
}).optional().refine(
|
|
373
787
|
(groups) => !getDuplicateSlugsInGroups(groups),
|
|
@@ -395,14 +809,14 @@ function getDuplicateSlugsInGroups(groups) {
|
|
|
395
809
|
}
|
|
396
810
|
|
|
397
811
|
// packages/models/src/lib/runner-config.ts
|
|
398
|
-
import { z as
|
|
399
|
-
var outputTransformSchema =
|
|
400
|
-
var runnerConfigSchema =
|
|
812
|
+
import { z as z10 } from "zod";
|
|
813
|
+
var outputTransformSchema = z10.function().args(z10.unknown()).returns(z10.union([auditOutputsSchema, z10.promise(auditOutputsSchema)]));
|
|
814
|
+
var runnerConfigSchema = z10.object(
|
|
401
815
|
{
|
|
402
|
-
command:
|
|
816
|
+
command: z10.string({
|
|
403
817
|
description: "Shell command to execute"
|
|
404
818
|
}),
|
|
405
|
-
args:
|
|
819
|
+
args: z10.array(z10.string({ description: "Command arguments" })).optional(),
|
|
406
820
|
outputFile: filePathSchema.describe("Output path"),
|
|
407
821
|
outputTransform: outputTransformSchema.optional()
|
|
408
822
|
},
|
|
@@ -410,8 +824,8 @@ var runnerConfigSchema = z9.object(
|
|
|
410
824
|
description: "How to execute runner"
|
|
411
825
|
}
|
|
412
826
|
);
|
|
413
|
-
var onProgressSchema =
|
|
414
|
-
var runnerFunctionSchema =
|
|
827
|
+
var onProgressSchema = z10.function().args(z10.unknown()).returns(z10.void());
|
|
828
|
+
var runnerFunctionSchema = z10.function().args(onProgressSchema.optional()).returns(z10.union([auditOutputsSchema, z10.promise(auditOutputsSchema)]));
|
|
415
829
|
|
|
416
830
|
// packages/models/src/lib/plugin-config.ts
|
|
417
831
|
var pluginMetaSchema = packageVersionSchema().merge(
|
|
@@ -422,13 +836,13 @@ var pluginMetaSchema = packageVersionSchema().merge(
|
|
|
422
836
|
description: "Plugin metadata"
|
|
423
837
|
})
|
|
424
838
|
).merge(
|
|
425
|
-
|
|
839
|
+
z11.object({
|
|
426
840
|
slug: slugSchema.describe("Unique plugin slug within core config"),
|
|
427
841
|
icon: materialIconSchema
|
|
428
842
|
})
|
|
429
843
|
);
|
|
430
|
-
var pluginDataSchema =
|
|
431
|
-
runner:
|
|
844
|
+
var pluginDataSchema = z11.object({
|
|
845
|
+
runner: z11.union([runnerConfigSchema, runnerFunctionSchema]),
|
|
432
846
|
audits: pluginAuditsSchema,
|
|
433
847
|
groups: groupsSchema
|
|
434
848
|
});
|
|
@@ -454,22 +868,22 @@ function getMissingRefsFromGroups(pluginCfg) {
|
|
|
454
868
|
}
|
|
455
869
|
|
|
456
870
|
// packages/models/src/lib/upload-config.ts
|
|
457
|
-
import { z as
|
|
458
|
-
var uploadConfigSchema =
|
|
871
|
+
import { z as z12 } from "zod";
|
|
872
|
+
var uploadConfigSchema = z12.object({
|
|
459
873
|
server: urlSchema.describe("URL of deployed portal API"),
|
|
460
|
-
apiKey:
|
|
874
|
+
apiKey: z12.string({
|
|
461
875
|
description: "API key with write access to portal (use `process.env` for security)"
|
|
462
876
|
}),
|
|
463
877
|
organization: slugSchema.describe(
|
|
464
878
|
"Organization slug from Code PushUp portal"
|
|
465
879
|
),
|
|
466
880
|
project: slugSchema.describe("Project slug from Code PushUp portal"),
|
|
467
|
-
timeout:
|
|
881
|
+
timeout: z12.number({ description: "Request timeout in minutes (default is 5)" }).positive().int().optional()
|
|
468
882
|
});
|
|
469
883
|
|
|
470
884
|
// packages/models/src/lib/core-config.ts
|
|
471
|
-
var unrefinedCoreConfigSchema =
|
|
472
|
-
plugins:
|
|
885
|
+
var unrefinedCoreConfigSchema = z13.object({
|
|
886
|
+
plugins: z13.array(pluginConfigSchema, {
|
|
473
887
|
description: "List of plugins to be used (official, community-provided, or custom)"
|
|
474
888
|
}).min(1),
|
|
475
889
|
/** portal configuration for persisting results */
|
|
@@ -492,7 +906,7 @@ function refineCoreConfig(schema) {
|
|
|
492
906
|
}
|
|
493
907
|
|
|
494
908
|
// packages/models/src/lib/report.ts
|
|
495
|
-
import { z as
|
|
909
|
+
import { z as z14 } from "zod";
|
|
496
910
|
var auditReportSchema = auditSchema.merge(auditOutputSchema);
|
|
497
911
|
var pluginReportSchema = pluginMetaSchema.merge(
|
|
498
912
|
executionMetaSchema({
|
|
@@ -500,9 +914,9 @@ var pluginReportSchema = pluginMetaSchema.merge(
|
|
|
500
914
|
descriptionDuration: "Duration of the plugin run in ms"
|
|
501
915
|
})
|
|
502
916
|
).merge(
|
|
503
|
-
|
|
504
|
-
audits:
|
|
505
|
-
groups:
|
|
917
|
+
z14.object({
|
|
918
|
+
audits: z14.array(auditReportSchema).min(1),
|
|
919
|
+
groups: z14.array(groupSchema).optional()
|
|
506
920
|
})
|
|
507
921
|
).refine(
|
|
508
922
|
(pluginReport) => !getMissingRefsFromGroups2(pluginReport.audits, pluginReport.groups ?? []),
|
|
@@ -536,10 +950,10 @@ var reportSchema = packageVersionSchema({
|
|
|
536
950
|
descriptionDuration: "Duration of the collect run in ms"
|
|
537
951
|
})
|
|
538
952
|
).merge(
|
|
539
|
-
|
|
953
|
+
z14.object(
|
|
540
954
|
{
|
|
541
|
-
categories:
|
|
542
|
-
plugins:
|
|
955
|
+
categories: z14.array(categoryConfigSchema),
|
|
956
|
+
plugins: z14.array(pluginReportSchema).min(1),
|
|
543
957
|
commit: commitSchema.describe("Git commit for which report was collected").nullable()
|
|
544
958
|
},
|
|
545
959
|
{ description: "Collect output data" }
|
|
@@ -555,36 +969,40 @@ var reportSchema = packageVersionSchema({
|
|
|
555
969
|
);
|
|
556
970
|
|
|
557
971
|
// packages/models/src/lib/reports-diff.ts
|
|
558
|
-
import { z as
|
|
972
|
+
import { z as z15 } from "zod";
|
|
559
973
|
function makeComparisonSchema(schema) {
|
|
560
974
|
const sharedDescription = schema.description || "Result";
|
|
561
|
-
return
|
|
975
|
+
return z15.object({
|
|
562
976
|
before: schema.describe(`${sharedDescription} (source commit)`),
|
|
563
977
|
after: schema.describe(`${sharedDescription} (target commit)`)
|
|
564
978
|
});
|
|
565
979
|
}
|
|
566
980
|
function makeArraysComparisonSchema(diffSchema, resultSchema, description) {
|
|
567
|
-
return
|
|
981
|
+
return z15.object(
|
|
568
982
|
{
|
|
569
|
-
changed:
|
|
570
|
-
unchanged:
|
|
571
|
-
added:
|
|
572
|
-
removed:
|
|
983
|
+
changed: z15.array(diffSchema),
|
|
984
|
+
unchanged: z15.array(resultSchema),
|
|
985
|
+
added: z15.array(resultSchema),
|
|
986
|
+
removed: z15.array(resultSchema)
|
|
573
987
|
},
|
|
574
988
|
{ description }
|
|
575
989
|
);
|
|
576
990
|
}
|
|
577
|
-
var scorableMetaSchema =
|
|
991
|
+
var scorableMetaSchema = z15.object({
|
|
992
|
+
slug: slugSchema,
|
|
993
|
+
title: titleSchema,
|
|
994
|
+
docsUrl: docsUrlSchema
|
|
995
|
+
});
|
|
578
996
|
var scorableWithPluginMetaSchema = scorableMetaSchema.merge(
|
|
579
|
-
|
|
580
|
-
plugin: pluginMetaSchema.pick({ slug: true, title: true }).describe("Plugin which defines it")
|
|
997
|
+
z15.object({
|
|
998
|
+
plugin: pluginMetaSchema.pick({ slug: true, title: true, docsUrl: true }).describe("Plugin which defines it")
|
|
581
999
|
})
|
|
582
1000
|
);
|
|
583
1001
|
var scorableDiffSchema = scorableMetaSchema.merge(
|
|
584
|
-
|
|
1002
|
+
z15.object({
|
|
585
1003
|
scores: makeComparisonSchema(scoreSchema).merge(
|
|
586
|
-
|
|
587
|
-
diff:
|
|
1004
|
+
z15.object({
|
|
1005
|
+
diff: z15.number().min(-1).max(1).describe("Score change (`scores.after - scores.before`)")
|
|
588
1006
|
})
|
|
589
1007
|
).describe("Score comparison")
|
|
590
1008
|
})
|
|
@@ -595,10 +1013,10 @@ var scorableWithPluginDiffSchema = scorableDiffSchema.merge(
|
|
|
595
1013
|
var categoryDiffSchema = scorableDiffSchema;
|
|
596
1014
|
var groupDiffSchema = scorableWithPluginDiffSchema;
|
|
597
1015
|
var auditDiffSchema = scorableWithPluginDiffSchema.merge(
|
|
598
|
-
|
|
1016
|
+
z15.object({
|
|
599
1017
|
values: makeComparisonSchema(auditValueSchema).merge(
|
|
600
|
-
|
|
601
|
-
diff:
|
|
1018
|
+
z15.object({
|
|
1019
|
+
diff: z15.number().int().describe("Value change (`values.after - values.before`)")
|
|
602
1020
|
})
|
|
603
1021
|
).describe("Audit `value` comparison"),
|
|
604
1022
|
displayValues: makeComparisonSchema(auditDisplayValueSchema).describe(
|
|
@@ -607,15 +1025,15 @@ var auditDiffSchema = scorableWithPluginDiffSchema.merge(
|
|
|
607
1025
|
})
|
|
608
1026
|
);
|
|
609
1027
|
var categoryResultSchema = scorableMetaSchema.merge(
|
|
610
|
-
|
|
1028
|
+
z15.object({ score: scoreSchema })
|
|
611
1029
|
);
|
|
612
1030
|
var groupResultSchema = scorableWithPluginMetaSchema.merge(
|
|
613
|
-
|
|
1031
|
+
z15.object({ score: scoreSchema })
|
|
614
1032
|
);
|
|
615
1033
|
var auditResultSchema = scorableWithPluginMetaSchema.merge(
|
|
616
1034
|
auditOutputSchema.pick({ score: true, value: true, displayValue: true })
|
|
617
1035
|
);
|
|
618
|
-
var reportsDiffSchema =
|
|
1036
|
+
var reportsDiffSchema = z15.object({
|
|
619
1037
|
commits: makeComparisonSchema(commitSchema).nullable().describe("Commits identifying compared reports"),
|
|
620
1038
|
categories: makeArraysComparisonSchema(
|
|
621
1039
|
categoryDiffSchema,
|
|
@@ -778,40 +1196,48 @@ import chalk from "chalk";
|
|
|
778
1196
|
|
|
779
1197
|
// packages/utils/src/lib/reports/constants.ts
|
|
780
1198
|
var TERMINAL_WIDTH = 80;
|
|
781
|
-
var NEW_LINE = "\n";
|
|
782
1199
|
var SCORE_COLOR_RANGE = {
|
|
783
1200
|
GREEN_MIN: 0.9,
|
|
784
1201
|
YELLOW_MIN: 0.5
|
|
785
1202
|
};
|
|
1203
|
+
var CATEGORIES_TITLE = "\u{1F3F7} Categories";
|
|
786
1204
|
var FOOTER_PREFIX = "Made with \u2764 by";
|
|
787
1205
|
var CODE_PUSHUP_DOMAIN = "code-pushup.dev";
|
|
788
|
-
var README_LINK = "https://github.com/
|
|
1206
|
+
var README_LINK = "https://github.com/code-pushup/cli#readme";
|
|
789
1207
|
var reportHeadlineText = "Code PushUp Report";
|
|
790
1208
|
var reportOverviewTableHeaders = [
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
1209
|
+
{
|
|
1210
|
+
key: "category",
|
|
1211
|
+
label: "\u{1F3F7} Category",
|
|
1212
|
+
align: "left"
|
|
1213
|
+
},
|
|
1214
|
+
{
|
|
1215
|
+
key: "score",
|
|
1216
|
+
label: "\u2B50 Score"
|
|
1217
|
+
},
|
|
1218
|
+
{
|
|
1219
|
+
key: "audits",
|
|
1220
|
+
label: "\u{1F6E1} Audits"
|
|
1221
|
+
}
|
|
794
1222
|
];
|
|
795
1223
|
var reportRawOverviewTableHeaders = ["Category", "Score", "Audits"];
|
|
796
|
-
var
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
"Source file",
|
|
814
|
-
"Line(s)"
|
|
1224
|
+
var issuesTableHeadings = [
|
|
1225
|
+
{
|
|
1226
|
+
key: "severity",
|
|
1227
|
+
label: "Severity"
|
|
1228
|
+
},
|
|
1229
|
+
{
|
|
1230
|
+
key: "message",
|
|
1231
|
+
label: "Message"
|
|
1232
|
+
},
|
|
1233
|
+
{
|
|
1234
|
+
key: "file",
|
|
1235
|
+
label: "Source file"
|
|
1236
|
+
},
|
|
1237
|
+
{
|
|
1238
|
+
key: "line",
|
|
1239
|
+
label: "Line(s)"
|
|
1240
|
+
}
|
|
815
1241
|
];
|
|
816
1242
|
|
|
817
1243
|
// packages/utils/src/lib/logging.ts
|
|
@@ -837,7 +1263,7 @@ function logListItem(args) {
|
|
|
837
1263
|
singletonisaacUi.rows = [];
|
|
838
1264
|
singletonUiInstance?.logger.log(content);
|
|
839
1265
|
}
|
|
840
|
-
function
|
|
1266
|
+
function link3(text) {
|
|
841
1267
|
return chalk.underline(chalk.blueBright(text));
|
|
842
1268
|
}
|
|
843
1269
|
|
|
@@ -904,7 +1330,7 @@ async function ensureDirectoryExists(baseDir) {
|
|
|
904
1330
|
await mkdir(baseDir, { recursive: true });
|
|
905
1331
|
return;
|
|
906
1332
|
} catch (error) {
|
|
907
|
-
ui().logger.
|
|
1333
|
+
ui().logger.info(error.message);
|
|
908
1334
|
if (error.code !== "EEXIST") {
|
|
909
1335
|
throw error;
|
|
910
1336
|
}
|
|
@@ -969,127 +1395,40 @@ async function crawlFileSystem(options) {
|
|
|
969
1395
|
return resultsNestedArray.flat();
|
|
970
1396
|
}
|
|
971
1397
|
function findLineNumberInText(content, pattern) {
|
|
972
|
-
const
|
|
973
|
-
const lineNumber =
|
|
1398
|
+
const lines6 = content.split(/\r?\n/);
|
|
1399
|
+
const lineNumber = lines6.findIndex((line) => line.includes(pattern)) + 1;
|
|
974
1400
|
return lineNumber === 0 ? null : lineNumber;
|
|
975
1401
|
}
|
|
976
1402
|
|
|
977
|
-
// packages/utils/src/lib/reports/md/details.ts
|
|
978
|
-
function details(title, content, cfg = { open: false }) {
|
|
979
|
-
return `<details${cfg.open ? " open" : ""}>
|
|
980
|
-
<summary>${title}</summary>
|
|
981
|
-
|
|
982
|
-
${content}
|
|
983
|
-
|
|
984
|
-
</details>
|
|
985
|
-
`;
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
// packages/utils/src/lib/reports/md/font-style.ts
|
|
989
|
-
var stylesMap = {
|
|
990
|
-
i: "_",
|
|
991
|
-
// italic
|
|
992
|
-
b: "**",
|
|
993
|
-
// bold
|
|
994
|
-
s: "~",
|
|
995
|
-
// strike through
|
|
996
|
-
c: "`"
|
|
997
|
-
// code
|
|
998
|
-
};
|
|
999
|
-
function style(text, styles = ["b"]) {
|
|
1000
|
-
return styles.reduce((t, s) => `${stylesMap[s]}${t}${stylesMap[s]}`, text);
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
// packages/utils/src/lib/reports/md/headline.ts
|
|
1004
|
-
function headline(text, hierarchy = 1) {
|
|
1005
|
-
return `${"#".repeat(hierarchy)} ${text}`;
|
|
1006
|
-
}
|
|
1007
|
-
function h1(text) {
|
|
1008
|
-
return headline(text, 1);
|
|
1009
|
-
}
|
|
1010
|
-
function h2(text) {
|
|
1011
|
-
return headline(text, 2);
|
|
1012
|
-
}
|
|
1013
|
-
function h3(text) {
|
|
1014
|
-
return headline(text, 3);
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
// packages/utils/src/lib/reports/md/image.ts
|
|
1018
|
-
function image(src, alt) {
|
|
1019
|
-
return ``;
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
// packages/utils/src/lib/reports/md/link.ts
|
|
1023
|
-
function link2(href, text) {
|
|
1024
|
-
return `[${text || href}](${href})`;
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
// packages/utils/src/lib/reports/md/list.ts
|
|
1028
|
-
function li(text, order = "unordered") {
|
|
1029
|
-
const style2 = order === "unordered" ? "-" : "- [ ]";
|
|
1030
|
-
return `${style2} ${text}`;
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
// packages/utils/src/lib/reports/md/paragraphs.ts
|
|
1034
|
-
function paragraphs(...sections) {
|
|
1035
|
-
return sections.filter(Boolean).join("\n\n");
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
// packages/utils/src/lib/reports/md/table.ts
|
|
1039
|
-
var alignString = /* @__PURE__ */ new Map([
|
|
1040
|
-
["l", ":--"],
|
|
1041
|
-
["c", ":--:"],
|
|
1042
|
-
["r", "--:"]
|
|
1043
|
-
]);
|
|
1044
|
-
function tableMd(data, align) {
|
|
1045
|
-
if (data.length === 0) {
|
|
1046
|
-
throw new Error("Data can't be empty");
|
|
1047
|
-
}
|
|
1048
|
-
const alignmentSetting = align ?? data[0]?.map(() => "c");
|
|
1049
|
-
const tableContent = data.map((arr) => `|${arr.join("|")}|`);
|
|
1050
|
-
const alignmentRow = `|${alignmentSetting?.map((s) => alignString.get(s)).join("|")}|`;
|
|
1051
|
-
return tableContent[0] + NEW_LINE + alignmentRow + NEW_LINE + tableContent.slice(1).join(NEW_LINE);
|
|
1052
|
-
}
|
|
1053
|
-
function tableHtml(data) {
|
|
1054
|
-
if (data.length === 0) {
|
|
1055
|
-
throw new Error("Data can't be empty");
|
|
1056
|
-
}
|
|
1057
|
-
const tableContent = data.map((arr, index) => {
|
|
1058
|
-
if (index === 0) {
|
|
1059
|
-
const headerRow = arr.map((s) => `<th>${s}</th>`).join("");
|
|
1060
|
-
return `<tr>${headerRow}</tr>`;
|
|
1061
|
-
}
|
|
1062
|
-
const row = arr.map((s) => `<td>${s}</td>`).join("");
|
|
1063
|
-
return `<tr>${row}</tr>`;
|
|
1064
|
-
});
|
|
1065
|
-
return `<table>${tableContent.join("")}</table>`;
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
1403
|
// packages/utils/src/lib/reports/utils.ts
|
|
1404
|
+
var { image: image2, bold: boldMd } = md;
|
|
1069
1405
|
function formatReportScore(score) {
|
|
1070
1406
|
return Math.round(score * 100).toString();
|
|
1071
1407
|
}
|
|
1072
1408
|
function formatScoreWithColor(score, options) {
|
|
1073
|
-
const styledNumber = options?.skipBold ? formatReportScore(score) :
|
|
1074
|
-
return `${
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1409
|
+
const styledNumber = options?.skipBold ? formatReportScore(score) : boldMd(formatReportScore(score));
|
|
1410
|
+
return `${scoreMarker(score)} ${styledNumber}`;
|
|
1411
|
+
}
|
|
1412
|
+
var MARKERS = {
|
|
1413
|
+
circle: {
|
|
1414
|
+
red: "\u{1F534}",
|
|
1415
|
+
yellow: "\u{1F7E1}",
|
|
1416
|
+
green: "\u{1F7E2}"
|
|
1417
|
+
},
|
|
1418
|
+
square: {
|
|
1419
|
+
red: "\u{1F7E5}",
|
|
1420
|
+
yellow: "\u{1F7E8}",
|
|
1421
|
+
green: "\u{1F7E9}"
|
|
1082
1422
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
function getSquaredScoreMarker(score) {
|
|
1423
|
+
};
|
|
1424
|
+
function scoreMarker(score, markerType = "circle") {
|
|
1086
1425
|
if (score >= SCORE_COLOR_RANGE.GREEN_MIN) {
|
|
1087
|
-
return
|
|
1426
|
+
return MARKERS[markerType].green;
|
|
1088
1427
|
}
|
|
1089
1428
|
if (score >= SCORE_COLOR_RANGE.YELLOW_MIN) {
|
|
1090
|
-
return
|
|
1429
|
+
return MARKERS[markerType].yellow;
|
|
1091
1430
|
}
|
|
1092
|
-
return
|
|
1431
|
+
return MARKERS[markerType].red;
|
|
1093
1432
|
}
|
|
1094
1433
|
function getDiffMarker(diff) {
|
|
1095
1434
|
if (diff > 0) {
|
|
@@ -1105,7 +1444,7 @@ function colorByScoreDiff(text, diff) {
|
|
|
1105
1444
|
return shieldsBadge(text, color);
|
|
1106
1445
|
}
|
|
1107
1446
|
function shieldsBadge(text, color) {
|
|
1108
|
-
return
|
|
1447
|
+
return image2(
|
|
1109
1448
|
`https://img.shields.io/badge/${encodeURIComponent(text)}-${color}`,
|
|
1110
1449
|
text
|
|
1111
1450
|
);
|
|
@@ -1115,7 +1454,7 @@ function formatDiffNumber(diff) {
|
|
|
1115
1454
|
const sign = diff < 0 ? "\u2212" : "+";
|
|
1116
1455
|
return `${sign}${number}`;
|
|
1117
1456
|
}
|
|
1118
|
-
function
|
|
1457
|
+
function severityMarker(severity) {
|
|
1119
1458
|
if (severity === "error") {
|
|
1120
1459
|
return "\u{1F6A8}";
|
|
1121
1460
|
}
|
|
@@ -1306,13 +1645,13 @@ function executeProcess(cfg) {
|
|
|
1306
1645
|
process2.on("error", (err) => {
|
|
1307
1646
|
stderr += err.toString();
|
|
1308
1647
|
});
|
|
1309
|
-
process2.on("close", (
|
|
1648
|
+
process2.on("close", (code3) => {
|
|
1310
1649
|
const timings = { date, duration: calcDuration(start) };
|
|
1311
|
-
if (
|
|
1650
|
+
if (code3 === 0 || ignoreExitCode) {
|
|
1312
1651
|
onComplete?.();
|
|
1313
|
-
resolve({ code, stdout, stderr, ...timings });
|
|
1652
|
+
resolve({ code: code3, stdout, stderr, ...timings });
|
|
1314
1653
|
} else {
|
|
1315
|
-
const errorMsg = new ProcessError({ code, stdout, stderr, ...timings });
|
|
1654
|
+
const errorMsg = new ProcessError({ code: code3, stdout, stderr, ...timings });
|
|
1316
1655
|
onError?.(errorMsg);
|
|
1317
1656
|
reject(errorMsg);
|
|
1318
1657
|
}
|
|
@@ -1328,165 +1667,181 @@ function filterItemRefsBy(items, refFilterFn) {
|
|
|
1328
1667
|
})).filter((item) => item.refs.length);
|
|
1329
1668
|
}
|
|
1330
1669
|
|
|
1331
|
-
// packages/utils/src/lib/git.ts
|
|
1670
|
+
// packages/utils/src/lib/git/git.ts
|
|
1332
1671
|
import { isAbsolute, join as join3, relative } from "node:path";
|
|
1333
1672
|
import { simpleGit } from "simple-git";
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
import { platform } from "node:os";
|
|
1337
|
-
function toArray(val) {
|
|
1338
|
-
return Array.isArray(val) ? val : [val];
|
|
1339
|
-
}
|
|
1340
|
-
function objectToKeys(obj) {
|
|
1341
|
-
return Object.keys(obj);
|
|
1342
|
-
}
|
|
1343
|
-
function objectToEntries(obj) {
|
|
1344
|
-
return Object.entries(obj);
|
|
1345
|
-
}
|
|
1346
|
-
function objectFromEntries(entries) {
|
|
1347
|
-
return Object.fromEntries(entries);
|
|
1348
|
-
}
|
|
1349
|
-
function countOccurrences(values) {
|
|
1350
|
-
return values.reduce(
|
|
1351
|
-
(acc, value) => ({ ...acc, [value]: (acc[value] ?? 0) + 1 }),
|
|
1352
|
-
{}
|
|
1353
|
-
);
|
|
1673
|
+
function getGitRoot(git = simpleGit()) {
|
|
1674
|
+
return git.revparse("--show-toplevel");
|
|
1354
1675
|
}
|
|
1355
|
-
function
|
|
1356
|
-
|
|
1676
|
+
function formatGitPath(path, gitRoot) {
|
|
1677
|
+
const absolutePath = isAbsolute(path) ? path : join3(process.cwd(), path);
|
|
1678
|
+
const relativePath = relative(gitRoot, absolutePath);
|
|
1679
|
+
return toUnixPath(relativePath);
|
|
1357
1680
|
}
|
|
1358
|
-
function
|
|
1359
|
-
|
|
1681
|
+
async function toGitPath(path, git = simpleGit()) {
|
|
1682
|
+
const gitRoot = await getGitRoot(git);
|
|
1683
|
+
return formatGitPath(path, gitRoot);
|
|
1360
1684
|
}
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
return
|
|
1685
|
+
var GitStatusError = class _GitStatusError extends Error {
|
|
1686
|
+
static ignoredProps = /* @__PURE__ */ new Set(["current", "tracking"]);
|
|
1687
|
+
static getReducedStatus(status) {
|
|
1688
|
+
return Object.fromEntries(
|
|
1689
|
+
Object.entries(status).filter(([key]) => !this.ignoredProps.has(key)).filter(
|
|
1690
|
+
(entry) => {
|
|
1691
|
+
const value = entry[1];
|
|
1692
|
+
if (value == null) {
|
|
1693
|
+
return false;
|
|
1694
|
+
}
|
|
1695
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
1696
|
+
return false;
|
|
1697
|
+
}
|
|
1698
|
+
if (typeof value === "number" && value === 0) {
|
|
1699
|
+
return false;
|
|
1700
|
+
}
|
|
1701
|
+
return !(typeof value === "boolean" && !value);
|
|
1702
|
+
}
|
|
1703
|
+
)
|
|
1704
|
+
);
|
|
1365
1705
|
}
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1706
|
+
constructor(status) {
|
|
1707
|
+
super(
|
|
1708
|
+
`Working directory needs to be clean before we you can proceed. Commit your local changes or stash them:
|
|
1709
|
+
${JSON.stringify(
|
|
1710
|
+
_GitStatusError.getReducedStatus(status),
|
|
1711
|
+
null,
|
|
1712
|
+
2
|
|
1713
|
+
)}`
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1716
|
+
};
|
|
1717
|
+
async function guardAgainstLocalChanges(git = simpleGit()) {
|
|
1718
|
+
const status = await git.status(["-s"]);
|
|
1719
|
+
if (status.files.length > 0) {
|
|
1720
|
+
throw new GitStatusError(status);
|
|
1372
1721
|
}
|
|
1373
|
-
return Object.entries(params).flatMap(([key, value]) => {
|
|
1374
|
-
if (key === "_") {
|
|
1375
|
-
return Array.isArray(value) ? value : [`${value}`];
|
|
1376
|
-
}
|
|
1377
|
-
const prefix = key.length === 1 ? "-" : "--";
|
|
1378
|
-
if (Array.isArray(value)) {
|
|
1379
|
-
return value.map((v) => `${prefix}${key}="${v}"`);
|
|
1380
|
-
}
|
|
1381
|
-
if (Array.isArray(value)) {
|
|
1382
|
-
return value.map((v) => `${prefix}${key}="${v}"`);
|
|
1383
|
-
}
|
|
1384
|
-
if (typeof value === "string") {
|
|
1385
|
-
return [`${prefix}${key}="${value}"`];
|
|
1386
|
-
}
|
|
1387
|
-
if (typeof value === "number") {
|
|
1388
|
-
return [`${prefix}${key}=${value}`];
|
|
1389
|
-
}
|
|
1390
|
-
if (typeof value === "boolean") {
|
|
1391
|
-
return [`${prefix}${value ? "" : "no-"}${key}`];
|
|
1392
|
-
}
|
|
1393
|
-
throw new Error(`Unsupported type ${typeof value} for key ${key}`);
|
|
1394
|
-
});
|
|
1395
|
-
}
|
|
1396
|
-
function toUnixPath(path) {
|
|
1397
|
-
return path.replace(/\\/g, "/");
|
|
1398
|
-
}
|
|
1399
|
-
function toUnixNewlines(text) {
|
|
1400
|
-
return platform() === "win32" ? text.replace(/\r\n/g, "\n") : text;
|
|
1401
|
-
}
|
|
1402
|
-
function fromJsonLines(jsonLines) {
|
|
1403
|
-
const unifiedNewLines = toUnixNewlines(jsonLines).trim();
|
|
1404
|
-
return JSON.parse(`[${unifiedNewLines.split("\n").join(",")}]`);
|
|
1405
|
-
}
|
|
1406
|
-
function toJsonLines(json) {
|
|
1407
|
-
return json.map((item) => JSON.stringify(item)).join("\n");
|
|
1408
|
-
}
|
|
1409
|
-
function capitalize(text) {
|
|
1410
|
-
return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
|
|
1411
|
-
1
|
|
1412
|
-
)}`;
|
|
1413
|
-
}
|
|
1414
|
-
function apostrophize(text, upperCase) {
|
|
1415
|
-
const lastCharMatch = text.match(/(\w)\W*$/);
|
|
1416
|
-
const lastChar = lastCharMatch?.[1] ?? "";
|
|
1417
|
-
return `${text}'${lastChar.toLocaleLowerCase() === "s" ? "" : upperCase ? "S" : "s"}`;
|
|
1418
|
-
}
|
|
1419
|
-
function toNumberPrecision(value, decimalPlaces) {
|
|
1420
|
-
return Number(
|
|
1421
|
-
`${Math.round(
|
|
1422
|
-
Number.parseFloat(`${value}e${decimalPlaces}`)
|
|
1423
|
-
)}e-${decimalPlaces}`
|
|
1424
|
-
);
|
|
1425
1722
|
}
|
|
1426
|
-
function
|
|
1427
|
-
if (
|
|
1428
|
-
|
|
1723
|
+
async function safeCheckout(branchOrHash, forceCleanStatus = false, git = simpleGit()) {
|
|
1724
|
+
if (forceCleanStatus) {
|
|
1725
|
+
await git.raw(["reset", "--hard"]);
|
|
1726
|
+
await git.clean(["f", "d"]);
|
|
1727
|
+
ui().logger.info(`git status cleaned`);
|
|
1429
1728
|
}
|
|
1430
|
-
|
|
1431
|
-
|
|
1729
|
+
await guardAgainstLocalChanges(git);
|
|
1730
|
+
await git.checkout(branchOrHash);
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
// packages/utils/src/lib/git/git.commits-and-tags.ts
|
|
1734
|
+
import { simpleGit as simpleGit2 } from "simple-git";
|
|
1735
|
+
|
|
1736
|
+
// packages/utils/src/lib/semver.ts
|
|
1737
|
+
import { rcompare, valid } from "semver";
|
|
1738
|
+
function normalizeSemver(semverString) {
|
|
1739
|
+
if (semverString.startsWith("v") || semverString.startsWith("V")) {
|
|
1740
|
+
return semverString.slice(1);
|
|
1432
1741
|
}
|
|
1433
|
-
if (
|
|
1434
|
-
return
|
|
1742
|
+
if (semverString.includes("@")) {
|
|
1743
|
+
return semverString.split("@").at(-1) ?? "";
|
|
1435
1744
|
}
|
|
1436
|
-
return
|
|
1745
|
+
return semverString;
|
|
1746
|
+
}
|
|
1747
|
+
function isSemver(semverString = "") {
|
|
1748
|
+
return valid(normalizeSemver(semverString)) != null;
|
|
1749
|
+
}
|
|
1750
|
+
function sortSemvers(semverStrings) {
|
|
1751
|
+
return semverStrings.map(normalizeSemver).filter(isSemver).sort(rcompare);
|
|
1437
1752
|
}
|
|
1438
1753
|
|
|
1439
|
-
// packages/utils/src/lib/git.ts
|
|
1440
|
-
async function getLatestCommit(git =
|
|
1754
|
+
// packages/utils/src/lib/git/git.commits-and-tags.ts
|
|
1755
|
+
async function getLatestCommit(git = simpleGit2()) {
|
|
1441
1756
|
const log2 = await git.log({
|
|
1442
1757
|
maxCount: 1,
|
|
1758
|
+
// git log -1 --pretty=format:"%H %s %an %aI" - See: https://git-scm.com/docs/pretty-formats
|
|
1443
1759
|
format: { hash: "%H", message: "%s", author: "%an", date: "%aI" }
|
|
1444
1760
|
});
|
|
1445
|
-
if (!log2.latest) {
|
|
1446
|
-
return null;
|
|
1447
|
-
}
|
|
1448
1761
|
return commitSchema.parse(log2.latest);
|
|
1449
1762
|
}
|
|
1450
|
-
function
|
|
1451
|
-
return git.
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
const absolutePath = isAbsolute(path) ? path : join3(process.cwd(), path);
|
|
1455
|
-
const relativePath = relative(gitRoot, absolutePath);
|
|
1456
|
-
return toUnixPath(relativePath);
|
|
1763
|
+
async function getCurrentBranchOrTag(git = simpleGit2()) {
|
|
1764
|
+
return await git.branch().then((r) => r.current) || // If no current branch, try to get the tag
|
|
1765
|
+
// @TODO use simple git
|
|
1766
|
+
await git.raw(["describe", "--tags", "--exact-match"]).then((out) => out.trim());
|
|
1457
1767
|
}
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
return formatGitPath(path, gitRoot);
|
|
1461
|
-
}
|
|
1462
|
-
async function guardAgainstLocalChanges(git = simpleGit()) {
|
|
1463
|
-
const isClean = await git.status(["-s"]).then((r) => r.files.length === 0);
|
|
1464
|
-
if (!isClean) {
|
|
1768
|
+
function validateFilter({ from, to }) {
|
|
1769
|
+
if (to && !from) {
|
|
1465
1770
|
throw new Error(
|
|
1466
|
-
|
|
1771
|
+
`filter needs the "from" option defined to accept the "to" option.
|
|
1772
|
+
`
|
|
1467
1773
|
);
|
|
1468
1774
|
}
|
|
1469
1775
|
}
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
if (branch) {
|
|
1474
|
-
return branch;
|
|
1475
|
-
} else {
|
|
1476
|
-
return await git.raw(["describe", "--tags", "--exact-match"]).then((out) => out.trim());
|
|
1477
|
-
}
|
|
1478
|
-
} catch {
|
|
1479
|
-
throw new Error("Could not get current tag or branch.");
|
|
1776
|
+
function filterLogs(allTags, opt) {
|
|
1777
|
+
if (!opt) {
|
|
1778
|
+
return allTags;
|
|
1480
1779
|
}
|
|
1780
|
+
validateFilter(opt);
|
|
1781
|
+
const { from, to, maxCount } = opt;
|
|
1782
|
+
const finIndex = (tagName, fallback) => {
|
|
1783
|
+
const idx = allTags.indexOf(tagName ?? "");
|
|
1784
|
+
if (idx > -1) {
|
|
1785
|
+
return idx;
|
|
1786
|
+
}
|
|
1787
|
+
return fallback;
|
|
1788
|
+
};
|
|
1789
|
+
const fromIndex = finIndex(from, 0);
|
|
1790
|
+
const toIndex = finIndex(to, void 0);
|
|
1791
|
+
return allTags.slice(fromIndex, toIndex ? toIndex + 1 : toIndex).slice(0, maxCount ?? void 0);
|
|
1481
1792
|
}
|
|
1482
|
-
async function
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1793
|
+
async function getHashFromTag(tag, git = simpleGit2()) {
|
|
1794
|
+
const tagDetails = await git.show(["--no-patch", "--format=%H", tag]);
|
|
1795
|
+
const hash = tagDetails.trim();
|
|
1796
|
+
return {
|
|
1797
|
+
hash: hash.split("\n").at(-1) ?? "",
|
|
1798
|
+
message: tag
|
|
1799
|
+
};
|
|
1800
|
+
}
|
|
1801
|
+
async function getSemverTags(opt = {}, git = simpleGit2()) {
|
|
1802
|
+
validateFilter(opt);
|
|
1803
|
+
const { targetBranch, ...options } = opt;
|
|
1804
|
+
let currentBranch;
|
|
1805
|
+
if (targetBranch) {
|
|
1806
|
+
currentBranch = await getCurrentBranchOrTag(git);
|
|
1807
|
+
await git.checkout(targetBranch);
|
|
1808
|
+
}
|
|
1809
|
+
const tagsRaw = await git.tag([
|
|
1810
|
+
"--merged",
|
|
1811
|
+
targetBranch ?? await getCurrentBranchOrTag(git)
|
|
1812
|
+
]);
|
|
1813
|
+
const allTags = tagsRaw.split(/\n/).map((tag) => tag.trim()).filter(Boolean).filter(isSemver);
|
|
1814
|
+
const relevantTags = filterLogs(allTags, options);
|
|
1815
|
+
const tagsWithHashes = await Promise.all(
|
|
1816
|
+
relevantTags.map((tag) => getHashFromTag(tag, git))
|
|
1817
|
+
);
|
|
1818
|
+
if (currentBranch) {
|
|
1819
|
+
await git.checkout(currentBranch);
|
|
1820
|
+
}
|
|
1821
|
+
return tagsWithHashes;
|
|
1822
|
+
}
|
|
1823
|
+
async function getHashes(options = {}, git = simpleGit2()) {
|
|
1824
|
+
const { targetBranch, from, to, maxCount, ...opt } = options;
|
|
1825
|
+
validateFilter({ from, to });
|
|
1826
|
+
let currentBranch;
|
|
1827
|
+
if (targetBranch) {
|
|
1828
|
+
currentBranch = await getCurrentBranchOrTag(git);
|
|
1829
|
+
await git.checkout(targetBranch);
|
|
1830
|
+
}
|
|
1831
|
+
const logs = await git.log({
|
|
1832
|
+
...opt,
|
|
1833
|
+
format: {
|
|
1834
|
+
hash: "%H",
|
|
1835
|
+
message: "%s"
|
|
1836
|
+
},
|
|
1837
|
+
from,
|
|
1838
|
+
to,
|
|
1839
|
+
maxCount
|
|
1840
|
+
});
|
|
1841
|
+
if (targetBranch) {
|
|
1842
|
+
await git.checkout(currentBranch);
|
|
1487
1843
|
}
|
|
1488
|
-
|
|
1489
|
-
await git.checkout(branchOrHash);
|
|
1844
|
+
return [...logs.all];
|
|
1490
1845
|
}
|
|
1491
1846
|
|
|
1492
1847
|
// packages/utils/src/lib/group-by-status.ts
|
|
@@ -1564,44 +1919,65 @@ function listAuditsFromAllPlugins(report) {
|
|
|
1564
1919
|
);
|
|
1565
1920
|
}
|
|
1566
1921
|
|
|
1567
|
-
// packages/utils/src/lib/reports/
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
`${FOOTER_PREFIX} ${link2(README_LINK, "Code PushUp")}`
|
|
1922
|
+
// packages/utils/src/lib/reports/formatting.ts
|
|
1923
|
+
var { headline: headline2, lines: lines2, link: link4, section: section2, table: table3 } = md;
|
|
1924
|
+
function tableSection(tableData, options) {
|
|
1925
|
+
if (tableData.rows.length === 0) {
|
|
1926
|
+
return "";
|
|
1927
|
+
}
|
|
1928
|
+
const { level = 4 } = options ?? {};
|
|
1929
|
+
const render = (h7, l) => l === 0 ? h7 : headline2(h7, l);
|
|
1930
|
+
return lines2(
|
|
1931
|
+
tableData.title && render(tableData.title, level),
|
|
1932
|
+
table3(tableData)
|
|
1579
1933
|
);
|
|
1580
1934
|
}
|
|
1581
|
-
function
|
|
1582
|
-
|
|
1935
|
+
function metaDescription({
|
|
1936
|
+
docsUrl,
|
|
1937
|
+
description
|
|
1938
|
+
}) {
|
|
1939
|
+
if (docsUrl) {
|
|
1940
|
+
const docsLink = link4(docsUrl, "\u{1F4D6} Docs");
|
|
1941
|
+
if (!description) {
|
|
1942
|
+
return section2(docsLink);
|
|
1943
|
+
}
|
|
1944
|
+
const parsedDescription = description.toString().endsWith("```") ? `${description}${NEW_LINE + NEW_LINE}` : `${description}${SPACE}`;
|
|
1945
|
+
return section2(`${parsedDescription}${docsLink}`);
|
|
1946
|
+
}
|
|
1947
|
+
if (description && description.trim().length > 0) {
|
|
1948
|
+
return section2(description);
|
|
1949
|
+
}
|
|
1950
|
+
return "";
|
|
1583
1951
|
}
|
|
1584
|
-
|
|
1952
|
+
|
|
1953
|
+
// packages/utils/src/lib/reports/generate-md-report-categoy-section.ts
|
|
1954
|
+
var { link: link5, section: section3, h2: h22, lines: lines3, li: li2, bold: boldMd2, h3: h32, indentation: indentation2 } = md;
|
|
1955
|
+
function categoriesOverviewSection(report) {
|
|
1585
1956
|
const { categories, plugins } = report;
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1957
|
+
if (categories.length > 0 && plugins.length > 0) {
|
|
1958
|
+
const tableContent = {
|
|
1959
|
+
columns: reportOverviewTableHeaders,
|
|
1960
|
+
rows: categories.map(({ title, refs, score }) => ({
|
|
1961
|
+
// The heading "ID" is inferred from the heading text in Markdown.
|
|
1962
|
+
category: link5(`#${slugify(title)}`, title),
|
|
1963
|
+
score: `${scoreMarker(score)}${SPACE}${boldMd2(
|
|
1964
|
+
formatReportScore(score)
|
|
1965
|
+
)}`,
|
|
1966
|
+
audits: countCategoryAudits(refs, plugins).toString()
|
|
1967
|
+
}))
|
|
1968
|
+
};
|
|
1969
|
+
return tableSection(tableContent);
|
|
1970
|
+
}
|
|
1971
|
+
return "";
|
|
1595
1972
|
}
|
|
1596
|
-
function
|
|
1973
|
+
function categoriesDetailsSection(report) {
|
|
1597
1974
|
const { categories, plugins } = report;
|
|
1598
|
-
const categoryDetails = categories.
|
|
1599
|
-
const categoryTitle =
|
|
1600
|
-
const categoryScore = `${
|
|
1975
|
+
const categoryDetails = categories.flatMap((category) => {
|
|
1976
|
+
const categoryTitle = h32(category.title);
|
|
1977
|
+
const categoryScore = `${scoreMarker(
|
|
1601
1978
|
category.score
|
|
1602
|
-
)}
|
|
1603
|
-
const
|
|
1604
|
-
const categoryMDItems = category.refs.reduce((refAcc, ref) => {
|
|
1979
|
+
)}${SPACE}Score: ${boldMd2(formatReportScore(category.score))}`;
|
|
1980
|
+
const categoryMDItems = category.refs.map((ref) => {
|
|
1605
1981
|
if (ref.type === "group") {
|
|
1606
1982
|
const group = getSortableGroupByRef(ref, plugins);
|
|
1607
1983
|
const groupAudits = group.refs.map(
|
|
@@ -1611,151 +1987,240 @@ function reportToCategoriesSection(report) {
|
|
|
1611
1987
|
)
|
|
1612
1988
|
);
|
|
1613
1989
|
const pluginTitle = getPluginNameFromSlug(ref.plugin, plugins);
|
|
1614
|
-
|
|
1615
|
-
group,
|
|
1616
|
-
groupAudits,
|
|
1617
|
-
pluginTitle
|
|
1618
|
-
);
|
|
1619
|
-
return refAcc + mdGroupItem + NEW_LINE;
|
|
1990
|
+
return categoryGroupItem(group, groupAudits, pluginTitle);
|
|
1620
1991
|
} else {
|
|
1621
1992
|
const audit = getSortableAuditByRef(ref, plugins);
|
|
1622
1993
|
const pluginTitle = getPluginNameFromSlug(ref.plugin, plugins);
|
|
1623
|
-
|
|
1624
|
-
return refAcc + mdAuditItem + NEW_LINE;
|
|
1994
|
+
return categoryRef(audit, pluginTitle);
|
|
1625
1995
|
}
|
|
1626
|
-
}
|
|
1627
|
-
return
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1996
|
+
});
|
|
1997
|
+
return section3(
|
|
1998
|
+
categoryTitle,
|
|
1999
|
+
metaDescription(category),
|
|
2000
|
+
categoryScore,
|
|
2001
|
+
...categoryMDItems
|
|
2002
|
+
);
|
|
2003
|
+
});
|
|
2004
|
+
return lines3(h22(CATEGORIES_TITLE), ...categoryDetails);
|
|
2005
|
+
}
|
|
2006
|
+
function categoryRef({ title, score, value, displayValue }, pluginTitle) {
|
|
2007
|
+
const auditTitleAsLink = link5(
|
|
2008
|
+
`#${slugify(title)}-${slugify(pluginTitle)}`,
|
|
2009
|
+
title
|
|
1635
2010
|
);
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
2011
|
+
const marker = scoreMarker(score, "square");
|
|
2012
|
+
return li2(
|
|
2013
|
+
`${marker}${SPACE}${auditTitleAsLink}${SPACE}(_${pluginTitle}_) - ${boldMd2(
|
|
2014
|
+
(displayValue || value).toString()
|
|
2015
|
+
)}`
|
|
1640
2016
|
);
|
|
1641
2017
|
}
|
|
1642
|
-
function
|
|
1643
|
-
const
|
|
1644
|
-
|
|
1645
|
-
`${getRoundScoreMarker(groupScore)} ${group.title} (_${pluginTitle}_)`
|
|
2018
|
+
function categoryGroupItem({ score = 0, title }, groupAudits, pluginTitle) {
|
|
2019
|
+
const groupTitle = li2(
|
|
2020
|
+
`${scoreMarker(score)}${SPACE}${title}${SPACE}(_${pluginTitle}_)`
|
|
1646
2021
|
);
|
|
1647
|
-
const auditTitles = groupAudits.
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
const auditsData = plugin.audits.reduce((auditAcc, audit) => {
|
|
1663
|
-
const auditTitle = `${audit.title} (${getPluginNameFromSlug(
|
|
1664
|
-
plugin.slug,
|
|
1665
|
-
report.plugins
|
|
1666
|
-
)})`;
|
|
1667
|
-
return auditAcc + h3(auditTitle) + NEW_LINE + NEW_LINE + reportToDetailsSection(audit) + NEW_LINE + NEW_LINE + getDocsAndDescription(audit);
|
|
1668
|
-
}, "");
|
|
1669
|
-
return pluginAcc + auditsData;
|
|
1670
|
-
}, "");
|
|
1671
|
-
return h2("\u{1F6E1}\uFE0F Audits") + NEW_LINE + NEW_LINE + auditsSection;
|
|
1672
|
-
}
|
|
1673
|
-
function reportToDetailsSection(audit) {
|
|
1674
|
-
const detailsTitle = `${getSquaredScoreMarker(audit.score)} ${getAuditResult(
|
|
1675
|
-
audit,
|
|
1676
|
-
true
|
|
1677
|
-
)} (score: ${formatReportScore(audit.score)})`;
|
|
1678
|
-
if (!audit.details?.issues.length) {
|
|
1679
|
-
return detailsTitle;
|
|
1680
|
-
}
|
|
1681
|
-
const detailsTableData = [
|
|
1682
|
-
detailsTableHeaders,
|
|
1683
|
-
...audit.details.issues.map((issue) => {
|
|
1684
|
-
const severity = `${getSeverityIcon(issue.severity)} <i>${issue.severity}</i>`;
|
|
1685
|
-
const message = issue.message;
|
|
1686
|
-
if (!issue.source) {
|
|
1687
|
-
return [severity, message, "", ""];
|
|
1688
|
-
}
|
|
1689
|
-
const file = `<code>${issue.source.file}</code>`;
|
|
1690
|
-
if (!issue.source.position) {
|
|
1691
|
-
return [severity, message, file, ""];
|
|
1692
|
-
}
|
|
1693
|
-
const { startLine, endLine } = issue.source.position;
|
|
1694
|
-
const line = `${startLine || ""}${endLine && startLine !== endLine ? `-${endLine}` : ""}`;
|
|
1695
|
-
return [severity, message, file, line];
|
|
1696
|
-
})
|
|
1697
|
-
];
|
|
1698
|
-
const detailsTable = `<h4>Issues</h4>${tableHtml(detailsTableData)}`;
|
|
1699
|
-
return details(detailsTitle, detailsTable);
|
|
1700
|
-
}
|
|
1701
|
-
function reportToAboutSection(report) {
|
|
1702
|
-
const date = formatDate(/* @__PURE__ */ new Date());
|
|
1703
|
-
const { duration, version, commit, plugins, categories } = report;
|
|
1704
|
-
const commitInfo = commit ? `${commit.message} (${commit.hash})` : "N/A";
|
|
1705
|
-
const reportMetaTable = [
|
|
1706
|
-
reportMetaTableHeaders,
|
|
1707
|
-
[
|
|
1708
|
-
commitInfo,
|
|
1709
|
-
style(version || "", ["c"]),
|
|
1710
|
-
formatDuration(duration),
|
|
1711
|
-
plugins.length.toString(),
|
|
1712
|
-
categories.length.toString(),
|
|
1713
|
-
plugins.reduce((acc, { audits }) => acc + audits.length, 0).toString()
|
|
1714
|
-
]
|
|
1715
|
-
];
|
|
1716
|
-
const pluginMetaTable = [
|
|
1717
|
-
pluginMetaTableHeaders,
|
|
1718
|
-
...plugins.map((plugin) => [
|
|
1719
|
-
plugin.title,
|
|
1720
|
-
plugin.audits.length.toString(),
|
|
1721
|
-
style(plugin.version || "", ["c"]),
|
|
1722
|
-
formatDuration(plugin.duration)
|
|
1723
|
-
])
|
|
1724
|
-
];
|
|
1725
|
-
return (
|
|
1726
|
-
// eslint-disable-next-line prefer-template
|
|
1727
|
-
h2("About") + NEW_LINE + NEW_LINE + `Report was created by [Code PushUp](${README_LINK}) on ${date}.` + NEW_LINE + NEW_LINE + tableMd(reportMetaTable, ["l", "c", "c", "c", "c", "c"]) + NEW_LINE + NEW_LINE + "The following plugins were run:" + NEW_LINE + NEW_LINE + tableMd(pluginMetaTable, ["l", "c", "c", "c"])
|
|
2022
|
+
const auditTitles = groupAudits.map(
|
|
2023
|
+
({ title: auditTitle, score: auditScore, value, displayValue }) => {
|
|
2024
|
+
const auditTitleLink = link5(
|
|
2025
|
+
`#${slugify(auditTitle)}-${slugify(pluginTitle)}`,
|
|
2026
|
+
auditTitle
|
|
2027
|
+
);
|
|
2028
|
+
const marker = scoreMarker(auditScore, "square");
|
|
2029
|
+
return indentation2(
|
|
2030
|
+
li2(
|
|
2031
|
+
`${marker}${SPACE}${auditTitleLink} - ${boldMd2(
|
|
2032
|
+
String(displayValue ?? value)
|
|
2033
|
+
)}`
|
|
2034
|
+
)
|
|
2035
|
+
);
|
|
2036
|
+
}
|
|
1728
2037
|
);
|
|
2038
|
+
return lines3(groupTitle, ...auditTitles);
|
|
1729
2039
|
}
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
2040
|
+
|
|
2041
|
+
// packages/utils/src/lib/reports/generate-md-report.ts
|
|
2042
|
+
var { h1: h12, h2: h23, h3: h33, lines: lines4, link: link6, section: section4, code: codeMd } = md;
|
|
2043
|
+
var { bold: boldHtml, details: details2 } = html;
|
|
2044
|
+
function auditDetailsAuditValue({
|
|
2045
|
+
score,
|
|
2046
|
+
value,
|
|
2047
|
+
displayValue
|
|
1733
2048
|
}) {
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
2049
|
+
return `${scoreMarker(score, "square")} ${boldHtml(
|
|
2050
|
+
String(displayValue ?? value)
|
|
2051
|
+
)} (score: ${formatReportScore(score)})`;
|
|
2052
|
+
}
|
|
2053
|
+
function generateMdReport(report) {
|
|
2054
|
+
const printCategories = report.categories.length > 0;
|
|
2055
|
+
return lines4(
|
|
2056
|
+
h12(reportHeadlineText),
|
|
2057
|
+
printCategories ? categoriesOverviewSection(report) : "",
|
|
2058
|
+
printCategories ? categoriesDetailsSection(report) : "",
|
|
2059
|
+
auditsSection(report),
|
|
2060
|
+
aboutSection(report),
|
|
2061
|
+
`${FOOTER_PREFIX}${SPACE}${link6(README_LINK, "Code PushUp")}`
|
|
2062
|
+
);
|
|
2063
|
+
}
|
|
2064
|
+
function auditDetailsIssues(issues = []) {
|
|
2065
|
+
if (issues.length === 0) {
|
|
2066
|
+
return "";
|
|
1746
2067
|
}
|
|
1747
|
-
|
|
2068
|
+
const detailsTableData = {
|
|
2069
|
+
title: "Issues",
|
|
2070
|
+
columns: issuesTableHeadings,
|
|
2071
|
+
rows: issues.map(
|
|
2072
|
+
({ severity: severityVal, message, source: sourceVal }) => {
|
|
2073
|
+
const severity = `${severityMarker(severityVal)} <i>${severityVal}</i>`;
|
|
2074
|
+
if (!sourceVal) {
|
|
2075
|
+
return { severity, message, file: "", line: "" };
|
|
2076
|
+
}
|
|
2077
|
+
const file = `<code>${sourceVal.file}</code>`;
|
|
2078
|
+
if (!sourceVal.position) {
|
|
2079
|
+
return { severity, message, file, line: "" };
|
|
2080
|
+
}
|
|
2081
|
+
const { startLine, endLine } = sourceVal.position;
|
|
2082
|
+
const line = `${startLine || ""}${endLine && startLine !== endLine ? `-${endLine}` : ""}`;
|
|
2083
|
+
return { severity, message, file, line };
|
|
2084
|
+
}
|
|
2085
|
+
)
|
|
2086
|
+
};
|
|
2087
|
+
return tableSection(detailsTableData);
|
|
2088
|
+
}
|
|
2089
|
+
function auditDetails(audit) {
|
|
2090
|
+
const { table: table5, issues = [] } = audit.details ?? {};
|
|
2091
|
+
const detailsValue = auditDetailsAuditValue(audit);
|
|
2092
|
+
if (issues.length === 0 && table5 == null) {
|
|
2093
|
+
return section4(detailsValue);
|
|
2094
|
+
}
|
|
2095
|
+
const tableSectionContent = table5 == null ? "" : tableSection(table5);
|
|
2096
|
+
const issuesSectionContent = issues.length > 0 ? auditDetailsIssues(issues) : "";
|
|
2097
|
+
return details2(
|
|
2098
|
+
detailsValue,
|
|
2099
|
+
lines4(tableSectionContent, issuesSectionContent)
|
|
2100
|
+
);
|
|
2101
|
+
}
|
|
2102
|
+
function auditsSection({
|
|
2103
|
+
plugins
|
|
2104
|
+
}) {
|
|
2105
|
+
const content = plugins.flatMap(
|
|
2106
|
+
({ slug, audits }) => audits.flatMap((audit) => {
|
|
2107
|
+
const auditTitle = `${audit.title}${SPACE}(${getPluginNameFromSlug(
|
|
2108
|
+
slug,
|
|
2109
|
+
plugins
|
|
2110
|
+
)})`;
|
|
2111
|
+
const detailsContent = auditDetails(audit);
|
|
2112
|
+
const descriptionContent = metaDescription(audit);
|
|
2113
|
+
return [h33(auditTitle), detailsContent, descriptionContent];
|
|
2114
|
+
})
|
|
2115
|
+
);
|
|
2116
|
+
return section4(h23("\u{1F6E1}\uFE0F Audits"), ...content);
|
|
2117
|
+
}
|
|
2118
|
+
function aboutSection(report) {
|
|
2119
|
+
const { date, plugins } = report;
|
|
2120
|
+
const reportMetaTable = reportMetaData(report);
|
|
2121
|
+
const pluginMetaTable = reportPluginMeta({ plugins });
|
|
2122
|
+
return lines4(
|
|
2123
|
+
h23("About"),
|
|
2124
|
+
section4(
|
|
2125
|
+
`Report was created by [Code PushUp](${README_LINK}) on ${formatDate(
|
|
2126
|
+
new Date(date)
|
|
2127
|
+
)}.`
|
|
2128
|
+
),
|
|
2129
|
+
tableSection(pluginMetaTable),
|
|
2130
|
+
tableSection(reportMetaTable)
|
|
2131
|
+
);
|
|
2132
|
+
}
|
|
2133
|
+
function reportPluginMeta({ plugins }) {
|
|
2134
|
+
return {
|
|
2135
|
+
columns: [
|
|
2136
|
+
{
|
|
2137
|
+
key: "plugin",
|
|
2138
|
+
align: "left"
|
|
2139
|
+
},
|
|
2140
|
+
{
|
|
2141
|
+
key: "audits"
|
|
2142
|
+
},
|
|
2143
|
+
{
|
|
2144
|
+
key: "version"
|
|
2145
|
+
},
|
|
2146
|
+
{
|
|
2147
|
+
key: "duration"
|
|
2148
|
+
}
|
|
2149
|
+
],
|
|
2150
|
+
rows: plugins.map(
|
|
2151
|
+
({
|
|
2152
|
+
title: pluginTitle,
|
|
2153
|
+
audits,
|
|
2154
|
+
version: pluginVersion,
|
|
2155
|
+
duration: pluginDuration
|
|
2156
|
+
}) => ({
|
|
2157
|
+
plugin: pluginTitle,
|
|
2158
|
+
audits: audits.length.toString(),
|
|
2159
|
+
version: codeMd(pluginVersion || ""),
|
|
2160
|
+
duration: formatDuration(pluginDuration)
|
|
2161
|
+
})
|
|
2162
|
+
)
|
|
2163
|
+
};
|
|
1748
2164
|
}
|
|
1749
|
-
function
|
|
1750
|
-
|
|
1751
|
-
|
|
2165
|
+
function reportMetaData({
|
|
2166
|
+
commit,
|
|
2167
|
+
version,
|
|
2168
|
+
duration,
|
|
2169
|
+
plugins,
|
|
2170
|
+
categories
|
|
2171
|
+
}) {
|
|
2172
|
+
const commitInfo = commit ? `${commit.message}${SPACE}(${commit.hash})` : "N/A";
|
|
2173
|
+
return {
|
|
2174
|
+
columns: [
|
|
2175
|
+
{
|
|
2176
|
+
key: "commit",
|
|
2177
|
+
align: "left"
|
|
2178
|
+
},
|
|
2179
|
+
{
|
|
2180
|
+
key: "version"
|
|
2181
|
+
},
|
|
2182
|
+
{
|
|
2183
|
+
key: "duration"
|
|
2184
|
+
},
|
|
2185
|
+
{
|
|
2186
|
+
key: "plugins"
|
|
2187
|
+
},
|
|
2188
|
+
{
|
|
2189
|
+
key: "categories"
|
|
2190
|
+
},
|
|
2191
|
+
{
|
|
2192
|
+
key: "audits"
|
|
2193
|
+
}
|
|
2194
|
+
],
|
|
2195
|
+
rows: [
|
|
2196
|
+
{
|
|
2197
|
+
commit: commitInfo,
|
|
2198
|
+
version: codeMd(version || ""),
|
|
2199
|
+
duration: formatDuration(duration),
|
|
2200
|
+
plugins: plugins.length,
|
|
2201
|
+
categories: categories.length,
|
|
2202
|
+
audits: plugins.reduce((acc, { audits }) => acc + audits.length, 0).toString()
|
|
2203
|
+
}
|
|
2204
|
+
]
|
|
2205
|
+
};
|
|
1752
2206
|
}
|
|
1753
2207
|
|
|
1754
2208
|
// packages/utils/src/lib/reports/generate-md-reports-diff.ts
|
|
2209
|
+
var {
|
|
2210
|
+
h1: h13,
|
|
2211
|
+
h2: h24,
|
|
2212
|
+
lines: lines5,
|
|
2213
|
+
link: link7,
|
|
2214
|
+
bold: boldMd3,
|
|
2215
|
+
italic: italicMd,
|
|
2216
|
+
table: table4,
|
|
2217
|
+
section: section5
|
|
2218
|
+
} = md;
|
|
2219
|
+
var { details: details3 } = html;
|
|
1755
2220
|
var MAX_ROWS = 100;
|
|
1756
2221
|
function generateMdReportsDiff(diff) {
|
|
1757
|
-
return
|
|
1758
|
-
formatDiffHeaderSection(diff),
|
|
2222
|
+
return lines5(
|
|
2223
|
+
section5(formatDiffHeaderSection(diff)),
|
|
1759
2224
|
formatDiffCategoriesSection(diff),
|
|
1760
2225
|
formatDiffGroupsSection(diff),
|
|
1761
2226
|
formatDiffAuditsSection(diff)
|
|
@@ -1763,12 +2228,12 @@ function generateMdReportsDiff(diff) {
|
|
|
1763
2228
|
}
|
|
1764
2229
|
function formatDiffHeaderSection(diff) {
|
|
1765
2230
|
const outcomeTexts = {
|
|
1766
|
-
positive: `\u{1F973} Code PushUp report has ${
|
|
1767
|
-
negative: `\u{1F61F} Code PushUp report has ${
|
|
1768
|
-
mixed: `\u{1F928} Code PushUp report has both ${
|
|
2231
|
+
positive: `\u{1F973} Code PushUp report has ${boldMd3("improved")}`,
|
|
2232
|
+
negative: `\u{1F61F} Code PushUp report has ${boldMd3("regressed")}`,
|
|
2233
|
+
mixed: `\u{1F928} Code PushUp report has both ${boldMd3(
|
|
1769
2234
|
"improvements and regressions"
|
|
1770
2235
|
)}`,
|
|
1771
|
-
unchanged: `\u{1F610} Code PushUp report is ${
|
|
2236
|
+
unchanged: `\u{1F610} Code PushUp report is ${boldMd3("unchanged")}`
|
|
1772
2237
|
};
|
|
1773
2238
|
const outcome = mergeDiffOutcomes(
|
|
1774
2239
|
changesToDiffOutcomes([
|
|
@@ -1778,8 +2243,8 @@ function formatDiffHeaderSection(diff) {
|
|
|
1778
2243
|
])
|
|
1779
2244
|
);
|
|
1780
2245
|
const styleCommits = (commits) => `compared target commit ${commits.after.hash} with source commit ${commits.before.hash}`;
|
|
1781
|
-
return
|
|
1782
|
-
|
|
2246
|
+
return lines5(
|
|
2247
|
+
h13("Code PushUp"),
|
|
1783
2248
|
diff.commits ? `${outcomeTexts[outcome]} \u2013 ${styleCommits(diff.commits)}.` : `${outcomeTexts[outcome]}.`
|
|
1784
2249
|
);
|
|
1785
2250
|
}
|
|
@@ -1790,102 +2255,104 @@ function formatDiffCategoriesSection(diff) {
|
|
|
1790
2255
|
if (categoriesCount === 0) {
|
|
1791
2256
|
return "";
|
|
1792
2257
|
}
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
formatScoreWithColor(category.scores.
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
category.
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
2258
|
+
const columns = [
|
|
2259
|
+
{ key: "category", label: "\u{1F3F7}\uFE0F Category", align: "left" },
|
|
2260
|
+
{ key: "after", label: hasChanges ? "\u2B50 Current score" : "\u2B50 Score" },
|
|
2261
|
+
{ key: "before", label: "\u2B50 Previous score" },
|
|
2262
|
+
{ key: "change", label: "\u{1F504} Score change" }
|
|
2263
|
+
];
|
|
2264
|
+
return lines5(
|
|
2265
|
+
h24("\u{1F3F7}\uFE0F Categories"),
|
|
2266
|
+
categoriesCount > 0 && table4({
|
|
2267
|
+
columns: hasChanges ? columns : columns.slice(0, 2),
|
|
2268
|
+
rows: [
|
|
2269
|
+
...sortChanges(changed).map((category) => ({
|
|
2270
|
+
category: formatTitle(category),
|
|
2271
|
+
after: formatScoreWithColor(category.scores.after),
|
|
2272
|
+
before: formatScoreWithColor(category.scores.before, {
|
|
2273
|
+
skipBold: true
|
|
2274
|
+
}),
|
|
2275
|
+
change: formatScoreChange(category.scores.diff)
|
|
2276
|
+
})),
|
|
2277
|
+
...added.map((category) => ({
|
|
2278
|
+
category: formatTitle(category),
|
|
2279
|
+
after: formatScoreWithColor(category.score),
|
|
2280
|
+
before: italicMd("n/a (\\*)"),
|
|
2281
|
+
change: italicMd("n/a (\\*)")
|
|
2282
|
+
})),
|
|
2283
|
+
...unchanged.map((category) => ({
|
|
2284
|
+
category: formatTitle(category),
|
|
2285
|
+
after: formatScoreWithColor(category.score),
|
|
2286
|
+
before: formatScoreWithColor(category.score, { skipBold: true }),
|
|
2287
|
+
change: "\u2013"
|
|
2288
|
+
}))
|
|
2289
|
+
].map(
|
|
2290
|
+
(row) => hasChanges ? row : { category: row.category, after: row.after }
|
|
2291
|
+
)
|
|
2292
|
+
}),
|
|
2293
|
+
added.length > 0 && section5(italicMd("(\\*) New category."))
|
|
1825
2294
|
);
|
|
1826
2295
|
}
|
|
1827
2296
|
function formatDiffGroupsSection(diff) {
|
|
1828
2297
|
if (diff.groups.changed.length + diff.groups.unchanged.length === 0) {
|
|
1829
2298
|
return "";
|
|
1830
2299
|
}
|
|
1831
|
-
return
|
|
1832
|
-
|
|
2300
|
+
return lines5(
|
|
2301
|
+
h24("\u{1F5C3}\uFE0F Groups"),
|
|
1833
2302
|
formatGroupsOrAuditsDetails("group", diff.groups, {
|
|
1834
|
-
|
|
1835
|
-
"\u{1F50C} Plugin",
|
|
1836
|
-
"\u{1F5C3}\uFE0F Group",
|
|
1837
|
-
"\u2B50 Current score",
|
|
1838
|
-
"\u2B50 Previous score",
|
|
1839
|
-
"\u{1F504} Score change"
|
|
2303
|
+
columns: [
|
|
2304
|
+
{ key: "plugin", label: "\u{1F50C} Plugin", align: "left" },
|
|
2305
|
+
{ key: "group", label: "\u{1F5C3}\uFE0F Group", align: "left" },
|
|
2306
|
+
{ key: "after", label: "\u2B50 Current score" },
|
|
2307
|
+
{ key: "before", label: "\u2B50 Previous score" },
|
|
2308
|
+
{ key: "change", label: "\u{1F504} Score change" }
|
|
1840
2309
|
],
|
|
1841
|
-
rows: sortChanges(diff.groups.changed).map((group) =>
|
|
1842
|
-
group.plugin
|
|
1843
|
-
group
|
|
1844
|
-
formatScoreWithColor(group.scores.after),
|
|
1845
|
-
formatScoreWithColor(group.scores.before, { skipBold: true }),
|
|
1846
|
-
formatScoreChange(group.scores.diff)
|
|
1847
|
-
|
|
1848
|
-
align: ["l", "l", "c", "c", "c"]
|
|
2310
|
+
rows: sortChanges(diff.groups.changed).map((group) => ({
|
|
2311
|
+
plugin: formatTitle(group.plugin),
|
|
2312
|
+
group: formatTitle(group),
|
|
2313
|
+
after: formatScoreWithColor(group.scores.after),
|
|
2314
|
+
before: formatScoreWithColor(group.scores.before, { skipBold: true }),
|
|
2315
|
+
change: formatScoreChange(group.scores.diff)
|
|
2316
|
+
}))
|
|
1849
2317
|
})
|
|
1850
2318
|
);
|
|
1851
2319
|
}
|
|
1852
2320
|
function formatDiffAuditsSection(diff) {
|
|
1853
|
-
return
|
|
1854
|
-
|
|
2321
|
+
return lines5(
|
|
2322
|
+
h24("\u{1F6E1}\uFE0F Audits"),
|
|
1855
2323
|
formatGroupsOrAuditsDetails("audit", diff.audits, {
|
|
1856
|
-
|
|
1857
|
-
"\u{1F50C} Plugin",
|
|
1858
|
-
"\u{1F6E1}\uFE0F Audit",
|
|
1859
|
-
"\u{1F4CF} Current value",
|
|
1860
|
-
"\u{1F4CF} Previous value",
|
|
1861
|
-
"\u{1F504} Value change"
|
|
2324
|
+
columns: [
|
|
2325
|
+
{ key: "plugin", label: "\u{1F50C} Plugin", align: "left" },
|
|
2326
|
+
{ key: "audit", label: "\u{1F6E1}\uFE0F Audit", align: "left" },
|
|
2327
|
+
{ key: "after", label: "\u{1F4CF} Current value" },
|
|
2328
|
+
{ key: "before", label: "\u{1F4CF} Previous value" },
|
|
2329
|
+
{ key: "change", label: "\u{1F504} Value change" }
|
|
1862
2330
|
],
|
|
1863
|
-
rows: sortChanges(diff.audits.changed).map((audit) =>
|
|
1864
|
-
audit.plugin
|
|
1865
|
-
audit
|
|
1866
|
-
`${
|
|
2331
|
+
rows: sortChanges(diff.audits.changed).map((audit) => ({
|
|
2332
|
+
plugin: formatTitle(audit.plugin),
|
|
2333
|
+
audit: formatTitle(audit),
|
|
2334
|
+
after: `${scoreMarker(audit.scores.after, "square")} ${boldMd3(
|
|
1867
2335
|
audit.displayValues.after || audit.values.after.toString()
|
|
1868
2336
|
)}`,
|
|
1869
|
-
`${
|
|
1870
|
-
formatValueChange(audit)
|
|
1871
|
-
|
|
1872
|
-
align: ["l", "l", "c", "c", "c"]
|
|
2337
|
+
before: `${scoreMarker(audit.scores.before, "square")} ${audit.displayValues.before || audit.values.before.toString()}`,
|
|
2338
|
+
change: formatValueChange(audit)
|
|
2339
|
+
}))
|
|
1873
2340
|
})
|
|
1874
2341
|
);
|
|
1875
2342
|
}
|
|
1876
|
-
function formatGroupsOrAuditsDetails(token, { changed, unchanged },
|
|
1877
|
-
return changed.length === 0 ? summarizeUnchanged(token, { changed, unchanged }) :
|
|
2343
|
+
function formatGroupsOrAuditsDetails(token, { changed, unchanged }, tableData) {
|
|
2344
|
+
return changed.length === 0 ? summarizeUnchanged(token, { changed, unchanged }) : details3(
|
|
1878
2345
|
summarizeDiffOutcomes(changesToDiffOutcomes(changed), token),
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
2346
|
+
lines5(
|
|
2347
|
+
table4({
|
|
2348
|
+
...tableData,
|
|
2349
|
+
rows: tableData.rows.slice(0, MAX_ROWS)
|
|
2350
|
+
// use never to avoid typing problem
|
|
2351
|
+
}),
|
|
2352
|
+
changed.length > MAX_ROWS && italicMd(
|
|
1885
2353
|
`Only the ${MAX_ROWS} most affected ${pluralize(
|
|
1886
2354
|
token
|
|
1887
|
-
)} are listed above for brevity
|
|
1888
|
-
["i"]
|
|
2355
|
+
)} are listed above for brevity.`
|
|
1889
2356
|
),
|
|
1890
2357
|
unchanged.length > 0 && summarizeUnchanged(token, { changed, unchanged })
|
|
1891
2358
|
)
|
|
@@ -1906,11 +2373,13 @@ function formatValueChange({
|
|
|
1906
2373
|
return colorByScoreDiff(`${marker} ${text}`, scores.diff);
|
|
1907
2374
|
}
|
|
1908
2375
|
function summarizeUnchanged(token, { changed, unchanged }) {
|
|
1909
|
-
return
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
2376
|
+
return section5(
|
|
2377
|
+
[
|
|
2378
|
+
changed.length > 0 ? pluralizeToken(`other ${token}`, unchanged.length) : `All of ${pluralizeToken(token, unchanged.length)}`,
|
|
2379
|
+
unchanged.length === 1 ? "is" : "are",
|
|
2380
|
+
"unchanged."
|
|
2381
|
+
].join(" ")
|
|
2382
|
+
);
|
|
1914
2383
|
}
|
|
1915
2384
|
function summarizeDiffOutcomes(outcomes, token) {
|
|
1916
2385
|
return objectToEntries(countDiffOutcomes(outcomes)).filter(
|
|
@@ -1930,6 +2399,15 @@ function summarizeDiffOutcomes(outcomes, token) {
|
|
|
1930
2399
|
}
|
|
1931
2400
|
}).join(", ");
|
|
1932
2401
|
}
|
|
2402
|
+
function formatTitle({
|
|
2403
|
+
title,
|
|
2404
|
+
docsUrl
|
|
2405
|
+
}) {
|
|
2406
|
+
if (docsUrl) {
|
|
2407
|
+
return link7(docsUrl, title);
|
|
2408
|
+
}
|
|
2409
|
+
return title;
|
|
2410
|
+
}
|
|
1933
2411
|
function sortChanges(changes) {
|
|
1934
2412
|
return [...changes].sort(
|
|
1935
2413
|
(a, b) => Math.abs(b.scores.diff) - Math.abs(a.scores.diff) || Math.abs(b.values?.diff ?? 0) - Math.abs(a.values?.diff ?? 0)
|
|
@@ -1977,7 +2455,7 @@ function log(msg = "") {
|
|
|
1977
2455
|
}
|
|
1978
2456
|
function logStdoutSummary(report) {
|
|
1979
2457
|
const printCategories = report.categories.length > 0;
|
|
1980
|
-
log(
|
|
2458
|
+
log(reportToHeaderSection(report));
|
|
1981
2459
|
log();
|
|
1982
2460
|
logPlugins(report);
|
|
1983
2461
|
if (printCategories) {
|
|
@@ -1986,7 +2464,7 @@ function logStdoutSummary(report) {
|
|
|
1986
2464
|
log(`${FOOTER_PREFIX} ${CODE_PUSHUP_DOMAIN}`);
|
|
1987
2465
|
log();
|
|
1988
2466
|
}
|
|
1989
|
-
function
|
|
2467
|
+
function reportToHeaderSection(report) {
|
|
1990
2468
|
const { packageName, version } = report;
|
|
1991
2469
|
return `${chalk4.bold(reportHeadlineText)} - ${packageName}@${version}`;
|
|
1992
2470
|
}
|
|
@@ -2026,16 +2504,16 @@ function logCategories({ categories, plugins }) {
|
|
|
2026
2504
|
applyScoreColor({ score }),
|
|
2027
2505
|
countCategoryAudits(refs, plugins)
|
|
2028
2506
|
]);
|
|
2029
|
-
const
|
|
2030
|
-
|
|
2031
|
-
|
|
2507
|
+
const table5 = ui().table();
|
|
2508
|
+
table5.columnWidths([TERMINAL_WIDTH - 9 - 10 - 4, 9, 10]);
|
|
2509
|
+
table5.head(
|
|
2032
2510
|
reportRawOverviewTableHeaders.map((heading, idx) => ({
|
|
2033
2511
|
content: chalk4.cyan(heading),
|
|
2034
2512
|
hAlign: hAlign(idx)
|
|
2035
2513
|
}))
|
|
2036
2514
|
);
|
|
2037
2515
|
rows.forEach(
|
|
2038
|
-
(row) =>
|
|
2516
|
+
(row) => table5.row(
|
|
2039
2517
|
row.map((content, idx) => ({
|
|
2040
2518
|
content: content.toString(),
|
|
2041
2519
|
hAlign: hAlign(idx)
|
|
@@ -2044,19 +2522,19 @@ function logCategories({ categories, plugins }) {
|
|
|
2044
2522
|
);
|
|
2045
2523
|
log(chalk4.magentaBright.bold("Categories"));
|
|
2046
2524
|
log();
|
|
2047
|
-
|
|
2525
|
+
table5.render();
|
|
2048
2526
|
log();
|
|
2049
2527
|
}
|
|
2050
2528
|
function applyScoreColor({ score, text }) {
|
|
2051
2529
|
const formattedScore = text ?? formatReportScore(score);
|
|
2052
|
-
const
|
|
2530
|
+
const style = text ? chalk4 : chalk4.bold;
|
|
2053
2531
|
if (score >= SCORE_COLOR_RANGE.GREEN_MIN) {
|
|
2054
|
-
return
|
|
2532
|
+
return style.green(formattedScore);
|
|
2055
2533
|
}
|
|
2056
2534
|
if (score >= SCORE_COLOR_RANGE.YELLOW_MIN) {
|
|
2057
|
-
return
|
|
2535
|
+
return style.yellow(formattedScore);
|
|
2058
2536
|
}
|
|
2059
|
-
return
|
|
2537
|
+
return style.red(formattedScore);
|
|
2060
2538
|
}
|
|
2061
2539
|
|
|
2062
2540
|
// packages/utils/src/lib/reports/scoring.ts
|
|
@@ -2218,8 +2696,11 @@ var verboseUtils = (verbose = false) => ({
|
|
|
2218
2696
|
export {
|
|
2219
2697
|
CODE_PUSHUP_DOMAIN,
|
|
2220
2698
|
FOOTER_PREFIX,
|
|
2699
|
+
NEW_LINE,
|
|
2221
2700
|
ProcessError,
|
|
2222
2701
|
README_LINK,
|
|
2702
|
+
SPACE,
|
|
2703
|
+
TAB,
|
|
2223
2704
|
TERMINAL_WIDTH,
|
|
2224
2705
|
apostrophize,
|
|
2225
2706
|
calcDuration,
|
|
@@ -2245,13 +2726,19 @@ export {
|
|
|
2245
2726
|
generateMdReportsDiff,
|
|
2246
2727
|
getCurrentBranchOrTag,
|
|
2247
2728
|
getGitRoot,
|
|
2729
|
+
getHashFromTag,
|
|
2730
|
+
getHashes,
|
|
2248
2731
|
getLatestCommit,
|
|
2249
2732
|
getProgressBar,
|
|
2733
|
+
getSemverTags,
|
|
2250
2734
|
groupByStatus,
|
|
2735
|
+
guardAgainstLocalChanges,
|
|
2736
|
+
html,
|
|
2251
2737
|
importEsmModule,
|
|
2252
2738
|
isPromiseFulfilledResult,
|
|
2253
2739
|
isPromiseRejectedResult,
|
|
2254
|
-
|
|
2740
|
+
isSemver,
|
|
2741
|
+
link3 as link,
|
|
2255
2742
|
listAuditsFromAllPlugins,
|
|
2256
2743
|
listGroupsFromAllPlugins,
|
|
2257
2744
|
loadReport,
|
|
@@ -2259,6 +2746,8 @@ export {
|
|
|
2259
2746
|
logMultipleResults,
|
|
2260
2747
|
logStdoutSummary,
|
|
2261
2748
|
matchArrayItemsByKey,
|
|
2749
|
+
md,
|
|
2750
|
+
normalizeSemver,
|
|
2262
2751
|
objectFromEntries,
|
|
2263
2752
|
objectToCliArgs,
|
|
2264
2753
|
objectToEntries,
|
|
@@ -2273,6 +2762,7 @@ export {
|
|
|
2273
2762
|
scoreReport,
|
|
2274
2763
|
slugify,
|
|
2275
2764
|
sortReport,
|
|
2765
|
+
sortSemvers,
|
|
2276
2766
|
toArray,
|
|
2277
2767
|
toGitPath,
|
|
2278
2768
|
toJsonLines,
|