@code-pushup/utils 0.8.24 → 0.8.25

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.
Files changed (2) hide show
  1. package/index.js +106 -135
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -566,15 +566,15 @@ function pluralize(text) {
566
566
  return `${text}s`;
567
567
  }
568
568
  function formatBytes(bytes, decimals = 2) {
569
- bytes = Math.max(bytes, 0);
570
- if (!bytes) {
569
+ const positiveBytes = Math.max(bytes, 0);
570
+ if (positiveBytes === 0) {
571
571
  return "0 B";
572
572
  }
573
573
  const k = 1024;
574
574
  const dm = decimals < 0 ? 0 : decimals;
575
575
  const sizes = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
576
- const i = Math.floor(Math.log(bytes) / Math.log(k));
577
- return `${Number.parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
576
+ const i = Math.floor(Math.log(positiveBytes) / Math.log(k));
577
+ return `${Number.parseFloat((positiveBytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
578
578
  }
579
579
  function pluralizeToken(token, times = 0) {
580
580
  return `${times} ${Math.abs(times) === 1 ? token : pluralize(token)}`;
@@ -807,8 +807,7 @@ function getSeverityIcon(severity) {
807
807
  return "\u2139\uFE0F";
808
808
  }
809
809
  function calcDuration(start, stop) {
810
- stop ??= performance.now();
811
- return Math.floor(stop - start);
810
+ return Math.floor((stop ?? performance.now()) - start);
812
811
  }
813
812
  function countCategoryAudits(refs, plugins) {
814
813
  const groupLookup = plugins.reduce(
@@ -834,15 +833,15 @@ function countCategoryAudits(refs, plugins) {
834
833
  }, 0);
835
834
  }
836
835
  function getAuditByRef({ slug, weight, plugin }, plugins) {
837
- const auditPlugin = plugins.find(({ slug: slug2 }) => slug2 === plugin);
836
+ const auditPlugin = plugins.find((p) => p.slug === plugin);
838
837
  if (!auditPlugin) {
839
838
  throwIsNotPresentError(`Plugin ${plugin}`, "report");
840
839
  }
841
- const audit = auditPlugin?.audits.find(
840
+ const audit = auditPlugin.audits.find(
842
841
  ({ slug: auditSlug }) => auditSlug === slug
843
842
  );
844
843
  if (!audit) {
845
- throwIsNotPresentError(`Audit ${slug}`, auditPlugin?.slug);
844
+ throwIsNotPresentError(`Audit ${slug}`, auditPlugin.slug);
846
845
  }
847
846
  return {
848
847
  ...audit,
@@ -855,24 +854,21 @@ function getGroupWithAudits(refSlug, refPlugin, plugins) {
855
854
  if (!plugin) {
856
855
  throwIsNotPresentError(`Plugin ${refPlugin}`, "report");
857
856
  }
858
- const groupWithAudits = plugin?.groups?.find(({ slug }) => slug === refSlug);
857
+ const groupWithAudits = plugin.groups?.find(({ slug }) => slug === refSlug);
859
858
  if (!groupWithAudits) {
860
- throwIsNotPresentError(`Group ${refSlug}`, plugin?.slug);
859
+ throwIsNotPresentError(`Group ${refSlug}`, plugin.slug);
861
860
  }
862
861
  const groupAudits = groupWithAudits.refs.reduce(
863
862
  (acc, ref) => {
864
863
  const audit = getAuditByRef(
865
- { ...ref, plugin: refPlugin },
864
+ { ...ref, plugin: refPlugin, type: "audit" },
866
865
  plugins
867
866
  );
868
- if (audit) {
869
- return [...acc, audit];
870
- }
871
- return [...acc];
867
+ return [...acc, audit];
872
868
  },
873
869
  []
874
870
  );
875
- const audits = groupAudits.sort(compareCategoryAudits);
871
+ const audits = [...groupAudits].sort(compareCategoryAudits);
876
872
  return {
877
873
  ...groupWithAudits,
878
874
  audits
@@ -915,7 +911,8 @@ async function loadReport(options) {
915
911
  const content = await readJsonFile(filePath);
916
912
  return reportSchema.parse(content);
917
913
  }
918
- return readTextFile(filePath);
914
+ const text = await readTextFile(filePath);
915
+ return text;
919
916
  }
920
917
  function throwIsNotPresentError(itemName, presentPlace) {
921
918
  throw new Error(`${itemName} is not present in ${presentPlace}`);
@@ -970,11 +967,11 @@ function executeProcess(cfg) {
970
967
  let stdout = "";
971
968
  let stderr = "";
972
969
  process2.stdout.on("data", (data) => {
973
- stdout += data.toString();
974
- onStdout?.(data);
970
+ stdout += String(data);
971
+ onStdout?.(String(data));
975
972
  });
976
973
  process2.stderr.on("data", (data) => {
977
- stderr += data.toString();
974
+ stderr += String(data);
978
975
  });
979
976
  process2.on("error", (err) => {
980
977
  stderr += err.toString();
@@ -994,28 +991,20 @@ function executeProcess(cfg) {
994
991
  }
995
992
 
996
993
  // packages/utils/src/lib/git.ts
997
- import simpleGit from "simple-git";
994
+ import { simpleGit } from "simple-git";
998
995
  var git = simpleGit();
999
996
  async function getLatestCommit() {
1000
997
  const log = await git.log({
1001
998
  maxCount: 1,
1002
999
  format: { hash: "%H", message: "%s", author: "%an", date: "%ad" }
1003
1000
  });
1004
- return log?.latest;
1001
+ return log.latest;
1005
1002
  }
1006
1003
 
1007
1004
  // packages/utils/src/lib/group-by-status.ts
1008
1005
  function groupByStatus(results) {
1009
1006
  return results.reduce(
1010
- (acc, result) => {
1011
- if (result.status === "fulfilled") {
1012
- return { ...acc, fulfilled: [...acc.fulfilled, result] };
1013
- }
1014
- if (result.status === "rejected") {
1015
- return { ...acc, rejected: [...acc.rejected, result] };
1016
- }
1017
- return acc;
1018
- },
1007
+ (acc, result) => result.status === "fulfilled" ? { ...acc, fulfilled: [...acc.fulfilled, result] } : { ...acc, rejected: [...acc.rejected, result] },
1019
1008
  { fulfilled: [], rejected: [] }
1020
1009
  );
1021
1010
  }
@@ -1130,10 +1119,10 @@ function tableMd(data, align) {
1130
1119
  if (data.length === 0) {
1131
1120
  throw new Error("Data can't be empty");
1132
1121
  }
1133
- align ??= data[0]?.map(() => "c");
1122
+ const alignmentSetting = align ?? data[0]?.map(() => "c");
1134
1123
  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);
1124
+ const alignmentRow = `|${alignmentSetting?.map((s) => alignString.get(s)).join("|")}|`;
1125
+ return tableContent[0] + NEW_LINE + alignmentRow + NEW_LINE + tableContent.slice(1).join(NEW_LINE);
1137
1126
  }
1138
1127
  function tableHtml(data) {
1139
1128
  if (data.length === 0) {
@@ -1186,15 +1175,15 @@ function reportToCategoriesSection(report) {
1186
1175
  category.score
1187
1176
  )} Score: ${style(formatReportScore(category.score))}`;
1188
1177
  const categoryDocs = getDocsAndDescription(category);
1189
- const categoryMDItems = category.refs.reduce((acc2, ref) => {
1178
+ const categoryMDItems = category.refs.reduce((refAcc, ref) => {
1190
1179
  if (ref.type === "group") {
1191
1180
  const group = getGroupWithAudits(ref.slug, ref.plugin, plugins);
1192
1181
  const mdGroupItem = groupItemToCategorySection(group, plugins);
1193
- return acc2 + mdGroupItem + NEW_LINE;
1182
+ return refAcc + mdGroupItem + NEW_LINE;
1194
1183
  } else {
1195
1184
  const audit = getAuditByRef(ref, plugins);
1196
1185
  const mdAuditItem = auditItemToCategorySection(audit, plugins);
1197
- return acc2 + mdAuditItem + NEW_LINE;
1186
+ return refAcc + mdAuditItem + NEW_LINE;
1198
1187
  }
1199
1188
  }, "");
1200
1189
  return acc + NEW_LINE + categoryTitle + NEW_LINE + NEW_LINE + categoryDocs + categoryScore + NEW_LINE + categoryMDItems;
@@ -1205,7 +1194,7 @@ function auditItemToCategorySection(audit, plugins) {
1205
1194
  const pluginTitle = getPluginNameFromSlug(audit.plugin, plugins);
1206
1195
  const auditTitle = link(
1207
1196
  `#${slugify(audit.title)}-${slugify(pluginTitle)}`,
1208
- audit?.title
1197
+ audit.title
1209
1198
  );
1210
1199
  return li(
1211
1200
  `${getSquaredScoreMarker(
@@ -1222,69 +1211,57 @@ function groupItemToCategorySection(group, plugins) {
1222
1211
  const groupAudits = group.audits.reduce((acc, audit) => {
1223
1212
  const auditTitle = link(
1224
1213
  `#${slugify(audit.title)}-${slugify(pluginTitle)}`,
1225
- audit?.title
1214
+ audit.title
1226
1215
  );
1227
- acc += ` ${li(
1216
+ return `${acc} ${li(
1228
1217
  `${getSquaredScoreMarker(audit.score)} ${auditTitle} - ${getAuditResult(
1229
1218
  audit
1230
1219
  )}`
1231
- )}`;
1232
- acc += NEW_LINE;
1233
- return acc;
1220
+ )}${NEW_LINE}`;
1234
1221
  }, "");
1235
1222
  return groupTitle + NEW_LINE + groupAudits;
1236
1223
  }
1237
1224
  function reportToAuditsSection(report) {
1238
- const auditsSection = report.plugins.reduce((acc, plugin) => {
1239
- const auditsData = plugin.audits.reduce((acc2, audit) => {
1225
+ const auditsSection = report.plugins.reduce((pluginAcc, plugin) => {
1226
+ const auditsData = plugin.audits.reduce((auditAcc, audit) => {
1240
1227
  const auditTitle = `${audit.title} (${getPluginNameFromSlug(
1241
1228
  audit.plugin,
1242
1229
  report.plugins
1243
1230
  )})`;
1244
- const detailsTitle = `${getSquaredScoreMarker(
1245
- audit.score
1246
- )} ${getAuditResult(audit, true)} (score: ${formatReportScore(
1247
- audit.score
1248
- )})`;
1249
- const docsItem = getDocsAndDescription(audit);
1250
- acc2 += h3(auditTitle);
1251
- acc2 += NEW_LINE;
1252
- acc2 += NEW_LINE;
1253
- if (!audit.details?.issues?.length) {
1254
- acc2 += detailsTitle;
1255
- acc2 += NEW_LINE;
1256
- acc2 += NEW_LINE;
1257
- acc2 += docsItem;
1258
- return acc2;
1259
- }
1260
- const detailsTableData = [
1261
- detailsTableHeaders,
1262
- ...audit.details.issues.map((issue) => {
1263
- const severity = `${getSeverityIcon(issue.severity)} <i>${issue.severity}</i>`;
1264
- const message = issue.message;
1265
- if (!issue.source) {
1266
- return [severity, message, "", ""];
1267
- }
1268
- const file = `<code>${issue.source?.file}</code>`;
1269
- if (!issue.source.position) {
1270
- return [severity, message, file, ""];
1271
- }
1272
- const { startLine, endLine } = issue.source.position;
1273
- const line = `${startLine || ""}${endLine && startLine !== endLine ? `-${endLine}` : ""}`;
1274
- return [severity, message, file, line];
1275
- })
1276
- ];
1277
- const detailsTable = `<h4>Issues</h4>${tableHtml(detailsTableData)}`;
1278
- acc2 += details(detailsTitle, detailsTable);
1279
- acc2 += NEW_LINE;
1280
- acc2 += NEW_LINE;
1281
- acc2 += docsItem;
1282
- return acc2;
1231
+ return auditAcc + h3(auditTitle) + NEW_LINE + NEW_LINE + reportToDetailsSection(audit) + NEW_LINE + NEW_LINE + getDocsAndDescription(audit);
1283
1232
  }, "");
1284
- return acc + auditsData;
1233
+ return pluginAcc + auditsData;
1285
1234
  }, "");
1286
1235
  return h2("\u{1F6E1}\uFE0F Audits") + NEW_LINE + NEW_LINE + auditsSection;
1287
1236
  }
1237
+ function reportToDetailsSection(audit) {
1238
+ const detailsTitle = `${getSquaredScoreMarker(audit.score)} ${getAuditResult(
1239
+ audit,
1240
+ true
1241
+ )} (score: ${formatReportScore(audit.score)})`;
1242
+ if (!audit.details?.issues.length) {
1243
+ return detailsTitle;
1244
+ }
1245
+ const detailsTableData = [
1246
+ detailsTableHeaders,
1247
+ ...audit.details.issues.map((issue) => {
1248
+ const severity = `${getSeverityIcon(issue.severity)} <i>${issue.severity}</i>`;
1249
+ const message = issue.message;
1250
+ if (!issue.source) {
1251
+ return [severity, message, "", ""];
1252
+ }
1253
+ const file = `<code>${issue.source.file}</code>`;
1254
+ if (!issue.source.position) {
1255
+ return [severity, message, file, ""];
1256
+ }
1257
+ const { startLine, endLine } = issue.source.position;
1258
+ const line = `${startLine || ""}${endLine && startLine !== endLine ? `-${endLine}` : ""}`;
1259
+ return [severity, message, file, line];
1260
+ })
1261
+ ];
1262
+ const detailsTable = `<h4>Issues</h4>${tableHtml(detailsTableData)}`;
1263
+ return details(detailsTitle, detailsTable);
1264
+ }
1288
1265
  function reportToAboutSection(report, commitData) {
1289
1266
  const date = (/* @__PURE__ */ new Date()).toString();
1290
1267
  const { duration, version, plugins, categories } = report;
@@ -1302,11 +1279,11 @@ function reportToAboutSection(report, commitData) {
1302
1279
  ];
1303
1280
  const pluginMetaTable = [
1304
1281
  pluginMetaTableHeaders,
1305
- ...plugins.map(({ title, version: version2, duration: duration2, audits }) => [
1306
- title,
1307
- audits.length.toString(),
1308
- style(version2 || "", ["c"]),
1309
- formatDuration(duration2)
1282
+ ...plugins.map((plugin) => [
1283
+ plugin.title,
1284
+ plugin.audits.length.toString(),
1285
+ style(plugin.version || "", ["c"]),
1286
+ formatDuration(plugin.duration)
1310
1287
  ])
1311
1288
  ];
1312
1289
  return (
@@ -1341,7 +1318,7 @@ function getAuditResult(audit, isHtml = false) {
1341
1318
  // packages/utils/src/lib/reports/generate-stdout-summary.ts
1342
1319
  import cliui from "@isaacs/cliui";
1343
1320
  import chalk3 from "chalk";
1344
- import Table from "cli-table3";
1321
+ import CliTable3 from "cli-table3";
1345
1322
  function addLine(line = "") {
1346
1323
  return line + NEW_LINE;
1347
1324
  }
@@ -1357,20 +1334,20 @@ function reportToDetailSection(report) {
1357
1334
  return plugins.reduce((acc, plugin) => {
1358
1335
  const { title, audits } = plugin;
1359
1336
  const ui = cliui({ width: TERMINAL_WIDTH });
1360
- audits.forEach(({ score, title: title2, displayValue, value }) => {
1337
+ audits.forEach((audit) => {
1361
1338
  ui.div(
1362
1339
  {
1363
- text: withColor({ score, text: "\u25CF" }),
1340
+ text: withColor({ score: audit.score, text: "\u25CF" }),
1364
1341
  width: 2,
1365
1342
  padding: [0, 1, 0, 0]
1366
1343
  },
1367
1344
  {
1368
- text: title2,
1345
+ text: audit.title,
1369
1346
  // eslint-disable-next-line no-magic-numbers
1370
1347
  padding: [0, 3, 0, 0]
1371
1348
  },
1372
1349
  {
1373
- text: chalk3.cyanBright(displayValue || `${value}`),
1350
+ text: chalk3.cyanBright(audit.displayValue || `${audit.value}`),
1374
1351
  width: 10,
1375
1352
  padding: [0, 0, 0, 0]
1376
1353
  }
@@ -1383,7 +1360,7 @@ function reportToOverviewSection2({
1383
1360
  categories,
1384
1361
  plugins
1385
1362
  }) {
1386
- const table = new Table({
1363
+ const table = new CliTable3({
1387
1364
  head: reportRawOverviewTableHeaders,
1388
1365
  colAligns: ["left", "right", "right"],
1389
1366
  style: {
@@ -1431,16 +1408,7 @@ function distinct(array) {
1431
1408
  return [...new Set(array)];
1432
1409
  }
1433
1410
  function deepClone(obj) {
1434
- if (obj == null || typeof obj !== "object") {
1435
- return obj;
1436
- }
1437
- const cloned = Array.isArray(obj) ? [] : {};
1438
- for (const key in obj) {
1439
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
1440
- cloned[key] = deepClone(obj[key]);
1441
- }
1442
- }
1443
- return cloned;
1411
+ return obj == null || typeof obj !== "object" ? obj : structuredClone(obj);
1444
1412
  }
1445
1413
  function factorOf(items, filterFn) {
1446
1414
  const itemCount = items.length;
@@ -1505,15 +1473,12 @@ function calculateScore(refs, scoreFn) {
1505
1473
  return numerator / denominator;
1506
1474
  }
1507
1475
  function scoreReport(report) {
1508
- const scoredReport = deepClone(report);
1509
1476
  const allScoredAuditsAndGroups = /* @__PURE__ */ new Map();
1510
- scoredReport.plugins?.forEach((plugin) => {
1511
- const { slug, audits } = plugin;
1512
- const groups = plugin.groups || [];
1513
- audits.forEach((audit) => {
1514
- const key = `${slug}-${audit.slug}-audit`;
1515
- audit.plugin = slug;
1516
- allScoredAuditsAndGroups.set(key, audit);
1477
+ const scoredPlugins = report.plugins.map((plugin) => {
1478
+ const { slug, audits, groups } = plugin;
1479
+ const updatedAudits = audits.map((audit) => ({ ...audit, plugin: slug }));
1480
+ updatedAudits.forEach((audit) => {
1481
+ allScoredAuditsAndGroups.set(`${slug}-${audit.slug}-audit`, audit);
1517
1482
  });
1518
1483
  function groupScoreFn(ref) {
1519
1484
  const score = allScoredAuditsAndGroups.get(
@@ -1526,13 +1491,15 @@ function scoreReport(report) {
1526
1491
  }
1527
1492
  return score;
1528
1493
  }
1529
- groups.forEach((group) => {
1530
- const key = `${slug}-${group.slug}-group`;
1531
- group.score = calculateScore(group.refs, groupScoreFn);
1532
- group.plugin = slug;
1533
- allScoredAuditsAndGroups.set(key, group);
1494
+ const scoredGroups = groups?.map((group) => ({
1495
+ ...group,
1496
+ score: calculateScore(group.refs, groupScoreFn),
1497
+ plugin: slug
1498
+ })) ?? [];
1499
+ scoredGroups.forEach((group) => {
1500
+ allScoredAuditsAndGroups.set(`${slug}-${group.slug}-group`, group);
1534
1501
  });
1535
- plugin.groups = groups;
1502
+ return { ...plugin, audits: updatedAudits, groups: scoredGroups };
1536
1503
  });
1537
1504
  function catScoreFn(ref) {
1538
1505
  const key = `${ref.plugin}-${ref.slug}-${ref.type}`;
@@ -1544,13 +1511,15 @@ function scoreReport(report) {
1544
1511
  }
1545
1512
  return item.score;
1546
1513
  }
1547
- const scoredCategoriesMap = /* @__PURE__ */ new Map();
1548
- for (const category of scoredReport.categories) {
1549
- category.score = calculateScore(category.refs, catScoreFn);
1550
- scoredCategoriesMap.set(category.slug, category);
1551
- }
1552
- scoredReport.categories = [...scoredCategoriesMap.values()];
1553
- return scoredReport;
1514
+ const scoredCategories = report.categories.map((category) => ({
1515
+ ...category,
1516
+ score: calculateScore(category.refs, catScoreFn)
1517
+ }));
1518
+ return {
1519
+ ...deepClone(report),
1520
+ plugins: scoredPlugins,
1521
+ categories: scoredCategories
1522
+ };
1554
1523
  }
1555
1524
 
1556
1525
  // packages/utils/src/lib/reports/sorting.ts
@@ -1573,7 +1542,7 @@ function sortReport(report) {
1573
1542
  );
1574
1543
  const sortedAuditsAndGroups = [
1575
1544
  ...groups,
1576
- ...audits.sort(compareCategoryAudits)
1545
+ ...[...audits].sort(compareCategoryAudits)
1577
1546
  ];
1578
1547
  const sortedRefs = [...category.refs].sort((a, b) => {
1579
1548
  const aIndex = sortedAuditsAndGroups.findIndex(
@@ -1586,7 +1555,14 @@ function sortReport(report) {
1586
1555
  });
1587
1556
  return { ...category, refs: sortedRefs };
1588
1557
  });
1589
- const sortedPlugins = plugins.map((plugin) => ({
1558
+ return {
1559
+ ...report,
1560
+ categories: sortedCategories,
1561
+ plugins: sortPlugins(plugins)
1562
+ };
1563
+ }
1564
+ function sortPlugins(plugins) {
1565
+ return plugins.map((plugin) => ({
1590
1566
  ...plugin,
1591
1567
  audits: [...plugin.audits].sort(compareAudits).map(
1592
1568
  (audit) => audit.details?.issues ? {
@@ -1598,11 +1574,6 @@ function sortReport(report) {
1598
1574
  } : audit
1599
1575
  )
1600
1576
  }));
1601
- return {
1602
- ...report,
1603
- categories: sortedCategories,
1604
- plugins: sortedPlugins
1605
- };
1606
1577
  }
1607
1578
 
1608
1579
  // packages/utils/src/lib/verbose-utils.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-pushup/utils",
3
- "version": "0.8.24",
3
+ "version": "0.8.25",
4
4
  "dependencies": {
5
5
  "@code-pushup/models": "*",
6
6
  "bundle-require": "^4.0.1",