Skip to content

Commit 483ae9e

Browse files
committed
fix: incorrect behaviour for checkKeyMustBeforeSpread with map callbacks
1 parent 393bfa2 commit 483ae9e

File tree

2 files changed

+43
-18
lines changed

2 files changed

+43
-18
lines changed

lib/rules/jsx-key.js

+28-18
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,35 @@ module.exports = {
7373
const reactPragma = pragmaUtil.getFromContext(context);
7474
const fragmentPragma = pragmaUtil.getFragmentFromContext(context);
7575

76+
function isKeyAfterSpread(attributes) {
77+
let hasFoundSpread = false;
78+
return attributes.some((attribute) => {
79+
if (attribute.type === 'JSXSpreadAttribute') {
80+
hasFoundSpread = true;
81+
return false;
82+
}
83+
if (attribute.type !== 'JSXAttribute') {
84+
return false;
85+
}
86+
return hasFoundSpread && propName(attribute) === 'key';
87+
});
88+
}
89+
7690
function checkIteratorElement(node) {
77-
if (node.type === 'JSXElement' && !hasProp(node.openingElement.attributes, 'key')) {
78-
report(context, messages.missingIterKey, 'missingIterKey', {
79-
node,
80-
});
91+
if (node.type === 'JSXElement') {
92+
if (!hasProp(node.openingElement.attributes, 'key')) {
93+
report(context, messages.missingIterKey, 'missingIterKey', {
94+
node,
95+
});
96+
} else {
97+
const attrs = node.openingElement.attributes;
98+
99+
if (checkKeyMustBeforeSpread && isKeyAfterSpread(attrs)) {
100+
report(context, messages.keyBeforeSpread, 'keyBeforeSpread', {
101+
node: node.type === 'ArrayExpression' ? node : node.parent,
102+
});
103+
}
104+
}
81105
} else if (checkFragmentShorthand && node.type === 'JSXFragment') {
82106
report(context, messages.missingIterKeyUsePrag, 'missingIterKeyUsePrag', {
83107
node,
@@ -115,20 +139,6 @@ module.exports = {
115139
return returnStatements;
116140
}
117141

118-
function isKeyAfterSpread(attributes) {
119-
let hasFoundSpread = false;
120-
return attributes.some((attribute) => {
121-
if (attribute.type === 'JSXSpreadAttribute') {
122-
hasFoundSpread = true;
123-
return false;
124-
}
125-
if (attribute.type !== 'JSXAttribute') {
126-
return false;
127-
}
128-
return hasFoundSpread && propName(attribute) === 'key';
129-
});
130-
}
131-
132142
/**
133143
* Checks if the given node is a function expression or arrow function,
134144
* and checks if there is a missing key prop in return statement's arguments

tests/lib/rules/jsx-key.js

+15
Original file line numberDiff line numberDiff line change
@@ -409,5 +409,20 @@ ruleTester.run('jsx-key', rule, {
409409
{ messageId: 'missingIterKey' },
410410
],
411411
},
412+
{
413+
code: `
414+
const TestCase = () => {
415+
const list = [1, 2, 3, 4, 5];
416+
417+
return (
418+
<div>
419+
{list.map(x => <div {...spread} key={x} />)}
420+
</div>
421+
);
422+
};
423+
`,
424+
options: [{ checkKeyMustBeforeSpread: true }],
425+
errors: [{ messageId: 'keyBeforeSpread' }],
426+
},
412427
]),
413428
});

0 commit comments

Comments
 (0)