Skip to content

Commit 4705533

Browse files
committed
fix: skip dynamic roles, fix code formatting (Copilot review)
1 parent 50d6782 commit 4705533

3 files changed

Lines changed: 21 additions & 7 deletions

File tree

docs/rules/template-no-aria-label-misuse.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ the plugin's "when in doubt, don't flag" stance.
3939
## Configuration
4040

4141
- `strictTabindex` (`boolean`, default `false`): when `true`, the
42-
tabindex escape hatch is disabled — a `<div tabindex="0"
43-
aria-label="x">` is flagged as strictly as any other generic element.
44-
Enable this for strict spec-role enforcement.
42+
tabindex escape hatch is disabled — a `<div tabindex="0" aria-label="x">`
43+
is flagged as strictly as any other generic element. Enable this for
44+
strict spec-role enforcement.
4545

4646
```js
4747
module.exports = {

lib/rules/template-no-aria-label-misuse.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Logic inspired by html-validate (MIT), Copyright 2017 David Sveningsson.
22
// Role resolution delegates to `aria-query` — the authoritative WAI-ARIA
3-
// data package (already a dependency of this plugin). `roles.get(r)
4-
// .prohibitedProps` drives the flag/allow decision.
3+
// data package (already a dependency of this plugin). The
4+
// `roles.get(r).prohibitedProps` list drives the flag/allow decision.
55

66
const { roles, elementRoles } = require('aria-query');
77

@@ -79,12 +79,22 @@ function getImplicitRole(node) {
7979
}
8080

8181
function getRole(node) {
82-
const explicit = getStaticAttrString(node, 'role');
83-
if (explicit) {
82+
const roleAttr = findAttr(node, 'role');
83+
if (roleAttr) {
84+
// Present but dynamic (mustache / concat) — the runtime role is unknown,
85+
// and if it differs from the element's implicit role we'd false-positive
86+
// against the implicit. Skip rather than guess.
87+
const explicit = getStaticAttrString(node, 'role');
88+
if (explicit === null) {
89+
return null;
90+
}
8491
const first = explicit.trim().split(/\s+/)[0]?.toLowerCase();
8592
if (first && roles.has(first)) {
8693
return first;
8794
}
95+
// `role` present with an unknown token (e.g. `role="bogus"`) — per ARIA
96+
// the invalid value is ignored and the implicit role applies. Fall
97+
// through to the implicit-role lookup.
8898
}
8999
return getImplicitRole(node);
90100
}

tests/lib/rules/template-no-aria-label-misuse.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ const validHbs = [
3737
'<section aria-label="About"></section>',
3838
// <form> transitions to role=form when aria-label is present.
3939
'<form aria-label="Search"></form>',
40+
// Dynamic role — runtime role may differ from implicit; skip rather than
41+
// false-flag against the element's implicit role.
42+
'<div role={{this.role}} aria-label="x">x</div>',
43+
'<span role={{this.role}} aria-labelledby="t">x</span>',
4044
];
4145

4246
const invalidHbs = [

0 commit comments

Comments
 (0)