diff --git a/.eslintrc b/.eslintrc index a413b4ca4..aeb58e1f6 100644 --- a/.eslintrc +++ b/.eslintrc @@ -23,6 +23,20 @@ "eslint-plugin/require-meta-type": "off", }, }, + { + "files": ["markdown.config.js"], + "parserOptions": { + "sourceType": "script", + }, + "rules": { + "no-console": 0, + "import/no-extraneous-dependencies": [ + "error", + { "devDependencies": true }, + ], + "strict": ["error", "global"], + }, + }, { "files": ["__tests__/src/rules/*.js"], "extends": ["plugin:eslint-plugin/tests-recommended"], diff --git a/.github/workflows/readme.yml b/.github/workflows/readme.yml new file mode 100644 index 000000000..1a943aa4c --- /dev/null +++ b/.github/workflows/readme.yml @@ -0,0 +1,15 @@ +name: 'Tests: readme' + +on: [pull_request, push] + +jobs: + readme: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: ljharb/actions/node/install@main + name: 'nvm install lts/* && npm install' + with: + node-version: 'lts/*' + - run: npm run generate-list-of-rules:check diff --git a/README.md b/README.md index c229f7353..c75e78dad 100644 --- a/README.md +++ b/README.md @@ -91,76 +91,87 @@ Add `plugin:jsx-a11y/recommended` or `plugin:jsx-a11y/strict` in `extends`: ## Supported Rules -- [alt-text](docs/rules/alt-text.md): Enforce all elements that require alternative text have meaningful information to relay back to end user. -- [anchor-has-content](docs/rules/anchor-has-content.md): Enforce all anchors to contain accessible content. -- [anchor-is-valid](docs/rules/anchor-is-valid.md): Enforce all anchors are valid, navigable elements. -- [aria-activedescendant-has-tabindex](docs/rules/aria-activedescendant-has-tabindex.md): Enforce elements with aria-activedescendant are tabbable. -- [aria-props](docs/rules/aria-props.md): Enforce all `aria-*` props are valid. -- [aria-proptypes](docs/rules/aria-proptypes.md): Enforce ARIA state and property values are valid. -- [aria-role](docs/rules/aria-role.md): Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role. -- [aria-unsupported-elements](docs/rules/aria-unsupported-elements.md): Enforce that elements that do not support ARIA roles, states, and properties do not have those attributes. -- [autocomplete-valid](docs/rules/autocomplete-valid.md): Enforce that autocomplete attributes are used correctly. -- [click-events-have-key-events](docs/rules/click-events-have-key-events.md): Enforce a clickable non-interactive element has at least one keyboard event listener. -- [heading-has-content](docs/rules/heading-has-content.md): Enforce heading (`h1`, `h2`, etc) elements contain accessible content. -- [html-has-lang](docs/rules/html-has-lang.md): Enforce `` element has `lang` prop. -- [iframe-has-title](docs/rules/iframe-has-title.md): Enforce iframe elements have a title attribute. -- [img-redundant-alt](docs/rules/img-redundant-alt.md): Enforce `` alt prop does not contain the word "image", "picture", or "photo". -- [interactive-supports-focus](docs/rules/interactive-supports-focus.md): Enforce that elements with interactive handlers like `onClick` must be focusable. -- [label-has-associated-control](docs/rules/label-has-associated-control.md): Enforce that a `label` tag has a text label and an associated control. -- [lang](docs/rules/lang.md): Enforce lang attribute has a valid value. -- [media-has-caption](docs/rules/media-has-caption.md): Enforces that `` and `` elements must have a `` for captions. -- [mouse-events-have-key-events](docs/rules/mouse-events-have-key-events.md): Enforce that `onMouseOver`/`onMouseOut` are accompanied by `onFocus`/`onBlur` for keyboard-only users. -- [no-access-key](docs/rules/no-access-key.md): Enforce that the `accessKey` prop is not used on any element to avoid complications with keyboard commands used by a screenreader. -- [no-autofocus](docs/rules/no-autofocus.md): Enforce autoFocus prop is not used. -- [no-distracting-elements](docs/rules/no-distracting-elements.md): Enforce distracting elements are not used. -- [no-interactive-element-to-noninteractive-role](docs/rules/no-interactive-element-to-noninteractive-role.md): Interactive elements should not be assigned non-interactive roles. -- [no-noninteractive-element-interactions](docs/rules/no-noninteractive-element-interactions.md): Non-interactive elements should not be assigned mouse or keyboard event listeners. -- [no-noninteractive-element-to-interactive-role](docs/rules/no-noninteractive-element-to-interactive-role.md): Non-interactive elements should not be assigned interactive roles. -- [no-noninteractive-tabindex](docs/rules/no-noninteractive-tabindex.md): `tabIndex` should only be declared on interactive elements. -- [no-onchange](docs/rules/no-onchange.md): Enforce usage of `onBlur` over `onChange` on select menus for accessibility. -- [no-redundant-roles](docs/rules/no-redundant-roles.md): Enforce explicit role property is not the same as implicit/default role property on element. -- [no-static-element-interactions](docs/rules/no-static-element-interactions.md): Enforce that non-interactive, visible elements (such as ``) that have click handlers use the role attribute. -- [role-has-required-aria-props](docs/rules/role-has-required-aria-props.md): Enforce that elements with ARIA roles must have all required attributes for that role. -- [role-supports-aria-props](docs/rules/role-supports-aria-props.md): Enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`. -- [scope](docs/rules/scope.md): Enforce `scope` prop is only used on `` elements. -- [tabindex-no-positive](docs/rules/tabindex-no-positive.md): Enforce `tabIndex` value is not greater than zero. + + +- [alt-text](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/alt-text.md): Enforce all elements that require alternative text have meaningful information to relay back to end user. +- [anchor-has-content](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-has-content.md): Enforce all anchors to contain accessible content. +- [anchor-is-valid](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-is-valid.md): Enforce all anchors are valid, navigable elements. +- [aria-activedescendant-has-tabindex](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-activedescendant-has-tabindex.md): Enforce elements with aria-activedescendant are tabbable. +- [aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-props.md): Enforce all `aria-*` props are valid. +- [aria-proptypes](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-proptypes.md): Enforce ARIA state and property values are valid. +- [aria-role](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-role.md): Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role. +- [aria-unsupported-elements](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-unsupported-elements.md): Enforce that elements that do not support ARIA roles, states, and properties do not have those attributes. +- [autocomplete-valid](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/autocomplete-valid.md): Enforce that autocomplete attributes are used correctly. +- [click-events-have-key-events](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/click-events-have-key-events.md): Enforce a clickable non-interactive element has at least one keyboard event listener. + +- [heading-has-content](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/heading-has-content.md): Enforce heading (`h1`, `h2`, etc) elements contain accessible content. +- [html-has-lang](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/html-has-lang.md): Enforce `` element has `lang` prop. +- [iframe-has-title](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/iframe-has-title.md): Enforce iframe elements have a title attribute. +- [img-redundant-alt](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/img-redundant-alt.md): Enforce `` alt prop does not contain the word "image", "picture", or "photo". +- [interactive-supports-focus](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/interactive-supports-focus.md): Enforce that elements with interactive handlers like `onClick` must be focusable. +- [label-has-associated-control](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/label-has-associated-control.md): Enforce that a `label` tag has a text label and an associated control. + +- [lang](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/lang.md): Enforce lang attribute has a valid value. +- [media-has-caption](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/media-has-caption.md): Enforces that `` and `` elements must have a `` for captions. +- [mouse-events-have-key-events](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/mouse-events-have-key-events.md): Enforce that `onMouseOver`/`onMouseOut` are accompanied by `onFocus`/`onBlur` for keyboard-only users. +- [no-access-key](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-access-key.md): Enforce that the `accessKey` prop is not used on any element to avoid complications with keyboard commands used by a screenreader. +- [no-autofocus](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-autofocus.md): Enforce autoFocus prop is not used. +- [no-distracting-elements](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-distracting-elements.md): Enforce distracting elements are not used. +- [no-interactive-element-to-noninteractive-role](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-interactive-element-to-noninteractive-role.md): Interactive elements should not be assigned non-interactive roles. +- [no-noninteractive-element-interactions](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-interactions.md): Non-interactive elements should not be assigned mouse or keyboard event listeners. +- [no-noninteractive-element-to-interactive-role](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-to-interactive-role.md): Non-interactive elements should not be assigned interactive roles. +- [no-noninteractive-tabindex](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-tabindex.md): `tabIndex` should only be declared on interactive elements. +- [no-onchange](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-onchange.md): Enforce usage of `onBlur` over `onChange` on select menus for accessibility. +- [no-redundant-roles](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-redundant-roles.md): Enforce explicit role property is not the same as implicit/default role property on element. +- [no-static-element-interactions](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-static-element-interactions.md): Enforce that non-interactive, visible elements (such as ``) that have click handlers use the role attribute. +- [role-has-required-aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-has-required-aria-props.md): Enforce that elements with ARIA roles must have all required attributes for that role. +- [role-supports-aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-supports-aria-props.md): Enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`. +- [scope](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/scope.md): Enforce `scope` prop is only used on `` elements. +- [tabindex-no-positive](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/tabindex-no-positive.md): Enforce `tabIndex` value is not greater than zero. + ### Rule strictness in different modes -| Rule | Recommended | Strict | -| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ------ | -| [alt-text](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/alt-text.md) | error | error | -| [anchor-has-content](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/anchor-has-content.md) | error | error | -| [anchor-is-valid](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/anchor-is-valid.md) | error | error | -| [aria-activedescendant-has-tabindex](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/aria-activedescendant-has-tabindex.md) | error | error | -| [aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/aria-props.md) | error | error | -| [aria-proptypes](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/aria-proptypes.md) | error | error | -| [aria-role](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/aria-role.md) | error | error | -| [aria-unsupported-elements](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/aria-unsupported-elements.md) | error | error | -| [autocomplete-valid](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/autocomplete-valid.md) | error | error | -| [click-events-have-key-events](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/click-events-have-key-events.md) | error | error | -| [heading-has-content](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/heading-has-content.md) | error | error | -| [html-has-lang](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/html-has-lang.md) | error | error | -| [iframe-has-title](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/iframe-has-title.md) | error | error | -| [img-redundant-alt](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/img-redundant-alt.md) | error | error | -| [interactive-supports-focus](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/interactive-supports-focus.md) | error | error | -| [label-has-associated-control](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/label-has-associated-control.md) | error | error | -| [media-has-caption](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/media-has-caption.md) | error | error | -| [mouse-events-have-key-events](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/mouse-events-have-key-events.md) | error | error | -| [no-access-key](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/no-access-key.md) | error | error | -| [no-autofocus](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/no-autofocus.md) | error | error | -| [no-distracting-elements](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/no-distracting-elements.md) | error | error | -| [no-interactive-element-to-noninteractive-role](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/no-interactive-element-to-noninteractive-role.md) | error, with options | error | -| [no-noninteractive-element-interactions](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/no-noninteractive-element-interactions.md) | error, with options | error | -| [no-noninteractive-element-to-interactive-role](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/no-noninteractive-element-to-interactive-role.md) | error, with options | error | -| [no-noninteractive-tabindex](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/no-noninteractive-tabindex.md) | error, with options | error | -| [no-onchange](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/no-onchange.md) | error | error | -| [no-redundant-roles](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/no-redundant-roles.md) | error | error | -| [no-static-element-interactions](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/no-static-element-interactions.md) | error, with options | error | -| [role-has-required-aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/role-has-required-aria-props.md) | error | error | -| [role-supports-aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/role-supports-aria-props.md) | error | error | -| [scope](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/scope.md) | error, with options | error | -| [tabindex-no-positive](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/tabindex-no-positive.md) | error | error | + +| Rule | Recommended | Strict | +| :--- | :--- | :--- | +| [accessible-emoji](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/accessible-emoji.md) | error | error | +| [alt-text](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/alt-text.md) | error | error | +| [anchor-has-content](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-has-content.md) | error | error | +| [anchor-is-valid](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-is-valid.md) | error | error | +| [aria-activedescendant-has-tabindex](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-activedescendant-has-tabindex.md) | error | error | +| [aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-props.md) | error | error | +| [aria-proptypes](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-proptypes.md) | error | error | +| [aria-role](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-role.md) | error | error | +| [aria-unsupported-elements](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-unsupported-elements.md) | error | error | +| [autocomplete-valid](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/autocomplete-valid.md) | error | error | +| [click-events-have-key-events](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/click-events-have-key-events.md) | error | error | +| [control-has-associated-label](undefined) | error | error | +| [heading-has-content](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/heading-has-content.md) | error | error | +| [html-has-lang](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/html-has-lang.md) | error | error | +| [iframe-has-title](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/iframe-has-title.md) | error | error | +| [img-redundant-alt](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/img-redundant-alt.md) | error | error | +| [interactive-supports-focus](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/interactive-supports-focus.md) | error | error | +| [label-has-associated-control](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/label-has-associated-control.md) | error | error | +| [label-has-for](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/label-has-for.md) | error | error | +| [lang](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/lang.md) | error | error | +| [media-has-caption](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/media-has-caption.md) | error | error | +| [mouse-events-have-key-events](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/mouse-events-have-key-events.md) | error | error | +| [no-access-key](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-access-key.md) | error | error | +| [no-autofocus](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-autofocus.md) | error | error | +| [no-distracting-elements](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-distracting-elements.md) | error | error | +| [no-interactive-element-to-noninteractive-role](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-interactive-element-to-noninteractive-role.md) | error, with options | error | +| [no-noninteractive-element-interactions](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-interactions.md) | error, with options | error | +| [no-noninteractive-element-to-interactive-role](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-to-interactive-role.md) | error, with options | error | +| [no-noninteractive-tabindex](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-tabindex.md) | error, with options | error | +| [no-onchange](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-onchange.md) | error | error | +| [no-redundant-roles](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-redundant-roles.md) | error | error | +| [no-static-element-interactions](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-static-element-interactions.md) | error, with options | error | +| [role-has-required-aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-has-required-aria-props.md) | error | error | +| [role-supports-aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-supports-aria-props.md) | error | error | +| [scope](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/scope.md) | error, with options | error | +| [tabindex-no-positive](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/tabindex-no-positive.md) | error | error | + The following rules have extra options when in _recommended_ mode: diff --git a/markdown.config.js b/markdown.config.js new file mode 100644 index 000000000..a4a776992 --- /dev/null +++ b/markdown.config.js @@ -0,0 +1,49 @@ +'use strict'; + +require('@babel/register'); + +const { rules } = require('./src'); + +const ruleTableRows = Object.keys(rules) + .sort() + .map((id) => { + const { meta } = rules[id]; + const { url, errorOptions } = meta.docs; + return [ + `[${id}](${url})`, + errorOptions ? 'error, with options' : 'error', + 'error', + ].join(' | '); + }); + +const buildRulesTable = (rows) => { + const header = 'Rule | Recommended | Strict'; + const separator = ':--- | :--- | :---'; + + return [header, separator].concat(rows) + .map((row) => `| ${row} |`) + .join('\n'); +}; + +const ruleList = Object.keys(rules) + .sort() + .map((id) => { + const { meta } = rules[id]; + const { description, url } = meta.docs; + return description ? [`- [${id}](${url}): ${description}`] : null; + }); + +const buildRuleList = (listItems) => listItems.join('\n'); + +const LIST = () => buildRuleList(ruleList); +const TABLE = () => buildRulesTable(ruleTableRows); + +module.exports = { + transforms: { + TABLE, + LIST, + }, + callback: () => { + console.log('The auto-generating of rules finished!'); + }, +}; diff --git a/package.json b/package.json index 55ab2c7dc..a03971440 100644 --- a/package.json +++ b/package.json @@ -28,13 +28,16 @@ "test": "npm run jest", "posttest": "aud --production", "test:ci": "npm run jest -- --ci --runInBand", - "jest": "jest --coverage __tests__/**/*" + "jest": "jest --coverage __tests__/**/*", + "generate-list-of-rules": "md-magic --path '**/*.md' --ignore 'node_modules'", + "generate-list-of-rules:check": "npm run generate-list-of-rules && git diff --exit-code README.md" }, "devDependencies": { "@babel/cli": "^7.17.0", - "@babel/core": "^7.17.0", + "@babel/core": "^7.17.5", "@babel/eslint-parser": "^7.17.0", "@babel/plugin-transform-flow-strip-types": "^7.16.7", + "@babel/register": "^7.17.0", "ast-types-flow": "^0.0.7", "aud": "^2.0.0", "babel-jest": "^24.9.0", @@ -51,6 +54,7 @@ "in-publish": "^2.0.1", "jest": "^24.9.0", "jscodeshift": "^0.7.1", + "markdown-magic": "^2.6.0", "minimist": "^1.2.5", "object.assign": "^4.1.2", "rimraf": "^3.0.2", diff --git a/src/rules/alt-text.js b/src/rules/alt-text.js index b3a7ef7de..64fdc37f3 100644 --- a/src/rules/alt-text.js +++ b/src/rules/alt-text.js @@ -196,6 +196,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/alt-text.md', + description: 'Enforce all elements that require alternative text have meaningful information to relay back to end user.', }, schema: [schema], }, diff --git a/src/rules/anchor-has-content.js b/src/rules/anchor-has-content.js index c29baeea9..bb4bc3398 100644 --- a/src/rules/anchor-has-content.js +++ b/src/rules/anchor-has-content.js @@ -19,6 +19,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-has-content.md', + description: 'Enforce all anchors to contain accessible content.', }, schema: [schema], }, diff --git a/src/rules/anchor-is-valid.js b/src/rules/anchor-is-valid.js index fc1112832..28871b3a6 100644 --- a/src/rules/anchor-is-valid.js +++ b/src/rules/anchor-is-valid.js @@ -31,6 +31,7 @@ export default ({ meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-is-valid.md', + description: 'Enforce all anchors are valid, navigable elements.', }, schema: [schema], }, diff --git a/src/rules/aria-activedescendant-has-tabindex.js b/src/rules/aria-activedescendant-has-tabindex.js index ec510c4ae..21a9b5518 100644 --- a/src/rules/aria-activedescendant-has-tabindex.js +++ b/src/rules/aria-activedescendant-has-tabindex.js @@ -23,6 +23,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-activedescendant-has-tabindex.md', + description: 'Enforce elements with aria-activedescendant are tabbable.', }, schema: [schema], }, diff --git a/src/rules/aria-props.js b/src/rules/aria-props.js index 86a190e2b..4c9f62d3b 100644 --- a/src/rules/aria-props.js +++ b/src/rules/aria-props.js @@ -31,6 +31,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-props.md', + description: 'Enforce all `aria-*` props are valid.', }, schema: [schema], }, diff --git a/src/rules/aria-proptypes.js b/src/rules/aria-proptypes.js index 0f914fb7b..23640f567 100644 --- a/src/rules/aria-proptypes.js +++ b/src/rules/aria-proptypes.js @@ -67,6 +67,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-proptypes.md', + description: 'Enforce ARIA state and property values are valid.', }, schema: [schema], }, diff --git a/src/rules/aria-role.js b/src/rules/aria-role.js index 57e4096bd..6cec7b88f 100644 --- a/src/rules/aria-role.js +++ b/src/rules/aria-role.js @@ -31,6 +31,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-role.md', + description: 'Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role.', }, schema: [schema], }, diff --git a/src/rules/aria-unsupported-elements.js b/src/rules/aria-unsupported-elements.js index 9b7e281ea..73a9ddcb6 100644 --- a/src/rules/aria-unsupported-elements.js +++ b/src/rules/aria-unsupported-elements.js @@ -26,6 +26,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-unsupported-elements.md', + description: 'Enforce that elements that do not support ARIA roles, states, and properties do not have those attributes.', }, schema: [schema], }, diff --git a/src/rules/autocomplete-valid.js b/src/rules/autocomplete-valid.js index abff7adde..b22c05c04 100644 --- a/src/rules/autocomplete-valid.js +++ b/src/rules/autocomplete-valid.js @@ -18,6 +18,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/autocomplete-valid.md', + description: 'Enforce that autocomplete attributes are used correctly.', }, schema: [schema], }, diff --git a/src/rules/click-events-have-key-events.js b/src/rules/click-events-have-key-events.js index 7094085fa..cde1b6caa 100644 --- a/src/rules/click-events-have-key-events.js +++ b/src/rules/click-events-have-key-events.js @@ -24,6 +24,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/click-events-have-key-events.md', + description: 'Enforce a clickable non-interactive element has at least one keyboard event listener.', }, schema: [schema], }, diff --git a/src/rules/heading-has-content.js b/src/rules/heading-has-content.js index 19ecac080..426910179 100644 --- a/src/rules/heading-has-content.js +++ b/src/rules/heading-has-content.js @@ -29,6 +29,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/heading-has-content.md', + description: 'Enforce heading (`h1`, `h2`, etc) elements contain accessible content.', }, schema: [schema], }, diff --git a/src/rules/html-has-lang.js b/src/rules/html-has-lang.js index dc12b5a8f..d106c72f2 100644 --- a/src/rules/html-has-lang.js +++ b/src/rules/html-has-lang.js @@ -18,6 +18,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/html-has-lang.md', + description: 'Enforce `` element has `lang` prop.', }, schema: [schema], }, diff --git a/src/rules/iframe-has-title.js b/src/rules/iframe-has-title.js index 938b07230..ecde98c65 100644 --- a/src/rules/iframe-has-title.js +++ b/src/rules/iframe-has-title.js @@ -18,6 +18,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/iframe-has-title.md', + description: 'Enforce iframe elements have a title attribute.', }, schema: [schema], }, diff --git a/src/rules/img-redundant-alt.js b/src/rules/img-redundant-alt.js index 604a502c8..d034458fd 100644 --- a/src/rules/img-redundant-alt.js +++ b/src/rules/img-redundant-alt.js @@ -28,6 +28,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/img-redundant-alt.md', + description: 'Enforce `` alt prop does not contain the word "image", "picture", or "photo".', }, schema: [schema], }, diff --git a/src/rules/interactive-supports-focus.js b/src/rules/interactive-supports-focus.js index a172744cd..dec42e320 100644 --- a/src/rules/interactive-supports-focus.js +++ b/src/rules/interactive-supports-focus.js @@ -51,6 +51,7 @@ export default ({ meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/interactive-supports-focus.md', + description: 'Enforce that elements with interactive handlers like `onClick` must be focusable.', }, schema: [schema], }, diff --git a/src/rules/label-has-associated-control.js b/src/rules/label-has-associated-control.js index 0ea44c69a..acd463222 100644 --- a/src/rules/label-has-associated-control.js +++ b/src/rules/label-has-associated-control.js @@ -43,7 +43,10 @@ const validateId = (node) => { export default ({ meta: { - docs: {}, + docs: { + description: 'Enforce that a `label` tag has a text label and an associated control.', + url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/label-has-associated-control.md', + }, schema: [schema], }, diff --git a/src/rules/lang.js b/src/rules/lang.js index 5ec36015d..cecfc97c5 100644 --- a/src/rules/lang.js +++ b/src/rules/lang.js @@ -19,6 +19,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/lang.md', + description: 'Enforce lang attribute has a valid value.', }, schema: [schema], }, diff --git a/src/rules/media-has-caption.js b/src/rules/media-has-caption.js index 0a17ee4bc..227acab1f 100644 --- a/src/rules/media-has-caption.js +++ b/src/rules/media-has-caption.js @@ -39,6 +39,7 @@ export default ({ meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/media-has-caption.md', + description: 'Enforces that `` and `` elements must have a `` for captions.', }, schema: [schema], }, diff --git a/src/rules/mouse-events-have-key-events.js b/src/rules/mouse-events-have-key-events.js index 59d471e4d..5761551f2 100644 --- a/src/rules/mouse-events-have-key-events.js +++ b/src/rules/mouse-events-have-key-events.js @@ -21,6 +21,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/mouse-events-have-key-events.md', + description: 'Enforce that `onMouseOver`/`onMouseOut` are accompanied by `onFocus`/`onBlur` for keyboard-only users.', }, schema: [schema], }, diff --git a/src/rules/no-access-key.js b/src/rules/no-access-key.js index d212d008a..0c124ab16 100644 --- a/src/rules/no-access-key.js +++ b/src/rules/no-access-key.js @@ -18,6 +18,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-access-key.md', + description: 'Enforce that the `accessKey` prop is not used on any element to avoid complications with keyboard commands used by a screenreader.', }, schema: [schema], }, diff --git a/src/rules/no-autofocus.js b/src/rules/no-autofocus.js index f16f040d0..dfbd00c3b 100644 --- a/src/rules/no-autofocus.js +++ b/src/rules/no-autofocus.js @@ -24,6 +24,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-autofocus.md', + description: 'Enforce autoFocus prop is not used.', }, schema: [schema], }, diff --git a/src/rules/no-distracting-elements.js b/src/rules/no-distracting-elements.js index 366a5bf44..5377f625c 100644 --- a/src/rules/no-distracting-elements.js +++ b/src/rules/no-distracting-elements.js @@ -27,6 +27,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-distracting-elements.md', + description: 'Enforce distracting elements are not used.', }, schema: [schema], }, diff --git a/src/rules/no-interactive-element-to-noninteractive-role.js b/src/rules/no-interactive-element-to-noninteractive-role.js index dff3d2eab..dbb374135 100644 --- a/src/rules/no-interactive-element-to-noninteractive-role.js +++ b/src/rules/no-interactive-element-to-noninteractive-role.js @@ -33,6 +33,8 @@ export default ({ meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-interactive-element-to-noninteractive-role.md', + description: 'Interactive elements should not be assigned non-interactive roles.', + errorOptions: true, }, schema: [{ type: 'object', diff --git a/src/rules/no-noninteractive-element-interactions.js b/src/rules/no-noninteractive-element-interactions.js index 68d4153e1..8e3a793ed 100644 --- a/src/rules/no-noninteractive-element-interactions.js +++ b/src/rules/no-noninteractive-element-interactions.js @@ -46,6 +46,8 @@ export default ({ meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-interactions.md', + description: 'Non-interactive elements should not be assigned mouse or keyboard event listeners.', + errorOptions: true, }, schema: [schema], }, diff --git a/src/rules/no-noninteractive-element-to-interactive-role.js b/src/rules/no-noninteractive-element-to-interactive-role.js index 4be06cee7..64ed9a766 100644 --- a/src/rules/no-noninteractive-element-to-interactive-role.js +++ b/src/rules/no-noninteractive-element-to-interactive-role.js @@ -31,6 +31,8 @@ export default ({ meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-to-interactive-role.md', + description: 'Non-interactive elements should not be assigned interactive roles.', + errorOptions: true, }, schema: [{ type: 'object', diff --git a/src/rules/no-noninteractive-tabindex.js b/src/rules/no-noninteractive-tabindex.js index 434ceb584..7d6dbfff6 100644 --- a/src/rules/no-noninteractive-tabindex.js +++ b/src/rules/no-noninteractive-tabindex.js @@ -40,6 +40,8 @@ export default ({ meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-tabindex.md', + description: '`tabIndex` should only be declared on interactive elements.', + errorOptions: true, }, schema: [schema], }, diff --git a/src/rules/no-onchange.js b/src/rules/no-onchange.js index 77b081253..48012632d 100644 --- a/src/rules/no-onchange.js +++ b/src/rules/no-onchange.js @@ -23,6 +23,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-onchange.md', + description: 'Enforce usage of `onBlur` over `onChange` on select menus for accessibility.', }, deprecated: true, schema: [schema], diff --git a/src/rules/no-redundant-roles.js b/src/rules/no-redundant-roles.js index 7b1360320..602aa2c75 100644 --- a/src/rules/no-redundant-roles.js +++ b/src/rules/no-redundant-roles.js @@ -27,6 +27,7 @@ export default ({ meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-redundant-roles.md', + description: 'Enforce explicit role property is not the same as implicit/default role property on element.', }, schema: [{ type: 'object', diff --git a/src/rules/no-static-element-interactions.js b/src/rules/no-static-element-interactions.js index 2a4082f91..8348f1578 100644 --- a/src/rules/no-static-element-interactions.js +++ b/src/rules/no-static-element-interactions.js @@ -45,6 +45,8 @@ export default ({ meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-static-element-interactions.md', + description: 'Enforce that non-interactive, visible elements (such as ``) that have click handlers use the role attribute.', + errorOptions: true, }, schema: [schema], }, diff --git a/src/rules/role-has-required-aria-props.js b/src/rules/role-has-required-aria-props.js index 912798300..4803db650 100644 --- a/src/rules/role-has-required-aria-props.js +++ b/src/rules/role-has-required-aria-props.js @@ -28,6 +28,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-has-required-aria-props.md', + description: 'Enforce that elements with ARIA roles must have all required attributes for that role.', }, schema: [schema], }, diff --git a/src/rules/role-supports-aria-props.js b/src/rules/role-supports-aria-props.js index 161dc9c22..d6edb8945 100644 --- a/src/rules/role-supports-aria-props.js +++ b/src/rules/role-supports-aria-props.js @@ -37,6 +37,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-supports-aria-props.md', + description: 'Enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`.', }, schema: [schema], }, diff --git a/src/rules/scope.js b/src/rules/scope.js index d245d6f80..8434e0ae1 100644 --- a/src/rules/scope.js +++ b/src/rules/scope.js @@ -19,6 +19,8 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/scope.md', + description: 'Enforce `scope` prop is only used on `` elements.', + errorOptions: true, }, schema: [schema], }, diff --git a/src/rules/tabindex-no-positive.js b/src/rules/tabindex-no-positive.js index 529018abe..aba110728 100644 --- a/src/rules/tabindex-no-positive.js +++ b/src/rules/tabindex-no-positive.js @@ -18,6 +18,7 @@ export default { meta: { docs: { url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/tabindex-no-positive.md', + description: 'Enforce `tabIndex` value is not greater than zero.', }, schema: [schema], },