@code-pushup/coverage-plugin 0.48.0 → 0.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // packages/plugin-coverage/src/lib/runner/index.ts
2
- import chalk5 from "chalk";
2
+ import { bold as bold5 } from "ansis";
3
3
  import { writeFile } from "node:fs/promises";
4
4
  import { dirname } from "node:path";
5
5
 
@@ -671,6 +671,8 @@ var auditResultSchema = scorableWithPluginMetaSchema.merge(
671
671
  );
672
672
  var reportsDiffSchema = z15.object({
673
673
  commits: makeComparisonSchema(commitSchema).nullable().describe("Commits identifying compared reports"),
674
+ portalUrl: urlSchema.optional().describe("Link to comparison page in Code PushUp portal"),
675
+ label: z15.string().optional().describe("Label (e.g. project name)"),
674
676
  categories: makeArraysComparisonSchema(
675
677
  categoryDiffSchema,
676
678
  categoryResultSchema,
@@ -699,23 +701,81 @@ var reportsDiffSchema = z15.object({
699
701
  );
700
702
 
701
703
  // packages/utils/src/lib/execute-process.ts
702
- import { spawn } from "node:child_process";
704
+ import {
705
+ spawn
706
+ } from "node:child_process";
707
+
708
+ // packages/utils/src/lib/reports/utils.ts
709
+ import ansis from "ansis";
710
+ import { md } from "build-md";
711
+
712
+ // packages/utils/src/lib/reports/constants.ts
713
+ var TERMINAL_WIDTH = 80;
714
+
715
+ // packages/utils/src/lib/reports/utils.ts
716
+ function calcDuration(start, stop) {
717
+ return Math.round((stop ?? performance.now()) - start);
718
+ }
719
+
720
+ // packages/utils/src/lib/execute-process.ts
721
+ var ProcessError = class extends Error {
722
+ code;
723
+ stderr;
724
+ stdout;
725
+ constructor(result) {
726
+ super(result.stderr);
727
+ this.code = result.code;
728
+ this.stderr = result.stderr;
729
+ this.stdout = result.stdout;
730
+ }
731
+ };
732
+ function executeProcess(cfg) {
733
+ const { command, args, observer, ignoreExitCode = false, ...options } = cfg;
734
+ const { onStdout, onStderr, onError, onComplete } = observer ?? {};
735
+ const date = (/* @__PURE__ */ new Date()).toISOString();
736
+ const start = performance.now();
737
+ return new Promise((resolve, reject) => {
738
+ const spawnedProcess = spawn(command, args ?? [], {
739
+ shell: true,
740
+ ...options
741
+ });
742
+ let stdout = "";
743
+ let stderr = "";
744
+ spawnedProcess.stdout.on("data", (data) => {
745
+ stdout += String(data);
746
+ onStdout?.(String(data), spawnedProcess);
747
+ });
748
+ spawnedProcess.stderr.on("data", (data) => {
749
+ stderr += String(data);
750
+ onStderr?.(String(data), spawnedProcess);
751
+ });
752
+ spawnedProcess.on("error", (err) => {
753
+ stderr += err.toString();
754
+ });
755
+ spawnedProcess.on("close", (code2) => {
756
+ const timings = { date, duration: calcDuration(start) };
757
+ if (code2 === 0 || ignoreExitCode) {
758
+ onComplete?.();
759
+ resolve({ code: code2, stdout, stderr, ...timings });
760
+ } else {
761
+ const errorMsg = new ProcessError({ code: code2, stdout, stderr, ...timings });
762
+ onError?.(errorMsg);
763
+ reject(errorMsg);
764
+ }
765
+ });
766
+ });
767
+ }
703
768
 
704
769
  // packages/utils/src/lib/file-system.ts
770
+ import { bold, gray } from "ansis";
705
771
  import { bundleRequire } from "bundle-require";
706
- import chalk2 from "chalk";
707
772
  import { mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
708
773
  import { join } from "node:path";
709
774
 
710
775
  // packages/utils/src/lib/logging.ts
711
776
  import isaacs_cliui from "@isaacs/cliui";
712
777
  import { cliui } from "@poppinss/cliui";
713
- import chalk from "chalk";
714
-
715
- // packages/utils/src/lib/reports/constants.ts
716
- var TERMINAL_WIDTH = 80;
717
-
718
- // packages/utils/src/lib/logging.ts
778
+ import { underline } from "ansis";
719
779
  var singletonUiInstance;
720
780
  function ui() {
721
781
  if (singletonUiInstance === void 0) {
@@ -763,48 +823,14 @@ function pluginWorkDir(slug) {
763
823
  return join("node_modules", ".code-pushup", slug);
764
824
  }
765
825
 
766
- // packages/utils/src/lib/text-formats/constants.ts
767
- var NEW_LINE = "\n";
768
- var TAB = " ";
769
-
770
- // packages/utils/src/lib/text-formats/html/details.ts
771
- function details(title, content, cfg = { open: false }) {
772
- return `<details${cfg.open ? " open" : ""}>${NEW_LINE}<summary>${title}</summary>${NEW_LINE}${// ⚠️ The blank line is needed to ensure Markdown in content is rendered correctly.
773
- NEW_LINE}${content}${NEW_LINE}${// @TODO in the future we could consider adding it only if the content ends with a code block
774
- // ⚠️ The blank line ensure Markdown in content is rendered correctly.
775
- NEW_LINE}</details>${// ⚠️ The blank line is needed to ensure Markdown after details is rendered correctly.
776
- NEW_LINE}`;
777
- }
778
-
779
- // packages/utils/src/lib/text-formats/html/font-style.ts
780
- var boldElement = "b";
781
- function bold(text) {
782
- return `<${boldElement}>${text}</${boldElement}>`;
783
- }
784
- var italicElement = "i";
785
- function italic(text) {
786
- return `<${italicElement}>${text}</${italicElement}>`;
787
- }
788
- var codeElement = "code";
789
- function code(text) {
790
- return `<${codeElement}>${text}</${codeElement}>`;
791
- }
792
-
793
- // packages/utils/src/lib/text-formats/html/link.ts
794
- function link(href, text) {
795
- return `<a href="${href}">${text || href}</a>`;
796
- }
826
+ // packages/utils/src/lib/git/git.ts
827
+ import { simpleGit } from "simple-git";
797
828
 
798
829
  // packages/utils/src/lib/transform.ts
799
830
  import { platform } from "node:os";
800
831
  function toUnixNewlines(text) {
801
832
  return platform() === "win32" ? text.replace(/\r\n/g, "\n") : text;
802
833
  }
803
- function capitalize(text) {
804
- return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
805
- 1
806
- )}`;
807
- }
808
834
  function toNumberPrecision(value, decimalPlaces) {
809
835
  return Number(
810
836
  `${Math.round(
@@ -825,306 +851,6 @@ function toOrdinal(value) {
825
851
  return `${value}th`;
826
852
  }
827
853
 
828
- // packages/utils/src/lib/text-formats/table.ts
829
- function rowToStringArray({ rows, columns = [] }) {
830
- if (Array.isArray(rows.at(0)) && typeof columns.at(0) === "object") {
831
- throw new TypeError(
832
- "Column can`t be object when rows are primitive values"
833
- );
834
- }
835
- return rows.map((row) => {
836
- if (Array.isArray(row)) {
837
- return row.map(String);
838
- }
839
- const objectRow = row;
840
- if (columns.length === 0 || typeof columns.at(0) === "string") {
841
- return Object.values(objectRow).map(
842
- (value) => value == null ? "" : String(value)
843
- );
844
- }
845
- return columns.map(
846
- ({ key }) => objectRow[key] == null ? "" : String(objectRow[key])
847
- );
848
- });
849
- }
850
- function columnsToStringArray({
851
- rows,
852
- columns = []
853
- }) {
854
- const firstRow = rows.at(0);
855
- const primitiveRows = Array.isArray(firstRow);
856
- if (typeof columns.at(0) === "string" && !primitiveRows) {
857
- throw new Error("invalid union type. Caught by model parsing.");
858
- }
859
- if (columns.length === 0) {
860
- if (Array.isArray(firstRow)) {
861
- return firstRow.map((_, idx) => String(idx));
862
- }
863
- return Object.keys(firstRow);
864
- }
865
- if (typeof columns.at(0) === "string") {
866
- return columns.map(String);
867
- }
868
- const cols = columns;
869
- return cols.map(({ label, key }) => label ?? capitalize(key));
870
- }
871
- function getColumnAlignmentForKeyAndIndex(targetKey, targetIdx, columns = []) {
872
- const column = columns.at(targetIdx) ?? columns.find((col) => col.key === targetKey);
873
- if (typeof column === "string") {
874
- return column;
875
- } else if (typeof column === "object") {
876
- return column.align ?? "center";
877
- } else {
878
- return "center";
879
- }
880
- }
881
- function getColumnAlignmentForIndex(targetIdx, columns = []) {
882
- const column = columns.at(targetIdx);
883
- if (column == null) {
884
- return "center";
885
- } else if (typeof column === "string") {
886
- return column;
887
- } else if (typeof column === "object") {
888
- return column.align ?? "center";
889
- } else {
890
- return "center";
891
- }
892
- }
893
- function getColumnAlignments(tableData) {
894
- const { rows, columns = [] } = tableData;
895
- if (rows.at(0) == null) {
896
- throw new Error("first row can`t be undefined.");
897
- }
898
- if (Array.isArray(rows.at(0))) {
899
- const firstPrimitiveRow = rows.at(0);
900
- return Array.from({ length: firstPrimitiveRow.length }).map(
901
- (_, idx) => getColumnAlignmentForIndex(idx, columns)
902
- );
903
- }
904
- const biggestRow = [...rows].sort((a, b) => Object.keys(a).length - Object.keys(b).length).at(-1);
905
- if (columns.length > 0) {
906
- return columns.map(
907
- (column, idx) => typeof column === "string" ? column : getColumnAlignmentForKeyAndIndex(
908
- column.key,
909
- idx,
910
- columns
911
- )
912
- );
913
- }
914
- return Object.keys(biggestRow ?? {}).map((_) => "center");
915
- }
916
-
917
- // packages/utils/src/lib/text-formats/html/table.ts
918
- function wrap(elem, content) {
919
- return `<${elem}>${content}</${elem}>${NEW_LINE}`;
920
- }
921
- function wrapRow(content) {
922
- const elem = "tr";
923
- return `<${elem}>${NEW_LINE}${content}</${elem}>${NEW_LINE}`;
924
- }
925
- function table(tableData) {
926
- if (tableData.rows.length === 0) {
927
- throw new Error("Data can't be empty");
928
- }
929
- const tableHeaderCols = columnsToStringArray(tableData).map((s) => wrap("th", s)).join("");
930
- const tableHeaderRow = wrapRow(tableHeaderCols);
931
- const tableBody = rowToStringArray(tableData).map((arr) => {
932
- const columns = arr.map((s) => wrap("td", s)).join("");
933
- return wrapRow(columns);
934
- }).join("");
935
- return wrap("table", `${NEW_LINE}${tableHeaderRow}${tableBody}`);
936
- }
937
-
938
- // packages/utils/src/lib/text-formats/md/font-style.ts
939
- var boldWrap = "**";
940
- function bold2(text) {
941
- return `${boldWrap}${text}${boldWrap}`;
942
- }
943
- var italicWrap = "_";
944
- function italic2(text) {
945
- return `${italicWrap}${text}${italicWrap}`;
946
- }
947
- var strikeThroughWrap = "~";
948
- function strikeThrough(text) {
949
- return `${strikeThroughWrap}${text}${strikeThroughWrap}`;
950
- }
951
- var codeWrap = "`";
952
- function code2(text) {
953
- return `${codeWrap}${text}${codeWrap}`;
954
- }
955
-
956
- // packages/utils/src/lib/text-formats/md/headline.ts
957
- function headline(text, hierarchy = 1) {
958
- return `${"#".repeat(hierarchy)} ${text}${NEW_LINE}`;
959
- }
960
- function h(text, hierarchy = 1) {
961
- return headline(text, hierarchy);
962
- }
963
- function h1(text) {
964
- return headline(text, 1);
965
- }
966
- function h2(text) {
967
- return headline(text, 2);
968
- }
969
- function h3(text) {
970
- return headline(text, 3);
971
- }
972
- function h4(text) {
973
- return headline(text, 4);
974
- }
975
- function h5(text) {
976
- return headline(text, 5);
977
- }
978
- function h6(text) {
979
- return headline(text, 6);
980
- }
981
-
982
- // packages/utils/src/lib/text-formats/md/image.ts
983
- function image(src, alt) {
984
- return `![${alt}](${src})`;
985
- }
986
-
987
- // packages/utils/src/lib/text-formats/md/link.ts
988
- function link2(href, text) {
989
- return `[${text || href}](${href})`;
990
- }
991
-
992
- // packages/utils/src/lib/text-formats/md/list.ts
993
- function li(text, order = "unordered") {
994
- const style = order === "unordered" ? "-" : "- [ ]";
995
- return `${style} ${text}`;
996
- }
997
- function indentation(text, level = 1) {
998
- return `${TAB.repeat(level)}${text}`;
999
- }
1000
-
1001
- // packages/utils/src/lib/text-formats/md/paragraphs.ts
1002
- function paragraphs(...sections) {
1003
- return sections.filter(Boolean).join(`${NEW_LINE}${NEW_LINE}`);
1004
- }
1005
-
1006
- // packages/utils/src/lib/text-formats/md/section.ts
1007
- function section(...contents) {
1008
- return `${lines(...contents)}${NEW_LINE}`;
1009
- }
1010
- function lines(...contents) {
1011
- const filteredContent = contents.filter(
1012
- (value) => value != null && value !== "" && value !== false
1013
- );
1014
- return `${filteredContent.join(NEW_LINE)}`;
1015
- }
1016
-
1017
- // packages/utils/src/lib/text-formats/md/table.ts
1018
- var alignString = /* @__PURE__ */ new Map([
1019
- ["left", ":--"],
1020
- ["center", ":--:"],
1021
- ["right", "--:"]
1022
- ]);
1023
- function tableRow(rows) {
1024
- return `|${rows.join("|")}|`;
1025
- }
1026
- function table2(data) {
1027
- if (data.rows.length === 0) {
1028
- throw new Error("Data can't be empty");
1029
- }
1030
- const alignmentRow = getColumnAlignments(data).map(
1031
- (s) => alignString.get(s) ?? String(alignString.get("center"))
1032
- );
1033
- return section(
1034
- `${lines(
1035
- tableRow(columnsToStringArray(data)),
1036
- tableRow(alignmentRow),
1037
- ...rowToStringArray(data).map(tableRow)
1038
- )}`
1039
- );
1040
- }
1041
-
1042
- // packages/utils/src/lib/text-formats/index.ts
1043
- var md = {
1044
- bold: bold2,
1045
- italic: italic2,
1046
- strikeThrough,
1047
- code: code2,
1048
- link: link2,
1049
- image,
1050
- headline,
1051
- h,
1052
- h1,
1053
- h2,
1054
- h3,
1055
- h4,
1056
- h5,
1057
- h6,
1058
- indentation,
1059
- lines,
1060
- li,
1061
- section,
1062
- paragraphs,
1063
- table: table2
1064
- };
1065
- var html = {
1066
- bold,
1067
- italic,
1068
- code,
1069
- link,
1070
- details,
1071
- table
1072
- };
1073
-
1074
- // packages/utils/src/lib/reports/utils.ts
1075
- var { image: image2, bold: boldMd } = md;
1076
- function calcDuration(start, stop) {
1077
- return Math.round((stop ?? performance.now()) - start);
1078
- }
1079
-
1080
- // packages/utils/src/lib/execute-process.ts
1081
- var ProcessError = class extends Error {
1082
- code;
1083
- stderr;
1084
- stdout;
1085
- constructor(result) {
1086
- super(result.stderr);
1087
- this.code = result.code;
1088
- this.stderr = result.stderr;
1089
- this.stdout = result.stdout;
1090
- }
1091
- };
1092
- function executeProcess(cfg) {
1093
- const { observer, cwd, command, args, ignoreExitCode = false } = cfg;
1094
- const { onStdout, onError, onComplete } = observer ?? {};
1095
- const date = (/* @__PURE__ */ new Date()).toISOString();
1096
- const start = performance.now();
1097
- return new Promise((resolve, reject) => {
1098
- const process2 = spawn(command, args, { cwd, shell: true });
1099
- let stdout = "";
1100
- let stderr = "";
1101
- process2.stdout.on("data", (data) => {
1102
- stdout += String(data);
1103
- onStdout?.(String(data));
1104
- });
1105
- process2.stderr.on("data", (data) => {
1106
- stderr += String(data);
1107
- });
1108
- process2.on("error", (err) => {
1109
- stderr += err.toString();
1110
- });
1111
- process2.on("close", (code3) => {
1112
- const timings = { date, duration: calcDuration(start) };
1113
- if (code3 === 0 || ignoreExitCode) {
1114
- onComplete?.();
1115
- resolve({ code: code3, stdout, stderr, ...timings });
1116
- } else {
1117
- const errorMsg = new ProcessError({ code: code3, stdout, stderr, ...timings });
1118
- onError?.(errorMsg);
1119
- reject(errorMsg);
1120
- }
1121
- });
1122
- });
1123
- }
1124
-
1125
- // packages/utils/src/lib/git/git.ts
1126
- import { simpleGit } from "simple-git";
1127
-
1128
854
  // packages/utils/src/lib/git/git.commits-and-tags.ts
1129
855
  import { simpleGit as simpleGit2 } from "simple-git";
1130
856
 
@@ -1132,34 +858,32 @@ import { simpleGit as simpleGit2 } from "simple-git";
1132
858
  import { rcompare, valid } from "semver";
1133
859
 
1134
860
  // packages/utils/src/lib/progress.ts
1135
- import chalk3 from "chalk";
861
+ import { black, bold as bold2, gray as gray2, green } from "ansis";
1136
862
  import { MultiProgressBars } from "multi-progress-bars";
1137
863
 
864
+ // packages/utils/src/lib/reports/generate-md-report.ts
865
+ import { MarkdownDocument as MarkdownDocument3, md as md4 } from "build-md";
866
+
1138
867
  // packages/utils/src/lib/reports/formatting.ts
1139
- var { headline: headline2, lines: lines2, link: link3, section: section2, table: table3 } = md;
868
+ import {
869
+ MarkdownDocument,
870
+ md as md2
871
+ } from "build-md";
1140
872
 
1141
873
  // packages/utils/src/lib/reports/generate-md-report-categoy-section.ts
1142
- var { link: link4, section: section3, h2: h22, lines: lines3, li: li2, bold: boldMd2, h3: h32, indentation: indentation2 } = md;
1143
-
1144
- // packages/utils/src/lib/reports/generate-md-report.ts
1145
- var { h1: h12, h2: h23, h3: h33, lines: lines4, link: link5, section: section4, code: codeMd } = md;
1146
- var { bold: boldHtml, details: details2 } = html;
874
+ import { MarkdownDocument as MarkdownDocument2, md as md3 } from "build-md";
1147
875
 
1148
876
  // packages/utils/src/lib/reports/generate-md-reports-diff.ts
1149
- var {
1150
- h1: h13,
1151
- h2: h24,
1152
- lines: lines5,
1153
- link: link6,
1154
- bold: boldMd3,
1155
- italic: italicMd,
1156
- table: table4,
1157
- section: section5
1158
- } = md;
1159
- var { details: details3 } = html;
877
+ import {
878
+ MarkdownDocument as MarkdownDocument5,
879
+ md as md6
880
+ } from "build-md";
881
+
882
+ // packages/utils/src/lib/reports/generate-md-reports-diff-utils.ts
883
+ import { MarkdownDocument as MarkdownDocument4, md as md5 } from "build-md";
1160
884
 
1161
885
  // packages/utils/src/lib/reports/log-stdout-summary.ts
1162
- import chalk4 from "chalk";
886
+ import { bold as bold4, cyan, cyanBright, green as green2, red } from "ansis";
1163
887
 
1164
888
  // packages/plugin-coverage/src/lib/runner/constants.ts
1165
889
  import { join as join2 } from "node:path";
@@ -1183,10 +907,10 @@ function mergeLcovResults(records) {
1183
907
  }
1184
908
  return records.reduce((accMerged, currRecord, currIndex) => {
1185
909
  const filePath = currRecord.file;
1186
- const lines6 = currRecord.lines.found;
910
+ const lines = currRecord.lines.found;
1187
911
  const duplicates = records.reduce(
1188
912
  (acc, candidateRecord, candidateIndex) => {
1189
- if (candidateRecord.file === filePath && candidateRecord.lines.found === lines6 && candidateIndex !== currIndex) {
913
+ if (candidateRecord.file === filePath && candidateRecord.lines.found === lines && candidateIndex !== currIndex) {
1190
914
  return [...acc, [candidateRecord, candidateIndex]];
1191
915
  }
1192
916
  return acc;
@@ -1253,8 +977,8 @@ function mergeDuplicateLcovRecords(records) {
1253
977
  };
1254
978
  return mergedRecord;
1255
979
  }
1256
- function mergeLcovLineDetails(details4) {
1257
- const flatDetails = details4.flat();
980
+ function mergeLcovLineDetails(details2) {
981
+ const flatDetails = details2.flat();
1258
982
  const uniqueLines = [
1259
983
  ...new Set(flatDetails.map((flatDetail) => flatDetail.line))
1260
984
  ];
@@ -1263,8 +987,8 @@ function mergeLcovLineDetails(details4) {
1263
987
  return { line, hit: hitSum };
1264
988
  });
1265
989
  }
1266
- function mergeLcovBranchesDetails(details4) {
1267
- const flatDetails = details4.flat();
990
+ function mergeLcovBranchesDetails(details2) {
991
+ const flatDetails = details2.flat();
1268
992
  const uniqueBranches = [
1269
993
  ...new Set(
1270
994
  flatDetails.map(
@@ -1281,8 +1005,8 @@ function mergeLcovBranchesDetails(details4) {
1281
1005
  return { line, block, branch, taken: takenSum };
1282
1006
  });
1283
1007
  }
1284
- function mergeLcovFunctionsDetails(details4) {
1285
- const flatDetails = details4.flat();
1008
+ function mergeLcovFunctionsDetails(details2) {
1009
+ const flatDetails = details2.flat();
1286
1010
  const uniqueFunctions = [
1287
1011
  ...new Set(
1288
1012
  flatDetails.map(({ line, name }) => JSON.stringify({ line, name }))
@@ -1359,8 +1083,8 @@ function removeEmptyReport(record) {
1359
1083
  }
1360
1084
  function lcovReportToLineStat(record) {
1361
1085
  const missingCoverage = record.lines.hit < record.lines.found;
1362
- const lines6 = missingCoverage ? record.lines.details.filter((detail) => !detail.hit).map((detail) => detail.line) : [];
1363
- const linePositions = mergeConsecutiveNumbers(lines6);
1086
+ const lines = missingCoverage ? record.lines.details.filter((detail) => !detail.hit).map((detail) => detail.line) : [];
1087
+ const linePositions = mergeConsecutiveNumbers(lines);
1364
1088
  return {
1365
1089
  totalFound: record.lines.found,
1366
1090
  totalHit: record.lines.hit,
@@ -1496,13 +1220,9 @@ async function executeRunner() {
1496
1220
  await executeProcess({ command, args });
1497
1221
  } catch (error) {
1498
1222
  if (error instanceof ProcessError) {
1499
- ui().logger.error(
1500
- chalk5.bold("stdout from failed coverage tool process:")
1501
- );
1223
+ ui().logger.error(bold5("stdout from failed coverage tool process:"));
1502
1224
  ui().logger.error(error.stdout);
1503
- ui().logger.error(
1504
- chalk5.bold("stderr from failed coverage tool process:")
1505
- );
1225
+ ui().logger.error(bold5("stderr from failed coverage tool process:"));
1506
1226
  ui().logger.error(error.stderr);
1507
1227
  }
1508
1228
  throw new Error(
package/index.js CHANGED
@@ -670,6 +670,8 @@ var auditResultSchema = scorableWithPluginMetaSchema.merge(
670
670
  );
671
671
  var reportsDiffSchema = z15.object({
672
672
  commits: makeComparisonSchema(commitSchema).nullable().describe("Commits identifying compared reports"),
673
+ portalUrl: urlSchema.optional().describe("Link to comparison page in Code PushUp portal"),
674
+ label: z15.string().optional().describe("Label (e.g. project name)"),
673
675
  categories: makeArraysComparisonSchema(
674
676
  categoryDiffSchema,
675
677
  categoryResultSchema,
@@ -697,21 +699,23 @@ var reportsDiffSchema = z15.object({
697
699
  })
698
700
  );
699
701
 
702
+ // packages/utils/src/lib/reports/utils.ts
703
+ import ansis from "ansis";
704
+ import { md } from "build-md";
705
+
706
+ // packages/utils/src/lib/reports/constants.ts
707
+ var TERMINAL_WIDTH = 80;
708
+
700
709
  // packages/utils/src/lib/file-system.ts
710
+ import { bold, gray } from "ansis";
701
711
  import { bundleRequire } from "bundle-require";
702
- import chalk2 from "chalk";
703
712
  import { mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
704
713
  import { join } from "node:path";
705
714
 
706
715
  // packages/utils/src/lib/logging.ts
707
716
  import isaacs_cliui from "@isaacs/cliui";
708
717
  import { cliui } from "@poppinss/cliui";
709
- import chalk from "chalk";
710
-
711
- // packages/utils/src/lib/reports/constants.ts
712
- var TERMINAL_WIDTH = 80;
713
-
714
- // packages/utils/src/lib/logging.ts
718
+ import { underline } from "ansis";
715
719
  var singletonUiInstance;
716
720
  function ui() {
717
721
  if (singletonUiInstance === void 0) {
@@ -761,37 +765,8 @@ function filePathToCliArg(path) {
761
765
  return `"${path}"`;
762
766
  }
763
767
 
764
- // packages/utils/src/lib/text-formats/constants.ts
765
- var NEW_LINE = "\n";
766
- var TAB = " ";
767
-
768
- // packages/utils/src/lib/text-formats/html/details.ts
769
- function details(title, content, cfg = { open: false }) {
770
- 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.
771
- NEW_LINE}${content}${NEW_LINE}${// @TODO in the future we could consider adding it only if the content ends with a code block
772
- // ⚠️ The blank line ensure Markdown in content is rendered correctly.
773
- NEW_LINE}</details>${// ⚠️ The blank line is needed to ensure Markdown after details is rendered correctly.
774
- NEW_LINE}`;
775
- }
776
-
777
- // packages/utils/src/lib/text-formats/html/font-style.ts
778
- var boldElement = "b";
779
- function bold(text) {
780
- return `<${boldElement}>${text}</${boldElement}>`;
781
- }
782
- var italicElement = "i";
783
- function italic(text) {
784
- return `<${italicElement}>${text}</${italicElement}>`;
785
- }
786
- var codeElement = "code";
787
- function code(text) {
788
- return `<${codeElement}>${text}</${codeElement}>`;
789
- }
790
-
791
- // packages/utils/src/lib/text-formats/html/link.ts
792
- function link(href, text) {
793
- return `<a href="${href}">${text || href}</a>`;
794
- }
768
+ // packages/utils/src/lib/git/git.ts
769
+ import { simpleGit } from "simple-git";
795
770
 
796
771
  // packages/utils/src/lib/transform.ts
797
772
  function capitalize(text) {
@@ -800,258 +775,6 @@ function capitalize(text) {
800
775
  )}`;
801
776
  }
802
777
 
803
- // packages/utils/src/lib/text-formats/table.ts
804
- function rowToStringArray({ rows, columns = [] }) {
805
- if (Array.isArray(rows.at(0)) && typeof columns.at(0) === "object") {
806
- throw new TypeError(
807
- "Column can`t be object when rows are primitive values"
808
- );
809
- }
810
- return rows.map((row) => {
811
- if (Array.isArray(row)) {
812
- return row.map(String);
813
- }
814
- const objectRow = row;
815
- if (columns.length === 0 || typeof columns.at(0) === "string") {
816
- return Object.values(objectRow).map(
817
- (value) => value == null ? "" : String(value)
818
- );
819
- }
820
- return columns.map(
821
- ({ key }) => objectRow[key] == null ? "" : String(objectRow[key])
822
- );
823
- });
824
- }
825
- function columnsToStringArray({
826
- rows,
827
- columns = []
828
- }) {
829
- const firstRow = rows.at(0);
830
- const primitiveRows = Array.isArray(firstRow);
831
- if (typeof columns.at(0) === "string" && !primitiveRows) {
832
- throw new Error("invalid union type. Caught by model parsing.");
833
- }
834
- if (columns.length === 0) {
835
- if (Array.isArray(firstRow)) {
836
- return firstRow.map((_, idx) => String(idx));
837
- }
838
- return Object.keys(firstRow);
839
- }
840
- if (typeof columns.at(0) === "string") {
841
- return columns.map(String);
842
- }
843
- const cols = columns;
844
- return cols.map(({ label, key }) => label ?? capitalize(key));
845
- }
846
- function getColumnAlignmentForKeyAndIndex(targetKey, targetIdx, columns = []) {
847
- const column = columns.at(targetIdx) ?? columns.find((col) => col.key === targetKey);
848
- if (typeof column === "string") {
849
- return column;
850
- } else if (typeof column === "object") {
851
- return column.align ?? "center";
852
- } else {
853
- return "center";
854
- }
855
- }
856
- function getColumnAlignmentForIndex(targetIdx, columns = []) {
857
- const column = columns.at(targetIdx);
858
- if (column == null) {
859
- return "center";
860
- } else if (typeof column === "string") {
861
- return column;
862
- } else if (typeof column === "object") {
863
- return column.align ?? "center";
864
- } else {
865
- return "center";
866
- }
867
- }
868
- function getColumnAlignments(tableData) {
869
- const { rows, columns = [] } = tableData;
870
- if (rows.at(0) == null) {
871
- throw new Error("first row can`t be undefined.");
872
- }
873
- if (Array.isArray(rows.at(0))) {
874
- const firstPrimitiveRow = rows.at(0);
875
- return Array.from({ length: firstPrimitiveRow.length }).map(
876
- (_, idx) => getColumnAlignmentForIndex(idx, columns)
877
- );
878
- }
879
- const biggestRow = [...rows].sort((a, b) => Object.keys(a).length - Object.keys(b).length).at(-1);
880
- if (columns.length > 0) {
881
- return columns.map(
882
- (column, idx) => typeof column === "string" ? column : getColumnAlignmentForKeyAndIndex(
883
- column.key,
884
- idx,
885
- columns
886
- )
887
- );
888
- }
889
- return Object.keys(biggestRow ?? {}).map((_) => "center");
890
- }
891
-
892
- // packages/utils/src/lib/text-formats/html/table.ts
893
- function wrap(elem, content) {
894
- return `<${elem}>${content}</${elem}>${NEW_LINE}`;
895
- }
896
- function wrapRow(content) {
897
- const elem = "tr";
898
- return `<${elem}>${NEW_LINE}${content}</${elem}>${NEW_LINE}`;
899
- }
900
- function table(tableData) {
901
- if (tableData.rows.length === 0) {
902
- throw new Error("Data can't be empty");
903
- }
904
- const tableHeaderCols = columnsToStringArray(tableData).map((s) => wrap("th", s)).join("");
905
- const tableHeaderRow = wrapRow(tableHeaderCols);
906
- const tableBody = rowToStringArray(tableData).map((arr) => {
907
- const columns = arr.map((s) => wrap("td", s)).join("");
908
- return wrapRow(columns);
909
- }).join("");
910
- return wrap("table", `${NEW_LINE}${tableHeaderRow}${tableBody}`);
911
- }
912
-
913
- // packages/utils/src/lib/text-formats/md/font-style.ts
914
- var boldWrap = "**";
915
- function bold2(text) {
916
- return `${boldWrap}${text}${boldWrap}`;
917
- }
918
- var italicWrap = "_";
919
- function italic2(text) {
920
- return `${italicWrap}${text}${italicWrap}`;
921
- }
922
- var strikeThroughWrap = "~";
923
- function strikeThrough(text) {
924
- return `${strikeThroughWrap}${text}${strikeThroughWrap}`;
925
- }
926
- var codeWrap = "`";
927
- function code2(text) {
928
- return `${codeWrap}${text}${codeWrap}`;
929
- }
930
-
931
- // packages/utils/src/lib/text-formats/md/headline.ts
932
- function headline(text, hierarchy = 1) {
933
- return `${"#".repeat(hierarchy)} ${text}${NEW_LINE}`;
934
- }
935
- function h(text, hierarchy = 1) {
936
- return headline(text, hierarchy);
937
- }
938
- function h1(text) {
939
- return headline(text, 1);
940
- }
941
- function h2(text) {
942
- return headline(text, 2);
943
- }
944
- function h3(text) {
945
- return headline(text, 3);
946
- }
947
- function h4(text) {
948
- return headline(text, 4);
949
- }
950
- function h5(text) {
951
- return headline(text, 5);
952
- }
953
- function h6(text) {
954
- return headline(text, 6);
955
- }
956
-
957
- // packages/utils/src/lib/text-formats/md/image.ts
958
- function image(src, alt) {
959
- return `![${alt}](${src})`;
960
- }
961
-
962
- // packages/utils/src/lib/text-formats/md/link.ts
963
- function link2(href, text) {
964
- return `[${text || href}](${href})`;
965
- }
966
-
967
- // packages/utils/src/lib/text-formats/md/list.ts
968
- function li(text, order = "unordered") {
969
- const style = order === "unordered" ? "-" : "- [ ]";
970
- return `${style} ${text}`;
971
- }
972
- function indentation(text, level = 1) {
973
- return `${TAB.repeat(level)}${text}`;
974
- }
975
-
976
- // packages/utils/src/lib/text-formats/md/paragraphs.ts
977
- function paragraphs(...sections) {
978
- return sections.filter(Boolean).join(`${NEW_LINE}${NEW_LINE}`);
979
- }
980
-
981
- // packages/utils/src/lib/text-formats/md/section.ts
982
- function section(...contents) {
983
- return `${lines(...contents)}${NEW_LINE}`;
984
- }
985
- function lines(...contents) {
986
- const filteredContent = contents.filter(
987
- (value) => value != null && value !== "" && value !== false
988
- );
989
- return `${filteredContent.join(NEW_LINE)}`;
990
- }
991
-
992
- // packages/utils/src/lib/text-formats/md/table.ts
993
- var alignString = /* @__PURE__ */ new Map([
994
- ["left", ":--"],
995
- ["center", ":--:"],
996
- ["right", "--:"]
997
- ]);
998
- function tableRow(rows) {
999
- return `|${rows.join("|")}|`;
1000
- }
1001
- function table2(data) {
1002
- if (data.rows.length === 0) {
1003
- throw new Error("Data can't be empty");
1004
- }
1005
- const alignmentRow = getColumnAlignments(data).map(
1006
- (s) => alignString.get(s) ?? String(alignString.get("center"))
1007
- );
1008
- return section(
1009
- `${lines(
1010
- tableRow(columnsToStringArray(data)),
1011
- tableRow(alignmentRow),
1012
- ...rowToStringArray(data).map(tableRow)
1013
- )}`
1014
- );
1015
- }
1016
-
1017
- // packages/utils/src/lib/text-formats/index.ts
1018
- var md = {
1019
- bold: bold2,
1020
- italic: italic2,
1021
- strikeThrough,
1022
- code: code2,
1023
- link: link2,
1024
- image,
1025
- headline,
1026
- h,
1027
- h1,
1028
- h2,
1029
- h3,
1030
- h4,
1031
- h5,
1032
- h6,
1033
- indentation,
1034
- lines,
1035
- li,
1036
- section,
1037
- paragraphs,
1038
- table: table2
1039
- };
1040
- var html = {
1041
- bold,
1042
- italic,
1043
- code,
1044
- link,
1045
- details,
1046
- table
1047
- };
1048
-
1049
- // packages/utils/src/lib/reports/utils.ts
1050
- var { image: image2, bold: boldMd } = md;
1051
-
1052
- // packages/utils/src/lib/git/git.ts
1053
- import { simpleGit } from "simple-git";
1054
-
1055
778
  // packages/utils/src/lib/git/git.commits-and-tags.ts
1056
779
  import { simpleGit as simpleGit2 } from "simple-git";
1057
780
 
@@ -1059,38 +782,36 @@ import { simpleGit as simpleGit2 } from "simple-git";
1059
782
  import { rcompare, valid } from "semver";
1060
783
 
1061
784
  // packages/utils/src/lib/progress.ts
1062
- import chalk3 from "chalk";
785
+ import { black, bold as bold2, gray as gray2, green } from "ansis";
1063
786
  import { MultiProgressBars } from "multi-progress-bars";
1064
787
 
788
+ // packages/utils/src/lib/reports/generate-md-report.ts
789
+ import { MarkdownDocument as MarkdownDocument3, md as md4 } from "build-md";
790
+
1065
791
  // packages/utils/src/lib/reports/formatting.ts
1066
- var { headline: headline2, lines: lines2, link: link3, section: section2, table: table3 } = md;
792
+ import {
793
+ MarkdownDocument,
794
+ md as md2
795
+ } from "build-md";
1067
796
 
1068
797
  // packages/utils/src/lib/reports/generate-md-report-categoy-section.ts
1069
- var { link: link4, section: section3, h2: h22, lines: lines3, li: li2, bold: boldMd2, h3: h32, indentation: indentation2 } = md;
1070
-
1071
- // packages/utils/src/lib/reports/generate-md-report.ts
1072
- var { h1: h12, h2: h23, h3: h33, lines: lines4, link: link5, section: section4, code: codeMd } = md;
1073
- var { bold: boldHtml, details: details2 } = html;
798
+ import { MarkdownDocument as MarkdownDocument2, md as md3 } from "build-md";
1074
799
 
1075
800
  // packages/utils/src/lib/reports/generate-md-reports-diff.ts
1076
- var {
1077
- h1: h13,
1078
- h2: h24,
1079
- lines: lines5,
1080
- link: link6,
1081
- bold: boldMd3,
1082
- italic: italicMd,
1083
- table: table4,
1084
- section: section5
1085
- } = md;
1086
- var { details: details3 } = html;
801
+ import {
802
+ MarkdownDocument as MarkdownDocument5,
803
+ md as md6
804
+ } from "build-md";
805
+
806
+ // packages/utils/src/lib/reports/generate-md-reports-diff-utils.ts
807
+ import { MarkdownDocument as MarkdownDocument4, md as md5 } from "build-md";
1087
808
 
1088
809
  // packages/utils/src/lib/reports/log-stdout-summary.ts
1089
- import chalk4 from "chalk";
810
+ import { bold as bold4, cyan, cyanBright, green as green2, red } from "ansis";
1090
811
 
1091
812
  // packages/plugin-coverage/package.json
1092
813
  var name = "@code-pushup/coverage-plugin";
1093
- var version = "0.48.0";
814
+ var version = "0.50.0";
1094
815
 
1095
816
  // packages/plugin-coverage/src/lib/config.ts
1096
817
  import { z as z16 } from "zod";
@@ -1127,7 +848,7 @@ var coveragePluginConfigSchema = z16.object({
1127
848
  });
1128
849
 
1129
850
  // packages/plugin-coverage/src/lib/runner/index.ts
1130
- import chalk5 from "chalk";
851
+ import { bold as bold5 } from "ansis";
1131
852
  import { writeFile } from "node:fs/promises";
1132
853
  import { dirname } from "node:path";
1133
854
 
@@ -1216,12 +937,12 @@ async function coveragePlugin(config) {
1216
937
  }
1217
938
 
1218
939
  // packages/plugin-coverage/src/lib/nx/coverage-paths.ts
1219
- import chalk6 from "chalk";
940
+ import { bold as bold6 } from "ansis";
1220
941
  import { isAbsolute, join as join4 } from "node:path";
1221
942
  async function getNxCoveragePaths(targets = ["test"], verbose) {
1222
943
  if (verbose) {
1223
944
  ui().logger.info(
1224
- chalk6.bold("\u{1F4A1} Gathering coverage from the following nx projects:")
945
+ bold6("\u{1F4A1} Gathering coverage from the following nx projects:")
1225
946
  );
1226
947
  }
1227
948
  const { createProjectGraphAsync } = await import("@nx/devkit");
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@code-pushup/coverage-plugin",
3
- "version": "0.48.0",
3
+ "version": "0.50.0",
4
+ "description": "Code PushUp plugin for tracking code coverage ☂",
4
5
  "dependencies": {
5
- "@code-pushup/models": "0.48.0",
6
- "@code-pushup/utils": "0.48.0",
6
+ "@code-pushup/models": "0.50.0",
7
+ "@code-pushup/utils": "0.50.0",
8
+ "ansis": "^3.3.0",
7
9
  "parse-lcov": "^1.0.4",
8
- "chalk": "^5.3.0",
9
10
  "zod": "^3.22.4"
10
11
  },
11
12
  "peerDependencies": {
@@ -25,7 +26,7 @@
25
26
  }
26
27
  },
27
28
  "license": "MIT",
28
- "homepage": "https://github.com/code-pushup/cli#readme",
29
+ "homepage": "https://github.com/code-pushup/cli/tree/main/packages/plugin-coverage#readme",
29
30
  "bugs": {
30
31
  "url": "https://github.com/code-pushup/cli/issues"
31
32
  },
@@ -34,33 +35,6 @@
34
35
  "url": "git+https://github.com/code-pushup/cli.git",
35
36
  "directory": "packages/plugin-coverage"
36
37
  },
37
- "contributors": [
38
- {
39
- "name": "Igor Katsuba",
40
- "email": "igor@katsuba.dev",
41
- "url": "https://katsuba.dev"
42
- },
43
- {
44
- "name": "Kateřina Pilátová",
45
- "email": "katerina.pilatova@flowup.cz",
46
- "url": "https://github.com/Tlacenka"
47
- },
48
- {
49
- "name": "Matěj Chalk",
50
- "email": "matej.chalk@flowup.cz",
51
- "url": "https://github.com/matejchalk"
52
- },
53
- {
54
- "name": "Michael Hladky",
55
- "email": "michael.hladky@push-based.io",
56
- "url": "https://push-based.io"
57
- },
58
- {
59
- "name": "Michael Seredenko",
60
- "email": "misha.seredenko@push-based.io",
61
- "url": "https://github.com/MishaSeredenkoPushBased"
62
- }
63
- ],
64
38
  "type": "module",
65
39
  "main": "./index.js",
66
40
  "types": "./src/index.d.ts"
@@ -36,7 +36,7 @@ export declare const coveragePluginConfigSchema: z.ZodObject<{
36
36
  }>, z.ZodString]>, "many">;
37
37
  perfectScoreThreshold: z.ZodOptional<z.ZodNumber>;
38
38
  }, "strip", z.ZodTypeAny, {
39
- coverageTypes: ("function" | "line" | "branch")[];
39
+ coverageTypes: ("function" | "branch" | "line")[];
40
40
  reports: (string | {
41
41
  resultsPath: string;
42
42
  pathToProject?: string | undefined;
@@ -55,7 +55,7 @@ export declare const coveragePluginConfigSchema: z.ZodObject<{
55
55
  command: string;
56
56
  args?: string[] | undefined;
57
57
  } | undefined;
58
- coverageTypes?: ("function" | "line" | "branch")[] | undefined;
58
+ coverageTypes?: ("function" | "branch" | "line")[] | undefined;
59
59
  perfectScoreThreshold?: number | undefined;
60
60
  }>;
61
61
  export type CoveragePluginConfig = z.input<typeof coveragePluginConfigSchema>;
@@ -1,5 +1,5 @@
1
1
  import type { PluginConfig } from '@code-pushup/models';
2
- import { CoveragePluginConfig } from './config';
2
+ import { type CoveragePluginConfig } from './config';
3
3
  /**
4
4
  * Instantiates Code PushUp code coverage plugin for core config.
5
5
  *
@@ -1,7 +1,7 @@
1
1
  import type { ProjectConfiguration } from '@nx/devkit';
2
2
  import type { JestExecutorOptions } from '@nx/jest/src/executors/jest/schema';
3
3
  import type { VitestExecutorOptions } from '@nx/vite/executors';
4
- import { CoverageResult } from '../config';
4
+ import type { CoverageResult } from '../config';
5
5
  /**
6
6
  * @param targets nx targets to be used for measuring coverage, test by default
7
7
  * @returns An array of coverage result information for the coverage plugin.
@@ -1,4 +1,4 @@
1
1
  import type { RunnerConfig } from '@code-pushup/models';
2
- import { FinalCoveragePluginConfig } from '../config';
2
+ import type { FinalCoveragePluginConfig } from '../config';
3
3
  export declare function executeRunner(): Promise<void>;
4
4
  export declare function createRunnerConfig(scriptPath: string, config: FinalCoveragePluginConfig): Promise<RunnerConfig>;
@@ -1,6 +1,6 @@
1
1
  import type { LCOVRecord } from 'parse-lcov';
2
- import { AuditOutputs } from '@code-pushup/models';
3
- import { CoverageResult, CoverageType } from '../../config';
2
+ import type { AuditOutputs } from '@code-pushup/models';
3
+ import type { CoverageResult, CoverageType } from '../../config';
4
4
  /**
5
5
  *
6
6
  * @param results Paths to LCOV results
@@ -1,4 +1,4 @@
1
- import { BranchesDetails, FunctionsDetails, LCOVRecord, LinesDetails } from 'parse-lcov';
1
+ import type { BranchesDetails, FunctionsDetails, LCOVRecord, LinesDetails } from 'parse-lcov';
2
2
  export declare function mergeLcovResults(records: LCOVRecord[]): LCOVRecord[];
3
3
  export declare function mergeDuplicateLcovRecords(records: LCOVRecord[]): LCOVRecord;
4
4
  export declare function mergeLcovLineDetails(details: LinesDetails[][]): LinesDetails[];
@@ -1,7 +1,7 @@
1
- import { LCOVRecord } from 'parse-lcov';
2
- import { AuditOutput } from '@code-pushup/models';
3
- import { CoverageType } from '../../config';
4
- import { LCOVStat } from './types';
1
+ import type { LCOVRecord } from 'parse-lcov';
2
+ import type { AuditOutput } from '@code-pushup/models';
3
+ import type { CoverageType } from '../../config';
4
+ import type { LCOVStat } from './types';
5
5
  export declare function lcovReportToFunctionStat(record: LCOVRecord): LCOVStat;
6
6
  export declare function lcovReportToLineStat(record: LCOVRecord): LCOVStat;
7
7
  export declare function lcovReportToBranchStat(record: LCOVRecord): LCOVStat;
@@ -1,5 +1,5 @@
1
1
  import type { Issue } from '@code-pushup/models';
2
- import { CoverageType } from '../../config';
2
+ import type { CoverageType } from '../../config';
3
3
  export type LCOVStat = {
4
4
  totalFound: number;
5
5
  totalHit: number;
@@ -1,4 +1,4 @@
1
- import { NumberRange } from './types';
1
+ import type { NumberRange } from './types';
2
2
  /**
3
3
  * This function calculates coverage as ratio of tested entities vs total
4
4
  * @param hit how many entities were executed in at least one test
@@ -1,5 +1,5 @@
1
1
  import type { AuditOutputs } from '@code-pushup/models';
2
- import { CoverageType } from './config';
2
+ import type { CoverageType } from './config';
3
3
  export declare const coverageDescription: Record<CoverageType, string>;
4
4
  /**
5
5
  * Since more code coverage does not necessarily mean better score, this optional override allows for defining custom coverage goals.