11import { createRequire } from "node:module" ;
2- import type { Framework } from "./types.js" ;
2+ import type { AccessibilityPreset , Framework } from "./types.js" ;
33
44const esmRequire = createRequire ( import . meta. url ) ;
55
6+ // Minimal preset: The original curated set of high-impact rules
7+ const A11Y_RULES_MINIMAL : Record < string , string > = {
8+ "jsx-a11y/alt-text" : "error" ,
9+ "jsx-a11y/anchor-is-valid" : "warn" ,
10+ "jsx-a11y/click-events-have-key-events" : "warn" ,
11+ "jsx-a11y/no-static-element-interactions" : "warn" ,
12+ "jsx-a11y/no-noninteractive-element-interactions" : "warn" ,
13+ "jsx-a11y/role-has-required-aria-props" : "error" ,
14+ "jsx-a11y/no-autofocus" : "warn" ,
15+ "jsx-a11y/heading-has-content" : "warn" ,
16+ "jsx-a11y/html-has-lang" : "warn" ,
17+ "jsx-a11y/no-redundant-roles" : "warn" ,
18+ "jsx-a11y/scope" : "warn" ,
19+ "jsx-a11y/tabindex-no-positive" : "warn" ,
20+ "jsx-a11y/label-has-associated-control" : "warn" ,
21+ "jsx-a11y/no-distracting-elements" : "error" ,
22+ "jsx-a11y/iframe-has-title" : "warn" ,
23+ } ;
24+
25+ // Recommended preset: All jsx-a11y recommended rules
26+ const A11Y_RULES_RECOMMENDED : Record < string , string > = {
27+ ...A11Y_RULES_MINIMAL ,
28+ "jsx-a11y/anchor-has-content" : "warn" ,
29+ "jsx-a11y/aria-activedescendant-has-tabindex" : "warn" ,
30+ "jsx-a11y/aria-props" : "warn" ,
31+ "jsx-a11y/aria-proptypes" : "warn" ,
32+ "jsx-a11y/aria-role" : "warn" ,
33+ "jsx-a11y/aria-unsupported-elements" : "warn" ,
34+ "jsx-a11y/autocomplete-valid" : "warn" ,
35+ "jsx-a11y/img-redundant-alt" : "warn" ,
36+ "jsx-a11y/interactive-supports-focus" : "warn" ,
37+ "jsx-a11y/media-has-caption" : "warn" ,
38+ "jsx-a11y/mouse-events-have-key-events" : "warn" ,
39+ "jsx-a11y/no-access-key" : "warn" ,
40+ "jsx-a11y/no-interactive-element-to-noninteractive-role" : "warn" ,
41+ "jsx-a11y/no-noninteractive-element-to-interactive-role" : "warn" ,
42+ "jsx-a11y/no-noninteractive-tabindex" : "warn" ,
43+ "jsx-a11y/role-supports-aria-props" : "warn" ,
44+ } ;
45+
46+ // Strict preset: All recommended rules plus strict-only rules, with errors instead of warnings
47+ const A11Y_RULES_STRICT : Record < string , string > = {
48+ ...Object . fromEntries ( Object . entries ( A11Y_RULES_RECOMMENDED ) . map ( ( [ rule ] ) => [ rule , "error" ] ) ) ,
49+ "jsx-a11y/anchor-ambiguous-text" : "error" ,
50+ "jsx-a11y/control-has-associated-label" : "error" ,
51+ } ;
52+
53+ const getAccessibilityRules = ( preset : AccessibilityPreset | false ) : Record < string , string > => {
54+ switch ( preset ) {
55+ case false :
56+ return { } ;
57+ case "minimal" :
58+ return A11Y_RULES_MINIMAL ;
59+ case "recommended" :
60+ return A11Y_RULES_RECOMMENDED ;
61+ case "strict" :
62+ return A11Y_RULES_STRICT ;
63+ default :
64+ return A11Y_RULES_MINIMAL ;
65+ }
66+ } ;
67+
668const NEXTJS_RULES : Record < string , string > = {
769 "react-doctor/nextjs-no-img-element" : "warn" ,
870 "react-doctor/nextjs-async-client-component" : "error" ,
@@ -45,12 +107,14 @@ interface OxlintConfigOptions {
45107 pluginPath : string ;
46108 framework : Framework ;
47109 hasReactCompiler : boolean ;
110+ accessibilityPreset : AccessibilityPreset | false ;
48111}
49112
50113export const createOxlintConfig = ( {
51114 pluginPath,
52115 framework,
53116 hasReactCompiler,
117+ accessibilityPreset,
54118} : OxlintConfigOptions ) => ( {
55119 categories : {
56120 correctness : "off" ,
@@ -61,7 +125,11 @@ export const createOxlintConfig = ({
61125 style : "off" ,
62126 nursery : "off" ,
63127 } ,
64- plugins : [ "react" , "jsx-a11y" , ...( hasReactCompiler ? [ ] : [ "react-perf" ] ) ] ,
128+ plugins : [
129+ "react" ,
130+ ...( accessibilityPreset !== false ? [ "jsx-a11y" ] : [ ] ) ,
131+ ...( hasReactCompiler ? [ ] : [ "react-perf" ] ) ,
132+ ] ,
65133 jsPlugins : [
66134 ...( hasReactCompiler
67135 ? [ { name : "react-hooks-js" , specifier : esmRequire . resolve ( "eslint-plugin-react-hooks" ) } ]
@@ -82,21 +150,7 @@ export const createOxlintConfig = ({
82150 "react/require-render-return" : "error" ,
83151 "react/no-unknown-property" : "warn" ,
84152
85- "jsx-a11y/alt-text" : "error" ,
86- "jsx-a11y/anchor-is-valid" : "warn" ,
87- "jsx-a11y/click-events-have-key-events" : "warn" ,
88- "jsx-a11y/no-static-element-interactions" : "warn" ,
89- "jsx-a11y/no-noninteractive-element-interactions" : "warn" ,
90- "jsx-a11y/role-has-required-aria-props" : "error" ,
91- "jsx-a11y/no-autofocus" : "warn" ,
92- "jsx-a11y/heading-has-content" : "warn" ,
93- "jsx-a11y/html-has-lang" : "warn" ,
94- "jsx-a11y/no-redundant-roles" : "warn" ,
95- "jsx-a11y/scope" : "warn" ,
96- "jsx-a11y/tabindex-no-positive" : "warn" ,
97- "jsx-a11y/label-has-associated-control" : "warn" ,
98- "jsx-a11y/no-distracting-elements" : "error" ,
99- "jsx-a11y/iframe-has-title" : "warn" ,
153+ ...getAccessibilityRules ( accessibilityPreset ) ,
100154
101155 ...( hasReactCompiler ? REACT_COMPILER_RULES : { } ) ,
102156
0 commit comments