Skip to content

Commit

Permalink
Start reporting fragments in html element
Browse files Browse the repository at this point in the history
  • Loading branch information
golopot committed May 16, 2019
1 parent 6d9acd1 commit 4bdeb5c
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 8 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -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
Expand Down
18 changes: 16 additions & 2 deletions 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

Expand All @@ -18,6 +18,13 @@ The following patterns are considered warnings:
<Fragment>foo</Fragment>

<React.Fragment>foo</React.Fragment>

<section>
<>
<div />
<div />
</>
</section>
```

The following patterns are **not** considered warnings:
Expand All @@ -31,4 +38,11 @@ The following patterns are **not** considered warnings:
<>foo {bar}</>

<> {foo}</>

<SomeComponent>
<>
<div />
<div />
</>
</SomeComponent>
```
26 changes: 22 additions & 4 deletions lib/rules/jsx-no-useless-fragment.js
Expand Up @@ -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.'
}
},

Expand All @@ -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
};
}
};
2 changes: 2 additions & 0 deletions lib/types.d.ts
Expand Up @@ -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 {
Expand Down
35 changes: 34 additions & 1 deletion tests/lib/rules/jsx-no-useless-fragment.js
Expand Up @@ -47,7 +47,15 @@ ruleTester.run('jsx-no-uselses-fragment', rule, {
},
'<NotFragment />',
'<React.NotFragment />',
'<NotReact.Fragment />'
'<NotReact.Fragment />',
{
code: '<Foo><><div /><div /></></Foo>',
parser: parsers.BABEL_ESLINT
},
{
code: '<div p={<>{"a"}{"b"}</>} />',
parser: parsers.BABEL_ESLINT
}
],
invalid: [
{
Expand Down Expand Up @@ -95,6 +103,31 @@ ruleTester.run('jsx-no-uselses-fragment', rule, {
code: '<></>',
errors: [{messageId: 'NeedsMoreChidren'}],
parser: parsers.BABEL_ESLINT
},
{
code: '<div><>foo</></div>',
errors: [{messageId: 'NeedsMoreChidren'}, {messageId: 'ChildOfHtmlElement'}],
parser: parsers.BABEL_ESLINT
},
{
code: '<div><>{"a"}{"b"}</></div>',
errors: [{messageId: 'ChildOfHtmlElement'}],
parser: parsers.BABEL_ESLINT
},
{
code: `
<section>
<Eeee />
<Eeee />
<>{"a"}{"b"}</>
</section>`,
errors: [{messageId: 'ChildOfHtmlElement'}],
parser: parsers.BABEL_ESLINT
},

{
code: '<div><Fragment>{"a"}{"b"}</Fragment></div>',
errors: [{messageId: 'ChildOfHtmlElement'}]
}
]
});

0 comments on commit 4bdeb5c

Please sign in to comment.