Skip to content

Commit

Permalink
fix(lint): don't trigger useJsxKeyInIterable when iterating on non-…
Browse files Browse the repository at this point in the history
…jsx things
  • Loading branch information
dyc3 committed May 2, 2024
1 parent 5fda633 commit 65a06f2
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ declare_node_union! {
#[derive(Debug)]
pub enum UseJsxKeyInIterableState {
MissingKeyProps(TextRange),
CantDetermineJSXProp(TextRange),
}

impl Rule for UseJsxKeyInIterable {
Expand Down Expand Up @@ -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 "<Emphasis>"key"</Emphasis>" prop."
},
)
.note(markup! {
"Either return a JSX expression, or suppress this instance if you determine it is safe."
}).note(markup! {
"Check the "<Hyperlink href="https://react.dev/learn/rendering-lists#why-does-react-need-keys">"React documentation for why a key prop is required"</Hyperlink>". "
});
Some(diagnostic)
}
}
}
}
Expand All @@ -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()
}

Expand Down Expand Up @@ -198,6 +183,7 @@ fn handle_iterators(
let returned_value = statement.argument()?;
handle_potential_react_component(returned_value, model, is_inside_jsx)
})
.flatten()
.collect::<Vec<_>>();

Some(res)
Expand All @@ -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
Expand All @@ -218,6 +203,7 @@ fn handle_iterators(
let returned_value = statement.argument()?;
handle_potential_react_component(returned_value, model, is_inside_jsx)
})
.flatten()
.collect::<Vec<_>>();
Some(res)
}
Expand All @@ -231,19 +217,33 @@ fn handle_potential_react_component(
node: AnyJsExpression,
model: &SemanticModel,
is_inside_jsx: bool,
) -> Option<UseJsxKeyInIterableState> {
) -> Option<Vec<UseJsxKeyInIterableState>> {
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::<Vec<_>>();

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)])
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 │ (<h1>{[<h1></h1>, <h1></h1>, <h1></h1>]}</h1>)
32 │
> 33 │ (<h1>{[<h1></h1>, xyz, abc? <h2></h2>: bcd]}</h1>)
│ ^^^
34 │
35 │ (<h1>{data.map(c => <h1></h1>)}</h1>)
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 │ (<h1>{[<h1></h1>, <h1></h1>, <h1></h1>]}</h1>)
32 │
> 33 │ (<h1>{[<h1></h1>, xyz, abc? <h2></h2>: bcd]}</h1>)
^^^^^^^^^^^^^^^^^^^
^^^^
34 │
35 │ (<h1>{data.map(c => <h1></h1>)}</h1>)
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.
```
Expand All @@ -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 │ (<h1>{data.map(c => <h1></h1>)}</h1>)
36 │
> 37 │ (<h1>{data.map(c => xyz)}</h1>)
│ ^^^
38 │
39 │ (<h1>{data.map(c => (<h1></h1>))}</h1>)
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.
```

```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,10 @@ React.Children.map(c => React.cloneElement(c, {key: c}));

(<h1>{data.map(c => (<h1 key={c}></h1>))}</h1>)

(<h1>{data.map(c => {return (<h1 key={c}></h1>)})}</h1>)
(<h1>{data.map(c => {return (<h1 key={c}></h1>)})}</h1>)

<>{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)}</>
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,11 @@ React.Children.map(c => React.cloneElement(c, {key: c}));
(<h1>{data.map(c => (<h1 key={c}></h1>))}</h1>)

(<h1>{data.map(c => {return (<h1 key={c}></h1>)})}</h1>)

<>{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)}</>

```

0 comments on commit 65a06f2

Please sign in to comment.