Skip to content

Commit 041a120

Browse files
metreniukljharb
authored andcommitted
[Fix] jsx-key: detect keys in logical expression and conditional expression (jsx-eslint#3490)
Fixes jsx-eslint#3481.
1 parent f5e5da8 commit 041a120

File tree

4 files changed

+34
-8
lines changed

4 files changed

+34
-8
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
88
### Fixed
99
* [`jsx-no-target-blank`]: allow ternaries with literals ([#3464][] @akulsr0)
1010
* [`no-unknown-property`]: add `inert` attribute ([#3484][] @ljharb)
11+
* [`jsx-key`]: detect keys in logical expression and conditional expression ([#3490][] @metreniuk)
1112

1213
### Changed
1314
* [Perf] component detection: improve performance by avoiding traversing parents unnecessarily ([#3459][] @golopot)
1415
* [Docs] `forbid-component-props`: inclusive language w/ allowlist ([#3473][] @AndersDJohnson)
1516
* [Docs] automate doc generation with `eslint-doc-generator` ([#3469][] @bmish)
1617

18+
[#3490]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3490
1719
[#3484]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3484
1820
[#3473]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3473
1921
[#3469]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3469

docs/rules/jsx-key.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ data.map(x => <Hello>{x}</Hello>);
2020
```
2121

2222
```jsx
23-
<Hello {...{ key: id, id, caption }} />
23+
Array.from([1, 2, 3], (x) => <Hello>{x}</Hello>);
2424
```
2525

2626
```jsx
27-
Array.from([1, 2, 3], (x) => <Hello>{x}</Hello>);
27+
<Hello {...{ key: id, id, caption }} />
2828
```
2929

3030
In the last example the key is being spread, which is currently possible, but discouraged in favor of the statically provided key.
@@ -40,11 +40,11 @@ data.map((x) => <Hello key={x.id}>{x}</Hello>);
4040
```
4141

4242
```jsx
43-
<Hello key={id} {...{ id, caption }} />
43+
Array.from([1, 2, 3], (x) => <Hello key={x.id}>{x}</Hello>);
4444
```
4545

4646
```jsx
47-
Array.from([1, 2, 3], (x) => <Hello key={x.id}>{x}</Hello>);
47+
<Hello key={id} {...{ id, caption }} />
4848
```
4949

5050
## Rule Options

lib/rules/jsx-key.js

+12-2
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,20 @@ module.exports = {
149149
*/
150150
function checkArrowFunctionWithJSX(node) {
151151
const isArrFn = node && node.type === 'ArrowFunctionExpression';
152-
153-
if (isArrFn && (node.body.type === 'JSXElement' || node.body.type === 'JSXFragment')) {
152+
const shouldCheckNode = (n) => n && (n.type === 'JSXElement' || n.type === 'JSXFragment');
153+
if (isArrFn && shouldCheckNode(node.body)) {
154154
checkIteratorElement(node.body);
155155
}
156+
if (node.body.type === 'ConditionalExpression') {
157+
if (shouldCheckNode(node.body.consequent)) {
158+
checkIteratorElement(node.body.consequent);
159+
}
160+
if (shouldCheckNode(node.body.alternate)) {
161+
checkIteratorElement(node.body.alternate);
162+
}
163+
} else if (node.body.type === 'LogicalExpression' && shouldCheckNode(node.body.right)) {
164+
checkIteratorElement(node.body.right);
165+
}
156166
}
157167

158168
const childrenToArraySelector = `:matches(

tests/lib/rules/jsx-key.js

+16-2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ ruleTester.run('jsx-key', rule, {
4242
{ code: '[<App key={0} />, <App key={1} />];' },
4343
{ code: '[1, 2, 3].map(function(x) { return <App key={x} /> });' },
4444
{ code: '[1, 2, 3].map(x => <App key={x} />);' },
45+
{ code: '[1, 2 ,3].map(x => x && <App x={x} key={x} />);' },
46+
{ code: '[1, 2 ,3].map(x => x ? <App x={x} key="1" /> : <OtherApp x={x} key="2" />);' },
4547
{ code: '[1, 2, 3].map(x => { return <App key={x} /> });' },
4648
{ code: 'Array.from([1, 2, 3], function(x) { return <App key={x} /> });' },
4749
{ code: 'Array.from([1, 2, 3], (x => <App key={x} />));' },
@@ -188,10 +190,10 @@ ruleTester.run('jsx-key', rule, {
188190
code: `
189191
import Act from 'react';
190192
import { Children as ReactChildren } from 'react';
191-
193+
192194
const { Children } = Act;
193195
const { toArray } = Children;
194-
196+
195197
Act.Children.toArray([1, 2 ,3].map(x => <App />));
196198
Act.Children.toArray(Array.from([1, 2 ,3], x => <App />));
197199
Children.toArray([1, 2 ,3].map(x => <App />));
@@ -225,6 +227,18 @@ ruleTester.run('jsx-key', rule, {
225227
code: '[1, 2 ,3].map(x => <App />);',
226228
errors: [{ messageId: 'missingIterKey' }],
227229
},
230+
{
231+
code: '[1, 2 ,3].map(x => x && <App x={x} />);',
232+
errors: [{ messageId: 'missingIterKey' }],
233+
},
234+
{
235+
code: '[1, 2 ,3].map(x => x ? <App x={x} key="1" /> : <OtherApp x={x} />);',
236+
errors: [{ messageId: 'missingIterKey' }],
237+
},
238+
{
239+
code: '[1, 2 ,3].map(x => x ? <App x={x} /> : <OtherApp x={x} key="2" />);',
240+
errors: [{ messageId: 'missingIterKey' }],
241+
},
228242
{
229243
code: '[1, 2 ,3].map(x => { return <App /> });',
230244
errors: [{ messageId: 'missingIterKey' }],

0 commit comments

Comments
 (0)