Skip to content

Commit b26900c

Browse files
authored
fix(linter): Improve diagnostic for react/button-has-type. (#15200)
Fixes #15147. Previously, the diagnostic message did not change based on the options configured for the rule. **Disclaimer:** Fully written by GitHub Copilot w/ Claude Sonnet 4.5. I only made minor edits and followed its work to make sure it made sense and tested the changes briefly. I also added the basic additional test cases. But I do not really know much Rust, so please review accordingly.
1 parent 4ba1bca commit b26900c

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

crates/oxc_linter/src/rules/react/button_has_type.rs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ fn missing_type_prop(span: Span) -> OxcDiagnostic {
2323
.with_label(span)
2424
}
2525

26-
fn invalid_type_prop(span: Span) -> OxcDiagnostic {
26+
fn invalid_type_prop(span: Span, allowed_types: &str) -> OxcDiagnostic {
2727
OxcDiagnostic::warn("`button` elements must have a valid `type` attribute.")
28-
.with_help("Change the `type` attribute to one of the allowed values: `button`, `submit`, or `reset`.")
28+
.with_help(format!(
29+
"Change the `type` attribute to one of the allowed values: {allowed_types}."
30+
))
2931
.with_label(span)
3032
}
3133

@@ -95,7 +97,11 @@ impl Rule for ButtonHasType {
9597
},
9698
|button_type_prop| {
9799
if !self.is_valid_button_type_prop(button_type_prop) {
98-
ctx.diagnostic(invalid_type_prop(button_type_prop.span()));
100+
let allowed_types = self.allowed_types_message();
101+
ctx.diagnostic(invalid_type_prop(
102+
button_type_prop.span(),
103+
&allowed_types,
104+
));
99105
}
100106
},
101107
);
@@ -130,7 +136,11 @@ impl Rule for ButtonHasType {
130136
|type_prop| {
131137
if !self.is_valid_button_type_prop_expression(&type_prop.value)
132138
{
133-
ctx.diagnostic(invalid_type_prop(type_prop.span));
139+
let allowed_types = self.allowed_types_message();
140+
ctx.diagnostic(invalid_type_prop(
141+
type_prop.span,
142+
&allowed_types,
143+
));
134144
}
135145
},
136146
);
@@ -165,6 +175,29 @@ impl Rule for ButtonHasType {
165175
}
166176

167177
impl ButtonHasType {
178+
fn allowed_types_message(&self) -> String {
179+
let mut types = Vec::new();
180+
if self.button {
181+
types.push("`button`");
182+
}
183+
if self.submit {
184+
types.push("`submit`");
185+
}
186+
if self.reset {
187+
types.push("`reset`");
188+
}
189+
190+
match types.len() {
191+
0 => String::new(),
192+
1 => types[0].to_string(),
193+
2 => format!("{} or {}", types[0], types[1]),
194+
_ => {
195+
let last = types.pop().unwrap();
196+
format!("{}, or {}", types.join(", "), last)
197+
}
198+
}
199+
}
200+
168201
fn is_valid_button_type_prop(&self, item: &JSXAttributeItem) -> bool {
169202
match get_prop_value(item) {
170203
Some(JSXAttributeValue::ExpressionContainer(container)) => {
@@ -243,6 +276,10 @@ fn test() {
243276
r#"React.createElement("button", {type: "button"})"#,
244277
Some(serde_json::json!([{ "reset": false }])),
245278
),
279+
(
280+
r#"React.createElement("button", {type: "button"})"#,
281+
Some(serde_json::json!([{ "reset": false, "submit": false }])),
282+
),
246283
(
247284
r#"
248285
function MyComponent(): ReactElement {
@@ -312,6 +349,10 @@ fn test() {
312349
r#"React.createElement("button", {type: condition ? "reset" : "button"})"#,
313350
Some(serde_json::json!([{ "reset": false }])),
314351
),
352+
(
353+
r#"React.createElement("button", {type: condition ? "reset" : "button"})"#,
354+
Some(serde_json::json!([{ "reset": false, "submit": false }])),
355+
),
315356
(r#"Foo.createElement("button")"#, None),
316357
(
317358
r"function Button({ type, ...extraProps }) { const button = type; return <button type={button} {...extraProps} />; }",

crates/oxc_linter/src/snapshots/react_button_has_type.snap

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ source: crates/oxc_linter/src/tester.rs
5555
1 │ <button type="reset"/>
5656
· ────────────
5757
╰────
58-
help: Change the `type` attribute to one of the allowed values: `button`, `submit`, or `reset`.
58+
help: Change the `type` attribute to one of the allowed values: `button` or `submit`.
5959
6060
⚠ eslint-plugin-react(button-has-type): `button` elements must have a valid `type` attribute.
6161
╭─[button_has_type.tsx:1:9]
@@ -76,7 +76,7 @@ source: crates/oxc_linter/src/tester.rs
7676
1 │ <button type={condition ? "button" : "reset"}/>
7777
· ─────────────────────────────────────
7878
╰────
79-
help: Change the `type` attribute to one of the allowed values: `button`, `submit`, or `reset`.
79+
help: Change the `type` attribute to one of the allowed values: `button` or `submit`.
8080
8181
⚠ eslint-plugin-react(button-has-type): `button` elements must have a valid `type` attribute.
8282
╭─[button_has_type.tsx:1:9]
@@ -104,7 +104,7 @@ source: crates/oxc_linter/src/tester.rs
104104
1 │ <button type={condition ? "reset" : "button"}/>
105105
· ─────────────────────────────────────
106106
╰────
107-
help: Change the `type` attribute to one of the allowed values: `button`, `submit`, or `reset`.
107+
help: Change the `type` attribute to one of the allowed values: `button` or `submit`.
108108
109109
⚠ eslint-plugin-react(button-has-type): `button` elements must have an explicit `type` attribute.
110110
╭─[button_has_type.tsx:1:1]
@@ -139,7 +139,7 @@ source: crates/oxc_linter/src/tester.rs
139139
1 │ React.createElement("button", {type: "reset"})
140140
· ─────────────
141141
╰────
142-
help: Change the `type` attribute to one of the allowed values: `button`, `submit`, or `reset`.
142+
help: Change the `type` attribute to one of the allowed values: `button` or `submit`.
143143
144144
⚠ eslint-plugin-react(button-has-type): `button` elements must have a valid `type` attribute.
145145
╭─[button_has_type.tsx:1:32]
@@ -160,7 +160,7 @@ source: crates/oxc_linter/src/tester.rs
160160
1 │ React.createElement("button", {type: condition ? "button" : "reset"})
161161
· ────────────────────────────────────
162162
╰────
163-
help: Change the `type` attribute to one of the allowed values: `button`, `submit`, or `reset`.
163+
help: Change the `type` attribute to one of the allowed values: `button` or `submit`.
164164
165165
⚠ eslint-plugin-react(button-has-type): `button` elements must have a valid `type` attribute.
166166
╭─[button_has_type.tsx:1:32]
@@ -181,7 +181,14 @@ source: crates/oxc_linter/src/tester.rs
181181
1 │ React.createElement("button", {type: condition ? "reset" : "button"})
182182
· ────────────────────────────────────
183183
╰────
184-
help: Change the `type` attribute to one of the allowed values: `button`, `submit`, or `reset`.
184+
help: Change the `type` attribute to one of the allowed values: `button` or `submit`.
185+
186+
⚠ eslint-plugin-react(button-has-type): `button` elements must have a valid `type` attribute.
187+
╭─[button_has_type.tsx:1:32]
188+
1 │ React.createElement("button", {type: condition ? "reset" : "button"})
189+
· ────────────────────────────────────
190+
╰────
191+
help: Change the `type` attribute to one of the allowed values: `button`.
185192
186193
⚠ eslint-plugin-react(button-has-type): `button` elements must have an explicit `type` attribute.
187194
╭─[button_has_type.tsx:1:1]

0 commit comments

Comments
 (0)