check noninteractive roles on interactive elements

pull/5955/head
Anthony Le Goas 6 years ago committed by tanhauhau
parent 1913e7fad7
commit bde3236071

@ -24,6 +24,8 @@ import { Literal } from 'estree';
import compiler_warnings from '../compiler_warnings'; import compiler_warnings from '../compiler_warnings';
import compiler_errors from '../compiler_errors'; import compiler_errors from '../compiler_errors';
import { ARIARoleDefintionKey, roles, aria, ARIAPropertyDefinition, ARIAProperty } from 'aria-query'; import { ARIARoleDefintionKey, roles, aria, ARIAPropertyDefinition, ARIAProperty } from 'aria-query';
import { noninteractive_roles } from '../utils/aria_roles';
import { interactive_elements } from '../utils/elements';
const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|svg|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/; const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|svg|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/;
@ -684,6 +686,18 @@ export default class Element extends Node {
if (handlers_map.has('mouseout') && !handlers_map.has('blur')) { if (handlers_map.has('mouseout') && !handlers_map.has('blur')) {
component.warn(this, compiler_warnings.a11y_mouse_events_have_key_events('mouseout', 'blur')); component.warn(this, compiler_warnings.a11y_mouse_events_have_key_events('mouseout', 'blur'));
} }
if (interactive_elements.has(this.name)) {
if (attribute_map.has('role')) {
const roleValue = this.attributes.find(a => a.name === 'role').get_static_value().toString() as ARIARoleDefintionKey;
if (noninteractive_roles.has(roleValue)) {
component.warn(this, {
code: 'a11y-no-interactive-element-to-noninteractive-role',
message: `A11y: <${this.name}> cannot have role ${roleValue}`
});
}
}
}
} }
validate_bindings_foreign() { validate_bindings_foreign() {

@ -0,0 +1,9 @@
import { roles as rolesMap } from 'aria-query';
const roles = [...rolesMap.keys()];
const noninteractive_roles = new Set(roles
.filter((name) => !rolesMap.get(name).abstract)
.filter((name) => !rolesMap.get(name).superClass.some((c) => c.includes('widget'))));
export { noninteractive_roles };

@ -0,0 +1,5 @@
const interactive_elements = new Set([
'a', 'button', 'input', 'select', 'textarea'
]);
export { interactive_elements };

@ -0,0 +1,54 @@
<!-- a -->
<a href="test" role="article">link</a>
<a href="test" role="banner">link</a>
<a href="test" role="complementary">link</a>
<a href="test" role="img">link</a>
<a href="test" role="listitem">link</a>
<a href="test" role="main">link</a>
<a href="test" role="region">link</a>
<a href="test" role="tooltip">link</a>
<a href="test" role="button">link</a>
<!-- button -->
<button role="article">button</button>
<button role="banner">button</button>
<button role="complementary">button</button>
<button role="img">button</button>
<button role="listitem">button</button>
<button role="main">button</button>
<button role="region">button</button>
<button role="tooltip">button</button>
<button role="button">button</button>
<!-- input -->
<input role="article"/>
<input role="banner"/>
<input role="complementary"/>
<input role="img"/>
<input role="listitem"/>
<input role="main"/>
<input role="region"/>
<input role="tooltip"/>
<input role="button"/>
<!-- select -->
<select role="article"/>
<select role="banner"/>
<select role="complementary"/>
<select role="img"/>
<select role="listitem"/>
<select role="main"/>
<select role="region"/>
<select role="tooltip"/>
<select role="button"/>
<!-- textarea -->
<textarea role="article"/>
<textarea role="banner"/>
<textarea role="complementary"/>
<textarea role="img"/>
<textarea role="listitem"/>
<textarea role="main"/>
<textarea role="region"/>
<textarea role="tooltip"/>
<textarea role="button"/>

@ -0,0 +1,602 @@
[
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 49,
"column": 38,
"line": 2
},
"message": "A11y: <a> cannot have role article",
"pos": 11,
"start": {
"character": 11,
"column": 0,
"line": 2
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 87,
"column": 37,
"line": 3
},
"message": "A11y: <a> cannot have role banner",
"pos": 50,
"start": {
"character": 50,
"column": 0,
"line": 3
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 132,
"column": 44,
"line": 4
},
"message": "A11y: <a> cannot have role complementary",
"pos": 88,
"start": {
"character": 88,
"column": 0,
"line": 4
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 167,
"column": 34,
"line": 5
},
"message": "A11y: <a> cannot have role img",
"pos": 133,
"start": {
"character": 133,
"column": 0,
"line": 5
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 207,
"column": 39,
"line": 6
},
"message": "A11y: <a> cannot have role listitem",
"pos": 168,
"start": {
"character": 168,
"column": 0,
"line": 6
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 243,
"column": 35,
"line": 7
},
"message": "A11y: <a> cannot have role main",
"pos": 208,
"start": {
"character": 208,
"column": 0,
"line": 7
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 281,
"column": 37,
"line": 8
},
"message": "A11y: <a> cannot have role region",
"pos": 244,
"start": {
"character": 244,
"column": 0,
"line": 8
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 320,
"column": 38,
"line": 9
},
"message": "A11y: <a> cannot have role tooltip",
"pos": 282,
"start": {
"character": 282,
"column": 0,
"line": 9
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 414,
"column": 38,
"line": 13
},
"message": "A11y: <button> cannot have role article",
"pos": 376,
"start": {
"character": 376,
"column": 0,
"line": 13
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 452,
"column": 37,
"line": 14
},
"message": "A11y: <button> cannot have role banner",
"pos": 415,
"start": {
"character": 415,
"column": 0,
"line": 14
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 497,
"column": 44,
"line": 15
},
"message": "A11y: <button> cannot have role complementary",
"pos": 453,
"start": {
"character": 453,
"column": 0,
"line": 15
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 532,
"column": 34,
"line": 16
},
"message": "A11y: <button> cannot have role img",
"pos": 498,
"start": {
"character": 498,
"column": 0,
"line": 16
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 572,
"column": 39,
"line": 17
},
"message": "A11y: <button> cannot have role listitem",
"pos": 533,
"start": {
"character": 533,
"column": 0,
"line": 17
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 608,
"column": 35,
"line": 18
},
"message": "A11y: <button> cannot have role main",
"pos": 573,
"start": {
"character": 573,
"column": 0,
"line": 18
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 646,
"column": 37,
"line": 19
},
"message": "A11y: <button> cannot have role region",
"pos": 609,
"start": {
"character": 609,
"column": 0,
"line": 19
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 685,
"column": 38,
"line": 20
},
"message": "A11y: <button> cannot have role tooltip",
"pos": 647,
"start": {
"character": 647,
"column": 0,
"line": 20
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 763,
"column": 23,
"line": 24
},
"message": "A11y: <input> cannot have role article",
"pos": 740,
"start": {
"character": 740,
"column": 0,
"line": 24
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 786,
"column": 22,
"line": 25
},
"message": "A11y: <input> cannot have role banner",
"pos": 764,
"start": {
"character": 764,
"column": 0,
"line": 25
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 816,
"column": 29,
"line": 26
},
"message": "A11y: <input> cannot have role complementary",
"pos": 787,
"start": {
"character": 787,
"column": 0,
"line": 26
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 836,
"column": 19,
"line": 27
},
"message": "A11y: <input> cannot have role img",
"pos": 817,
"start": {
"character": 817,
"column": 0,
"line": 27
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 861,
"column": 24,
"line": 28
},
"message": "A11y: <input> cannot have role listitem",
"pos": 837,
"start": {
"character": 837,
"column": 0,
"line": 28
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 882,
"column": 20,
"line": 29
},
"message": "A11y: <input> cannot have role main",
"pos": 862,
"start": {
"character": 862,
"column": 0,
"line": 29
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 905,
"column": 22,
"line": 30
},
"message": "A11y: <input> cannot have role region",
"pos": 883,
"start": {
"character": 883,
"column": 0,
"line": 30
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 929,
"column": 23,
"line": 31
},
"message": "A11y: <input> cannot have role tooltip",
"pos": 906,
"start": {
"character": 906,
"column": 0,
"line": 31
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 994,
"column": 24,
"line": 35
},
"message": "A11y: <select> cannot have role article",
"pos": 970,
"start": {
"character": 970,
"column": 0,
"line": 35
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1018,
"column": 23,
"line": 36
},
"message": "A11y: <select> cannot have role banner",
"pos": 995,
"start": {
"character": 995,
"column": 0,
"line": 36
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1049,
"column": 30,
"line": 37
},
"message": "A11y: <select> cannot have role complementary",
"pos": 1019,
"start": {
"character": 1019,
"column": 0,
"line": 37
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1070,
"column": 20,
"line": 38
},
"message": "A11y: <select> cannot have role img",
"pos": 1050,
"start": {
"character": 1050,
"column": 0,
"line": 38
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1096,
"column": 25,
"line": 39
},
"message": "A11y: <select> cannot have role listitem",
"pos": 1071,
"start": {
"character": 1071,
"column": 0,
"line": 39
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1118,
"column": 21,
"line": 40
},
"message": "A11y: <select> cannot have role main",
"pos": 1097,
"start": {
"character": 1097,
"column": 0,
"line": 40
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1142,
"column": 23,
"line": 41
},
"message": "A11y: <select> cannot have role region",
"pos": 1119,
"start": {
"character": 1119,
"column": 0,
"line": 41
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1167,
"column": 24,
"line": 42
},
"message": "A11y: <select> cannot have role tooltip",
"pos": 1143,
"start": {
"character": 1143,
"column": 0,
"line": 42
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1237,
"column": 26,
"line": 46
},
"message": "A11y: <textarea> cannot have role article",
"pos": 1211,
"start": {
"character": 1211,
"column": 0,
"line": 46
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1263,
"column": 25,
"line": 47
},
"message": "A11y: <textarea> cannot have role banner",
"pos": 1238,
"start": {
"character": 1238,
"column": 0,
"line": 47
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1296,
"column": 32,
"line": 48
},
"message": "A11y: <textarea> cannot have role complementary",
"pos": 1264,
"start": {
"character": 1264,
"column": 0,
"line": 48
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1319,
"column": 22,
"line": 49
},
"message": "A11y: <textarea> cannot have role img",
"pos": 1297,
"start": {
"character": 1297,
"column": 0,
"line": 49
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1347,
"column": 27,
"line": 50
},
"message": "A11y: <textarea> cannot have role listitem",
"pos": 1320,
"start": {
"character": 1320,
"column": 0,
"line": 50
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1371,
"column": 23,
"line": 51
},
"message": "A11y: <textarea> cannot have role main",
"pos": 1348,
"start": {
"character": 1348,
"column": 0,
"line": 51
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1397,
"column": 25,
"line": 52
},
"message": "A11y: <textarea> cannot have role region",
"pos": 1372,
"start": {
"character": 1372,
"column": 0,
"line": 52
}
},
{
"code": "a11y-no-interactive-element-to-noninteractive-role",
"end": {
"character": 1424,
"column": 26,
"line": 53
},
"message": "A11y: <textarea> cannot have role tooltip",
"pos": 1398,
"start": {
"character": 1398,
"column": 0,
"line": 53
}
}
]
Loading…
Cancel
Save