diff --git a/docs/rules/jsx-one-expression-per-line.md b/docs/rules/jsx-one-expression-per-line.md
index 972b56cea4..390f786e81 100644
--- a/docs/rules/jsx-one-expression-per-line.md
+++ b/docs/rules/jsx-one-expression-per-line.md
@@ -102,3 +102,31 @@ The following patterns are **not** warnings:
```
+
+## Rule Options
+
+```js
+...
+"react/jsx-one-expression-per-line": [, { "allow": "none"|"literal"|"single-child" }]
+...
+```
+
+### `allow`
+
+Defaults to `none`.
+
+The following pattern is **not** considered a warning when configured as `"literal"`:
+
+```jsx
+Hello
+```
+
+The following patterns are **not** considered warnings when configured as `"single-child"`:
+
+```jsx
+Hello
+
+{"Hello"}
+
+
+```
diff --git a/lib/rules/jsx-one-expression-per-line.js b/lib/rules/jsx-one-expression-per-line.js
index 7be01233e1..cc14ad8323 100644
--- a/lib/rules/jsx-one-expression-per-line.js
+++ b/lib/rules/jsx-one-expression-per-line.js
@@ -11,6 +11,10 @@ const docsUrl = require('../util/docsUrl');
// Rule Definition
// ------------------------------------------------------------------------------
+const optionDefaults = {
+ allow: 'none'
+};
+
module.exports = {
meta: {
docs: {
@@ -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) {
@@ -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 = {};
diff --git a/tests/lib/rules/jsx-one-expression-per-line.js b/tests/lib/rules/jsx-one-expression-per-line.js
index 173d611554..0ca57b8882 100644
--- a/tests/lib/rules/jsx-one-expression-per-line.js
+++ b/tests/lib/rules/jsx-one-expression-per-line.js
@@ -84,6 +84,24 @@ ruleTester.run('jsx-one-expression-per-line', rule, {
'App',
'>'
].join('\n')
+ }, {
+ code: 'foo',
+ options: [{allow: 'literal'}]
+ }, {
+ code: '123',
+ options: [{allow: 'literal'}]
+ }, {
+ code: 'foo',
+ options: [{allow: 'single-child'}]
+ }, {
+ code: '{"foo"}',
+ options: [{allow: 'single-child'}]
+ }, {
+ code: '{foo && }',
+ options: [{allow: 'single-child'}]
+ }, {
+ code: '',
+ options: [{allow: 'single-child'}]
}],
invalid: [{
@@ -852,5 +870,84 @@ ruleTester.run('jsx-one-expression-per-line', rule, {
{message: '`{ foo}` must be placed on a new line'}
],
parserOptions: parserOptions
+ }, {
+ code: '',
+ options: [{allow: 'none'}],
+ output: [
+ '',
+ '',
+ ''
+ ].join('\n'),
+ errors: [{message: '`Foo` must be placed on a new line'}]
+ }, {
+ code: 'foo',
+ options: [{allow: 'none'}],
+ output: [
+ '',
+ 'foo',
+ ''
+ ].join('\n'),
+ errors: [{message: '`foo` must be placed on a new line'}]
+ }, {
+ code: '{"foo"}',
+ options: [{allow: 'none'}],
+ output: [
+ '',
+ '{"foo"}',
+ ''
+ ].join('\n'),
+ errors: [{message: '`{"foo"}` must be placed on a new line'}]
+ }, {
+ code: [
+ 'foo',
+ ''
+ ].join('\n'),
+ options: [{allow: 'literal'}],
+ output: [
+ '',
+ 'foo',
+ ''
+ ].join('\n'),
+ errors: [{message: '`foo` must be placed on a new line'}]
+ }, {
+ code: '',
+ options: [{allow: 'literal'}],
+ output: [
+ '',
+ '',
+ ''
+ ].join('\n'),
+ errors: [{message: '`Foo` must be placed on a new line'}]
+ }, {
+ code: [
+ 'baz'
+ ].join('\n'),
+ options: [{allow: 'literal'}],
+ output: [
+ '',
+ 'baz',
+ ''
+ ].join('\n'),
+ errors: [{message: '`baz` must be placed on a new line'}]
+ }, {
+ code: [
+ 'foo',
+ 'bar',
+ ''
+ ].join('\n'),
+ options: [{allow: 'literal'}],
+ output: [
+ '',
+ 'foo',
+ 'bar',
+ ''
+ ].join('\n'),
+ errors: [{message: '`foobar` must be placed on a new line'}]
}]
});