@@ -7,7 +7,13 @@ use oxc_span::{Atom, Span};
7
7
8
8
use itertools:: Itertools ;
9
9
10
- use crate :: { context:: LintContext , rule:: Rule , utils:: is_same_member_expression, AstNode } ;
10
+ use crate :: {
11
+ context:: LintContext ,
12
+ fixer:: { Fix , RuleFix } ,
13
+ rule:: Rule ,
14
+ utils:: is_same_member_expression,
15
+ AstNode ,
16
+ } ;
11
17
12
18
fn jsx_props_no_spread_multiple_identifiers_diagnostic (
13
19
spans : Vec < Span > ,
@@ -20,6 +26,7 @@ fn jsx_props_no_spread_multiple_identifiers_diagnostic(
20
26
21
27
fn jsx_props_no_spread_multiple_member_expressions_diagnostic ( spans : Vec < Span > ) -> OxcDiagnostic {
22
28
OxcDiagnostic :: warn ( "Disallow JSX prop spreading the same member expression multiple times." )
29
+ . with_help ( "Remove the first spread." )
23
30
. with_labels ( spans)
24
31
}
25
32
@@ -45,7 +52,7 @@ declare_oxc_lint!(
45
52
/// ```
46
53
JsxPropsNoSpreadMulti ,
47
54
correctness,
48
- pending // TODO: add auto- fix to remove the first spread. Removing the second one would change program behavior.
55
+ fix
49
56
) ;
50
57
51
58
impl Rule for JsxPropsNoSpreadMulti {
@@ -82,18 +89,32 @@ impl Rule for JsxPropsNoSpreadMulti {
82
89
}
83
90
84
91
for ( identifier_name, spans) in duplicate_spreads {
85
- ctx. diagnostic ( jsx_props_no_spread_multiple_identifiers_diagnostic (
86
- spans,
87
- identifier_name,
88
- ) ) ;
92
+ ctx. diagnostic_with_fix (
93
+ jsx_props_no_spread_multiple_identifiers_diagnostic (
94
+ spans. clone ( ) ,
95
+ identifier_name,
96
+ ) ,
97
+ |_fixer| {
98
+ spans
99
+ . iter ( )
100
+ . rev ( )
101
+ . skip ( 1 )
102
+ . map ( |span| Fix :: delete ( * span) )
103
+ . collect :: < RuleFix < ' a > > ( )
104
+ } ,
105
+ ) ;
89
106
}
90
107
91
108
member_expressions. iter ( ) . tuple_combinations ( ) . for_each (
92
109
|( ( left, left_span) , ( right, right_span) ) | {
93
110
if is_same_member_expression ( left, right, ctx) {
94
- ctx. diagnostic ( jsx_props_no_spread_multiple_member_expressions_diagnostic (
95
- vec ! [ * left_span, * right_span] ,
96
- ) ) ;
111
+ ctx. diagnostic_with_fix (
112
+ jsx_props_no_spread_multiple_member_expressions_diagnostic ( vec ! [
113
+ * left_span,
114
+ * right_span,
115
+ ] ) ,
116
+ |fixer| fixer. delete_range ( * left_span) ,
117
+ ) ;
97
118
}
98
119
} ,
99
120
) ;
@@ -147,6 +168,13 @@ fn test() {
147
168
<div {...props} {...props} {...props} />
148
169
" ,
149
170
] ;
171
+ let fix = vec ! [
172
+ ( "<App {...props} {...props} />" , "<App {...props} />" ) ,
173
+ ( "<App {...props.foo} {...props.foo} />" , "<App {...props.foo} />" ) ,
174
+ ( "<App {...(props.foo.baz)} {...(props.foo.baz)} />" , "<App {...(props.foo.baz)} />" ) ,
175
+ ( r#"<div {...props} a="a" {...props} />"# , r#"<div a="a" {...props} />"# ) ,
176
+ ( "<div {...props} {...props} {...props} />" , "<div {...props} />" ) ,
177
+ ] ;
150
178
151
- Tester :: new ( JsxPropsNoSpreadMulti :: NAME , pass, fail) . test_and_snapshot ( ) ;
179
+ Tester :: new ( JsxPropsNoSpreadMulti :: NAME , pass, fail) . expect_fix ( fix ) . test_and_snapshot ( ) ;
152
180
}
0 commit comments