Skip to content

Commit b8b0efc

Browse files
committed
fix: detect missing keys in arrays of pushed elements
1 parent f2869fd commit b8b0efc

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

lib/rules/jsx-key.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,41 @@ module.exports = {
186186
)`.replace(/\s/g, '');
187187
let isWithinChildrenToArray = false;
188188

189+
/**
190+
* Checks if the given node is a push call expression that has JSX Elements or JSX Fragments as arguments,
191+
* and the JSX is missing a key prop
192+
* @param {ASTNode} node
193+
*/
194+
function checkArrayPushArguments(node) {
195+
if (isWithinChildrenToArray) {
196+
return;
197+
}
198+
199+
node.arguments.forEach((arg) => {
200+
if (
201+
arg.type === 'JSXElement'
202+
&& !hasProp(arg.openingElement.attributes, 'key')
203+
) {
204+
report(context, messages.missingArrayKey, 'missingArrayKey', {
205+
node: arg,
206+
});
207+
} else if (checkFragmentShorthand && arg.type === 'JSXFragment') {
208+
report(
209+
context,
210+
messages.missingArrayKeyUsePrag,
211+
'missingArrayKeyUsePrag',
212+
{
213+
node: arg,
214+
data: {
215+
reactPrag: reactPragma,
216+
fragPrag: fragmentPragma,
217+
},
218+
}
219+
);
220+
}
221+
});
222+
}
223+
189224
const seen = new WeakSet();
190225

191226
return {
@@ -197,6 +232,12 @@ module.exports = {
197232
isWithinChildrenToArray = false;
198233
},
199234

235+
'CallExpression[callee.type="MemberExpression"][callee.property.name="push"]'(
236+
node
237+
) {
238+
checkArrayPushArguments(node);
239+
},
240+
200241
'ArrayExpression, JSXElement > JSXElement'(node) {
201242
if (isWithinChildrenToArray) {
202243
return;

tests/lib/rules/jsx-key.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,5 +424,19 @@ ruleTester.run('jsx-key', rule, {
424424
options: [{ checkKeyMustBeforeSpread: true }],
425425
errors: [{ messageId: 'keyBeforeSpread' }],
426426
},
427+
{
428+
code: `
429+
const TestCase = () => {
430+
const keyLessItems = [];
431+
432+
for (let i = 0; i < 4; i++) {
433+
keyLessItems.push(<li>No Key!</li>);
434+
}
435+
436+
return <ul>{keyLessItems}</ul>;
437+
}
438+
`,
439+
errors: [{ messageId: 'missingArrayKey' }],
440+
},
427441
]),
428442
});

0 commit comments

Comments
 (0)