Skip to content

Commit

Permalink
[Docs] Add infrastructure for auto-generating markdown table and list
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
uncommon-type authored and ljharb committed Feb 28, 2022
1 parent ea877c4 commit 9980d1d
Show file tree
Hide file tree
Showing 38 changed files with 204 additions and 70 deletions.
14 changes: 14 additions & 0 deletions .eslintrc
Expand Up @@ -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"],
Expand Down
15 changes: 15 additions & 0 deletions .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
145 changes: 78 additions & 67 deletions README.md

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions 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!');
},
};
8 changes: 6 additions & 2 deletions package.json
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
1 change: 1 addition & 0 deletions src/rules/alt-text.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/anchor-has-content.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/anchor-is-valid.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/aria-activedescendant-has-tabindex.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/aria-props.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/aria-proptypes.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/aria-role.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/aria-unsupported-elements.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/autocomplete-valid.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/click-events-have-key-events.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/heading-has-content.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/html-has-lang.js
Expand Up @@ -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 `<html>` element has `lang` prop.',
},
schema: [schema],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/iframe-has-title.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/img-redundant-alt.js
Expand Up @@ -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 `<img>` alt prop does not contain the word "image", "picture", or "photo".',
},
schema: [schema],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/interactive-supports-focus.js
Expand Up @@ -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],
},
Expand Down
5 changes: 4 additions & 1 deletion src/rules/label-has-associated-control.js
Expand Up @@ -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],
},

Expand Down
1 change: 1 addition & 0 deletions src/rules/lang.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/media-has-caption.js
Expand Up @@ -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 `<audio>` and `<video>` elements must have a `<track>` for captions.',
},
schema: [schema],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/mouse-events-have-key-events.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/no-access-key.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/no-autofocus.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/no-distracting-elements.js
Expand Up @@ -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],
},
Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-interactive-element-to-noninteractive-role.js
Expand Up @@ -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',
Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-noninteractive-element-interactions.js
Expand Up @@ -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],
},
Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-noninteractive-element-to-interactive-role.js
Expand Up @@ -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',
Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-noninteractive-tabindex.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/no-onchange.js
Expand Up @@ -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],
Expand Down
1 change: 1 addition & 0 deletions src/rules/no-redundant-roles.js
Expand Up @@ -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',
Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-static-element-interactions.js
Expand Up @@ -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 `<div>`) that have click handlers use the role attribute.',
errorOptions: true,
},
schema: [schema],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/role-has-required-aria-props.js
Expand Up @@ -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],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/role-supports-aria-props.js
Expand Up @@ -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],
},
Expand Down
2 changes: 2 additions & 0 deletions src/rules/scope.js
Expand Up @@ -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 `<th>` elements.',
errorOptions: true,
},
schema: [schema],
},
Expand Down
1 change: 1 addition & 0 deletions src/rules/tabindex-no-positive.js
Expand Up @@ -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],
},
Expand Down

0 comments on commit 9980d1d

Please sign in to comment.