@diegovelasquezweb/a11y-engine 0.11.8 → 0.11.12
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/package.json +1 -1
- package/src/index.mjs +60 -28
- package/src/pipeline/dom-scanner.mjs +7 -11
- package/src/reports/pdf.mjs +28 -3
package/package.json
CHANGED
package/src/index.mjs
CHANGED
|
@@ -852,10 +852,33 @@ export async function getPDFReport(payload, options = {}) {
|
|
|
852
852
|
buildPdfAuditLimitations,
|
|
853
853
|
} = await import("./reports/renderers/pdf.mjs");
|
|
854
854
|
|
|
855
|
-
const
|
|
856
|
-
|
|
857
|
-
(
|
|
858
|
-
|
|
855
|
+
const deriveConformanceLevel = () => {
|
|
856
|
+
const tags = payload?.metadata?.testingMethodology?.axe_tags || payload?.axeTags || [];
|
|
857
|
+
if (Array.isArray(tags)) {
|
|
858
|
+
if (tags.includes("wcag2aaa")) return "AAA";
|
|
859
|
+
if (tags.includes("wcag2aa") || tags.includes("wcag21aa") || tags.includes("wcag22aa")) return "AA";
|
|
860
|
+
if (tags.includes("wcag2a") || tags.includes("wcag21a") || tags.includes("wcag22a")) return "A";
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
const level = payload?.metadata?.testingMethodology?.conformance_level;
|
|
864
|
+
if (level === "A" || level === "AA" || level === "AAA") return level;
|
|
865
|
+
return "AA";
|
|
866
|
+
};
|
|
867
|
+
|
|
868
|
+
const filterByConformance = (finding, conformanceLevel) => {
|
|
869
|
+
const wcag = finding.wcagClassification;
|
|
870
|
+
if (wcag === "Best Practice") return false;
|
|
871
|
+
if (conformanceLevel === "A") return wcag !== "AA" && wcag !== "AAA";
|
|
872
|
+
if (conformanceLevel === "AA") return wcag !== "AAA";
|
|
873
|
+
return true;
|
|
874
|
+
};
|
|
875
|
+
|
|
876
|
+
const conformanceLevel = deriveConformanceLevel();
|
|
877
|
+
const args = {
|
|
878
|
+
baseUrl: options.baseUrl || "",
|
|
879
|
+
target: options.target || `WCAG 2.2 ${conformanceLevel}`,
|
|
880
|
+
};
|
|
881
|
+
const findings = normalizeForReports(payload).filter((f) => filterByConformance(f, conformanceLevel));
|
|
859
882
|
|
|
860
883
|
const totals = buildSummary(findings);
|
|
861
884
|
const score = computeComplianceScore(totals);
|
|
@@ -943,7 +966,6 @@ export async function getChecklist(options = {}) {
|
|
|
943
966
|
<nav aria-label="Checklist header">
|
|
944
967
|
<div class="max-w-4xl mx-auto px-4 h-16 flex justify-between items-center">
|
|
945
968
|
<div class="flex items-center gap-3">
|
|
946
|
-
<div class="px-3 h-10 rounded-lg bg-slate-900 text-white font-bold text-base font-mono flex items-center justify-center shadow-md">a11y</div>
|
|
947
969
|
<h1 class="text-xl font-bold">Manual <span class="text-slate-500">Checklist</span></h1>
|
|
948
970
|
</div>
|
|
949
971
|
<span class="text-sm text-slate-500 font-medium">${escapeHtml(siteLabel)}</span>
|
|
@@ -957,9 +979,6 @@ export async function getChecklist(options = {}) {
|
|
|
957
979
|
</div>
|
|
958
980
|
<div class="flex flex-wrap items-center gap-3 mb-8">
|
|
959
981
|
<div class="flex items-center gap-1.5 text-sm font-semibold"><span class="inline-block w-3 h-3 rounded-full bg-slate-300"></span><span id="count-total">${TOTAL}</span> Total</div>
|
|
960
|
-
<div class="flex items-center gap-1.5 text-sm font-semibold text-emerald-600"><span class="inline-block w-3 h-3 rounded-full bg-emerald-400"></span><span id="count-pass">0</span> Pass</div>
|
|
961
|
-
<div class="flex items-center gap-1.5 text-sm font-semibold text-rose-600"><span class="inline-block w-3 h-3 rounded-full bg-rose-400"></span><span id="count-fail">0</span> Fail</div>
|
|
962
|
-
<div class="flex items-center gap-1.5 text-sm font-semibold text-amber-600"><span class="inline-block w-3 h-3 rounded-full bg-amber-400"></span><span id="count-na">0</span> N/A</div>
|
|
963
982
|
<div class="ml-auto flex items-center gap-2">
|
|
964
983
|
<select id="level-filter" class="${selectClasses}">
|
|
965
984
|
<option value="all">All levels</option>
|
|
@@ -972,28 +991,41 @@ export async function getChecklist(options = {}) {
|
|
|
972
991
|
<div id="checklist-items" class="space-y-4">${cards}</div>
|
|
973
992
|
</main>
|
|
974
993
|
<script>
|
|
975
|
-
const items = document.querySelectorAll('
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
994
|
+
const items = [...document.querySelectorAll('.manual-card')];
|
|
995
|
+
|
|
996
|
+
function toggleCard(button) {
|
|
997
|
+
const card = button.closest('.manual-card');
|
|
998
|
+
if (!card) return;
|
|
999
|
+
const body = card.querySelector('.card-body');
|
|
1000
|
+
const chevron = card.querySelector('.card-chevron');
|
|
1001
|
+
const expanded = card.dataset.collapsed === 'false';
|
|
1002
|
+
const nextExpanded = !expanded;
|
|
1003
|
+
card.dataset.collapsed = nextExpanded ? 'false' : 'true';
|
|
1004
|
+
button.setAttribute('aria-expanded', nextExpanded ? 'true' : 'false');
|
|
1005
|
+
if (body) body.style.gridTemplateRows = nextExpanded ? '1fr' : '0fr';
|
|
1006
|
+
if (chevron) chevron.style.transform = nextExpanded ? 'rotate(180deg)' : 'rotate(0deg)';
|
|
982
1007
|
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1008
|
+
|
|
1009
|
+
function setManualState(criterion, newState) {
|
|
1010
|
+
const card = document.getElementById('manual-' + criterion.replace(/\./g, '-'));
|
|
1011
|
+
if (!card) return;
|
|
1012
|
+
const current = card.dataset.state || '';
|
|
1013
|
+
card.dataset.state = current === newState ? '' : newState;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
function applyFilter() {
|
|
1017
|
+
const select = document.getElementById('level-filter');
|
|
1018
|
+
const value = select ? select.value : 'all';
|
|
1019
|
+
items.forEach((card) => {
|
|
1020
|
+
card.style.display = value === 'all' || card.dataset.level === value ? '' : 'none';
|
|
994
1021
|
});
|
|
995
|
-
}
|
|
996
|
-
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
window.toggleCard = toggleCard;
|
|
1025
|
+
window.setManualState = setManualState;
|
|
1026
|
+
const levelFilter = document.getElementById('level-filter');
|
|
1027
|
+
if (levelFilter) levelFilter.addEventListener('change', applyFilter);
|
|
1028
|
+
applyFilter();
|
|
997
1029
|
<\/script>
|
|
998
1030
|
</body>
|
|
999
1031
|
</html>`;
|
|
@@ -1060,22 +1060,18 @@ async function runPa11yChecks(routeUrl, axeTags, sharedBrowser = null, includeWa
|
|
|
1060
1060
|
failureSummary: cleanMessage,
|
|
1061
1061
|
};
|
|
1062
1062
|
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
if (!isWarning) {
|
|
1069
|
-
existing.needs_verification = false;
|
|
1070
|
-
}
|
|
1063
|
+
// Group errors and warnings separately — mixing them loses confirmed findings
|
|
1064
|
+
const groupKey = `${ruleId}::${isWarning ? "warning" : "error"}`;
|
|
1065
|
+
|
|
1066
|
+
if (groupedByRule.has(groupKey)) {
|
|
1067
|
+
groupedByRule.get(groupKey).nodes.push(node);
|
|
1071
1068
|
} else {
|
|
1072
|
-
|
|
1073
|
-
groupedByRule.set(ruleId, {
|
|
1069
|
+
groupedByRule.set(groupKey, {
|
|
1074
1070
|
id: ruleId,
|
|
1075
1071
|
impact,
|
|
1076
1072
|
tags: ["pa11y-check", ...(wcagCriterion ? [`wcag${wcagCriterion.replace(/\./g, "")}`] : [])],
|
|
1077
1073
|
description: cleanMessage,
|
|
1078
|
-
help: cleanMessage
|
|
1074
|
+
help: cleanMessage,
|
|
1079
1075
|
helpUrl: wcagCriterion
|
|
1080
1076
|
? `https://www.w3.org/WAI/WCAG21/Understanding/${wcagCriterion.replace(/\./g, "")}`
|
|
1081
1077
|
: "https://squizlabs.github.io/HTML_CodeSniffer/",
|
package/src/reports/pdf.mjs
CHANGED
|
@@ -76,6 +76,29 @@ function parseArgs(argv) {
|
|
|
76
76
|
return args;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
function deriveConformanceLevelFromPayload(payload) {
|
|
80
|
+
const tags = payload?.metadata?.testingMethodology?.axe_tags || payload?.axeTags || [];
|
|
81
|
+
if (Array.isArray(tags)) {
|
|
82
|
+
if (tags.includes("wcag2aaa")) return "AAA";
|
|
83
|
+
if (tags.includes("wcag2aa") || tags.includes("wcag21aa") || tags.includes("wcag22aa")) return "AA";
|
|
84
|
+
if (tags.includes("wcag2a") || tags.includes("wcag21a") || tags.includes("wcag22a")) return "A";
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const level = payload?.metadata?.testingMethodology?.conformance_level;
|
|
88
|
+
if (level === "A" || level === "AA" || level === "AAA") return level;
|
|
89
|
+
return "AA";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function filterByConformance(findings, conformanceLevel) {
|
|
93
|
+
return findings.filter((finding) => {
|
|
94
|
+
const wcag = finding.wcagClassification;
|
|
95
|
+
if (wcag === "Best Practice") return false;
|
|
96
|
+
if (conformanceLevel === "A") return wcag !== "AA" && wcag !== "AAA";
|
|
97
|
+
if (conformanceLevel === "AA") return wcag !== "AAA";
|
|
98
|
+
return true;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
79
102
|
/**
|
|
80
103
|
* Constructs the HTML structure specifically tailored for PDF rendering.
|
|
81
104
|
* @param {Object} args - The parsed CLI arguments.
|
|
@@ -215,9 +238,11 @@ async function main() {
|
|
|
215
238
|
process.exit(1);
|
|
216
239
|
}
|
|
217
240
|
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
241
|
+
const conformanceLevel = deriveConformanceLevelFromPayload(inputPayload);
|
|
242
|
+
if (!args.target || args.target === DEFAULTS.complianceTarget) {
|
|
243
|
+
args.target = `WCAG 2.2 ${conformanceLevel}`;
|
|
244
|
+
}
|
|
245
|
+
const findings = filterByConformance(normalizeFindings(inputPayload), conformanceLevel);
|
|
221
246
|
const html = buildPdfHtml(args, findings);
|
|
222
247
|
|
|
223
248
|
log.info("Generating professional PDF report...");
|