Skip to content

Commit 8e43e9a

Browse files
authored
fix: correctly interpret empty aria- attribute (#11325)
* fix: correctly interpret empty aria- attribute * changeset * huh * only suggest default value for boolean/tristate attributes * adjust messages, disallow empty strings * gah
1 parent 9a887f8 commit 8e43e9a

File tree

28 files changed

+337
-348
lines changed

28 files changed

+337
-348
lines changed

.changeset/brown-geckos-fry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: correctly interpret empty aria- attribute

packages/svelte/messages/compile-warnings/a11y.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@
4444
4545
## a11y_incorrect_aria_attribute_type
4646

47-
> The value of '%attribute%' must be of type %type%
47+
> The value of '%attribute%' must be a %type%
4848
4949
## a11y_incorrect_aria_attribute_type_boolean
5050

51-
> The value of '%attribute%' must be either 'true' or 'false'
51+
> The value of '%attribute%' must be either 'true' or 'false'. It cannot be empty
5252
5353
## a11y_incorrect_aria_attribute_type_id
5454

packages/svelte/src/compiler/phases/2-analyze/a11y.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ function has_disabled_attribute(attribute_map) {
103103
const aria_disabled_attr = attribute_map.get('aria-disabled');
104104
if (aria_disabled_attr) {
105105
const aria_disabled_attr_value = get_static_value(aria_disabled_attr);
106-
if (aria_disabled_attr_value === true) {
106+
if (aria_disabled_attr_value === 'true') {
107107
return true;
108108
}
109109
}
@@ -601,20 +601,19 @@ function is_parent(parent, elements) {
601601
*/
602602
function validate_aria_attribute_value(attribute, name, schema, value) {
603603
const type = schema.type;
604-
const is_string = typeof value === 'string';
605604

606605
if (value === null) return;
607-
if (value === true) value = 'true'; // TODO this is actually incorrect, and we should fix it
606+
if (value === true) value = '';
608607

609608
if (type === 'boolean' && value !== 'true' && value !== 'false') {
610609
w.a11y_incorrect_aria_attribute_type_boolean(attribute, name);
611-
} else if (type === 'integer' && !Number.isInteger(+value)) {
610+
} else if (type === 'integer' && (value === '' || !Number.isInteger(+value))) {
612611
w.a11y_incorrect_aria_attribute_type_integer(attribute, name);
613-
} else if (type === 'number' && isNaN(+value)) {
612+
} else if (type === 'number' && (value === '' || isNaN(+value))) {
614613
w.a11y_incorrect_aria_attribute_type(attribute, name, 'number');
615-
} else if ((type === 'string' || type === 'id') && !is_string) {
616-
w.a11y_incorrect_aria_attribute_type(attribute, name, 'string');
617-
} else if (type === 'idlist' && !is_string) {
614+
} else if ((type === 'string' || type === 'id') && value === '') {
615+
w.a11y_incorrect_aria_attribute_type(attribute, name, 'non-empty string');
616+
} else if (type === 'idlist' && value === '') {
618617
w.a11y_incorrect_aria_attribute_type_idlist(attribute, name);
619618
} else if (type === 'token') {
620619
const values = (schema.values ?? []).map((value) => value.toString());

packages/svelte/src/compiler/warnings.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,22 +134,22 @@ export function a11y_img_redundant_alt(node) {
134134
}
135135

136136
/**
137-
* The value of '%attribute%' must be of type %type%
137+
* The value of '%attribute%' must be a %type%
138138
* @param {null | NodeLike} node
139139
* @param {string} attribute
140140
* @param {string} type
141141
*/
142142
export function a11y_incorrect_aria_attribute_type(node, attribute, type) {
143-
w(node, "a11y_incorrect_aria_attribute_type", `The value of '${attribute}' must be of type ${type}`);
143+
w(node, "a11y_incorrect_aria_attribute_type", `The value of '${attribute}' must be a ${type}`);
144144
}
145145

146146
/**
147-
* The value of '%attribute%' must be either 'true' or 'false'
147+
* The value of '%attribute%' must be either 'true' or 'false'. It cannot be empty
148148
* @param {null | NodeLike} node
149149
* @param {string} attribute
150150
*/
151151
export function a11y_incorrect_aria_attribute_type_boolean(node, attribute) {
152-
w(node, "a11y_incorrect_aria_attribute_type_boolean", `The value of '${attribute}' must be either 'true' or 'false'`);
152+
w(node, "a11y_incorrect_aria_attribute_type_boolean", `The value of '${attribute}' must be either 'true' or 'false'. It cannot be empty`);
153153
}
154154

155155
/**

packages/svelte/tests/validator/samples/a11y-aria-proptypes-boolean/warnings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
22
{
33
"code": "a11y_incorrect_aria_attribute_type_boolean",
4-
"message": "The value of 'aria-disabled' must be either 'true' or 'false'",
4+
"message": "The value of 'aria-disabled' must be either 'true' or 'false'. It cannot be empty",
55
"start": {
66
"line": 5,
77
"column": 8
@@ -13,7 +13,7 @@
1313
},
1414
{
1515
"code": "a11y_incorrect_aria_attribute_type_boolean",
16-
"message": "The value of 'aria-disabled' must be either 'true' or 'false'",
16+
"message": "The value of 'aria-disabled' must be either 'true' or 'false'. It cannot be empty",
1717
"start": {
1818
"line": 6,
1919
"column": 8
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<div aria-level="yes"></div>
22
<div aria-level="no"></div>
33
<div aria-level={`abc`}></div>
4-
<div aria-level={true}></div>
54
<div aria-level></div>
65
<div aria-level={"false"}></div>
76
<div aria-level={!"false"}></div>

packages/svelte/tests/validator/samples/a11y-aria-proptypes-integer/warnings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@
2727
"code": "a11y_incorrect_aria_attribute_type_integer",
2828
"message": "The value of 'aria-level' must be an integer",
2929
"start": {
30-
"line": 5,
30+
"line": 4,
3131
"column": 5
3232
},
3333
"end": {
34-
"line": 5,
34+
"line": 4,
3535
"column": 15
3636
}
3737
}

packages/svelte/tests/validator/samples/a11y-aria-proptypes-number/input.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
<div aria-valuemax="no"></div>
33
<div aria-valuemax={`abc`}></div>
44
<div aria-valuemax={true}></div>
5-
<div aria-valuemax></div>
5+
<div aria-valuemax="true"></div>
66
<div aria-valuemax={'false'}></div>
77
<div aria-valuemax={!'false'}></div>

packages/svelte/tests/validator/samples/a11y-aria-proptypes-number/warnings.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
22
{
33
"code": "a11y_incorrect_aria_attribute_type",
4-
"message": "The value of 'aria-valuemax' must be of type number",
4+
"message": "The value of 'aria-valuemax' must be a number",
55
"start": {
66
"line": 1,
77
"column": 5
@@ -13,7 +13,7 @@
1313
},
1414
{
1515
"code": "a11y_incorrect_aria_attribute_type",
16-
"message": "The value of 'aria-valuemax' must be of type number",
16+
"message": "The value of 'aria-valuemax' must be a number",
1717
"start": {
1818
"line": 2,
1919
"column": 5
@@ -25,14 +25,14 @@
2525
},
2626
{
2727
"code": "a11y_incorrect_aria_attribute_type",
28-
"message": "The value of 'aria-valuemax' must be of type number",
28+
"message": "The value of 'aria-valuemax' must be a number",
2929
"start": {
3030
"line": 5,
3131
"column": 5
3232
},
3333
"end": {
3434
"line": 5,
35-
"column": 18
35+
"column": 25
3636
}
3737
}
3838
]

packages/svelte/tests/validator/samples/a11y-aria-proptypes-string/input.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div aria-label></div>
1+
<div aria-label="true"></div>
22
<div aria-label={true}></div>
33
<div aria-label={false}></div>
44
<div aria-label={1234}></div>
Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1 @@
1-
[
2-
{
3-
"code": "a11y_incorrect_aria_attribute_type",
4-
"message": "The value of 'aria-label' must be of type string",
5-
"start": {
6-
"line": 1,
7-
"column": 5
8-
},
9-
"end": {
10-
"line": 1,
11-
"column": 15
12-
}
13-
}
14-
]
1+
[]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div aria-sort=""></div>
22
<div aria-sort="incorrect"></div>
3-
<div aria-sort></div>
3+
<div aria-sort="true"></div>
44
<div aria-sort={true}></div>
55
<div aria-sort={"false"}></div>
66
<div aria-sort="ascending descending"></div>

packages/svelte/tests/validator/samples/a11y-aria-proptypes-token/warnings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
},
3333
"end": {
3434
"line": 3,
35-
"column": 14
35+
"column": 21
3636
}
3737
},
3838
{

packages/svelte/tests/validator/samples/a11y-aria-proptypes-tokenlist/input.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div aria-relevant=""></div>
22
<div aria-relevant="foobar"></div>
3-
<div aria-relevant></div>
3+
<div aria-relevant="true"></div>
44
<div aria-relevant={true}></div>
55
<div aria-relevant={"false"}></div>
66
<div aria-relevant="additions removals_"></div>

packages/svelte/tests/validator/samples/a11y-aria-proptypes-tokenlist/warnings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
},
3333
"end": {
3434
"line": 3,
35-
"column": 18
35+
"column": 25
3636
}
3737
},
3838
{

packages/svelte/tests/validator/samples/a11y-click-events-have-key-events/input.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
<input on:click={noop} type="hidden" />
5858

5959
<!-- svelte-ignore a11y_no_static_element_interactions -->
60-
<div on:click={noop} aria-hidden></div>
60+
<div on:click={noop} aria-hidden="true"></div>
6161
<!-- svelte-ignore a11y_no_static_element_interactions -->
6262
<div on:click={noop} aria-hidden="true"></div>
6363
<!-- svelte-ignore a11y_no_static_element_interactions -->
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
<h1></h1>
2-
<h2 aria-hidden>invisible header</h2>
2+
<h2 aria-hidden="true">invisible header</h2>

packages/svelte/tests/validator/samples/a11y-heading-has-content/warnings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
},
2121
"end": {
2222
"line": 2,
23-
"column": 15
23+
"column": 22
2424
}
2525
}
2626
]

packages/svelte/tests/validator/samples/a11y-img-redundant-alt/input.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<img src="foo" alt="Foo eating a sandwich." />
2-
<img src="bar" aria-hidden alt="Picture of me taking a photo of an image" />
2+
<img src="bar" aria-hidden="true" alt="Picture of me taking a photo of an image" />
33
<img src="foo" alt="Photo of foo being weird." />
44
<img src="bar" alt="Image of me at a bar!" />
55
<img src="foo" alt="Picture of baz fixing a bug." />

packages/svelte/tests/validator/samples/a11y-interactive-supports-focus/input.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!-- VALID -->
2-
<div aria-hidden role="button" on:keypress={() => {}}></div>
3-
<div aria-disabled role="button" on:keypress={() => {}}></div>
2+
<div aria-hidden="true" role="button" on:keypress={() => {}}></div>
3+
<div aria-disabled="true" role="button" on:keypress={() => {}}></div>
44
<div disabled role="button" on:keypress={() => {}}></div>
55
<div role="presentation" on:keypress={() => {}}></div>
66
<button on:click={() => {}}></button>

packages/svelte/tests/validator/samples/a11y-media-has-caption/input.svelte

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@
22
<video></video>
33
<video><track /></video>
44
<audio></audio>
5-
<video aria-hidden></video>
6-
<video aria-hidden="false"></video>
75
<video aria-hidden="true"></video>
6+
<video aria-hidden="false"></video>

packages/svelte/tests/validator/samples/a11y-media-has-caption/warnings.json

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,6 @@
2323
"line": 3
2424
}
2525
},
26-
{
27-
"code": "a11y_media_has_caption",
28-
"end": {
29-
"column": 27,
30-
"line": 5
31-
},
32-
"message": "`<video>` elements must have a `<track kind=\"captions\">`",
33-
"start": {
34-
"column": 0,
35-
"line": 5
36-
}
37-
},
3826
{
3927
"code": "a11y_media_has_caption",
4028
"end": {

packages/svelte/tests/validator/samples/a11y-no-interactive-element-to-noninteractive-role/input.svelte

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,19 +83,19 @@
8383
<div role="menu"></div>
8484
<div role="menubar"></div>
8585
<div role="menuitem"></div>
86-
<div role="menuitemcheckbox" aria-checked></div>
87-
<div role="menuitemradio" aria-checked></div>
88-
<div role="option" aria-selected></div>
86+
<div role="menuitemcheckbox" aria-checked="true"></div>
87+
<div role="menuitemradio" aria-checked="true"></div>
88+
<div role="option" aria-selected="true"></div>
8989
<div role="progressbar"></div>
90-
<div role="radio" aria-checked></div>
90+
<div role="radio" aria-checked="true"></div>
9191
<div role="radiogroup"></div>
9292
<div role="row"></div>
9393
<div role="rowheader"></div>
9494
<div role="scrollbar" aria-controls={[]} aria-valuenow={0}></div>
9595
<div role="searchbox"></div>
9696
<div role="slider" aria-valuenow={0}></div>
9797
<div role="spinbutton"></div>
98-
<div role="switch" aria-checked></div>
98+
<div role="switch" aria-checked="true"></div>
9999
<div role="tab"></div>
100100
<div role="textbox"></div>
101101
<div role="treeitem" aria-selected={true}></div>

packages/svelte/tests/validator/samples/a11y-no-noninteractive-element-interactions/input.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!-- VALID -->
22
<div role="presentation" on:mouseup={() => {}}></div>
33
<div role="button" tabindex="-1" on:click={() => {}} on:keypress={() => {}}></div>
4-
<div role="listitem" aria-hidden on:click={() => {}} on:keypress={() => {}}></div>
4+
<div role="listitem" aria-hidden="true" on:click={() => {}} on:keypress={() => {}}></div>
55
<button on:click={() => {}}></button>
66
<h1 contenteditable="true" on:keydown={() => {}}>Heading</h1>
77
<h1>Heading</h1>

0 commit comments

Comments
 (0)