Skip to content

Commit dbaf144

Browse files
Merge pull request #2398 from NullVoxPopuli/nvp/template-lint-extract-rule-template-no-abstract-roles
Extract rule: template-no-abstract-roles
2 parents f758a0a + dc03efa commit dbaf144

4 files changed

Lines changed: 114 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ rules in templates can be disabled with eslint directives with mustache or html
179179
| Name | Description | 💼 | 🔧 | 💡 |
180180
| :------------------------------------------------------------------------------- | :-------------------------------------- | :- | :- | :- |
181181
| [template-link-href-attributes](docs/rules/template-link-href-attributes.md) | require href attribute on link elements | | | |
182+
| [template-no-abstract-roles](docs/rules/template-no-abstract-roles.md) | disallow abstract ARIA roles | | | |
182183
| [template-no-accesskey-attribute](docs/rules/template-no-accesskey-attribute.md) | disallow accesskey attribute | | 🔧 | |
183184

184185
### Best Practices
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# ember/template-no-abstract-roles
2+
3+
<!-- end auto-generated rule header -->
4+
5+
The HTML attribute `role` must never have the following values:
6+
7+
- `command`
8+
- `composite`
9+
- `input`
10+
- `landmark`
11+
- `range`
12+
- `roletype`
13+
- `section`
14+
- `sectionhead`
15+
- `select`
16+
- `structure`
17+
- `widget`
18+
- `window`
19+
20+
## Examples
21+
22+
This rule **forbids** the following:
23+
24+
```hbs
25+
<div role='window'> Hello, world! </div>
26+
```
27+
28+
This rule **allows** the following:
29+
30+
```hbs
31+
<div role='button'> Push it </div>
32+
```
33+
34+
## References
35+
36+
- See [https://www.w3.org/TR/wai-aria-1.0/roles#abstract_roles](https://www.w3.org/TR/wai-aria-1.0/roles#abstract_roles)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
const PROHIBITED_ROLE_VALUES = new Set([
2+
'command',
3+
'composite',
4+
'input',
5+
'landmark',
6+
'range',
7+
'roletype',
8+
'section',
9+
'sectionhead',
10+
'select',
11+
'structure',
12+
'widget',
13+
'window',
14+
]);
15+
16+
/** @type {import('eslint').Rule.RuleModule} */
17+
module.exports = {
18+
meta: {
19+
type: 'problem',
20+
docs: {
21+
description: 'disallow abstract ARIA roles',
22+
category: 'Accessibility',
23+
strictGjs: true,
24+
strictGts: true,
25+
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-abstract-roles.md',
26+
},
27+
fixable: null,
28+
schema: [],
29+
messages: {
30+
abstractRole:
31+
'{{role}} is an abstract role, and is not a valid value for the role attribute.',
32+
},
33+
},
34+
35+
create(context) {
36+
return {
37+
GlimmerElementNode(node) {
38+
const roleAttr = node.attributes?.find((attr) => attr.name === 'role');
39+
40+
if (roleAttr && roleAttr.value && roleAttr.value.type === 'GlimmerTextNode') {
41+
const roleValue = roleAttr.value.chars;
42+
43+
if (PROHIBITED_ROLE_VALUES.has(roleValue)) {
44+
context.report({
45+
node: roleAttr,
46+
messageId: 'abstractRole',
47+
data: { role: roleValue },
48+
});
49+
}
50+
}
51+
},
52+
};
53+
},
54+
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const rule = require('../../../lib/rules/template-no-abstract-roles');
2+
const RuleTester = require('eslint').RuleTester;
3+
4+
const ruleTester = new RuleTester({
5+
parser: require.resolve('ember-eslint-parser'),
6+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
7+
});
8+
9+
ruleTester.run('template-no-abstract-roles', rule, {
10+
valid: ['<template><div role="button"></div></template>', '<template><div></div></template>'],
11+
invalid: [
12+
{
13+
code: '<template><div role="command"></div></template>',
14+
output: null,
15+
errors: [{ messageId: 'abstractRole' }],
16+
},
17+
{
18+
code: '<template><div role="widget"></div></template>',
19+
output: null,
20+
errors: [{ messageId: 'abstractRole' }],
21+
},
22+
],
23+
});

0 commit comments

Comments
 (0)