diff --git a/lib/rules/jsx-wrap-multilines.js b/lib/rules/jsx-wrap-multilines.js index 0e2223f5e6..a42741eeb0 100644 --- a/lib/rules/jsx-wrap-multilines.js +++ b/lib/rules/jsx-wrap-multilines.js @@ -104,14 +104,21 @@ module.exports = { return node.loc.start.line !== node.loc.end.line; } - function report(node, message, fixerFn) { + function report(node, message, fix) { context.report({ - node: node, - message: message, - fix: fixerFn + node, + message, + fix }); } + function trimTokenBeforeNewline(node, tokenBefore) { + // if the token before the jsx is a bracket or curly brace + // we don't want a space between the opening parentheses and the multiline jsx + const isBracket = tokenBefore.value === '{' || tokenBefore.value === '['; + return `${tokenBefore.value.trim()}${isBracket ? '' : ' '}`; + } + function check(node, type) { if (!node || node.type !== 'JSXElement') { return; @@ -125,7 +132,21 @@ module.exports = { if (option === 'parens-new-line' && isMultilines(node)) { if (!isParenthesised(node)) { - report(node, MISSING_PARENS, fixer => fixer.replaceText(node, `(\n${sourceCode.getText(node)}\n)`)); + const tokenBefore = sourceCode.getTokenBefore(node, {includeComments: true}); + const tokenAfter = sourceCode.getTokenAfter(node, {includeComments: true}); + if (tokenBefore.loc.end.line < node.loc.start.line) { + // Strip newline after operator if parens newline is specified + report( + node, + MISSING_PARENS, + fixer => fixer.replaceTextRange( + [tokenBefore.range[0], tokenAfter.range[0]], + `${trimTokenBeforeNewline(node, tokenBefore)}(\n${sourceCode.getText(node)}\n)` + ) + ); + } else { + report(node, MISSING_PARENS, fixer => fixer.replaceText(node, `(\n${sourceCode.getText(node)}\n)`)); + } } else if (needsNewLines(node)) { report(node, PARENS_NEW_LINES, fixer => fixer.replaceText(node, `\n${sourceCode.getText(node)}\n`)); } @@ -171,7 +192,7 @@ module.exports = { } }, - 'ArrowFunctionExpression:exit': function (node) { + 'ArrowFunctionExpression:exit': function(node) { const arrowBody = node.body; const type = 'arrow'; @@ -195,7 +216,7 @@ module.exports = { } }, - JSXAttribute: function (node) { + JSXAttribute: function(node) { const type = 'prop'; if (isEnabled(type) && node.value && node.value.type === 'JSXExpressionContainer') { check(node.value.expression, type); diff --git a/tests/lib/rules/jsx-wrap-multilines.js b/tests/lib/rules/jsx-wrap-multilines.js index 202e308387..14727136af 100644 --- a/tests/lib/rules/jsx-wrap-multilines.js +++ b/tests/lib/rules/jsx-wrap-multilines.js @@ -249,6 +249,16 @@ const LOGICAL_NO_PAREN = ` `; +const LOGICAL_PAREN_NEW_LINE_AUTOFIX = ` +
Hello World
+Hello
+Hello
+ +`; + function addNewLineSymbols(code) { return code.replace(/\(\)/g, '>\n)'); } @@ -640,7 +660,7 @@ ruleTester.run('jsx-wrap-multilines', rule, { errors: [{message: PARENS_NEW_LINES}] }, { code: LOGICAL_NO_PAREN, - output: addNewLineSymbols(LOGICAL_PAREN), + output: LOGICAL_PAREN_NEW_LINE_AUTOFIX, options: [{logical: 'parens-new-line'}], errors: [{message: MISSING_PARENS}] }, { @@ -650,9 +670,8 @@ ruleTester.run('jsx-wrap-multilines', rule, { errors: [{message: PARENS_NEW_LINES}] }, { code: ATTR_NO_PAREN, - output: addNewLineSymbols(ATTR_PAREN), + output: ATTR_PAREN_NEW_LINE_AUTOFIX, options: [{prop: 'parens-new-line'}], errors: [{message: MISSING_PARENS}] - } - ] + }] });