@code-pushup/lighthouse-plugin 0.46.0 → 0.48.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 +374 -69
- package/package.json +3 -3
- package/src/lib/runner/details/details.d.ts +9 -0
- package/src/lib/runner/details/item-value.d.ts +10 -0
- package/src/lib/runner/details/opportunity.type.d.ts +8 -0
- package/src/lib/runner/details/table.type.d.ts +6 -0
- package/src/lib/runner/details/types.d.ts +4 -0
- package/src/lib/runner/details/utils.d.ts +4 -0
- package/src/lib/runner/utils.d.ts +3 -4
package/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// packages/plugin-lighthouse/package.json
|
|
2
|
+
var name = "@code-pushup/lighthouse-plugin";
|
|
3
|
+
var version = "0.48.0";
|
|
4
|
+
|
|
1
5
|
// packages/plugin-lighthouse/src/lib/constants.ts
|
|
2
6
|
import { join } from "node:path";
|
|
3
7
|
|
|
@@ -66,7 +70,7 @@ function missingRefsForCategoriesErrorMsg(categories2, plugins) {
|
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
// packages/models/src/lib/implementation/schemas.ts
|
|
69
|
-
var
|
|
73
|
+
var tableCellValueSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]).default(null);
|
|
70
74
|
function executionMetaSchema(options = {
|
|
71
75
|
descriptionDate: "Execution start date and time",
|
|
72
76
|
descriptionDuration: "Execution duration in ms"
|
|
@@ -230,10 +234,10 @@ var tableColumnObjectSchema = z4.object({
|
|
|
230
234
|
label: z4.string().optional(),
|
|
231
235
|
align: tableAlignmentSchema.optional()
|
|
232
236
|
});
|
|
233
|
-
var tableRowObjectSchema = z4.record(
|
|
237
|
+
var tableRowObjectSchema = z4.record(tableCellValueSchema, {
|
|
234
238
|
description: "Object row"
|
|
235
239
|
});
|
|
236
|
-
var tableRowPrimitiveSchema = z4.array(
|
|
240
|
+
var tableRowPrimitiveSchema = z4.array(tableCellValueSchema, {
|
|
237
241
|
description: "Primitive row"
|
|
238
242
|
});
|
|
239
243
|
var tableSharedSchema = z4.object({
|
|
@@ -707,13 +711,52 @@ var LIGHTHOUSE_OUTPUT_PATH = join(
|
|
|
707
711
|
);
|
|
708
712
|
|
|
709
713
|
// packages/plugin-lighthouse/src/lib/normalize-flags.ts
|
|
710
|
-
import
|
|
714
|
+
import chalk9 from "chalk";
|
|
711
715
|
|
|
712
716
|
// packages/utils/src/lib/file-system.ts
|
|
713
717
|
import { bundleRequire } from "bundle-require";
|
|
714
718
|
import chalk2 from "chalk";
|
|
715
719
|
import { mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
|
|
716
720
|
|
|
721
|
+
// packages/utils/src/lib/formatting.ts
|
|
722
|
+
function formatBytes(bytes, decimals = 2) {
|
|
723
|
+
const positiveBytes = Math.max(bytes, 0);
|
|
724
|
+
if (positiveBytes === 0) {
|
|
725
|
+
return "0 B";
|
|
726
|
+
}
|
|
727
|
+
const k = 1024;
|
|
728
|
+
const dm = decimals < 0 ? 0 : decimals;
|
|
729
|
+
const sizes = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
730
|
+
const i = Math.floor(Math.log(positiveBytes) / Math.log(k));
|
|
731
|
+
return `${Number.parseFloat((positiveBytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
|
|
732
|
+
}
|
|
733
|
+
function formatDuration(duration, granularity = 0) {
|
|
734
|
+
if (duration < 1e3) {
|
|
735
|
+
return `${granularity ? duration.toFixed(granularity) : duration} ms`;
|
|
736
|
+
}
|
|
737
|
+
return `${(duration / 1e3).toFixed(2)} s`;
|
|
738
|
+
}
|
|
739
|
+
function truncateText(text, options) {
|
|
740
|
+
const {
|
|
741
|
+
maxChars,
|
|
742
|
+
position = "end",
|
|
743
|
+
ellipsis = "..."
|
|
744
|
+
} = typeof options === "number" ? { maxChars: options } : options;
|
|
745
|
+
if (text.length <= maxChars) {
|
|
746
|
+
return text;
|
|
747
|
+
}
|
|
748
|
+
const maxLength = maxChars - ellipsis.length;
|
|
749
|
+
switch (position) {
|
|
750
|
+
case "start":
|
|
751
|
+
return ellipsis + text.slice(-maxLength).trim();
|
|
752
|
+
case "middle":
|
|
753
|
+
const halfMaxChars = Math.floor(maxLength / 2);
|
|
754
|
+
return text.slice(0, halfMaxChars).trim() + ellipsis + text.slice(-halfMaxChars).trim();
|
|
755
|
+
case "end":
|
|
756
|
+
return text.slice(0, maxLength).trim() + ellipsis;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
717
760
|
// packages/utils/src/lib/logging.ts
|
|
718
761
|
import isaacs_cliui from "@isaacs/cliui";
|
|
719
762
|
import { cliui } from "@poppinss/cliui";
|
|
@@ -766,20 +809,12 @@ async function ensureDirectoryExists(baseDir) {
|
|
|
766
809
|
}
|
|
767
810
|
}
|
|
768
811
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
812
|
+
async function importModule(options) {
|
|
813
|
+
const { mod } = await bundleRequire(options);
|
|
814
|
+
if (typeof mod === "object" && "default" in mod) {
|
|
815
|
+
return mod.default;
|
|
772
816
|
}
|
|
773
|
-
|
|
774
|
-
async function importEsmModule(options) {
|
|
775
|
-
const { mod } = await bundleRequire({
|
|
776
|
-
format: "esm",
|
|
777
|
-
...options
|
|
778
|
-
});
|
|
779
|
-
if (!("default" in mod)) {
|
|
780
|
-
throw new NoExportError(options.filepath);
|
|
781
|
-
}
|
|
782
|
-
return mod.default;
|
|
817
|
+
return mod;
|
|
783
818
|
}
|
|
784
819
|
|
|
785
820
|
// packages/utils/src/lib/text-formats/constants.ts
|
|
@@ -811,7 +846,7 @@ function code(text) {
|
|
|
811
846
|
|
|
812
847
|
// packages/utils/src/lib/text-formats/html/link.ts
|
|
813
848
|
function link(href, text) {
|
|
814
|
-
return `<a href="${href}">${text || href}
|
|
849
|
+
return `<a href="${href}">${text || href}</a>`;
|
|
815
850
|
}
|
|
816
851
|
|
|
817
852
|
// packages/utils/src/lib/transform.ts
|
|
@@ -824,7 +859,7 @@ function capitalize(text) {
|
|
|
824
859
|
)}`;
|
|
825
860
|
}
|
|
826
861
|
|
|
827
|
-
// packages/utils/src/lib/table.ts
|
|
862
|
+
// packages/utils/src/lib/text-formats/table.ts
|
|
828
863
|
function rowToStringArray({ rows, columns = [] }) {
|
|
829
864
|
if (Array.isArray(rows.at(0)) && typeof columns.at(0) === "object") {
|
|
830
865
|
throw new TypeError(
|
|
@@ -837,14 +872,19 @@ function rowToStringArray({ rows, columns = [] }) {
|
|
|
837
872
|
}
|
|
838
873
|
const objectRow = row;
|
|
839
874
|
if (columns.length === 0 || typeof columns.at(0) === "string") {
|
|
840
|
-
return Object.values(objectRow).map(
|
|
875
|
+
return Object.values(objectRow).map(
|
|
876
|
+
(value) => value == null ? "" : String(value)
|
|
877
|
+
);
|
|
841
878
|
}
|
|
842
879
|
return columns.map(
|
|
843
|
-
({ key }) => String(objectRow[key])
|
|
880
|
+
({ key }) => objectRow[key] == null ? "" : String(objectRow[key])
|
|
844
881
|
);
|
|
845
882
|
});
|
|
846
883
|
}
|
|
847
|
-
function columnsToStringArray({
|
|
884
|
+
function columnsToStringArray({
|
|
885
|
+
rows,
|
|
886
|
+
columns = []
|
|
887
|
+
}) {
|
|
848
888
|
const firstRow = rows.at(0);
|
|
849
889
|
const primitiveRows = Array.isArray(firstRow);
|
|
850
890
|
if (typeof columns.at(0) === "string" && !primitiveRows) {
|
|
@@ -884,10 +924,8 @@ function getColumnAlignmentForIndex(targetIdx, columns = []) {
|
|
|
884
924
|
return "center";
|
|
885
925
|
}
|
|
886
926
|
}
|
|
887
|
-
function getColumnAlignments({
|
|
888
|
-
rows,
|
|
889
|
-
columns = []
|
|
890
|
-
}) {
|
|
927
|
+
function getColumnAlignments(tableData) {
|
|
928
|
+
const { rows, columns = [] } = tableData;
|
|
891
929
|
if (rows.at(0) == null) {
|
|
892
930
|
throw new Error("first row can`t be undefined.");
|
|
893
931
|
}
|
|
@@ -897,10 +935,17 @@ function getColumnAlignments({
|
|
|
897
935
|
(_, idx) => getColumnAlignmentForIndex(idx, columns)
|
|
898
936
|
);
|
|
899
937
|
}
|
|
900
|
-
const
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
938
|
+
const biggestRow = [...rows].sort((a, b) => Object.keys(a).length - Object.keys(b).length).at(-1);
|
|
939
|
+
if (columns.length > 0) {
|
|
940
|
+
return columns.map(
|
|
941
|
+
(column, idx) => typeof column === "string" ? column : getColumnAlignmentForKeyAndIndex(
|
|
942
|
+
column.key,
|
|
943
|
+
idx,
|
|
944
|
+
columns
|
|
945
|
+
)
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
return Object.keys(biggestRow ?? {}).map((_) => "center");
|
|
904
949
|
}
|
|
905
950
|
|
|
906
951
|
// packages/utils/src/lib/text-formats/html/table.ts
|
|
@@ -997,7 +1042,10 @@ function section(...contents) {
|
|
|
997
1042
|
return `${lines(...contents)}${NEW_LINE}`;
|
|
998
1043
|
}
|
|
999
1044
|
function lines(...contents) {
|
|
1000
|
-
|
|
1045
|
+
const filteredContent = contents.filter(
|
|
1046
|
+
(value) => value != null && value !== "" && value !== false
|
|
1047
|
+
);
|
|
1048
|
+
return `${filteredContent.join(NEW_LINE)}`;
|
|
1001
1049
|
}
|
|
1002
1050
|
|
|
1003
1051
|
// packages/utils/src/lib/text-formats/md/table.ts
|
|
@@ -1184,20 +1232,289 @@ var DEFAULT_CLI_FLAGS = {
|
|
|
1184
1232
|
};
|
|
1185
1233
|
|
|
1186
1234
|
// packages/plugin-lighthouse/src/lib/runner/utils.ts
|
|
1187
|
-
import
|
|
1235
|
+
import chalk8 from "chalk";
|
|
1188
1236
|
import log from "lighthouse-logger";
|
|
1189
1237
|
import desktopConfig from "lighthouse/core/config/desktop-config.js";
|
|
1190
1238
|
import experimentalConfig from "lighthouse/core/config/experimental-config.js";
|
|
1191
1239
|
import perfConfig from "lighthouse/core/config/perf-config.js";
|
|
1240
|
+
|
|
1241
|
+
// packages/plugin-lighthouse/src/lib/runner/details/details.ts
|
|
1242
|
+
import chalk7 from "chalk";
|
|
1243
|
+
|
|
1244
|
+
// packages/plugin-lighthouse/src/lib/runner/details/item-value.ts
|
|
1245
|
+
import chalk5 from "chalk";
|
|
1246
|
+
function trimSlice(item, maxLength = 0) {
|
|
1247
|
+
const str = String(item).trim();
|
|
1248
|
+
return maxLength > 0 ? str.slice(0, maxLength) : str;
|
|
1249
|
+
}
|
|
1250
|
+
function parseNodeValue(node) {
|
|
1251
|
+
const { selector = "" } = node ?? {};
|
|
1252
|
+
return selector;
|
|
1253
|
+
}
|
|
1254
|
+
function formatTableItemPropertyValue(itemValue, itemValueFormat) {
|
|
1255
|
+
if (itemValue == null) {
|
|
1256
|
+
return "";
|
|
1257
|
+
}
|
|
1258
|
+
if (itemValueFormat == null) {
|
|
1259
|
+
if (typeof itemValue === "string") {
|
|
1260
|
+
return trimSlice(itemValue);
|
|
1261
|
+
}
|
|
1262
|
+
if (typeof itemValue === "number") {
|
|
1263
|
+
return Number(itemValue);
|
|
1264
|
+
}
|
|
1265
|
+
if (typeof itemValue === "boolean") {
|
|
1266
|
+
return itemValue;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
const parsedItemValue = parseTableItemPropertyValue(itemValue);
|
|
1270
|
+
switch (itemValueFormat) {
|
|
1271
|
+
case "bytes":
|
|
1272
|
+
return formatBytes(Number(parsedItemValue));
|
|
1273
|
+
case "code":
|
|
1274
|
+
return html.code(trimSlice(parsedItemValue));
|
|
1275
|
+
case "link":
|
|
1276
|
+
const link8 = parsedItemValue;
|
|
1277
|
+
return html.link(link8.url, link8.text);
|
|
1278
|
+
case "url":
|
|
1279
|
+
const url = parsedItemValue;
|
|
1280
|
+
return html.link(url);
|
|
1281
|
+
case "timespanMs":
|
|
1282
|
+
case "ms":
|
|
1283
|
+
return formatDuration(Number(parsedItemValue));
|
|
1284
|
+
case "node":
|
|
1285
|
+
return parseNodeValue(itemValue);
|
|
1286
|
+
case "source-location":
|
|
1287
|
+
return truncateText(String(parsedItemValue), 200);
|
|
1288
|
+
case "numeric":
|
|
1289
|
+
const num = Number(parsedItemValue);
|
|
1290
|
+
if (num.toFixed(3).toString().endsWith(".000")) {
|
|
1291
|
+
return String(num);
|
|
1292
|
+
}
|
|
1293
|
+
return String(num.toFixed(3));
|
|
1294
|
+
case "text":
|
|
1295
|
+
return truncateText(String(parsedItemValue), 500);
|
|
1296
|
+
case "multi":
|
|
1297
|
+
ui().logger.info(`Format type ${chalk5.bold("multi")} is not implemented`);
|
|
1298
|
+
return "";
|
|
1299
|
+
case "thumbnail":
|
|
1300
|
+
ui().logger.info(
|
|
1301
|
+
`Format type ${chalk5.bold("thumbnail")} is not implemented`
|
|
1302
|
+
);
|
|
1303
|
+
return "";
|
|
1304
|
+
}
|
|
1305
|
+
return itemValue;
|
|
1306
|
+
}
|
|
1307
|
+
function parseSimpleItemValue(item) {
|
|
1308
|
+
if (typeof item === "object") {
|
|
1309
|
+
const value = item.value;
|
|
1310
|
+
if (typeof value === "object") {
|
|
1311
|
+
return value.formattedDefault;
|
|
1312
|
+
}
|
|
1313
|
+
return value;
|
|
1314
|
+
}
|
|
1315
|
+
return item;
|
|
1316
|
+
}
|
|
1317
|
+
function parseTableItemPropertyValue(itemValue) {
|
|
1318
|
+
if (itemValue == null) {
|
|
1319
|
+
return "";
|
|
1320
|
+
}
|
|
1321
|
+
if (typeof itemValue === "string" || typeof itemValue === "number" || typeof itemValue === "boolean") {
|
|
1322
|
+
return parseSimpleItemValue(itemValue);
|
|
1323
|
+
}
|
|
1324
|
+
const objectValue = itemValue;
|
|
1325
|
+
const { type } = objectValue;
|
|
1326
|
+
switch (type) {
|
|
1327
|
+
case "code":
|
|
1328
|
+
case "url":
|
|
1329
|
+
return String(parseSimpleItemValue(objectValue));
|
|
1330
|
+
case "node":
|
|
1331
|
+
return parseNodeValue(objectValue);
|
|
1332
|
+
case "link":
|
|
1333
|
+
return objectValue;
|
|
1334
|
+
case "numeric":
|
|
1335
|
+
return Number(parseSimpleItemValue(objectValue));
|
|
1336
|
+
case "source-location":
|
|
1337
|
+
const { url } = objectValue;
|
|
1338
|
+
return String(url);
|
|
1339
|
+
case "subitems":
|
|
1340
|
+
ui().logger.info(
|
|
1341
|
+
`Value type ${chalk5.bold("subitems")} is not implemented`
|
|
1342
|
+
);
|
|
1343
|
+
return "";
|
|
1344
|
+
case "debugdata":
|
|
1345
|
+
ui().logger.info(
|
|
1346
|
+
`Value type ${chalk5.bold("debugdata")} is not implemented`,
|
|
1347
|
+
{ silent: true }
|
|
1348
|
+
);
|
|
1349
|
+
return "";
|
|
1350
|
+
}
|
|
1351
|
+
return parseSimpleItemValue(objectValue);
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
// packages/plugin-lighthouse/src/lib/runner/details/utils.ts
|
|
1355
|
+
import chalk6 from "chalk";
|
|
1356
|
+
var LighthouseAuditDetailsParsingError = class extends Error {
|
|
1357
|
+
constructor(type, rawTable, error) {
|
|
1358
|
+
super(
|
|
1359
|
+
`Parsing lighthouse report details ${chalk6.bold(
|
|
1360
|
+
type
|
|
1361
|
+
)} failed:
|
|
1362
|
+
Raw data:
|
|
1363
|
+
${JSON.stringify(rawTable, null, 2)}
|
|
1364
|
+
${error}`
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
};
|
|
1368
|
+
|
|
1369
|
+
// packages/plugin-lighthouse/src/lib/runner/details/table.type.ts
|
|
1370
|
+
function parseTableToAuditDetailsTable(details4) {
|
|
1371
|
+
const { headings: rawHeadings, items } = details4;
|
|
1372
|
+
if (items.length === 0) {
|
|
1373
|
+
return void 0;
|
|
1374
|
+
}
|
|
1375
|
+
try {
|
|
1376
|
+
return tableSchema().parse({
|
|
1377
|
+
title: "Table",
|
|
1378
|
+
columns: parseTableColumns(rawHeadings),
|
|
1379
|
+
rows: items.map((row) => parseTableRow(row, rawHeadings))
|
|
1380
|
+
});
|
|
1381
|
+
} catch (error) {
|
|
1382
|
+
throw new LighthouseAuditDetailsParsingError(
|
|
1383
|
+
"table",
|
|
1384
|
+
{ items, headings: rawHeadings },
|
|
1385
|
+
error.message.toString()
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
function parseTableColumns(rawHeadings) {
|
|
1390
|
+
return rawHeadings.map(({ key, label }) => ({
|
|
1391
|
+
key: key ?? "",
|
|
1392
|
+
...typeof label === "string" && label.length > 0 ? { label } : {},
|
|
1393
|
+
align: "left"
|
|
1394
|
+
}));
|
|
1395
|
+
}
|
|
1396
|
+
function parseTableRow(tableItem, headings) {
|
|
1397
|
+
const keys = new Set(headings.map(({ key }) => key));
|
|
1398
|
+
const valueTypesByKey = new Map(
|
|
1399
|
+
headings.map(({ key, valueType }) => [key, valueType])
|
|
1400
|
+
);
|
|
1401
|
+
return Object.fromEntries(
|
|
1402
|
+
Object.entries(tableItem).filter(([key]) => keys.has(key)).map(([key, value]) => {
|
|
1403
|
+
const valueType = valueTypesByKey.get(key);
|
|
1404
|
+
return parseTableEntry([key, value], valueType);
|
|
1405
|
+
})
|
|
1406
|
+
);
|
|
1407
|
+
}
|
|
1408
|
+
function parseTableEntry([key, value], valueType) {
|
|
1409
|
+
if (value == null) {
|
|
1410
|
+
return [key, value];
|
|
1411
|
+
}
|
|
1412
|
+
return [key, formatTableItemPropertyValue(value, valueType)];
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
// packages/plugin-lighthouse/src/lib/runner/details/opportunity.type.ts
|
|
1416
|
+
function parseOpportunityToAuditDetailsTable(details4) {
|
|
1417
|
+
const { headings: rawHeadings, items } = details4;
|
|
1418
|
+
if (items.length === 0) {
|
|
1419
|
+
return void 0;
|
|
1420
|
+
}
|
|
1421
|
+
try {
|
|
1422
|
+
return tableSchema().parse({
|
|
1423
|
+
title: "Opportunity",
|
|
1424
|
+
columns: parseTableColumns(rawHeadings),
|
|
1425
|
+
rows: items.map((row) => parseOpportunityItemToTableRow(row, rawHeadings))
|
|
1426
|
+
});
|
|
1427
|
+
} catch (error) {
|
|
1428
|
+
throw new LighthouseAuditDetailsParsingError(
|
|
1429
|
+
"opportunity",
|
|
1430
|
+
{ items, headings: rawHeadings },
|
|
1431
|
+
error.message.toString()
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
function parseOpportunityItemToTableRow(opportunityItem, headings) {
|
|
1436
|
+
const keys = new Set(headings.map(({ key }) => key));
|
|
1437
|
+
const valueTypesByKey = new Map(
|
|
1438
|
+
headings.map(({ key, valueType }) => [key, valueType])
|
|
1439
|
+
);
|
|
1440
|
+
return {
|
|
1441
|
+
...Object.fromEntries(
|
|
1442
|
+
Object.entries(opportunityItem).filter(([key]) => keys.has(key)).map(([key, value]) => {
|
|
1443
|
+
const valueType = valueTypesByKey.get(key);
|
|
1444
|
+
return parseOpportunityEntry([key, value], valueType);
|
|
1445
|
+
})
|
|
1446
|
+
)
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
function parseOpportunityEntry([key, value], valueType) {
|
|
1450
|
+
switch (key) {
|
|
1451
|
+
case "url":
|
|
1452
|
+
return [key, html.link(String(value))];
|
|
1453
|
+
case "wastedPercent":
|
|
1454
|
+
return [key, `${Number(value).toFixed(2)} %`];
|
|
1455
|
+
case "totalBytes":
|
|
1456
|
+
case "wastedBytes":
|
|
1457
|
+
return [key, formatBytes(Number(value))];
|
|
1458
|
+
case "wastedMs":
|
|
1459
|
+
return [key, formatDuration(Number(value))];
|
|
1460
|
+
default:
|
|
1461
|
+
return parseTableEntry([key, value], valueType);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// packages/plugin-lighthouse/src/lib/runner/details/details.ts
|
|
1466
|
+
function toAuditDetails(details4) {
|
|
1467
|
+
if (details4 == null) {
|
|
1468
|
+
return {};
|
|
1469
|
+
}
|
|
1470
|
+
const { type } = details4;
|
|
1471
|
+
switch (type) {
|
|
1472
|
+
case "table":
|
|
1473
|
+
const table5 = parseTableToAuditDetailsTable(details4);
|
|
1474
|
+
return table5 ? { table: table5 } : {};
|
|
1475
|
+
case "opportunity":
|
|
1476
|
+
const opportunity = parseOpportunityToAuditDetailsTable(details4);
|
|
1477
|
+
return opportunity ? { table: opportunity } : {};
|
|
1478
|
+
}
|
|
1479
|
+
return {};
|
|
1480
|
+
}
|
|
1481
|
+
var unsupportedDetailTypes = /* @__PURE__ */ new Set([
|
|
1482
|
+
"debugdata",
|
|
1483
|
+
"treemap-data",
|
|
1484
|
+
"screenshot",
|
|
1485
|
+
"filmstrip",
|
|
1486
|
+
"criticalrequestchain"
|
|
1487
|
+
]);
|
|
1488
|
+
function logUnsupportedDetails(lhrAudits, { displayCount = 3 } = {}) {
|
|
1489
|
+
const slugsWithDetailParsingErrors = [
|
|
1490
|
+
...new Set(
|
|
1491
|
+
lhrAudits.filter(
|
|
1492
|
+
({ details: details4 }) => unsupportedDetailTypes.has(details4?.type)
|
|
1493
|
+
).map(({ details: details4 }) => details4?.type)
|
|
1494
|
+
)
|
|
1495
|
+
];
|
|
1496
|
+
if (slugsWithDetailParsingErrors.length > 0) {
|
|
1497
|
+
const postFix = (count) => count > displayCount ? ` and ${count - displayCount} more.` : "";
|
|
1498
|
+
ui().logger.debug(
|
|
1499
|
+
`${chalk7.yellow("\u26A0")} Plugin ${chalk7.bold(
|
|
1500
|
+
PLUGIN_SLUG
|
|
1501
|
+
)} skipped parsing of unsupported audit details: ${chalk7.bold(
|
|
1502
|
+
slugsWithDetailParsingErrors.slice(0, displayCount).join(", ")
|
|
1503
|
+
)}${postFix(slugsWithDetailParsingErrors.length)}`
|
|
1504
|
+
);
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
// packages/plugin-lighthouse/src/lib/runner/utils.ts
|
|
1192
1509
|
function normalizeAuditOutputs(auditOutputs, flags = { skipAudits: [] }) {
|
|
1193
1510
|
const toSkip = new Set(flags.skipAudits ?? []);
|
|
1194
1511
|
return auditOutputs.filter(({ slug }) => {
|
|
1195
1512
|
const doSkip = toSkip.has(slug);
|
|
1196
1513
|
if (doSkip) {
|
|
1197
1514
|
ui().logger.info(
|
|
1198
|
-
`Audit ${
|
|
1515
|
+
`Audit ${chalk8.bold(
|
|
1199
1516
|
slug
|
|
1200
|
-
)} was included in audit outputs of lighthouse but listed under ${
|
|
1517
|
+
)} was included in audit outputs of lighthouse but listed under ${chalk8.bold(
|
|
1201
1518
|
"skipAudits"
|
|
1202
1519
|
)}.`
|
|
1203
1520
|
);
|
|
@@ -1205,6 +1522,15 @@ function normalizeAuditOutputs(auditOutputs, flags = { skipAudits: [] }) {
|
|
|
1205
1522
|
return !doSkip;
|
|
1206
1523
|
});
|
|
1207
1524
|
}
|
|
1525
|
+
var LighthouseAuditParsingError = class extends Error {
|
|
1526
|
+
constructor(slug, error) {
|
|
1527
|
+
super(
|
|
1528
|
+
`
|
|
1529
|
+
Audit ${chalk8.bold(slug)} failed parsing details:
|
|
1530
|
+
${error.message}`
|
|
1531
|
+
);
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1208
1534
|
function toAuditOutputs(lhrAudits, { verbose = false } = {}) {
|
|
1209
1535
|
if (verbose) {
|
|
1210
1536
|
logUnsupportedDetails(lhrAudits);
|
|
@@ -1222,44 +1548,21 @@ function toAuditOutputs(lhrAudits, { verbose = false } = {}) {
|
|
|
1222
1548
|
slug,
|
|
1223
1549
|
score: score ?? 1,
|
|
1224
1550
|
// score can be null
|
|
1225
|
-
value
|
|
1551
|
+
value,
|
|
1226
1552
|
displayValue
|
|
1227
1553
|
};
|
|
1228
|
-
if (details4
|
|
1229
|
-
|
|
1554
|
+
if (details4 != null) {
|
|
1555
|
+
try {
|
|
1556
|
+
const parsedDetails = toAuditDetails(details4);
|
|
1557
|
+
return Object.keys(parsedDetails).length > 0 ? { ...auditOutput, details: parsedDetails } : auditOutput;
|
|
1558
|
+
} catch (error) {
|
|
1559
|
+
throw new LighthouseAuditParsingError(slug, error);
|
|
1560
|
+
}
|
|
1230
1561
|
}
|
|
1231
1562
|
return auditOutput;
|
|
1232
1563
|
}
|
|
1233
1564
|
);
|
|
1234
1565
|
}
|
|
1235
|
-
var unsupportedDetailTypes = /* @__PURE__ */ new Set([
|
|
1236
|
-
"opportunity",
|
|
1237
|
-
"table",
|
|
1238
|
-
"treemap-data",
|
|
1239
|
-
"screenshot",
|
|
1240
|
-
"filmstrip",
|
|
1241
|
-
"debugdata",
|
|
1242
|
-
"criticalrequestchain"
|
|
1243
|
-
]);
|
|
1244
|
-
function logUnsupportedDetails(lhrAudits, { displayCount = 3 } = {}) {
|
|
1245
|
-
const slugsWithDetailParsingErrors = [
|
|
1246
|
-
...new Set(
|
|
1247
|
-
lhrAudits.filter(
|
|
1248
|
-
({ details: details4 }) => unsupportedDetailTypes.has(details4?.type)
|
|
1249
|
-
).map(({ details: details4 }) => details4?.type)
|
|
1250
|
-
)
|
|
1251
|
-
];
|
|
1252
|
-
if (slugsWithDetailParsingErrors.length > 0) {
|
|
1253
|
-
const postFix = (count) => count > displayCount ? ` and ${count - displayCount} more.` : "";
|
|
1254
|
-
ui().logger.debug(
|
|
1255
|
-
`${chalk5.yellow("\u26A0")} Plugin ${chalk5.bold(
|
|
1256
|
-
PLUGIN_SLUG
|
|
1257
|
-
)} skipped parsing of unsupported audit details: ${chalk5.bold(
|
|
1258
|
-
slugsWithDetailParsingErrors.slice(0, displayCount).join(", ")
|
|
1259
|
-
)}${postFix(slugsWithDetailParsingErrors.length)}`
|
|
1260
|
-
);
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
1566
|
function determineAndSetLogLevel({
|
|
1264
1567
|
verbose,
|
|
1265
1568
|
quiet
|
|
@@ -1275,11 +1578,11 @@ function determineAndSetLogLevel({
|
|
|
1275
1578
|
}
|
|
1276
1579
|
async function getConfig(options = {}) {
|
|
1277
1580
|
const { configPath: filepath, preset } = options;
|
|
1278
|
-
if (
|
|
1581
|
+
if (filepath != null) {
|
|
1279
1582
|
if (filepath.endsWith(".json")) {
|
|
1280
1583
|
return readJsonFile(filepath);
|
|
1281
1584
|
} else if (/\.(ts|js|mjs)$/.test(filepath)) {
|
|
1282
|
-
return
|
|
1585
|
+
return importModule({ filepath, format: "esm" });
|
|
1283
1586
|
} else {
|
|
1284
1587
|
ui().logger.info(`Format of file ${filepath} not supported`);
|
|
1285
1588
|
}
|
|
@@ -1385,9 +1688,9 @@ function logUnsupportedFlagsInUse(flags, displayCount = 3) {
|
|
|
1385
1688
|
if (unsupportedFlagsInUse.length > 0) {
|
|
1386
1689
|
const postFix = (count) => count > displayCount ? ` and ${count - displayCount} more.` : "";
|
|
1387
1690
|
ui().logger.debug(
|
|
1388
|
-
`${
|
|
1691
|
+
`${chalk9.yellow("\u26A0")} Plugin ${chalk9.bold(
|
|
1389
1692
|
LIGHTHOUSE_PLUGIN_SLUG
|
|
1390
|
-
)} used unsupported flags: ${
|
|
1693
|
+
)} used unsupported flags: ${chalk9.bold(
|
|
1391
1694
|
unsupportedFlagsInUse.slice(0, displayCount).join(", ")
|
|
1392
1695
|
)}${postFix(unsupportedFlagsInUse.length)}`
|
|
1393
1696
|
);
|
|
@@ -1494,6 +1797,8 @@ function lighthousePlugin(url, flags) {
|
|
|
1494
1797
|
);
|
|
1495
1798
|
return {
|
|
1496
1799
|
slug: LIGHTHOUSE_PLUGIN_SLUG,
|
|
1800
|
+
packageName: name,
|
|
1801
|
+
version,
|
|
1497
1802
|
title: "Lighthouse",
|
|
1498
1803
|
icon: "lighthouse",
|
|
1499
1804
|
audits: audits2,
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-pushup/lighthouse-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@code-pushup/models": "0.
|
|
6
|
+
"@code-pushup/models": "0.48.0",
|
|
7
7
|
"lighthouse": "^12.0.0",
|
|
8
|
-
"@code-pushup/utils": "0.
|
|
8
|
+
"@code-pushup/utils": "0.48.0",
|
|
9
9
|
"lighthouse-logger": "2.0.1",
|
|
10
10
|
"chalk": "^5.3.0"
|
|
11
11
|
},
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FormattedIcu } from 'lighthouse';
|
|
2
|
+
import type Details from 'lighthouse/types/lhr/audit-details';
|
|
3
|
+
import { Result } from 'lighthouse/types/lhr/audit-result';
|
|
4
|
+
import { AuditDetails } from '@code-pushup/models';
|
|
5
|
+
export declare function toAuditDetails<T extends FormattedIcu<Details>>(details: T | undefined): AuditDetails;
|
|
6
|
+
export declare const unsupportedDetailTypes: Set<string>;
|
|
7
|
+
export declare function logUnsupportedDetails(lhrAudits: Result[], { displayCount }?: {
|
|
8
|
+
displayCount?: number;
|
|
9
|
+
}): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IcuMessage } from 'lighthouse';
|
|
2
|
+
import type Details from 'lighthouse/types/lhr/audit-details';
|
|
3
|
+
export type PrimitiveItemValue = string | number | boolean;
|
|
4
|
+
export type ObjectItemValue = Exclude<Details.ItemValue, PrimitiveItemValue | IcuMessage>;
|
|
5
|
+
export type SimpleItemValue = Extract<ObjectItemValue, Details.NumericValue | Details.CodeValue | Details.UrlValue> | PrimitiveItemValue;
|
|
6
|
+
export declare function trimSlice(item?: PrimitiveItemValue, maxLength?: number): string;
|
|
7
|
+
export declare function parseNodeValue(node?: Details.NodeValue): string;
|
|
8
|
+
export declare function formatTableItemPropertyValue(itemValue?: Details.ItemValue, itemValueFormat?: Details.ItemValueType): Details.ItemValue;
|
|
9
|
+
export declare function parseSimpleItemValue(item: SimpleItemValue): PrimitiveItemValue;
|
|
10
|
+
export declare function parseTableItemPropertyValue(itemValue?: Details.ItemValue): PrimitiveItemValue | Details.LinkValue;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type Details from 'lighthouse/types/lhr/audit-details';
|
|
2
|
+
import { Table, TableRowObject } from '@code-pushup/models';
|
|
3
|
+
export declare function parseOpportunityToAuditDetailsTable(details: Details.Opportunity): Table | undefined;
|
|
4
|
+
export declare function parseOpportunityItemToTableRow(opportunityItem: Details.OpportunityItem, headings: Details.TableColumnHeading[]): TableRowObject;
|
|
5
|
+
export declare function parseOpportunityEntry([key, value]: [
|
|
6
|
+
keyof Details.OpportunityItem,
|
|
7
|
+
Details.OpportunityItem[string]
|
|
8
|
+
], valueType: Details.ItemValueType): string[] | [keyof Details.TableItem, Details.ItemValue | undefined];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type Details from 'lighthouse/types/lhr/audit-details';
|
|
2
|
+
import { Table, TableColumnObject, TableRowObject } from '@code-pushup/models';
|
|
3
|
+
export declare function parseTableToAuditDetailsTable(details: Details.Table): Table | undefined;
|
|
4
|
+
export declare function parseTableColumns(rawHeadings: Details.TableColumnHeading[]): TableColumnObject[];
|
|
5
|
+
export declare function parseTableRow(tableItem: Details.TableItem, headings: Details.TableColumnHeading[]): TableRowObject;
|
|
6
|
+
export declare function parseTableEntry<T extends Details.TableItem>([key, value]: [keyof T, T[keyof T]], valueType?: Details.ItemValueType): [keyof T, Details.ItemValue | undefined];
|
|
@@ -4,13 +4,12 @@ import { AuditOutputs } from '@code-pushup/models';
|
|
|
4
4
|
import type { LighthouseOptions } from '../types';
|
|
5
5
|
import { LighthouseCliFlags } from './types';
|
|
6
6
|
export declare function normalizeAuditOutputs(auditOutputs: AuditOutputs, flags?: LighthouseOptions): AuditOutputs;
|
|
7
|
+
export declare class LighthouseAuditParsingError extends Error {
|
|
8
|
+
constructor(slug: string, error: Error);
|
|
9
|
+
}
|
|
7
10
|
export declare function toAuditOutputs(lhrAudits: Result[], { verbose }?: {
|
|
8
11
|
verbose?: boolean;
|
|
9
12
|
}): AuditOutputs;
|
|
10
|
-
export declare const unsupportedDetailTypes: Set<string>;
|
|
11
|
-
export declare function logUnsupportedDetails(lhrAudits: Result[], { displayCount }?: {
|
|
12
|
-
displayCount?: number;
|
|
13
|
-
}): void;
|
|
14
13
|
export type LighthouseLogLevel = 'verbose' | 'error' | 'info' | 'silent' | 'warn' | undefined;
|
|
15
14
|
export declare function determineAndSetLogLevel({ verbose, quiet, }?: {
|
|
16
15
|
verbose?: boolean;
|