eslint-plugin-astro

repository·main·Indexed 19 days ago

https://github.com/ota-meshi/eslint-plugin-astro

An ESLint plugin for Astro components (v3.1.0) that provides linting for Frontmatter, HTML templates, JSX-like expressions, client-side scripts, and directives. It includes pre-defined configurations such as base, recommended, and all, as well as accessibility rules extending eslint-plugin-jsx-a11y and security rules to prevent XSS and CSP compliance issues.

Tokens
25.6K
Snippets
79
Records
138
Agent score
63%

What's inside eslint-plugin-astro

  1. What is eslint-plugin-astro?

    main

    eslint-plugin-astro is an ESLint plugin designed specifically for Astro components. It allows you to lint various parts of an Astro file, including:

    • Frontmatter: The component script section.
    • HTML Template: The component template section.
    • JSX-like Expressions: Logic within the template.
    • Client-Side Scripts: Scripts intended for the browser.
    • Directives: Astro-specific directives.

    The plugin helps find problems and enforce a consistent code style across these different sections of an Astro component.

  2. Use the astro/jsx-a11y/anchor-ambiguous-text rule

    main

    The astro/jsx-a11y/anchor-ambiguous-text rule enforces that <a> tag values in Astro components are not exact matches for ambiguous phrases like "click here", "here", "link", "a link", or "learn more".

    This rule ensures that screen reader users, who rely on the link text for context, have sufficient information about where a link leads. This rule is a wrapper around the eslint-plugin-jsx-a11y rule specifically tailored for Astro components.

    Prerequisite: You must have eslint-plugin-jsx-a11y version v6.7.0 or higher installed to use this rule.

    /* Rule introduced in eslint-plugin-astro v0.22.0 */
  3. Understand the astro/no-prerender-export-outside-pages rule

    main

    The astro/no-prerender-export-outside-pages rule prevents you from exporting the prerender directive in Astro files that are located outside of the src/pages/ directory.

    In Astro, the export const prerender = true (or false) directive only affects page files within the pages/ directory. Exporting this value from components or layouts is ineffective and can lead to confusion. This rule helps ensure that prerender exports are only used where they actually function.

    /* eslint astro/no-prerender-export-outside-pages: "error" */
    
    /* ✓ GOOD — in src/pages/index.astro */
    export const prerender = true
    
    /* ✗ BAD — in src/components/MyComponent.astro */
    export const prerender = true
  4. Understand the `astro/no-exports-from-components` rule

    main

    The astro/no-exports-from-components rule disallows exporting values from Astro components. This is intended to prevent accidental exports that don't serve a specific Astro framework purpose.

    What is allowed:

    • Type exports: Using export type or export interface is permitted.
    • Specific framework exports: The following named exports are exceptions and are allowed:
      • getStaticPaths: Used for dynamic routing.
      • partial: Used to dynamically update sections of a page.
      • prerender: Used to opt-in to pre-rendering in server mode.

    What is disallowed:

    • Any other value exports (e.g., export const x = 42).

    This rule is included in the recommended configuration by default.

    ---
    /* eslint astro/no-exports-from-components: "error" */
    
    /* ✓ GOOD */
    export type A = number | boolean
    export const getStaticPaths = () => {
      // logic here
    }
    export const prerender = true;
    
    /* ✗ BAD */
    export const x = 42
    ---
  5. Understand ESLint rule symbols

    main

    When browsing the available rules, you will see specific symbols indicating the rule's capabilities:

    • Recommended: These rules are included in the recommended configuration.
    • 🔧 Auto-fixable: These rules can be automatically fixed using the --fix option on the ESLint command line.
  6. Understand the versioning policy for eslint-plugin-astro

    main

    The plugin follows Semantic Versioning, but it does not follow ESLint's specific Semantic Versioning Policy.

    Because the plugin is in an experimental stage and frequently adds new features, minor version releases may change sharable configs or the default behavior of rules. This means a minor update might report more linting errors than the previous version.

    Recommendation: To ensure build stability and prevent unexpected linting errors during CI/CD, use the tilde (~) operator in your package.json to lock your dependency to a specific minor version.

  7. Understand the purpose of anchor-is-valid

    main

    The rule is based on the principle that the HTML <a> element with a valid href attribute is formally defined as a hyperlink (navigating between documents or locations).

    In modern web development, anchors are often misused to trigger JavaScript actions instead of navigation. While it is possible to make an anchor behave like a button using ARIA, it is a best practice to use native HTML elements (like <button>) for non-navigational interactions to ensure compatibility with screen readers and browser expectations.

  8. How to use A11Y extension rules in Astro

    main

    The plugin provides A11Y (Accessibility) rules that extend eslint-plugin-jsx-a11y to work with Astro components.

    Requirement: You must install eslint-plugin-jsx-a11y as a peer dependency to use these rules.

    Available rules include:

    • astro/jsx-a11y/alt-text
    • astro/jsx-a11y/anchor-is-valid
    • astro/jsx-a11y/aria-props
    • astro/jsx-a11y/label-has-associated-control
    • (and many others covering roles, focus, and interactive elements)
    | 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-ambiguous-text](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/anchor-ambiguous-text/) | apply `jsx-a11y/anchor-ambiguous-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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/jsx-a11y/no-access-key` rule to Astro components |
    | [astro/jsx-a11y/no-aria-hidden-on-focusable](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-aria-hidden-on-focusable/) | apply `astro/jsx-a11y/no-aria-hidden-on-focusable` rule to Astro components |
    | [astro/jsx-a11y/no-autofocus](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-autofocus/) | apply `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/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 `astro/jsx-a11y/no-static-element-interactions` rule to Astro components |
    | [astro/jsx-a11y/prefer-tag-over-role](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/prefer-tag-over-role/) | apply `astro/jsx-a11y/prefer-tag-over-role` 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 `astro/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 `astro/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 `astro/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 `astro/jsx-a11y/tabindex-no-positive` rule to Astro components |
  9. Versioning policy for eslint-plugin-astro

    main

    This plugin follows Semantic Versioning, but with a key difference from ESLint's policy:

    Minor updates may introduce new linting errors. This is because minor releases may change sharable configs or the default behavior of rules to support new Astro features.

    To ensure build stability and prevent unexpected linting failures in CI, it is recommended to use the tilde (~) version specifier in your package.json.

  10. Understand the astro/no-set-html-directive rule

    main

    The astro/no-set-html-directive rule disallows the use of the set:html directive in Astro components. This is a security measure designed to prevent Cross-Site Scripting (XSS) attacks by reducing the risk of injecting unescaped or unsafe HTML directly into the browser.

    To follow best practices, use standard interpolation or the set:text directive instead of set:html whenever possible.

    ---
    /* eslint astro/no-set-html-directive: "error" */
    ---
    
    {/* ✓ GOOD: Standard interpolation or set:text */}
    <p>{foo}</p>
    <p set:text={foo} />
    
    {/* ✗ BAD: Using set:html is unsafe */}
    <p set:html={foo} />