diff --git a/crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs b/crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs index 9704bfa506e4..bb659ce45eeb 100644 --- a/crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs +++ b/crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs @@ -55,7 +55,6 @@ declare_node_union! { #[derive(Debug)] pub enum UseJsxKeyInIterableState { MissingKeyProps(TextRange), - CantDetermineJSXProp(TextRange), } impl Rule for UseJsxKeyInIterable { @@ -93,21 +92,6 @@ impl Rule for UseJsxKeyInIterable { }); Some(diagnostic) } - UseJsxKeyInIterableState::CantDetermineJSXProp(state) => { - let diagnostic = RuleDiagnostic::new( - rule_category!(), - state, - markup! { - "Cannot determine whether this child has the required ""key"" prop." - }, - ) - .note(markup! { - "Either return a JSX expression, or suppress this instance if you determine it is safe." - }).note(markup! { - "Check the ""React documentation for why a key prop is required"". " - }); - Some(diagnostic) - } } } } @@ -133,6 +117,7 @@ fn handle_collections( let node = AnyJsExpression::cast(node.into_syntax())?; handle_potential_react_component(node, model, is_inside_jsx) }) + .flatten() .collect() } @@ -198,6 +183,7 @@ fn handle_iterators( let returned_value = statement.argument()?; handle_potential_react_component(returned_value, model, is_inside_jsx) }) + .flatten() .collect::>(); Some(res) @@ -207,7 +193,6 @@ fn handle_iterators( match body { AnyJsFunctionBody::AnyJsExpression(expr) => { handle_potential_react_component(expr, model, is_inside_jsx) - .map(|state| vec![state]) } AnyJsFunctionBody::JsFunctionBody(body) => { let res = body @@ -218,6 +203,7 @@ fn handle_iterators( let returned_value = statement.argument()?; handle_potential_react_component(returned_value, model, is_inside_jsx) }) + .flatten() .collect::>(); Some(res) } @@ -231,19 +217,33 @@ fn handle_potential_react_component( node: AnyJsExpression, model: &SemanticModel, is_inside_jsx: bool, -) -> Option { +) -> Option> { let node = unwrap_parenthesis(node)?; + if is_inside_jsx { + if let AnyJsExpression::JsConditionalExpression(node) = node { + let results = [node.consequent().ok()?, node.alternate().ok()?] + .into_iter() + .filter_map(|node| handle_potential_react_component(node, model, is_inside_jsx)) + .flatten() + .collect::>(); + + return if !results.is_empty() { + Some(results) + } else { + None + }; + } if let Some(node) = ReactComponentExpression::cast_ref(node.syntax()) { let range = handle_react_component(node, model)?; - Some(UseJsxKeyInIterableState::MissingKeyProps(range)) + Some(vec![UseJsxKeyInIterableState::MissingKeyProps(range)]) } else { - Some(UseJsxKeyInIterableState::CantDetermineJSXProp(node.range())) + None } } else { let range = handle_react_component(ReactComponentExpression::cast_ref(node.syntax())?, model)?; - Some(UseJsxKeyInIterableState::MissingKeyProps(range)) + Some(vec![UseJsxKeyInIterableState::MissingKeyProps(range)]) } } diff --git a/crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/invalid.jsx.snap b/crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/invalid.jsx.snap index 03ae8d055aee..a5e6779e092d 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/invalid.jsx.snap +++ b/crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/invalid.jsx.snap @@ -523,39 +523,20 @@ invalid.jsx:33:8 lint/correctness/useJsxKeyInIterable ━━━━━━━━ ``` ``` -invalid.jsx:33:19 lint/correctness/useJsxKeyInIterable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.jsx:33:29 lint/correctness/useJsxKeyInIterable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Cannot determine whether this child has the required key prop. - - 31 │ (

{[

,

,

]}) - 32 │ - > 33 │ (

{[

, xyz, abc?

: bcd]}) - │ ^^^ - 34 │ - 35 │ (

{data.map(c =>

)}) - - i Either return a JSX expression, or suppress this instance if you determine it is safe. - - i Check the React documentation for why a key prop is required. - - -``` - -``` -invalid.jsx:33:24 lint/correctness/useJsxKeyInIterable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! Cannot determine whether this child has the required key prop. + ! Missing key property for this element in iterable. 31 │ (

{[

,

,

]}) 32 │ > 33 │ (

{[

, xyz, abc?

: bcd]}) - │ ^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 34 │ 35 │ (

{data.map(c =>

)}) - i Either return a JSX expression, or suppress this instance if you determine it is safe. + i The order of the items may change, and having a key can help React identify which item was moved. - i Check the React documentation for why a key prop is required. + i Check the React documentation. ``` @@ -577,25 +558,6 @@ invalid.jsx:35:21 lint/correctness/useJsxKeyInIterable ━━━━━━━━ i Check the React documentation. -``` - -``` -invalid.jsx:37:21 lint/correctness/useJsxKeyInIterable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! Cannot determine whether this child has the required key prop. - - 35 │ (

{data.map(c =>

)}) - 36 │ - > 37 │ (

{data.map(c => xyz)}

) - │ ^^^ - 38 │ - 39 │ (

{data.map(c => (

))}) - - i Either return a JSX expression, or suppress this instance if you determine it is safe. - - i Check the React documentation for why a key prop is required. - - ``` ``` diff --git a/crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/valid.jsx b/crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/valid.jsx index 21c82252ba7e..c9e7be44af33 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/valid.jsx +++ b/crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/valid.jsx @@ -45,4 +45,10 @@ React.Children.map(c => React.cloneElement(c, {key: c})); (

{data.map(c => (

))}) -(

{data.map(c => {return (

)})}) \ No newline at end of file +(

{data.map(c => {return (

)})}) + +<>{data.reduce((total, next) => total + next, 0)} + +<>{data.reduce((a, b) => Math.max(a, b), 0)} + +<>{data.reduce((a, b) => a > b ? a : b, 0)} diff --git a/crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/valid.jsx.snap b/crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/valid.jsx.snap index f2611fff4426..d52efbcdd157 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/valid.jsx.snap +++ b/crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/valid.jsx.snap @@ -52,4 +52,11 @@ React.Children.map(c => React.cloneElement(c, {key: c})); (

{data.map(c => (

))}) (

{data.map(c => {return (

)})}) + +<>{data.reduce((total, next) => total + next, 0)} + +<>{data.reduce((a, b) => Math.max(a, b), 0)} + +<>{data.reduce((a, b) => a > b ? a : b, 0)} + ```