From 91d4f400a4f7701c01b4cbb8f88d8f2df8e12110 Mon Sep 17 00:00:00 2001 From: Alex Rattray Date: Tue, 7 Feb 2017 10:47:34 -0800 Subject: [PATCH] [JSX] jsx-whitespace breaks with parent (fixes #622) (#626) --- src/printer.js | 81 ++++++++++--------- .../__snapshots__/jsfmt.spec.js.snap | 2 +- .../__snapshots__/jsfmt.spec.js.snap | 47 +++++++++++ tests/jsx-significant-space/test.js | 15 ++++ 4 files changed, 104 insertions(+), 41 deletions(-) diff --git a/src/printer.js b/src/printer.js index dc4c9d95..f3cef8d0 100644 --- a/src/printer.js +++ b/src/printer.js @@ -2270,12 +2270,9 @@ function isEmptyJSXElement(node) { // // For another, leading, trailing, and lone whitespace all need to // turn themselves into the rather ugly `{' '}` when breaking. -function printJSXChildren(path, options, print) { +function printJSXChildren(path, options, print, jsxWhitespace) { const n = path.getValue(); const children = []; - const jsxWhitespace = options.singleQuote - ? ifBreak("{' '}", " ") - : ifBreak('{" "}', " "); // using `map` instead of `each` because it provides `i` path.map( @@ -2385,7 +2382,10 @@ function printJSXElement(path, options, print) { return openingLines; } - const children = printJSXChildren(path, options, print); + const jsxWhitespace = options.singleQuote + ? ifBreak("{' '}", " ") + : ifBreak('{" "}', " "); + const children = printJSXChildren(path, options, print, jsxWhitespace); let forcedBreak = false; // Trim trailing lines, recording if there was a hardline @@ -2417,46 +2417,47 @@ function printJSXElement(path, options, print) { } // Group by line, recording if there was a hardline. - let childrenGroupedByLine; - if (children.length === 1) { - if (!forcedBreak && willBreak(children[0])) { - forcedBreak = true; + let groups = [[]]; // Initialize the first line's group + children.forEach((child, i) => { + // leading and trailing JSX whitespace don't go into a group + if (child === jsxWhitespace) { + if (i === 0) { + groups.unshift(child); + return; + } else if (i === children.length - 1) { + groups.push(child); + return; + } } - // Don't wrap a single child in a group as there is no need, and a - // lone JSX whitespace doesn't work otherwise because the group - // will be printed in flat mode, and we need to print `{' '}` in - // break mode. - childrenGroupedByLine = [concat([hardline, children[0]])]; - } else { - // Prefill leading newline, and initialize the first line's group - let groups = [[]]; - children.forEach((child, i) => { - let prev = children[i - 1]; - if (prev && willBreak(prev)) { - forcedBreak = true; + let prev = children[i - 1]; + if (prev && willBreak(prev)) { + forcedBreak = true; - // On a new line, so create a new group and put this element - // in it. - groups.push([child]); - } else { - // Not on a newline, so add this element to the current group. - util.getLast(groups).push(child); - } + // On a new line, so create a new group and put this element in it. + groups.push([child]); + } else { + // Not on a newline, so add this element to the current group. + util.getLast(groups).push(child); + } - // Ensure we record hardline of last element. - if (!forcedBreak && i === children.length - 1) { - if (willBreak(child)) forcedBreak = true; - } - }); + // Ensure we record hardline of last element. + if (!forcedBreak && i === children.length - 1) { + if (willBreak(child)) forcedBreak = true; + } + }); - childrenGroupedByLine = [ - hardline, - // Conditional groups suppress break propagation; we want output - // hard lines without breaking up the entire jsx element. - concat(groups.map(contents => conditionalGroup([concat(contents)]))) - ]; - } + const childrenGroupedByLine = [ + hardline, + // Conditional groups suppress break propagation; we want to output + // hard lines without breaking up the entire jsx element. + // Note that leading and trailing JSX Whitespace don't go into a group. + concat(groups.map(contents => + Array.isArray(contents) + ? conditionalGroup([concat(contents)]) + : contents + )) + ]; const closingLines = path.call(print, "closingElement"); diff --git a/tests/flow/more_react/__snapshots__/jsfmt.spec.js.snap b/tests/flow/more_react/__snapshots__/jsfmt.spec.js.snap index 4bebcc2b..3a2682fd 100644 --- a/tests/flow/more_react/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/more_react/__snapshots__/jsfmt.spec.js.snap @@ -126,7 +126,7 @@ var App = require(\"App.react\"); var app = ( - // error, y: number but foo expects string in App.react + {\" \"}// error, y: number but foo expects string in App.react Some text. ); diff --git a/tests/jsx-significant-space/__snapshots__/jsfmt.spec.js.snap b/tests/jsx-significant-space/__snapshots__/jsfmt.spec.js.snap index 177f1bf3..e48419f1 100644 --- a/tests/jsx-significant-space/__snapshots__/jsfmt.spec.js.snap +++ b/tests/jsx-significant-space/__snapshots__/jsfmt.spec.js.snap @@ -48,6 +48,21 @@ nest_plz =
+ +regression_not_transformed_1 = + ; + +regression_not_transformed_2 = + ; + +similar_1 = + ; + +similar_2 = + ; + +similar_3 = + ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ after = ( @@ -113,5 +128,37 @@ nest_plz = ( ); + +regression_not_transformed_1 = ( + + {\" \"} + +); + +regression_not_transformed_2 = ( + + {\" \"} + +); + +similar_1 = ( + + {\" \"} + + +); + +similar_2 = ( + + + {\" \"} + +); + +similar_3 = ( + + + +); " `; diff --git a/tests/jsx-significant-space/test.js b/tests/jsx-significant-space/test.js index c3926439..31354e0c 100644 --- a/tests/jsx-significant-space/test.js +++ b/tests/jsx-significant-space/test.js @@ -47,3 +47,18 @@ nest_plz =
+ +regression_not_transformed_1 = + ; + +regression_not_transformed_2 = + ; + +similar_1 = + ; + +similar_2 = + ; + +similar_3 = + ;