@diegovelasquezweb/a11y-engine 0.11.9 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegovelasquezweb/a11y-engine",
3
- "version": "0.11.9",
3
+ "version": "0.11.12",
4
4
  "description": "WCAG 2.2 accessibility audit engine — scanner, analyzer, and report builders",
5
5
  "type": "module",
6
6
  "license": "MIT",
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 args = { baseUrl: options.baseUrl || "", target: options.target || "WCAG 2.2 AA" };
856
- const findings = normalizeForReports(payload).filter(
857
- (f) => f.wcagClassification !== "AAA" && f.wcagClassification !== "Best Practice",
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('[data-check]');
976
- function updateProgress() {
977
- let pass=0,fail=0,na=0;
978
- items.forEach(el => { const s=el.dataset.status; if(s==='pass')pass++; else if(s==='fail')fail++; else if(s==='na')na++; });
979
- document.getElementById('count-pass').textContent=pass;
980
- document.getElementById('count-fail').textContent=fail;
981
- document.getElementById('count-na').textContent=na;
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
- document.getElementById('level-filter').addEventListener('change',e=>{
984
- const v=e.target.value;
985
- items.forEach(el=>{el.style.display=(v==='all'||el.dataset.level===v)?'':'none';});
986
- });
987
- items.forEach(el=>{
988
- el.querySelectorAll('[data-action]').forEach(btn=>{
989
- btn.addEventListener('click',()=>{
990
- const action=btn.dataset.action;
991
- el.dataset.status=el.dataset.status===action?'none':action;
992
- updateProgress();
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
- updateProgress();
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>`;
@@ -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 findings = normalizeFindings(inputPayload).filter(
219
- (f) => f.wcagClassification !== "AAA" && f.wcagClassification !== "Best Practice",
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...");