diff --git a/src/index.js b/src/index.js index 980081e..3cf8018 100644 --- a/src/index.js +++ b/src/index.js @@ -1,48 +1,90 @@ /* eslint-disable global-require */ -const flatConfigBase = require('./configs/flat-config-base'); -const legacyConfigBase = require('./configs/legacy-config-base'); -const { name, version } = require('../package.json'); +import flatConfigBase from './configs/flat-config-base'; +import legacyConfigBase from './configs/legacy-config-base'; +import { name, version } from '../package.json'; + +import accessibleEmoji from './rules/accessible-emoji'; +import altText from './rules/alt-text'; +import anchorAmbiguousText from './rules/anchor-ambiguous-text'; +import anchorHasContent from './rules/anchor-has-content'; +import anchorIsValid from './rules/anchor-is-valid'; +import ariaActivedescendantHasTabindex from './rules/aria-activedescendant-has-tabindex'; +import ariaProps from './rules/aria-props'; +import ariaProptypes from './rules/aria-proptypes'; +import ariaRole from './rules/aria-role'; +import ariaUnsupportedElements from './rules/aria-unsupported-elements'; +import autocompleteValid from './rules/autocomplete-valid'; +import clickEventsHaveKeyEvents from './rules/click-events-have-key-events'; +import controlHasAssociatedLabel from './rules/control-has-associated-label'; +import headingHasContent from './rules/heading-has-content'; +import htmlHasLang from './rules/html-has-lang'; +import iframeHasTitle from './rules/iframe-has-title'; +import imgRedundantAlt from './rules/img-redundant-alt'; +import interactiveSupportsFocus from './rules/interactive-supports-focus'; +import labelHasAssociatedControl from './rules/label-has-associated-control'; +import labelHasFor from './rules/label-has-for'; +import lang from './rules/lang'; +import mediaHasCaption from './rules/media-has-caption'; +import mouseEventsHaveKeyEvents from './rules/mouse-events-have-key-events'; +import noAriaHiddenOnFocusable from './rules/no-aria-hidden-on-focusable'; +import noAccessKey from './rules/no-access-key'; +import noAutofocus from './rules/no-autofocus'; +import noDistractingElements from './rules/no-distracting-elements'; +import noInteractiveElementToNoninteractiveRole from './rules/no-interactive-element-to-noninteractive-role'; +import noNoninteractiveElementInteractions from './rules/no-noninteractive-element-interactions'; +import noNoninteractiveElementToInteractiveRole from './rules/no-noninteractive-element-to-interactive-role'; +import noNoninteractiveTabindex from './rules/no-noninteractive-tabindex'; +import noOnChange from './rules/no-onchange'; +import noRedundantRoles from './rules/no-redundant-roles'; +import noStaticElementInteractions from './rules/no-static-element-interactions'; +import preferTagOverRole from './rules/prefer-tag-over-role'; +import roleHasRequiredAriaProps from './rules/role-has-required-aria-props'; +import roleSupportsAriaProps from './rules/role-supports-aria-props'; +import scope from './rules/scope'; +import tabindexNoPositive from './rules/tabindex-no-positive'; const allRules = { - 'accessible-emoji': require('./rules/accessible-emoji'), - 'alt-text': require('./rules/alt-text'), - 'anchor-ambiguous-text': require('./rules/anchor-ambiguous-text'), - 'anchor-has-content': require('./rules/anchor-has-content'), - 'anchor-is-valid': require('./rules/anchor-is-valid'), - 'aria-activedescendant-has-tabindex': require('./rules/aria-activedescendant-has-tabindex'), - 'aria-props': require('./rules/aria-props'), - 'aria-proptypes': require('./rules/aria-proptypes'), - 'aria-role': require('./rules/aria-role'), - 'aria-unsupported-elements': require('./rules/aria-unsupported-elements'), - 'autocomplete-valid': require('./rules/autocomplete-valid'), - 'click-events-have-key-events': require('./rules/click-events-have-key-events'), - 'control-has-associated-label': require('./rules/control-has-associated-label'), - 'heading-has-content': require('./rules/heading-has-content'), - 'html-has-lang': require('./rules/html-has-lang'), - 'iframe-has-title': require('./rules/iframe-has-title'), - 'img-redundant-alt': require('./rules/img-redundant-alt'), - 'interactive-supports-focus': require('./rules/interactive-supports-focus'), - 'label-has-associated-control': require('./rules/label-has-associated-control'), - 'label-has-for': require('./rules/label-has-for'), - lang: require('./rules/lang'), - 'media-has-caption': require('./rules/media-has-caption'), - 'mouse-events-have-key-events': require('./rules/mouse-events-have-key-events'), - 'no-access-key': require('./rules/no-access-key'), - 'no-aria-hidden-on-focusable': require('./rules/no-aria-hidden-on-focusable'), - 'no-autofocus': require('./rules/no-autofocus'), - 'no-distracting-elements': require('./rules/no-distracting-elements'), - 'no-interactive-element-to-noninteractive-role': require('./rules/no-interactive-element-to-noninteractive-role'), - 'no-noninteractive-element-interactions': require('./rules/no-noninteractive-element-interactions'), - 'no-noninteractive-element-to-interactive-role': require('./rules/no-noninteractive-element-to-interactive-role'), - 'no-noninteractive-tabindex': require('./rules/no-noninteractive-tabindex'), - 'no-onchange': require('./rules/no-onchange'), - 'no-redundant-roles': require('./rules/no-redundant-roles'), - 'no-static-element-interactions': require('./rules/no-static-element-interactions'), - 'prefer-tag-over-role': require('./rules/prefer-tag-over-role'), - 'role-has-required-aria-props': require('./rules/role-has-required-aria-props'), - 'role-supports-aria-props': require('./rules/role-supports-aria-props'), - scope: require('./rules/scope'), - 'tabindex-no-positive': require('./rules/tabindex-no-positive'), + 'accessible-emoji': accessibleEmoji, + 'alt-text': altText, + 'anchor-ambiguous-text': anchorAmbiguousText, + 'anchor-has-content': anchorHasContent, + 'anchor-is-valid': anchorIsValid, + 'aria-activedescendant-has-tabindex': ariaActivedescendantHasTabindex, + 'aria-props': ariaProps, + 'aria-proptypes': ariaProptypes, + 'aria-role': ariaRole, + 'aria-unsupported-elements': ariaUnsupportedElements, + 'autocomplete-valid': autocompleteValid, + 'click-events-have-key-events': clickEventsHaveKeyEvents, + 'control-has-associated-label': controlHasAssociatedLabel, + 'heading-has-content': headingHasContent, + 'html-has-lang': htmlHasLang, + 'iframe-has-title': iframeHasTitle, + 'img-redundant-alt': imgRedundantAlt, + 'interactive-supports-focus': interactiveSupportsFocus, + 'label-has-associated-control': labelHasAssociatedControl, + 'label-has-for': labelHasFor, + lang, + 'media-has-caption': mediaHasCaption, + 'mouse-events-have-key-events': mouseEventsHaveKeyEvents, + 'no-access-key': noAccessKey, + 'no-aria-hidden-on-focusable': noAriaHiddenOnFocusable, + 'no-autofocus': noAutofocus, + 'no-distracting-elements': noDistractingElements, + 'no-interactive-element-to-noninteractive-role': + noInteractiveElementToNoninteractiveRole, + 'no-noninteractive-element-interactions': noNoninteractiveElementInteractions, + 'no-noninteractive-element-to-interactive-role': + noNoninteractiveElementToInteractiveRole, + 'no-noninteractive-tabindex': noNoninteractiveTabindex, + 'no-onchange': noOnChange, + 'no-redundant-roles': noRedundantRoles, + 'no-static-element-interactions': noStaticElementInteractions, + 'prefer-tag-over-role': preferTagOverRole, + 'role-has-required-aria-props': roleHasRequiredAriaProps, + 'role-supports-aria-props': roleSupportsAriaProps, + scope, + 'tabindex-no-positive': tabindexNoPositive, }; const recommendedRules = { @@ -294,15 +336,15 @@ const jsxA11y = { * Given a ruleset and optionally a flat config name, generate a config. * @param {object} rules - ruleset for this config * @param {string} flatConfigName - name for the config if flat - * @returns Config for this set of rules. + * @returns {import('eslint').Linter.Config} Config for this set of rules. */ const createConfig = (rules, flatConfigName) => ({ ...(flatConfigName ? { - ...flatConfigBase, - name: `jsx-a11y/${flatConfigName}`, - plugins: { 'jsx-a11y': jsxA11y }, - } + ...flatConfigBase, + name: `jsx-a11y/${flatConfigName}`, + plugins: { 'jsx-a11y': jsxA11y }, + } : { ...legacyConfigBase, plugins: ['jsx-a11y'] }), rules: { ...rules }, }); @@ -317,4 +359,4 @@ const flatConfigs = { strict: createConfig(strictRules, 'strict'), }; -module.exports = Object.assign(jsxA11y, { configs, flatConfigs }); +export default { ...jsxA11y, configs, flatConfigs }; diff --git a/src/rules/autocomplete-valid.js b/src/rules/autocomplete-valid.js index df7b6b8..c4d0da1 100644 --- a/src/rules/autocomplete-valid.js +++ b/src/rules/autocomplete-valid.js @@ -6,7 +6,7 @@ // ---------------------------------------------------------------------------- // Rule Definition // ---------------------------------------------------------------------------- -import { runVirtualRule } from 'axe-core'; +import axe from 'axe-core'; import { getLiteralPropValue, getProp } from 'jsx-ast-utils'; import { generateObjSchema, arraySchema } from '../util/schemas'; import getElementType from '../util/getElementType'; @@ -24,23 +24,25 @@ export default { schema: [schema], }, - create: (context) => { + create: context => { const elementType = getElementType(context); return { - JSXOpeningElement: (node) => { + JSXOpeningElement: node => { const options = context.options[0] || {}; const { inputComponents = [] } = options; const inputTypes = ['input'].concat(inputComponents); const elType = elementType(node); - const autocomplete = getLiteralPropValue(getProp(node.attributes, 'autocomplete')); + const autocomplete = getLiteralPropValue( + getProp(node.attributes, 'autocomplete'), + ); if (typeof autocomplete !== 'string' || !inputTypes.includes(elType)) { return; } const type = getLiteralPropValue(getProp(node.attributes, 'type')); - const { violations } = runVirtualRule('autocomplete-valid', { + const { violations } = axe.runVirtualRule('autocomplete-valid', { nodeName: 'input', attributes: { autocomplete, diff --git a/src/rules/label-has-associated-control.js b/src/rules/label-has-associated-control.js index d65abe9..22ecee7 100644 --- a/src/rules/label-has-associated-control.js +++ b/src/rules/label-has-associated-control.js @@ -11,7 +11,7 @@ import { hasProp, getProp, getPropValue } from 'jsx-ast-utils'; import type { JSXElement } from 'ast-types-flow'; -import minimatch from 'minimatch'; +import { minimatch } from 'minimatch'; import { generateObjSchema, arraySchema } from '../util/schemas'; import type { ESLintConfig, ESLintContext, ESLintVisitorSelectorConfig } from '../../flow/eslint'; import getElementType from '../util/getElementType'; diff --git a/src/util/mayContainChildComponent.js b/src/util/mayContainChildComponent.js index 65000a0..09b199a 100644 --- a/src/util/mayContainChildComponent.js +++ b/src/util/mayContainChildComponent.js @@ -9,7 +9,7 @@ import type { JSXOpeningElement, Node } from 'ast-types-flow'; import { elementType as rawElementType } from 'jsx-ast-utils'; -import minimatch from 'minimatch'; +import { minimatch } from 'minimatch'; export default function mayContainChildComponent( root: Node, diff --git a/src/util/mayHaveAccessibleLabel.js b/src/util/mayHaveAccessibleLabel.js index 186ef5e..3dd7d4d 100644 --- a/src/util/mayHaveAccessibleLabel.js +++ b/src/util/mayHaveAccessibleLabel.js @@ -11,7 +11,7 @@ import includes from 'array-includes'; import { getPropValue, propName, elementType as rawElementType } from 'jsx-ast-utils'; import type { JSXOpeningElement, Node } from 'ast-types-flow'; -import minimatch from 'minimatch'; +import { minimatch } from 'minimatch'; function tryTrim(value: any) { return typeof value === 'string' ? value.trim() : value;