diff --git a/crates/oxc_linter/src/rules/react/jsx_props_no_spread_multi.rs b/crates/oxc_linter/src/rules/react/jsx_props_no_spread_multi.rs index ee4afdeb0b058..4ad56aa5aad4a 100644 --- a/crates/oxc_linter/src/rules/react/jsx_props_no_spread_multi.rs +++ b/crates/oxc_linter/src/rules/react/jsx_props_no_spread_multi.rs @@ -7,7 +7,13 @@ use oxc_span::{Atom, Span}; use itertools::Itertools; -use crate::{context::LintContext, rule::Rule, utils::is_same_member_expression, AstNode}; +use crate::{ + context::LintContext, + fixer::{Fix, RuleFix}, + rule::Rule, + utils::is_same_member_expression, + AstNode, +}; fn jsx_props_no_spread_multiple_identifiers_diagnostic( spans: Vec, @@ -20,6 +26,7 @@ fn jsx_props_no_spread_multiple_identifiers_diagnostic( fn jsx_props_no_spread_multiple_member_expressions_diagnostic(spans: Vec) -> OxcDiagnostic { OxcDiagnostic::warn("Disallow JSX prop spreading the same member expression multiple times.") + .with_help("Remove the first spread.") .with_labels(spans) } @@ -45,7 +52,7 @@ declare_oxc_lint!( /// ``` JsxPropsNoSpreadMulti, correctness, - pending // TODO: add auto-fix to remove the first spread. Removing the second one would change program behavior. + fix ); impl Rule for JsxPropsNoSpreadMulti { @@ -82,18 +89,32 @@ impl Rule for JsxPropsNoSpreadMulti { } for (identifier_name, spans) in duplicate_spreads { - ctx.diagnostic(jsx_props_no_spread_multiple_identifiers_diagnostic( - spans, - identifier_name, - )); + ctx.diagnostic_with_fix( + jsx_props_no_spread_multiple_identifiers_diagnostic( + spans.clone(), + identifier_name, + ), + |_fixer| { + spans + .iter() + .rev() + .skip(1) + .map(|span| Fix::delete(*span)) + .collect::>() + }, + ); } member_expressions.iter().tuple_combinations().for_each( |((left, left_span), (right, right_span))| { if is_same_member_expression(left, right, ctx) { - ctx.diagnostic(jsx_props_no_spread_multiple_member_expressions_diagnostic( - vec![*left_span, *right_span], - )); + ctx.diagnostic_with_fix( + jsx_props_no_spread_multiple_member_expressions_diagnostic(vec![ + *left_span, + *right_span, + ]), + |fixer| fixer.delete_range(*left_span), + ); } }, ); @@ -147,6 +168,13 @@ fn test() {
", ]; + let fix = vec![ + ("", ""), + ("", ""), + ("", ""), + (r#"
"#, r#"
"#), + ("
", "
"), + ]; - Tester::new(JsxPropsNoSpreadMulti::NAME, pass, fail).test_and_snapshot(); + Tester::new(JsxPropsNoSpreadMulti::NAME, pass, fail).expect_fix(fix).test_and_snapshot(); } diff --git a/crates/oxc_linter/src/snapshots/jsx_props_no_spread_multi.snap b/crates/oxc_linter/src/snapshots/jsx_props_no_spread_multi.snap index 5944ba8632f7d..7a6449f260d14 100644 --- a/crates/oxc_linter/src/snapshots/jsx_props_no_spread_multi.snap +++ b/crates/oxc_linter/src/snapshots/jsx_props_no_spread_multi.snap @@ -17,6 +17,7 @@ source: crates/oxc_linter/src/tester.rs · ────────────── ────────────── 4 │ ╰──── + help: Remove the first spread. ⚠ eslint-plugin-react(jsx-props-no-spread-multi): Disallow JSX prop spreading the same member expression multiple times. ╭─[jsx_props_no_spread_multi.tsx:3:16] @@ -25,6 +26,7 @@ source: crates/oxc_linter/src/tester.rs · ──────────────────── ──────────────────── 4 │ ╰──── + help: Remove the first spread. ⚠ eslint-plugin-react(jsx-props-no-spread-multi): Disallow JSX prop spreading the same identifier multiple times. ╭─[jsx_props_no_spread_multi.tsx:3:16]