Skip to content

Commit 9980d1d

Browse files
uncommon-typeljharb
authored andcommittedFeb 28, 2022
[Docs] Add infrastructure for auto-generating markdown table and list
- Add readme.yml file to ensure table and list markdown content is auto-generated from rules folder - Add md-magic dependency and scripts to package.json for updating readme markdown - Add markdown.config.js file to add transformation functions to the transforms object - Add scripts to README markdown to keep documentation content in sync with readme - Disable `no-console` rule in markdown.config file in .eslintrc - Add errorOptions property to source files for rules with extra options Closes #836
1 parent ea877c4 commit 9980d1d

38 files changed

+204
-70
lines changed
 

‎.eslintrc

+14
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@
2323
"eslint-plugin/require-meta-type": "off",
2424
},
2525
},
26+
{
27+
"files": ["markdown.config.js"],
28+
"parserOptions": {
29+
"sourceType": "script",
30+
},
31+
"rules": {
32+
"no-console": 0,
33+
"import/no-extraneous-dependencies": [
34+
"error",
35+
{ "devDependencies": true },
36+
],
37+
"strict": ["error", "global"],
38+
},
39+
},
2640
{
2741
"files": ["__tests__/src/rules/*.js"],
2842
"extends": ["plugin:eslint-plugin/tests-recommended"],

‎.github/workflows/readme.yml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: 'Tests: readme'
2+
3+
on: [pull_request, push]
4+
5+
jobs:
6+
readme:
7+
runs-on: ubuntu-latest
8+
9+
steps:
10+
- uses: actions/checkout@v2
11+
- uses: ljharb/actions/node/install@main
12+
name: 'nvm install lts/* && npm install'
13+
with:
14+
node-version: 'lts/*'
15+
- run: npm run generate-list-of-rules:check

‎README.md

+78-67
Large diffs are not rendered by default.

‎markdown.config.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
3+
require('@babel/register');
4+
5+
const { rules } = require('./src');
6+
7+
const ruleTableRows = Object.keys(rules)
8+
.sort()
9+
.map((id) => {
10+
const { meta } = rules[id];
11+
const { url, errorOptions } = meta.docs;
12+
return [
13+
`[${id}](${url})`,
14+
errorOptions ? 'error, with options' : 'error',
15+
'error',
16+
].join(' | ');
17+
});
18+
19+
const buildRulesTable = (rows) => {
20+
const header = 'Rule | Recommended | Strict';
21+
const separator = ':--- | :--- | :---';
22+
23+
return [header, separator].concat(rows)
24+
.map((row) => `| ${row} |`)
25+
.join('\n');
26+
};
27+
28+
const ruleList = Object.keys(rules)
29+
.sort()
30+
.map((id) => {
31+
const { meta } = rules[id];
32+
const { description, url } = meta.docs;
33+
return description ? [`- [${id}](${url}): ${description}`] : null;
34+
});
35+
36+
const buildRuleList = (listItems) => listItems.join('\n');
37+
38+
const LIST = () => buildRuleList(ruleList);
39+
const TABLE = () => buildRulesTable(ruleTableRows);
40+
41+
module.exports = {
42+
transforms: {
43+
TABLE,
44+
LIST,
45+
},
46+
callback: () => {
47+
console.log('The auto-generating of rules finished!');
48+
},
49+
};

‎package.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,16 @@
2828
"test": "npm run jest",
2929
"posttest": "aud --production",
3030
"test:ci": "npm run jest -- --ci --runInBand",
31-
"jest": "jest --coverage __tests__/**/*"
31+
"jest": "jest --coverage __tests__/**/*",
32+
"generate-list-of-rules": "md-magic --path '**/*.md' --ignore 'node_modules'",
33+
"generate-list-of-rules:check": "npm run generate-list-of-rules && git diff --exit-code README.md"
3234
},
3335
"devDependencies": {
3436
"@babel/cli": "^7.17.0",
35-
"@babel/core": "^7.17.0",
37+
"@babel/core": "^7.17.5",
3638
"@babel/eslint-parser": "^7.17.0",
3739
"@babel/plugin-transform-flow-strip-types": "^7.16.7",
40+
"@babel/register": "^7.17.0",
3841
"ast-types-flow": "^0.0.7",
3942
"aud": "^2.0.0",
4043
"babel-jest": "^24.9.0",
@@ -51,6 +54,7 @@
5154
"in-publish": "^2.0.1",
5255
"jest": "^24.9.0",
5356
"jscodeshift": "^0.7.1",
57+
"markdown-magic": "^2.6.0",
5458
"minimist": "^1.2.5",
5559
"object.assign": "^4.1.2",
5660
"rimraf": "^3.0.2",

‎src/rules/alt-text.js

+1
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ export default {
196196
meta: {
197197
docs: {
198198
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/alt-text.md',
199+
description: 'Enforce all elements that require alternative text have meaningful information to relay back to end user.',
199200
},
200201
schema: [schema],
201202
},

‎src/rules/anchor-has-content.js

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export default {
1919
meta: {
2020
docs: {
2121
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-has-content.md',
22+
description: 'Enforce all anchors to contain accessible content.',
2223
},
2324
schema: [schema],
2425
},

‎src/rules/anchor-is-valid.js

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export default ({
3131
meta: {
3232
docs: {
3333
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-is-valid.md',
34+
description: 'Enforce all anchors are valid, navigable elements.',
3435
},
3536
schema: [schema],
3637
},

‎src/rules/aria-activedescendant-has-tabindex.js

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export default {
2323
meta: {
2424
docs: {
2525
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-activedescendant-has-tabindex.md',
26+
description: 'Enforce elements with aria-activedescendant are tabbable.',
2627
},
2728
schema: [schema],
2829
},

‎src/rules/aria-props.js

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export default {
3131
meta: {
3232
docs: {
3333
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-props.md',
34+
description: 'Enforce all `aria-*` props are valid.',
3435
},
3536
schema: [schema],
3637
},

‎src/rules/aria-proptypes.js

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export default {
6767
meta: {
6868
docs: {
6969
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-proptypes.md',
70+
description: 'Enforce ARIA state and property values are valid.',
7071
},
7172
schema: [schema],
7273
},

‎src/rules/aria-role.js

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export default {
3131
meta: {
3232
docs: {
3333
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-role.md',
34+
description: 'Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role.',
3435
},
3536
schema: [schema],
3637
},

‎src/rules/aria-unsupported-elements.js

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export default {
2626
meta: {
2727
docs: {
2828
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-unsupported-elements.md',
29+
description: 'Enforce that elements that do not support ARIA roles, states, and properties do not have those attributes.',
2930
},
3031
schema: [schema],
3132
},

‎src/rules/autocomplete-valid.js

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default {
1818
meta: {
1919
docs: {
2020
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/autocomplete-valid.md',
21+
description: 'Enforce that autocomplete attributes are used correctly.',
2122
},
2223
schema: [schema],
2324
},

‎src/rules/click-events-have-key-events.js

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export default {
2424
meta: {
2525
docs: {
2626
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/click-events-have-key-events.md',
27+
description: 'Enforce a clickable non-interactive element has at least one keyboard event listener.',
2728
},
2829
schema: [schema],
2930
},

‎src/rules/heading-has-content.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export default {
2929
meta: {
3030
docs: {
3131
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/heading-has-content.md',
32+
description: 'Enforce heading (`h1`, `h2`, etc) elements contain accessible content.',
3233
},
3334
schema: [schema],
3435
},

‎src/rules/html-has-lang.js

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default {
1818
meta: {
1919
docs: {
2020
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/html-has-lang.md',
21+
description: 'Enforce `<html>` element has `lang` prop.',
2122
},
2223
schema: [schema],
2324
},

‎src/rules/iframe-has-title.js

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default {
1818
meta: {
1919
docs: {
2020
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/iframe-has-title.md',
21+
description: 'Enforce iframe elements have a title attribute.',
2122
},
2223
schema: [schema],
2324
},

‎src/rules/img-redundant-alt.js

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export default {
2828
meta: {
2929
docs: {
3030
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/img-redundant-alt.md',
31+
description: 'Enforce `<img>` alt prop does not contain the word "image", "picture", or "photo".',
3132
},
3233
schema: [schema],
3334
},

‎src/rules/interactive-supports-focus.js

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export default ({
5151
meta: {
5252
docs: {
5353
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/interactive-supports-focus.md',
54+
description: 'Enforce that elements with interactive handlers like `onClick` must be focusable.',
5455
},
5556
schema: [schema],
5657
},

‎src/rules/label-has-associated-control.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ const validateId = (node) => {
4343

4444
export default ({
4545
meta: {
46-
docs: {},
46+
docs: {
47+
description: 'Enforce that a `label` tag has a text label and an associated control.',
48+
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/label-has-associated-control.md',
49+
},
4750
schema: [schema],
4851
},
4952

‎src/rules/lang.js

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export default {
1919
meta: {
2020
docs: {
2121
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/lang.md',
22+
description: 'Enforce lang attribute has a valid value.',
2223
},
2324
schema: [schema],
2425
},

‎src/rules/media-has-caption.js

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export default ({
3939
meta: {
4040
docs: {
4141
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/media-has-caption.md',
42+
description: 'Enforces that `<audio>` and `<video>` elements must have a `<track>` for captions.',
4243
},
4344
schema: [schema],
4445
},

‎src/rules/mouse-events-have-key-events.js

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export default {
2121
meta: {
2222
docs: {
2323
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/mouse-events-have-key-events.md',
24+
description: 'Enforce that `onMouseOver`/`onMouseOut` are accompanied by `onFocus`/`onBlur` for keyboard-only users.',
2425
},
2526
schema: [schema],
2627
},

‎src/rules/no-access-key.js

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default {
1818
meta: {
1919
docs: {
2020
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-access-key.md',
21+
description: 'Enforce that the `accessKey` prop is not used on any element to avoid complications with keyboard commands used by a screenreader.',
2122
},
2223
schema: [schema],
2324
},

‎src/rules/no-autofocus.js

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export default {
2424
meta: {
2525
docs: {
2626
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-autofocus.md',
27+
description: 'Enforce autoFocus prop is not used.',
2728
},
2829
schema: [schema],
2930
},

‎src/rules/no-distracting-elements.js

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export default {
2727
meta: {
2828
docs: {
2929
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-distracting-elements.md',
30+
description: 'Enforce distracting elements are not used.',
3031
},
3132
schema: [schema],
3233
},

‎src/rules/no-interactive-element-to-noninteractive-role.js

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ export default ({
3333
meta: {
3434
docs: {
3535
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-interactive-element-to-noninteractive-role.md',
36+
description: 'Interactive elements should not be assigned non-interactive roles.',
37+
errorOptions: true,
3638
},
3739
schema: [{
3840
type: 'object',

‎src/rules/no-noninteractive-element-interactions.js

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ export default ({
4646
meta: {
4747
docs: {
4848
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-interactions.md',
49+
description: 'Non-interactive elements should not be assigned mouse or keyboard event listeners.',
50+
errorOptions: true,
4951
},
5052
schema: [schema],
5153
},

‎src/rules/no-noninteractive-element-to-interactive-role.js

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export default ({
3131
meta: {
3232
docs: {
3333
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-to-interactive-role.md',
34+
description: 'Non-interactive elements should not be assigned interactive roles.',
35+
errorOptions: true,
3436
},
3537
schema: [{
3638
type: 'object',

‎src/rules/no-noninteractive-tabindex.js

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ export default ({
4040
meta: {
4141
docs: {
4242
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-tabindex.md',
43+
description: '`tabIndex` should only be declared on interactive elements.',
44+
errorOptions: true,
4345
},
4446
schema: [schema],
4547
},

‎src/rules/no-onchange.js

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export default {
2323
meta: {
2424
docs: {
2525
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-onchange.md',
26+
description: 'Enforce usage of `onBlur` over `onChange` on select menus for accessibility.',
2627
},
2728
deprecated: true,
2829
schema: [schema],

‎src/rules/no-redundant-roles.js

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export default ({
2727
meta: {
2828
docs: {
2929
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-redundant-roles.md',
30+
description: 'Enforce explicit role property is not the same as implicit/default role property on element.',
3031
},
3132
schema: [{
3233
type: 'object',

‎src/rules/no-static-element-interactions.js

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ export default ({
4545
meta: {
4646
docs: {
4747
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-static-element-interactions.md',
48+
description: 'Enforce that non-interactive, visible elements (such as `<div>`) that have click handlers use the role attribute.',
49+
errorOptions: true,
4850
},
4951
schema: [schema],
5052
},

‎src/rules/role-has-required-aria-props.js

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export default {
2828
meta: {
2929
docs: {
3030
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-has-required-aria-props.md',
31+
description: 'Enforce that elements with ARIA roles must have all required attributes for that role.',
3132
},
3233
schema: [schema],
3334
},

‎src/rules/role-supports-aria-props.js

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export default {
3737
meta: {
3838
docs: {
3939
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-supports-aria-props.md',
40+
description: 'Enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`.',
4041
},
4142
schema: [schema],
4243
},

‎src/rules/scope.js

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export default {
1919
meta: {
2020
docs: {
2121
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/scope.md',
22+
description: 'Enforce `scope` prop is only used on `<th>` elements.',
23+
errorOptions: true,
2224
},
2325
schema: [schema],
2426
},

‎src/rules/tabindex-no-positive.js

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default {
1818
meta: {
1919
docs: {
2020
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/tabindex-no-positive.md',
21+
description: 'Enforce `tabIndex` value is not greater than zero.',
2122
},
2223
schema: [schema],
2324
},

0 commit comments

Comments
 (0)
Please sign in to comment.