@@ -3,7 +3,9 @@ const baseStyleRules = require('eslint-config-airbnb-base/rules/style').rules;
33const dangleRules = baseStyleRules [ 'no-underscore-dangle' ] ;
44
55module . exports = {
6- plugins : [ 'react' ] ,
6+ extends : [ require . resolve ( 'eslint-config-airbnb-base' ) ] ,
7+
8+ plugins : [ 'jsx-a11y' , 'react' , 'react-hooks' ] ,
79
810 parserOptions : {
911 ecmaFeatures : {
@@ -588,6 +590,268 @@ module.exports = {
588590 unnamedComponents : 'function-expression' ,
589591 } ,
590592 ] ,
593+
594+ // a11y rules
595+
596+ // Enforce that anchors have content
597+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-has-content.md
598+ 'jsx-a11y/anchor-has-content' : [ 'error' , { components : [ ] } ] ,
599+
600+ // Require ARIA roles to be valid and non-abstract
601+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-role.md
602+ 'jsx-a11y/aria-role' : [ 'error' , { ignoreNonDOM : false } ] ,
603+
604+ // Enforce all aria-* props are valid.
605+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-props.md
606+ 'jsx-a11y/aria-props' : 'error' ,
607+
608+ // Enforce ARIA state and property values are valid.
609+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-proptypes.md
610+ 'jsx-a11y/aria-proptypes' : 'error' ,
611+
612+ // Enforce that elements that do not support ARIA roles, states, and
613+ // properties do not have those attributes.
614+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-unsupported-elements.md
615+ 'jsx-a11y/aria-unsupported-elements' : 'error' ,
616+
617+ // Enforce that all elements that require alternative text have meaningful information
618+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/alt-text.md
619+ 'jsx-a11y/alt-text' : [
620+ 'error' ,
621+ {
622+ elements : [ 'img' , 'object' , 'area' , 'input[type="image"]' ] ,
623+ img : [ ] ,
624+ object : [ ] ,
625+ area : [ ] ,
626+ 'input[type="image"]' : [ ] ,
627+ } ,
628+ ] ,
629+
630+ // Prevent img alt text from containing redundant words like "image", "picture", or "photo"
631+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-redundant-alt.md
632+ 'jsx-a11y/img-redundant-alt' : 'error' ,
633+
634+ // require that JSX labels use "htmlFor"
635+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/label-has-for.md
636+ // deprecated: replaced by `label-has-associated-control` rule
637+ 'jsx-a11y/label-has-for' : [
638+ 'off' ,
639+ {
640+ components : [ ] ,
641+ required : {
642+ every : [ 'nesting' , 'id' ] ,
643+ } ,
644+ allowChildren : false ,
645+ } ,
646+ ] ,
647+
648+ // Enforce that a label tag has a text label and an associated control.
649+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/b800f40a2a69ad48015ae9226fbe879f946757ed/docs/rules/label-has-associated-control.md
650+ 'jsx-a11y/label-has-associated-control' : [
651+ 'error' ,
652+ {
653+ labelComponents : [ ] ,
654+ labelAttributes : [ ] ,
655+ controlComponents : [ ] ,
656+ assert : 'both' ,
657+ depth : 25 ,
658+ } ,
659+ ] ,
660+
661+ // Enforce that a control (an interactive element) has a text label.
662+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/control-has-associated-label.md
663+ 'jsx-a11y/control-has-associated-label' : [
664+ 'error' ,
665+ {
666+ labelAttributes : [ 'label' ] ,
667+ controlComponents : [ ] ,
668+ ignoreElements : [ 'audio' , 'canvas' , 'embed' , 'input' , 'textarea' , 'tr' , 'video' ] ,
669+ ignoreRoles : [
670+ 'grid' ,
671+ 'listbox' ,
672+ 'menu' ,
673+ 'menubar' ,
674+ 'radiogroup' ,
675+ 'row' ,
676+ 'tablist' ,
677+ 'toolbar' ,
678+ 'tree' ,
679+ 'treegrid' ,
680+ ] ,
681+ depth : 5 ,
682+ } ,
683+ ] ,
684+
685+ // require that mouseover/out come with focus/blur, for keyboard-only users
686+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/mouse-events-have-key-events.md
687+ 'jsx-a11y/mouse-events-have-key-events' : 'error' ,
688+
689+ // Prevent use of `accessKey`
690+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md
691+ 'jsx-a11y/no-access-key' : 'error' ,
692+
693+ // require onBlur instead of onChange
694+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-onchange.md
695+ 'jsx-a11y/no-onchange' : 'off' ,
696+
697+ // Elements with an interactive role and interaction handlers must be focusable
698+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/interactive-supports-focus.md
699+ 'jsx-a11y/interactive-supports-focus' : 'error' ,
700+
701+ // Enforce that elements with ARIA roles must have all required attributes
702+ // for that role.
703+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/role-has-required-aria-props.md
704+ 'jsx-a11y/role-has-required-aria-props' : 'error' ,
705+
706+ // Enforce that elements with explicit or implicit roles defined contain
707+ // only aria-* properties supported by that role.
708+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/role-supports-aria-props.md
709+ 'jsx-a11y/role-supports-aria-props' : 'error' ,
710+
711+ // Enforce tabIndex value is not greater than zero.
712+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/tabindex-no-positive.md
713+ 'jsx-a11y/tabindex-no-positive' : 'error' ,
714+
715+ // ensure <hX> tags have content and are not aria-hidden
716+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/heading-has-content.md
717+ 'jsx-a11y/heading-has-content' : [ 'error' , { components : [ '' ] } ] ,
718+
719+ // require HTML elements to have a "lang" prop
720+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/html-has-lang.md
721+ 'jsx-a11y/html-has-lang' : 'error' ,
722+
723+ // require HTML element's lang prop to be valid
724+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/lang.md
725+ 'jsx-a11y/lang' : 'error' ,
726+
727+ // prevent distracting elements, like <marquee> and <blink>
728+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-distracting-elements.md
729+ 'jsx-a11y/no-distracting-elements' : [
730+ 'error' ,
731+ {
732+ elements : [ 'marquee' , 'blink' ] ,
733+ } ,
734+ ] ,
735+
736+ // only allow <th> to have the "scope" attr
737+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/scope.md
738+ 'jsx-a11y/scope' : 'error' ,
739+
740+ // require onClick be accompanied by onKeyUp/onKeyDown/onKeyPress
741+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/click-events-have-key-events.md
742+ 'jsx-a11y/click-events-have-key-events' : 'error' ,
743+
744+ // Enforce that DOM elements without semantic behavior not have interaction handlers
745+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-static-element-interactions.md
746+ 'jsx-a11y/no-static-element-interactions' : [
747+ 'error' ,
748+ {
749+ handlers : [ 'onClick' , 'onMouseDown' , 'onMouseUp' , 'onKeyPress' , 'onKeyDown' , 'onKeyUp' ] ,
750+ } ,
751+ ] ,
752+
753+ // A non-interactive element does not support event handlers (mouse and key handlers)
754+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-element-interactions.md
755+ 'jsx-a11y/no-noninteractive-element-interactions' : [
756+ 'error' ,
757+ {
758+ handlers : [ 'onClick' , 'onMouseDown' , 'onMouseUp' , 'onKeyPress' , 'onKeyDown' , 'onKeyUp' ] ,
759+ } ,
760+ ] ,
761+
762+ // ensure emoji are accessible
763+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/accessible-emoji.md
764+ // disabled; rule is deprecated
765+ 'jsx-a11y/accessible-emoji' : 'off' ,
766+
767+ // elements with aria-activedescendant must be tabbable
768+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-activedescendant-has-tabindex.md
769+ 'jsx-a11y/aria-activedescendant-has-tabindex' : 'error' ,
770+
771+ // ensure iframe elements have a unique title
772+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/iframe-has-title.md
773+ 'jsx-a11y/iframe-has-title' : 'error' ,
774+
775+ // prohibit autoFocus prop
776+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-autofocus.md
777+ 'jsx-a11y/no-autofocus' : [ 'error' , { ignoreNonDOM : true } ] ,
778+
779+ // ensure HTML elements do not specify redundant ARIA roles
780+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-redundant-roles.md
781+ 'jsx-a11y/no-redundant-roles' : 'error' ,
782+
783+ // media elements must have captions
784+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/media-has-caption.md
785+ 'jsx-a11y/media-has-caption' : [
786+ 'error' ,
787+ {
788+ audio : [ ] ,
789+ video : [ ] ,
790+ track : [ ] ,
791+ } ,
792+ ] ,
793+
794+ // WAI-ARIA roles should not be used to convert an interactive element to non-interactive
795+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-interactive-element-to-noninteractive-role.md
796+ 'jsx-a11y/no-interactive-element-to-noninteractive-role' : [
797+ 'error' ,
798+ {
799+ tr : [ 'none' , 'presentation' ] ,
800+ } ,
801+ ] ,
802+
803+ // WAI-ARIA roles should not be used to convert a non-interactive element to interactive
804+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-element-to-interactive-role.md
805+ 'jsx-a11y/no-noninteractive-element-to-interactive-role' : [
806+ 'error' ,
807+ {
808+ ul : [ 'listbox' , 'menu' , 'menubar' , 'radiogroup' , 'tablist' , 'tree' , 'treegrid' ] ,
809+ ol : [ 'listbox' , 'menu' , 'menubar' , 'radiogroup' , 'tablist' , 'tree' , 'treegrid' ] ,
810+ li : [ 'menuitem' , 'option' , 'row' , 'tab' , 'treeitem' ] ,
811+ table : [ 'grid' ] ,
812+ td : [ 'gridcell' ] ,
813+ } ,
814+ ] ,
815+
816+ // Tab key navigation should be limited to elements on the page that can be interacted with.
817+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-tabindex.md
818+ 'jsx-a11y/no-noninteractive-tabindex' : [
819+ 'error' ,
820+ {
821+ tags : [ ] ,
822+ roles : [ 'tabpanel' ] ,
823+ } ,
824+ ] ,
825+
826+ // ensure <a> tags are valid
827+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/0745af376cdc8686d85a361ce36952b1fb1ccf6e/docs/rules/anchor-is-valid.md
828+ 'jsx-a11y/anchor-is-valid' : [
829+ 'error' ,
830+ {
831+ components : [ 'Link' ] ,
832+ specialLink : [ 'to' ] ,
833+ aspects : [ 'noHref' , 'invalidHref' , 'preferButton' ] ,
834+ } ,
835+ ] ,
836+
837+ // Ensure the autocomplete attribute is correct and suitable for the form field it is used with
838+ // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/29c68596b15c4ff0a40daae6d4a2670e36e37d35/docs/rules/autocomplete-valid.md
839+ 'jsx-a11y/autocomplete-valid' : [
840+ 'off' ,
841+ {
842+ inputComponents : [ ] ,
843+ } ,
844+ ] ,
845+
846+ // hooks rules
847+
848+ // Enforce Rules of Hooks
849+ // https://github.com/facebook/react/blob/c11015ff4f610ac2924d1fc6d569a17657a404fd/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js
850+ 'react-hooks/rules-of-hooks' : 'error' ,
851+
852+ // Verify the list of the dependencies for Hooks like useEffect and similar
853+ // https://github.com/facebook/react/blob/1204c789776cb01fbaf3e9f032e7e2ba85a44137/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
854+ 'react-hooks/exhaustive-deps' : 'error' ,
591855 } ,
592856
593857 settings : {
0 commit comments