apex-auditor 0.2.0 → 0.2.2
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/dist/cli.js +82 -7
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -47,6 +47,7 @@ function parseArgs(argv) {
|
|
|
47
47
|
*/
|
|
48
48
|
export async function runAuditCli(argv) {
|
|
49
49
|
const args = parseArgs(argv);
|
|
50
|
+
const startTimeMs = Date.now();
|
|
50
51
|
const { configPath, config } = await loadConfig({ configPath: args.configPath });
|
|
51
52
|
const effectiveLogLevel = args.logLevelOverride ?? config.logLevel;
|
|
52
53
|
const effectiveConfig = {
|
|
@@ -66,6 +67,14 @@ export async function runAuditCli(argv) {
|
|
|
66
67
|
console.log(consoleTable);
|
|
67
68
|
printRedIssues(summary.results);
|
|
68
69
|
printCiSummary(args, summary.results, effectiveConfig.budgets);
|
|
70
|
+
printLowestPerformancePages(summary.results, useColor);
|
|
71
|
+
const elapsedMs = Date.now() - startTimeMs;
|
|
72
|
+
const elapsedText = formatElapsedTime(elapsedMs);
|
|
73
|
+
const runsPerTarget = effectiveConfig.runs ?? 1;
|
|
74
|
+
const comboCount = summary.results.length;
|
|
75
|
+
const totalRuns = comboCount * runsPerTarget;
|
|
76
|
+
// eslint-disable-next-line no-console
|
|
77
|
+
console.log(`\nCompleted in ${elapsedText} (${comboCount} page/device combinations x ${runsPerTarget} runs = ${totalRuns} Lighthouse runs).`);
|
|
69
78
|
}
|
|
70
79
|
function buildMarkdown(results) {
|
|
71
80
|
const header = [
|
|
@@ -77,11 +86,11 @@ function buildMarkdown(results) {
|
|
|
77
86
|
}
|
|
78
87
|
function buildConsoleTable(results, useColor) {
|
|
79
88
|
const header = [
|
|
80
|
-
"| Label | Path | Device | P | A | BP | SEO | LCP (s) | FCP (s) | TBT (ms) | CLS |
|
|
81
|
-
"
|
|
89
|
+
"| Label | Path | Device | P | A | BP | SEO | LCP (s) | FCP (s) | TBT (ms) | CLS |",
|
|
90
|
+
"|-------|------|--------|---|---|----|-----|---------|---------|----------|-----|",
|
|
82
91
|
].join("\n");
|
|
83
|
-
const
|
|
84
|
-
return `${header}\n${
|
|
92
|
+
const rows = results.map((result) => buildConsoleRow(result, useColor));
|
|
93
|
+
return `${header}\n${rows.join("\n")}`;
|
|
85
94
|
}
|
|
86
95
|
function buildRow(result) {
|
|
87
96
|
const scores = result.scores;
|
|
@@ -95,19 +104,47 @@ function buildRow(result) {
|
|
|
95
104
|
return `| ${result.label} | ${result.path} | ${result.device} | ${scores.performance ?? "-"} | ${scores.accessibility ?? "-"} | ${scores.bestPractices ?? "-"} | ${scores.seo ?? "-"} | ${lcpSeconds} | ${fcpSeconds} | ${tbtMs} | ${cls} | ${error} | ${issues} |`;
|
|
96
105
|
}
|
|
97
106
|
function buildConsoleRow(result, useColor) {
|
|
107
|
+
const line1 = buildConsoleRowLine1(result, useColor);
|
|
108
|
+
const line2 = buildConsoleRowLine2(result, useColor);
|
|
109
|
+
const line3 = buildConsoleRowLine3(result);
|
|
110
|
+
const lines = [line1];
|
|
111
|
+
if (line2.length > 0) {
|
|
112
|
+
lines.push(line2);
|
|
113
|
+
}
|
|
114
|
+
if (line3.length > 0) {
|
|
115
|
+
lines.push(line3);
|
|
116
|
+
}
|
|
117
|
+
return lines.join("\n");
|
|
118
|
+
}
|
|
119
|
+
function buildConsoleRowLine1(result, useColor) {
|
|
98
120
|
const scores = result.scores;
|
|
99
121
|
const metrics = result.metrics;
|
|
100
122
|
const lcpSeconds = metrics.lcpMs !== undefined ? (metrics.lcpMs / 1000).toFixed(1) : "-";
|
|
101
123
|
const fcpSeconds = metrics.fcpMs !== undefined ? (metrics.fcpMs / 1000).toFixed(1) : "-";
|
|
102
124
|
const tbtMs = metrics.tbtMs !== undefined ? Math.round(metrics.tbtMs).toString() : "-";
|
|
103
125
|
const cls = metrics.cls !== undefined ? metrics.cls.toFixed(3) : "-";
|
|
104
|
-
const issues = formatTopIssues(result.opportunities);
|
|
105
|
-
const error = result.runtimeErrorCode ?? (result.runtimeErrorMessage !== undefined ? result.runtimeErrorMessage : "");
|
|
106
126
|
const performanceText = colourScore(scores.performance, useColor);
|
|
107
127
|
const accessibilityText = colourScore(scores.accessibility, useColor);
|
|
108
128
|
const bestPracticesText = colourScore(scores.bestPractices, useColor);
|
|
109
129
|
const seoText = colourScore(scores.seo, useColor);
|
|
110
|
-
return `| ${result.label} | ${result.path} | ${result.device} | ${performanceText} | ${accessibilityText} | ${bestPracticesText} | ${seoText} | ${lcpSeconds} | ${fcpSeconds} | ${tbtMs} | ${cls}
|
|
130
|
+
return `| ${result.label} | ${result.path} | ${result.device} | ${performanceText} | ${accessibilityText} | ${bestPracticesText} | ${seoText} | ${lcpSeconds} | ${fcpSeconds} | ${tbtMs} | ${cls} |`;
|
|
131
|
+
}
|
|
132
|
+
function buildConsoleRowLine2(result, useColor) {
|
|
133
|
+
const errorCode = result.runtimeErrorCode;
|
|
134
|
+
const errorMessage = result.runtimeErrorMessage;
|
|
135
|
+
if (!errorCode && !errorMessage) {
|
|
136
|
+
return "";
|
|
137
|
+
}
|
|
138
|
+
const errorText = errorCode ?? errorMessage ?? "";
|
|
139
|
+
const prefix = useColor ? `${ANSI_RED}↳ Error:${ANSI_RESET}` : "↳ Error:";
|
|
140
|
+
return ` ${prefix} ${errorText}`;
|
|
141
|
+
}
|
|
142
|
+
function buildConsoleRowLine3(result) {
|
|
143
|
+
const issues = formatTopIssues(result.opportunities);
|
|
144
|
+
if (issues.length === 0) {
|
|
145
|
+
return "";
|
|
146
|
+
}
|
|
147
|
+
return ` ↳ Top issues: ${issues}`;
|
|
111
148
|
}
|
|
112
149
|
function formatTopIssues(opportunities) {
|
|
113
150
|
if (opportunities.length === 0) {
|
|
@@ -250,6 +287,44 @@ function addCategoryViolation(id, actual, limit, result, allViolations) {
|
|
|
250
287
|
limit,
|
|
251
288
|
});
|
|
252
289
|
}
|
|
290
|
+
function formatElapsedTime(elapsedMs) {
|
|
291
|
+
const totalSeconds = Math.round(elapsedMs / 1000);
|
|
292
|
+
if (totalSeconds < 60) {
|
|
293
|
+
return `${totalSeconds}s`;
|
|
294
|
+
}
|
|
295
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
296
|
+
const remainingSeconds = totalSeconds % 60;
|
|
297
|
+
if (remainingSeconds === 0) {
|
|
298
|
+
return `${minutes}m`;
|
|
299
|
+
}
|
|
300
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
301
|
+
}
|
|
302
|
+
function printLowestPerformancePages(results, useColor) {
|
|
303
|
+
const entries = results.map((result) => ({
|
|
304
|
+
result,
|
|
305
|
+
performance: result.scores.performance,
|
|
306
|
+
}));
|
|
307
|
+
const definedEntries = entries
|
|
308
|
+
.filter((entry) => {
|
|
309
|
+
return typeof entry.performance === "number";
|
|
310
|
+
})
|
|
311
|
+
.sort((a, b) => a.performance - b.performance);
|
|
312
|
+
const limit = 5;
|
|
313
|
+
const worst = definedEntries.slice(0, limit);
|
|
314
|
+
if (worst.length === 0) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
// eslint-disable-next-line no-console
|
|
318
|
+
console.log("\nLowest Performance pages:");
|
|
319
|
+
for (const entry of worst) {
|
|
320
|
+
const perfText = colourScore(entry.performance, useColor);
|
|
321
|
+
const label = entry.result.label;
|
|
322
|
+
const path = entry.result.path;
|
|
323
|
+
const device = entry.result.device;
|
|
324
|
+
// eslint-disable-next-line no-console
|
|
325
|
+
console.log(`- ${label} ${path} [${device}] P:${perfText}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
253
328
|
function collectMetricViolations(result, metricsBudgets, allViolations) {
|
|
254
329
|
const metrics = result.metrics;
|
|
255
330
|
addMetricViolation("lcpMs", metrics.lcpMs, metricsBudgets.lcpMs, result, allViolations);
|