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'}] }] });