@code-pushup/utils 0.8.21 → 0.8.22
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 +75 -89
- package/package.json +1 -1
- package/src/lib/reports/constants.d.ts +1 -0
- package/src/lib/transform.d.ts +2 -1
package/index.js
CHANGED
|
@@ -558,7 +558,7 @@ function slugify(text) {
|
|
|
558
558
|
}
|
|
559
559
|
function pluralize(text) {
|
|
560
560
|
if (text.endsWith("y")) {
|
|
561
|
-
return text.slice(0, -1)
|
|
561
|
+
return `${text.slice(0, -1)}ies`;
|
|
562
562
|
}
|
|
563
563
|
if (text.endsWith("s")) {
|
|
564
564
|
return `${text}es`;
|
|
@@ -567,13 +567,14 @@ function pluralize(text) {
|
|
|
567
567
|
}
|
|
568
568
|
function formatBytes(bytes, decimals = 2) {
|
|
569
569
|
bytes = Math.max(bytes, 0);
|
|
570
|
-
if (!bytes)
|
|
570
|
+
if (!bytes) {
|
|
571
571
|
return "0 B";
|
|
572
|
+
}
|
|
572
573
|
const k = 1024;
|
|
573
574
|
const dm = decimals < 0 ? 0 : decimals;
|
|
574
575
|
const sizes = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
575
576
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
576
|
-
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
|
|
577
|
+
return `${Number.parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
|
|
577
578
|
}
|
|
578
579
|
function pluralizeToken(token, times = 0) {
|
|
579
580
|
return `${times} ${Math.abs(times) === 1 ? token : pluralize(token)}`;
|
|
@@ -629,7 +630,7 @@ function logMultipleResults(results, messagePrefix, succeededCallback, failedCal
|
|
|
629
630
|
}
|
|
630
631
|
}
|
|
631
632
|
function logPromiseResults(results, logMessage, callback) {
|
|
632
|
-
if (results.length) {
|
|
633
|
+
if (results.length > 0) {
|
|
633
634
|
if (results[0]?.status === "fulfilled") {
|
|
634
635
|
console.info(logMessage);
|
|
635
636
|
} else {
|
|
@@ -678,9 +679,8 @@ async function ensureDirectoryExists(baseDir) {
|
|
|
678
679
|
function logMultipleFileResults(fileResults, messagePrefix) {
|
|
679
680
|
const succeededCallback = (result) => {
|
|
680
681
|
const [fileName, size] = result.value;
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
);
|
|
682
|
+
const formattedSize = size ? ` (${chalk.gray(formatBytes(size))})` : "";
|
|
683
|
+
console.info(`- ${chalk.bold(fileName)}${formattedSize}`);
|
|
684
684
|
};
|
|
685
685
|
const failedCallback = (result) => {
|
|
686
686
|
console.warn(`- ${chalk.bold(result.reason)}`);
|
|
@@ -738,6 +738,7 @@ function findLineNumberInText(content, pattern) {
|
|
|
738
738
|
}
|
|
739
739
|
|
|
740
740
|
// packages/utils/src/lib/reports/constants.ts
|
|
741
|
+
var TERMINAL_WIDTH = 80;
|
|
741
742
|
var NEW_LINE = "\n";
|
|
742
743
|
var SCORE_COLOR_RANGE = {
|
|
743
744
|
GREEN_MIN: 0.9,
|
|
@@ -806,28 +807,20 @@ function getSeverityIcon(severity) {
|
|
|
806
807
|
return "\u2139\uFE0F";
|
|
807
808
|
}
|
|
808
809
|
function calcDuration(start, stop) {
|
|
809
|
-
stop
|
|
810
|
+
stop ??= performance.now();
|
|
810
811
|
return Math.floor(stop - start);
|
|
811
812
|
}
|
|
812
813
|
function countCategoryAudits(refs, plugins) {
|
|
813
814
|
const groupLookup = plugins.reduce(
|
|
814
815
|
(lookup, plugin) => {
|
|
815
|
-
if (
|
|
816
|
+
if (plugin.groups.length === 0) {
|
|
816
817
|
return lookup;
|
|
817
818
|
}
|
|
818
819
|
return {
|
|
819
820
|
...lookup,
|
|
820
|
-
[plugin.slug]:
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
return {
|
|
824
|
-
...groupLookup2,
|
|
825
|
-
[group.slug]: group
|
|
826
|
-
};
|
|
827
|
-
},
|
|
828
|
-
{}
|
|
829
|
-
)
|
|
830
|
-
}
|
|
821
|
+
[plugin.slug]: Object.fromEntries(
|
|
822
|
+
plugin.groups.map((group) => [group.slug, group])
|
|
823
|
+
)
|
|
831
824
|
};
|
|
832
825
|
},
|
|
833
826
|
{}
|
|
@@ -835,7 +828,7 @@ function countCategoryAudits(refs, plugins) {
|
|
|
835
828
|
return refs.reduce((acc, ref) => {
|
|
836
829
|
if (ref.type === "group") {
|
|
837
830
|
const groupRefs = groupLookup[ref.plugin]?.[ref.slug]?.refs;
|
|
838
|
-
return acc + (groupRefs?.length
|
|
831
|
+
return acc + (groupRefs?.length ?? 0);
|
|
839
832
|
}
|
|
840
833
|
return acc + 1;
|
|
841
834
|
}, 0);
|
|
@@ -941,7 +934,7 @@ function compareIssues(a, b) {
|
|
|
941
934
|
return 1;
|
|
942
935
|
}
|
|
943
936
|
if (a.source?.file !== b.source?.file) {
|
|
944
|
-
return a.source?.file.localeCompare(b.source?.file || "")
|
|
937
|
+
return a.source?.file.localeCompare(b.source?.file || "") ?? 0;
|
|
945
938
|
}
|
|
946
939
|
if (!a.source?.position && b.source?.position) {
|
|
947
940
|
return -1;
|
|
@@ -950,7 +943,7 @@ function compareIssues(a, b) {
|
|
|
950
943
|
return 1;
|
|
951
944
|
}
|
|
952
945
|
if (a.source?.position?.startLine !== b.source?.position?.startLine) {
|
|
953
|
-
return (a.source?.position?.startLine
|
|
946
|
+
return (a.source?.position?.startLine ?? 0) - (b.source?.position?.startLine ?? 0);
|
|
954
947
|
}
|
|
955
948
|
return 0;
|
|
956
949
|
}
|
|
@@ -968,12 +961,12 @@ var ProcessError = class extends Error {
|
|
|
968
961
|
}
|
|
969
962
|
};
|
|
970
963
|
function executeProcess(cfg) {
|
|
971
|
-
const { observer, cwd } = cfg;
|
|
972
|
-
const { onStdout, onError, onComplete } = observer
|
|
964
|
+
const { observer, cwd, command, args } = cfg;
|
|
965
|
+
const { onStdout, onError, onComplete } = observer ?? {};
|
|
973
966
|
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
974
967
|
const start = performance.now();
|
|
975
968
|
return new Promise((resolve, reject) => {
|
|
976
|
-
const process2 = spawn(
|
|
969
|
+
const process2 = spawn(command, args, { cwd, shell: true });
|
|
977
970
|
let stdout = "";
|
|
978
971
|
let stderr = "";
|
|
979
972
|
process2.stdout.on("data", (data) => {
|
|
@@ -1107,7 +1100,7 @@ function style(text, styles = ["b"]) {
|
|
|
1107
1100
|
|
|
1108
1101
|
// packages/utils/src/lib/reports/md/headline.ts
|
|
1109
1102
|
function headline(text, hierarchy = 1) {
|
|
1110
|
-
return `${
|
|
1103
|
+
return `${"#".repeat(hierarchy)} ${text}`;
|
|
1111
1104
|
}
|
|
1112
1105
|
function h2(text) {
|
|
1113
1106
|
return headline(text, 2);
|
|
@@ -1137,45 +1130,50 @@ function tableMd(data, align) {
|
|
|
1137
1130
|
if (data.length === 0) {
|
|
1138
1131
|
throw new Error("Data can't be empty");
|
|
1139
1132
|
}
|
|
1140
|
-
align
|
|
1141
|
-
const
|
|
1142
|
-
const secondRow =
|
|
1143
|
-
return
|
|
1133
|
+
align ??= data[0]?.map(() => "c");
|
|
1134
|
+
const tableContent = data.map((arr) => `|${arr.join("|")}|`);
|
|
1135
|
+
const secondRow = `|${align?.map((s) => alignString.get(s)).join("|")}|`;
|
|
1136
|
+
return tableContent.shift() + NEW_LINE + secondRow + NEW_LINE + tableContent.join(NEW_LINE);
|
|
1144
1137
|
}
|
|
1145
1138
|
function tableHtml(data) {
|
|
1146
1139
|
if (data.length === 0) {
|
|
1147
1140
|
throw new Error("Data can't be empty");
|
|
1148
1141
|
}
|
|
1149
|
-
const
|
|
1142
|
+
const tableContent = data.map((arr, index) => {
|
|
1150
1143
|
if (index === 0) {
|
|
1151
|
-
|
|
1144
|
+
const headerRow = arr.map((s) => `<th>${s}</th>`).join("");
|
|
1145
|
+
return `<tr>${headerRow}</tr>`;
|
|
1152
1146
|
}
|
|
1153
|
-
|
|
1147
|
+
const row = arr.map((s) => `<td>${s}</td>`).join("");
|
|
1148
|
+
return `<tr>${row}</tr>`;
|
|
1154
1149
|
});
|
|
1155
|
-
return
|
|
1150
|
+
return `<table>${tableContent.join("")}</table>`;
|
|
1156
1151
|
}
|
|
1157
1152
|
|
|
1158
1153
|
// packages/utils/src/lib/reports/generate-md-report.ts
|
|
1159
1154
|
function generateMdReport(report, commitData) {
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1155
|
+
return (
|
|
1156
|
+
// header section
|
|
1157
|
+
// eslint-disable-next-line prefer-template
|
|
1158
|
+
reportToHeaderSection() + NEW_LINE + // overview section
|
|
1159
|
+
reportToOverviewSection(report) + NEW_LINE + NEW_LINE + // categories section
|
|
1160
|
+
reportToCategoriesSection(report) + NEW_LINE + NEW_LINE + // audits section
|
|
1161
|
+
reportToAuditsSection(report) + NEW_LINE + NEW_LINE + // about section
|
|
1162
|
+
reportToAboutSection(report, commitData) + NEW_LINE + NEW_LINE + // footer section
|
|
1163
|
+
`${FOOTER_PREFIX} ${link(README_LINK, "Code PushUp")}`
|
|
1164
|
+
);
|
|
1167
1165
|
}
|
|
1168
1166
|
function reportToHeaderSection() {
|
|
1169
1167
|
return headline(reportHeadlineText) + NEW_LINE;
|
|
1170
1168
|
}
|
|
1171
1169
|
function reportToOverviewSection(report) {
|
|
1172
|
-
const { categories } = report;
|
|
1170
|
+
const { categories, plugins } = report;
|
|
1173
1171
|
const tableContent = [
|
|
1174
1172
|
reportOverviewTableHeaders,
|
|
1175
1173
|
...categories.map(({ title, refs, score }) => [
|
|
1176
1174
|
link(`#${slugify(title)}`, title),
|
|
1177
1175
|
`${getRoundScoreMarker(score)} ${style(formatReportScore(score))}`,
|
|
1178
|
-
countCategoryAudits(refs,
|
|
1176
|
+
countCategoryAudits(refs, plugins).toString()
|
|
1179
1177
|
])
|
|
1180
1178
|
];
|
|
1181
1179
|
return tableMd(tableContent, ["l", "c", "c"]);
|
|
@@ -1311,7 +1309,10 @@ function reportToAboutSection(report, commitData) {
|
|
|
1311
1309
|
formatDuration(duration2)
|
|
1312
1310
|
])
|
|
1313
1311
|
];
|
|
1314
|
-
return
|
|
1312
|
+
return (
|
|
1313
|
+
// eslint-disable-next-line prefer-template
|
|
1314
|
+
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"])
|
|
1315
|
+
);
|
|
1315
1316
|
}
|
|
1316
1317
|
function getDocsAndDescription({
|
|
1317
1318
|
docsUrl,
|
|
@@ -1345,13 +1346,7 @@ function addLine(line = "") {
|
|
|
1345
1346
|
return line + NEW_LINE;
|
|
1346
1347
|
}
|
|
1347
1348
|
function generateStdoutSummary(report) {
|
|
1348
|
-
|
|
1349
|
-
output += addLine(reportToHeaderSection2(report));
|
|
1350
|
-
output += addLine();
|
|
1351
|
-
output += addLine(reportToDetailSection(report));
|
|
1352
|
-
output += addLine(reportToOverviewSection2(report));
|
|
1353
|
-
output += addLine(`${FOOTER_PREFIX} ${CODE_PUSHUP_DOMAIN}`);
|
|
1354
|
-
return output;
|
|
1349
|
+
return addLine(reportToHeaderSection2(report)) + addLine() + addLine(reportToDetailSection(report)) + addLine(reportToOverviewSection2(report)) + addLine(`${FOOTER_PREFIX} ${CODE_PUSHUP_DOMAIN}`);
|
|
1355
1350
|
}
|
|
1356
1351
|
function reportToHeaderSection2(report) {
|
|
1357
1352
|
const { packageName, version } = report;
|
|
@@ -1359,12 +1354,9 @@ function reportToHeaderSection2(report) {
|
|
|
1359
1354
|
}
|
|
1360
1355
|
function reportToDetailSection(report) {
|
|
1361
1356
|
const { plugins } = report;
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
output += addLine(chalk3.magentaBright.bold(`${title} audits`));
|
|
1366
|
-
output += addLine();
|
|
1367
|
-
const ui = cliui({ width: 80 });
|
|
1357
|
+
return plugins.reduce((acc, plugin) => {
|
|
1358
|
+
const { title, audits } = plugin;
|
|
1359
|
+
const ui = cliui({ width: TERMINAL_WIDTH });
|
|
1368
1360
|
audits.forEach(({ score, title: title2, displayValue, value }) => {
|
|
1369
1361
|
ui.div(
|
|
1370
1362
|
{
|
|
@@ -1374,6 +1366,7 @@ function reportToDetailSection(report) {
|
|
|
1374
1366
|
},
|
|
1375
1367
|
{
|
|
1376
1368
|
text: title2,
|
|
1369
|
+
// eslint-disable-next-line no-magic-numbers
|
|
1377
1370
|
padding: [0, 3, 0, 0]
|
|
1378
1371
|
},
|
|
1379
1372
|
{
|
|
@@ -1383,17 +1376,13 @@ function reportToDetailSection(report) {
|
|
|
1383
1376
|
}
|
|
1384
1377
|
);
|
|
1385
1378
|
});
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
});
|
|
1389
|
-
return output;
|
|
1379
|
+
return acc + addLine() + addLine(chalk3.magentaBright.bold(`${title} audits`)) + addLine() + addLine(ui.toString()) + addLine();
|
|
1380
|
+
}, "");
|
|
1390
1381
|
}
|
|
1391
1382
|
function reportToOverviewSection2({
|
|
1392
1383
|
categories,
|
|
1393
1384
|
plugins
|
|
1394
1385
|
}) {
|
|
1395
|
-
let output = addLine(chalk3.magentaBright.bold("Categories"));
|
|
1396
|
-
output += addLine();
|
|
1397
1386
|
const table = new Table({
|
|
1398
1387
|
head: reportRawOverviewTableHeaders,
|
|
1399
1388
|
colAligns: ["left", "right", "right"],
|
|
@@ -1408,8 +1397,7 @@ function reportToOverviewSection2({
|
|
|
1408
1397
|
countCategoryAudits(refs, plugins)
|
|
1409
1398
|
])
|
|
1410
1399
|
);
|
|
1411
|
-
|
|
1412
|
-
return output;
|
|
1400
|
+
return addLine(chalk3.magentaBright.bold("Categories")) + addLine() + addLine(table.toString());
|
|
1413
1401
|
}
|
|
1414
1402
|
function withColor({ score, text }) {
|
|
1415
1403
|
const formattedScore = text ?? formatReportScore(score);
|
|
@@ -1440,7 +1428,7 @@ function countOccurrences(values) {
|
|
|
1440
1428
|
);
|
|
1441
1429
|
}
|
|
1442
1430
|
function distinct(array) {
|
|
1443
|
-
return
|
|
1431
|
+
return [...new Set(array)];
|
|
1444
1432
|
}
|
|
1445
1433
|
function deepClone(obj) {
|
|
1446
1434
|
if (obj == null || typeof obj !== "object") {
|
|
@@ -1468,11 +1456,7 @@ function objectToCliArgs(params) {
|
|
|
1468
1456
|
}
|
|
1469
1457
|
return Object.entries(params).flatMap(([key, value]) => {
|
|
1470
1458
|
if (key === "_") {
|
|
1471
|
-
|
|
1472
|
-
return value;
|
|
1473
|
-
} else {
|
|
1474
|
-
return [value + ""];
|
|
1475
|
-
}
|
|
1459
|
+
return Array.isArray(value) ? value : [`${value}`];
|
|
1476
1460
|
}
|
|
1477
1461
|
const prefix = key.length === 1 ? "-" : "--";
|
|
1478
1462
|
if (Array.isArray(value)) {
|
|
@@ -1496,7 +1480,7 @@ function objectToCliArgs(params) {
|
|
|
1496
1480
|
function toUnixPath(path, options) {
|
|
1497
1481
|
const unixPath = path.replace(/\\/g, "/");
|
|
1498
1482
|
if (options?.toRelative) {
|
|
1499
|
-
return unixPath.replace(process.cwd().replace(/\\/g, "/")
|
|
1483
|
+
return unixPath.replace(`${process.cwd().replace(/\\/g, "/")}/`, "");
|
|
1500
1484
|
}
|
|
1501
1485
|
return unixPath;
|
|
1502
1486
|
}
|
|
@@ -1524,28 +1508,28 @@ function scoreReport(report) {
|
|
|
1524
1508
|
const scoredReport = deepClone(report);
|
|
1525
1509
|
const allScoredAuditsAndGroups = /* @__PURE__ */ new Map();
|
|
1526
1510
|
scoredReport.plugins?.forEach((plugin) => {
|
|
1527
|
-
const { audits } = plugin;
|
|
1511
|
+
const { slug, audits } = plugin;
|
|
1528
1512
|
const groups = plugin.groups || [];
|
|
1529
1513
|
audits.forEach((audit) => {
|
|
1530
|
-
const key = `${
|
|
1531
|
-
audit.plugin =
|
|
1514
|
+
const key = `${slug}-${audit.slug}-audit`;
|
|
1515
|
+
audit.plugin = slug;
|
|
1532
1516
|
allScoredAuditsAndGroups.set(key, audit);
|
|
1533
1517
|
});
|
|
1534
1518
|
function groupScoreFn(ref) {
|
|
1535
1519
|
const score = allScoredAuditsAndGroups.get(
|
|
1536
|
-
`${
|
|
1520
|
+
`${slug}-${ref.slug}-audit`
|
|
1537
1521
|
)?.score;
|
|
1538
1522
|
if (score == null) {
|
|
1539
1523
|
throw new Error(
|
|
1540
|
-
`Group has invalid ref - audit with slug ${
|
|
1524
|
+
`Group has invalid ref - audit with slug ${slug}-${ref.slug}-audit not found`
|
|
1541
1525
|
);
|
|
1542
1526
|
}
|
|
1543
1527
|
return score;
|
|
1544
1528
|
}
|
|
1545
1529
|
groups.forEach((group) => {
|
|
1546
|
-
const key = `${
|
|
1530
|
+
const key = `${slug}-${group.slug}-group`;
|
|
1547
1531
|
group.score = calculateScore(group.refs, groupScoreFn);
|
|
1548
|
-
group.plugin =
|
|
1532
|
+
group.plugin = slug;
|
|
1549
1533
|
allScoredAuditsAndGroups.set(key, group);
|
|
1550
1534
|
});
|
|
1551
1535
|
plugin.groups = groups;
|
|
@@ -1565,7 +1549,7 @@ function scoreReport(report) {
|
|
|
1565
1549
|
category.score = calculateScore(category.refs, catScoreFn);
|
|
1566
1550
|
scoredCategoriesMap.set(category.slug, category);
|
|
1567
1551
|
}
|
|
1568
|
-
scoredReport.categories =
|
|
1552
|
+
scoredReport.categories = [...scoredCategoriesMap.values()];
|
|
1569
1553
|
return scoredReport;
|
|
1570
1554
|
}
|
|
1571
1555
|
|
|
@@ -1591,7 +1575,7 @@ function sortReport(report) {
|
|
|
1591
1575
|
...groups,
|
|
1592
1576
|
...audits.sort(compareCategoryAudits)
|
|
1593
1577
|
];
|
|
1594
|
-
const sortedRefs = category.refs.
|
|
1578
|
+
const sortedRefs = [...category.refs].sort((a, b) => {
|
|
1595
1579
|
const aIndex = sortedAuditsAndGroups.findIndex(
|
|
1596
1580
|
(ref) => ref.slug === a.slug
|
|
1597
1581
|
);
|
|
@@ -1604,13 +1588,15 @@ function sortReport(report) {
|
|
|
1604
1588
|
});
|
|
1605
1589
|
const sortedPlugins = plugins.map((plugin) => ({
|
|
1606
1590
|
...plugin,
|
|
1607
|
-
audits: plugin.audits.sort(compareAudits).map(
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1591
|
+
audits: [...plugin.audits].sort(compareAudits).map(
|
|
1592
|
+
(audit) => audit.details?.issues ? {
|
|
1593
|
+
...audit,
|
|
1594
|
+
details: {
|
|
1595
|
+
...audit.details,
|
|
1596
|
+
issues: [...audit.details.issues].sort(compareIssues)
|
|
1597
|
+
}
|
|
1598
|
+
} : audit
|
|
1599
|
+
)
|
|
1614
1600
|
}));
|
|
1615
1601
|
return {
|
|
1616
1602
|
...report,
|
package/package.json
CHANGED
package/src/lib/transform.d.ts
CHANGED
|
@@ -6,7 +6,8 @@ export declare function distinct<T extends string | number | boolean>(array: T[]
|
|
|
6
6
|
export declare function deepClone<T>(obj: T): T;
|
|
7
7
|
export declare function factorOf<T>(items: T[], filterFn: (i: T) => boolean): number;
|
|
8
8
|
type ArgumentValue = number | string | boolean | string[];
|
|
9
|
-
export type CliArgsObject<T extends object = Record<string, ArgumentValue>> = T extends never ?
|
|
9
|
+
export type CliArgsObject<T extends object = Record<string, ArgumentValue>> = T extends never ? // eslint-disable-next-line @typescript-eslint/naming-convention
|
|
10
|
+
Record<string, ArgumentValue | undefined> | {
|
|
10
11
|
_: string;
|
|
11
12
|
} : T;
|
|
12
13
|
/**
|