@jay-framework/a11y-validator 0.23.0 → 0.23.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/dist/index.js +23 -46
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -146,8 +146,7 @@ const validate = (ctx) => {
|
|
|
146
146
|
checkLabelsStructure(ctx.body, allIds, findings);
|
|
147
147
|
walkElements(ctx.body, ctx, (el) => {
|
|
148
148
|
const tag = el.rawTagName?.toLowerCase();
|
|
149
|
-
if (!tag)
|
|
150
|
-
return;
|
|
149
|
+
if (!tag) return;
|
|
151
150
|
if (tag === "img") {
|
|
152
151
|
const alt = el.getAttribute?.("alt");
|
|
153
152
|
if (alt === void 0 || alt === null) {
|
|
@@ -165,8 +164,7 @@ const validate = (ctx) => {
|
|
|
165
164
|
if (IGNORED_INPUT_TYPES.has(type)) {
|
|
166
165
|
return;
|
|
167
166
|
}
|
|
168
|
-
if (!LABELABLE_INPUTS.has(type))
|
|
169
|
-
return;
|
|
167
|
+
if (!LABELABLE_INPUTS.has(type)) return;
|
|
170
168
|
checkLabel(el, tag, findings, labelForIds, allIds);
|
|
171
169
|
}
|
|
172
170
|
if (tag === "select" || tag === "textarea") {
|
|
@@ -316,14 +314,11 @@ function checkLabel(el, tag, findings, labelForIds, allIds) {
|
|
|
316
314
|
}
|
|
317
315
|
}
|
|
318
316
|
}
|
|
319
|
-
if (hasAccessibleName)
|
|
320
|
-
|
|
321
|
-
if (id && labelForIds.has(id))
|
|
322
|
-
return;
|
|
317
|
+
if (hasAccessibleName) return;
|
|
318
|
+
if (id && labelForIds.has(id)) return;
|
|
323
319
|
let parent = el.parentNode;
|
|
324
320
|
while (parent) {
|
|
325
|
-
if (parent.rawTagName?.toLowerCase() === "label")
|
|
326
|
-
return;
|
|
321
|
+
if (parent.rawTagName?.toLowerCase() === "label") return;
|
|
327
322
|
parent = parent.parentNode;
|
|
328
323
|
}
|
|
329
324
|
pushFinding(findings, {
|
|
@@ -342,32 +337,25 @@ function collectDomIndex(el, labelForIds, allIds, idCounts) {
|
|
|
342
337
|
}
|
|
343
338
|
if (el.rawTagName?.toLowerCase() === "label") {
|
|
344
339
|
const forId = el.getAttribute?.("for");
|
|
345
|
-
if (forId)
|
|
346
|
-
labelForIds.add(forId);
|
|
340
|
+
if (forId) labelForIds.add(forId);
|
|
347
341
|
}
|
|
348
342
|
for (const child of el.childNodes ?? []) {
|
|
349
|
-
if (child.nodeType === 1)
|
|
350
|
-
collectDomIndex(child, labelForIds, allIds, idCounts);
|
|
343
|
+
if (child.nodeType === 1) collectDomIndex(child, labelForIds, allIds, idCounts);
|
|
351
344
|
}
|
|
352
345
|
}
|
|
353
346
|
function isLabelableControl(el) {
|
|
354
347
|
const tag = el.rawTagName?.toLowerCase();
|
|
355
|
-
if (tag === "select" || tag === "textarea")
|
|
356
|
-
|
|
357
|
-
if (tag !== "input")
|
|
358
|
-
return false;
|
|
348
|
+
if (tag === "select" || tag === "textarea") return true;
|
|
349
|
+
if (tag !== "input") return false;
|
|
359
350
|
const type = (el.getAttribute?.("type") || "text").toLowerCase();
|
|
360
|
-
if (IGNORED_INPUT_TYPES.has(type))
|
|
361
|
-
return false;
|
|
351
|
+
if (IGNORED_INPUT_TYPES.has(type)) return false;
|
|
362
352
|
return LABELABLE_INPUTS.has(type);
|
|
363
353
|
}
|
|
364
354
|
function countLabelableDescendants(el) {
|
|
365
355
|
let count = 0;
|
|
366
356
|
for (const child of el.childNodes ?? []) {
|
|
367
|
-
if (child.nodeType !== 1)
|
|
368
|
-
|
|
369
|
-
if (isLabelableControl(child))
|
|
370
|
-
count += 1;
|
|
357
|
+
if (child.nodeType !== 1) continue;
|
|
358
|
+
if (isLabelableControl(child)) count += 1;
|
|
371
359
|
count += countLabelableDescendants(child);
|
|
372
360
|
}
|
|
373
361
|
return count;
|
|
@@ -396,8 +384,7 @@ function checkLabelsStructure(root, allIds, findings) {
|
|
|
396
384
|
}
|
|
397
385
|
}
|
|
398
386
|
for (const child of el.childNodes ?? []) {
|
|
399
|
-
if (child.nodeType === 1)
|
|
400
|
-
walk(child);
|
|
387
|
+
if (child.nodeType === 1) walk(child);
|
|
401
388
|
}
|
|
402
389
|
}
|
|
403
390
|
walk(root);
|
|
@@ -408,31 +395,23 @@ function hasHref(el) {
|
|
|
408
395
|
}
|
|
409
396
|
function isInteractiveContainer(el) {
|
|
410
397
|
const role = el.getAttribute?.("role")?.toLowerCase();
|
|
411
|
-
if (role)
|
|
412
|
-
return INTERACTIVE_CONTAINER_ROLES.has(role);
|
|
398
|
+
if (role) return INTERACTIVE_CONTAINER_ROLES.has(role);
|
|
413
399
|
const tag = el.rawTagName?.toLowerCase();
|
|
414
|
-
if (tag === "button")
|
|
415
|
-
|
|
416
|
-
if (tag === "a")
|
|
417
|
-
return hasHref(el);
|
|
400
|
+
if (tag === "button") return true;
|
|
401
|
+
if (tag === "a") return hasHref(el);
|
|
418
402
|
return false;
|
|
419
403
|
}
|
|
420
404
|
function isFocusable(el) {
|
|
421
405
|
const role = el.getAttribute?.("role")?.toLowerCase();
|
|
422
|
-
if (role && WIDGET_ROLES.has(role))
|
|
423
|
-
return true;
|
|
406
|
+
if (role && WIDGET_ROLES.has(role)) return true;
|
|
424
407
|
const tag = el.rawTagName?.toLowerCase();
|
|
425
|
-
if (tag === "a")
|
|
426
|
-
|
|
427
|
-
if (tag
|
|
428
|
-
return (el.getAttribute?.("type") || "text").toLowerCase() !== "hidden";
|
|
429
|
-
if (tag && FOCUSABLE_ELEMENTS.has(tag))
|
|
430
|
-
return true;
|
|
408
|
+
if (tag === "a") return hasHref(el);
|
|
409
|
+
if (tag === "input") return (el.getAttribute?.("type") || "text").toLowerCase() !== "hidden";
|
|
410
|
+
if (tag && FOCUSABLE_ELEMENTS.has(tag)) return true;
|
|
431
411
|
const tabindex = el.getAttribute?.("tabindex");
|
|
432
412
|
if (tabindex !== void 0 && tabindex !== null) {
|
|
433
413
|
const val = parseInt(tabindex, 10);
|
|
434
|
-
if (!isNaN(val) && val >= 0)
|
|
435
|
-
return true;
|
|
414
|
+
if (!isNaN(val) && val >= 0) return true;
|
|
436
415
|
}
|
|
437
416
|
return false;
|
|
438
417
|
}
|
|
@@ -449,15 +428,13 @@ function checkNestedInteractive(root, findings) {
|
|
|
449
428
|
}
|
|
450
429
|
const childAncestor = isInteractiveContainer(el) ? tag ?? ancestorTag : ancestorTag;
|
|
451
430
|
for (const child of el.childNodes ?? []) {
|
|
452
|
-
if (child.nodeType === 1)
|
|
453
|
-
walk(child, childAncestor);
|
|
431
|
+
if (child.nodeType === 1) walk(child, childAncestor);
|
|
454
432
|
}
|
|
455
433
|
}
|
|
456
434
|
walk(root, void 0);
|
|
457
435
|
}
|
|
458
436
|
function getVisibleText(el) {
|
|
459
|
-
if (el.getAttribute?.("aria-hidden") === "true")
|
|
460
|
-
return "";
|
|
437
|
+
if (el.getAttribute?.("aria-hidden") === "true") return "";
|
|
461
438
|
return (el.textContent ?? "").trim().replace(/\s+/g, " ");
|
|
462
439
|
}
|
|
463
440
|
function checkDuplicateAdjacentText(root, findings) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/a11y-validator",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Accessibility validation plugin for Jay Framework — checks jay-html templates for WCAG best practices",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
"test": "vitest run"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@jay-framework/compiler-shared": "^0.23.
|
|
27
|
+
"@jay-framework/compiler-shared": "^0.23.1"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@jay-framework/dev-environment": "^0.23.
|
|
31
|
-
"@jay-framework/jay-stack-cli": "^0.23.
|
|
30
|
+
"@jay-framework/dev-environment": "^0.23.1",
|
|
31
|
+
"@jay-framework/jay-stack-cli": "^0.23.1",
|
|
32
32
|
"@types/node": "^22.15.21",
|
|
33
33
|
"node-html-parser": "^6.1.0",
|
|
34
34
|
"rimraf": "^5.0.5",
|