Skip to content

Commit c8a3da9

Browse files
authored
[breaking] - Update schemas for all rules to objects (#81)
* [new] - Add support to pass prop options down for `href-no-hash` rule. Fixes #76 * [new] - Update all schemas to use objects so that they are extensible in the future. This will ensure that adding properties to the config won’t be a breaking change for all rules. * [docs] - Update docs to reflect new schemas. * Remove Link from anchor-has-content in favor of eslintrc customization. * Allow customization of keys for components and props for schema factories. * Camelcase specialLink for consistency. * Refactor schema generation to be more composable and local to the rules.
1 parent 2219de8 commit c8a3da9

38 files changed

+395
-404
lines changed

docs/rules/anchor-has-content.md

+13-12
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,19 @@ Enforce that anchors have content and that the content is accessible to screen r
77

88
## Rule details
99

10-
This rule takes one optional argument of type string or array of strings. These strings determine which JSX elements should be checked including `a` and `Link` (react-router) by default. This is a good use case when you have a wrapper component that simply renders a anchor element (like in React):
10+
This rule takes one optional object argument of type object:
11+
12+
```json
13+
{
14+
"rules": {
15+
"jsx-a11y/anchor-has-content": [ 2, {
16+
"components": [ "Anchor" ],
17+
}],
18+
}
19+
}
20+
```
21+
22+
For the `components` option, these strings determine which JSX elements (**always including** `<a>`) should be checked for having content. This is a good use case when you have a wrapper component that simply renders an `a` element (like in React):
1123

1224
```js
1325
// Anchor.js
@@ -26,17 +38,6 @@ return (
2638
);
2739
```
2840

29-
To tell this plugin to also check your `Anchor` element, specify this in your `.eslintrc` file:
30-
31-
```json
32-
{
33-
"rules": {
34-
"jsx-a11y/anchor-has-content": [ 2, "Anchor" ], // OR
35-
"jsx-a11y/anchor-has-content": [ 2, [ "AnchorOne", "AnchorTwo" ] ]
36-
}
37-
}
38-
```
39-
4041

4142
### Succeed
4243
```jsx

docs/rules/heading-has-content.md

+14-13
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,20 @@ Enforce that heading elements (`h1`, `h2`, etc.) have content and that the conte
77

88
## Rule details
99

10-
This rule takes one optional argument of type string or array of strings. These strings determine which JSX elements should be checked including `h1`, `h2`, `h3`, `h4`, `h5`, and `h6` by default. This is a good use case when you have a wrapper component that simply renders a heading element (like in React):
10+
This rule takes one optional object argument of type object:
11+
12+
```json
13+
{
14+
"rules": {
15+
"jsx-a11y/heading-has-content": [ 2, {
16+
"components": [ "MyHeading" ],
17+
}],
18+
}
19+
}
20+
```
21+
22+
For the `components` option, these strings determine which JSX elements (**always including** `<h1>` thru `<h6>`) should be checked for having content. This is a good use case when you have a wrapper component that simply renders an `h1` element (like in React):
23+
1124

1225
```js
1326
// Header.js
@@ -26,18 +39,6 @@ return (
2639
);
2740
```
2841

29-
To tell this plugin to also check your `Header` element, specify this in your `.eslintrc` file:
30-
31-
```json
32-
{
33-
"rules": {
34-
"jsx-a11y/heading-has-content": [ 2, "Header" ], // OR
35-
"jsx-a11y/heading-has-content": [ 2, [ "HeaderOne", "HeaderTwo" ] ]
36-
}
37-
}
38-
```
39-
40-
4142
#### Bad
4243
```jsx
4344
function Foo(props) {

docs/rules/href-no-hash.md

+14-11
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,20 @@ Enforce an anchor element's href prop value is not just #. You should use someth
44

55
## Rule details
66

7-
This rule takes one optional argument of type string or an array of strings. These strings determine which JSX elements should be checked for the `href` prop **including** `a` by default. This is a good use case when you have a wrapper component that simply renders an `a` element (like in React):
7+
This rule takes one optional object argument of type object:
8+
9+
```json
10+
{
11+
"rules": {
12+
"jsx-a11y/href-no-hash": [ 2, {
13+
"components": [ "Link" ],
14+
"specialLink": [ "hrefLeft", "hrefRight" ]
15+
}],
16+
}
17+
}
18+
```
19+
20+
For the `components` option, these strings determine which JSX elements (**always including** `<a>`) should be checked for the props designated in the `specialLink` options (**always including** `href`). This is a good use case when you have a wrapper component that simply renders an `a` element (like in React):
821

922
```js
1023
// Link.js
@@ -21,16 +34,6 @@ return (
2134
);
2235
```
2336

24-
To tell this plugin to also check your `Link` element, specify this in your `.eslintrc` file:
25-
26-
```json
27-
{
28-
"rules": {
29-
"jsx-a11y/href-no-hash": [ 2, "Link" ], // OR
30-
"jsx-a11y/href-no-hash": [ 2, [ "Link", "Anchor" ] ]
31-
}
32-
}
33-
```
3437

3538
### Succeed
3639
```jsx

docs/rules/img-has-alt.md

+14-12
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,19 @@ Enforce that an `img` element contains the `alt` prop. The `alt` attribute speci
44

55
## Rule details
66

7-
This rule takes one optional argument of type string or an array of strings. These strings determine which JSX elements should be checked for the `alt` prop **including** `img` by default. This is a good use case when you have a wrapper component that simply renders an `img` element (like in React):
7+
This rule takes one optional object argument of type object:
8+
9+
```json
10+
{
11+
"rules": {
12+
"jsx-a11y/img-has-alt": [ 2, {
13+
"components": [ "Image" ],
14+
}],
15+
}
16+
}
17+
```
18+
19+
For the `components` option, these strings determine which JSX elements (**always including** `<img>`) should be checked for having `alt` prop. This is a good use case when you have a wrapper component that simply renders an `img` element (like in React):
820

921
```js
1022
// Image.js
@@ -30,18 +42,8 @@ return (
3042
);
3143
```
3244

33-
To tell this plugin to also check your `Image` element, specify this in your `.eslintrc` file:
34-
35-
```json
36-
{
37-
"rules": {
38-
"jsx-a11y/img-has-alt": [ 2, "Image" ], <!-- OR -->
39-
"jsx-a11y/img-has-alt": [ 2, [ "Image", "Avatar" ] ]
40-
}
41-
}
42-
```
43-
4445
Note that passing props as spread attribute without `alt` explicitly defined will cause this rule to fail. Explicitly pass down `alt` prop or use `role="presentation"` for rule to pass. Use `Image` component above as a reference for destructuring and applying the prop. **It is a good thing to explicitly pass props that you expect to be passed for self-documentation.** For example:
46+
4547
#### Bad
4648
```jsx
4749
function Foo(props) {

docs/rules/img-redundant-alt.md

+11-6
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,26 @@
33
Enforce img alt attribute does not contain the word image, picture, or photo. Screenreaders already announce `img` elements as an image. There is no need to use words such as *image*, *photo*, and/or *picture*.
44

55
## Rule details
6-
This rule takes one optional argument of type string or array of strings. These strings can be used to specify custom words that should be checked for in the alt prop. Useful for specifying words in other languages.
76

8-
The rule will first check if `aria-hidden` is true to determine whether to enforce the rule. If the image is hidden, then rule will always succeed.
9-
10-
To tell this plugin to also check for custom words , specify this in your `.eslintrc` file:
7+
This rule takes one optional object argument of type object:
118

129
```json
1310
{
1411
"rules": {
15-
"jsx-a11y/img-redundant-alt": [ 2, "Bild" ], // OR
16-
"jsx-a11y/img-redundant-alt": [ 2, [ "Bild", "Foto" ] ]
12+
"jsx-a11y/img-redundant-alt": [ 2, {
13+
"components": [ "Image" ],
14+
"words": [ "Bild", "Foto" ],
15+
}],
1716
}
1817
}
1918
```
2019

20+
For the `components` option, these strings determine which JSX elements (**always including** `<img>`) should be checked for having redundant words in the `alt` prop value . This is a good use case when you have a wrapper component that simply renders an `img` element (like in React).
21+
22+
For the `words` option, these strings can be used to specify custom words that should be checked for in the alt prop, including `image`, `photo`, and `picture`. Useful for specifying words in other languages.
23+
24+
The rule will first check if `aria-hidden` is true to determine whether to enforce the rule. If the image is hidden, then rule will always succeed.
25+
2126
### Succeed
2227
```jsx
2328
<img src="foo" alt="Foo eating a sandwich." />

docs/rules/label-has-for.md

+14-12
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,19 @@ Enforce label tags have htmlFor attribute. Form controls using a label to identi
44

55
## Rule details
66

7-
This rule takes one optional argument of type string or array of strings. These strings determine which JSX elements should be checked for the `htmlFor` prop including `label` by default. This is a good use case when you have a wrapper component that simply renders an `label` element (like in React):
7+
This rule takes one optional object argument of type object:
8+
9+
```json
10+
{
11+
"rules": {
12+
"jsx-a11y/label-has-for": [ 2, {
13+
"components": [ "Label" ],
14+
}],
15+
}
16+
}
17+
```
18+
19+
For the `components` option, these strings determine which JSX elements (**always including** `<label>`) should be checked for having `htmlFor` prop. This is a good use case when you have a wrapper component that simply renders a `label` element (like in React):
820

921
```js
1022
// Label.js
@@ -31,18 +43,8 @@ return (
3143
);
3244
```
3345

34-
To tell this plugin to also check your `Label` element, specify this in your `.eslintrc` file:
35-
36-
```json
37-
{
38-
"rules": {
39-
"jsx-a11y/label-has-for": [ 2, "Label" ], // OR
40-
"jsx-a11y/label-has-for": [ 2, [ "Label", "InputDescriptor" ] ]
41-
}
42-
}
43-
```
44-
4546
Note that passing props as spread attribute without `htmlFor` explicitly defined will cause this rule to fail. Explicitly pass down `htmlFor` prop for rule to pass. The prop must have an actual value to pass. Use `Label` component above as a reference. **It is a good thing to explicitly pass props that you expect to be passed for self-documentation.** For example:
47+
4648
#### Bad
4749
```jsx
4850
function Foo(props) {

src/rules/anchor-has-content.js

+6-21
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,25 @@
88
// ----------------------------------------------------------------------------
99

1010
import { elementType, hasAnyProp } from 'jsx-ast-utils';
11+
import { arraySchema, generateObjSchema } from '../util/schemas';
1112
import isHiddenFromScreenReader from '../util/isHiddenFromScreenReader';
1213

1314
const errorMessage =
1415
'Anchors must have content and the content must be accessible by a screen reader.';
1516

16-
const anchors = [
17-
'a',
18-
'Link',
19-
];
17+
const schema = generateObjSchema({ components: arraySchema });
2018

2119
module.exports = {
2220
meta: {
2321
docs: {},
24-
25-
schema: [
26-
{
27-
oneOf: [
28-
{ type: 'string' },
29-
{
30-
type: 'array',
31-
items: {
32-
type: 'string',
33-
},
34-
minItems: 1,
35-
uniqueItems: true,
36-
},
37-
],
38-
},
39-
],
22+
schema: [schema],
4023
},
4124

4225
create: context => ({
4326
JSXOpeningElement: (node) => {
44-
const typeCheck = anchors.concat(context.options[0]);
27+
const options = context.options[0] || {};
28+
const componentOptions = options.components || [];
29+
const typeCheck = ['a'].concat(componentOptions);
4530
const nodeType = elementType(node);
4631

4732
// Only check anchor elements and custom types.

src/rules/aria-props.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// ----------------------------------------------------------------------------
99

1010
import { propName } from 'jsx-ast-utils';
11+
import { generateObjSchema } from '../util/schemas';
1112
import ariaAttributes from '../util/attributes/ARIA.json';
1213
import getSuggestion from '../util/getSuggestion';
1314

@@ -23,13 +24,12 @@ const errorMessage = (name) => {
2324
return message;
2425
};
2526

27+
const schema = generateObjSchema();
28+
2629
module.exports = {
2730
meta: {
2831
docs: {},
29-
30-
schema: [
31-
{ type: 'object' },
32-
],
32+
schema: [schema],
3333
},
3434

3535
create: context => ({

src/rules/aria-proptypes.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// ----------------------------------------------------------------------------
99

1010
import { getLiteralPropValue, propName } from 'jsx-ast-utils';
11+
import { generateObjSchema } from '../util/schemas';
1112
import ariaAttributes from '../util/attributes/ARIA.json';
1213

1314
const errorMessage = (name, type, permittedValues) => {
@@ -50,13 +51,12 @@ const validityCheck = (value, expectedType, permittedValues) => {
5051
}
5152
};
5253

54+
const schema = generateObjSchema();
55+
5356
module.exports = {
5457
meta: {
5558
docs: {},
56-
57-
schema: [
58-
{ type: 'object' },
59-
],
59+
schema: [schema],
6060
},
6161

6262
create: context => ({

src/rules/aria-role.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@
88
// ----------------------------------------------------------------------------
99

1010
import { getLiteralPropValue, propName } from 'jsx-ast-utils';
11+
import { generateObjSchema } from '../util/schemas';
1112
import roles from '../util/attributes/role.json';
1213

1314
const errorMessage = 'Elements with ARIA roles must use a valid, non-abstract ARIA role.';
1415

16+
const schema = generateObjSchema();
17+
1518
module.exports = {
1619
meta: {
1720
docs: {},
18-
19-
schema: [
20-
{ type: 'object' },
21-
],
21+
schema: [schema],
2222
},
2323

2424
create: context => ({

src/rules/aria-unsupported-elements.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@
99
// ----------------------------------------------------------------------------
1010

1111
import { elementType, propName } from 'jsx-ast-utils';
12+
import { generateObjSchema } from '../util/schemas';
1213
import DOM from '../util/attributes/DOM.json';
1314
import ARIA from '../util/attributes/ARIA.json';
1415

1516
const errorMessage = invalidProp =>
1617
`This element does not support ARIA roles, states and properties. \
1718
Try removing the prop '${invalidProp}'.`;
1819

20+
const schema = generateObjSchema();
21+
1922
module.exports = {
2023
meta: {
2124
docs: {},
22-
23-
schema: [
24-
{ type: 'object' },
25-
],
25+
schema: [schema],
2626
},
2727

2828
create: context => ({

0 commit comments

Comments
 (0)