@code-pushup/coverage-plugin 0.44.4 → 0.45.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/bin.js +506 -355
- package/index.js +981 -970
- package/package.json +3 -3
- package/src/lib/nx/coverage-paths.d.ts +6 -1
- package/src/lib/runner/constants.d.ts +1 -0
- package/src/lib/runner/lcov/lcov-runner.d.ts +7 -0
- package/src/lib/runner/lcov/merge-lcov.d.ts +6 -0
package/index.js
CHANGED
|
@@ -2,1041 +2,1045 @@
|
|
|
2
2
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
|
|
5
|
-
// packages/
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
// packages/models/src/lib/implementation/schemas.ts
|
|
6
|
+
import { MATERIAL_ICONS } from "vscode-material-icons";
|
|
7
|
+
import { z } from "zod";
|
|
8
8
|
|
|
9
|
-
// packages/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
NEW_LINE}</details>${// ⚠️ The blank line is needed to ensure Markdown after details is rendered correctly.
|
|
15
|
-
NEW_LINE}`;
|
|
16
|
-
}
|
|
9
|
+
// packages/models/src/lib/implementation/limits.ts
|
|
10
|
+
var MAX_SLUG_LENGTH = 128;
|
|
11
|
+
var MAX_TITLE_LENGTH = 256;
|
|
12
|
+
var MAX_DESCRIPTION_LENGTH = 65536;
|
|
13
|
+
var MAX_ISSUE_MESSAGE_LENGTH = 1024;
|
|
17
14
|
|
|
18
|
-
// packages/
|
|
19
|
-
var
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
// packages/models/src/lib/implementation/utils.ts
|
|
16
|
+
var slugRegex = /^[a-z\d]+(?:-[a-z\d]+)*$/;
|
|
17
|
+
var filenameRegex = /^(?!.*[ \\/:*?"<>|]).+$/;
|
|
18
|
+
function hasDuplicateStrings(strings) {
|
|
19
|
+
const sortedStrings = [...strings].sort();
|
|
20
|
+
const duplStrings = sortedStrings.filter(
|
|
21
|
+
(item, index) => index !== 0 && item === sortedStrings[index - 1]
|
|
22
|
+
);
|
|
23
|
+
return duplStrings.length === 0 ? false : [...new Set(duplStrings)];
|
|
22
24
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return
|
|
25
|
+
function hasMissingStrings(toCheck, existing) {
|
|
26
|
+
const nonExisting = toCheck.filter((s) => !existing.includes(s));
|
|
27
|
+
return nonExisting.length === 0 ? false : nonExisting;
|
|
26
28
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return `<${codeElement}>${text}</${codeElement}>`;
|
|
29
|
+
function errorItems(items, transform = (itemArr) => itemArr.join(", ")) {
|
|
30
|
+
return transform(items || []);
|
|
30
31
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
function link(href, text) {
|
|
34
|
-
return `<a href="${href}">${text || href}"</a>`;
|
|
32
|
+
function exists(value) {
|
|
33
|
+
return value != null;
|
|
35
34
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
function getMissingRefsForCategories(categories, plugins) {
|
|
36
|
+
if (categories.length === 0) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
const auditRefsFromCategory = categories.flatMap(
|
|
40
|
+
({ refs }) => refs.filter(({ type }) => type === "audit").map(({ plugin, slug }) => `${plugin}/${slug}`)
|
|
41
|
+
);
|
|
42
|
+
const auditRefsFromPlugins = plugins.flatMap(
|
|
43
|
+
({ audits, slug: pluginSlug }) => audits.map(({ slug }) => `${pluginSlug}/${slug}`)
|
|
44
|
+
);
|
|
45
|
+
const missingAuditRefs = hasMissingStrings(
|
|
46
|
+
auditRefsFromCategory,
|
|
47
|
+
auditRefsFromPlugins
|
|
48
|
+
);
|
|
49
|
+
const groupRefsFromCategory = categories.flatMap(
|
|
50
|
+
({ refs }) => refs.filter(({ type }) => type === "group").map(({ plugin, slug }) => `${plugin}#${slug} (group)`)
|
|
51
|
+
);
|
|
52
|
+
const groupRefsFromPlugins = plugins.flatMap(
|
|
53
|
+
({ groups, slug: pluginSlug }) => Array.isArray(groups) ? groups.map(({ slug }) => `${pluginSlug}#${slug} (group)`) : []
|
|
54
|
+
);
|
|
55
|
+
const missingGroupRefs = hasMissingStrings(
|
|
56
|
+
groupRefsFromCategory,
|
|
57
|
+
groupRefsFromPlugins
|
|
58
|
+
);
|
|
59
|
+
const missingRefs = [missingAuditRefs, missingGroupRefs].filter((refs) => Array.isArray(refs) && refs.length > 0).flat();
|
|
60
|
+
return missingRefs.length > 0 ? missingRefs : false;
|
|
61
|
+
}
|
|
62
|
+
function missingRefsForCategoriesErrorMsg(categories, plugins) {
|
|
63
|
+
const missingRefs = getMissingRefsForCategories(categories, plugins);
|
|
64
|
+
return `The following category references need to point to an audit or group: ${errorItems(
|
|
65
|
+
missingRefs
|
|
41
66
|
)}`;
|
|
42
67
|
}
|
|
43
68
|
|
|
44
|
-
// packages/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return row.map(String);
|
|
54
|
-
}
|
|
55
|
-
const objectRow = row;
|
|
56
|
-
if (columns.length === 0 || typeof columns.at(0) === "string") {
|
|
57
|
-
return Object.values(objectRow).map(String);
|
|
58
|
-
}
|
|
59
|
-
return columns.map(
|
|
60
|
-
({ key }) => String(objectRow[key])
|
|
61
|
-
);
|
|
69
|
+
// packages/models/src/lib/implementation/schemas.ts
|
|
70
|
+
var primitiveValueSchema = z.union([z.string(), z.number()]);
|
|
71
|
+
function executionMetaSchema(options = {
|
|
72
|
+
descriptionDate: "Execution start date and time",
|
|
73
|
+
descriptionDuration: "Execution duration in ms"
|
|
74
|
+
}) {
|
|
75
|
+
return z.object({
|
|
76
|
+
date: z.string({ description: options.descriptionDate }),
|
|
77
|
+
duration: z.number({ description: options.descriptionDuration })
|
|
62
78
|
});
|
|
63
79
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
80
|
+
var slugSchema = z.string({ description: "Unique ID (human-readable, URL-safe)" }).regex(slugRegex, {
|
|
81
|
+
message: "The slug has to follow the pattern [0-9a-z] followed by multiple optional groups of -[0-9a-z]. e.g. my-slug"
|
|
82
|
+
}).max(MAX_SLUG_LENGTH, {
|
|
83
|
+
message: `slug can be max ${MAX_SLUG_LENGTH} characters long`
|
|
84
|
+
});
|
|
85
|
+
var descriptionSchema = z.string({ description: "Description (markdown)" }).max(MAX_DESCRIPTION_LENGTH).optional();
|
|
86
|
+
var urlSchema = z.string().url();
|
|
87
|
+
var docsUrlSchema = urlSchema.optional().or(z.literal("")).describe("Documentation site");
|
|
88
|
+
var titleSchema = z.string({ description: "Descriptive name" }).max(MAX_TITLE_LENGTH);
|
|
89
|
+
var scoreSchema = z.number({
|
|
90
|
+
description: "Value between 0 and 1"
|
|
91
|
+
}).min(0).max(1);
|
|
92
|
+
function metaSchema(options) {
|
|
93
|
+
const {
|
|
94
|
+
descriptionDescription,
|
|
95
|
+
titleDescription,
|
|
96
|
+
docsUrlDescription,
|
|
97
|
+
description
|
|
98
|
+
} = options ?? {};
|
|
99
|
+
return z.object(
|
|
100
|
+
{
|
|
101
|
+
title: titleDescription ? titleSchema.describe(titleDescription) : titleSchema,
|
|
102
|
+
description: descriptionDescription ? descriptionSchema.describe(descriptionDescription) : descriptionSchema,
|
|
103
|
+
docsUrl: docsUrlDescription ? docsUrlSchema.describe(docsUrlDescription) : docsUrlSchema
|
|
104
|
+
},
|
|
105
|
+
{ description }
|
|
106
|
+
);
|
|
91
107
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
}
|
|
108
|
+
var filePathSchema = z.string().trim().min(1, { message: "path is invalid" });
|
|
109
|
+
var fileNameSchema = z.string().trim().regex(filenameRegex, {
|
|
110
|
+
message: `The filename has to be valid`
|
|
111
|
+
}).min(1, { message: "file name is invalid" });
|
|
112
|
+
var positiveIntSchema = z.number().int().positive();
|
|
113
|
+
var nonnegativeIntSchema = z.number().int().nonnegative();
|
|
114
|
+
var nonnegativeNumberSchema = z.number().nonnegative();
|
|
115
|
+
function packageVersionSchema(options) {
|
|
116
|
+
const { versionDescription = "NPM version of the package", required } = options ?? {};
|
|
117
|
+
const packageSchema = z.string({ description: "NPM package name" });
|
|
118
|
+
const versionSchema = z.string({ description: versionDescription });
|
|
119
|
+
return z.object(
|
|
120
|
+
{
|
|
121
|
+
packageName: required ? packageSchema : packageSchema.optional(),
|
|
122
|
+
version: required ? versionSchema : versionSchema.optional()
|
|
123
|
+
},
|
|
124
|
+
{ description: "NPM package name and version of a published package" }
|
|
125
|
+
);
|
|
103
126
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
(_, idx) => getColumnAlignmentForIndex(idx, columns)
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
const firstObject = rows.at(0);
|
|
118
|
-
return Object.keys(firstObject).map(
|
|
119
|
-
(key, idx) => getColumnAlignmentForKeyAndIndex(key, idx, columns)
|
|
127
|
+
var weightSchema = nonnegativeNumberSchema.describe(
|
|
128
|
+
"Coefficient for the given score (use weight 0 if only for display)"
|
|
129
|
+
);
|
|
130
|
+
function weightedRefSchema(description, slugDescription) {
|
|
131
|
+
return z.object(
|
|
132
|
+
{
|
|
133
|
+
slug: slugSchema.describe(slugDescription),
|
|
134
|
+
weight: weightSchema.describe("Weight used to calculate score")
|
|
135
|
+
},
|
|
136
|
+
{ description }
|
|
120
137
|
);
|
|
121
138
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
139
|
+
function scorableSchema(description, refSchema, duplicateCheckFn, duplicateMessageFn) {
|
|
140
|
+
return z.object(
|
|
141
|
+
{
|
|
142
|
+
slug: slugSchema.describe('Human-readable unique ID, e.g. "performance"'),
|
|
143
|
+
refs: z.array(refSchema).min(1).refine(
|
|
144
|
+
(refs) => !duplicateCheckFn(refs),
|
|
145
|
+
(refs) => ({
|
|
146
|
+
message: duplicateMessageFn(refs)
|
|
147
|
+
})
|
|
148
|
+
).refine(hasNonZeroWeightedRef, () => ({
|
|
149
|
+
message: "In a category there has to be at least one ref with weight > 0"
|
|
150
|
+
}))
|
|
151
|
+
},
|
|
152
|
+
{ description }
|
|
153
|
+
);
|
|
126
154
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (tableData.rows.length === 0) {
|
|
133
|
-
throw new Error("Data can't be empty");
|
|
134
|
-
}
|
|
135
|
-
const tableHeaderCols = columnsToStringArray(tableData).map((s) => wrap("th", s)).join("");
|
|
136
|
-
const tableHeaderRow = wrapRow(tableHeaderCols);
|
|
137
|
-
const tableBody = rowToStringArray(tableData).map((arr) => {
|
|
138
|
-
const columns = arr.map((s) => wrap("td", s)).join("");
|
|
139
|
-
return wrapRow(columns);
|
|
140
|
-
}).join("");
|
|
141
|
-
return wrap("table", `${NEW_LINE}${tableHeaderRow}${tableBody}`);
|
|
155
|
+
var materialIconSchema = z.enum(MATERIAL_ICONS, {
|
|
156
|
+
description: "Icon from VSCode Material Icons extension"
|
|
157
|
+
});
|
|
158
|
+
function hasNonZeroWeightedRef(refs) {
|
|
159
|
+
return refs.reduce((acc, { weight }) => weight + acc, 0) !== 0;
|
|
142
160
|
}
|
|
143
161
|
|
|
144
|
-
// packages/
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
162
|
+
// packages/models/src/lib/audit.ts
|
|
163
|
+
import { z as z2 } from "zod";
|
|
164
|
+
var auditSchema = z2.object({
|
|
165
|
+
slug: slugSchema.describe("ID (unique within plugin)")
|
|
166
|
+
}).merge(
|
|
167
|
+
metaSchema({
|
|
168
|
+
titleDescription: "Descriptive name",
|
|
169
|
+
descriptionDescription: "Description (markdown)",
|
|
170
|
+
docsUrlDescription: "Link to documentation (rationale)",
|
|
171
|
+
description: "List of scorable metrics for the given plugin"
|
|
172
|
+
})
|
|
173
|
+
);
|
|
174
|
+
var pluginAuditsSchema = z2.array(auditSchema, {
|
|
175
|
+
description: "List of audits maintained in a plugin"
|
|
176
|
+
}).min(1).refine(
|
|
177
|
+
(auditMetadata) => !getDuplicateSlugsInAudits(auditMetadata),
|
|
178
|
+
(auditMetadata) => ({
|
|
179
|
+
message: duplicateSlugsInAuditsErrorMsg(auditMetadata)
|
|
180
|
+
})
|
|
181
|
+
);
|
|
182
|
+
function duplicateSlugsInAuditsErrorMsg(audits) {
|
|
183
|
+
const duplicateRefs = getDuplicateSlugsInAudits(audits);
|
|
184
|
+
return `In plugin audits the following slugs are not unique: ${errorItems(
|
|
185
|
+
duplicateRefs
|
|
186
|
+
)}`;
|
|
156
187
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return `${codeWrap}${text}${codeWrap}`;
|
|
188
|
+
function getDuplicateSlugsInAudits(audits) {
|
|
189
|
+
return hasDuplicateStrings(audits.map(({ slug }) => slug));
|
|
160
190
|
}
|
|
161
191
|
|
|
162
|
-
// packages/
|
|
163
|
-
|
|
164
|
-
return `${"#".repeat(hierarchy)} ${text}${NEW_LINE}`;
|
|
165
|
-
}
|
|
166
|
-
function h(text, hierarchy = 1) {
|
|
167
|
-
return headline(text, hierarchy);
|
|
168
|
-
}
|
|
169
|
-
function h1(text) {
|
|
170
|
-
return headline(text, 1);
|
|
171
|
-
}
|
|
172
|
-
function h2(text) {
|
|
173
|
-
return headline(text, 2);
|
|
174
|
-
}
|
|
175
|
-
function h3(text) {
|
|
176
|
-
return headline(text, 3);
|
|
177
|
-
}
|
|
178
|
-
function h4(text) {
|
|
179
|
-
return headline(text, 4);
|
|
180
|
-
}
|
|
181
|
-
function h5(text) {
|
|
182
|
-
return headline(text, 5);
|
|
183
|
-
}
|
|
184
|
-
function h6(text) {
|
|
185
|
-
return headline(text, 6);
|
|
186
|
-
}
|
|
192
|
+
// packages/models/src/lib/audit-output.ts
|
|
193
|
+
import { z as z5 } from "zod";
|
|
187
194
|
|
|
188
|
-
// packages/
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
195
|
+
// packages/models/src/lib/issue.ts
|
|
196
|
+
import { z as z3 } from "zod";
|
|
197
|
+
var sourceFileLocationSchema = z3.object(
|
|
198
|
+
{
|
|
199
|
+
file: filePathSchema.describe("Relative path to source file in Git repo"),
|
|
200
|
+
position: z3.object(
|
|
201
|
+
{
|
|
202
|
+
startLine: positiveIntSchema.describe("Start line"),
|
|
203
|
+
startColumn: positiveIntSchema.describe("Start column").optional(),
|
|
204
|
+
endLine: positiveIntSchema.describe("End line").optional(),
|
|
205
|
+
endColumn: positiveIntSchema.describe("End column").optional()
|
|
206
|
+
},
|
|
207
|
+
{ description: "Location in file" }
|
|
208
|
+
).optional()
|
|
209
|
+
},
|
|
210
|
+
{ description: "Source file location" }
|
|
211
|
+
);
|
|
212
|
+
var issueSeveritySchema = z3.enum(["info", "warning", "error"], {
|
|
213
|
+
description: "Severity level"
|
|
214
|
+
});
|
|
215
|
+
var issueSchema = z3.object(
|
|
216
|
+
{
|
|
217
|
+
message: z3.string({ description: "Descriptive error message" }).max(MAX_ISSUE_MESSAGE_LENGTH),
|
|
218
|
+
severity: issueSeveritySchema,
|
|
219
|
+
source: sourceFileLocationSchema.optional()
|
|
220
|
+
},
|
|
221
|
+
{ description: "Issue information" }
|
|
222
|
+
);
|
|
192
223
|
|
|
193
|
-
// packages/
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
224
|
+
// packages/models/src/lib/table.ts
|
|
225
|
+
import { z as z4 } from "zod";
|
|
226
|
+
var tableAlignmentSchema = z4.enum(["left", "center", "right"], {
|
|
227
|
+
description: "Cell alignment"
|
|
228
|
+
});
|
|
229
|
+
var tableColumnObjectSchema = z4.object({
|
|
230
|
+
key: z4.string(),
|
|
231
|
+
label: z4.string().optional(),
|
|
232
|
+
align: tableAlignmentSchema.optional()
|
|
233
|
+
});
|
|
234
|
+
var tableRowObjectSchema = z4.record(primitiveValueSchema, {
|
|
235
|
+
description: "Object row"
|
|
236
|
+
});
|
|
237
|
+
var tableRowPrimitiveSchema = z4.array(primitiveValueSchema, {
|
|
238
|
+
description: "Primitive row"
|
|
239
|
+
});
|
|
240
|
+
var tableSharedSchema = z4.object({
|
|
241
|
+
title: z4.string().optional().describe("Display title for table")
|
|
242
|
+
});
|
|
243
|
+
var tablePrimitiveSchema = tableSharedSchema.merge(
|
|
244
|
+
z4.object(
|
|
245
|
+
{
|
|
246
|
+
columns: z4.array(tableAlignmentSchema).optional(),
|
|
247
|
+
rows: z4.array(tableRowPrimitiveSchema)
|
|
248
|
+
},
|
|
249
|
+
{ description: "Table with primitive rows and optional alignment columns" }
|
|
250
|
+
)
|
|
251
|
+
);
|
|
252
|
+
var tableObjectSchema = tableSharedSchema.merge(
|
|
253
|
+
z4.object(
|
|
254
|
+
{
|
|
255
|
+
columns: z4.union([
|
|
256
|
+
z4.array(tableAlignmentSchema),
|
|
257
|
+
z4.array(tableColumnObjectSchema)
|
|
258
|
+
]).optional(),
|
|
259
|
+
rows: z4.array(tableRowObjectSchema)
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
description: "Table with object rows and optional alignment or object columns"
|
|
263
|
+
}
|
|
264
|
+
)
|
|
265
|
+
);
|
|
266
|
+
var tableSchema = (description = "Table information") => z4.union([tablePrimitiveSchema, tableObjectSchema], { description });
|
|
197
267
|
|
|
198
|
-
// packages/
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
268
|
+
// packages/models/src/lib/audit-output.ts
|
|
269
|
+
var auditValueSchema = nonnegativeNumberSchema.describe("Raw numeric value");
|
|
270
|
+
var auditDisplayValueSchema = z5.string({ description: "Formatted value (e.g. '0.9 s', '2.1 MB')" }).optional();
|
|
271
|
+
var auditDetailsSchema = z5.object(
|
|
272
|
+
{
|
|
273
|
+
issues: z5.array(issueSchema, { description: "List of findings" }).optional(),
|
|
274
|
+
table: tableSchema("Table of related findings").optional()
|
|
275
|
+
},
|
|
276
|
+
{ description: "Detailed information" }
|
|
277
|
+
);
|
|
278
|
+
var auditOutputSchema = z5.object(
|
|
279
|
+
{
|
|
280
|
+
slug: slugSchema.describe("Reference to audit"),
|
|
281
|
+
displayValue: auditDisplayValueSchema,
|
|
282
|
+
value: auditValueSchema,
|
|
283
|
+
score: scoreSchema,
|
|
284
|
+
details: auditDetailsSchema.optional()
|
|
285
|
+
},
|
|
286
|
+
{ description: "Audit information" }
|
|
287
|
+
);
|
|
288
|
+
var auditOutputsSchema = z5.array(auditOutputSchema, {
|
|
289
|
+
description: "List of JSON formatted audit output emitted by the runner process of a plugin"
|
|
290
|
+
}).refine(
|
|
291
|
+
(audits) => !getDuplicateSlugsInAudits2(audits),
|
|
292
|
+
(audits) => ({ message: duplicateSlugsInAuditsErrorMsg2(audits) })
|
|
293
|
+
);
|
|
294
|
+
function duplicateSlugsInAuditsErrorMsg2(audits) {
|
|
295
|
+
const duplicateRefs = getDuplicateSlugsInAudits2(audits);
|
|
296
|
+
return `In plugin audits the slugs are not unique: ${errorItems(
|
|
297
|
+
duplicateRefs
|
|
298
|
+
)}`;
|
|
202
299
|
}
|
|
203
|
-
function
|
|
204
|
-
return
|
|
300
|
+
function getDuplicateSlugsInAudits2(audits) {
|
|
301
|
+
return hasDuplicateStrings(audits.map(({ slug }) => slug));
|
|
205
302
|
}
|
|
206
303
|
|
|
207
|
-
// packages/
|
|
208
|
-
|
|
209
|
-
|
|
304
|
+
// packages/models/src/lib/category-config.ts
|
|
305
|
+
import { z as z6 } from "zod";
|
|
306
|
+
var categoryRefSchema = weightedRefSchema(
|
|
307
|
+
"Weighted references to audits and/or groups for the category",
|
|
308
|
+
"Slug of an audit or group (depending on `type`)"
|
|
309
|
+
).merge(
|
|
310
|
+
z6.object({
|
|
311
|
+
type: z6.enum(["audit", "group"], {
|
|
312
|
+
description: "Discriminant for reference kind, affects where `slug` is looked up"
|
|
313
|
+
}),
|
|
314
|
+
plugin: slugSchema.describe(
|
|
315
|
+
"Plugin slug (plugin should contain referenced audit or group)"
|
|
316
|
+
)
|
|
317
|
+
})
|
|
318
|
+
);
|
|
319
|
+
var categoryConfigSchema = scorableSchema(
|
|
320
|
+
"Category with a score calculated from audits and groups from various plugins",
|
|
321
|
+
categoryRefSchema,
|
|
322
|
+
getDuplicateRefsInCategoryMetrics,
|
|
323
|
+
duplicateRefsInCategoryMetricsErrorMsg
|
|
324
|
+
).merge(
|
|
325
|
+
metaSchema({
|
|
326
|
+
titleDescription: "Category Title",
|
|
327
|
+
docsUrlDescription: "Category docs URL",
|
|
328
|
+
descriptionDescription: "Category description",
|
|
329
|
+
description: "Meta info for category"
|
|
330
|
+
})
|
|
331
|
+
).merge(
|
|
332
|
+
z6.object({
|
|
333
|
+
isBinary: z6.boolean({
|
|
334
|
+
description: 'Is this a binary category (i.e. only a perfect score considered a "pass")?'
|
|
335
|
+
}).optional()
|
|
336
|
+
})
|
|
337
|
+
);
|
|
338
|
+
function duplicateRefsInCategoryMetricsErrorMsg(metrics) {
|
|
339
|
+
const duplicateRefs = getDuplicateRefsInCategoryMetrics(metrics);
|
|
340
|
+
return `In the categories, the following audit or group refs are duplicates: ${errorItems(
|
|
341
|
+
duplicateRefs
|
|
342
|
+
)}`;
|
|
210
343
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
344
|
+
function getDuplicateRefsInCategoryMetrics(metrics) {
|
|
345
|
+
return hasDuplicateStrings(
|
|
346
|
+
metrics.map(({ slug, type, plugin }) => `${type} :: ${plugin} / ${slug}`)
|
|
347
|
+
);
|
|
215
348
|
}
|
|
216
|
-
|
|
217
|
-
|
|
349
|
+
var categoriesSchema = z6.array(categoryConfigSchema, {
|
|
350
|
+
description: "Categorization of individual audits"
|
|
351
|
+
}).refine(
|
|
352
|
+
(categoryCfg) => !getDuplicateSlugCategories(categoryCfg),
|
|
353
|
+
(categoryCfg) => ({
|
|
354
|
+
message: duplicateSlugCategoriesErrorMsg(categoryCfg)
|
|
355
|
+
})
|
|
356
|
+
);
|
|
357
|
+
function duplicateSlugCategoriesErrorMsg(categories) {
|
|
358
|
+
const duplicateStringSlugs = getDuplicateSlugCategories(categories);
|
|
359
|
+
return `In the categories, the following slugs are duplicated: ${errorItems(
|
|
360
|
+
duplicateStringSlugs
|
|
361
|
+
)}`;
|
|
362
|
+
}
|
|
363
|
+
function getDuplicateSlugCategories(categories) {
|
|
364
|
+
return hasDuplicateStrings(categories.map(({ slug }) => slug));
|
|
218
365
|
}
|
|
219
366
|
|
|
220
|
-
// packages/
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
]
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
tableRow(columnsToStringArray(data)),
|
|
239
|
-
tableRow(alignmentRow),
|
|
240
|
-
...rowToStringArray(data).map(tableRow)
|
|
241
|
-
)}`
|
|
242
|
-
);
|
|
243
|
-
}
|
|
367
|
+
// packages/models/src/lib/commit.ts
|
|
368
|
+
import { z as z7 } from "zod";
|
|
369
|
+
var commitSchema = z7.object(
|
|
370
|
+
{
|
|
371
|
+
hash: z7.string({ description: "Commit SHA (full)" }).regex(
|
|
372
|
+
/^[\da-f]{40}$/,
|
|
373
|
+
"Commit SHA should be a 40-character hexadecimal string"
|
|
374
|
+
),
|
|
375
|
+
message: z7.string({ description: "Commit message" }),
|
|
376
|
+
date: z7.coerce.date({
|
|
377
|
+
description: "Date and time when commit was authored"
|
|
378
|
+
}),
|
|
379
|
+
author: z7.string({
|
|
380
|
+
description: "Commit author name"
|
|
381
|
+
}).trim()
|
|
382
|
+
},
|
|
383
|
+
{ description: "Git commit" }
|
|
384
|
+
);
|
|
244
385
|
|
|
245
|
-
// packages/
|
|
246
|
-
|
|
247
|
-
bold: bold2,
|
|
248
|
-
italic: italic2,
|
|
249
|
-
strikeThrough,
|
|
250
|
-
code: code2,
|
|
251
|
-
link: link2,
|
|
252
|
-
image,
|
|
253
|
-
headline,
|
|
254
|
-
h,
|
|
255
|
-
h1,
|
|
256
|
-
h2,
|
|
257
|
-
h3,
|
|
258
|
-
h4,
|
|
259
|
-
h5,
|
|
260
|
-
h6,
|
|
261
|
-
indentation,
|
|
262
|
-
lines,
|
|
263
|
-
li,
|
|
264
|
-
section,
|
|
265
|
-
paragraphs,
|
|
266
|
-
table: table2
|
|
267
|
-
};
|
|
268
|
-
var html = {
|
|
269
|
-
bold,
|
|
270
|
-
italic,
|
|
271
|
-
code,
|
|
272
|
-
link,
|
|
273
|
-
details,
|
|
274
|
-
table
|
|
275
|
-
};
|
|
386
|
+
// packages/models/src/lib/core-config.ts
|
|
387
|
+
import { z as z13 } from "zod";
|
|
276
388
|
|
|
277
|
-
// packages/models/src/lib/
|
|
278
|
-
import {
|
|
279
|
-
|
|
389
|
+
// packages/models/src/lib/persist-config.ts
|
|
390
|
+
import { z as z8 } from "zod";
|
|
391
|
+
var formatSchema = z8.enum(["json", "md"]);
|
|
392
|
+
var persistConfigSchema = z8.object({
|
|
393
|
+
outputDir: filePathSchema.describe("Artifacts folder").optional(),
|
|
394
|
+
filename: fileNameSchema.describe("Artifacts file name (without extension)").optional(),
|
|
395
|
+
format: z8.array(formatSchema).optional()
|
|
396
|
+
});
|
|
280
397
|
|
|
281
|
-
// packages/models/src/lib/
|
|
282
|
-
|
|
283
|
-
var MAX_TITLE_LENGTH = 256;
|
|
284
|
-
var MAX_DESCRIPTION_LENGTH = 65536;
|
|
285
|
-
var MAX_ISSUE_MESSAGE_LENGTH = 1024;
|
|
398
|
+
// packages/models/src/lib/plugin-config.ts
|
|
399
|
+
import { z as z11 } from "zod";
|
|
286
400
|
|
|
287
|
-
// packages/models/src/lib/
|
|
288
|
-
|
|
289
|
-
var
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
401
|
+
// packages/models/src/lib/group.ts
|
|
402
|
+
import { z as z9 } from "zod";
|
|
403
|
+
var groupRefSchema = weightedRefSchema(
|
|
404
|
+
"Weighted reference to a group",
|
|
405
|
+
"Reference slug to a group within this plugin (e.g. 'max-lines')"
|
|
406
|
+
);
|
|
407
|
+
var groupMetaSchema = metaSchema({
|
|
408
|
+
titleDescription: "Descriptive name for the group",
|
|
409
|
+
descriptionDescription: "Description of the group (markdown)",
|
|
410
|
+
docsUrlDescription: "Group documentation site",
|
|
411
|
+
description: "Group metadata"
|
|
412
|
+
});
|
|
413
|
+
var groupSchema = scorableSchema(
|
|
414
|
+
'A group aggregates a set of audits into a single score which can be referenced from a category. E.g. the group slug "performance" groups audits and can be referenced in a category',
|
|
415
|
+
groupRefSchema,
|
|
416
|
+
getDuplicateRefsInGroups,
|
|
417
|
+
duplicateRefsInGroupsErrorMsg
|
|
418
|
+
).merge(groupMetaSchema);
|
|
419
|
+
var groupsSchema = z9.array(groupSchema, {
|
|
420
|
+
description: "List of groups"
|
|
421
|
+
}).optional().refine(
|
|
422
|
+
(groups) => !getDuplicateSlugsInGroups(groups),
|
|
423
|
+
(groups) => ({
|
|
424
|
+
message: duplicateSlugsInGroupsErrorMsg(groups)
|
|
425
|
+
})
|
|
426
|
+
);
|
|
427
|
+
function duplicateRefsInGroupsErrorMsg(groups) {
|
|
428
|
+
const duplicateRefs = getDuplicateRefsInGroups(groups);
|
|
429
|
+
return `In plugin groups the following references are not unique: ${errorItems(
|
|
430
|
+
duplicateRefs
|
|
431
|
+
)}`;
|
|
296
432
|
}
|
|
297
|
-
function
|
|
298
|
-
|
|
299
|
-
return nonExisting.length === 0 ? false : nonExisting;
|
|
433
|
+
function getDuplicateRefsInGroups(groups) {
|
|
434
|
+
return hasDuplicateStrings(groups.map(({ slug: ref }) => ref).filter(exists));
|
|
300
435
|
}
|
|
301
|
-
function
|
|
302
|
-
|
|
436
|
+
function duplicateSlugsInGroupsErrorMsg(groups) {
|
|
437
|
+
const duplicateRefs = getDuplicateSlugsInGroups(groups);
|
|
438
|
+
return `In groups the following slugs are not unique: ${errorItems(
|
|
439
|
+
duplicateRefs
|
|
440
|
+
)}`;
|
|
303
441
|
}
|
|
304
|
-
function
|
|
305
|
-
return
|
|
442
|
+
function getDuplicateSlugsInGroups(groups) {
|
|
443
|
+
return Array.isArray(groups) ? hasDuplicateStrings(groups.map(({ slug }) => slug)) : false;
|
|
306
444
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
445
|
+
|
|
446
|
+
// packages/models/src/lib/runner-config.ts
|
|
447
|
+
import { z as z10 } from "zod";
|
|
448
|
+
var outputTransformSchema = z10.function().args(z10.unknown()).returns(z10.union([auditOutputsSchema, z10.promise(auditOutputsSchema)]));
|
|
449
|
+
var runnerConfigSchema = z10.object(
|
|
450
|
+
{
|
|
451
|
+
command: z10.string({
|
|
452
|
+
description: "Shell command to execute"
|
|
453
|
+
}),
|
|
454
|
+
args: z10.array(z10.string({ description: "Command arguments" })).optional(),
|
|
455
|
+
outputFile: filePathSchema.describe("Output path"),
|
|
456
|
+
outputTransform: outputTransformSchema.optional()
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
description: "How to execute runner"
|
|
310
460
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const auditRefsFromPlugins = plugins.flatMap(
|
|
315
|
-
({ audits, slug: pluginSlug }) => audits.map(({ slug }) => `${pluginSlug}/${slug}`)
|
|
316
|
-
);
|
|
317
|
-
const missingAuditRefs = hasMissingStrings(
|
|
318
|
-
auditRefsFromCategory,
|
|
319
|
-
auditRefsFromPlugins
|
|
320
|
-
);
|
|
321
|
-
const groupRefsFromCategory = categories.flatMap(
|
|
322
|
-
({ refs }) => refs.filter(({ type }) => type === "group").map(({ plugin, slug }) => `${plugin}#${slug} (group)`)
|
|
323
|
-
);
|
|
324
|
-
const groupRefsFromPlugins = plugins.flatMap(
|
|
325
|
-
({ groups, slug: pluginSlug }) => Array.isArray(groups) ? groups.map(({ slug }) => `${pluginSlug}#${slug} (group)`) : []
|
|
326
|
-
);
|
|
327
|
-
const missingGroupRefs = hasMissingStrings(
|
|
328
|
-
groupRefsFromCategory,
|
|
329
|
-
groupRefsFromPlugins
|
|
330
|
-
);
|
|
331
|
-
const missingRefs = [missingAuditRefs, missingGroupRefs].filter((refs) => Array.isArray(refs) && refs.length > 0).flat();
|
|
332
|
-
return missingRefs.length > 0 ? missingRefs : false;
|
|
333
|
-
}
|
|
334
|
-
function missingRefsForCategoriesErrorMsg(categories, plugins) {
|
|
335
|
-
const missingRefs = getMissingRefsForCategories(categories, plugins);
|
|
336
|
-
return `The following category references need to point to an audit or group: ${errorItems(
|
|
337
|
-
missingRefs
|
|
338
|
-
)}`;
|
|
339
|
-
}
|
|
461
|
+
);
|
|
462
|
+
var onProgressSchema = z10.function().args(z10.unknown()).returns(z10.void());
|
|
463
|
+
var runnerFunctionSchema = z10.function().args(onProgressSchema.optional()).returns(z10.union([auditOutputsSchema, z10.promise(auditOutputsSchema)]));
|
|
340
464
|
|
|
341
|
-
// packages/models/src/lib/
|
|
342
|
-
var
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
465
|
+
// packages/models/src/lib/plugin-config.ts
|
|
466
|
+
var pluginMetaSchema = packageVersionSchema().merge(
|
|
467
|
+
metaSchema({
|
|
468
|
+
titleDescription: "Descriptive name",
|
|
469
|
+
descriptionDescription: "Description (markdown)",
|
|
470
|
+
docsUrlDescription: "Plugin documentation site",
|
|
471
|
+
description: "Plugin metadata"
|
|
472
|
+
})
|
|
473
|
+
).merge(
|
|
474
|
+
z11.object({
|
|
475
|
+
slug: slugSchema.describe("Unique plugin slug within core config"),
|
|
476
|
+
icon: materialIconSchema
|
|
477
|
+
})
|
|
478
|
+
);
|
|
479
|
+
var pluginDataSchema = z11.object({
|
|
480
|
+
runner: z11.union([runnerConfigSchema, runnerFunctionSchema]),
|
|
481
|
+
audits: pluginAuditsSchema,
|
|
482
|
+
groups: groupsSchema
|
|
356
483
|
});
|
|
357
|
-
var
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
description: "Value between 0 and 1"
|
|
363
|
-
}).min(0).max(1);
|
|
364
|
-
function metaSchema(options) {
|
|
365
|
-
const {
|
|
366
|
-
descriptionDescription,
|
|
367
|
-
titleDescription,
|
|
368
|
-
docsUrlDescription,
|
|
369
|
-
description
|
|
370
|
-
} = options ?? {};
|
|
371
|
-
return z.object(
|
|
372
|
-
{
|
|
373
|
-
title: titleDescription ? titleSchema.describe(titleDescription) : titleSchema,
|
|
374
|
-
description: descriptionDescription ? descriptionSchema.describe(descriptionDescription) : descriptionSchema,
|
|
375
|
-
docsUrl: docsUrlDescription ? docsUrlSchema.describe(docsUrlDescription) : docsUrlSchema
|
|
376
|
-
},
|
|
377
|
-
{ description }
|
|
378
|
-
);
|
|
379
|
-
}
|
|
380
|
-
var filePathSchema = z.string().trim().min(1, { message: "path is invalid" });
|
|
381
|
-
var fileNameSchema = z.string().trim().regex(filenameRegex, {
|
|
382
|
-
message: `The filename has to be valid`
|
|
383
|
-
}).min(1, { message: "file name is invalid" });
|
|
384
|
-
var positiveIntSchema = z.number().int().positive();
|
|
385
|
-
var nonnegativeIntSchema = z.number().int().nonnegative();
|
|
386
|
-
function packageVersionSchema(options) {
|
|
387
|
-
const { versionDescription = "NPM version of the package", required } = options ?? {};
|
|
388
|
-
const packageSchema = z.string({ description: "NPM package name" });
|
|
389
|
-
const versionSchema = z.string({ description: versionDescription });
|
|
390
|
-
return z.object(
|
|
391
|
-
{
|
|
392
|
-
packageName: required ? packageSchema : packageSchema.optional(),
|
|
393
|
-
version: required ? versionSchema : versionSchema.optional()
|
|
394
|
-
},
|
|
395
|
-
{ description: "NPM package name and version of a published package" }
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
var weightSchema = nonnegativeIntSchema.describe(
|
|
399
|
-
"Coefficient for the given score (use weight 0 if only for display)"
|
|
484
|
+
var pluginConfigSchema = pluginMetaSchema.merge(pluginDataSchema).refine(
|
|
485
|
+
(pluginCfg) => !getMissingRefsFromGroups(pluginCfg),
|
|
486
|
+
(pluginCfg) => ({
|
|
487
|
+
message: missingRefsFromGroupsErrorMsg(pluginCfg)
|
|
488
|
+
})
|
|
400
489
|
);
|
|
401
|
-
function
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
},
|
|
407
|
-
{ description }
|
|
408
|
-
);
|
|
490
|
+
function missingRefsFromGroupsErrorMsg(pluginCfg) {
|
|
491
|
+
const missingRefs = getMissingRefsFromGroups(pluginCfg);
|
|
492
|
+
return `The following group references need to point to an existing audit in this plugin config: ${errorItems(
|
|
493
|
+
missingRefs
|
|
494
|
+
)}`;
|
|
409
495
|
}
|
|
410
|
-
function
|
|
411
|
-
return
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
(refs) => ({
|
|
417
|
-
message: duplicateMessageFn(refs)
|
|
418
|
-
})
|
|
419
|
-
).refine(hasNonZeroWeightedRef, () => ({
|
|
420
|
-
message: "In a category there has to be at least one ref with weight > 0"
|
|
421
|
-
}))
|
|
422
|
-
},
|
|
423
|
-
{ description }
|
|
496
|
+
function getMissingRefsFromGroups(pluginCfg) {
|
|
497
|
+
return hasMissingStrings(
|
|
498
|
+
pluginCfg.groups?.flatMap(
|
|
499
|
+
({ refs: audits }) => audits.map(({ slug: ref }) => ref)
|
|
500
|
+
) ?? [],
|
|
501
|
+
pluginCfg.audits.map(({ slug }) => slug)
|
|
424
502
|
);
|
|
425
503
|
}
|
|
426
|
-
|
|
427
|
-
|
|
504
|
+
|
|
505
|
+
// packages/models/src/lib/upload-config.ts
|
|
506
|
+
import { z as z12 } from "zod";
|
|
507
|
+
var uploadConfigSchema = z12.object({
|
|
508
|
+
server: urlSchema.describe("URL of deployed portal API"),
|
|
509
|
+
apiKey: z12.string({
|
|
510
|
+
description: "API key with write access to portal (use `process.env` for security)"
|
|
511
|
+
}),
|
|
512
|
+
organization: slugSchema.describe(
|
|
513
|
+
"Organization slug from Code PushUp portal"
|
|
514
|
+
),
|
|
515
|
+
project: slugSchema.describe("Project slug from Code PushUp portal"),
|
|
516
|
+
timeout: z12.number({ description: "Request timeout in minutes (default is 5)" }).positive().int().optional()
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
// packages/models/src/lib/core-config.ts
|
|
520
|
+
var unrefinedCoreConfigSchema = z13.object({
|
|
521
|
+
plugins: z13.array(pluginConfigSchema, {
|
|
522
|
+
description: "List of plugins to be used (official, community-provided, or custom)"
|
|
523
|
+
}).min(1),
|
|
524
|
+
/** portal configuration for persisting results */
|
|
525
|
+
persist: persistConfigSchema.optional(),
|
|
526
|
+
/** portal configuration for uploading results */
|
|
527
|
+
upload: uploadConfigSchema.optional(),
|
|
528
|
+
categories: categoriesSchema.optional()
|
|
428
529
|
});
|
|
429
|
-
|
|
430
|
-
|
|
530
|
+
var coreConfigSchema = refineCoreConfig(unrefinedCoreConfigSchema);
|
|
531
|
+
function refineCoreConfig(schema) {
|
|
532
|
+
return schema.refine(
|
|
533
|
+
(coreCfg) => !getMissingRefsForCategories(coreCfg.categories ?? [], coreCfg.plugins),
|
|
534
|
+
(coreCfg) => ({
|
|
535
|
+
message: missingRefsForCategoriesErrorMsg(
|
|
536
|
+
coreCfg.categories ?? [],
|
|
537
|
+
coreCfg.plugins
|
|
538
|
+
)
|
|
539
|
+
})
|
|
540
|
+
);
|
|
431
541
|
}
|
|
432
542
|
|
|
433
|
-
// packages/models/src/lib/
|
|
434
|
-
import { z as
|
|
435
|
-
var
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
descriptionDescription: "Description (markdown)",
|
|
441
|
-
docsUrlDescription: "Link to documentation (rationale)",
|
|
442
|
-
description: "List of scorable metrics for the given plugin"
|
|
543
|
+
// packages/models/src/lib/report.ts
|
|
544
|
+
import { z as z14 } from "zod";
|
|
545
|
+
var auditReportSchema = auditSchema.merge(auditOutputSchema);
|
|
546
|
+
var pluginReportSchema = pluginMetaSchema.merge(
|
|
547
|
+
executionMetaSchema({
|
|
548
|
+
descriptionDate: "Start date and time of plugin run",
|
|
549
|
+
descriptionDuration: "Duration of the plugin run in ms"
|
|
443
550
|
})
|
|
444
|
-
)
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
551
|
+
).merge(
|
|
552
|
+
z14.object({
|
|
553
|
+
audits: z14.array(auditReportSchema).min(1),
|
|
554
|
+
groups: z14.array(groupSchema).optional()
|
|
555
|
+
})
|
|
556
|
+
).refine(
|
|
557
|
+
(pluginReport) => !getMissingRefsFromGroups2(pluginReport.audits, pluginReport.groups ?? []),
|
|
558
|
+
(pluginReport) => ({
|
|
559
|
+
message: missingRefsFromGroupsErrorMsg2(
|
|
560
|
+
pluginReport.audits,
|
|
561
|
+
pluginReport.groups ?? []
|
|
562
|
+
)
|
|
451
563
|
})
|
|
452
564
|
);
|
|
453
|
-
function
|
|
454
|
-
const
|
|
455
|
-
return `
|
|
456
|
-
|
|
565
|
+
function missingRefsFromGroupsErrorMsg2(audits, groups) {
|
|
566
|
+
const missingRefs = getMissingRefsFromGroups2(audits, groups);
|
|
567
|
+
return `group references need to point to an existing audit in this plugin report: ${errorItems(
|
|
568
|
+
missingRefs
|
|
457
569
|
)}`;
|
|
458
570
|
}
|
|
459
|
-
function
|
|
460
|
-
return
|
|
571
|
+
function getMissingRefsFromGroups2(audits, groups) {
|
|
572
|
+
return hasMissingStrings(
|
|
573
|
+
groups.flatMap(
|
|
574
|
+
({ refs: auditRefs }) => auditRefs.map(({ slug: ref }) => ref)
|
|
575
|
+
),
|
|
576
|
+
audits.map(({ slug }) => slug)
|
|
577
|
+
);
|
|
461
578
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
{
|
|
473
|
-
startLine: positiveIntSchema.describe("Start line"),
|
|
474
|
-
startColumn: positiveIntSchema.describe("Start column").optional(),
|
|
475
|
-
endLine: positiveIntSchema.describe("End line").optional(),
|
|
476
|
-
endColumn: positiveIntSchema.describe("End column").optional()
|
|
477
|
-
},
|
|
478
|
-
{ description: "Location in file" }
|
|
479
|
-
).optional()
|
|
480
|
-
},
|
|
481
|
-
{ description: "Source file location" }
|
|
482
|
-
);
|
|
483
|
-
var issueSeveritySchema = z3.enum(["info", "warning", "error"], {
|
|
484
|
-
description: "Severity level"
|
|
485
|
-
});
|
|
486
|
-
var issueSchema = z3.object(
|
|
487
|
-
{
|
|
488
|
-
message: z3.string({ description: "Descriptive error message" }).max(MAX_ISSUE_MESSAGE_LENGTH),
|
|
489
|
-
severity: issueSeveritySchema,
|
|
490
|
-
source: sourceFileLocationSchema.optional()
|
|
491
|
-
},
|
|
492
|
-
{ description: "Issue information" }
|
|
493
|
-
);
|
|
494
|
-
|
|
495
|
-
// packages/models/src/lib/table.ts
|
|
496
|
-
import { z as z4 } from "zod";
|
|
497
|
-
var tableAlignmentSchema = z4.enum(["left", "center", "right"], {
|
|
498
|
-
description: "Cell alignment"
|
|
499
|
-
});
|
|
500
|
-
var tableColumnObjectSchema = z4.object({
|
|
501
|
-
key: z4.string(),
|
|
502
|
-
label: z4.string().optional(),
|
|
503
|
-
align: tableAlignmentSchema.optional()
|
|
504
|
-
});
|
|
505
|
-
var tableRowObjectSchema = z4.record(primitiveValueSchema, {
|
|
506
|
-
description: "Object row"
|
|
507
|
-
});
|
|
508
|
-
var tableRowPrimitiveSchema = z4.array(primitiveValueSchema, {
|
|
509
|
-
description: "Primitive row"
|
|
510
|
-
});
|
|
511
|
-
var tableSharedSchema = z4.object({
|
|
512
|
-
title: z4.string().optional().describe("Display title for table")
|
|
513
|
-
});
|
|
514
|
-
var tablePrimitiveSchema = tableSharedSchema.merge(
|
|
515
|
-
z4.object(
|
|
579
|
+
var reportSchema = packageVersionSchema({
|
|
580
|
+
versionDescription: "NPM version of the CLI",
|
|
581
|
+
required: true
|
|
582
|
+
}).merge(
|
|
583
|
+
executionMetaSchema({
|
|
584
|
+
descriptionDate: "Start date and time of the collect run",
|
|
585
|
+
descriptionDuration: "Duration of the collect run in ms"
|
|
586
|
+
})
|
|
587
|
+
).merge(
|
|
588
|
+
z14.object(
|
|
516
589
|
{
|
|
517
|
-
|
|
518
|
-
|
|
590
|
+
categories: z14.array(categoryConfigSchema),
|
|
591
|
+
plugins: z14.array(pluginReportSchema).min(1),
|
|
592
|
+
commit: commitSchema.describe("Git commit for which report was collected").nullable()
|
|
519
593
|
},
|
|
520
|
-
{ description: "
|
|
594
|
+
{ description: "Collect output data" }
|
|
521
595
|
)
|
|
596
|
+
).refine(
|
|
597
|
+
(report) => !getMissingRefsForCategories(report.categories, report.plugins),
|
|
598
|
+
(report) => ({
|
|
599
|
+
message: missingRefsForCategoriesErrorMsg(
|
|
600
|
+
report.categories,
|
|
601
|
+
report.plugins
|
|
602
|
+
)
|
|
603
|
+
})
|
|
522
604
|
);
|
|
523
|
-
|
|
524
|
-
|
|
605
|
+
|
|
606
|
+
// packages/models/src/lib/reports-diff.ts
|
|
607
|
+
import { z as z15 } from "zod";
|
|
608
|
+
function makeComparisonSchema(schema) {
|
|
609
|
+
const sharedDescription = schema.description || "Result";
|
|
610
|
+
return z15.object({
|
|
611
|
+
before: schema.describe(`${sharedDescription} (source commit)`),
|
|
612
|
+
after: schema.describe(`${sharedDescription} (target commit)`)
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
function makeArraysComparisonSchema(diffSchema, resultSchema, description) {
|
|
616
|
+
return z15.object(
|
|
525
617
|
{
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
rows: z4.array(tableRowObjectSchema)
|
|
618
|
+
changed: z15.array(diffSchema),
|
|
619
|
+
unchanged: z15.array(resultSchema),
|
|
620
|
+
added: z15.array(resultSchema),
|
|
621
|
+
removed: z15.array(resultSchema)
|
|
531
622
|
},
|
|
532
|
-
{
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
var
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
issues: z5.array(issueSchema, { description: "List of findings" }).optional(),
|
|
545
|
-
table: tableSchema("Table of related findings").optional()
|
|
546
|
-
},
|
|
547
|
-
{ description: "Detailed information" }
|
|
623
|
+
{ description }
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
var scorableMetaSchema = z15.object({
|
|
627
|
+
slug: slugSchema,
|
|
628
|
+
title: titleSchema,
|
|
629
|
+
docsUrl: docsUrlSchema
|
|
630
|
+
});
|
|
631
|
+
var scorableWithPluginMetaSchema = scorableMetaSchema.merge(
|
|
632
|
+
z15.object({
|
|
633
|
+
plugin: pluginMetaSchema.pick({ slug: true, title: true, docsUrl: true }).describe("Plugin which defines it")
|
|
634
|
+
})
|
|
548
635
|
);
|
|
549
|
-
var
|
|
550
|
-
{
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
}
|
|
557
|
-
{ description: "Audit information" }
|
|
636
|
+
var scorableDiffSchema = scorableMetaSchema.merge(
|
|
637
|
+
z15.object({
|
|
638
|
+
scores: makeComparisonSchema(scoreSchema).merge(
|
|
639
|
+
z15.object({
|
|
640
|
+
diff: z15.number().min(-1).max(1).describe("Score change (`scores.after - scores.before`)")
|
|
641
|
+
})
|
|
642
|
+
).describe("Score comparison")
|
|
643
|
+
})
|
|
558
644
|
);
|
|
559
|
-
var
|
|
560
|
-
|
|
561
|
-
}).refine(
|
|
562
|
-
(audits) => !getDuplicateSlugsInAudits2(audits),
|
|
563
|
-
(audits) => ({ message: duplicateSlugsInAuditsErrorMsg2(audits) })
|
|
645
|
+
var scorableWithPluginDiffSchema = scorableDiffSchema.merge(
|
|
646
|
+
scorableWithPluginMetaSchema
|
|
564
647
|
);
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
import { z as z6 } from "zod";
|
|
577
|
-
var categoryRefSchema = weightedRefSchema(
|
|
578
|
-
"Weighted references to audits and/or groups for the category",
|
|
579
|
-
"Slug of an audit or group (depending on `type`)"
|
|
580
|
-
).merge(
|
|
581
|
-
z6.object({
|
|
582
|
-
type: z6.enum(["audit", "group"], {
|
|
583
|
-
description: "Discriminant for reference kind, affects where `slug` is looked up"
|
|
584
|
-
}),
|
|
585
|
-
plugin: slugSchema.describe(
|
|
586
|
-
"Plugin slug (plugin should contain referenced audit or group)"
|
|
648
|
+
var categoryDiffSchema = scorableDiffSchema;
|
|
649
|
+
var groupDiffSchema = scorableWithPluginDiffSchema;
|
|
650
|
+
var auditDiffSchema = scorableWithPluginDiffSchema.merge(
|
|
651
|
+
z15.object({
|
|
652
|
+
values: makeComparisonSchema(auditValueSchema).merge(
|
|
653
|
+
z15.object({
|
|
654
|
+
diff: z15.number().int().describe("Value change (`values.after - values.before`)")
|
|
655
|
+
})
|
|
656
|
+
).describe("Audit `value` comparison"),
|
|
657
|
+
displayValues: makeComparisonSchema(auditDisplayValueSchema).describe(
|
|
658
|
+
"Audit `displayValue` comparison"
|
|
587
659
|
)
|
|
588
660
|
})
|
|
589
661
|
);
|
|
590
|
-
var
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
)
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
662
|
+
var categoryResultSchema = scorableMetaSchema.merge(
|
|
663
|
+
z15.object({ score: scoreSchema })
|
|
664
|
+
);
|
|
665
|
+
var groupResultSchema = scorableWithPluginMetaSchema.merge(
|
|
666
|
+
z15.object({ score: scoreSchema })
|
|
667
|
+
);
|
|
668
|
+
var auditResultSchema = scorableWithPluginMetaSchema.merge(
|
|
669
|
+
auditOutputSchema.pick({ score: true, value: true, displayValue: true })
|
|
670
|
+
);
|
|
671
|
+
var reportsDiffSchema = z15.object({
|
|
672
|
+
commits: makeComparisonSchema(commitSchema).nullable().describe("Commits identifying compared reports"),
|
|
673
|
+
categories: makeArraysComparisonSchema(
|
|
674
|
+
categoryDiffSchema,
|
|
675
|
+
categoryResultSchema,
|
|
676
|
+
"Changes affecting categories"
|
|
677
|
+
),
|
|
678
|
+
groups: makeArraysComparisonSchema(
|
|
679
|
+
groupDiffSchema,
|
|
680
|
+
groupResultSchema,
|
|
681
|
+
"Changes affecting groups"
|
|
682
|
+
),
|
|
683
|
+
audits: makeArraysComparisonSchema(
|
|
684
|
+
auditDiffSchema,
|
|
685
|
+
auditResultSchema,
|
|
686
|
+
"Changes affecting audits"
|
|
687
|
+
)
|
|
688
|
+
}).merge(
|
|
689
|
+
packageVersionSchema({
|
|
690
|
+
versionDescription: "NPM version of the CLI (when `compare` was run)",
|
|
691
|
+
required: true
|
|
601
692
|
})
|
|
602
693
|
).merge(
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
}).optional()
|
|
694
|
+
executionMetaSchema({
|
|
695
|
+
descriptionDate: "Start date and time of the compare run",
|
|
696
|
+
descriptionDuration: "Duration of the compare run in ms"
|
|
607
697
|
})
|
|
608
698
|
);
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
699
|
+
|
|
700
|
+
// packages/utils/src/lib/file-system.ts
|
|
701
|
+
import { bundleRequire } from "bundle-require";
|
|
702
|
+
import chalk2 from "chalk";
|
|
703
|
+
import { mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
|
|
704
|
+
import { join } from "node:path";
|
|
705
|
+
|
|
706
|
+
// packages/utils/src/lib/logging.ts
|
|
707
|
+
import isaacs_cliui from "@isaacs/cliui";
|
|
708
|
+
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
|
|
715
|
+
var singletonUiInstance;
|
|
716
|
+
function ui() {
|
|
717
|
+
if (singletonUiInstance === void 0) {
|
|
718
|
+
singletonUiInstance = cliui();
|
|
719
|
+
}
|
|
720
|
+
return {
|
|
721
|
+
...singletonUiInstance,
|
|
722
|
+
row: (args) => {
|
|
723
|
+
logListItem(args);
|
|
724
|
+
}
|
|
725
|
+
};
|
|
614
726
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
727
|
+
var singletonisaacUi;
|
|
728
|
+
function logListItem(args) {
|
|
729
|
+
if (singletonisaacUi === void 0) {
|
|
730
|
+
singletonisaacUi = isaacs_cliui({ width: TERMINAL_WIDTH });
|
|
731
|
+
}
|
|
732
|
+
singletonisaacUi.div(...args);
|
|
733
|
+
const content = singletonisaacUi.toString();
|
|
734
|
+
singletonisaacUi.rows = [];
|
|
735
|
+
singletonUiInstance?.logger.log(content);
|
|
619
736
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
})
|
|
627
|
-
);
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
)}`;
|
|
737
|
+
|
|
738
|
+
// packages/utils/src/lib/file-system.ts
|
|
739
|
+
async function ensureDirectoryExists(baseDir) {
|
|
740
|
+
try {
|
|
741
|
+
await mkdir(baseDir, { recursive: true });
|
|
742
|
+
return;
|
|
743
|
+
} catch (error) {
|
|
744
|
+
ui().logger.info(error.message);
|
|
745
|
+
if (error.code !== "EEXIST") {
|
|
746
|
+
throw error;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
633
749
|
}
|
|
634
|
-
|
|
635
|
-
|
|
750
|
+
var NoExportError = class extends Error {
|
|
751
|
+
constructor(filepath) {
|
|
752
|
+
super(`No default export found in ${filepath}`);
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
async function importEsmModule(options) {
|
|
756
|
+
const { mod } = await bundleRequire({
|
|
757
|
+
format: "esm",
|
|
758
|
+
...options
|
|
759
|
+
});
|
|
760
|
+
if (!("default" in mod)) {
|
|
761
|
+
throw new NoExportError(options.filepath);
|
|
762
|
+
}
|
|
763
|
+
return mod.default;
|
|
764
|
+
}
|
|
765
|
+
function pluginWorkDir(slug) {
|
|
766
|
+
return join("node_modules", ".code-pushup", slug);
|
|
767
|
+
}
|
|
768
|
+
function filePathToCliArg(path) {
|
|
769
|
+
return `"${path}"`;
|
|
636
770
|
}
|
|
637
771
|
|
|
638
|
-
// packages/
|
|
639
|
-
|
|
640
|
-
var
|
|
641
|
-
{
|
|
642
|
-
hash: z7.string({ description: "Commit SHA (full)" }).regex(
|
|
643
|
-
/^[\da-f]{40}$/,
|
|
644
|
-
"Commit SHA should be a 40-character hexadecimal string"
|
|
645
|
-
),
|
|
646
|
-
message: z7.string({ description: "Commit message" }),
|
|
647
|
-
date: z7.coerce.date({
|
|
648
|
-
description: "Date and time when commit was authored"
|
|
649
|
-
}),
|
|
650
|
-
author: z7.string({
|
|
651
|
-
description: "Commit author name"
|
|
652
|
-
}).trim()
|
|
653
|
-
},
|
|
654
|
-
{ description: "Git commit" }
|
|
655
|
-
);
|
|
772
|
+
// packages/utils/src/lib/text-formats/constants.ts
|
|
773
|
+
var NEW_LINE = "\n";
|
|
774
|
+
var TAB = " ";
|
|
656
775
|
|
|
657
|
-
// packages/
|
|
658
|
-
|
|
776
|
+
// packages/utils/src/lib/text-formats/html/details.ts
|
|
777
|
+
function details(title, content, cfg = { open: false }) {
|
|
778
|
+
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.
|
|
779
|
+
NEW_LINE}${content}${NEW_LINE}${// @TODO in the future we could consider adding it only if the content ends with a code block
|
|
780
|
+
// ⚠️ The blank line ensure Markdown in content is rendered correctly.
|
|
781
|
+
NEW_LINE}</details>${// ⚠️ The blank line is needed to ensure Markdown after details is rendered correctly.
|
|
782
|
+
NEW_LINE}`;
|
|
783
|
+
}
|
|
659
784
|
|
|
660
|
-
// packages/
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
}
|
|
785
|
+
// packages/utils/src/lib/text-formats/html/font-style.ts
|
|
786
|
+
var boldElement = "b";
|
|
787
|
+
function bold(text) {
|
|
788
|
+
return `<${boldElement}>${text}</${boldElement}>`;
|
|
789
|
+
}
|
|
790
|
+
var italicElement = "i";
|
|
791
|
+
function italic(text) {
|
|
792
|
+
return `<${italicElement}>${text}</${italicElement}>`;
|
|
793
|
+
}
|
|
794
|
+
var codeElement = "code";
|
|
795
|
+
function code(text) {
|
|
796
|
+
return `<${codeElement}>${text}</${codeElement}>`;
|
|
797
|
+
}
|
|
668
798
|
|
|
669
|
-
// packages/
|
|
670
|
-
|
|
799
|
+
// packages/utils/src/lib/text-formats/html/link.ts
|
|
800
|
+
function link(href, text) {
|
|
801
|
+
return `<a href="${href}">${text || href}"</a>`;
|
|
802
|
+
}
|
|
671
803
|
|
|
672
|
-
// packages/
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
"Reference slug to a group within this plugin (e.g. 'max-lines')"
|
|
677
|
-
);
|
|
678
|
-
var groupMetaSchema = metaSchema({
|
|
679
|
-
titleDescription: "Descriptive name for the group",
|
|
680
|
-
descriptionDescription: "Description of the group (markdown)",
|
|
681
|
-
docsUrlDescription: "Group documentation site",
|
|
682
|
-
description: "Group metadata"
|
|
683
|
-
});
|
|
684
|
-
var groupSchema = scorableSchema(
|
|
685
|
-
'A group aggregates a set of audits into a single score which can be referenced from a category. E.g. the group slug "performance" groups audits and can be referenced in a category',
|
|
686
|
-
groupRefSchema,
|
|
687
|
-
getDuplicateRefsInGroups,
|
|
688
|
-
duplicateRefsInGroupsErrorMsg
|
|
689
|
-
).merge(groupMetaSchema);
|
|
690
|
-
var groupsSchema = z9.array(groupSchema, {
|
|
691
|
-
description: "List of groups"
|
|
692
|
-
}).optional().refine(
|
|
693
|
-
(groups) => !getDuplicateSlugsInGroups(groups),
|
|
694
|
-
(groups) => ({
|
|
695
|
-
message: duplicateSlugsInGroupsErrorMsg(groups)
|
|
696
|
-
})
|
|
697
|
-
);
|
|
698
|
-
function duplicateRefsInGroupsErrorMsg(groups) {
|
|
699
|
-
const duplicateRefs = getDuplicateRefsInGroups(groups);
|
|
700
|
-
return `In plugin groups the following references are not unique: ${errorItems(
|
|
701
|
-
duplicateRefs
|
|
804
|
+
// packages/utils/src/lib/transform.ts
|
|
805
|
+
function capitalize(text) {
|
|
806
|
+
return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
|
|
807
|
+
1
|
|
702
808
|
)}`;
|
|
703
809
|
}
|
|
704
|
-
|
|
705
|
-
|
|
810
|
+
|
|
811
|
+
// packages/utils/src/lib/table.ts
|
|
812
|
+
function rowToStringArray({ rows, columns = [] }) {
|
|
813
|
+
if (Array.isArray(rows.at(0)) && typeof columns.at(0) === "object") {
|
|
814
|
+
throw new TypeError(
|
|
815
|
+
"Column can`t be object when rows are primitive values"
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
return rows.map((row) => {
|
|
819
|
+
if (Array.isArray(row)) {
|
|
820
|
+
return row.map(String);
|
|
821
|
+
}
|
|
822
|
+
const objectRow = row;
|
|
823
|
+
if (columns.length === 0 || typeof columns.at(0) === "string") {
|
|
824
|
+
return Object.values(objectRow).map(String);
|
|
825
|
+
}
|
|
826
|
+
return columns.map(
|
|
827
|
+
({ key }) => String(objectRow[key])
|
|
828
|
+
);
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
function columnsToStringArray({ rows, columns = [] }) {
|
|
832
|
+
const firstRow = rows.at(0);
|
|
833
|
+
const primitiveRows = Array.isArray(firstRow);
|
|
834
|
+
if (typeof columns.at(0) === "string" && !primitiveRows) {
|
|
835
|
+
throw new Error("invalid union type. Caught by model parsing.");
|
|
836
|
+
}
|
|
837
|
+
if (columns.length === 0) {
|
|
838
|
+
if (Array.isArray(firstRow)) {
|
|
839
|
+
return firstRow.map((_, idx) => String(idx));
|
|
840
|
+
}
|
|
841
|
+
return Object.keys(firstRow);
|
|
842
|
+
}
|
|
843
|
+
if (typeof columns.at(0) === "string") {
|
|
844
|
+
return columns.map(String);
|
|
845
|
+
}
|
|
846
|
+
const cols = columns;
|
|
847
|
+
return cols.map(({ label, key }) => label ?? capitalize(key));
|
|
848
|
+
}
|
|
849
|
+
function getColumnAlignmentForKeyAndIndex(targetKey, targetIdx, columns = []) {
|
|
850
|
+
const column = columns.at(targetIdx) ?? columns.find((col) => col.key === targetKey);
|
|
851
|
+
if (typeof column === "string") {
|
|
852
|
+
return column;
|
|
853
|
+
} else if (typeof column === "object") {
|
|
854
|
+
return column.align ?? "center";
|
|
855
|
+
} else {
|
|
856
|
+
return "center";
|
|
857
|
+
}
|
|
706
858
|
}
|
|
707
|
-
function
|
|
708
|
-
const
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
)
|
|
859
|
+
function getColumnAlignmentForIndex(targetIdx, columns = []) {
|
|
860
|
+
const column = columns.at(targetIdx);
|
|
861
|
+
if (column == null) {
|
|
862
|
+
return "center";
|
|
863
|
+
} else if (typeof column === "string") {
|
|
864
|
+
return column;
|
|
865
|
+
} else if (typeof column === "object") {
|
|
866
|
+
return column.align ?? "center";
|
|
867
|
+
} else {
|
|
868
|
+
return "center";
|
|
869
|
+
}
|
|
712
870
|
}
|
|
713
|
-
function
|
|
714
|
-
|
|
871
|
+
function getColumnAlignments({
|
|
872
|
+
rows,
|
|
873
|
+
columns = []
|
|
874
|
+
}) {
|
|
875
|
+
if (rows.at(0) == null) {
|
|
876
|
+
throw new Error("first row can`t be undefined.");
|
|
877
|
+
}
|
|
878
|
+
if (Array.isArray(rows.at(0))) {
|
|
879
|
+
const firstPrimitiveRow = rows.at(0);
|
|
880
|
+
return Array.from({ length: firstPrimitiveRow.length }).map(
|
|
881
|
+
(_, idx) => getColumnAlignmentForIndex(idx, columns)
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
const firstObject = rows.at(0);
|
|
885
|
+
return Object.keys(firstObject).map(
|
|
886
|
+
(key, idx) => getColumnAlignmentForKeyAndIndex(key, idx, columns)
|
|
887
|
+
);
|
|
715
888
|
}
|
|
716
889
|
|
|
717
|
-
// packages/
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
},
|
|
729
|
-
{
|
|
730
|
-
description: "How to execute runner"
|
|
890
|
+
// packages/utils/src/lib/text-formats/html/table.ts
|
|
891
|
+
function wrap(elem, content) {
|
|
892
|
+
return `<${elem}>${content}</${elem}>${NEW_LINE}`;
|
|
893
|
+
}
|
|
894
|
+
function wrapRow(content) {
|
|
895
|
+
const elem = "tr";
|
|
896
|
+
return `<${elem}>${NEW_LINE}${content}</${elem}>${NEW_LINE}`;
|
|
897
|
+
}
|
|
898
|
+
function table(tableData) {
|
|
899
|
+
if (tableData.rows.length === 0) {
|
|
900
|
+
throw new Error("Data can't be empty");
|
|
731
901
|
}
|
|
732
|
-
);
|
|
733
|
-
|
|
734
|
-
|
|
902
|
+
const tableHeaderCols = columnsToStringArray(tableData).map((s) => wrap("th", s)).join("");
|
|
903
|
+
const tableHeaderRow = wrapRow(tableHeaderCols);
|
|
904
|
+
const tableBody = rowToStringArray(tableData).map((arr) => {
|
|
905
|
+
const columns = arr.map((s) => wrap("td", s)).join("");
|
|
906
|
+
return wrapRow(columns);
|
|
907
|
+
}).join("");
|
|
908
|
+
return wrap("table", `${NEW_LINE}${tableHeaderRow}${tableBody}`);
|
|
909
|
+
}
|
|
735
910
|
|
|
736
|
-
// packages/
|
|
737
|
-
var
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
descriptionDescription: "Description (markdown)",
|
|
741
|
-
docsUrlDescription: "Plugin documentation site",
|
|
742
|
-
description: "Plugin metadata"
|
|
743
|
-
})
|
|
744
|
-
).merge(
|
|
745
|
-
z11.object({
|
|
746
|
-
slug: slugSchema.describe("Unique plugin slug within core config"),
|
|
747
|
-
icon: materialIconSchema
|
|
748
|
-
})
|
|
749
|
-
);
|
|
750
|
-
var pluginDataSchema = z11.object({
|
|
751
|
-
runner: z11.union([runnerConfigSchema, runnerFunctionSchema]),
|
|
752
|
-
audits: pluginAuditsSchema,
|
|
753
|
-
groups: groupsSchema
|
|
754
|
-
});
|
|
755
|
-
var pluginConfigSchema = pluginMetaSchema.merge(pluginDataSchema).refine(
|
|
756
|
-
(pluginCfg) => !getMissingRefsFromGroups(pluginCfg),
|
|
757
|
-
(pluginCfg) => ({
|
|
758
|
-
message: missingRefsFromGroupsErrorMsg(pluginCfg)
|
|
759
|
-
})
|
|
760
|
-
);
|
|
761
|
-
function missingRefsFromGroupsErrorMsg(pluginCfg) {
|
|
762
|
-
const missingRefs = getMissingRefsFromGroups(pluginCfg);
|
|
763
|
-
return `The following group references need to point to an existing audit in this plugin config: ${errorItems(
|
|
764
|
-
missingRefs
|
|
765
|
-
)}`;
|
|
911
|
+
// packages/utils/src/lib/text-formats/md/font-style.ts
|
|
912
|
+
var boldWrap = "**";
|
|
913
|
+
function bold2(text) {
|
|
914
|
+
return `${boldWrap}${text}${boldWrap}`;
|
|
766
915
|
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
({ refs: audits }) => audits.map(({ slug: ref }) => ref)
|
|
771
|
-
) ?? [],
|
|
772
|
-
pluginCfg.audits.map(({ slug }) => slug)
|
|
773
|
-
);
|
|
916
|
+
var italicWrap = "_";
|
|
917
|
+
function italic2(text) {
|
|
918
|
+
return `${italicWrap}${text}${italicWrap}`;
|
|
774
919
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
}),
|
|
783
|
-
organization: slugSchema.describe(
|
|
784
|
-
"Organization slug from Code PushUp portal"
|
|
785
|
-
),
|
|
786
|
-
project: slugSchema.describe("Project slug from Code PushUp portal"),
|
|
787
|
-
timeout: z12.number({ description: "Request timeout in minutes (default is 5)" }).positive().int().optional()
|
|
788
|
-
});
|
|
789
|
-
|
|
790
|
-
// packages/models/src/lib/core-config.ts
|
|
791
|
-
var unrefinedCoreConfigSchema = z13.object({
|
|
792
|
-
plugins: z13.array(pluginConfigSchema, {
|
|
793
|
-
description: "List of plugins to be used (official, community-provided, or custom)"
|
|
794
|
-
}).min(1),
|
|
795
|
-
/** portal configuration for persisting results */
|
|
796
|
-
persist: persistConfigSchema.optional(),
|
|
797
|
-
/** portal configuration for uploading results */
|
|
798
|
-
upload: uploadConfigSchema.optional(),
|
|
799
|
-
categories: categoriesSchema.optional()
|
|
800
|
-
});
|
|
801
|
-
var coreConfigSchema = refineCoreConfig(unrefinedCoreConfigSchema);
|
|
802
|
-
function refineCoreConfig(schema) {
|
|
803
|
-
return schema.refine(
|
|
804
|
-
(coreCfg) => !getMissingRefsForCategories(coreCfg.categories ?? [], coreCfg.plugins),
|
|
805
|
-
(coreCfg) => ({
|
|
806
|
-
message: missingRefsForCategoriesErrorMsg(
|
|
807
|
-
coreCfg.categories ?? [],
|
|
808
|
-
coreCfg.plugins
|
|
809
|
-
)
|
|
810
|
-
})
|
|
811
|
-
);
|
|
920
|
+
var strikeThroughWrap = "~";
|
|
921
|
+
function strikeThrough(text) {
|
|
922
|
+
return `${strikeThroughWrap}${text}${strikeThroughWrap}`;
|
|
923
|
+
}
|
|
924
|
+
var codeWrap = "`";
|
|
925
|
+
function code2(text) {
|
|
926
|
+
return `${codeWrap}${text}${codeWrap}`;
|
|
812
927
|
}
|
|
813
928
|
|
|
814
|
-
// packages/
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
var pluginReportSchema = pluginMetaSchema.merge(
|
|
818
|
-
executionMetaSchema({
|
|
819
|
-
descriptionDate: "Start date and time of plugin run",
|
|
820
|
-
descriptionDuration: "Duration of the plugin run in ms"
|
|
821
|
-
})
|
|
822
|
-
).merge(
|
|
823
|
-
z14.object({
|
|
824
|
-
audits: z14.array(auditReportSchema).min(1),
|
|
825
|
-
groups: z14.array(groupSchema).optional()
|
|
826
|
-
})
|
|
827
|
-
).refine(
|
|
828
|
-
(pluginReport) => !getMissingRefsFromGroups2(pluginReport.audits, pluginReport.groups ?? []),
|
|
829
|
-
(pluginReport) => ({
|
|
830
|
-
message: missingRefsFromGroupsErrorMsg2(
|
|
831
|
-
pluginReport.audits,
|
|
832
|
-
pluginReport.groups ?? []
|
|
833
|
-
)
|
|
834
|
-
})
|
|
835
|
-
);
|
|
836
|
-
function missingRefsFromGroupsErrorMsg2(audits, groups) {
|
|
837
|
-
const missingRefs = getMissingRefsFromGroups2(audits, groups);
|
|
838
|
-
return `group references need to point to an existing audit in this plugin report: ${errorItems(
|
|
839
|
-
missingRefs
|
|
840
|
-
)}`;
|
|
929
|
+
// packages/utils/src/lib/text-formats/md/headline.ts
|
|
930
|
+
function headline(text, hierarchy = 1) {
|
|
931
|
+
return `${"#".repeat(hierarchy)} ${text}${NEW_LINE}`;
|
|
841
932
|
}
|
|
842
|
-
function
|
|
843
|
-
return
|
|
844
|
-
groups.flatMap(
|
|
845
|
-
({ refs: auditRefs }) => auditRefs.map(({ slug: ref }) => ref)
|
|
846
|
-
),
|
|
847
|
-
audits.map(({ slug }) => slug)
|
|
848
|
-
);
|
|
933
|
+
function h(text, hierarchy = 1) {
|
|
934
|
+
return headline(text, hierarchy);
|
|
849
935
|
}
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
descriptionDate: "Start date and time of the collect run",
|
|
856
|
-
descriptionDuration: "Duration of the collect run in ms"
|
|
857
|
-
})
|
|
858
|
-
).merge(
|
|
859
|
-
z14.object(
|
|
860
|
-
{
|
|
861
|
-
categories: z14.array(categoryConfigSchema),
|
|
862
|
-
plugins: z14.array(pluginReportSchema).min(1),
|
|
863
|
-
commit: commitSchema.describe("Git commit for which report was collected").nullable()
|
|
864
|
-
},
|
|
865
|
-
{ description: "Collect output data" }
|
|
866
|
-
)
|
|
867
|
-
).refine(
|
|
868
|
-
(report) => !getMissingRefsForCategories(report.categories, report.plugins),
|
|
869
|
-
(report) => ({
|
|
870
|
-
message: missingRefsForCategoriesErrorMsg(
|
|
871
|
-
report.categories,
|
|
872
|
-
report.plugins
|
|
873
|
-
)
|
|
874
|
-
})
|
|
875
|
-
);
|
|
876
|
-
|
|
877
|
-
// packages/models/src/lib/reports-diff.ts
|
|
878
|
-
import { z as z15 } from "zod";
|
|
879
|
-
function makeComparisonSchema(schema) {
|
|
880
|
-
const sharedDescription = schema.description || "Result";
|
|
881
|
-
return z15.object({
|
|
882
|
-
before: schema.describe(`${sharedDescription} (source commit)`),
|
|
883
|
-
after: schema.describe(`${sharedDescription} (target commit)`)
|
|
884
|
-
});
|
|
936
|
+
function h1(text) {
|
|
937
|
+
return headline(text, 1);
|
|
938
|
+
}
|
|
939
|
+
function h2(text) {
|
|
940
|
+
return headline(text, 2);
|
|
885
941
|
}
|
|
886
|
-
function
|
|
887
|
-
return
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
942
|
+
function h3(text) {
|
|
943
|
+
return headline(text, 3);
|
|
944
|
+
}
|
|
945
|
+
function h4(text) {
|
|
946
|
+
return headline(text, 4);
|
|
947
|
+
}
|
|
948
|
+
function h5(text) {
|
|
949
|
+
return headline(text, 5);
|
|
950
|
+
}
|
|
951
|
+
function h6(text) {
|
|
952
|
+
return headline(text, 6);
|
|
896
953
|
}
|
|
897
|
-
var scorableMetaSchema = z15.object({
|
|
898
|
-
slug: slugSchema,
|
|
899
|
-
title: titleSchema,
|
|
900
|
-
docsUrl: docsUrlSchema
|
|
901
|
-
});
|
|
902
|
-
var scorableWithPluginMetaSchema = scorableMetaSchema.merge(
|
|
903
|
-
z15.object({
|
|
904
|
-
plugin: pluginMetaSchema.pick({ slug: true, title: true, docsUrl: true }).describe("Plugin which defines it")
|
|
905
|
-
})
|
|
906
|
-
);
|
|
907
|
-
var scorableDiffSchema = scorableMetaSchema.merge(
|
|
908
|
-
z15.object({
|
|
909
|
-
scores: makeComparisonSchema(scoreSchema).merge(
|
|
910
|
-
z15.object({
|
|
911
|
-
diff: z15.number().min(-1).max(1).describe("Score change (`scores.after - scores.before`)")
|
|
912
|
-
})
|
|
913
|
-
).describe("Score comparison")
|
|
914
|
-
})
|
|
915
|
-
);
|
|
916
|
-
var scorableWithPluginDiffSchema = scorableDiffSchema.merge(
|
|
917
|
-
scorableWithPluginMetaSchema
|
|
918
|
-
);
|
|
919
|
-
var categoryDiffSchema = scorableDiffSchema;
|
|
920
|
-
var groupDiffSchema = scorableWithPluginDiffSchema;
|
|
921
|
-
var auditDiffSchema = scorableWithPluginDiffSchema.merge(
|
|
922
|
-
z15.object({
|
|
923
|
-
values: makeComparisonSchema(auditValueSchema).merge(
|
|
924
|
-
z15.object({
|
|
925
|
-
diff: z15.number().int().describe("Value change (`values.after - values.before`)")
|
|
926
|
-
})
|
|
927
|
-
).describe("Audit `value` comparison"),
|
|
928
|
-
displayValues: makeComparisonSchema(auditDisplayValueSchema).describe(
|
|
929
|
-
"Audit `displayValue` comparison"
|
|
930
|
-
)
|
|
931
|
-
})
|
|
932
|
-
);
|
|
933
|
-
var categoryResultSchema = scorableMetaSchema.merge(
|
|
934
|
-
z15.object({ score: scoreSchema })
|
|
935
|
-
);
|
|
936
|
-
var groupResultSchema = scorableWithPluginMetaSchema.merge(
|
|
937
|
-
z15.object({ score: scoreSchema })
|
|
938
|
-
);
|
|
939
|
-
var auditResultSchema = scorableWithPluginMetaSchema.merge(
|
|
940
|
-
auditOutputSchema.pick({ score: true, value: true, displayValue: true })
|
|
941
|
-
);
|
|
942
|
-
var reportsDiffSchema = z15.object({
|
|
943
|
-
commits: makeComparisonSchema(commitSchema).nullable().describe("Commits identifying compared reports"),
|
|
944
|
-
categories: makeArraysComparisonSchema(
|
|
945
|
-
categoryDiffSchema,
|
|
946
|
-
categoryResultSchema,
|
|
947
|
-
"Changes affecting categories"
|
|
948
|
-
),
|
|
949
|
-
groups: makeArraysComparisonSchema(
|
|
950
|
-
groupDiffSchema,
|
|
951
|
-
groupResultSchema,
|
|
952
|
-
"Changes affecting groups"
|
|
953
|
-
),
|
|
954
|
-
audits: makeArraysComparisonSchema(
|
|
955
|
-
auditDiffSchema,
|
|
956
|
-
auditResultSchema,
|
|
957
|
-
"Changes affecting audits"
|
|
958
|
-
)
|
|
959
|
-
}).merge(
|
|
960
|
-
packageVersionSchema({
|
|
961
|
-
versionDescription: "NPM version of the CLI (when `compare` was run)",
|
|
962
|
-
required: true
|
|
963
|
-
})
|
|
964
|
-
).merge(
|
|
965
|
-
executionMetaSchema({
|
|
966
|
-
descriptionDate: "Start date and time of the compare run",
|
|
967
|
-
descriptionDuration: "Duration of the compare run in ms"
|
|
968
|
-
})
|
|
969
|
-
);
|
|
970
954
|
|
|
971
|
-
// packages/utils/src/lib/
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
import { join } from "node:path";
|
|
955
|
+
// packages/utils/src/lib/text-formats/md/image.ts
|
|
956
|
+
function image(src, alt) {
|
|
957
|
+
return ``;
|
|
958
|
+
}
|
|
976
959
|
|
|
977
|
-
// packages/utils/src/lib/
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
960
|
+
// packages/utils/src/lib/text-formats/md/link.ts
|
|
961
|
+
function link2(href, text) {
|
|
962
|
+
return `[${text || href}](${href})`;
|
|
963
|
+
}
|
|
981
964
|
|
|
982
|
-
// packages/utils/src/lib/
|
|
983
|
-
|
|
965
|
+
// packages/utils/src/lib/text-formats/md/list.ts
|
|
966
|
+
function li(text, order = "unordered") {
|
|
967
|
+
const style = order === "unordered" ? "-" : "- [ ]";
|
|
968
|
+
return `${style} ${text}`;
|
|
969
|
+
}
|
|
970
|
+
function indentation(text, level = 1) {
|
|
971
|
+
return `${TAB.repeat(level)}${text}`;
|
|
972
|
+
}
|
|
984
973
|
|
|
985
|
-
// packages/utils/src/lib/
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
if (singletonUiInstance === void 0) {
|
|
989
|
-
singletonUiInstance = cliui();
|
|
990
|
-
}
|
|
991
|
-
return {
|
|
992
|
-
...singletonUiInstance,
|
|
993
|
-
row: (args) => {
|
|
994
|
-
logListItem(args);
|
|
995
|
-
}
|
|
996
|
-
};
|
|
974
|
+
// packages/utils/src/lib/text-formats/md/paragraphs.ts
|
|
975
|
+
function paragraphs(...sections) {
|
|
976
|
+
return sections.filter(Boolean).join(`${NEW_LINE}${NEW_LINE}`);
|
|
997
977
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
singletonisaacUi.rows = [];
|
|
1006
|
-
singletonUiInstance?.logger.log(content);
|
|
978
|
+
|
|
979
|
+
// packages/utils/src/lib/text-formats/md/section.ts
|
|
980
|
+
function section(...contents) {
|
|
981
|
+
return `${lines(...contents)}${NEW_LINE}`;
|
|
982
|
+
}
|
|
983
|
+
function lines(...contents) {
|
|
984
|
+
return `${contents.filter(Boolean).join(NEW_LINE)}`;
|
|
1007
985
|
}
|
|
1008
986
|
|
|
1009
|
-
// packages/utils/src/lib/
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
throw error;
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
987
|
+
// packages/utils/src/lib/text-formats/md/table.ts
|
|
988
|
+
var alignString = /* @__PURE__ */ new Map([
|
|
989
|
+
["left", ":--"],
|
|
990
|
+
["center", ":--:"],
|
|
991
|
+
["right", "--:"]
|
|
992
|
+
]);
|
|
993
|
+
function tableRow(rows) {
|
|
994
|
+
return `|${rows.join("|")}|`;
|
|
1020
995
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
}
|
|
1025
|
-
};
|
|
1026
|
-
async function importEsmModule(options) {
|
|
1027
|
-
const { mod } = await bundleRequire({
|
|
1028
|
-
format: "esm",
|
|
1029
|
-
...options
|
|
1030
|
-
});
|
|
1031
|
-
if (!("default" in mod)) {
|
|
1032
|
-
throw new NoExportError(options.filepath);
|
|
996
|
+
function table2(data) {
|
|
997
|
+
if (data.rows.length === 0) {
|
|
998
|
+
throw new Error("Data can't be empty");
|
|
1033
999
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
return
|
|
1000
|
+
const alignmentRow = getColumnAlignments(data).map(
|
|
1001
|
+
(s) => alignString.get(s) ?? String(alignString.get("center"))
|
|
1002
|
+
);
|
|
1003
|
+
return section(
|
|
1004
|
+
`${lines(
|
|
1005
|
+
tableRow(columnsToStringArray(data)),
|
|
1006
|
+
tableRow(alignmentRow),
|
|
1007
|
+
...rowToStringArray(data).map(tableRow)
|
|
1008
|
+
)}`
|
|
1009
|
+
);
|
|
1038
1010
|
}
|
|
1039
1011
|
|
|
1012
|
+
// packages/utils/src/lib/text-formats/index.ts
|
|
1013
|
+
var md = {
|
|
1014
|
+
bold: bold2,
|
|
1015
|
+
italic: italic2,
|
|
1016
|
+
strikeThrough,
|
|
1017
|
+
code: code2,
|
|
1018
|
+
link: link2,
|
|
1019
|
+
image,
|
|
1020
|
+
headline,
|
|
1021
|
+
h,
|
|
1022
|
+
h1,
|
|
1023
|
+
h2,
|
|
1024
|
+
h3,
|
|
1025
|
+
h4,
|
|
1026
|
+
h5,
|
|
1027
|
+
h6,
|
|
1028
|
+
indentation,
|
|
1029
|
+
lines,
|
|
1030
|
+
li,
|
|
1031
|
+
section,
|
|
1032
|
+
paragraphs,
|
|
1033
|
+
table: table2
|
|
1034
|
+
};
|
|
1035
|
+
var html = {
|
|
1036
|
+
bold,
|
|
1037
|
+
italic,
|
|
1038
|
+
code,
|
|
1039
|
+
link,
|
|
1040
|
+
details,
|
|
1041
|
+
table
|
|
1042
|
+
};
|
|
1043
|
+
|
|
1040
1044
|
// packages/utils/src/lib/reports/utils.ts
|
|
1041
1045
|
var { image: image2, bold: boldMd } = md;
|
|
1042
1046
|
|
|
@@ -1081,7 +1085,7 @@ import chalk4 from "chalk";
|
|
|
1081
1085
|
|
|
1082
1086
|
// packages/plugin-coverage/package.json
|
|
1083
1087
|
var name = "@code-pushup/coverage-plugin";
|
|
1084
|
-
var version = "0.
|
|
1088
|
+
var version = "0.45.1";
|
|
1085
1089
|
|
|
1086
1090
|
// packages/plugin-coverage/src/lib/config.ts
|
|
1087
1091
|
import { z as z16 } from "zod";
|
|
@@ -1161,7 +1165,7 @@ async function createRunnerConfig(scriptPath, config) {
|
|
|
1161
1165
|
const threshold = config.perfectScoreThreshold;
|
|
1162
1166
|
return {
|
|
1163
1167
|
command: "node",
|
|
1164
|
-
args: [scriptPath],
|
|
1168
|
+
args: [filePathToCliArg(scriptPath)],
|
|
1165
1169
|
outputFile: RUNNER_OUTPUT_PATH,
|
|
1166
1170
|
...threshold != null && {
|
|
1167
1171
|
outputTransform: (outputs) => applyMaxScoreAboveThreshold(outputs, threshold)
|
|
@@ -1225,19 +1229,15 @@ async function getNxCoveragePaths(targets = ["test"], verbose) {
|
|
|
1225
1229
|
return await Promise.all(
|
|
1226
1230
|
relevantNodes.map(async ({ name: name2, data }) => {
|
|
1227
1231
|
const targetConfig = data.targets?.[target];
|
|
1228
|
-
const
|
|
1229
|
-
target,
|
|
1232
|
+
const coveragePaths = await getCoveragePathsForTarget(
|
|
1230
1233
|
targetConfig,
|
|
1231
|
-
|
|
1234
|
+
data.root,
|
|
1235
|
+
`${target} in ${name2}`
|
|
1232
1236
|
);
|
|
1233
|
-
const rootToReportsDir = join4(data.root, coveragePath);
|
|
1234
1237
|
if (verbose) {
|
|
1235
1238
|
ui().logger.info(`- ${name2}: ${target}`);
|
|
1236
1239
|
}
|
|
1237
|
-
return
|
|
1238
|
-
pathToProject: data.root,
|
|
1239
|
-
resultsPath: join4(rootToReportsDir, "lcov.info")
|
|
1240
|
-
};
|
|
1240
|
+
return coveragePaths;
|
|
1241
1241
|
})
|
|
1242
1242
|
);
|
|
1243
1243
|
})
|
|
@@ -1250,47 +1250,58 @@ async function getNxCoveragePaths(targets = ["test"], verbose) {
|
|
|
1250
1250
|
function hasNxTarget(project, target) {
|
|
1251
1251
|
return project.data.targets != null && target in project.data.targets;
|
|
1252
1252
|
}
|
|
1253
|
-
async function
|
|
1253
|
+
async function getCoveragePathsForTarget(targetConfig, pathToRoot, targetContext) {
|
|
1254
1254
|
const { config } = targetConfig.options;
|
|
1255
1255
|
if (targetConfig.executor?.includes("@nx/vite")) {
|
|
1256
|
-
|
|
1257
|
-
filepath: config
|
|
1258
|
-
});
|
|
1259
|
-
const reportsDirectory = testConfig.test.coverage?.reportsDirectory;
|
|
1260
|
-
const reporter = testConfig.test.coverage?.reporter;
|
|
1261
|
-
if (reportsDirectory == null) {
|
|
1262
|
-
throw new Error(
|
|
1263
|
-
`Vitest coverage configuration at ${config} does not include coverage path for target ${target} in ${projectName}. Add the path under coverage > reportsDirectory.`
|
|
1264
|
-
);
|
|
1265
|
-
}
|
|
1266
|
-
if (!reporter?.includes("lcov")) {
|
|
1267
|
-
throw new Error(
|
|
1268
|
-
`Vitest coverage configuration at ${config} does not include LCOV report format for target ${target} in ${projectName}. Add 'lcov' format under coverage > reporter.`
|
|
1269
|
-
);
|
|
1270
|
-
}
|
|
1271
|
-
return reportsDirectory;
|
|
1256
|
+
return await getCoveragePathForVitest(config, pathToRoot, targetContext);
|
|
1272
1257
|
}
|
|
1273
1258
|
if (targetConfig.executor?.includes("@nx/jest")) {
|
|
1274
|
-
|
|
1275
|
-
filepath: config
|
|
1276
|
-
});
|
|
1277
|
-
const coverageDirectory = testConfig.coverageDirectory;
|
|
1278
|
-
if (coverageDirectory == null) {
|
|
1279
|
-
throw new Error(
|
|
1280
|
-
`Jest coverage configuration at ${config} does not include coverage path for target ${target} in ${projectName}. Add the path under coverageDirectory.`
|
|
1281
|
-
);
|
|
1282
|
-
}
|
|
1283
|
-
if (!testConfig.coverageReporters?.includes("lcov")) {
|
|
1284
|
-
throw new Error(
|
|
1285
|
-
`Jest coverage configuration at ${config} does not include LCOV report format for target ${target} in ${projectName}. Add 'lcov' format under coverageReporters.`
|
|
1286
|
-
);
|
|
1287
|
-
}
|
|
1288
|
-
return coverageDirectory;
|
|
1259
|
+
return await getCoveragePathForJest(config, pathToRoot, targetContext);
|
|
1289
1260
|
}
|
|
1290
1261
|
throw new Error(
|
|
1291
1262
|
`Unsupported executor ${targetConfig.executor}. @nx/vite and @nx/jest are currently supported.`
|
|
1292
1263
|
);
|
|
1293
1264
|
}
|
|
1265
|
+
async function getCoveragePathForVitest(pathToConfig, pathToRoot, context) {
|
|
1266
|
+
const vitestConfig = await importEsmModule({
|
|
1267
|
+
filepath: pathToConfig,
|
|
1268
|
+
format: "esm"
|
|
1269
|
+
});
|
|
1270
|
+
const reportsDirectory = vitestConfig.test.coverage?.reportsDirectory;
|
|
1271
|
+
const reporter = vitestConfig.test.coverage?.reporter;
|
|
1272
|
+
if (reportsDirectory == null) {
|
|
1273
|
+
throw new Error(
|
|
1274
|
+
`Vitest coverage configuration at ${pathToConfig} does not include coverage path for target ${context}. Add the path under coverage > reportsDirectory.`
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
if (!reporter?.includes("lcov")) {
|
|
1278
|
+
throw new Error(
|
|
1279
|
+
`Vitest coverage configuration at ${pathToConfig} does not include LCOV report format for target ${context}. Add 'lcov' format under coverage > reporter.`
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1282
|
+
return {
|
|
1283
|
+
pathToProject: pathToRoot,
|
|
1284
|
+
resultsPath: join4(pathToRoot, reportsDirectory, "lcov.info")
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
async function getCoveragePathForJest(pathToConfig, pathToRoot, context) {
|
|
1288
|
+
const testConfig = await importEsmModule({
|
|
1289
|
+
filepath: pathToConfig,
|
|
1290
|
+
format: "cjs"
|
|
1291
|
+
});
|
|
1292
|
+
const coverageDirectory = testConfig.coverageDirectory;
|
|
1293
|
+
if (coverageDirectory == null) {
|
|
1294
|
+
throw new Error(
|
|
1295
|
+
`Jest coverage configuration at ${pathToConfig} does not include coverage path for target ${context}. Add the path under coverageDirectory.`
|
|
1296
|
+
);
|
|
1297
|
+
}
|
|
1298
|
+
if (!testConfig.coverageReporters?.includes("lcov")) {
|
|
1299
|
+
throw new Error(
|
|
1300
|
+
`Jest coverage configuration at ${pathToConfig} does not include LCOV report format for target ${context}. Add 'lcov' format under coverageReporters.`
|
|
1301
|
+
);
|
|
1302
|
+
}
|
|
1303
|
+
return join4(pathToRoot, coverageDirectory, "lcov.info");
|
|
1304
|
+
}
|
|
1294
1305
|
|
|
1295
1306
|
// packages/plugin-coverage/src/index.ts
|
|
1296
1307
|
var src_default = coveragePlugin;
|