From 2b77484cf4e7484fbb0da5c45cc937a3816c5318 Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Wed, 8 Jun 2022 19:11:10 +0900 Subject: [PATCH] Add A11Y rules (#36) * Add A11Y rules * fix --- .eslintignore | 1 + .gitignore | 1 + README.md | 60 +++++- astro.config.mjs | 4 + docs-build/build-system/build.js | 4 + .../src/eslint-plugin-jsx-a11y.mjs | 5 + .../src/components/ESLintCodeBlock.svelte | 4 + .../src/components/ESLintPlayground.svelte | 4 + .../src/components/eslint/scripts/linter.mjs | 5 + docs-build/src/config.ts | 1 + docs/README.md | 1 + docs/rules.md | 43 +++++ docs/rules/jsx-a11y/alt-text.md | 24 +++ docs/rules/jsx-a11y/anchor-has-content.md | 24 +++ docs/rules/jsx-a11y/anchor-is-valid.md | 24 +++ .../aria-activedescendant-has-tabindex.md | 24 +++ docs/rules/jsx-a11y/aria-props.md | 24 +++ docs/rules/jsx-a11y/aria-proptypes.md | 24 +++ docs/rules/jsx-a11y/aria-role.md | 24 +++ .../jsx-a11y/aria-unsupported-elements.md | 24 +++ docs/rules/jsx-a11y/autocomplete-valid.md | 24 +++ .../jsx-a11y/click-events-have-key-events.md | 24 +++ .../jsx-a11y/control-has-associated-label.md | 24 +++ docs/rules/jsx-a11y/heading-has-content.md | 24 +++ docs/rules/jsx-a11y/html-has-lang.md | 24 +++ docs/rules/jsx-a11y/iframe-has-title.md | 24 +++ docs/rules/jsx-a11y/img-redundant-alt.md | 24 +++ .../jsx-a11y/interactive-supports-focus.md | 24 +++ .../jsx-a11y/label-has-associated-control.md | 24 +++ docs/rules/jsx-a11y/lang.md | 24 +++ docs/rules/jsx-a11y/media-has-caption.md | 24 +++ .../jsx-a11y/mouse-events-have-key-events.md | 24 +++ docs/rules/jsx-a11y/no-access-key.md | 24 +++ docs/rules/jsx-a11y/no-autofocus.md | 24 +++ .../rules/jsx-a11y/no-distracting-elements.md | 24 +++ ...eractive-element-to-noninteractive-role.md | 24 +++ .../no-noninteractive-element-interactions.md | 24 +++ ...interactive-element-to-interactive-role.md | 24 +++ .../jsx-a11y/no-noninteractive-tabindex.md | 24 +++ docs/rules/jsx-a11y/no-redundant-roles.md | 24 +++ .../no-static-element-interactions.md | 24 +++ .../jsx-a11y/role-has-required-aria-props.md | 24 +++ .../jsx-a11y/role-supports-aria-props.md | 24 +++ docs/rules/jsx-a11y/scope.md | 24 +++ docs/rules/jsx-a11y/tabindex-no-positive.md | 24 +++ docs/user-guide.md | 18 +- package.json | 1 + src/a11y/configs.ts | 36 ++++ src/a11y/index.ts | 13 ++ src/a11y/keys.ts | 45 +++++ src/a11y/load.ts | 50 +++++ src/a11y/rules.ts | 173 ++++++++++++++++++ src/configs/all.ts | 4 +- src/configs/base.ts | 4 +- src/index.ts | 12 ++ src/types.ts | 19 +- src/utils/index.ts | 1 + src/utils/rules.ts | 2 + tests/src/integration/config-for-a11y.ts | 110 +++++++++++ tools/render-rules.ts | 3 + tools/update-docs-rules-index.ts | 4 +- tools/update-docs.ts | 12 +- tools/update-jsx-a11y-keys.ts | 31 ++++ tools/update-rules.ts | 4 +- tools/update-rulesets.ts | 4 +- tools/update.ts | 1 + 66 files changed, 1455 insertions(+), 17 deletions(-) create mode 100644 docs-build/build-system/src/eslint-plugin-jsx-a11y.mjs create mode 100644 docs/rules/jsx-a11y/alt-text.md create mode 100644 docs/rules/jsx-a11y/anchor-has-content.md create mode 100644 docs/rules/jsx-a11y/anchor-is-valid.md create mode 100644 docs/rules/jsx-a11y/aria-activedescendant-has-tabindex.md create mode 100644 docs/rules/jsx-a11y/aria-props.md create mode 100644 docs/rules/jsx-a11y/aria-proptypes.md create mode 100644 docs/rules/jsx-a11y/aria-role.md create mode 100644 docs/rules/jsx-a11y/aria-unsupported-elements.md create mode 100644 docs/rules/jsx-a11y/autocomplete-valid.md create mode 100644 docs/rules/jsx-a11y/click-events-have-key-events.md create mode 100644 docs/rules/jsx-a11y/control-has-associated-label.md create mode 100644 docs/rules/jsx-a11y/heading-has-content.md create mode 100644 docs/rules/jsx-a11y/html-has-lang.md create mode 100644 docs/rules/jsx-a11y/iframe-has-title.md create mode 100644 docs/rules/jsx-a11y/img-redundant-alt.md create mode 100644 docs/rules/jsx-a11y/interactive-supports-focus.md create mode 100644 docs/rules/jsx-a11y/label-has-associated-control.md create mode 100644 docs/rules/jsx-a11y/lang.md create mode 100644 docs/rules/jsx-a11y/media-has-caption.md create mode 100644 docs/rules/jsx-a11y/mouse-events-have-key-events.md create mode 100644 docs/rules/jsx-a11y/no-access-key.md create mode 100644 docs/rules/jsx-a11y/no-autofocus.md create mode 100644 docs/rules/jsx-a11y/no-distracting-elements.md create mode 100644 docs/rules/jsx-a11y/no-interactive-element-to-noninteractive-role.md create mode 100644 docs/rules/jsx-a11y/no-noninteractive-element-interactions.md create mode 100644 docs/rules/jsx-a11y/no-noninteractive-element-to-interactive-role.md create mode 100644 docs/rules/jsx-a11y/no-noninteractive-tabindex.md create mode 100644 docs/rules/jsx-a11y/no-redundant-roles.md create mode 100644 docs/rules/jsx-a11y/no-static-element-interactions.md create mode 100644 docs/rules/jsx-a11y/role-has-required-aria-props.md create mode 100644 docs/rules/jsx-a11y/role-supports-aria-props.md create mode 100644 docs/rules/jsx-a11y/scope.md create mode 100644 docs/rules/jsx-a11y/tabindex-no-positive.md create mode 100644 src/a11y/configs.ts create mode 100644 src/a11y/index.ts create mode 100644 src/a11y/keys.ts create mode 100644 src/a11y/load.ts create mode 100644 src/a11y/rules.ts create mode 100644 tests/src/integration/config-for-a11y.ts create mode 100644 tools/update-jsx-a11y-keys.ts diff --git a/.eslintignore b/.eslintignore index 496ef8a2..7a08b294 100644 --- a/.eslintignore +++ b/.eslintignore @@ -13,6 +13,7 @@ /docs-build/shim/assert.mjs /docs-build/shim/eslint.mjs /docs-build/shim/astro-eslint-parser.mjs +/docs-build/shim/eslint-plugin-jsx-a11y.mjs /tests/fixtures/rules/indent/invalid/ts /tests/fixtures/rules/indent/invalid/ts-v5 /tests/fixtures/rules/valid-compile/invalid/ts diff --git a/.gitignore b/.gitignore index dad29e41..14e43c29 100644 --- a/.gitignore +++ b/.gitignore @@ -107,3 +107,4 @@ dist /docs-build/shim/assert.mjs /docs-build/shim/eslint.mjs /docs-build/shim/astro-eslint-parser.mjs +/docs-build/shim/eslint-plugin-jsx-a11y.mjs diff --git a/README.md b/README.md index 7e72df9b..44b1417c 100644 --- a/README.md +++ b/README.md @@ -50,12 +50,21 @@ See [documents](https://ota-meshi.github.io/eslint-plugin-astro/). npm install --save-dev eslint eslint-plugin-astro ``` -If you write TypeScript in Astro components, install the `@typescript-eslint/parser` as well: +If you write TypeScript in Astro components, you also need to install the `@typescript-eslint/parser`: ```bash npm install --save-dev @typescript-eslint/parser ``` +If you want to use the rules for checking accessibility (A11Y), you also need to install [eslint-plugin-jsx-a11y] additionally: +(It is used internally in the rules for A11Y.) + +```bash +npm install --save-dev eslint-plugin-jsx-a11y +``` + +[eslint-plugin-jsx-a11y]: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y + > **Requirements** > > - ESLint v7.0.0 and above @@ -121,7 +130,7 @@ module.exports = { // Enables global variables available in Astro components. node: true, "astro/astro": true, - es2022: true, + es2020: true, }, // Allows Astro components to be parsed. parser: "astro-eslint-parser", @@ -148,7 +157,7 @@ module.exports = { files: ["**/*.astro/*.js", "*.astro/*.js"], env: { browser: true, - es2022: true, + es2020: true, }, parserOptions: { sourceType: "module", @@ -174,6 +183,9 @@ This plugin provides configs: - `plugin:astro/base` ... Minimal configuration to enable correct Astro component linting. - `plugin:astro/recommended` ... Above, plus rules to prevent errors or unintended behavior. - `plugin:astro/all` ... Configuration enables all astro rules. It's meant for testing, not for production use because it changes with every minor and major version of the plugin. Use it at your own risk. +- Extension of sharable configuration provided by [eslint-plugin-jsx-a11y]. You need to install [eslint-plugin-jsx-a11y] to use it. + - `plugin:astro/jsx-a11y-recommended` ... Similar to the [`"plugin:jsx-a11y/recommended"` configuration](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#rule-strictness-in-different-modes), but with the rules extended for Astro components enabled. + - `plugin:astro/jsx-a11y-strict` ... Similar to the [`"plugin:jsx-a11y/strict"` configuration](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#rule-strictness-in-different-modes), but with the rules extended for Astro components enabled. See [the rule list](https://ota-meshi.github.io/eslint-plugin-astro/rules/) to get the `rules` that this plugin provides. @@ -262,6 +274,47 @@ These rules relate to style guidelines, and are therefore quite subjective: | [astro/prefer-object-class-list](https://ota-meshi.github.io/eslint-plugin-astro/rules/prefer-object-class-list/) | require use object instead of ternary expression in `class:list` | :wrench: | | [astro/prefer-split-class-list](https://ota-meshi.github.io/eslint-plugin-astro/rules/prefer-split-class-list/) | require use split array elements in `class:list` | :wrench: | +## A11Y Extension Rules + +These rules extend the rules provided by [eslint-plugin-jsx-a11y] to work well in Astro component: +(You need to install [eslint-plugin-jsx-a11y] to use the rules.) + +| Rule ID | Description | | +|:--------|:------------|:---| +| [astro/jsx-a11y/alt-text](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/alt-text/) | apply `jsx-a11y/alt-text` rule to Astro components | | +| [astro/jsx-a11y/anchor-has-content](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/anchor-has-content/) | apply `jsx-a11y/anchor-has-content` rule to Astro components | | +| [astro/jsx-a11y/anchor-is-valid](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/anchor-is-valid/) | apply `jsx-a11y/anchor-is-valid` rule to Astro components | | +| [astro/jsx-a11y/aria-activedescendant-has-tabindex](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-activedescendant-has-tabindex/) | apply `jsx-a11y/aria-activedescendant-has-tabindex` rule to Astro components | | +| [astro/jsx-a11y/aria-props](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-props/) | apply `jsx-a11y/aria-props` rule to Astro components | | +| [astro/jsx-a11y/aria-proptypes](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-proptypes/) | apply `jsx-a11y/aria-proptypes` rule to Astro components | | +| [astro/jsx-a11y/aria-role](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-role/) | apply `jsx-a11y/aria-role` rule to Astro components | | +| [astro/jsx-a11y/aria-unsupported-elements](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-unsupported-elements/) | apply `jsx-a11y/aria-unsupported-elements` rule to Astro components | | +| [astro/jsx-a11y/autocomplete-valid](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/autocomplete-valid/) | apply `jsx-a11y/autocomplete-valid` rule to Astro components | | +| [astro/jsx-a11y/click-events-have-key-events](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/click-events-have-key-events/) | apply `jsx-a11y/click-events-have-key-events` rule to Astro components | | +| [astro/jsx-a11y/control-has-associated-label](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/control-has-associated-label/) | apply `jsx-a11y/control-has-associated-label` rule to Astro components | | +| [astro/jsx-a11y/heading-has-content](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/heading-has-content/) | apply `jsx-a11y/heading-has-content` rule to Astro components | | +| [astro/jsx-a11y/html-has-lang](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/html-has-lang/) | apply `jsx-a11y/html-has-lang` rule to Astro components | | +| [astro/jsx-a11y/iframe-has-title](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/iframe-has-title/) | apply `jsx-a11y/iframe-has-title` rule to Astro components | | +| [astro/jsx-a11y/img-redundant-alt](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/img-redundant-alt/) | apply `jsx-a11y/img-redundant-alt` rule to Astro components | | +| [astro/jsx-a11y/interactive-supports-focus](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/interactive-supports-focus/) | apply `jsx-a11y/interactive-supports-focus` rule to Astro components | | +| [astro/jsx-a11y/label-has-associated-control](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/label-has-associated-control/) | apply `jsx-a11y/label-has-associated-control` rule to Astro components | | +| [astro/jsx-a11y/lang](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/lang/) | apply `jsx-a11y/lang` rule to Astro components | | +| [astro/jsx-a11y/media-has-caption](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/media-has-caption/) | apply `jsx-a11y/media-has-caption` rule to Astro components | | +| [astro/jsx-a11y/mouse-events-have-key-events](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/mouse-events-have-key-events/) | apply `jsx-a11y/mouse-events-have-key-events` rule to Astro components | | +| [astro/jsx-a11y/no-access-key](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-access-key/) | apply `jsx-a11y/no-access-key` rule to Astro components | | +| [astro/jsx-a11y/no-autofocus](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-autofocus/) | apply `jsx-a11y/no-autofocus` rule to Astro components | | +| [astro/jsx-a11y/no-distracting-elements](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-distracting-elements/) | apply `jsx-a11y/no-distracting-elements` rule to Astro components | | +| [astro/jsx-a11y/no-interactive-element-to-noninteractive-role](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-interactive-element-to-noninteractive-role/) | apply `jsx-a11y/no-interactive-element-to-noninteractive-role` rule to Astro components | | +| [astro/jsx-a11y/no-noninteractive-element-interactions](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-noninteractive-element-interactions/) | apply `jsx-a11y/no-noninteractive-element-interactions` rule to Astro components | | +| [astro/jsx-a11y/no-noninteractive-element-to-interactive-role](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-noninteractive-element-to-interactive-role/) | apply `jsx-a11y/no-noninteractive-element-to-interactive-role` rule to Astro components | | +| [astro/jsx-a11y/no-noninteractive-tabindex](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-noninteractive-tabindex/) | apply `jsx-a11y/no-noninteractive-tabindex` rule to Astro components | | +| [astro/jsx-a11y/no-redundant-roles](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-redundant-roles/) | apply `jsx-a11y/no-redundant-roles` rule to Astro components | | +| [astro/jsx-a11y/no-static-element-interactions](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-static-element-interactions/) | apply `jsx-a11y/no-static-element-interactions` rule to Astro components | | +| [astro/jsx-a11y/role-has-required-aria-props](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/role-has-required-aria-props/) | apply `jsx-a11y/role-has-required-aria-props` rule to Astro components | | +| [astro/jsx-a11y/role-supports-aria-props](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/role-supports-aria-props/) | apply `jsx-a11y/role-supports-aria-props` rule to Astro components | | +| [astro/jsx-a11y/scope](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/scope/) | apply `jsx-a11y/scope` rule to Astro components | | +| [astro/jsx-a11y/tabindex-no-positive](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/tabindex-no-positive/) | apply `jsx-a11y/tabindex-no-positive` rule to Astro components | | + @@ -297,3 +350,4 @@ See the [LICENSE](LICENSE) file for license rights and limitations (MIT). [astro]: https://astro.build/ [eslint]: https://eslint.org/ [astro components]: https://docs.astro.build/en/core-concepts/astro-components/ +[eslint-plugin-jsx-a11y]: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y diff --git a/astro.config.mjs b/astro.config.mjs index 559e3788..b7e2f787 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -42,6 +42,10 @@ export default defineConfig({ dirname, "./docs-build/shim/astro-eslint-parser.mjs", ), + "eslint-plugin-jsx-a11y": path.join( + dirname, + "./docs-build/shim/eslint-plugin-jsx-a11y.mjs", + ), [path.join( dirname, "./node_modules/astro-eslint-parser/lib/parser/astro-parser/astrojs-compiler-service.js", diff --git a/docs-build/build-system/build.js b/docs-build/build-system/build.js index a846cc5d..f1ec04ed 100644 --- a/docs-build/build-system/build.js +++ b/docs-build/build-system/build.js @@ -27,6 +27,10 @@ build( ), ], ) +build( + require.resolve("./src/eslint-plugin-jsx-a11y.mjs"), + path.join(__dirname, "../shim/eslint-plugin-jsx-a11y.mjs"), +) /** build */ function build(input, out, injects = []) { diff --git a/docs-build/build-system/src/eslint-plugin-jsx-a11y.mjs b/docs-build/build-system/src/eslint-plugin-jsx-a11y.mjs new file mode 100644 index 00000000..ef48e34f --- /dev/null +++ b/docs-build/build-system/src/eslint-plugin-jsx-a11y.mjs @@ -0,0 +1,5 @@ +/* eslint require-jsdoc:0 -- shim */ + +import * as all from "../../../node_modules/eslint-plugin-jsx-a11y" +export const rules = all.rules +export default all diff --git a/docs-build/src/components/ESLintCodeBlock.svelte b/docs-build/src/components/ESLintCodeBlock.svelte index e35eb578..4bedfe27 100644 --- a/docs-build/src/components/ESLintCodeBlock.svelte +++ b/docs-build/src/components/ESLintCodeBlock.svelte @@ -14,6 +14,10 @@ if (typeof window !== "undefined") { window.require.define("@typescript-eslint/parser", parser) } + const pluginJsxA11y = await import("eslint-plugin-jsx-a11y") + if (typeof window !== "undefined") { + window.require.define("eslint-plugin-jsx-a11y", pluginJsxA11y) + } return window.waitSetupForAstroCompilerWasm }) .then(() => { diff --git a/docs-build/src/components/ESLintPlayground.svelte b/docs-build/src/components/ESLintPlayground.svelte index 8ca513da..27dada0b 100644 --- a/docs-build/src/components/ESLintPlayground.svelte +++ b/docs-build/src/components/ESLintPlayground.svelte @@ -19,6 +19,10 @@ if (typeof window !== "undefined") { window.require.define("@typescript-eslint/parser", parser) } + const pluginJsxA11y = await import("eslint-plugin-jsx-a11y") + if (typeof window !== "undefined") { + window.require.define("eslint-plugin-jsx-a11y", pluginJsxA11y) + } return window.waitSetupForAstroCompilerWasm }) .then(() => { diff --git a/docs-build/src/components/eslint/scripts/linter.mjs b/docs-build/src/components/eslint/scripts/linter.mjs index 90a22631..33fa8b2a 100644 --- a/docs-build/src/components/eslint/scripts/linter.mjs +++ b/docs-build/src/components/eslint/scripts/linter.mjs @@ -26,6 +26,11 @@ export const categories = [ classes: "astro-category", rules: [], }, + { + title: "A11Y Extension Rules", + classes: "astro-category", + rules: [], + }, { title: "Extension Rules", classes: "astro-category", diff --git a/docs-build/src/config.ts b/docs-build/src/config.ts index 7f623582..2104ca58 100644 --- a/docs-build/src/config.ts +++ b/docs-build/src/config.ts @@ -5,6 +5,7 @@ const categories = [ "Security Vulnerability", "Best Practices", "Stylistic Issues", + "A11Y Extension Rules", "Extension Rules", "System", ] as const diff --git a/docs/README.md b/docs/README.md index 8732e229..98cab2f4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -61,3 +61,4 @@ See the [LICENSE](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/LIC [astro]: https://astro.build/ [eslint]: https://eslint.org/ [astro components]: https://docs.astro.build/en/core-concepts/astro-components/ +[eslint-plugin-jsx-a11y]: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y diff --git a/docs/rules.md b/docs/rules.md index b04eb208..ea5a17c0 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -40,3 +40,46 @@ These rules relate to style guidelines, and are therefore quite subjective: | [astro/prefer-class-list-directive](./rules/prefer-class-list-directive.md) | require `class:list` directives instead of `class` with expressions | :wrench: | | [astro/prefer-object-class-list](./rules/prefer-object-class-list.md) | require use object instead of ternary expression in `class:list` | :wrench: | | [astro/prefer-split-class-list](./rules/prefer-split-class-list.md) | require use split array elements in `class:list` | :wrench: | + +## A11Y Extension Rules + +These rules extend the rules provided by [eslint-plugin-jsx-a11y] to work well in Astro component: +(You need to install [eslint-plugin-jsx-a11y] to use the rules.) + +| Rule ID | Description | | +|:--------|:------------|:---| +| [astro/jsx-a11y/alt-text](./rules/jsx-a11y/alt-text.md) | apply `jsx-a11y/alt-text` rule to Astro components | | +| [astro/jsx-a11y/anchor-has-content](./rules/jsx-a11y/anchor-has-content.md) | apply `jsx-a11y/anchor-has-content` rule to Astro components | | +| [astro/jsx-a11y/anchor-is-valid](./rules/jsx-a11y/anchor-is-valid.md) | apply `jsx-a11y/anchor-is-valid` rule to Astro components | | +| [astro/jsx-a11y/aria-activedescendant-has-tabindex](./rules/jsx-a11y/aria-activedescendant-has-tabindex.md) | apply `jsx-a11y/aria-activedescendant-has-tabindex` rule to Astro components | | +| [astro/jsx-a11y/aria-props](./rules/jsx-a11y/aria-props.md) | apply `jsx-a11y/aria-props` rule to Astro components | | +| [astro/jsx-a11y/aria-proptypes](./rules/jsx-a11y/aria-proptypes.md) | apply `jsx-a11y/aria-proptypes` rule to Astro components | | +| [astro/jsx-a11y/aria-role](./rules/jsx-a11y/aria-role.md) | apply `jsx-a11y/aria-role` rule to Astro components | | +| [astro/jsx-a11y/aria-unsupported-elements](./rules/jsx-a11y/aria-unsupported-elements.md) | apply `jsx-a11y/aria-unsupported-elements` rule to Astro components | | +| [astro/jsx-a11y/autocomplete-valid](./rules/jsx-a11y/autocomplete-valid.md) | apply `jsx-a11y/autocomplete-valid` rule to Astro components | | +| [astro/jsx-a11y/click-events-have-key-events](./rules/jsx-a11y/click-events-have-key-events.md) | apply `jsx-a11y/click-events-have-key-events` rule to Astro components | | +| [astro/jsx-a11y/control-has-associated-label](./rules/jsx-a11y/control-has-associated-label.md) | apply `jsx-a11y/control-has-associated-label` rule to Astro components | | +| [astro/jsx-a11y/heading-has-content](./rules/jsx-a11y/heading-has-content.md) | apply `jsx-a11y/heading-has-content` rule to Astro components | | +| [astro/jsx-a11y/html-has-lang](./rules/jsx-a11y/html-has-lang.md) | apply `jsx-a11y/html-has-lang` rule to Astro components | | +| [astro/jsx-a11y/iframe-has-title](./rules/jsx-a11y/iframe-has-title.md) | apply `jsx-a11y/iframe-has-title` rule to Astro components | | +| [astro/jsx-a11y/img-redundant-alt](./rules/jsx-a11y/img-redundant-alt.md) | apply `jsx-a11y/img-redundant-alt` rule to Astro components | | +| [astro/jsx-a11y/interactive-supports-focus](./rules/jsx-a11y/interactive-supports-focus.md) | apply `jsx-a11y/interactive-supports-focus` rule to Astro components | | +| [astro/jsx-a11y/label-has-associated-control](./rules/jsx-a11y/label-has-associated-control.md) | apply `jsx-a11y/label-has-associated-control` rule to Astro components | | +| [astro/jsx-a11y/lang](./rules/jsx-a11y/lang.md) | apply `jsx-a11y/lang` rule to Astro components | | +| [astro/jsx-a11y/media-has-caption](./rules/jsx-a11y/media-has-caption.md) | apply `jsx-a11y/media-has-caption` rule to Astro components | | +| [astro/jsx-a11y/mouse-events-have-key-events](./rules/jsx-a11y/mouse-events-have-key-events.md) | apply `jsx-a11y/mouse-events-have-key-events` rule to Astro components | | +| [astro/jsx-a11y/no-access-key](./rules/jsx-a11y/no-access-key.md) | apply `jsx-a11y/no-access-key` rule to Astro components | | +| [astro/jsx-a11y/no-autofocus](./rules/jsx-a11y/no-autofocus.md) | apply `jsx-a11y/no-autofocus` rule to Astro components | | +| [astro/jsx-a11y/no-distracting-elements](./rules/jsx-a11y/no-distracting-elements.md) | apply `jsx-a11y/no-distracting-elements` rule to Astro components | | +| [astro/jsx-a11y/no-interactive-element-to-noninteractive-role](./rules/jsx-a11y/no-interactive-element-to-noninteractive-role.md) | apply `jsx-a11y/no-interactive-element-to-noninteractive-role` rule to Astro components | | +| [astro/jsx-a11y/no-noninteractive-element-interactions](./rules/jsx-a11y/no-noninteractive-element-interactions.md) | apply `jsx-a11y/no-noninteractive-element-interactions` rule to Astro components | | +| [astro/jsx-a11y/no-noninteractive-element-to-interactive-role](./rules/jsx-a11y/no-noninteractive-element-to-interactive-role.md) | apply `jsx-a11y/no-noninteractive-element-to-interactive-role` rule to Astro components | | +| [astro/jsx-a11y/no-noninteractive-tabindex](./rules/jsx-a11y/no-noninteractive-tabindex.md) | apply `jsx-a11y/no-noninteractive-tabindex` rule to Astro components | | +| [astro/jsx-a11y/no-redundant-roles](./rules/jsx-a11y/no-redundant-roles.md) | apply `jsx-a11y/no-redundant-roles` rule to Astro components | | +| [astro/jsx-a11y/no-static-element-interactions](./rules/jsx-a11y/no-static-element-interactions.md) | apply `jsx-a11y/no-static-element-interactions` rule to Astro components | | +| [astro/jsx-a11y/role-has-required-aria-props](./rules/jsx-a11y/role-has-required-aria-props.md) | apply `jsx-a11y/role-has-required-aria-props` rule to Astro components | | +| [astro/jsx-a11y/role-supports-aria-props](./rules/jsx-a11y/role-supports-aria-props.md) | apply `jsx-a11y/role-supports-aria-props` rule to Astro components | | +| [astro/jsx-a11y/scope](./rules/jsx-a11y/scope.md) | apply `jsx-a11y/scope` rule to Astro components | | +| [astro/jsx-a11y/tabindex-no-positive](./rules/jsx-a11y/tabindex-no-positive.md) | apply `jsx-a11y/tabindex-no-positive` rule to Astro components | | + +[eslint-plugin-jsx-a11y]: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y diff --git a/docs/rules/jsx-a11y/alt-text.md b/docs/rules/jsx-a11y/alt-text.md new file mode 100644 index 00000000..e8c98570 --- /dev/null +++ b/docs/rules/jsx-a11y/alt-text.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/alt-text" +description: "apply `jsx-a11y/alt-text` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/alt-text + +> apply `jsx-a11y/alt-text` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/alt-text](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/alt-text.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/alt-text](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/alt-text.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/alt-text.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/alt-text.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/alt-text.md) diff --git a/docs/rules/jsx-a11y/anchor-has-content.md b/docs/rules/jsx-a11y/anchor-has-content.md new file mode 100644 index 00000000..593246e8 --- /dev/null +++ b/docs/rules/jsx-a11y/anchor-has-content.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/anchor-has-content" +description: "apply `jsx-a11y/anchor-has-content` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/anchor-has-content + +> apply `jsx-a11y/anchor-has-content` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/anchor-has-content](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-has-content.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/anchor-has-content](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-has-content.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/anchor-has-content.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/anchor-has-content.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-has-content.md) diff --git a/docs/rules/jsx-a11y/anchor-is-valid.md b/docs/rules/jsx-a11y/anchor-is-valid.md new file mode 100644 index 00000000..7a6989aa --- /dev/null +++ b/docs/rules/jsx-a11y/anchor-is-valid.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/anchor-is-valid" +description: "apply `jsx-a11y/anchor-is-valid` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/anchor-is-valid + +> apply `jsx-a11y/anchor-is-valid` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/anchor-is-valid](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-is-valid.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/anchor-is-valid](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-is-valid.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/anchor-is-valid.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/anchor-is-valid.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-is-valid.md) diff --git a/docs/rules/jsx-a11y/aria-activedescendant-has-tabindex.md b/docs/rules/jsx-a11y/aria-activedescendant-has-tabindex.md new file mode 100644 index 00000000..dbf0a7dc --- /dev/null +++ b/docs/rules/jsx-a11y/aria-activedescendant-has-tabindex.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/aria-activedescendant-has-tabindex" +description: "apply `jsx-a11y/aria-activedescendant-has-tabindex` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/aria-activedescendant-has-tabindex + +> apply `jsx-a11y/aria-activedescendant-has-tabindex` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/aria-activedescendant-has-tabindex](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-activedescendant-has-tabindex.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/aria-activedescendant-has-tabindex](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-activedescendant-has-tabindex.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/aria-activedescendant-has-tabindex.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/aria-activedescendant-has-tabindex.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-activedescendant-has-tabindex.md) diff --git a/docs/rules/jsx-a11y/aria-props.md b/docs/rules/jsx-a11y/aria-props.md new file mode 100644 index 00000000..62d63217 --- /dev/null +++ b/docs/rules/jsx-a11y/aria-props.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/aria-props" +description: "apply `jsx-a11y/aria-props` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/aria-props + +> apply `jsx-a11y/aria-props` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-props.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-props.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/aria-props.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/aria-props.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-props.md) diff --git a/docs/rules/jsx-a11y/aria-proptypes.md b/docs/rules/jsx-a11y/aria-proptypes.md new file mode 100644 index 00000000..1ca5446b --- /dev/null +++ b/docs/rules/jsx-a11y/aria-proptypes.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/aria-proptypes" +description: "apply `jsx-a11y/aria-proptypes` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/aria-proptypes + +> apply `jsx-a11y/aria-proptypes` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/aria-proptypes](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-proptypes.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/aria-proptypes](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-proptypes.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/aria-proptypes.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/aria-proptypes.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-proptypes.md) diff --git a/docs/rules/jsx-a11y/aria-role.md b/docs/rules/jsx-a11y/aria-role.md new file mode 100644 index 00000000..20977715 --- /dev/null +++ b/docs/rules/jsx-a11y/aria-role.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/aria-role" +description: "apply `jsx-a11y/aria-role` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/aria-role + +> apply `jsx-a11y/aria-role` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/aria-role](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-role.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/aria-role](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-role.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/aria-role.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/aria-role.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-role.md) diff --git a/docs/rules/jsx-a11y/aria-unsupported-elements.md b/docs/rules/jsx-a11y/aria-unsupported-elements.md new file mode 100644 index 00000000..11501067 --- /dev/null +++ b/docs/rules/jsx-a11y/aria-unsupported-elements.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/aria-unsupported-elements" +description: "apply `jsx-a11y/aria-unsupported-elements` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/aria-unsupported-elements + +> apply `jsx-a11y/aria-unsupported-elements` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/aria-unsupported-elements](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-unsupported-elements.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/aria-unsupported-elements](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-unsupported-elements.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/aria-unsupported-elements.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/aria-unsupported-elements.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-unsupported-elements.md) diff --git a/docs/rules/jsx-a11y/autocomplete-valid.md b/docs/rules/jsx-a11y/autocomplete-valid.md new file mode 100644 index 00000000..6abe83ad --- /dev/null +++ b/docs/rules/jsx-a11y/autocomplete-valid.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/autocomplete-valid" +description: "apply `jsx-a11y/autocomplete-valid` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/autocomplete-valid + +> apply `jsx-a11y/autocomplete-valid` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/autocomplete-valid](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/autocomplete-valid.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/autocomplete-valid](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/autocomplete-valid.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/autocomplete-valid.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/autocomplete-valid.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/autocomplete-valid.md) diff --git a/docs/rules/jsx-a11y/click-events-have-key-events.md b/docs/rules/jsx-a11y/click-events-have-key-events.md new file mode 100644 index 00000000..755d0761 --- /dev/null +++ b/docs/rules/jsx-a11y/click-events-have-key-events.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/click-events-have-key-events" +description: "apply `jsx-a11y/click-events-have-key-events` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/click-events-have-key-events + +> apply `jsx-a11y/click-events-have-key-events` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/click-events-have-key-events](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/click-events-have-key-events.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/click-events-have-key-events](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/click-events-have-key-events.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/click-events-have-key-events.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/click-events-have-key-events.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/click-events-have-key-events.md) diff --git a/docs/rules/jsx-a11y/control-has-associated-label.md b/docs/rules/jsx-a11y/control-has-associated-label.md new file mode 100644 index 00000000..37b3098d --- /dev/null +++ b/docs/rules/jsx-a11y/control-has-associated-label.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/control-has-associated-label" +description: "apply `jsx-a11y/control-has-associated-label` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/control-has-associated-label + +> apply `jsx-a11y/control-has-associated-label` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/control-has-associated-label](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/control-has-associated-label.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/control-has-associated-label](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/control-has-associated-label.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/control-has-associated-label.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/control-has-associated-label.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/control-has-associated-label.md) diff --git a/docs/rules/jsx-a11y/heading-has-content.md b/docs/rules/jsx-a11y/heading-has-content.md new file mode 100644 index 00000000..88ae81a0 --- /dev/null +++ b/docs/rules/jsx-a11y/heading-has-content.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/heading-has-content" +description: "apply `jsx-a11y/heading-has-content` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/heading-has-content + +> apply `jsx-a11y/heading-has-content` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/heading-has-content](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/heading-has-content.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/heading-has-content](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/heading-has-content.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/heading-has-content.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/heading-has-content.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/heading-has-content.md) diff --git a/docs/rules/jsx-a11y/html-has-lang.md b/docs/rules/jsx-a11y/html-has-lang.md new file mode 100644 index 00000000..842f0849 --- /dev/null +++ b/docs/rules/jsx-a11y/html-has-lang.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/html-has-lang" +description: "apply `jsx-a11y/html-has-lang` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/html-has-lang + +> apply `jsx-a11y/html-has-lang` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/html-has-lang](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/html-has-lang.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/html-has-lang](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/html-has-lang.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/html-has-lang.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/html-has-lang.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/html-has-lang.md) diff --git a/docs/rules/jsx-a11y/iframe-has-title.md b/docs/rules/jsx-a11y/iframe-has-title.md new file mode 100644 index 00000000..1dcc60e7 --- /dev/null +++ b/docs/rules/jsx-a11y/iframe-has-title.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/iframe-has-title" +description: "apply `jsx-a11y/iframe-has-title` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/iframe-has-title + +> apply `jsx-a11y/iframe-has-title` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/iframe-has-title](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/iframe-has-title.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/iframe-has-title](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/iframe-has-title.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/iframe-has-title.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/iframe-has-title.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/iframe-has-title.md) diff --git a/docs/rules/jsx-a11y/img-redundant-alt.md b/docs/rules/jsx-a11y/img-redundant-alt.md new file mode 100644 index 00000000..9811687b --- /dev/null +++ b/docs/rules/jsx-a11y/img-redundant-alt.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/img-redundant-alt" +description: "apply `jsx-a11y/img-redundant-alt` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/img-redundant-alt + +> apply `jsx-a11y/img-redundant-alt` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/img-redundant-alt](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/img-redundant-alt.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/img-redundant-alt](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/img-redundant-alt.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/img-redundant-alt.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/img-redundant-alt.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/img-redundant-alt.md) diff --git a/docs/rules/jsx-a11y/interactive-supports-focus.md b/docs/rules/jsx-a11y/interactive-supports-focus.md new file mode 100644 index 00000000..d7764e6a --- /dev/null +++ b/docs/rules/jsx-a11y/interactive-supports-focus.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/interactive-supports-focus" +description: "apply `jsx-a11y/interactive-supports-focus` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/interactive-supports-focus + +> apply `jsx-a11y/interactive-supports-focus` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/interactive-supports-focus](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/interactive-supports-focus.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/interactive-supports-focus](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/interactive-supports-focus.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/interactive-supports-focus.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/interactive-supports-focus.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/interactive-supports-focus.md) diff --git a/docs/rules/jsx-a11y/label-has-associated-control.md b/docs/rules/jsx-a11y/label-has-associated-control.md new file mode 100644 index 00000000..c12de2e1 --- /dev/null +++ b/docs/rules/jsx-a11y/label-has-associated-control.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/label-has-associated-control" +description: "apply `jsx-a11y/label-has-associated-control` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/label-has-associated-control + +> apply `jsx-a11y/label-has-associated-control` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/label-has-associated-control](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/label-has-associated-control.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/label-has-associated-control](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/label-has-associated-control.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/label-has-associated-control.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/label-has-associated-control.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/label-has-associated-control.md) diff --git a/docs/rules/jsx-a11y/lang.md b/docs/rules/jsx-a11y/lang.md new file mode 100644 index 00000000..71189788 --- /dev/null +++ b/docs/rules/jsx-a11y/lang.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/lang" +description: "apply `jsx-a11y/lang` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/lang + +> apply `jsx-a11y/lang` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/lang](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/lang.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/lang](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/lang.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/lang.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/lang.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/lang.md) diff --git a/docs/rules/jsx-a11y/media-has-caption.md b/docs/rules/jsx-a11y/media-has-caption.md new file mode 100644 index 00000000..af0eff75 --- /dev/null +++ b/docs/rules/jsx-a11y/media-has-caption.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/media-has-caption" +description: "apply `jsx-a11y/media-has-caption` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/media-has-caption + +> apply `jsx-a11y/media-has-caption` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/media-has-caption](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/media-has-caption.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/media-has-caption](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/media-has-caption.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/media-has-caption.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/media-has-caption.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/media-has-caption.md) diff --git a/docs/rules/jsx-a11y/mouse-events-have-key-events.md b/docs/rules/jsx-a11y/mouse-events-have-key-events.md new file mode 100644 index 00000000..6acf013c --- /dev/null +++ b/docs/rules/jsx-a11y/mouse-events-have-key-events.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/mouse-events-have-key-events" +description: "apply `jsx-a11y/mouse-events-have-key-events` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/mouse-events-have-key-events + +> apply `jsx-a11y/mouse-events-have-key-events` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/mouse-events-have-key-events](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/mouse-events-have-key-events.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/mouse-events-have-key-events](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/mouse-events-have-key-events.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/mouse-events-have-key-events.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/mouse-events-have-key-events.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/mouse-events-have-key-events.md) diff --git a/docs/rules/jsx-a11y/no-access-key.md b/docs/rules/jsx-a11y/no-access-key.md new file mode 100644 index 00000000..241652ab --- /dev/null +++ b/docs/rules/jsx-a11y/no-access-key.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/no-access-key" +description: "apply `jsx-a11y/no-access-key` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/no-access-key + +> apply `jsx-a11y/no-access-key` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/no-access-key](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-access-key.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/no-access-key](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-access-key.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/no-access-key.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/no-access-key.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-access-key.md) diff --git a/docs/rules/jsx-a11y/no-autofocus.md b/docs/rules/jsx-a11y/no-autofocus.md new file mode 100644 index 00000000..382c3b6c --- /dev/null +++ b/docs/rules/jsx-a11y/no-autofocus.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/no-autofocus" +description: "apply `jsx-a11y/no-autofocus` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/no-autofocus + +> apply `jsx-a11y/no-autofocus` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/no-autofocus](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-autofocus.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/no-autofocus](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-autofocus.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/no-autofocus.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/no-autofocus.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-autofocus.md) diff --git a/docs/rules/jsx-a11y/no-distracting-elements.md b/docs/rules/jsx-a11y/no-distracting-elements.md new file mode 100644 index 00000000..93da9c63 --- /dev/null +++ b/docs/rules/jsx-a11y/no-distracting-elements.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/no-distracting-elements" +description: "apply `jsx-a11y/no-distracting-elements` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/no-distracting-elements + +> apply `jsx-a11y/no-distracting-elements` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/no-distracting-elements](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-distracting-elements.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/no-distracting-elements](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-distracting-elements.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/no-distracting-elements.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/no-distracting-elements.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-distracting-elements.md) diff --git a/docs/rules/jsx-a11y/no-interactive-element-to-noninteractive-role.md b/docs/rules/jsx-a11y/no-interactive-element-to-noninteractive-role.md new file mode 100644 index 00000000..fa5c9088 --- /dev/null +++ b/docs/rules/jsx-a11y/no-interactive-element-to-noninteractive-role.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/no-interactive-element-to-noninteractive-role" +description: "apply `jsx-a11y/no-interactive-element-to-noninteractive-role` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/no-interactive-element-to-noninteractive-role + +> apply `jsx-a11y/no-interactive-element-to-noninteractive-role` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/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) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/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) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/no-interactive-element-to-noninteractive-role.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/no-interactive-element-to-noninteractive-role.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-interactive-element-to-noninteractive-role.md) diff --git a/docs/rules/jsx-a11y/no-noninteractive-element-interactions.md b/docs/rules/jsx-a11y/no-noninteractive-element-interactions.md new file mode 100644 index 00000000..9fdde284 --- /dev/null +++ b/docs/rules/jsx-a11y/no-noninteractive-element-interactions.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/no-noninteractive-element-interactions" +description: "apply `jsx-a11y/no-noninteractive-element-interactions` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/no-noninteractive-element-interactions + +> apply `jsx-a11y/no-noninteractive-element-interactions` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/no-noninteractive-element-interactions](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-interactions.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/no-noninteractive-element-interactions](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-interactions.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/no-noninteractive-element-interactions.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/no-noninteractive-element-interactions.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-interactions.md) diff --git a/docs/rules/jsx-a11y/no-noninteractive-element-to-interactive-role.md b/docs/rules/jsx-a11y/no-noninteractive-element-to-interactive-role.md new file mode 100644 index 00000000..f20ea7fd --- /dev/null +++ b/docs/rules/jsx-a11y/no-noninteractive-element-to-interactive-role.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/no-noninteractive-element-to-interactive-role" +description: "apply `jsx-a11y/no-noninteractive-element-to-interactive-role` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/no-noninteractive-element-to-interactive-role + +> apply `jsx-a11y/no-noninteractive-element-to-interactive-role` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/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) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/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) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/no-noninteractive-element-to-interactive-role.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/no-noninteractive-element-to-interactive-role.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-to-interactive-role.md) diff --git a/docs/rules/jsx-a11y/no-noninteractive-tabindex.md b/docs/rules/jsx-a11y/no-noninteractive-tabindex.md new file mode 100644 index 00000000..6177f3cf --- /dev/null +++ b/docs/rules/jsx-a11y/no-noninteractive-tabindex.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/no-noninteractive-tabindex" +description: "apply `jsx-a11y/no-noninteractive-tabindex` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/no-noninteractive-tabindex + +> apply `jsx-a11y/no-noninteractive-tabindex` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/no-noninteractive-tabindex](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-tabindex.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/no-noninteractive-tabindex](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-tabindex.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/no-noninteractive-tabindex.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/no-noninteractive-tabindex.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-tabindex.md) diff --git a/docs/rules/jsx-a11y/no-redundant-roles.md b/docs/rules/jsx-a11y/no-redundant-roles.md new file mode 100644 index 00000000..09fe6306 --- /dev/null +++ b/docs/rules/jsx-a11y/no-redundant-roles.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/no-redundant-roles" +description: "apply `jsx-a11y/no-redundant-roles` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/no-redundant-roles + +> apply `jsx-a11y/no-redundant-roles` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/no-redundant-roles](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-redundant-roles.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/no-redundant-roles](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-redundant-roles.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/no-redundant-roles.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/no-redundant-roles.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-redundant-roles.md) diff --git a/docs/rules/jsx-a11y/no-static-element-interactions.md b/docs/rules/jsx-a11y/no-static-element-interactions.md new file mode 100644 index 00000000..ee8675fa --- /dev/null +++ b/docs/rules/jsx-a11y/no-static-element-interactions.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/no-static-element-interactions" +description: "apply `jsx-a11y/no-static-element-interactions` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/no-static-element-interactions + +> apply `jsx-a11y/no-static-element-interactions` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/no-static-element-interactions](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-static-element-interactions.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/no-static-element-interactions](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-static-element-interactions.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/no-static-element-interactions.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/no-static-element-interactions.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-static-element-interactions.md) diff --git a/docs/rules/jsx-a11y/role-has-required-aria-props.md b/docs/rules/jsx-a11y/role-has-required-aria-props.md new file mode 100644 index 00000000..b7a742d8 --- /dev/null +++ b/docs/rules/jsx-a11y/role-has-required-aria-props.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/role-has-required-aria-props" +description: "apply `jsx-a11y/role-has-required-aria-props` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/role-has-required-aria-props + +> apply `jsx-a11y/role-has-required-aria-props` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/role-has-required-aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-has-required-aria-props.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/role-has-required-aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-has-required-aria-props.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/role-has-required-aria-props.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/role-has-required-aria-props.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-has-required-aria-props.md) diff --git a/docs/rules/jsx-a11y/role-supports-aria-props.md b/docs/rules/jsx-a11y/role-supports-aria-props.md new file mode 100644 index 00000000..d9b1df76 --- /dev/null +++ b/docs/rules/jsx-a11y/role-supports-aria-props.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/role-supports-aria-props" +description: "apply `jsx-a11y/role-supports-aria-props` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/role-supports-aria-props + +> apply `jsx-a11y/role-supports-aria-props` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/role-supports-aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-supports-aria-props.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/role-supports-aria-props](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-supports-aria-props.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/role-supports-aria-props.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/role-supports-aria-props.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-supports-aria-props.md) diff --git a/docs/rules/jsx-a11y/scope.md b/docs/rules/jsx-a11y/scope.md new file mode 100644 index 00000000..a1be4810 --- /dev/null +++ b/docs/rules/jsx-a11y/scope.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/scope" +description: "apply `jsx-a11y/scope` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/scope + +> apply `jsx-a11y/scope` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/scope](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/scope.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/scope](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/scope.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/scope.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/scope.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/scope.md) diff --git a/docs/rules/jsx-a11y/tabindex-no-positive.md b/docs/rules/jsx-a11y/tabindex-no-positive.md new file mode 100644 index 00000000..32432779 --- /dev/null +++ b/docs/rules/jsx-a11y/tabindex-no-positive.md @@ -0,0 +1,24 @@ +--- +title: "astro/jsx-a11y/tabindex-no-positive" +description: "apply `jsx-a11y/tabindex-no-positive` rule to Astro components" +setup: "import ESLintCodeBlock from '../docs-build/src/components/ESLintCodeBlockWrap.astro'" +--- + +# astro/jsx-a11y/tabindex-no-positive + +> apply `jsx-a11y/tabindex-no-positive` rule to Astro components + +- :exclamation: **_This rule has not been released yet._** + +This rule is the same rule as [jsx-a11y/tabindex-no-positive](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/tabindex-no-positive.md) rule but it applies to the Astro components. + +## :books: Further Reading + +- [jsx-a11y/tabindex-no-positive](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/tabindex-no-positive.md) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/jsx-a11y/tabindex-no-positive.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/jsx-a11y/tabindex-no-positive.ts) + +Taken with ❤️ [from eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/tabindex-no-positive.md) diff --git a/docs/user-guide.md b/docs/user-guide.md index dfcbae15..4adb8249 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -8,12 +8,21 @@ npm install --save-dev eslint eslint-plugin-astro ``` -If you write TypeScript in Astro components, install the `@typescript-eslint/parser` as well: +If you write TypeScript in Astro components, you also need to install the `@typescript-eslint/parser`: ```bash npm install --save-dev @typescript-eslint/parser ``` +If you want to use the rules for checking accessibility (A11Y), you also need to install [eslint-plugin-jsx-a11y] additionally: +(It is used internally in the rules for A11Y.) + +```bash +npm install --save-dev eslint-plugin-jsx-a11y +``` + +[eslint-plugin-jsx-a11y]: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y + > **Requirements** > > - ESLint v7.0.0 and above @@ -76,7 +85,7 @@ module.exports = { // Enables global variables available in Astro components. node: true, "astro/astro": true, - es2022: true, + es2020: true, }, // Allows Astro components to be parsed. parser: "astro-eslint-parser", @@ -103,7 +112,7 @@ module.exports = { files: ["**/*.astro/*.js", "*.astro/*.js"], env: { browser: true, - es2022: true, + es2020: true, }, parserOptions: { sourceType: "module", @@ -129,6 +138,9 @@ This plugin provides configs: - `plugin:astro/base` ... Minimal configuration to enable correct Astro component linting. - `plugin:astro/recommended` ... Above, plus rules to prevent errors or unintended behavior. - `plugin:astro/all` ... Configuration enables all astro rules. It's meant for testing, not for production use because it changes with every minor and major version of the plugin. Use it at your own risk. +- Extension of sharable configuration provided by [eslint-plugin-jsx-a11y]. You need to install [eslint-plugin-jsx-a11y] to use it. + - `plugin:astro/jsx-a11y-recommended` ... Similar to the [`"plugin:jsx-a11y/recommended"` configuration](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#rule-strictness-in-different-modes), but with the rules extended for Astro components enabled. + - `plugin:astro/jsx-a11y-strict` ... Similar to the [`"plugin:jsx-a11y/strict"` configuration](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#rule-strictness-in-different-modes), but with the rules extended for Astro components enabled. See [the rule list](./rules.md) to get the `rules` that this plugin provides. diff --git a/package.json b/package.json index 4be29ecc..70a6dd23 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "eslint-plugin-eslint-plugin": "^4.2.0", "eslint-plugin-json-schema-validator": "^3.0.2", "eslint-plugin-jsonc": "^2.2.1", + "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-markdown": "^2.2.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-node-dependencies": "^0.8.0", diff --git a/src/a11y/configs.ts b/src/a11y/configs.ts new file mode 100644 index 00000000..cfed59bd --- /dev/null +++ b/src/a11y/configs.ts @@ -0,0 +1,36 @@ +import { getPluginJsxA11y } from "./load" +import path from "path" +import { a11yConfigKeys } from "./keys" + +/** Build a11y configs */ +export function buildConfigs(): Record { + const basePath = require.resolve("../configs/base") + const baseExtend = + path.extname(`${basePath}`) === ".ts" ? "plugin:astro/base" : basePath + + const configs: Record = {} + + for (const configName of a11yConfigKeys) { + Object.defineProperty(configs, `jsx-a11y-${configName}`, { + enumerable: true, + get() { + const base = getPluginJsxA11y() + const baseConfig = base?.configs?.[configName] ?? {} + + const baseRules = baseConfig.rules ?? {} + const newRules: Record = {} + for (const ruleName of Object.keys(baseRules)) { + newRules[`astro/${ruleName}`] = baseRules[ruleName] + } + + return { + ...baseConfig, + plugins: ["jsx-a11y"], + extends: [baseExtend], + rules: newRules, + } + }, + }) + } + return configs +} diff --git a/src/a11y/index.ts b/src/a11y/index.ts new file mode 100644 index 00000000..6f1f956f --- /dev/null +++ b/src/a11y/index.ts @@ -0,0 +1,13 @@ +import type { RuleModule } from "../types" +import { buildConfigs } from "./configs" +import { buildRules } from "./rules" + +/** Build a11y rules */ +export function buildA11yRules(): RuleModule[] { + return buildRules() +} + +/** Build a11y configs */ +export function buildA11yConfigs(): Record { + return buildConfigs() +} diff --git a/src/a11y/keys.ts b/src/a11y/keys.ts new file mode 100644 index 00000000..efeb2f89 --- /dev/null +++ b/src/a11y/keys.ts @@ -0,0 +1,45 @@ +import { getPluginJsxA11y } from "./load" + +const plugin = getPluginJsxA11y() +export const a11yRuleKeys = plugin?.rules + ? Object.keys(plugin.rules).filter( + (s) => !plugin?.rules?.[s]?.meta?.deprecated, + ) + : ([ + "alt-text", + "anchor-has-content", + "anchor-is-valid", + "aria-activedescendant-has-tabindex", + "aria-props", + "aria-proptypes", + "aria-role", + "aria-unsupported-elements", + "autocomplete-valid", + "click-events-have-key-events", + "control-has-associated-label", + "heading-has-content", + "html-has-lang", + "iframe-has-title", + "img-redundant-alt", + "interactive-supports-focus", + "label-has-associated-control", + "lang", + "media-has-caption", + "mouse-events-have-key-events", + "no-access-key", + "no-autofocus", + "no-distracting-elements", + "no-interactive-element-to-noninteractive-role", + "no-noninteractive-element-interactions", + "no-noninteractive-element-to-interactive-role", + "no-noninteractive-tabindex", + "no-redundant-roles", + "no-static-element-interactions", + "role-has-required-aria-props", + "role-supports-aria-props", + "scope", + "tabindex-no-positive", + ] as const) +export const a11yConfigKeys = plugin?.configs + ? Object.keys(plugin.configs) + : (["recommended", "strict"] as const) diff --git a/src/a11y/load.ts b/src/a11y/load.ts new file mode 100644 index 00000000..b7ed618e --- /dev/null +++ b/src/a11y/load.ts @@ -0,0 +1,50 @@ +import type { RuleContext, RuleListener } from "../types" +import { requireUserLocal } from "../utils/resolve-parser/require-user" + +export type PluginRuleModule = { + meta?: { + docs?: { + url?: string + } + messages?: never + schema?: never + type?: never + fixable?: never + deprecated?: boolean + } + create: (context: RuleContext) => RuleListener +} +type PluginConfig = { + plugins?: string | string[] + parserOptions?: unknown + rules?: Record +} +export type PluginJsxA11y = { + rules?: Record + configs?: Record +} +let pluginJsxA11yCache: PluginJsxA11y | null = null +let loaded = false +/** + * Load `eslint-plugin-jsx-a11y` from the user local. + */ +export function getPluginJsxA11y(): PluginJsxA11y | null { + if (loaded) { + return pluginJsxA11yCache + } + if (!pluginJsxA11yCache) { + pluginJsxA11yCache = requireUserLocal("eslint-plugin-jsx-a11y") + } + if (!pluginJsxA11yCache) { + if (typeof require !== "undefined") { + try { + // eslint-disable-next-line @typescript-eslint/no-require-imports -- ignore + pluginJsxA11yCache = require("eslint-plugin-jsx-a11y") + } catch { + loaded = true + } + } + } + + return pluginJsxA11yCache || null +} diff --git a/src/a11y/rules.ts b/src/a11y/rules.ts new file mode 100644 index 00000000..1a481485 --- /dev/null +++ b/src/a11y/rules.ts @@ -0,0 +1,173 @@ +import type { RuleContext, RuleListener, RuleModule } from "../types" +import type { PluginRuleModule } from "./load" +import { getPluginJsxA11y } from "./load" +import type { ASTNode } from "../types-for-node" +import { createRule } from "../utils" +import { a11yRuleKeys } from "./keys" + +const TYPE_MAP: Partial> = { + AstroRawText: "JSXText", + AstroTemplateLiteralAttribute: "JSXAttribute", + AstroShorthandAttribute: "JSXAttribute", +} + +/** Get `eslint-plugin-jsx-a11y` rule. */ +function getPluginJsxA11yRule(ruleName: string) { + const base = getPluginJsxA11y() + return base?.rules?.[ruleName] +} + +/** Build a11y rules */ +export function buildRules(): RuleModule[] { + const rules: RuleModule[] = [] + + for (const ruleKey of a11yRuleKeys) { + const jsxRuleName = `jsx-a11y/${ruleKey}` + const astroRuleName = `astro/${jsxRuleName}` + const ruleWithoutMeta = createRule(jsxRuleName, { + meta: { + messages: {}, + schema: [], + type: "problem", + docs: { + description: `apply \`${jsxRuleName}\` rule to Astro components`, + category: "A11Y Extension Rules", + recommended: false, + available: () => Boolean(getPluginJsxA11y()), + }, + }, + create(context) { + const baseRule = getPluginJsxA11yRule(ruleKey) + if (!baseRule) { + context.report({ + loc: { line: 0, column: 0 }, + message: `If you want to use ${astroRuleName} rule, you need to install eslint-plugin-jsx-a11y.`, + }) + return {} + } + return defineWrapperListener(baseRule, context) + }, + }) + const docs: RuleModule["meta"]["docs"] = { + ...ruleWithoutMeta.meta.docs, + extensionRule: { + plugin: "eslint-plugin-jsx-a11y", + get url() { + return ( + getPluginJsxA11yRule(ruleKey)?.meta?.docs?.url ?? + `https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/${ruleKey}.md` + ) + }, + }, + } + const newRule: RuleModule = { + meta: new Proxy(ruleWithoutMeta.meta, { + get(_t, key: keyof RuleModule["meta"]) { + if (key === "docs") { + return docs + } + const baseRule = getPluginJsxA11yRule(ruleKey) + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ignore + return (baseRule?.meta as any)?.[key] ?? ruleWithoutMeta.meta[key] + }, + }), + create: ruleWithoutMeta.create, + } + + rules.push(newRule) + } + return rules +} + +/** + * Define the wrapped plugin rule. + */ +function defineWrapperListener( + coreRule: PluginRuleModule, + context: RuleContext, +): RuleListener { + if (!context.parserServices.isAstro) { + return {} + } + const listener = coreRule.create(context) + + const astroListener: RuleListener = {} + for (const key of Object.keys(listener)) { + const original = listener[key] + if (!original) { + continue + } + + // eslint-disable-next-line func-style -- ignore + const wrappedListener = function ( + this: never, + node: never, + ...args: never[] + ) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any, no-invalid-this -- ignore + ;(original as any).call(this, getProxyNode(node), ...args) + } + + astroListener[key] = wrappedListener + const astroKey = key + .replace(/(?:^|\b)AstroRawText(?:\b|$)/gu, "JSXText") + .replace( + /(?:^|\b)(?:AstroTemplateLiteralAttribute|AstroShorthandAttribute)(?:\b|$)/gu, + "JSXAttribute", + ) + // AstroFragment + // AstroHTMLComment + // AstroDoctype + if (astroKey !== key) { + astroListener[astroKey] = wrappedListener + } + } + + /** + * Check whether a given value is a node. + */ + function isNode( + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ignore + data: any, + ): boolean { + return ( + data && + typeof data.type === "string" && + Array.isArray(data.range) && + data.range.length === 2 && + typeof data.range[0] === "number" && + typeof data.range[1] === "number" + ) + } + + /** + * Get the proxy node + */ + function getProxyNode( + node: ASTNode, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ignore + ): any { + const type = TYPE_MAP[node.type] || node.type + const cache: Record = { type } + return new Proxy(node, { + get(_t, key) { + if (key in cache) { + return cache[key] + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ignore + const data = (node as any)[key] + if (isNode(data)) { + return (cache[key] = getProxyNode(data)) + } + if (Array.isArray(data)) { + return (cache[key] = data.map((e) => + isNode(e) ? getProxyNode(e) : e, + )) + } + return data + }, + }) + } + + return astroListener +} diff --git a/src/configs/all.ts b/src/configs/all.ts index 7f2103f2..e4ab78d2 100644 --- a/src/configs/all.ts +++ b/src/configs/all.ts @@ -2,7 +2,9 @@ import recommended from "./recommended" import { rules } from "../utils/rules" const all: Record = {} -for (const rule of rules) { +for (const rule of rules.filter( + (rule) => rule.meta.docs.available() && !rule.meta.deprecated, +)) { all[rule.meta.docs.ruleId] = "error" } diff --git a/src/configs/base.ts b/src/configs/base.ts index 26a7bc08..e459899c 100644 --- a/src/configs/base.ts +++ b/src/configs/base.ts @@ -10,7 +10,7 @@ export = { // Enables global variables available in Astro components. node: true, "astro/astro": true, - es2022: true, + es2020: true, }, // Allows Astro components to be parsed. parser: require.resolve("astro-eslint-parser"), @@ -32,7 +32,7 @@ export = { files: ["**/*.astro/*.js", "*.astro/*.js"], env: { browser: true, - es2022: true, + es2020: true, }, parserOptions: { sourceType: "module", diff --git a/src/index.ts b/src/index.ts index c0b09721..ea97a79d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,11 +5,23 @@ import { environment } from "./environment" import base from "./configs/base" import recommended from "./configs/recommended" import all from "./configs/all" +import { buildA11yConfigs } from "./a11y" const configs = { base, recommended, all, + ...buildA11yConfigs(), +} + +const a11yConfigs = buildA11yConfigs() +for (const configName of Object.keys(a11yConfigs)) { + Object.defineProperty(configs, configName, { + enumerable: true, + get() { + return a11yConfigs[configName] + }, + }) } const rules = ruleList.reduce((obj, r) => { diff --git a/src/types.ts b/src/types.ts index 49299956..c7274920 100644 --- a/src/types.ts +++ b/src/types.ts @@ -52,6 +52,7 @@ export type RuleCategory = | "Security Vulnerability" | "Best Practices" | "Stylistic Issues" + | "A11Y Extension Rules" | "Extension Rules" | "System" @@ -60,14 +61,21 @@ export interface RuleMetaData { description: string category: RuleCategory recommended: boolean | "base" - extensionRule?: string + extensionRule?: + | string + | { + plugin: string + url: string + } url: string ruleId: string ruleName: string default?: "error" | "warn" + available: () => boolean } messages: { [messageId: string]: string } fixable?: "code" | "whitespace" + hasSuggestions?: boolean schema: JSONSchema4 | JSONSchema4[] deprecated?: boolean replacedBy?: string[] @@ -84,11 +92,18 @@ export interface PartialRuleMetaData { description: string category: RuleCategory recommended: boolean | "base" - extensionRule?: string + extensionRule?: + | string + | { + plugin: string + url: string + } default?: "error" | "warn" + available?: () => boolean } messages: { [messageId: string]: string } fixable?: "code" | "whitespace" + hasSuggestions?: boolean schema: JSONSchema4 | JSONSchema4[] deprecated?: boolean replacedBy?: string[] diff --git a/src/utils/index.ts b/src/utils/index.ts index 5b94631d..bc9c269b 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -13,6 +13,7 @@ export function createRule( meta: { ...rule.meta, docs: { + available: () => true, ...rule.meta.docs, url: `https://ota-meshi.github.io/eslint-plugin-astro/rules/${ruleName}/`, ruleId: `astro/${ruleName}`, diff --git a/src/utils/rules.ts b/src/utils/rules.ts index 1f36ea66..7e24dacf 100644 --- a/src/utils/rules.ts +++ b/src/utils/rules.ts @@ -7,6 +7,7 @@ import noUnusedDefineVarsInStyle from "../rules/no-unused-define-vars-in-style" import preferClassListDirective from "../rules/prefer-class-list-directive" import preferObjectClassList from "../rules/prefer-object-class-list" import preferSplitClassList from "../rules/prefer-split-class-list" +import { buildA11yRules } from "../a11y" export const rules = [ noConflictSetDirectives, @@ -17,4 +18,5 @@ export const rules = [ preferClassListDirective, preferObjectClassList, preferSplitClassList, + ...buildA11yRules(), ] as RuleModule[] diff --git a/tests/src/integration/config-for-a11y.ts b/tests/src/integration/config-for-a11y.ts new file mode 100644 index 00000000..f0a513c4 --- /dev/null +++ b/tests/src/integration/config-for-a11y.ts @@ -0,0 +1,110 @@ +import { ESLint } from "eslint" +// @ts-expect-error -- ignore +import jsxA11yPlugin from "eslint-plugin-jsx-a11y" +import astroPlugin from "../../../src/index" +import assert from "assert" +import Module from "module" + +describe("Integration test for a11y config", () => { + // @ts-expect-error -- ignore + const originalLoad = Module._load + before(() => { + // @ts-expect-error -- ignore + Module._load = function (name, ...args) { + if (name === "eslint-plugin-astro") { + return astroPlugin + } + return originalLoad(name, ...args) + } + }) + after(() => { + // @ts-expect-error -- ignore + Module._load = originalLoad + }) + it("should work with a11y config strict", async () => { + const eslint = new ESLint({ + plugins: { + "jsx-a11y": jsxA11yPlugin, + astro: astroPlugin, + }, + useEslintrc: false, + overrideConfig: { + extends: ["plugin:astro/jsx-a11y-strict"], + }, + }) + + const result = await eslint.lintText( + `--- +const src = 'icon.png' +--- + +`, + { filePath: "path/to/test.astro" }, + ) + + assert.deepStrictEqual( + result + .flatMap((r) => r.messages) + .map((m) => { + return { + ruleId: m.ruleId, + message: m.message, + line: m.line, + column: m.column, + } + }), + [ + { + ruleId: "astro/jsx-a11y/alt-text", + message: + "img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.", + line: 4, + column: 1, + }, + ], + ) + }) + it("should work with a11y config recommended", async () => { + const eslint = new ESLint({ + plugins: { + "jsx-a11y": jsxA11yPlugin, + astro: astroPlugin, + }, + useEslintrc: false, + overrideConfig: { + extends: ["plugin:astro/jsx-a11y-recommended"], + }, + }) + + const result = await eslint.lintText( + `--- +const src = 'icon.png' +--- + +`, + { filePath: "path/to/test.astro" }, + ) + + assert.deepStrictEqual( + result + .flatMap((r) => r.messages) + .map((m) => { + return { + ruleId: m.ruleId, + message: m.message, + line: m.line, + column: m.column, + } + }), + [ + { + ruleId: "astro/jsx-a11y/alt-text", + message: + "img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.", + line: 4, + column: 1, + }, + ], + ) + }) +}) diff --git a/tools/render-rules.ts b/tools/render-rules.ts index eafb138b..45edbf1f 100644 --- a/tools/render-rules.ts +++ b/tools/render-rules.ts @@ -6,6 +6,7 @@ const categories = [ "Security Vulnerability", "Best Practices", "Stylistic Issues", + "A11Y Extension Rules", "Extension Rules", "System", ] as const @@ -19,6 +20,8 @@ const descriptions: Record = { "These rules relate to better ways of doing things to help you avoid problems:", "Stylistic Issues": "These rules relate to style guidelines, and are therefore quite subjective:", + "A11Y Extension Rules": + "These rules extend the rules provided by [eslint-plugin-jsx-a11y] to work well in Astro component: \n(You need to install [eslint-plugin-jsx-a11y] to use the rules.)", "Extension Rules": "These rules extend the rules provided by ESLint itself to work well in Astro component:", System: "These rules relate to this plugin works:", diff --git a/tools/update-docs-rules-index.ts b/tools/update-docs-rules-index.ts index 1f8d2c6e..07836e9e 100644 --- a/tools/update-docs-rules-index.ts +++ b/tools/update-docs-rules-index.ts @@ -12,5 +12,7 @@ The \`--fix\` option on the [command line](https://eslint.org/docs/user-guide/co The rules with the following star :star: are included in the \`plugin:astro/recommended\` config. -${renderRulesTableContent()}`, +${renderRulesTableContent()} +[eslint-plugin-jsx-a11y]: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y +`, ) diff --git a/tools/update-docs.ts b/tools/update-docs.ts index 725f96b9..106a46f2 100644 --- a/tools/update-docs.ts +++ b/tools/update-docs.ts @@ -53,7 +53,11 @@ class DocFile { public constructor(rule: RuleModule) { this.rule = rule this.filePath = path.join(ROOT, `${rule.meta.docs.ruleName}.md`) - this.content = fs.readFileSync(this.filePath, "utf8") + this.content = fs.existsSync(this.filePath) + ? fs.readFileSync(this.filePath, "utf8") + : ` + +` this.since = pickSince(this.content) } @@ -148,8 +152,12 @@ This rule was introduced in eslint-plugin-astro ${this.since} - [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/${ruleName}.ts) ${ extensionRule - ? ` + ? typeof extensionRule === "string" + ? ` Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/${extensionRule}) +` + : ` +Taken with ❤️ [from ${extensionRule.plugin}](${extensionRule.url}) ` : "" }` diff --git a/tools/update-jsx-a11y-keys.ts b/tools/update-jsx-a11y-keys.ts new file mode 100644 index 00000000..b3b70138 --- /dev/null +++ b/tools/update-jsx-a11y-keys.ts @@ -0,0 +1,31 @@ +import path from "path" +// @ts-expect-error -- ignore +import { rules, configs } from "eslint-plugin-jsx-a11y" +import { formatAndSave } from "./lib/utils" + +const content = `import { getPluginJsxA11y } from "./load" + +const plugin = getPluginJsxA11y() +export const a11yRuleKeys = plugin?.rules + ? Object.keys(plugin.rules).filter( + (s) => !plugin?.rules?.[s]?.meta?.deprecated, + ) + : ([ + ${Object.keys(rules) + .filter((s) => !rules[s].meta.deprecated) + .map((s) => JSON.stringify(s)) + .join(",")} +] as const) +export const a11yConfigKeys = plugin?.configs + ? Object.keys(plugin.configs) + : ([ + ${Object.keys(configs) + .map((s) => JSON.stringify(s)) + .join(",")} +] as const) +` + +const filePath = path.resolve(__dirname, "../src/a11y/keys.ts") + +// Update file. +void formatAndSave(filePath, content) diff --git a/tools/update-rules.ts b/tools/update-rules.ts index 7d723e2d..45447511 100644 --- a/tools/update-rules.ts +++ b/tools/update-rules.ts @@ -19,9 +19,11 @@ ${rules }"`, ) .join("\n")} +import { buildA11yRules } from "../a11y" export const rules = [ - ${rules.map((rule) => camelCase(rule.meta.docs.ruleName)).join(",")} + ${rules.map((rule) => camelCase(rule.meta.docs.ruleName)).join(",")}, + ...buildA11yRules() ] as RuleModule[] ` diff --git a/tools/update-rulesets.ts b/tools/update-rulesets.ts index 892700f1..ee3a1a07 100644 --- a/tools/update-rulesets.ts +++ b/tools/update-rulesets.ts @@ -17,7 +17,7 @@ const baseContent = `export = { // Enables global variables available in Astro components. node: true, "astro/astro": true, - es2022: true, + es2020: true, }, // Allows Astro components to be parsed. parser: require.resolve("astro-eslint-parser"), @@ -45,7 +45,7 @@ const baseContent = `export = { files: ["**/*.astro/*.js", "*.astro/*.js"], env: { browser: true, - es2022: true, + es2020: true, }, parserOptions: { sourceType: "module", diff --git a/tools/update.ts b/tools/update.ts index 06847339..703cf12b 100644 --- a/tools/update.ts +++ b/tools/update.ts @@ -4,3 +4,4 @@ import "./update-docs" import "./update-readme" import "./update-docs-rules-index" import "./update-types-for-node" +import "./update-jsx-a11y-keys"