Skip to content

Commit

Permalink
Merge pull request #1924 from alexzherdev/1775-one-expression-options
Browse files Browse the repository at this point in the history
[New] Add allow option to jsx-one-expression-per-line
  • Loading branch information
ljharb committed Aug 13, 2018
2 parents c1c3d19 + 3567c5b commit 1eccf7f
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 1 deletion.
28 changes: 28 additions & 0 deletions docs/rules/jsx-one-expression-per-line.md
Expand Up @@ -102,3 +102,31 @@ The following patterns are **not** warnings:
<Hello3 />
</App>
```

## Rule Options

```js
...
"react/jsx-one-expression-per-line": [<enabled>, { "allow": "none"|"literal"|"single-child" }]
...
```

### `allow`

Defaults to `none`.

The following pattern is **not** considered a warning when configured as `"literal"`:

```jsx
<App>Hello</App>
```

The following patterns are **not** considered warnings when configured as `"single-child"`:

```jsx
<App>Hello</App>

<App>{"Hello"}</App>

<App><Hello /></App>
```
38 changes: 37 additions & 1 deletion lib/rules/jsx-one-expression-per-line.js
Expand Up @@ -11,6 +11,10 @@ const docsUrl = require('../util/docsUrl');
// Rule Definition
// ------------------------------------------------------------------------------

const optionDefaults = {
allow: 'none'
};

module.exports = {
meta: {
docs: {
Expand All @@ -20,10 +24,22 @@ module.exports = {
url: docsUrl('jsx-one-expression-per-line')
},
fixable: 'whitespace',
schema: []
schema: [
{
type: 'object',
properties: {
allow: {
enum: ['none', 'literal', 'single-child']
}
},
default: optionDefaults,
additionalProperties: false
}
]
},

create: function (context) {
const options = Object.assign({}, optionDefaults, context.options[0]);
const sourceCode = context.getSourceCode();

function nodeKey (node) {
Expand All @@ -44,8 +60,28 @@ module.exports = {

const openingElement = node.openingElement;
const closingElement = node.closingElement;
const openingElementStartLine = openingElement.loc.start.line;
const openingElementEndLine = openingElement.loc.end.line;
const closingElementStartLine = closingElement.loc.start.line;
const closingElementEndLine = closingElement.loc.end.line;

if (children.length === 1) {
const child = children[0];
if (
openingElementStartLine === openingElementEndLine &&
openingElementEndLine === closingElementStartLine &&
closingElementStartLine === closingElementEndLine &&
closingElementEndLine === child.loc.start.line &&
child.loc.start.line === child.loc.end.line
) {
if (
options.allow === 'single-child' ||
options.allow === 'literal' && (child.type === 'Literal' || child.type === 'JSXText')
) {
return;
}
}
}

const childrenGroupedByLine = {};
const fixDetailsByNode = {};
Expand Down
97 changes: 97 additions & 0 deletions tests/lib/rules/jsx-one-expression-per-line.js
Expand Up @@ -84,6 +84,24 @@ ruleTester.run('jsx-one-expression-per-line', rule, {
'App',
'>'
].join('\n')
}, {
code: '<App>foo</App>',
options: [{allow: 'literal'}]
}, {
code: '<App>123</App>',
options: [{allow: 'literal'}]
}, {
code: '<App>foo</App>',
options: [{allow: 'single-child'}]
}, {
code: '<App>{"foo"}</App>',
options: [{allow: 'single-child'}]
}, {
code: '<App>{foo && <Bar />}</App>',
options: [{allow: 'single-child'}]
}, {
code: '<App><Foo /></App>',
options: [{allow: 'single-child'}]
}],

invalid: [{
Expand Down Expand Up @@ -852,5 +870,84 @@ ruleTester.run('jsx-one-expression-per-line', rule, {
{message: '`{ foo}` must be placed on a new line'}
],
parserOptions: parserOptions
}, {
code: '<App><Foo /></App>',
options: [{allow: 'none'}],
output: [
'<App>',
'<Foo />',
'</App>'
].join('\n'),
errors: [{message: '`Foo` must be placed on a new line'}]
}, {
code: '<App>foo</App>',
options: [{allow: 'none'}],
output: [
'<App>',
'foo',
'</App>'
].join('\n'),
errors: [{message: '`foo` must be placed on a new line'}]
}, {
code: '<App>{"foo"}</App>',
options: [{allow: 'none'}],
output: [
'<App>',
'{"foo"}',
'</App>'
].join('\n'),
errors: [{message: '`{"foo"}` must be placed on a new line'}]
}, {
code: [
'<App>foo',
'</App>'
].join('\n'),
options: [{allow: 'literal'}],
output: [
'<App>',
'foo',
'</App>'
].join('\n'),
errors: [{message: '`foo` must be placed on a new line'}]
}, {
code: '<App><Foo /></App>',
options: [{allow: 'literal'}],
output: [
'<App>',
'<Foo />',
'</App>'
].join('\n'),
errors: [{message: '`Foo` must be placed on a new line'}]
}, {
code: [
'<App',
' foo="1"',
' bar="2"',
'>baz</App>'
].join('\n'),
options: [{allow: 'literal'}],
output: [
'<App',
' foo="1"',
' bar="2"',
'>',
'baz',
'</App>'
].join('\n'),
errors: [{message: '`baz` must be placed on a new line'}]
}, {
code: [
'<App>foo',
'bar',
'</App>'
].join('\n'),
options: [{allow: 'literal'}],
output: [
'<App>',
'foo',
'bar',
'</App>'
].join('\n'),
errors: [{message: '`foobar` must be placed on a new line'}]
}]
});

0 comments on commit 1eccf7f

Please sign in to comment.