@code-pushup/utils 0.18.1 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +212 -214
- package/package.json +1 -1
- package/src/index.d.ts +3 -3
- package/src/lib/git.d.ts +5 -3
- package/src/lib/transform.d.ts +1 -3
package/index.js
CHANGED
|
@@ -75,25 +75,15 @@ function executionMetaSchema(options = {
|
|
|
75
75
|
duration: z.number({ description: options.descriptionDuration })
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
function docsUrlSchema(description = "Documentation site") {
|
|
89
|
-
return urlSchema(description).optional().or(z.string().max(0));
|
|
90
|
-
}
|
|
91
|
-
function urlSchema(description) {
|
|
92
|
-
return z.string({ description }).url();
|
|
93
|
-
}
|
|
94
|
-
function titleSchema(description = "Descriptive name") {
|
|
95
|
-
return z.string({ description }).max(MAX_TITLE_LENGTH);
|
|
96
|
-
}
|
|
78
|
+
var slugSchema = z.string({ description: "Unique ID (human-readable, URL-safe)" }).regex(slugRegex, {
|
|
79
|
+
message: "The slug has to follow the pattern [0-9a-z] followed by multiple optional groups of -[0-9a-z]. e.g. my-slug"
|
|
80
|
+
}).max(MAX_SLUG_LENGTH, {
|
|
81
|
+
message: `slug can be max ${MAX_SLUG_LENGTH} characters long`
|
|
82
|
+
});
|
|
83
|
+
var descriptionSchema = z.string({ description: "Description (markdown)" }).max(MAX_DESCRIPTION_LENGTH).optional();
|
|
84
|
+
var urlSchema = z.string().url();
|
|
85
|
+
var docsUrlSchema = urlSchema.optional().or(z.literal("")).describe("Documentation site");
|
|
86
|
+
var titleSchema = z.string({ description: "Descriptive name" }).max(MAX_TITLE_LENGTH);
|
|
97
87
|
function metaSchema(options) {
|
|
98
88
|
const {
|
|
99
89
|
descriptionDescription,
|
|
@@ -103,24 +93,19 @@ function metaSchema(options) {
|
|
|
103
93
|
} = options ?? {};
|
|
104
94
|
return z.object(
|
|
105
95
|
{
|
|
106
|
-
title: titleSchema(titleDescription),
|
|
107
|
-
description: descriptionSchema(descriptionDescription),
|
|
108
|
-
docsUrl: docsUrlSchema(docsUrlDescription)
|
|
96
|
+
title: titleDescription ? titleSchema.describe(titleDescription) : titleSchema,
|
|
97
|
+
description: descriptionDescription ? descriptionSchema.describe(descriptionDescription) : descriptionSchema,
|
|
98
|
+
docsUrl: docsUrlDescription ? docsUrlSchema.describe(docsUrlDescription) : docsUrlSchema
|
|
109
99
|
},
|
|
110
100
|
{ description }
|
|
111
101
|
);
|
|
112
102
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}).min(1, { message: "file name is invalid" });
|
|
120
|
-
}
|
|
121
|
-
function positiveIntSchema(description) {
|
|
122
|
-
return z.number({ description }).int().nonnegative();
|
|
123
|
-
}
|
|
103
|
+
var filePathSchema = z.string().trim().min(1, { message: "path is invalid" });
|
|
104
|
+
var fileNameSchema = z.string().trim().regex(filenameRegex, {
|
|
105
|
+
message: `The filename has to be valid`
|
|
106
|
+
}).min(1, { message: "file name is invalid" });
|
|
107
|
+
var positiveIntSchema = z.number().int().positive();
|
|
108
|
+
var nonnegativeIntSchema = z.number().int().nonnegative();
|
|
124
109
|
function packageVersionSchema(options) {
|
|
125
110
|
const { versionDescription = "NPM version of the package", required } = options ?? {};
|
|
126
111
|
const packageSchema = z.string({ description: "NPM package name" });
|
|
@@ -133,14 +118,14 @@ function packageVersionSchema(options) {
|
|
|
133
118
|
{ description: "NPM package name and version of a published package" }
|
|
134
119
|
);
|
|
135
120
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
121
|
+
var weightSchema = nonnegativeIntSchema.describe(
|
|
122
|
+
"Coefficient for the given score (use weight 0 if only for display)"
|
|
123
|
+
);
|
|
139
124
|
function weightedRefSchema(description, slugDescription) {
|
|
140
125
|
return z.object(
|
|
141
126
|
{
|
|
142
|
-
slug: slugSchema(slugDescription),
|
|
143
|
-
weight: weightSchema("Weight used to calculate score")
|
|
127
|
+
slug: slugSchema.describe(slugDescription),
|
|
128
|
+
weight: weightSchema.describe("Weight used to calculate score")
|
|
144
129
|
},
|
|
145
130
|
{ description }
|
|
146
131
|
);
|
|
@@ -148,14 +133,14 @@ function weightedRefSchema(description, slugDescription) {
|
|
|
148
133
|
function scorableSchema(description, refSchema, duplicateCheckFn, duplicateMessageFn) {
|
|
149
134
|
return z.object(
|
|
150
135
|
{
|
|
151
|
-
slug: slugSchema('Human-readable unique ID, e.g. "performance"'),
|
|
136
|
+
slug: slugSchema.describe('Human-readable unique ID, e.g. "performance"'),
|
|
152
137
|
refs: z.array(refSchema).min(1).refine(
|
|
153
138
|
(refs) => !duplicateCheckFn(refs),
|
|
154
139
|
(refs) => ({
|
|
155
140
|
message: duplicateMessageFn(refs)
|
|
156
141
|
})
|
|
157
|
-
).refine(
|
|
158
|
-
message:
|
|
142
|
+
).refine(hasNonZeroWeightedRef, () => ({
|
|
143
|
+
message: "In a category there has to be at least one ref with weight > 0"
|
|
159
144
|
}))
|
|
160
145
|
},
|
|
161
146
|
{ description }
|
|
@@ -164,13 +149,13 @@ function scorableSchema(description, refSchema, duplicateCheckFn, duplicateMessa
|
|
|
164
149
|
var materialIconSchema = z.enum(MATERIAL_ICONS, {
|
|
165
150
|
description: "Icon from VSCode Material Icons extension"
|
|
166
151
|
});
|
|
167
|
-
function
|
|
168
|
-
return
|
|
152
|
+
function hasNonZeroWeightedRef(refs) {
|
|
153
|
+
return refs.reduce((acc, { weight }) => weight + acc, 0) !== 0;
|
|
169
154
|
}
|
|
170
155
|
|
|
171
156
|
// packages/models/src/lib/audit.ts
|
|
172
157
|
var auditSchema = z2.object({
|
|
173
|
-
slug: slugSchema("ID (unique within plugin)")
|
|
158
|
+
slug: slugSchema.describe("ID (unique within plugin)")
|
|
174
159
|
}).merge(
|
|
175
160
|
metaSchema({
|
|
176
161
|
titleDescription: "Descriptive name",
|
|
@@ -197,17 +182,20 @@ function getDuplicateSlugsInAudits(audits) {
|
|
|
197
182
|
return hasDuplicateStrings(audits.map(({ slug }) => slug));
|
|
198
183
|
}
|
|
199
184
|
|
|
200
|
-
// packages/models/src/lib/audit-
|
|
185
|
+
// packages/models/src/lib/audit-output.ts
|
|
186
|
+
import { z as z4 } from "zod";
|
|
187
|
+
|
|
188
|
+
// packages/models/src/lib/issue.ts
|
|
201
189
|
import { z as z3 } from "zod";
|
|
202
190
|
var sourceFileLocationSchema = z3.object(
|
|
203
191
|
{
|
|
204
|
-
file: filePathSchema("Relative path to source file in Git repo"),
|
|
192
|
+
file: filePathSchema.describe("Relative path to source file in Git repo"),
|
|
205
193
|
position: z3.object(
|
|
206
194
|
{
|
|
207
|
-
startLine: positiveIntSchema("Start line"),
|
|
208
|
-
startColumn: positiveIntSchema("Start column").optional(),
|
|
209
|
-
endLine: positiveIntSchema("End line").optional(),
|
|
210
|
-
endColumn: positiveIntSchema("End column").optional()
|
|
195
|
+
startLine: positiveIntSchema.describe("Start line"),
|
|
196
|
+
startColumn: positiveIntSchema.describe("Start column").optional(),
|
|
197
|
+
endLine: positiveIntSchema.describe("End line").optional(),
|
|
198
|
+
endColumn: positiveIntSchema.describe("End column").optional()
|
|
211
199
|
},
|
|
212
200
|
{ description: "Location in file" }
|
|
213
201
|
).optional()
|
|
@@ -227,21 +215,21 @@ var issueSchema = z3.object(
|
|
|
227
215
|
);
|
|
228
216
|
|
|
229
217
|
// packages/models/src/lib/audit-output.ts
|
|
230
|
-
|
|
218
|
+
var auditDetailsSchema = z4.object(
|
|
219
|
+
{
|
|
220
|
+
issues: z4.array(issueSchema, { description: "List of findings" })
|
|
221
|
+
},
|
|
222
|
+
{ description: "Detailed information" }
|
|
223
|
+
);
|
|
231
224
|
var auditOutputSchema = z4.object(
|
|
232
225
|
{
|
|
233
|
-
slug: slugSchema("Reference to audit"),
|
|
226
|
+
slug: slugSchema.describe("Reference to audit"),
|
|
234
227
|
displayValue: z4.string({ description: "Formatted value (e.g. '0.9 s', '2.1 MB')" }).optional(),
|
|
235
|
-
value:
|
|
228
|
+
value: nonnegativeIntSchema.describe("Raw numeric value"),
|
|
236
229
|
score: z4.number({
|
|
237
230
|
description: "Value between 0 and 1"
|
|
238
231
|
}).min(0).max(1),
|
|
239
|
-
details:
|
|
240
|
-
{
|
|
241
|
-
issues: z4.array(issueSchema, { description: "List of findings" })
|
|
242
|
-
},
|
|
243
|
-
{ description: "Detailed information" }
|
|
244
|
-
).optional()
|
|
232
|
+
details: auditDetailsSchema.optional()
|
|
245
233
|
},
|
|
246
234
|
{ description: "Audit information" }
|
|
247
235
|
);
|
|
@@ -271,7 +259,7 @@ var categoryRefSchema = weightedRefSchema(
|
|
|
271
259
|
type: z5.enum(["audit", "group"], {
|
|
272
260
|
description: "Discriminant for reference kind, affects where `slug` is looked up"
|
|
273
261
|
}),
|
|
274
|
-
plugin: slugSchema(
|
|
262
|
+
plugin: slugSchema.describe(
|
|
275
263
|
"Plugin slug (plugin should contain referenced audit or group)"
|
|
276
264
|
)
|
|
277
265
|
})
|
|
@@ -331,10 +319,8 @@ import { z as z11 } from "zod";
|
|
|
331
319
|
import { z as z6 } from "zod";
|
|
332
320
|
var formatSchema = z6.enum(["json", "md"]);
|
|
333
321
|
var persistConfigSchema = z6.object({
|
|
334
|
-
outputDir: filePathSchema("Artifacts folder").optional(),
|
|
335
|
-
filename: fileNameSchema(
|
|
336
|
-
"Artifacts file name (without extension)"
|
|
337
|
-
).optional(),
|
|
322
|
+
outputDir: filePathSchema.describe("Artifacts folder").optional(),
|
|
323
|
+
filename: fileNameSchema.describe("Artifacts file name (without extension)").optional(),
|
|
338
324
|
format: z6.array(formatSchema).optional()
|
|
339
325
|
});
|
|
340
326
|
|
|
@@ -395,7 +381,7 @@ var runnerConfigSchema = z8.object(
|
|
|
395
381
|
description: "Shell command to execute"
|
|
396
382
|
}),
|
|
397
383
|
args: z8.array(z8.string({ description: "Command arguments" })).optional(),
|
|
398
|
-
outputFile: filePathSchema("Output path"),
|
|
384
|
+
outputFile: filePathSchema.describe("Output path"),
|
|
399
385
|
outputTransform: outputTransformSchema.optional()
|
|
400
386
|
},
|
|
401
387
|
{
|
|
@@ -415,7 +401,7 @@ var pluginMetaSchema = packageVersionSchema().merge(
|
|
|
415
401
|
})
|
|
416
402
|
).merge(
|
|
417
403
|
z9.object({
|
|
418
|
-
slug: slugSchema("Unique plugin slug within core config"),
|
|
404
|
+
slug: slugSchema.describe("Unique plugin slug within core config"),
|
|
419
405
|
icon: materialIconSchema
|
|
420
406
|
})
|
|
421
407
|
);
|
|
@@ -448,12 +434,14 @@ function getMissingRefsFromGroups(pluginCfg) {
|
|
|
448
434
|
// packages/models/src/lib/upload-config.ts
|
|
449
435
|
import { z as z10 } from "zod";
|
|
450
436
|
var uploadConfigSchema = z10.object({
|
|
451
|
-
server: urlSchema("URL of deployed portal API"),
|
|
437
|
+
server: urlSchema.describe("URL of deployed portal API"),
|
|
452
438
|
apiKey: z10.string({
|
|
453
439
|
description: "API key with write access to portal (use `process.env` for security)"
|
|
454
440
|
}),
|
|
455
|
-
organization: slugSchema(
|
|
456
|
-
|
|
441
|
+
organization: slugSchema.describe(
|
|
442
|
+
"Organization slug from Code PushUp portal"
|
|
443
|
+
),
|
|
444
|
+
project: slugSchema.describe("Project slug from Code PushUp portal"),
|
|
457
445
|
timeout: z10.number({ description: "Request timeout in minutes (default is 5)" }).positive().int().optional()
|
|
458
446
|
});
|
|
459
447
|
|
|
@@ -1017,16 +1005,140 @@ function executeProcess(cfg) {
|
|
|
1017
1005
|
});
|
|
1018
1006
|
}
|
|
1019
1007
|
|
|
1008
|
+
// packages/utils/src/lib/transform.ts
|
|
1009
|
+
import { platform } from "node:os";
|
|
1010
|
+
function toArray(val) {
|
|
1011
|
+
return Array.isArray(val) ? val : [val];
|
|
1012
|
+
}
|
|
1013
|
+
function objectToKeys(obj) {
|
|
1014
|
+
return Object.keys(obj);
|
|
1015
|
+
}
|
|
1016
|
+
function objectToEntries(obj) {
|
|
1017
|
+
return Object.entries(obj);
|
|
1018
|
+
}
|
|
1019
|
+
function countOccurrences(values) {
|
|
1020
|
+
return values.reduce(
|
|
1021
|
+
(acc, value) => ({ ...acc, [value]: (acc[value] ?? 0) + 1 }),
|
|
1022
|
+
{}
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
function distinct(array) {
|
|
1026
|
+
return [...new Set(array)];
|
|
1027
|
+
}
|
|
1028
|
+
function deepClone(obj) {
|
|
1029
|
+
return obj == null || typeof obj !== "object" ? obj : structuredClone(obj);
|
|
1030
|
+
}
|
|
1031
|
+
function factorOf(items, filterFn) {
|
|
1032
|
+
const itemCount = items.length;
|
|
1033
|
+
if (!itemCount) {
|
|
1034
|
+
return 1;
|
|
1035
|
+
}
|
|
1036
|
+
const filterCount = items.filter(filterFn).length;
|
|
1037
|
+
return filterCount === 0 ? 1 : (itemCount - filterCount) / itemCount;
|
|
1038
|
+
}
|
|
1039
|
+
function objectToCliArgs(params) {
|
|
1040
|
+
if (!params) {
|
|
1041
|
+
return [];
|
|
1042
|
+
}
|
|
1043
|
+
return Object.entries(params).flatMap(([key, value]) => {
|
|
1044
|
+
if (key === "_") {
|
|
1045
|
+
return Array.isArray(value) ? value : [`${value}`];
|
|
1046
|
+
}
|
|
1047
|
+
const prefix = key.length === 1 ? "-" : "--";
|
|
1048
|
+
if (Array.isArray(value)) {
|
|
1049
|
+
return value.map((v) => `${prefix}${key}="${v}"`);
|
|
1050
|
+
}
|
|
1051
|
+
if (Array.isArray(value)) {
|
|
1052
|
+
return value.map((v) => `${prefix}${key}="${v}"`);
|
|
1053
|
+
}
|
|
1054
|
+
if (typeof value === "string") {
|
|
1055
|
+
return [`${prefix}${key}="${value}"`];
|
|
1056
|
+
}
|
|
1057
|
+
if (typeof value === "number") {
|
|
1058
|
+
return [`${prefix}${key}=${value}`];
|
|
1059
|
+
}
|
|
1060
|
+
if (typeof value === "boolean") {
|
|
1061
|
+
return [`${prefix}${value ? "" : "no-"}${key}`];
|
|
1062
|
+
}
|
|
1063
|
+
throw new Error(`Unsupported type ${typeof value} for key ${key}`);
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
function toUnixPath(path) {
|
|
1067
|
+
return path.replace(/\\/g, "/");
|
|
1068
|
+
}
|
|
1069
|
+
function toUnixNewlines(text) {
|
|
1070
|
+
return platform() === "win32" ? text.replace(/\r\n/g, "\n") : text;
|
|
1071
|
+
}
|
|
1072
|
+
function capitalize(text) {
|
|
1073
|
+
return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
|
|
1074
|
+
1
|
|
1075
|
+
)}`;
|
|
1076
|
+
}
|
|
1077
|
+
function toNumberPrecision(value, decimalPlaces) {
|
|
1078
|
+
return Number(
|
|
1079
|
+
`${Math.round(
|
|
1080
|
+
Number.parseFloat(`${value}e${decimalPlaces}`)
|
|
1081
|
+
)}e-${decimalPlaces}`
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
function toOrdinal(value) {
|
|
1085
|
+
if (value % 10 === 1 && value % 100 !== 11) {
|
|
1086
|
+
return `${value}st`;
|
|
1087
|
+
}
|
|
1088
|
+
if (value % 10 === 2 && value % 100 !== 12) {
|
|
1089
|
+
return `${value}nd`;
|
|
1090
|
+
}
|
|
1091
|
+
if (value % 10 === 3 && value % 100 !== 13) {
|
|
1092
|
+
return `${value}rd`;
|
|
1093
|
+
}
|
|
1094
|
+
return `${value}th`;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
// packages/utils/src/lib/filter-by-slug.ts
|
|
1098
|
+
function filterGroupsByAuditSlug(groups, auditSlugs) {
|
|
1099
|
+
const slugs = toArray(auditSlugs);
|
|
1100
|
+
if (slugs.length === 0) {
|
|
1101
|
+
return groups;
|
|
1102
|
+
}
|
|
1103
|
+
return groups.map((group) => ({
|
|
1104
|
+
...group,
|
|
1105
|
+
refs: filterSlug(group.refs, slugs)
|
|
1106
|
+
})).filter((group) => group.refs.length);
|
|
1107
|
+
}
|
|
1108
|
+
function filterAuditsBySlug(list, auditSlugs) {
|
|
1109
|
+
const slugs = toArray(auditSlugs);
|
|
1110
|
+
if (slugs.length === 0) {
|
|
1111
|
+
return list;
|
|
1112
|
+
}
|
|
1113
|
+
return filterSlug(list, slugs);
|
|
1114
|
+
}
|
|
1115
|
+
function filterSlug(refs, slugOrSlugs) {
|
|
1116
|
+
const slugs = toArray(slugOrSlugs);
|
|
1117
|
+
return refs.filter(({ slug }) => slugs.includes(slug));
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1020
1120
|
// packages/utils/src/lib/git.ts
|
|
1121
|
+
import { isAbsolute, join as join3, relative } from "node:path";
|
|
1021
1122
|
import { simpleGit } from "simple-git";
|
|
1022
|
-
|
|
1023
|
-
async function getLatestCommit() {
|
|
1123
|
+
async function getLatestCommit(git = simpleGit()) {
|
|
1024
1124
|
const log = await git.log({
|
|
1025
1125
|
maxCount: 1,
|
|
1026
1126
|
format: { hash: "%H", message: "%s", author: "%an", date: "%ad" }
|
|
1027
1127
|
});
|
|
1028
1128
|
return log.latest;
|
|
1029
1129
|
}
|
|
1130
|
+
function getGitRoot(git = simpleGit()) {
|
|
1131
|
+
return git.revparse("--show-toplevel");
|
|
1132
|
+
}
|
|
1133
|
+
function formatGitPath(path, gitRoot) {
|
|
1134
|
+
const absolutePath = isAbsolute(path) ? path : join3(process.cwd(), path);
|
|
1135
|
+
const relativePath = relative(gitRoot, absolutePath);
|
|
1136
|
+
return toUnixPath(relativePath);
|
|
1137
|
+
}
|
|
1138
|
+
async function toGitPath(path, git = simpleGit()) {
|
|
1139
|
+
const gitRoot = await getGitRoot(git);
|
|
1140
|
+
return formatGitPath(path, gitRoot);
|
|
1141
|
+
}
|
|
1030
1142
|
function validateCommitData(commitData, options = {}) {
|
|
1031
1143
|
const { throwError = false } = options;
|
|
1032
1144
|
if (!commitData) {
|
|
@@ -1049,18 +1161,24 @@ function groupByStatus(results) {
|
|
|
1049
1161
|
);
|
|
1050
1162
|
}
|
|
1051
1163
|
|
|
1052
|
-
// packages/utils/src/lib/
|
|
1164
|
+
// packages/utils/src/lib/logging.ts
|
|
1053
1165
|
import chalk2 from "chalk";
|
|
1166
|
+
function link(text) {
|
|
1167
|
+
return chalk2.underline(chalk2.blueBright(text));
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// packages/utils/src/lib/progress.ts
|
|
1171
|
+
import chalk3 from "chalk";
|
|
1054
1172
|
import { MultiProgressBars } from "multi-progress-bars";
|
|
1055
1173
|
var barStyles = {
|
|
1056
|
-
active: (s) =>
|
|
1057
|
-
done: (s) =>
|
|
1058
|
-
idle: (s) =>
|
|
1174
|
+
active: (s) => chalk3.green(s),
|
|
1175
|
+
done: (s) => chalk3.gray(s),
|
|
1176
|
+
idle: (s) => chalk3.gray(s)
|
|
1059
1177
|
};
|
|
1060
1178
|
var messageStyles = {
|
|
1061
|
-
active: (s) =>
|
|
1062
|
-
done: (s) =>
|
|
1063
|
-
idle: (s) =>
|
|
1179
|
+
active: (s) => chalk3.black(s),
|
|
1180
|
+
done: (s) => chalk3.green(chalk3.bold(s)),
|
|
1181
|
+
idle: (s) => chalk3.gray(s)
|
|
1064
1182
|
};
|
|
1065
1183
|
var mpb;
|
|
1066
1184
|
function getSingletonProgressBars(options) {
|
|
@@ -1140,7 +1258,7 @@ function h3(text) {
|
|
|
1140
1258
|
}
|
|
1141
1259
|
|
|
1142
1260
|
// packages/utils/src/lib/reports/md/link.ts
|
|
1143
|
-
function
|
|
1261
|
+
function link2(href, text) {
|
|
1144
1262
|
return `[${text || href}](${href})`;
|
|
1145
1263
|
}
|
|
1146
1264
|
|
|
@@ -1191,7 +1309,7 @@ function generateMdReport(report, commitData) {
|
|
|
1191
1309
|
(printCategories ? reportToCategoriesSection(report) + NEW_LINE + NEW_LINE : "") + // audits section
|
|
1192
1310
|
reportToAuditsSection(report) + NEW_LINE + NEW_LINE + // about section
|
|
1193
1311
|
reportToAboutSection(report, commitData) + NEW_LINE + NEW_LINE + // footer section
|
|
1194
|
-
`${FOOTER_PREFIX} ${
|
|
1312
|
+
`${FOOTER_PREFIX} ${link2(README_LINK, "Code PushUp")}`
|
|
1195
1313
|
);
|
|
1196
1314
|
}
|
|
1197
1315
|
function reportToHeaderSection() {
|
|
@@ -1202,7 +1320,7 @@ function reportToOverviewSection(report) {
|
|
|
1202
1320
|
const tableContent = [
|
|
1203
1321
|
reportOverviewTableHeaders,
|
|
1204
1322
|
...categories.map(({ title, refs, score }) => [
|
|
1205
|
-
|
|
1323
|
+
link2(`#${slugify(title)}`, title),
|
|
1206
1324
|
`${getRoundScoreMarker(score)} ${style(formatReportScore(score))}`,
|
|
1207
1325
|
countCategoryAudits(refs, plugins).toString()
|
|
1208
1326
|
])
|
|
@@ -1234,7 +1352,7 @@ function reportToCategoriesSection(report) {
|
|
|
1234
1352
|
}
|
|
1235
1353
|
function auditItemToCategorySection(audit, plugins) {
|
|
1236
1354
|
const pluginTitle = getPluginNameFromSlug(audit.plugin, plugins);
|
|
1237
|
-
const auditTitle =
|
|
1355
|
+
const auditTitle = link2(
|
|
1238
1356
|
`#${slugify(audit.title)}-${slugify(pluginTitle)}`,
|
|
1239
1357
|
audit.title
|
|
1240
1358
|
);
|
|
@@ -1251,7 +1369,7 @@ function groupItemToCategorySection(group, plugins) {
|
|
|
1251
1369
|
`${getRoundScoreMarker(groupScore)} ${group.title} (_${pluginTitle}_)`
|
|
1252
1370
|
);
|
|
1253
1371
|
const groupAudits = group.audits.reduce((acc, audit) => {
|
|
1254
|
-
const auditTitle =
|
|
1372
|
+
const auditTitle = link2(
|
|
1255
1373
|
`#${slugify(audit.title)}-${slugify(pluginTitle)}`,
|
|
1256
1374
|
audit.title
|
|
1257
1375
|
);
|
|
@@ -1338,7 +1456,7 @@ function getDocsAndDescription({
|
|
|
1338
1456
|
description
|
|
1339
1457
|
}) {
|
|
1340
1458
|
if (docsUrl) {
|
|
1341
|
-
const docsLink =
|
|
1459
|
+
const docsLink = link2(docsUrl, "\u{1F4D6} Docs");
|
|
1342
1460
|
if (!description) {
|
|
1343
1461
|
return docsLink + NEW_LINE + NEW_LINE;
|
|
1344
1462
|
}
|
|
@@ -1359,7 +1477,7 @@ function getAuditResult(audit, isHtml = false) {
|
|
|
1359
1477
|
|
|
1360
1478
|
// packages/utils/src/lib/reports/generate-stdout-summary.ts
|
|
1361
1479
|
import cliui from "@isaacs/cliui";
|
|
1362
|
-
import
|
|
1480
|
+
import chalk4 from "chalk";
|
|
1363
1481
|
import CliTable3 from "cli-table3";
|
|
1364
1482
|
function addLine(line = "") {
|
|
1365
1483
|
return line + NEW_LINE;
|
|
@@ -1370,7 +1488,7 @@ function generateStdoutSummary(report) {
|
|
|
1370
1488
|
}
|
|
1371
1489
|
function reportToHeaderSection2(report) {
|
|
1372
1490
|
const { packageName, version } = report;
|
|
1373
|
-
return `${
|
|
1491
|
+
return `${chalk4.bold(reportHeadlineText)} - ${packageName}@${version}`;
|
|
1374
1492
|
}
|
|
1375
1493
|
function reportToDetailSection(report) {
|
|
1376
1494
|
const { plugins } = report;
|
|
@@ -1390,13 +1508,13 @@ function reportToDetailSection(report) {
|
|
|
1390
1508
|
padding: [0, 3, 0, 0]
|
|
1391
1509
|
},
|
|
1392
1510
|
{
|
|
1393
|
-
text:
|
|
1511
|
+
text: chalk4.cyanBright(audit.displayValue || `${audit.value}`),
|
|
1394
1512
|
width: 10,
|
|
1395
1513
|
padding: [0, 0, 0, 0]
|
|
1396
1514
|
}
|
|
1397
1515
|
);
|
|
1398
1516
|
});
|
|
1399
|
-
return acc + addLine() + addLine(
|
|
1517
|
+
return acc + addLine() + addLine(chalk4.magentaBright.bold(`${title} audits`)) + addLine() + addLine(ui.toString()) + addLine();
|
|
1400
1518
|
}, "");
|
|
1401
1519
|
}
|
|
1402
1520
|
function reportToOverviewSection2({
|
|
@@ -1419,11 +1537,11 @@ function reportToOverviewSection2({
|
|
|
1419
1537
|
countCategoryAudits(refs, plugins)
|
|
1420
1538
|
])
|
|
1421
1539
|
);
|
|
1422
|
-
return addLine(
|
|
1540
|
+
return addLine(chalk4.magentaBright.bold("Categories")) + addLine() + addLine(table.toString());
|
|
1423
1541
|
}
|
|
1424
1542
|
function withColor({ score, text }) {
|
|
1425
1543
|
const formattedScore = text ?? formatReportScore(score);
|
|
1426
|
-
const style2 = text ?
|
|
1544
|
+
const style2 = text ? chalk4 : chalk4.bold;
|
|
1427
1545
|
if (score >= SCORE_COLOR_RANGE.GREEN_MIN) {
|
|
1428
1546
|
return style2.green(formattedScore);
|
|
1429
1547
|
}
|
|
@@ -1433,99 +1551,6 @@ function withColor({ score, text }) {
|
|
|
1433
1551
|
return style2.red(formattedScore);
|
|
1434
1552
|
}
|
|
1435
1553
|
|
|
1436
|
-
// packages/utils/src/lib/transform.ts
|
|
1437
|
-
import { platform } from "node:os";
|
|
1438
|
-
function toArray(val) {
|
|
1439
|
-
return Array.isArray(val) ? val : [val];
|
|
1440
|
-
}
|
|
1441
|
-
function objectToKeys(obj) {
|
|
1442
|
-
return Object.keys(obj);
|
|
1443
|
-
}
|
|
1444
|
-
function objectToEntries(obj) {
|
|
1445
|
-
return Object.entries(obj);
|
|
1446
|
-
}
|
|
1447
|
-
function countOccurrences(values) {
|
|
1448
|
-
return values.reduce(
|
|
1449
|
-
(acc, value) => ({ ...acc, [value]: (acc[value] ?? 0) + 1 }),
|
|
1450
|
-
{}
|
|
1451
|
-
);
|
|
1452
|
-
}
|
|
1453
|
-
function distinct(array) {
|
|
1454
|
-
return [...new Set(array)];
|
|
1455
|
-
}
|
|
1456
|
-
function deepClone(obj) {
|
|
1457
|
-
return obj == null || typeof obj !== "object" ? obj : structuredClone(obj);
|
|
1458
|
-
}
|
|
1459
|
-
function factorOf(items, filterFn) {
|
|
1460
|
-
const itemCount = items.length;
|
|
1461
|
-
if (!itemCount) {
|
|
1462
|
-
return 1;
|
|
1463
|
-
}
|
|
1464
|
-
const filterCount = items.filter(filterFn).length;
|
|
1465
|
-
return filterCount === 0 ? 1 : (itemCount - filterCount) / itemCount;
|
|
1466
|
-
}
|
|
1467
|
-
function objectToCliArgs(params) {
|
|
1468
|
-
if (!params) {
|
|
1469
|
-
return [];
|
|
1470
|
-
}
|
|
1471
|
-
return Object.entries(params).flatMap(([key, value]) => {
|
|
1472
|
-
if (key === "_") {
|
|
1473
|
-
return Array.isArray(value) ? value : [`${value}`];
|
|
1474
|
-
}
|
|
1475
|
-
const prefix = key.length === 1 ? "-" : "--";
|
|
1476
|
-
if (Array.isArray(value)) {
|
|
1477
|
-
return value.map((v) => `${prefix}${key}="${v}"`);
|
|
1478
|
-
}
|
|
1479
|
-
if (Array.isArray(value)) {
|
|
1480
|
-
return value.map((v) => `${prefix}${key}="${v}"`);
|
|
1481
|
-
}
|
|
1482
|
-
if (typeof value === "string") {
|
|
1483
|
-
return [`${prefix}${key}="${value}"`];
|
|
1484
|
-
}
|
|
1485
|
-
if (typeof value === "number") {
|
|
1486
|
-
return [`${prefix}${key}=${value}`];
|
|
1487
|
-
}
|
|
1488
|
-
if (typeof value === "boolean") {
|
|
1489
|
-
return [`${prefix}${value ? "" : "no-"}${key}`];
|
|
1490
|
-
}
|
|
1491
|
-
throw new Error(`Unsupported type ${typeof value} for key ${key}`);
|
|
1492
|
-
});
|
|
1493
|
-
}
|
|
1494
|
-
function toUnixPath(path, options) {
|
|
1495
|
-
const unixPath = path.replace(/\\/g, "/");
|
|
1496
|
-
if (options?.toRelative) {
|
|
1497
|
-
return unixPath.replace(`${process.cwd().replace(/\\/g, "/")}/`, "");
|
|
1498
|
-
}
|
|
1499
|
-
return unixPath;
|
|
1500
|
-
}
|
|
1501
|
-
function toUnixNewlines(text) {
|
|
1502
|
-
return platform() === "win32" ? text.replace(/\r\n/g, "\n") : text;
|
|
1503
|
-
}
|
|
1504
|
-
function capitalize(text) {
|
|
1505
|
-
return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
|
|
1506
|
-
1
|
|
1507
|
-
)}`;
|
|
1508
|
-
}
|
|
1509
|
-
function toNumberPrecision(value, decimalPlaces) {
|
|
1510
|
-
return Number(
|
|
1511
|
-
`${Math.round(
|
|
1512
|
-
Number.parseFloat(`${value}e${decimalPlaces}`)
|
|
1513
|
-
)}e-${decimalPlaces}`
|
|
1514
|
-
);
|
|
1515
|
-
}
|
|
1516
|
-
function toOrdinal(value) {
|
|
1517
|
-
if (value % 10 === 1 && value % 100 !== 11) {
|
|
1518
|
-
return `${value}st`;
|
|
1519
|
-
}
|
|
1520
|
-
if (value % 10 === 2 && value % 100 !== 12) {
|
|
1521
|
-
return `${value}nd`;
|
|
1522
|
-
}
|
|
1523
|
-
if (value % 10 === 3 && value % 100 !== 13) {
|
|
1524
|
-
return `${value}rd`;
|
|
1525
|
-
}
|
|
1526
|
-
return `${value}th`;
|
|
1527
|
-
}
|
|
1528
|
-
|
|
1529
1554
|
// packages/utils/src/lib/reports/scoring.ts
|
|
1530
1555
|
var GroupRefInvalidError = class extends Error {
|
|
1531
1556
|
constructor(auditSlug, pluginSlug) {
|
|
@@ -1685,35 +1710,6 @@ var verboseUtils = (verbose = false) => ({
|
|
|
1685
1710
|
log: getLogVerbose(verbose),
|
|
1686
1711
|
exec: getExecVerbose(verbose)
|
|
1687
1712
|
});
|
|
1688
|
-
|
|
1689
|
-
// packages/utils/src/lib/logging.ts
|
|
1690
|
-
import chalk4 from "chalk";
|
|
1691
|
-
function link2(text) {
|
|
1692
|
-
return chalk4.underline(chalk4.blueBright(text));
|
|
1693
|
-
}
|
|
1694
|
-
|
|
1695
|
-
// packages/utils/src/lib/filter-by-slug.ts
|
|
1696
|
-
function filterGroupsByAuditSlug(groups, auditSlugs) {
|
|
1697
|
-
const slugs = toArray(auditSlugs);
|
|
1698
|
-
if (slugs.length === 0) {
|
|
1699
|
-
return groups;
|
|
1700
|
-
}
|
|
1701
|
-
return groups.map((group) => ({
|
|
1702
|
-
...group,
|
|
1703
|
-
refs: filterSlug(group.refs, slugs)
|
|
1704
|
-
})).filter((group) => group.refs.length);
|
|
1705
|
-
}
|
|
1706
|
-
function filterAuditsBySlug(list, auditSlugs) {
|
|
1707
|
-
const slugs = toArray(auditSlugs);
|
|
1708
|
-
if (slugs.length === 0) {
|
|
1709
|
-
return list;
|
|
1710
|
-
}
|
|
1711
|
-
return filterSlug(list, slugs);
|
|
1712
|
-
}
|
|
1713
|
-
function filterSlug(refs, slugOrSlugs) {
|
|
1714
|
-
const slugs = toArray(slugOrSlugs);
|
|
1715
|
-
return refs.filter(({ slug }) => slugs.includes(slug));
|
|
1716
|
-
}
|
|
1717
1713
|
export {
|
|
1718
1714
|
CODE_PUSHUP_DOMAIN,
|
|
1719
1715
|
FOOTER_PREFIX,
|
|
@@ -1737,16 +1733,17 @@ export {
|
|
|
1737
1733
|
findLineNumberInText,
|
|
1738
1734
|
formatBytes,
|
|
1739
1735
|
formatDuration,
|
|
1736
|
+
formatGitPath,
|
|
1740
1737
|
generateMdReport,
|
|
1741
1738
|
generateStdoutSummary,
|
|
1739
|
+
getGitRoot,
|
|
1742
1740
|
getLatestCommit,
|
|
1743
1741
|
getProgressBar,
|
|
1744
|
-
git,
|
|
1745
1742
|
groupByStatus,
|
|
1746
1743
|
importEsmModule,
|
|
1747
1744
|
isPromiseFulfilledResult,
|
|
1748
1745
|
isPromiseRejectedResult,
|
|
1749
|
-
|
|
1746
|
+
link,
|
|
1750
1747
|
loadReport,
|
|
1751
1748
|
logMultipleFileResults,
|
|
1752
1749
|
logMultipleResults,
|
|
@@ -1764,6 +1761,7 @@ export {
|
|
|
1764
1761
|
slugify,
|
|
1765
1762
|
sortReport,
|
|
1766
1763
|
toArray,
|
|
1764
|
+
toGitPath,
|
|
1767
1765
|
toNumberPrecision,
|
|
1768
1766
|
toOrdinal,
|
|
1769
1767
|
toUnixNewlines,
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
export { exists } from '@code-pushup/models';
|
|
2
2
|
export { ProcessConfig, ProcessError, ProcessObserver, ProcessResult, executeProcess, } from './lib/execute-process';
|
|
3
3
|
export { CrawlFileSystemOptions, FileResult, MultipleFileResults, crawlFileSystem, directoryExists, ensureDirectoryExists, fileExists, findLineNumberInText, importEsmModule, logMultipleFileResults, pluginWorkDir, readJsonFile, readTextFile, removeDirectoryIfExists, } from './lib/file-system';
|
|
4
|
+
export { filterAuditsBySlug, filterGroupsByAuditSlug, } from './lib/filter-by-slug';
|
|
4
5
|
export { formatBytes, formatDuration, pluralize, pluralizeToken, slugify, truncateDescription, truncateIssueMessage, truncateText, truncateTitle, } from './lib/formatting';
|
|
5
|
-
export { getLatestCommit,
|
|
6
|
+
export { formatGitPath, getGitRoot, getLatestCommit, toGitPath, validateCommitData, } from './lib/git';
|
|
6
7
|
export { groupByStatus } from './lib/group-by-status';
|
|
7
8
|
export { isPromiseFulfilledResult, isPromiseRejectedResult, } from './lib/guards';
|
|
8
9
|
export { logMultipleResults } from './lib/log-results';
|
|
10
|
+
export { link } from './lib/logging';
|
|
9
11
|
export { ProgressBar, getProgressBar } from './lib/progress';
|
|
10
12
|
export { TERMINAL_WIDTH } from './lib/reports/constants';
|
|
11
13
|
export { generateMdReport } from './lib/reports/generate-md-report';
|
|
@@ -15,5 +17,3 @@ export { sortReport } from './lib/reports/sorting';
|
|
|
15
17
|
export { CODE_PUSHUP_DOMAIN, FOOTER_PREFIX, README_LINK, calcDuration, compareIssueSeverity, loadReport, portalCommitDashboardLink, } from './lib/reports/utils';
|
|
16
18
|
export { CliArgsObject, capitalize, countOccurrences, distinct, factorOf, objectToCliArgs, objectToEntries, objectToKeys, toArray, toNumberPrecision, toOrdinal, toUnixNewlines, toUnixPath, } from './lib/transform';
|
|
17
19
|
export { verboseUtils } from './lib/verbose-utils';
|
|
18
|
-
export { link } from './lib/logging';
|
|
19
|
-
export { filterAuditsBySlug, filterGroupsByAuditSlug, } from './lib/filter-by-slug';
|
package/src/lib/git.d.ts
CHANGED
|
@@ -4,13 +4,15 @@ export type CommitData = {
|
|
|
4
4
|
author: string;
|
|
5
5
|
date: string;
|
|
6
6
|
};
|
|
7
|
-
export declare
|
|
8
|
-
export declare function getLatestCommit(): Promise<({
|
|
7
|
+
export declare function getLatestCommit(git?: import("simple-git").SimpleGit): Promise<({
|
|
9
8
|
hash: string;
|
|
10
9
|
message: string;
|
|
11
10
|
author: string;
|
|
12
11
|
date: string;
|
|
13
12
|
} & import("simple-git").ListLogLine) | null>;
|
|
14
|
-
export declare function
|
|
13
|
+
export declare function getGitRoot(git?: import("simple-git").SimpleGit): Promise<string>;
|
|
14
|
+
export declare function formatGitPath(path: string, gitRoot: string): string;
|
|
15
|
+
export declare function toGitPath(path: string, git?: import("simple-git").SimpleGit): Promise<string>;
|
|
16
|
+
export declare function validateCommitData(commitData: CommitData | null, options?: {
|
|
15
17
|
throwError?: boolean;
|
|
16
18
|
}): commitData is CommitData;
|
package/src/lib/transform.d.ts
CHANGED
|
@@ -22,9 +22,7 @@ Record<string, ArgumentValue | undefined> | {
|
|
|
22
22
|
* });
|
|
23
23
|
*/
|
|
24
24
|
export declare function objectToCliArgs<T extends object = Record<string, ArgumentValue>>(params?: CliArgsObject<T>): string[];
|
|
25
|
-
export declare function toUnixPath(path: string
|
|
26
|
-
toRelative?: boolean;
|
|
27
|
-
}): string;
|
|
25
|
+
export declare function toUnixPath(path: string): string;
|
|
28
26
|
export declare function toUnixNewlines(text: string): string;
|
|
29
27
|
export declare function capitalize<T extends string>(text: T): Capitalize<T>;
|
|
30
28
|
export declare function toNumberPrecision(value: number, decimalPlaces: number): number;
|