Skip to content

Commit c52b61b

Browse files
authored
Merge pull request #2316 from kaykayehnn/jsx-key-fragments
fix(jsx-key): handle shorthand fragment syntax
2 parents 8db631b + 0364ed2 commit c52b61b

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

lib/rules/jsx-key.js

+36-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ const docsUrl = require('../util/docsUrl');
1313
// Rule Definition
1414
// ------------------------------------------------------------------------------
1515

16+
const defaultOptions = {
17+
checkFragmentShorthand: false
18+
};
19+
1620
module.exports = {
1721
meta: {
1822
docs: {
@@ -21,16 +25,33 @@ module.exports = {
2125
recommended: true,
2226
url: docsUrl('jsx-key')
2327
},
24-
schema: []
28+
schema: [{
29+
type: 'object',
30+
properties: {
31+
checkFragmentShorthand: {
32+
type: 'boolean',
33+
default: defaultOptions.checkFragmentShorthand
34+
}
35+
},
36+
additionalProperties: false
37+
}]
2538
},
2639

2740
create(context) {
41+
const options = Object.assign({}, defaultOptions, context.options[0]);
42+
const checkFragmentShorthand = options.checkFragmentShorthand;
43+
2844
function checkIteratorElement(node) {
2945
if (node.type === 'JSXElement' && !hasProp(node.openingElement.attributes, 'key')) {
3046
context.report({
3147
node,
3248
message: 'Missing "key" prop for element in iterator'
3349
});
50+
} else if (checkFragmentShorthand && node.type === 'JSXFragment') {
51+
context.report({
52+
node,
53+
message: 'Missing "key" prop for element in iterator. Shorthand fragment syntax does support providing keys'
54+
});
3455
}
3556
}
3657

@@ -52,6 +73,19 @@ module.exports = {
5273
}
5374
},
5475

76+
JSXFragment(node) {
77+
if (!checkFragmentShorthand) {
78+
return;
79+
}
80+
81+
if (node.parent.type === 'ArrayExpression') {
82+
context.report({
83+
node,
84+
message: 'Missing "key" prop for element in array. Shorthand fragment syntax does support providing keys'
85+
});
86+
}
87+
},
88+
5589
// Array.prototype.map
5690
CallExpression(node) {
5791
if (node.callee && node.callee.type !== 'MemberExpression') {
@@ -66,7 +100,7 @@ module.exports = {
66100
const isFn = fn && fn.type === 'FunctionExpression';
67101
const isArrFn = fn && fn.type === 'ArrowFunctionExpression';
68102

69-
if (isArrFn && fn.body.type === 'JSXElement') {
103+
if (isArrFn && (fn.body.type === 'JSXElement' || fn.body.type === 'JSXFragment')) {
70104
checkIteratorElement(fn.body);
71105
}
72106

tests/lib/rules/jsx-key.js

+15-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
const RuleTester = require('eslint').RuleTester;
1313
const rule = require('../../../lib/rules/jsx-key');
1414

15+
const parsers = require('../../helpers/parsers');
16+
1517
const parserOptions = {
1618
ecmaVersion: 2018,
1719
sourceType: 'module',
@@ -37,7 +39,9 @@ ruleTester.run('jsx-key', rule, {
3739
{code: '[1, 2, 3].foo(x => <App />);'},
3840
{code: 'var App = () => <div />;'},
3941
{code: '[1, 2, 3].map(function(x) { return; });'},
40-
{code: 'foo(() => <div />);'}
42+
{code: 'foo(() => <div />);'},
43+
{code: 'foo(() => <></>);', parser: parsers.BABEL_ESLINT},
44+
{code: '<></>;', parser: parsers.BABEL_ESLINT}
4145
],
4246
invalid: [{
4347
code: '[<App />];',
@@ -57,5 +61,15 @@ ruleTester.run('jsx-key', rule, {
5761
}, {
5862
code: '[1, 2 ,3].map(x => { return <App /> });',
5963
errors: [{message: 'Missing "key" prop for element in iterator'}]
64+
}, {
65+
code: '[1, 2, 3].map(x => <>{x}</>);',
66+
parser: parsers.BABEL_ESLINT,
67+
options: [{checkFragmentShorthand: true}],
68+
errors: [{message: 'Missing "key" prop for element in iterator. Shorthand fragment syntax does support providing keys'}]
69+
}, {
70+
code: '[<></>];',
71+
parser: parsers.BABEL_ESLINT,
72+
options: [{checkFragmentShorthand: true}],
73+
errors: [{message: 'Missing "key" prop for element in array. Shorthand fragment syntax does support providing keys'}]
6074
}]
6175
});

0 commit comments

Comments
 (0)