Skip to content

Commit 41087e0

Browse files
committed
fix(template-no-invalid-role): flag empty / whitespace-only role attribute
Previously the rule early-returned when the trimmed role value was empty, silently accepting `<div role="">` and `<div role=" ">`. Both jsx-a11y and vue-a11y flag these — they're authoring mistakes, not no-ops, since the attribute is malformed (no recognized role token) and supplies zero ARIA semantics while still appearing in the DOM. Replace the early-return with a single 'invalid' report (role rendered as the empty string in the message), keeping the existing error format intact. No new messageId; the existing 'invalid' template renders the empty value clearly. Tests: move `role=""` from valid to invalid; add `role=" "` for parity with the trim-then-flag path. Documented as ports of the audit- fixture divergence cases that previously pinned the under-flag behavior.
1 parent 5919767 commit 41087e0

2 files changed

Lines changed: 25 additions & 10 deletions

File tree

lib/rules/template-no-invalid-role.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,23 @@ module.exports = {
155155
return;
156156
}
157157

158+
// ARIA role attribute is a whitespace-separated list of tokens
159+
// (role-fallback pattern per ARIA 1.2 §5.4). An empty / whitespace-
160+
// only value supplies zero tokens — flag as `role=""` to catch the
161+
// authoring mistake (matches jsx-a11y / vue-a11y).
158162
const raw = roleAttr.value.chars.trim();
159163
if (!raw) {
164+
context.report({
165+
node: roleAttr,
166+
messageId: 'invalid',
167+
data: { role: '' },
168+
});
160169
return;
161170
}
162171

163-
// ARIA role attribute is a whitespace-separated list of tokens
164-
// (role-fallback pattern per ARIA 1.2 §5.4). Validate each token.
165-
// Keep the original casing alongside the normalized (lowercase) form
166-
// so reported-back tokens preserve author intent — the validation
167-
// is case-insensitive, the ERROR MESSAGE isn't.
172+
// Validate each token. Keep the original casing alongside the
173+
// normalized (lowercase) form so reported tokens preserve author
174+
// intent — validation is case-insensitive, the ERROR MESSAGE isn't.
168175
const rawTokens = raw.split(/\s+/u);
169176
const tokens = rawTokens.map((t) => t.toLowerCase());
170177

tests/lib/rules/template-no-invalid-role.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,6 @@ ruleTester.run('template-no-invalid-role', rule, {
9494
'<template><div role="associationlistitemvalue"></div></template>',
9595
'<template><div role="comment"></div></template>',
9696
'<template><div role="suggestion"></div></template>',
97-
98-
// Documented divergence — empty role string. jsx-a11y / vue-a11y flag
99-
// it; our rule early-returns on empty/whitespace role values, so we
100-
// don't. Pin our current behavior.
101-
'<template><div role=""></div></template>',
10297
],
10398

10499
invalid: [
@@ -110,6 +105,19 @@ ruleTester.run('template-no-invalid-role', rule, {
110105
output: null,
111106
errors: [{ messageId: 'invalid' }],
112107
},
108+
// Empty / whitespace-only role attribute supplies no recognized role
109+
// token — flag as an authoring mistake. Aligns with jsx-a11y and
110+
// vue-a11y (both flag).
111+
{
112+
code: '<template><div role=""></div></template>',
113+
output: null,
114+
errors: [{ messageId: 'invalid' }],
115+
},
116+
{
117+
code: '<template><div role=" "></div></template>',
118+
output: null,
119+
errors: [{ messageId: 'invalid' }],
120+
},
113121
{
114122
code: `<template>
115123
<div role="invalid">Content</div>

0 commit comments

Comments
 (0)