Skip to content

Commit

Permalink
[New] add jsx-no-padded-children
Browse files Browse the repository at this point in the history
Fixes #2045
  • Loading branch information
golopot committed Mar 22, 2019
1 parent 6bb1604 commit a02a634
Show file tree
Hide file tree
Showing 4 changed files with 356 additions and 0 deletions.
40 changes: 40 additions & 0 deletions docs/rules/jsx-no-padded-children.md
@@ -0,0 +1,40 @@
# Disallow padding blank lines in a jsx element (react/jsx-no-padded-children)

**Fixable:** This rule is automatically fixable using the `--fix` flag on the command line.

## Rule Details

This rule will disallow padding blank lines in the start and end of a jsx element.

The following patterns are considered warnings:

```jsx
var Hello = <div>
test

</div>;
```

```jsx
var Hello = <div>


<Foo />
</div>;
```

The following patterns are **not** considered warnings:

```jsx
var Hello = <div> {'test'} </div>;
```

```jsx
var Hello = <div>
{'test'}
</div>;
```

## When Not To Use It

You can turn this rule off if you are not concerned with the consistency of padding blank lines in jsx element.
1 change: 1 addition & 0 deletions index.js
Expand Up @@ -32,6 +32,7 @@ const allRules = {
'jsx-no-duplicate-props': require('./lib/rules/jsx-no-duplicate-props'),
'jsx-no-literals': require('./lib/rules/jsx-no-literals'),
'jsx-no-target-blank': require('./lib/rules/jsx-no-target-blank'),
'jsx-no-padded-children': require('./lib/rules/jsx-no-padded-children'),
'jsx-one-expression-per-line': require('./lib/rules/jsx-one-expression-per-line'),
'jsx-no-undef': require('./lib/rules/jsx-no-undef'),
'jsx-curly-brace-presence': require('./lib/rules/jsx-curly-brace-presence'),
Expand Down
104 changes: 104 additions & 0 deletions lib/rules/jsx-no-padded-children.js
@@ -0,0 +1,104 @@
/**
* @fileoverview Disallow padding blank lines in the children of a JSX element
* @author Jiawen Chen
*/

'use strict';

const docsUrl = require('../util/docsUrl');

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = {
meta: {
docs: {
description: 'Disallow padding blank lines in the children of a JSX element.',
category: 'Stylistic Issues',
recommended: false,
url: docsUrl('jsx-no-padded-children')
},
fixable: 'whitespace',
type: 'layout'
},

create: function(context) {
const message = 'JSX children must not be padded by blank lines.';

/**
* Test wether input string has 2 or more `\n` .
* @param {string} str String to test
* @returns {boolean} Result
*/
function hasTwoNewlines(str) {
let count = 0;
for (const c of str) {
if (c === '\n') {
count += 1;
if (count >= 2) {
return true;
}
}
}
return false;
}


function checkPaddingTop (node) {
const child = node.children[0];

if (child && (child.type === 'JSXText' || child.type === 'Literal')) {
const {0: leadingSpaces} = /^\s*/.exec(child.raw) || {};

if (leadingSpaces && hasTwoNewlines(leadingSpaces)) {
context.report({
node: child,
message,
fix(fixer) {
return fixer.removeRange([
child.start + leadingSpaces.indexOf('\n'),
child.start + leadingSpaces.lastIndexOf('\n')
]);
}
});
}
}
}

function checkPaddingBottom (node) {
const child = node.children[node.children.length - 1];

if (child && (child.type === 'JSXText' || child.type === 'Literal')) {
const {0: trailingSpaces, index: paddingStart} = /\s*$/.exec(child.raw) || {};

if (trailingSpaces && hasTwoNewlines(trailingSpaces)) {
context.report({
node: child,
message,
fix(fixer) {
return fixer.removeRange([
child.start + paddingStart + trailingSpaces.indexOf('\n'),
child.start + paddingStart + trailingSpaces.lastIndexOf('\n')
]);
}
});
}
}
}

function checkElement(node) {
if (node.children.length === 1 && /^\s*$/.test(node.children[0].raw)) {
checkPaddingTop(node);
return;
}
checkPaddingTop(node);
checkPaddingBottom(node);
}

return {
JSXElement: checkElement,
JSXFragment: checkElement
};
}
};
211 changes: 211 additions & 0 deletions tests/lib/rules/jsx-no-padded-children.js
@@ -0,0 +1,211 @@
/**
* @fileoverview Test for js-no-padded-children
**/
'use strict';

const rule = require('../../../lib/rules/jsx-no-padded-children');
const {RuleTester} = require('eslint');

const parserOptions = {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
jsx: true
}
};

const ruleTester = new RuleTester({parserOptions});

const message = 'JSX children must not be padded by blank lines.';

ruleTester.run('jsx-no-padded-children', rule, {
valid: [
'<div><Foo /></div>',

`
<div>
<Foo />
</div>`,

`
<div>
foo
<Foo />
</div>`,

{
code: `
<>{\`
\`}</>`,
parser: 'babel-eslint'
}
],

invalid: [
{
code: `
<div>
</div>`,
output: `
<div>
</div>`,
errors: [{message}]
},
{
code: [
'<div>',
' ',
' ',
'</div>'
].join('\r\n'),
output: [
'<div>',
'</div>'
].join('\r\n'),
errors: [{message}]
},
{
code: `
<div>
\ \t
<Foo />
</div>`,
output: `
<div>
<Foo />
</div>`,
errors: [{message}]
},
{
code: `
<div>
<Foo />
</div>`,
output: `
<div>
<Foo />
</div>`,
errors: [{message}]
},
{
code: `
<div>
<Foo />
\ \r \t
</div>`,
output: `
<div>
<Foo />
</div>`,
errors: [{message}, {message}]
},
{
code: `
<div>
<Foo />
\ \t
</div>`,
output: `
<div>
<Foo />
</div>`,
errors: [{message}]
},
{
code: `
<div>
\r \t
foo
\r \t
</div>`,
output: `
<div>
foo
</div>`,
errors: [{message}, {message}]
},
{
code: `
<div>
foo
\r \t
</div>`,
output: `
<div>
foo
</div>`,
errors: [{message}]
},

{
code: [
'<div>',
' ',
' <Foo />',
' ',
'</div>'
].join('\r\n'),
output: [
'<div>',
' <Foo />',
'</div>'
].join('\r\n'),
errors: [{message}, {message}]
},
{
code: `
<div>
<>
\ \t \r
</>
</div>`,
output: `
<div>
<>
</>
</div>`,
errors: [{message}, {message}, {message}],
parser: 'babel-eslint'
},
{
code: `
<div>
{'foo'}
foo
{'bar'}
</div>`,
output: `
<div>
{'foo'}
foo
{'bar'}
</div>`,
errors: [{message}, {message}],
parser: 'babel-eslint'
}
]
});

0 comments on commit a02a634

Please sign in to comment.