diff --git a/README.md b/README.md
index 463cff4ceb..77decc5a46 100644
--- a/README.md
+++ b/README.md
@@ -169,7 +169,7 @@ Enable the rules that you would like to use.
* [react/jsx-no-literals](docs/rules/jsx-no-literals.md): Prevent usage of unwrapped JSX strings
* [react/jsx-no-target-blank](docs/rules/jsx-no-target-blank.md): Prevent usage of unsafe `target='_blank'`
* [react/jsx-no-undef](docs/rules/jsx-no-undef.md): Disallow undeclared variables in JSX
-* [react/jsx-no-useless-fragment](docs/rules/jsx-no-useless-fragment.md): Disallow fragments with less than 2 children
+* [react/jsx-no-useless-fragment](docs/rules/jsx-no-useless-fragment.md): Disallow unnescessary fragments
* [react/jsx-one-expression-per-line](docs/rules/jsx-one-expression-per-line.md): Limit to one expression per line in JSX
* [react/jsx-curly-brace-presence](docs/rules/jsx-curly-brace-presence.md): Enforce curly braces or disallow unnecessary curly braces in JSX
* [react/jsx-fragments](docs/rules/jsx-fragments.md): Enforce shorthand or standard form for React fragments
diff --git a/docs/rules/jsx-no-useless-fragment.md b/docs/rules/jsx-no-useless-fragment.md
index 8e2f9e3fed..a096d133d4 100644
--- a/docs/rules/jsx-no-useless-fragment.md
+++ b/docs/rules/jsx-no-useless-fragment.md
@@ -1,6 +1,6 @@
-# Disallow fragments with less than 2 children (react/jsx-no-useless-fragment)
+# Disallow unnecessary fragments (react/jsx-no-useless-fragment)
-A fragment is redundant if it only wraps a single child.
+A fragment is redundant if it contains only one child, or if it is the child of a html element.
## Rule Details
@@ -18,6 +18,13 @@ The following patterns are considered warnings:
foo
foo
+
+
```
The following patterns are **not** considered warnings:
@@ -31,4 +38,11 @@ The following patterns are **not** considered warnings:
<>foo {bar}>
<> {foo}>
+
+
+ <>
+
+
+ >
+
```
diff --git a/lib/rules/jsx-no-useless-fragment.js b/lib/rules/jsx-no-useless-fragment.js
index 5a0380cd5c..9c9d5f9b33 100644
--- a/lib/rules/jsx-no-useless-fragment.js
+++ b/lib/rules/jsx-no-useless-fragment.js
@@ -62,7 +62,8 @@ module.exports = {
url: docsUrl('jsx-no-useless-fragment')
},
messages: {
- NeedsMoreChidren: 'Fragments should contain more than one child.'
+ NeedsMoreChidren: 'Fragments should contain more than one child.',
+ ChildOfHtmlElement: 'Fragment in a html element is useless.'
}
},
@@ -79,22 +80,39 @@ module.exports = {
) < 2;
}
- function checkChildrenLength(node) {
+ /**
+ * @param {JSXElement|JSXFragment} node
+ * @returns {boolean}
+ */
+ function isChildOfHtmlElement(node) {
+ return node.parent.type === 'JSXElement'
+ && node.parent.openingElement.name.type === 'JSXIdentifier'
+ && /^[a-z]+$/.test(node.parent.openingElement.name.name);
+ }
+
+ function checkNode(node) {
if (hasLessThanTwoChildren(node)) {
context.report({
node,
messageId: 'NeedsMoreChidren'
});
}
+
+ if (isChildOfHtmlElement(node)) {
+ context.report({
+ node,
+ messageId: 'ChildOfHtmlElement'
+ });
+ }
}
return {
JSXElement(node) {
if (isFragment(node, context)) {
- checkChildrenLength(node);
+ checkNode(node);
}
},
- JSXFragment: checkChildrenLength
+ JSXFragment: checkNode
};
}
};
diff --git a/lib/types.d.ts b/lib/types.d.ts
index d1ae21f948..91e5b4bd48 100644
--- a/lib/types.d.ts
+++ b/lib/types.d.ts
@@ -9,6 +9,8 @@ declare global {
type Token = eslint.AST.Token;
type Fixer = eslint.Rule.RuleFixer;
type JSXAttribute = ASTNode;
+ type JSXElement = ASTNode;
+ type JSXFragment = ASTNode;
type JSXSpreadAttribute = ASTNode;
interface Context extends eslint.SourceCode {
diff --git a/tests/lib/rules/jsx-no-useless-fragment.js b/tests/lib/rules/jsx-no-useless-fragment.js
index eb53b73a15..4c7d887009 100644
--- a/tests/lib/rules/jsx-no-useless-fragment.js
+++ b/tests/lib/rules/jsx-no-useless-fragment.js
@@ -47,7 +47,15 @@ ruleTester.run('jsx-no-uselses-fragment', rule, {
},
'',
'',
- ''
+ '',
+ {
+ code: '<>>',
+ parser: parsers.BABEL_ESLINT
+ },
+ {
+ code: '
{"a"}{"b"}>} />',
+ parser: parsers.BABEL_ESLINT
+ }
],
invalid: [
{
@@ -95,6 +103,31 @@ ruleTester.run('jsx-no-uselses-fragment', rule, {
code: '<>>',
errors: [{messageId: 'NeedsMoreChidren'}],
parser: parsers.BABEL_ESLINT
+ },
+ {
+ code: '
<>foo>
',
+ errors: [{messageId: 'NeedsMoreChidren'}, {messageId: 'ChildOfHtmlElement'}],
+ parser: parsers.BABEL_ESLINT
+ },
+ {
+ code: '
<>{"a"}{"b"}>
',
+ errors: [{messageId: 'ChildOfHtmlElement'}],
+ parser: parsers.BABEL_ESLINT
+ },
+ {
+ code: `
+
`,
+ errors: [{messageId: 'ChildOfHtmlElement'}],
+ parser: parsers.BABEL_ESLINT
+ },
+
+ {
+ code: '
{"a"}{"b"}
',
+ errors: [{messageId: 'ChildOfHtmlElement'}]
}
]
});