Skip to content

Commit d5c4ce8

Browse files
connorsheaCopilot
andauthored
docs(linter): Add config option docs for 7 rules. (#15209)
Part of #14743. - eslint/no-self-assign - jest/prefer-lowercase-title - jsx-a11y/label-has-associated-control - jsx-a11y/media-has-caption - jsx-a11y/no-noninteractive-tabindex - promise/spec-only - typescript/consistent-generic-constructors For `jsx-a11y/no-noninteractive-tabindex`, this required changing the way this is implemented slightly so we properly derive the default value, otherwise the JsonSchema derivation complained. Generated docs: ```md ## Configuration This rule accepts a configuration object with the following properties: ### props type: `boolean` default: `true` The `props` option when set to `false`, disables the checking of properties. With `props` set to `false` the following are examples of correct code: \```javascript obj.a = obj.a; obj.a.b = obj.a.b; obj["a"] = obj["a"]; obj[a] = obj[a]; \``` ``` ```md ## Configuration This rule accepts a configuration object with the following properties: ### option default: `"constructor"` Specifies where the generic type should be specified. Possible values: - `"constructor"` (default):Type arguments that only appear on the type annotation are disallowed. - `"type-annotation"`: Type arguments that only appear on the constructor are disallowed. ``` ```md ## Configuration This rule accepts a configuration object with the following properties: ### allowedPrefixes type: `string[]` default: `[]` This array option allows specifying prefixes, which contain capitals that titles can start with. This can be useful when writing tests for API endpoints, where you'd like to prefix with the HTTP method. By default, nothing is allowed (the equivalent of `{ "allowedPrefixes": [] }`). Example of **correct** code for the `{ "allowedPrefixes": ["GET"] }` option: \```js /* eslint jest/prefer-lowercase-title: ["error", { "allowedPrefixes": ["GET"] }] */ describe('GET /live'); \``` ### ignore type: `string[]` default: `[]` This array option controls which Jest or Vitest functions are checked by this rule. There are four possible values: - `"describe"` - `"test"` - `"it"` - `"bench"` By default, none of these options are enabled (the equivalent of `{ "ignore": [] }`). Example of **correct** code for the `{ "ignore": ["describe"] }` option: \```js /* eslint jest/prefer-lowercase-title: ["error", { "ignore": ["describe"] }] */ describe('Uppercase description'); \``` Example of **correct** code for the `{ "ignore": ["test"] }` option: \```js /* eslint jest/prefer-lowercase-title: ["error", { "ignore": ["test"] }] */ test('Uppercase description'); \``` Example of **correct** code for the `{ "ignore": ["it"] }` option: \```js /* eslint jest/prefer-lowercase-title: ["error", { "ignore": ["it"] }] */ it('Uppercase description'); \``` ### ignoreTopLevelDescribe type: `boolean` default: `false` This option can be set to allow only the top-level `describe` blocks to have a title starting with an upper-case letter. Example of **correct** code for the `{ "ignoreTopLevelDescribe": true }` option: \```js /* eslint jest/prefer-lowercase-title: ["error", { "ignoreTopLevelDescribe": true }] */ describe('MyClass', () => { describe('#myMethod', () => { it('does things', () => { // }); }); }); \``` ### lowercaseFirstCharacterOnly type: `boolean` default: `true` This option can be set to only validate that the first character of a test name is lowercased. Example of **correct** code for the `{ "lowercaseFirstCharacterOnly": true }` option: \```js /* eslint vitest/prefer-lowercase-title: ["error", { "lowercaseFirstCharacterOnly": true }] */ describe('myClass', () => { describe('myMethod', () => { it('does things', () => { // }); }); }); \``` Example of **incorrect** code for the `{ "lowercaseFirstCharacterOnly": true }` option: \```js /* eslint vitest/prefer-lowercase-title: ["error", { "lowercaseFirstCharacterOnly": true }] */ describe('MyClass', () => { describe('MyMethod', () => { it('does things', () => { // }); }); }); \``` ``` ```md ## Configuration This rule accepts a configuration object with the following properties: ### audio type: `string[]` default: `["audio"]` Element names to treat as `<audio>` elements ### track type: `string[]` default: `["track"]` Element names to treat as `<track>` elements ### video type: `string[]` default: `["video"]` Element names to treat as `<video>` elements ``` ```md ## Configuration This rule accepts a configuration object with the following properties: ### assert type: `"html-for" | "nesting" | "both" | "either"` default: `"either"` The type of association required between the label and the control. ### controlComponents type: `string[]` default: `[]` Custom JSX components to be treated as form controls. ### depth type: `integer` default: `2` Maximum depth to search for a nested control. ### labelAttributes type: `string[]` default: `["alt", "aria-label", "aria-labelledby"]` Attributes to check for accessible label text. ### labelComponents type: `string[]` default: `["label"]` Custom JSX components to be treated as labels. ``` ```md ## Configuration This rule accepts a configuration object with the following properties: ### allowExpressionValues type: `boolean` default: `true` If `true`, allows tabIndex values to be expression values (e.g., variables, ternaries). If `false`, only string literal values are allowed. ### roles type: `string[]` default: `["tabpanel"]` An array of ARIA roles that should be considered interactive. ### tags type: `string[]` default: `[]` An array of custom HTML elements that should be considered interactive. ``` ```md ## Configuration This rule accepts a configuration object with the following properties: ### allowedMethods type: `string[]` default: `null` List of Promise static methods that are allowed to be used. ``` --------- Signed-off-by: Connor Shea <connor.james.shea@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 096fb2c commit d5c4ce8

File tree

7 files changed

+134
-116
lines changed

7 files changed

+134
-116
lines changed

crates/oxc_linter/src/rules/eslint/no_self_assign.rs

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,27 @@ use oxc_diagnostics::OxcDiagnostic;
1010
use oxc_macros::declare_oxc_lint;
1111
use oxc_span::{GetSpan, Span};
1212
use oxc_syntax::operator::AssignmentOperator;
13+
use schemars::JsonSchema;
14+
use serde::Deserialize;
1315

1416
use crate::{AstNode, context::LintContext, rule::Rule};
1517

1618
fn no_self_assign_diagnostic(span: Span) -> OxcDiagnostic {
1719
OxcDiagnostic::warn("this expression is assigned to itself").with_label(span)
1820
}
1921

20-
#[derive(Debug, Clone)]
22+
#[derive(Debug, Clone, Deserialize, JsonSchema)]
23+
#[serde(rename_all = "camelCase", default)]
2124
pub struct NoSelfAssign {
22-
/// if this is true, no-self-assign rule warns self-assignments of properties. Default is true.
25+
/// The `props` option when set to `false`, disables the checking of properties.
26+
///
27+
/// With `props` set to `false` the following are examples of correct code:
28+
/// ```javascript
29+
/// obj.a = obj.a;
30+
/// obj.a.b = obj.a.b;
31+
/// obj["a"] = obj["a"];
32+
/// obj[a] = obj[a];
33+
/// ```
2334
props: bool,
2435
}
2536

@@ -81,25 +92,10 @@ declare_oxc_lint!(
8192
/// foo &= foo;
8293
/// foo |= foo;
8394
/// ```
84-
///
85-
/// ### Options
86-
///
87-
/// #### props
88-
///
89-
/// `{ type: boolean, default: true }`
90-
///
91-
/// The `props` option when set to `false`, disables the checking of properties.
92-
///
93-
/// With `props` set to `false` the following are examples of correct code:
94-
/// ```javascript
95-
/// obj.a = obj.a;
96-
/// obj.a.b = obj.a.b;
97-
/// obj["a"] = obj["a"];
98-
/// obj[a] = obj[a];
99-
/// ```
10095
NoSelfAssign,
10196
eslint,
102-
correctness
97+
correctness,
98+
config = NoSelfAssign
10399
);
104100

105101
impl Rule for NoSelfAssign {

crates/oxc_linter/src/rules/jest/prefer_lowercase_title/mod.rs

Lines changed: 64 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use oxc_ast::{AstKind, ast::Argument};
22
use oxc_diagnostics::OxcDiagnostic;
33
use oxc_macros::declare_oxc_lint;
44
use oxc_span::{CompactStr, Span};
5+
use schemars::JsonSchema;
6+
use serde::Deserialize;
57

68
#[cfg(test)]
79
mod tests;
@@ -20,73 +22,20 @@ fn prefer_lowercase_title_diagnostic(title: &str, span: Span) -> OxcDiagnostic {
2022
.with_label(span)
2123
}
2224

23-
#[derive(Debug, Clone)]
25+
#[derive(Debug, Clone, Deserialize, JsonSchema)]
26+
#[serde(rename_all = "camelCase", default)]
2427
pub struct PreferLowercaseTitleConfig {
25-
allowed_prefixes: Vec<CompactStr>,
26-
ignore: Vec<CompactStr>,
27-
ignore_top_level_describe: bool,
28-
lowercase_first_character_only: bool,
29-
}
30-
31-
impl Default for PreferLowercaseTitleConfig {
32-
fn default() -> Self {
33-
Self {
34-
allowed_prefixes: Vec::new(),
35-
ignore: Vec::new(),
36-
ignore_top_level_describe: false,
37-
lowercase_first_character_only: true,
38-
}
39-
}
40-
}
41-
42-
impl std::ops::Deref for PreferLowercaseTitle {
43-
type Target = PreferLowercaseTitleConfig;
44-
45-
fn deref(&self) -> &Self::Target {
46-
&self.0
47-
}
48-
}
49-
50-
#[derive(Debug, Default, Clone)]
51-
pub struct PreferLowercaseTitle(Box<PreferLowercaseTitleConfig>);
52-
53-
declare_oxc_lint!(
54-
/// ### What it does
55-
///
56-
/// Enforce `it`, `test`, `describe`, and `bench` to have descriptions that begin with a
57-
/// lowercase letter. This provides more readable test failures. This rule is not
58-
/// enabled by default.
59-
///
60-
/// ### Examples
61-
///
62-
/// Examples of **incorrect** code for this rule:
63-
/// ```javascript
64-
/// it('Adds 1 + 2 to equal 3', () => {
65-
/// expect(sum(1, 2)).toBe(3);
66-
/// });
67-
/// ```
68-
///
69-
/// Examples of **correct** code for this rule:
70-
/// ```javascript
71-
/// it('adds 1 + 2 to equal 3', () => {
72-
/// expect(sum(1, 2)).toBe(3);
73-
/// });
74-
/// ```
28+
/// This array option allows specifying prefixes, which contain capitals that titles
29+
/// can start with. This can be useful when writing tests for API endpoints, where
30+
/// you'd like to prefix with the HTTP method.
31+
/// By default, nothing is allowed (the equivalent of `{ "allowedPrefixes": [] }`).
7532
///
76-
/// ### Options
77-
/// ```json
78-
/// {
79-
/// "jest/prefer-lowercase-title": [
80-
/// "error",
81-
/// {
82-
/// "ignore": ["describe", "test"]
83-
/// }
84-
/// ]
85-
/// }
33+
/// Example of **correct** code for the `{ "allowedPrefixes": ["GET"] }` option:
34+
/// ```js
35+
/// /* eslint jest/prefer-lowercase-title: ["error", { "allowedPrefixes": ["GET"] }] */
36+
/// describe('GET /live');
8637
/// ```
87-
///
88-
/// #### `ignore`
89-
///
38+
allowed_prefixes: Vec<CompactStr>,
9039
/// This array option controls which Jest or Vitest functions are checked by this rule. There
9140
/// are four possible values:
9241
/// - `"describe"`
@@ -114,22 +63,7 @@ declare_oxc_lint!(
11463
/// /* eslint jest/prefer-lowercase-title: ["error", { "ignore": ["it"] }] */
11564
/// it('Uppercase description');
11665
/// ```
117-
///
118-
/// #### `allowedPrefixes`
119-
///
120-
/// This array option allows specifying prefixes, which contain capitals that titles
121-
/// can start with. This can be useful when writing tests for API endpoints, where
122-
/// you'd like to prefix with the HTTP method.
123-
/// By default, nothing is allowed (the equivalent of `{ "allowedPrefixes": [] }`).
124-
///
125-
/// Example of **correct** code for the `{ "allowedPrefixes": ["GET"] }` option:
126-
/// ```js
127-
/// /* eslint jest/prefer-lowercase-title: ["error", { "allowedPrefixes": ["GET"] }] */
128-
/// describe('GET /live');
129-
/// ```
130-
///
131-
/// #### `ignoreTopLevelDescribe`
132-
///
66+
ignore: Vec<CompactStr>,
13367
/// This option can be set to allow only the top-level `describe` blocks to have a
13468
/// title starting with an upper-case letter.
13569
///
@@ -144,9 +78,7 @@ declare_oxc_lint!(
14478
/// });
14579
/// });
14680
/// ```
147-
///
148-
/// #### `lowercaseFirstCharacterOnly`
149-
///
81+
ignore_top_level_describe: bool,
15082
/// This option can be set to only validate that the first character of a test name is lowercased.
15183
///
15284
/// Example of **correct** code for the `{ "lowercaseFirstCharacterOnly": true }` option:
@@ -172,10 +104,58 @@ declare_oxc_lint!(
172104
/// });
173105
/// });
174106
/// ```
107+
lowercase_first_character_only: bool,
108+
}
109+
110+
impl Default for PreferLowercaseTitleConfig {
111+
fn default() -> Self {
112+
Self {
113+
allowed_prefixes: Vec::new(),
114+
ignore: Vec::new(),
115+
ignore_top_level_describe: false,
116+
lowercase_first_character_only: true,
117+
}
118+
}
119+
}
120+
121+
impl std::ops::Deref for PreferLowercaseTitle {
122+
type Target = PreferLowercaseTitleConfig;
123+
124+
fn deref(&self) -> &Self::Target {
125+
&self.0
126+
}
127+
}
128+
129+
#[derive(Debug, Default, Clone)]
130+
pub struct PreferLowercaseTitle(Box<PreferLowercaseTitleConfig>);
131+
132+
declare_oxc_lint!(
133+
/// ### What it does
134+
///
135+
/// Enforce `it`, `test`, `describe`, and `bench` to have descriptions that begin with a
136+
/// lowercase letter. This provides more readable test failures. This rule is not
137+
/// enabled by default.
138+
///
139+
/// ### Examples
140+
///
141+
/// Examples of **incorrect** code for this rule:
142+
/// ```javascript
143+
/// it('Adds 1 + 2 to equal 3', () => {
144+
/// expect(sum(1, 2)).toBe(3);
145+
/// });
146+
/// ```
147+
///
148+
/// Examples of **correct** code for this rule:
149+
/// ```javascript
150+
/// it('adds 1 + 2 to equal 3', () => {
151+
/// expect(sum(1, 2)).toBe(3);
152+
/// });
153+
/// ```
175154
PreferLowercaseTitle,
176155
jest,
177156
style,
178-
fix
157+
fix,
158+
config = PreferLowercaseTitleConfig
179159
);
180160

181161
impl Rule for PreferLowercaseTitle {

crates/oxc_linter/src/rules/jsx_a11y/label_has_associated_control.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use oxc_ast::{
77
use oxc_diagnostics::OxcDiagnostic;
88
use oxc_macros::declare_oxc_lint;
99
use oxc_span::{CompactStr, Span};
10+
use schemars::JsonSchema;
11+
use serde::{Deserialize, Serialize};
1012

1113
use crate::{
1214
AstNode,
@@ -33,20 +35,28 @@ pub struct LabelHasAssociatedControl(Box<LabelHasAssociatedControlConfig>);
3335
const DEFAULT_CONTROL_COMPONENTS: [&str; 6] =
3436
["input", "meter", "output", "progress", "select", "textarea"];
3537

36-
#[derive(Debug, Clone)]
38+
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
39+
#[serde(rename_all = "camelCase", default)]
3740
pub struct LabelHasAssociatedControlConfig {
41+
/// Maximum depth to search for a nested control.
3842
depth: u8,
43+
/// The type of association required between the label and the control.
3944
assert: Assert,
45+
/// Custom JSX components to be treated as labels.
4046
label_components: Vec<CompactStr>,
47+
/// Attributes to check for accessible label text.
4148
label_attributes: Vec<CompactStr>,
49+
/// Custom JSX components to be treated as form controls.
4250
control_components: Vec<CompactStr>,
4351
}
4452

45-
#[derive(Debug, Clone)]
53+
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
54+
#[serde(rename_all = "kebab-case")]
4655
enum Assert {
4756
HtmlFor,
4857
Nesting,
4958
Both,
59+
#[default]
5060
Either,
5161
}
5262

@@ -110,6 +120,7 @@ declare_oxc_lint!(
110120
LabelHasAssociatedControl,
111121
jsx_a11y,
112122
correctness,
123+
config = LabelHasAssociatedControlConfig
113124
);
114125

115126
impl Rule for LabelHasAssociatedControl {

crates/oxc_linter/src/rules/jsx_a11y/media_has_caption.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use oxc_ast::{
77
use oxc_diagnostics::OxcDiagnostic;
88
use oxc_macros::declare_oxc_lint;
99
use oxc_span::Span;
10+
use schemars::JsonSchema;
11+
use serde::{Deserialize, Serialize};
1012
use serde_json::Value;
1113

1214
use crate::{AstNode, context::LintContext, rule::Rule, utils::get_element_type};
@@ -20,10 +22,14 @@ fn media_has_caption_diagnostic(span: Span) -> OxcDiagnostic {
2022
#[derive(Debug, Default, Clone)]
2123
pub struct MediaHasCaption(Box<MediaHasCaptionConfig>);
2224

23-
#[derive(Debug, Clone)]
25+
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
26+
#[serde(rename_all = "camelCase", default)]
2427
pub struct MediaHasCaptionConfig {
28+
/// Element names to treat as `<audio>` elements
2529
audio: Vec<Cow<'static, str>>,
30+
/// Element names to treat as `<video>` elements
2631
video: Vec<Cow<'static, str>>,
32+
/// Element names to treat as `<track>` elements
2733
track: Vec<Cow<'static, str>>,
2834
}
2935

@@ -63,7 +69,8 @@ declare_oxc_lint!(
6369
/// ```
6470
MediaHasCaption,
6571
jsx_a11y,
66-
correctness
72+
correctness,
73+
config = MediaHasCaptionConfig,
6774
);
6875

6976
impl Rule for MediaHasCaption {

crates/oxc_linter/src/rules/jsx_a11y/no_noninteractive_tabindex.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use oxc_ast::{
55
use oxc_diagnostics::OxcDiagnostic;
66
use oxc_macros::declare_oxc_lint;
77
use oxc_span::{CompactStr, Span};
8+
use schemars::JsonSchema;
9+
use serde::Deserialize;
810

911
use crate::{
1012
AstNode,
@@ -19,23 +21,27 @@ fn no_noninteractive_tabindex_diagnostic(span: Span) -> OxcDiagnostic {
1921
.with_label(span)
2022
}
2123

22-
#[derive(Debug, Clone)]
24+
#[derive(Debug, Default, Clone)]
2325
pub struct NoNoninteractiveTabindex(Box<NoNoninteractiveTabindexConfig>);
2426

25-
#[derive(Debug, Clone)]
27+
#[derive(Debug, Clone, Deserialize, JsonSchema)]
28+
#[serde(rename_all = "camelCase", default)]
2629
struct NoNoninteractiveTabindexConfig {
30+
/// An array of custom HTML elements that should be considered interactive.
2731
tags: Vec<CompactStr>,
32+
/// An array of ARIA roles that should be considered interactive.
2833
roles: Vec<CompactStr>,
34+
/// If `true`, allows tabIndex values to be expression values (e.g., variables, ternaries). If `false`, only string literal values are allowed.
2935
allow_expression_values: bool,
3036
}
3137

32-
impl Default for NoNoninteractiveTabindex {
38+
impl Default for NoNoninteractiveTabindexConfig {
3339
fn default() -> Self {
34-
Self(Box::new(NoNoninteractiveTabindexConfig {
40+
Self {
3541
roles: vec![CompactStr::new("tabpanel")],
3642
allow_expression_values: true,
3743
tags: vec![],
38-
}))
44+
}
3945
}
4046
}
4147

@@ -79,6 +85,7 @@ declare_oxc_lint!(
7985
NoNoninteractiveTabindex,
8086
jsx_a11y,
8187
correctness,
88+
config = NoNoninteractiveTabindexConfig,
8289
);
8390

8491
// https://html.spec.whatwg.org/multipage/dom.html#interactive-content

0 commit comments

Comments
 (0)