@code-pushup/utils 0.39.0 → 0.42.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/index.js +1042 -587
- package/package.json +5 -4
- package/src/index.d.ts +4 -1
- package/src/lib/git/git.commits-and-tags.d.ts +57 -0
- package/src/lib/{git.d.ts → git/git.d.ts} +0 -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/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,40 +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({
|
|
578
992
|
slug: slugSchema,
|
|
579
993
|
title: titleSchema,
|
|
580
994
|
docsUrl: docsUrlSchema
|
|
581
995
|
});
|
|
582
996
|
var scorableWithPluginMetaSchema = scorableMetaSchema.merge(
|
|
583
|
-
|
|
997
|
+
z15.object({
|
|
584
998
|
plugin: pluginMetaSchema.pick({ slug: true, title: true, docsUrl: true }).describe("Plugin which defines it")
|
|
585
999
|
})
|
|
586
1000
|
);
|
|
587
1001
|
var scorableDiffSchema = scorableMetaSchema.merge(
|
|
588
|
-
|
|
1002
|
+
z15.object({
|
|
589
1003
|
scores: makeComparisonSchema(scoreSchema).merge(
|
|
590
|
-
|
|
591
|
-
diff:
|
|
1004
|
+
z15.object({
|
|
1005
|
+
diff: z15.number().min(-1).max(1).describe("Score change (`scores.after - scores.before`)")
|
|
592
1006
|
})
|
|
593
1007
|
).describe("Score comparison")
|
|
594
1008
|
})
|
|
@@ -599,10 +1013,10 @@ var scorableWithPluginDiffSchema = scorableDiffSchema.merge(
|
|
|
599
1013
|
var categoryDiffSchema = scorableDiffSchema;
|
|
600
1014
|
var groupDiffSchema = scorableWithPluginDiffSchema;
|
|
601
1015
|
var auditDiffSchema = scorableWithPluginDiffSchema.merge(
|
|
602
|
-
|
|
1016
|
+
z15.object({
|
|
603
1017
|
values: makeComparisonSchema(auditValueSchema).merge(
|
|
604
|
-
|
|
605
|
-
diff:
|
|
1018
|
+
z15.object({
|
|
1019
|
+
diff: z15.number().int().describe("Value change (`values.after - values.before`)")
|
|
606
1020
|
})
|
|
607
1021
|
).describe("Audit `value` comparison"),
|
|
608
1022
|
displayValues: makeComparisonSchema(auditDisplayValueSchema).describe(
|
|
@@ -611,15 +1025,15 @@ var auditDiffSchema = scorableWithPluginDiffSchema.merge(
|
|
|
611
1025
|
})
|
|
612
1026
|
);
|
|
613
1027
|
var categoryResultSchema = scorableMetaSchema.merge(
|
|
614
|
-
|
|
1028
|
+
z15.object({ score: scoreSchema })
|
|
615
1029
|
);
|
|
616
1030
|
var groupResultSchema = scorableWithPluginMetaSchema.merge(
|
|
617
|
-
|
|
1031
|
+
z15.object({ score: scoreSchema })
|
|
618
1032
|
);
|
|
619
1033
|
var auditResultSchema = scorableWithPluginMetaSchema.merge(
|
|
620
1034
|
auditOutputSchema.pick({ score: true, value: true, displayValue: true })
|
|
621
1035
|
);
|
|
622
|
-
var reportsDiffSchema =
|
|
1036
|
+
var reportsDiffSchema = z15.object({
|
|
623
1037
|
commits: makeComparisonSchema(commitSchema).nullable().describe("Commits identifying compared reports"),
|
|
624
1038
|
categories: makeArraysComparisonSchema(
|
|
625
1039
|
categoryDiffSchema,
|
|
@@ -782,40 +1196,48 @@ import chalk from "chalk";
|
|
|
782
1196
|
|
|
783
1197
|
// packages/utils/src/lib/reports/constants.ts
|
|
784
1198
|
var TERMINAL_WIDTH = 80;
|
|
785
|
-
var NEW_LINE = "\n";
|
|
786
1199
|
var SCORE_COLOR_RANGE = {
|
|
787
1200
|
GREEN_MIN: 0.9,
|
|
788
1201
|
YELLOW_MIN: 0.5
|
|
789
1202
|
};
|
|
1203
|
+
var CATEGORIES_TITLE = "\u{1F3F7} Categories";
|
|
790
1204
|
var FOOTER_PREFIX = "Made with \u2764 by";
|
|
791
1205
|
var CODE_PUSHUP_DOMAIN = "code-pushup.dev";
|
|
792
|
-
var README_LINK = "https://github.com/
|
|
1206
|
+
var README_LINK = "https://github.com/code-pushup/cli#readme";
|
|
793
1207
|
var reportHeadlineText = "Code PushUp Report";
|
|
794
1208
|
var reportOverviewTableHeaders = [
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
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
|
+
}
|
|
798
1222
|
];
|
|
799
1223
|
var reportRawOverviewTableHeaders = ["Category", "Score", "Audits"];
|
|
800
|
-
var
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
"Source file",
|
|
818
|
-
"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
|
+
}
|
|
819
1241
|
];
|
|
820
1242
|
|
|
821
1243
|
// packages/utils/src/lib/logging.ts
|
|
@@ -841,7 +1263,7 @@ function logListItem(args) {
|
|
|
841
1263
|
singletonisaacUi.rows = [];
|
|
842
1264
|
singletonUiInstance?.logger.log(content);
|
|
843
1265
|
}
|
|
844
|
-
function
|
|
1266
|
+
function link3(text) {
|
|
845
1267
|
return chalk.underline(chalk.blueBright(text));
|
|
846
1268
|
}
|
|
847
1269
|
|
|
@@ -973,127 +1395,40 @@ async function crawlFileSystem(options) {
|
|
|
973
1395
|
return resultsNestedArray.flat();
|
|
974
1396
|
}
|
|
975
1397
|
function findLineNumberInText(content, pattern) {
|
|
976
|
-
const
|
|
977
|
-
const lineNumber =
|
|
1398
|
+
const lines6 = content.split(/\r?\n/);
|
|
1399
|
+
const lineNumber = lines6.findIndex((line) => line.includes(pattern)) + 1;
|
|
978
1400
|
return lineNumber === 0 ? null : lineNumber;
|
|
979
1401
|
}
|
|
980
1402
|
|
|
981
|
-
// packages/utils/src/lib/reports/
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
${content}
|
|
987
|
-
|
|
988
|
-
</details>
|
|
989
|
-
`;
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
// packages/utils/src/lib/reports/md/font-style.ts
|
|
993
|
-
var stylesMap = {
|
|
994
|
-
i: "_",
|
|
995
|
-
// italic
|
|
996
|
-
b: "**",
|
|
997
|
-
// bold
|
|
998
|
-
s: "~",
|
|
999
|
-
// strike through
|
|
1000
|
-
c: "`"
|
|
1001
|
-
// code
|
|
1002
|
-
};
|
|
1003
|
-
function style(text, styles = ["b"]) {
|
|
1004
|
-
return styles.reduce((t, s) => `${stylesMap[s]}${t}${stylesMap[s]}`, text);
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
// packages/utils/src/lib/reports/md/headline.ts
|
|
1008
|
-
function headline(text, hierarchy = 1) {
|
|
1009
|
-
return `${"#".repeat(hierarchy)} ${text}`;
|
|
1010
|
-
}
|
|
1011
|
-
function h1(text) {
|
|
1012
|
-
return headline(text, 1);
|
|
1013
|
-
}
|
|
1014
|
-
function h2(text) {
|
|
1015
|
-
return headline(text, 2);
|
|
1016
|
-
}
|
|
1017
|
-
function h3(text) {
|
|
1018
|
-
return headline(text, 3);
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
// packages/utils/src/lib/reports/md/image.ts
|
|
1022
|
-
function image(src, alt) {
|
|
1023
|
-
return ``;
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
// packages/utils/src/lib/reports/md/link.ts
|
|
1027
|
-
function link2(href, text) {
|
|
1028
|
-
return `[${text || href}](${href})`;
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
// packages/utils/src/lib/reports/md/list.ts
|
|
1032
|
-
function li(text, order = "unordered") {
|
|
1033
|
-
const style2 = order === "unordered" ? "-" : "- [ ]";
|
|
1034
|
-
return `${style2} ${text}`;
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
// packages/utils/src/lib/reports/md/paragraphs.ts
|
|
1038
|
-
function paragraphs(...sections) {
|
|
1039
|
-
return sections.filter(Boolean).join("\n\n");
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
// packages/utils/src/lib/reports/md/table.ts
|
|
1043
|
-
var alignString = /* @__PURE__ */ new Map([
|
|
1044
|
-
["l", ":--"],
|
|
1045
|
-
["c", ":--:"],
|
|
1046
|
-
["r", "--:"]
|
|
1047
|
-
]);
|
|
1048
|
-
function tableMd(data, align) {
|
|
1049
|
-
if (data.length === 0) {
|
|
1050
|
-
throw new Error("Data can't be empty");
|
|
1051
|
-
}
|
|
1052
|
-
const alignmentSetting = align ?? data[0]?.map(() => "c");
|
|
1053
|
-
const tableContent = data.map((arr) => `|${arr.join("|")}|`);
|
|
1054
|
-
const alignmentRow = `|${alignmentSetting?.map((s) => alignString.get(s)).join("|")}|`;
|
|
1055
|
-
return tableContent[0] + NEW_LINE + alignmentRow + NEW_LINE + tableContent.slice(1).join(NEW_LINE);
|
|
1056
|
-
}
|
|
1057
|
-
function tableHtml(data) {
|
|
1058
|
-
if (data.length === 0) {
|
|
1059
|
-
throw new Error("Data can't be empty");
|
|
1060
|
-
}
|
|
1061
|
-
const tableContent = data.map((arr, index) => {
|
|
1062
|
-
if (index === 0) {
|
|
1063
|
-
const headerRow = arr.map((s) => `<th>${s}</th>`).join("");
|
|
1064
|
-
return `<tr>${headerRow}</tr>`;
|
|
1065
|
-
}
|
|
1066
|
-
const row = arr.map((s) => `<td>${s}</td>`).join("");
|
|
1067
|
-
return `<tr>${row}</tr>`;
|
|
1068
|
-
});
|
|
1069
|
-
return `<table>${tableContent.join("")}</table>`;
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
// packages/utils/src/lib/reports/utils.ts
|
|
1073
|
-
function formatReportScore(score) {
|
|
1074
|
-
return Math.round(score * 100).toString();
|
|
1403
|
+
// packages/utils/src/lib/reports/utils.ts
|
|
1404
|
+
var { image: image2, bold: boldMd } = md;
|
|
1405
|
+
function formatReportScore(score) {
|
|
1406
|
+
return Math.round(score * 100).toString();
|
|
1075
1407
|
}
|
|
1076
1408
|
function formatScoreWithColor(score, options) {
|
|
1077
|
-
const styledNumber = options?.skipBold ? formatReportScore(score) :
|
|
1078
|
-
return `${
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
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}"
|
|
1086
1422
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
function getSquaredScoreMarker(score) {
|
|
1423
|
+
};
|
|
1424
|
+
function scoreMarker(score, markerType = "circle") {
|
|
1090
1425
|
if (score >= SCORE_COLOR_RANGE.GREEN_MIN) {
|
|
1091
|
-
return
|
|
1426
|
+
return MARKERS[markerType].green;
|
|
1092
1427
|
}
|
|
1093
1428
|
if (score >= SCORE_COLOR_RANGE.YELLOW_MIN) {
|
|
1094
|
-
return
|
|
1429
|
+
return MARKERS[markerType].yellow;
|
|
1095
1430
|
}
|
|
1096
|
-
return
|
|
1431
|
+
return MARKERS[markerType].red;
|
|
1097
1432
|
}
|
|
1098
1433
|
function getDiffMarker(diff) {
|
|
1099
1434
|
if (diff > 0) {
|
|
@@ -1109,7 +1444,7 @@ function colorByScoreDiff(text, diff) {
|
|
|
1109
1444
|
return shieldsBadge(text, color);
|
|
1110
1445
|
}
|
|
1111
1446
|
function shieldsBadge(text, color) {
|
|
1112
|
-
return
|
|
1447
|
+
return image2(
|
|
1113
1448
|
`https://img.shields.io/badge/${encodeURIComponent(text)}-${color}`,
|
|
1114
1449
|
text
|
|
1115
1450
|
);
|
|
@@ -1119,7 +1454,7 @@ function formatDiffNumber(diff) {
|
|
|
1119
1454
|
const sign = diff < 0 ? "\u2212" : "+";
|
|
1120
1455
|
return `${sign}${number}`;
|
|
1121
1456
|
}
|
|
1122
|
-
function
|
|
1457
|
+
function severityMarker(severity) {
|
|
1123
1458
|
if (severity === "error") {
|
|
1124
1459
|
return "\u{1F6A8}";
|
|
1125
1460
|
}
|
|
@@ -1310,13 +1645,13 @@ function executeProcess(cfg) {
|
|
|
1310
1645
|
process2.on("error", (err) => {
|
|
1311
1646
|
stderr += err.toString();
|
|
1312
1647
|
});
|
|
1313
|
-
process2.on("close", (
|
|
1648
|
+
process2.on("close", (code3) => {
|
|
1314
1649
|
const timings = { date, duration: calcDuration(start) };
|
|
1315
|
-
if (
|
|
1650
|
+
if (code3 === 0 || ignoreExitCode) {
|
|
1316
1651
|
onComplete?.();
|
|
1317
|
-
resolve({ code, stdout, stderr, ...timings });
|
|
1652
|
+
resolve({ code: code3, stdout, stderr, ...timings });
|
|
1318
1653
|
} else {
|
|
1319
|
-
const errorMsg = new ProcessError({ code, stdout, stderr, ...timings });
|
|
1654
|
+
const errorMsg = new ProcessError({ code: code3, stdout, stderr, ...timings });
|
|
1320
1655
|
onError?.(errorMsg);
|
|
1321
1656
|
reject(errorMsg);
|
|
1322
1657
|
}
|
|
@@ -1332,123 +1667,9 @@ function filterItemRefsBy(items, refFilterFn) {
|
|
|
1332
1667
|
})).filter((item) => item.refs.length);
|
|
1333
1668
|
}
|
|
1334
1669
|
|
|
1335
|
-
// packages/utils/src/lib/git.ts
|
|
1670
|
+
// packages/utils/src/lib/git/git.ts
|
|
1336
1671
|
import { isAbsolute, join as join3, relative } from "node:path";
|
|
1337
1672
|
import { simpleGit } from "simple-git";
|
|
1338
|
-
|
|
1339
|
-
// packages/utils/src/lib/transform.ts
|
|
1340
|
-
import { platform } from "node:os";
|
|
1341
|
-
function toArray(val) {
|
|
1342
|
-
return Array.isArray(val) ? val : [val];
|
|
1343
|
-
}
|
|
1344
|
-
function objectToKeys(obj) {
|
|
1345
|
-
return Object.keys(obj);
|
|
1346
|
-
}
|
|
1347
|
-
function objectToEntries(obj) {
|
|
1348
|
-
return Object.entries(obj);
|
|
1349
|
-
}
|
|
1350
|
-
function objectFromEntries(entries) {
|
|
1351
|
-
return Object.fromEntries(entries);
|
|
1352
|
-
}
|
|
1353
|
-
function countOccurrences(values) {
|
|
1354
|
-
return values.reduce(
|
|
1355
|
-
(acc, value) => ({ ...acc, [value]: (acc[value] ?? 0) + 1 }),
|
|
1356
|
-
{}
|
|
1357
|
-
);
|
|
1358
|
-
}
|
|
1359
|
-
function distinct(array) {
|
|
1360
|
-
return [...new Set(array)];
|
|
1361
|
-
}
|
|
1362
|
-
function deepClone(obj) {
|
|
1363
|
-
return obj == null || typeof obj !== "object" ? obj : structuredClone(obj);
|
|
1364
|
-
}
|
|
1365
|
-
function factorOf(items, filterFn) {
|
|
1366
|
-
const itemCount = items.length;
|
|
1367
|
-
if (!itemCount) {
|
|
1368
|
-
return 1;
|
|
1369
|
-
}
|
|
1370
|
-
const filterCount = items.filter(filterFn).length;
|
|
1371
|
-
return filterCount === 0 ? 1 : (itemCount - filterCount) / itemCount;
|
|
1372
|
-
}
|
|
1373
|
-
function objectToCliArgs(params) {
|
|
1374
|
-
if (!params) {
|
|
1375
|
-
return [];
|
|
1376
|
-
}
|
|
1377
|
-
return Object.entries(params).flatMap(([key, value]) => {
|
|
1378
|
-
if (key === "_") {
|
|
1379
|
-
return Array.isArray(value) ? value : [`${value}`];
|
|
1380
|
-
}
|
|
1381
|
-
const prefix = key.length === 1 ? "-" : "--";
|
|
1382
|
-
if (Array.isArray(value)) {
|
|
1383
|
-
return value.map((v) => `${prefix}${key}="${v}"`);
|
|
1384
|
-
}
|
|
1385
|
-
if (Array.isArray(value)) {
|
|
1386
|
-
return value.map((v) => `${prefix}${key}="${v}"`);
|
|
1387
|
-
}
|
|
1388
|
-
if (typeof value === "string") {
|
|
1389
|
-
return [`${prefix}${key}="${value}"`];
|
|
1390
|
-
}
|
|
1391
|
-
if (typeof value === "number") {
|
|
1392
|
-
return [`${prefix}${key}=${value}`];
|
|
1393
|
-
}
|
|
1394
|
-
if (typeof value === "boolean") {
|
|
1395
|
-
return [`${prefix}${value ? "" : "no-"}${key}`];
|
|
1396
|
-
}
|
|
1397
|
-
throw new Error(`Unsupported type ${typeof value} for key ${key}`);
|
|
1398
|
-
});
|
|
1399
|
-
}
|
|
1400
|
-
function toUnixPath(path) {
|
|
1401
|
-
return path.replace(/\\/g, "/");
|
|
1402
|
-
}
|
|
1403
|
-
function toUnixNewlines(text) {
|
|
1404
|
-
return platform() === "win32" ? text.replace(/\r\n/g, "\n") : text;
|
|
1405
|
-
}
|
|
1406
|
-
function fromJsonLines(jsonLines) {
|
|
1407
|
-
const unifiedNewLines = toUnixNewlines(jsonLines).trim();
|
|
1408
|
-
return JSON.parse(`[${unifiedNewLines.split("\n").join(",")}]`);
|
|
1409
|
-
}
|
|
1410
|
-
function toJsonLines(json) {
|
|
1411
|
-
return json.map((item) => JSON.stringify(item)).join("\n");
|
|
1412
|
-
}
|
|
1413
|
-
function capitalize(text) {
|
|
1414
|
-
return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
|
|
1415
|
-
1
|
|
1416
|
-
)}`;
|
|
1417
|
-
}
|
|
1418
|
-
function apostrophize(text, upperCase) {
|
|
1419
|
-
const lastCharMatch = text.match(/(\w)\W*$/);
|
|
1420
|
-
const lastChar = lastCharMatch?.[1] ?? "";
|
|
1421
|
-
return `${text}'${lastChar.toLocaleLowerCase() === "s" ? "" : upperCase ? "S" : "s"}`;
|
|
1422
|
-
}
|
|
1423
|
-
function toNumberPrecision(value, decimalPlaces) {
|
|
1424
|
-
return Number(
|
|
1425
|
-
`${Math.round(
|
|
1426
|
-
Number.parseFloat(`${value}e${decimalPlaces}`)
|
|
1427
|
-
)}e-${decimalPlaces}`
|
|
1428
|
-
);
|
|
1429
|
-
}
|
|
1430
|
-
function toOrdinal(value) {
|
|
1431
|
-
if (value % 10 === 1 && value % 100 !== 11) {
|
|
1432
|
-
return `${value}st`;
|
|
1433
|
-
}
|
|
1434
|
-
if (value % 10 === 2 && value % 100 !== 12) {
|
|
1435
|
-
return `${value}nd`;
|
|
1436
|
-
}
|
|
1437
|
-
if (value % 10 === 3 && value % 100 !== 13) {
|
|
1438
|
-
return `${value}rd`;
|
|
1439
|
-
}
|
|
1440
|
-
return `${value}th`;
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
// packages/utils/src/lib/git.ts
|
|
1444
|
-
async function getLatestCommit(git = simpleGit()) {
|
|
1445
|
-
const log2 = await git.log({
|
|
1446
|
-
maxCount: 1,
|
|
1447
|
-
// git log -1 --pretty=format:"%H %s %an %aI" - See: https://git-scm.com/docs/pretty-formats
|
|
1448
|
-
format: { hash: "%H", message: "%s", author: "%an", date: "%aI" }
|
|
1449
|
-
});
|
|
1450
|
-
return commitSchema.parse(log2.latest);
|
|
1451
|
-
}
|
|
1452
1673
|
function getGitRoot(git = simpleGit()) {
|
|
1453
1674
|
return git.revparse("--show-toplevel");
|
|
1454
1675
|
}
|
|
@@ -1499,11 +1720,6 @@ async function guardAgainstLocalChanges(git = simpleGit()) {
|
|
|
1499
1720
|
throw new GitStatusError(status);
|
|
1500
1721
|
}
|
|
1501
1722
|
}
|
|
1502
|
-
async function getCurrentBranchOrTag(git = simpleGit()) {
|
|
1503
|
-
return await git.branch().then((r) => r.current) || // If no current branch, try to get the tag
|
|
1504
|
-
// @TODO use simple git
|
|
1505
|
-
await git.raw(["describe", "--tags", "--exact-match"]).then((out) => out.trim());
|
|
1506
|
-
}
|
|
1507
1723
|
async function safeCheckout(branchOrHash, forceCleanStatus = false, git = simpleGit()) {
|
|
1508
1724
|
if (forceCleanStatus) {
|
|
1509
1725
|
await git.raw(["reset", "--hard"]);
|
|
@@ -1514,6 +1730,120 @@ async function safeCheckout(branchOrHash, forceCleanStatus = false, git = simple
|
|
|
1514
1730
|
await git.checkout(branchOrHash);
|
|
1515
1731
|
}
|
|
1516
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);
|
|
1741
|
+
}
|
|
1742
|
+
if (semverString.includes("@")) {
|
|
1743
|
+
return semverString.split("@").at(-1) ?? "";
|
|
1744
|
+
}
|
|
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);
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
// packages/utils/src/lib/git/git.commits-and-tags.ts
|
|
1755
|
+
async function getLatestCommit(git = simpleGit2()) {
|
|
1756
|
+
const log2 = await git.log({
|
|
1757
|
+
maxCount: 1,
|
|
1758
|
+
// git log -1 --pretty=format:"%H %s %an %aI" - See: https://git-scm.com/docs/pretty-formats
|
|
1759
|
+
format: { hash: "%H", message: "%s", author: "%an", date: "%aI" }
|
|
1760
|
+
});
|
|
1761
|
+
return commitSchema.parse(log2.latest);
|
|
1762
|
+
}
|
|
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());
|
|
1767
|
+
}
|
|
1768
|
+
function validateFilter({ from, to }) {
|
|
1769
|
+
if (to && !from) {
|
|
1770
|
+
throw new Error(
|
|
1771
|
+
`filter needs the "from" option defined to accept the "to" option.
|
|
1772
|
+
`
|
|
1773
|
+
);
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
function filterLogs(allTags, opt) {
|
|
1777
|
+
if (!opt) {
|
|
1778
|
+
return allTags;
|
|
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);
|
|
1792
|
+
}
|
|
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);
|
|
1843
|
+
}
|
|
1844
|
+
return [...logs.all];
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1517
1847
|
// packages/utils/src/lib/group-by-status.ts
|
|
1518
1848
|
function groupByStatus(results) {
|
|
1519
1849
|
return results.reduce(
|
|
@@ -1589,44 +1919,65 @@ function listAuditsFromAllPlugins(report) {
|
|
|
1589
1919
|
);
|
|
1590
1920
|
}
|
|
1591
1921
|
|
|
1592
|
-
// packages/utils/src/lib/reports/
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
`${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)
|
|
1604
1933
|
);
|
|
1605
1934
|
}
|
|
1606
|
-
function
|
|
1607
|
-
|
|
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 "";
|
|
1608
1951
|
}
|
|
1609
|
-
|
|
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) {
|
|
1610
1956
|
const { categories, plugins } = report;
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
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 "";
|
|
1620
1972
|
}
|
|
1621
|
-
function
|
|
1973
|
+
function categoriesDetailsSection(report) {
|
|
1622
1974
|
const { categories, plugins } = report;
|
|
1623
|
-
const categoryDetails = categories.
|
|
1624
|
-
const categoryTitle =
|
|
1625
|
-
const categoryScore = `${
|
|
1975
|
+
const categoryDetails = categories.flatMap((category) => {
|
|
1976
|
+
const categoryTitle = h32(category.title);
|
|
1977
|
+
const categoryScore = `${scoreMarker(
|
|
1626
1978
|
category.score
|
|
1627
|
-
)}
|
|
1628
|
-
const
|
|
1629
|
-
const categoryMDItems = category.refs.reduce((refAcc, ref) => {
|
|
1979
|
+
)}${SPACE}Score: ${boldMd2(formatReportScore(category.score))}`;
|
|
1980
|
+
const categoryMDItems = category.refs.map((ref) => {
|
|
1630
1981
|
if (ref.type === "group") {
|
|
1631
1982
|
const group = getSortableGroupByRef(ref, plugins);
|
|
1632
1983
|
const groupAudits = group.refs.map(
|
|
@@ -1636,151 +1987,240 @@ function reportToCategoriesSection(report) {
|
|
|
1636
1987
|
)
|
|
1637
1988
|
);
|
|
1638
1989
|
const pluginTitle = getPluginNameFromSlug(ref.plugin, plugins);
|
|
1639
|
-
|
|
1640
|
-
group,
|
|
1641
|
-
groupAudits,
|
|
1642
|
-
pluginTitle
|
|
1643
|
-
);
|
|
1644
|
-
return refAcc + mdGroupItem + NEW_LINE;
|
|
1990
|
+
return categoryGroupItem(group, groupAudits, pluginTitle);
|
|
1645
1991
|
} else {
|
|
1646
1992
|
const audit = getSortableAuditByRef(ref, plugins);
|
|
1647
1993
|
const pluginTitle = getPluginNameFromSlug(ref.plugin, plugins);
|
|
1648
|
-
|
|
1649
|
-
return refAcc + mdAuditItem + NEW_LINE;
|
|
1994
|
+
return categoryRef(audit, pluginTitle);
|
|
1650
1995
|
}
|
|
1651
|
-
}
|
|
1652
|
-
return
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
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
|
|
1660
2010
|
);
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
2011
|
+
const marker = scoreMarker(score, "square");
|
|
2012
|
+
return li2(
|
|
2013
|
+
`${marker}${SPACE}${auditTitleAsLink}${SPACE}(_${pluginTitle}_) - ${boldMd2(
|
|
2014
|
+
(displayValue || value).toString()
|
|
2015
|
+
)}`
|
|
1665
2016
|
);
|
|
1666
2017
|
}
|
|
1667
|
-
function
|
|
1668
|
-
const
|
|
1669
|
-
|
|
1670
|
-
`${getRoundScoreMarker(groupScore)} ${group.title} (_${pluginTitle}_)`
|
|
2018
|
+
function categoryGroupItem({ score = 0, title }, groupAudits, pluginTitle) {
|
|
2019
|
+
const groupTitle = li2(
|
|
2020
|
+
`${scoreMarker(score)}${SPACE}${title}${SPACE}(_${pluginTitle}_)`
|
|
1671
2021
|
);
|
|
1672
|
-
const auditTitles = groupAudits.
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
const auditsData = plugin.audits.reduce((auditAcc, audit) => {
|
|
1688
|
-
const auditTitle = `${audit.title} (${getPluginNameFromSlug(
|
|
1689
|
-
plugin.slug,
|
|
1690
|
-
report.plugins
|
|
1691
|
-
)})`;
|
|
1692
|
-
return auditAcc + h3(auditTitle) + NEW_LINE + NEW_LINE + reportToDetailsSection(audit) + NEW_LINE + NEW_LINE + getDocsAndDescription(audit);
|
|
1693
|
-
}, "");
|
|
1694
|
-
return pluginAcc + auditsData;
|
|
1695
|
-
}, "");
|
|
1696
|
-
return h2("\u{1F6E1}\uFE0F Audits") + NEW_LINE + NEW_LINE + auditsSection;
|
|
1697
|
-
}
|
|
1698
|
-
function reportToDetailsSection(audit) {
|
|
1699
|
-
const detailsTitle = `${getSquaredScoreMarker(audit.score)} ${getAuditResult(
|
|
1700
|
-
audit,
|
|
1701
|
-
true
|
|
1702
|
-
)} (score: ${formatReportScore(audit.score)})`;
|
|
1703
|
-
if (!audit.details?.issues.length) {
|
|
1704
|
-
return detailsTitle;
|
|
1705
|
-
}
|
|
1706
|
-
const detailsTableData = [
|
|
1707
|
-
detailsTableHeaders,
|
|
1708
|
-
...audit.details.issues.map((issue) => {
|
|
1709
|
-
const severity = `${getSeverityIcon(issue.severity)} <i>${issue.severity}</i>`;
|
|
1710
|
-
const message = issue.message;
|
|
1711
|
-
if (!issue.source) {
|
|
1712
|
-
return [severity, message, "", ""];
|
|
1713
|
-
}
|
|
1714
|
-
const file = `<code>${issue.source.file}</code>`;
|
|
1715
|
-
if (!issue.source.position) {
|
|
1716
|
-
return [severity, message, file, ""];
|
|
1717
|
-
}
|
|
1718
|
-
const { startLine, endLine } = issue.source.position;
|
|
1719
|
-
const line = `${startLine || ""}${endLine && startLine !== endLine ? `-${endLine}` : ""}`;
|
|
1720
|
-
return [severity, message, file, line];
|
|
1721
|
-
})
|
|
1722
|
-
];
|
|
1723
|
-
const detailsTable = `<h4>Issues</h4>${tableHtml(detailsTableData)}`;
|
|
1724
|
-
return details(detailsTitle, detailsTable);
|
|
1725
|
-
}
|
|
1726
|
-
function reportToAboutSection(report) {
|
|
1727
|
-
const date = formatDate(/* @__PURE__ */ new Date());
|
|
1728
|
-
const { duration, version, commit, plugins, categories } = report;
|
|
1729
|
-
const commitInfo = commit ? `${commit.message} (${commit.hash})` : "N/A";
|
|
1730
|
-
const reportMetaTable = [
|
|
1731
|
-
reportMetaTableHeaders,
|
|
1732
|
-
[
|
|
1733
|
-
commitInfo,
|
|
1734
|
-
style(version || "", ["c"]),
|
|
1735
|
-
formatDuration(duration),
|
|
1736
|
-
plugins.length.toString(),
|
|
1737
|
-
categories.length.toString(),
|
|
1738
|
-
plugins.reduce((acc, { audits }) => acc + audits.length, 0).toString()
|
|
1739
|
-
]
|
|
1740
|
-
];
|
|
1741
|
-
const pluginMetaTable = [
|
|
1742
|
-
pluginMetaTableHeaders,
|
|
1743
|
-
...plugins.map((plugin) => [
|
|
1744
|
-
plugin.title,
|
|
1745
|
-
plugin.audits.length.toString(),
|
|
1746
|
-
style(plugin.version || "", ["c"]),
|
|
1747
|
-
formatDuration(plugin.duration)
|
|
1748
|
-
])
|
|
1749
|
-
];
|
|
1750
|
-
return (
|
|
1751
|
-
// eslint-disable-next-line prefer-template
|
|
1752
|
-
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
|
+
}
|
|
1753
2037
|
);
|
|
2038
|
+
return lines3(groupTitle, ...auditTitles);
|
|
1754
2039
|
}
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
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
|
|
1758
2048
|
}) {
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
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 "";
|
|
1771
2067
|
}
|
|
1772
|
-
|
|
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
|
+
);
|
|
1773
2101
|
}
|
|
1774
|
-
function
|
|
1775
|
-
|
|
1776
|
-
|
|
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
|
+
};
|
|
2164
|
+
}
|
|
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
|
+
};
|
|
1777
2206
|
}
|
|
1778
2207
|
|
|
1779
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;
|
|
1780
2220
|
var MAX_ROWS = 100;
|
|
1781
2221
|
function generateMdReportsDiff(diff) {
|
|
1782
|
-
return
|
|
1783
|
-
formatDiffHeaderSection(diff),
|
|
2222
|
+
return lines5(
|
|
2223
|
+
section5(formatDiffHeaderSection(diff)),
|
|
1784
2224
|
formatDiffCategoriesSection(diff),
|
|
1785
2225
|
formatDiffGroupsSection(diff),
|
|
1786
2226
|
formatDiffAuditsSection(diff)
|
|
@@ -1788,12 +2228,12 @@ function generateMdReportsDiff(diff) {
|
|
|
1788
2228
|
}
|
|
1789
2229
|
function formatDiffHeaderSection(diff) {
|
|
1790
2230
|
const outcomeTexts = {
|
|
1791
|
-
positive: `\u{1F973} Code PushUp report has ${
|
|
1792
|
-
negative: `\u{1F61F} Code PushUp report has ${
|
|
1793
|
-
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(
|
|
1794
2234
|
"improvements and regressions"
|
|
1795
2235
|
)}`,
|
|
1796
|
-
unchanged: `\u{1F610} Code PushUp report is ${
|
|
2236
|
+
unchanged: `\u{1F610} Code PushUp report is ${boldMd3("unchanged")}`
|
|
1797
2237
|
};
|
|
1798
2238
|
const outcome = mergeDiffOutcomes(
|
|
1799
2239
|
changesToDiffOutcomes([
|
|
@@ -1803,8 +2243,8 @@ function formatDiffHeaderSection(diff) {
|
|
|
1803
2243
|
])
|
|
1804
2244
|
);
|
|
1805
2245
|
const styleCommits = (commits) => `compared target commit ${commits.after.hash} with source commit ${commits.before.hash}`;
|
|
1806
|
-
return
|
|
1807
|
-
|
|
2246
|
+
return lines5(
|
|
2247
|
+
h13("Code PushUp"),
|
|
1808
2248
|
diff.commits ? `${outcomeTexts[outcome]} \u2013 ${styleCommits(diff.commits)}.` : `${outcomeTexts[outcome]}.`
|
|
1809
2249
|
);
|
|
1810
2250
|
}
|
|
@@ -1815,102 +2255,104 @@ function formatDiffCategoriesSection(diff) {
|
|
|
1815
2255
|
if (categoriesCount === 0) {
|
|
1816
2256
|
return "";
|
|
1817
2257
|
}
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
formatScoreWithColor(category.scores.
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
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."))
|
|
1850
2294
|
);
|
|
1851
2295
|
}
|
|
1852
2296
|
function formatDiffGroupsSection(diff) {
|
|
1853
2297
|
if (diff.groups.changed.length + diff.groups.unchanged.length === 0) {
|
|
1854
2298
|
return "";
|
|
1855
2299
|
}
|
|
1856
|
-
return
|
|
1857
|
-
|
|
2300
|
+
return lines5(
|
|
2301
|
+
h24("\u{1F5C3}\uFE0F Groups"),
|
|
1858
2302
|
formatGroupsOrAuditsDetails("group", diff.groups, {
|
|
1859
|
-
|
|
1860
|
-
"\u{1F50C} Plugin",
|
|
1861
|
-
"\u{1F5C3}\uFE0F Group",
|
|
1862
|
-
"\u2B50 Current score",
|
|
1863
|
-
"\u2B50 Previous score",
|
|
1864
|
-
"\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" }
|
|
1865
2309
|
],
|
|
1866
|
-
rows: sortChanges(diff.groups.changed).map((group) =>
|
|
1867
|
-
formatTitle(group.plugin),
|
|
1868
|
-
formatTitle(group),
|
|
1869
|
-
formatScoreWithColor(group.scores.after),
|
|
1870
|
-
formatScoreWithColor(group.scores.before, { skipBold: true }),
|
|
1871
|
-
formatScoreChange(group.scores.diff)
|
|
1872
|
-
|
|
1873
|
-
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
|
+
}))
|
|
1874
2317
|
})
|
|
1875
2318
|
);
|
|
1876
2319
|
}
|
|
1877
2320
|
function formatDiffAuditsSection(diff) {
|
|
1878
|
-
return
|
|
1879
|
-
|
|
2321
|
+
return lines5(
|
|
2322
|
+
h24("\u{1F6E1}\uFE0F Audits"),
|
|
1880
2323
|
formatGroupsOrAuditsDetails("audit", diff.audits, {
|
|
1881
|
-
|
|
1882
|
-
"\u{1F50C} Plugin",
|
|
1883
|
-
"\u{1F6E1}\uFE0F Audit",
|
|
1884
|
-
"\u{1F4CF} Current value",
|
|
1885
|
-
"\u{1F4CF} Previous value",
|
|
1886
|
-
"\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" }
|
|
1887
2330
|
],
|
|
1888
|
-
rows: sortChanges(diff.audits.changed).map((audit) =>
|
|
1889
|
-
formatTitle(audit.plugin),
|
|
1890
|
-
formatTitle(audit),
|
|
1891
|
-
`${
|
|
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(
|
|
1892
2335
|
audit.displayValues.after || audit.values.after.toString()
|
|
1893
2336
|
)}`,
|
|
1894
|
-
`${
|
|
1895
|
-
formatValueChange(audit)
|
|
1896
|
-
|
|
1897
|
-
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
|
+
}))
|
|
1898
2340
|
})
|
|
1899
2341
|
);
|
|
1900
2342
|
}
|
|
1901
|
-
function formatGroupsOrAuditsDetails(token, { changed, unchanged },
|
|
1902
|
-
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(
|
|
1903
2345
|
summarizeDiffOutcomes(changesToDiffOutcomes(changed), token),
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
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(
|
|
1910
2353
|
`Only the ${MAX_ROWS} most affected ${pluralize(
|
|
1911
2354
|
token
|
|
1912
|
-
)} are listed above for brevity
|
|
1913
|
-
["i"]
|
|
2355
|
+
)} are listed above for brevity.`
|
|
1914
2356
|
),
|
|
1915
2357
|
unchanged.length > 0 && summarizeUnchanged(token, { changed, unchanged })
|
|
1916
2358
|
)
|
|
@@ -1931,11 +2373,13 @@ function formatValueChange({
|
|
|
1931
2373
|
return colorByScoreDiff(`${marker} ${text}`, scores.diff);
|
|
1932
2374
|
}
|
|
1933
2375
|
function summarizeUnchanged(token, { changed, unchanged }) {
|
|
1934
|
-
return
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
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
|
+
);
|
|
1939
2383
|
}
|
|
1940
2384
|
function summarizeDiffOutcomes(outcomes, token) {
|
|
1941
2385
|
return objectToEntries(countDiffOutcomes(outcomes)).filter(
|
|
@@ -1960,7 +2404,7 @@ function formatTitle({
|
|
|
1960
2404
|
docsUrl
|
|
1961
2405
|
}) {
|
|
1962
2406
|
if (docsUrl) {
|
|
1963
|
-
return
|
|
2407
|
+
return link7(docsUrl, title);
|
|
1964
2408
|
}
|
|
1965
2409
|
return title;
|
|
1966
2410
|
}
|
|
@@ -2011,7 +2455,7 @@ function log(msg = "") {
|
|
|
2011
2455
|
}
|
|
2012
2456
|
function logStdoutSummary(report) {
|
|
2013
2457
|
const printCategories = report.categories.length > 0;
|
|
2014
|
-
log(
|
|
2458
|
+
log(reportToHeaderSection(report));
|
|
2015
2459
|
log();
|
|
2016
2460
|
logPlugins(report);
|
|
2017
2461
|
if (printCategories) {
|
|
@@ -2020,7 +2464,7 @@ function logStdoutSummary(report) {
|
|
|
2020
2464
|
log(`${FOOTER_PREFIX} ${CODE_PUSHUP_DOMAIN}`);
|
|
2021
2465
|
log();
|
|
2022
2466
|
}
|
|
2023
|
-
function
|
|
2467
|
+
function reportToHeaderSection(report) {
|
|
2024
2468
|
const { packageName, version } = report;
|
|
2025
2469
|
return `${chalk4.bold(reportHeadlineText)} - ${packageName}@${version}`;
|
|
2026
2470
|
}
|
|
@@ -2060,16 +2504,16 @@ function logCategories({ categories, plugins }) {
|
|
|
2060
2504
|
applyScoreColor({ score }),
|
|
2061
2505
|
countCategoryAudits(refs, plugins)
|
|
2062
2506
|
]);
|
|
2063
|
-
const
|
|
2064
|
-
|
|
2065
|
-
|
|
2507
|
+
const table5 = ui().table();
|
|
2508
|
+
table5.columnWidths([TERMINAL_WIDTH - 9 - 10 - 4, 9, 10]);
|
|
2509
|
+
table5.head(
|
|
2066
2510
|
reportRawOverviewTableHeaders.map((heading, idx) => ({
|
|
2067
2511
|
content: chalk4.cyan(heading),
|
|
2068
2512
|
hAlign: hAlign(idx)
|
|
2069
2513
|
}))
|
|
2070
2514
|
);
|
|
2071
2515
|
rows.forEach(
|
|
2072
|
-
(row) =>
|
|
2516
|
+
(row) => table5.row(
|
|
2073
2517
|
row.map((content, idx) => ({
|
|
2074
2518
|
content: content.toString(),
|
|
2075
2519
|
hAlign: hAlign(idx)
|
|
@@ -2078,19 +2522,19 @@ function logCategories({ categories, plugins }) {
|
|
|
2078
2522
|
);
|
|
2079
2523
|
log(chalk4.magentaBright.bold("Categories"));
|
|
2080
2524
|
log();
|
|
2081
|
-
|
|
2525
|
+
table5.render();
|
|
2082
2526
|
log();
|
|
2083
2527
|
}
|
|
2084
2528
|
function applyScoreColor({ score, text }) {
|
|
2085
2529
|
const formattedScore = text ?? formatReportScore(score);
|
|
2086
|
-
const
|
|
2530
|
+
const style = text ? chalk4 : chalk4.bold;
|
|
2087
2531
|
if (score >= SCORE_COLOR_RANGE.GREEN_MIN) {
|
|
2088
|
-
return
|
|
2532
|
+
return style.green(formattedScore);
|
|
2089
2533
|
}
|
|
2090
2534
|
if (score >= SCORE_COLOR_RANGE.YELLOW_MIN) {
|
|
2091
|
-
return
|
|
2535
|
+
return style.yellow(formattedScore);
|
|
2092
2536
|
}
|
|
2093
|
-
return
|
|
2537
|
+
return style.red(formattedScore);
|
|
2094
2538
|
}
|
|
2095
2539
|
|
|
2096
2540
|
// packages/utils/src/lib/reports/scoring.ts
|
|
@@ -2252,8 +2696,11 @@ var verboseUtils = (verbose = false) => ({
|
|
|
2252
2696
|
export {
|
|
2253
2697
|
CODE_PUSHUP_DOMAIN,
|
|
2254
2698
|
FOOTER_PREFIX,
|
|
2699
|
+
NEW_LINE,
|
|
2255
2700
|
ProcessError,
|
|
2256
2701
|
README_LINK,
|
|
2702
|
+
SPACE,
|
|
2703
|
+
TAB,
|
|
2257
2704
|
TERMINAL_WIDTH,
|
|
2258
2705
|
apostrophize,
|
|
2259
2706
|
calcDuration,
|
|
@@ -2279,14 +2726,19 @@ export {
|
|
|
2279
2726
|
generateMdReportsDiff,
|
|
2280
2727
|
getCurrentBranchOrTag,
|
|
2281
2728
|
getGitRoot,
|
|
2729
|
+
getHashFromTag,
|
|
2730
|
+
getHashes,
|
|
2282
2731
|
getLatestCommit,
|
|
2283
2732
|
getProgressBar,
|
|
2733
|
+
getSemverTags,
|
|
2284
2734
|
groupByStatus,
|
|
2285
2735
|
guardAgainstLocalChanges,
|
|
2736
|
+
html,
|
|
2286
2737
|
importEsmModule,
|
|
2287
2738
|
isPromiseFulfilledResult,
|
|
2288
2739
|
isPromiseRejectedResult,
|
|
2289
|
-
|
|
2740
|
+
isSemver,
|
|
2741
|
+
link3 as link,
|
|
2290
2742
|
listAuditsFromAllPlugins,
|
|
2291
2743
|
listGroupsFromAllPlugins,
|
|
2292
2744
|
loadReport,
|
|
@@ -2294,6 +2746,8 @@ export {
|
|
|
2294
2746
|
logMultipleResults,
|
|
2295
2747
|
logStdoutSummary,
|
|
2296
2748
|
matchArrayItemsByKey,
|
|
2749
|
+
md,
|
|
2750
|
+
normalizeSemver,
|
|
2297
2751
|
objectFromEntries,
|
|
2298
2752
|
objectToCliArgs,
|
|
2299
2753
|
objectToEntries,
|
|
@@ -2308,6 +2762,7 @@ export {
|
|
|
2308
2762
|
scoreReport,
|
|
2309
2763
|
slugify,
|
|
2310
2764
|
sortReport,
|
|
2765
|
+
sortSemvers,
|
|
2311
2766
|
toArray,
|
|
2312
2767
|
toGitPath,
|
|
2313
2768
|
toJsonLines,
|