Skip to content

Commit dd083fb

Browse files
committed
fix(template-no-redundant-role): valueless <select size> stays combobox (Copilot review)
Per HTML boolean-attr semantics, a missing-value attribute's value is the empty string — Number('') is 0; 0 is not > 1, so the implicit role of a <select size> (no value) stays combobox. Previously we bailed out to 'unknown' for any sizeAttr.value that wasn't a GlimmerTextNode, conflating valueless with dynamic. Split the two: valueless → combobox (static), dynamic (mustache / concat) → unknown (skip). Add an invalid test: <select role='combobox' size> flags as redundant combobox.
1 parent baa2dd4 commit dd083fb

2 files changed

Lines changed: 23 additions & 3 deletions

File tree

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,16 @@ function getSelectImplicitRole(node) {
6161
}
6262
const sizeAttr = attrs.find((a) => a.name === 'size');
6363
if (sizeAttr) {
64-
if (!sizeAttr.value || sizeAttr.value.type !== 'GlimmerTextNode') {
65-
// Dynamic `size` — can't tell whether implicit role is combobox or
66-
// listbox, so bail out instead of risking a false positive.
64+
// Valueless `size` (e.g. `<select size>`) — per HTML boolean-attr
65+
// semantics the attribute value is an empty string, which Number()
66+
// parses as 0. Per HTML's default size (>1 → listbox), 0 leaves the
67+
// implicit role as combobox. Treat the same as the static-0 case.
68+
if (!sizeAttr.value) {
69+
return 'combobox';
70+
}
71+
if (sizeAttr.value.type !== 'GlimmerTextNode') {
72+
// Dynamic `size={{...}}` / concat — can't tell whether the runtime
73+
// value is >1 or not, so bail out instead of risking a false positive.
6774
return 'unknown';
6875
}
6976
const sizeValue = Number(sizeAttr.value.chars);

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@ ruleTester.run('template-no-redundant-role', rule, {
8787
},
8888
],
8989
},
90+
{
91+
// Valueless `<select size>` — per HTML boolean-attr semantics, the
92+
// attribute value is an empty string; Number('') is 0; 0 is NOT > 1,
93+
// so the implicit role stays combobox. `role="combobox"` is therefore
94+
// redundant and must be flagged.
95+
code: '<template><select role="combobox" size></select></template>',
96+
output: '<template><select size></select></template>',
97+
errors: [
98+
{
99+
message: 'Use of redundant or invalid role: combobox on <select> detected.',
100+
},
101+
],
102+
},
90103
{
91104
// Role-fallback: unknown leading token is skipped per ARIA §4.1.
92105
// `role="xxyxyz button"` resolves to `button`, which IS redundant on

0 commit comments

Comments
 (0)