Allow JSX lines to be recombined (#1831)
* Allow JSX lines to be recombined * Add test case for `<br />` breaking expression * Fix issue where JSX whitespace could be dropped * Newlines were incorrectly being preserved when JSX contained textmaster
parent
39954f7951
commit
0cc0ebc3bc
238
src/printer.js
238
src/printer.js
|
@ -1565,7 +1565,7 @@ function genericPrintNoParens(path, options, print, args) {
|
|||
if (n.value) {
|
||||
let res;
|
||||
if (isStringLiteral(n.value)) {
|
||||
const value = n.value.extra ? n.value.extra.raw : n.value.raw;
|
||||
const value = rawText(n.value);
|
||||
res = '"' + value.slice(1, -1).replace(/"/g, """) + '"';
|
||||
} else {
|
||||
res = path.call(print, "value");
|
||||
|
@ -3650,6 +3650,7 @@ const jsxWhitespaceChars = " \n\r\t";
|
|||
const containsNonJsxWhitespaceRegex = new RegExp(
|
||||
"[^" + jsxWhitespaceChars + "]"
|
||||
);
|
||||
const matchJsxWhitespaceRegex = new RegExp("([" + jsxWhitespaceChars + "]+)");
|
||||
|
||||
// Meaningful if it contains non-whitespace characters,
|
||||
// or it contains whitespace without a new line.
|
||||
|
@ -3661,18 +3662,24 @@ function isMeaningfulJSXText(node) {
|
|||
);
|
||||
}
|
||||
|
||||
// Detect an expression node representing `{" "}`
|
||||
function isJSXWhitespaceExpression(node) {
|
||||
return (
|
||||
node.type === "JSXExpressionContainer" &&
|
||||
isLiteral(node.expression) &&
|
||||
node.expression.value === " "
|
||||
);
|
||||
}
|
||||
|
||||
// JSX Children are strange, mostly for two reasons:
|
||||
// 1. JSX reads newlines into string values, instead of skipping them like JS
|
||||
// 2. up to one whitespace between elements within a line is significant,
|
||||
// but not between lines.
|
||||
//
|
||||
// So for one thing, '\n' needs to be parsed out of string literals
|
||||
// and turned into hardlines (with string boundaries otherwise using softline)
|
||||
//
|
||||
// For another, leading, trailing, and lone whitespace all need to
|
||||
// Leading, trailing, and lone whitespace all need to
|
||||
// turn themselves into the rather ugly `{' '}` when breaking.
|
||||
//
|
||||
// Finally we print JSX using the `fill` doc primitive.
|
||||
// We print JSX using the `fill` doc primitive.
|
||||
// This requires that we give it an array of alternating
|
||||
// content and whitespace elements.
|
||||
// To ensure this we add dummy `""` content elements as needed.
|
||||
|
@ -3683,101 +3690,105 @@ function printJSXChildren(path, options, print, jsxWhitespace) {
|
|||
// using `map` instead of `each` because it provides `i`
|
||||
path.map((childPath, i) => {
|
||||
const child = childPath.getValue();
|
||||
if (isLiteral(child) && typeof child.value === "string") {
|
||||
const value = child.raw || child.extra.raw;
|
||||
if (isLiteral(child)) {
|
||||
const text = rawText(child);
|
||||
|
||||
// Contains a non-whitespace character
|
||||
if (/[^ \n\r\t]/.test(value)) {
|
||||
// treat each line of text as its own entity
|
||||
value.split(/(\r?\n\s*)/).forEach(textLine => {
|
||||
const newlines = textLine.match(/\n/g);
|
||||
if (newlines) {
|
||||
children.push("");
|
||||
children.push(hardline);
|
||||
if (isMeaningfulJSXText(child)) {
|
||||
const words = text.split(matchJsxWhitespaceRegex);
|
||||
|
||||
// allow one extra newline
|
||||
if (newlines.length > 1) {
|
||||
children.push("");
|
||||
children.push(hardline);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (textLine.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const beginSpace = /^[ \n\r\t]+/.test(textLine);
|
||||
if (beginSpace) {
|
||||
children.push("");
|
||||
children.push(jsxWhitespace);
|
||||
}
|
||||
|
||||
const stripped = textLine.replace(/^[ \n\r\t]+|[ \n\r\t]+$/g, "");
|
||||
// Split text into words separated by "line"s.
|
||||
stripped.split(/([ \n\r\t]+)/).forEach(word => {
|
||||
const space = /[ \n\r\t]+/.test(word);
|
||||
if (space) {
|
||||
children.push(line);
|
||||
} else {
|
||||
children.push(word);
|
||||
}
|
||||
});
|
||||
|
||||
const endSpace = /[ \n\r\t]+$/.test(textLine);
|
||||
if (endSpace) {
|
||||
children.push(jsxWhitespace);
|
||||
// Starts with whitespace
|
||||
if (words[0] === "") {
|
||||
children.push("");
|
||||
words.shift();
|
||||
if (/\n/.test(words[0])) {
|
||||
children.push(softline);
|
||||
} else {
|
||||
// Ideally this would be a `softline` to allow a break between
|
||||
// tags and text.
|
||||
// Unfortunately Facebook have a custom translation pipeline
|
||||
// (https://github.com/prettier/prettier/issues/1581#issuecomment-300975032)
|
||||
// that uses the JSX syntax, but does not follow the React whitespace
|
||||
// rules.
|
||||
// Ensuring that we never have a break between tags and text in JSX
|
||||
// will allow Facebook to adopt Prettier without too much of an
|
||||
// adverse effect on formatting algorithm.
|
||||
children.push("");
|
||||
children.push(jsxWhitespace);
|
||||
}
|
||||
words.shift();
|
||||
}
|
||||
|
||||
let endWhitespace;
|
||||
// Ends with whitespace
|
||||
if (util.getLast(words) === "") {
|
||||
words.pop();
|
||||
endWhitespace = words.pop();
|
||||
}
|
||||
|
||||
// This was whitespace only without a new line.
|
||||
if (words.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
words.forEach((word, i) => {
|
||||
if (i % 2 === 1) {
|
||||
children.push(line);
|
||||
} else {
|
||||
children.push(word);
|
||||
}
|
||||
});
|
||||
} else if (/\n/.test(value)) {
|
||||
children.push("");
|
||||
children.push(hardline);
|
||||
|
||||
// allow one extra newline
|
||||
if (value.match(/\n/g).length > 1) {
|
||||
if (endWhitespace !== undefined) {
|
||||
if (/\n/.test(endWhitespace)) {
|
||||
children.push(softline);
|
||||
} else {
|
||||
children.push(jsxWhitespace);
|
||||
}
|
||||
} else {
|
||||
// Ideally this would be a `softline` to allow a break between
|
||||
// tags and text.
|
||||
// Unfortunately Facebook have a custom translation pipeline
|
||||
// (https://github.com/prettier/prettier/issues/1581#issuecomment-300975032)
|
||||
// that uses the JSX syntax, but does not follow the React whitespace
|
||||
// rules.
|
||||
// Ensuring that we never have a break between tags and text in JSX
|
||||
// will allow Facebook to adopt Prettier without too much of an
|
||||
// adverse effect on formatting algorithm.
|
||||
children.push("");
|
||||
}
|
||||
} else if (/\n/.test(text)) {
|
||||
// Keep (up to one) blank line between tags/expressions/text.
|
||||
// Note: We don't keep blank lines between text elements.
|
||||
if (text.match(/\n/g).length > 1) {
|
||||
children.push("");
|
||||
children.push(hardline);
|
||||
}
|
||||
} else if (/[ \n\r\t]/.test(value)) {
|
||||
// whitespace(s)-only without newlines,
|
||||
// eg; one or more spaces separating two elements
|
||||
for (let i = 0; i < value.length; ++i) {
|
||||
// Because fill expects alternating content and whitespace parts
|
||||
// we need to include an empty content part before each JSX
|
||||
// whitespace.
|
||||
children.push("");
|
||||
children.push(jsxWhitespace);
|
||||
}
|
||||
} else {
|
||||
children.push("");
|
||||
children.push(jsxWhitespace);
|
||||
}
|
||||
} else {
|
||||
children.push(print(childPath));
|
||||
// Convert `{" "}` to jsxWhitespace so it can be printed as a standard
|
||||
// space if needed.
|
||||
if (isJSXWhitespaceExpression(child)) {
|
||||
children.push("");
|
||||
children.push(jsxWhitespace);
|
||||
return;
|
||||
}
|
||||
|
||||
const printedChild = print(childPath);
|
||||
children.push(printedChild);
|
||||
|
||||
const isBrTag =
|
||||
child.type === "JSXElement" && child.openingElement.name.name === "br";
|
||||
if (isBrTag) {
|
||||
// Forcing a hardline after a `<br />` tag gives much better text
|
||||
// layout.
|
||||
children.push(hardline);
|
||||
return;
|
||||
}
|
||||
|
||||
const next = n.children[i + 1];
|
||||
const followedByJSXElement = next && !isLiteral(next);
|
||||
const followedByJSXWhitespace =
|
||||
next &&
|
||||
next.type === "JSXExpressionContainer" &&
|
||||
isLiteral(next.expression) &&
|
||||
next.expression.value === " ";
|
||||
|
||||
if (followedByJSXElement && !followedByJSXWhitespace) {
|
||||
children.push(softline);
|
||||
} else {
|
||||
// Ideally this would be a softline as well.
|
||||
const followedByMeaningfulText = next && isMeaningfulJSXText(next);
|
||||
const followedByJSXWhitespace = next && isJSXWhitespaceExpression(next);
|
||||
if (followedByMeaningfulText || followedByJSXWhitespace) {
|
||||
// Potentially this could be a softline as well.
|
||||
// See the comment above about the Facebook translation pipeline as
|
||||
// to why this is an empty string.
|
||||
children.push("");
|
||||
} else {
|
||||
children.push(softline);
|
||||
}
|
||||
}
|
||||
}, "children");
|
||||
|
@ -3830,18 +3841,46 @@ function printJSXElement(path, options, print) {
|
|||
assert.ok(!n.closingElement);
|
||||
return openingLines;
|
||||
}
|
||||
|
||||
const containsTag =
|
||||
n.children.filter(child => child.type === "JSXElement").length > 0;
|
||||
const containsMultipleExpressions =
|
||||
n.children.filter(child => child.type === "JSXExpressionContainer").length >
|
||||
1;
|
||||
const containsMultipleAttributes = n.openingElement.attributes.length > 1;
|
||||
|
||||
// Record any breaks. Should never go from true to false, only false to true.
|
||||
let forcedBreak = willBreak(openingLines);
|
||||
let forcedBreak =
|
||||
willBreak(openingLines) ||
|
||||
containsTag ||
|
||||
containsMultipleAttributes ||
|
||||
containsMultipleExpressions;
|
||||
|
||||
const rawJsxWhitespace = options.singleQuote ? "{' '}" : '{" "}';
|
||||
const jsxWhitespace = ifBreak(concat([rawJsxWhitespace, softline]), " ");
|
||||
|
||||
const children = printJSXChildren(path, options, print, jsxWhitespace);
|
||||
|
||||
// Remove multiple filler empty strings
|
||||
// These can occur when a text element is followed by a newline.
|
||||
const containsText =
|
||||
n.children.filter(child => isMeaningfulJSXText(child)).length > 0;
|
||||
|
||||
// We can end up we multiple whitespace elements with empty string
|
||||
// content between them.
|
||||
// We need to remove empty whitespace and softlines before JSX whitespace
|
||||
// to get the correct output.
|
||||
for (let i = children.length - 2; i >= 0; i--) {
|
||||
if (children[i] === "" && children[i + 1] === "") {
|
||||
const isPairOfEmptyStrings = children[i] === "" && children[i + 1] === "";
|
||||
const isSoftlineFollowedByJSXWhitespace =
|
||||
children[i] === softline &&
|
||||
children[i + 1] === "" &&
|
||||
children[i + 2] === jsxWhitespace;
|
||||
const isEmptyFollowedByHardline =
|
||||
children[i] === "" && children[i + 1] === hardline;
|
||||
if (
|
||||
isPairOfEmptyStrings ||
|
||||
isSoftlineFollowedByJSXWhitespace ||
|
||||
(isEmptyFollowedByHardline && containsText)
|
||||
) {
|
||||
children.splice(i, 2);
|
||||
}
|
||||
}
|
||||
|
@ -3888,13 +3927,19 @@ function printJSXElement(path, options, print) {
|
|||
// Also detect whether we will force this element to output over multiple lines.
|
||||
const multilineChildren = [];
|
||||
children.forEach((child, i) => {
|
||||
// Ensure that we display leading, trailing, and solitary whitespace as
|
||||
// `{" "}` when outputting this element over multiple lines.
|
||||
// There are a number of situations where we need to ensure we display
|
||||
// whitespace as `{" "}` when outputting this element over multiple lines.
|
||||
if (child === jsxWhitespace) {
|
||||
if (i === 1 && children[i - 1] === "") {
|
||||
// Leading whitespace
|
||||
multilineChildren.push(rawJsxWhitespace);
|
||||
return;
|
||||
} else if (i === children.length - 1) {
|
||||
// Trailing whitespace
|
||||
multilineChildren.push(rawJsxWhitespace);
|
||||
return;
|
||||
} else if (children[i - 1] === "" && children[i - 2] === hardline) {
|
||||
// Whitespace after line break
|
||||
multilineChildren.push(rawJsxWhitespace);
|
||||
return;
|
||||
}
|
||||
|
@ -3907,10 +3952,17 @@ function printJSXElement(path, options, print) {
|
|||
}
|
||||
});
|
||||
|
||||
// If there is text we use `fill` to fit as much onto each line as possible.
|
||||
// When there is no text (just tags and expressions) we use `group`
|
||||
// to output each on a separate line.
|
||||
const content = containsText
|
||||
? fill(multilineChildren)
|
||||
: group(concat(multilineChildren), { shouldBreak: true });
|
||||
|
||||
const multiLineElem = group(
|
||||
concat([
|
||||
openingLines,
|
||||
indent(concat([hardline, fill(multilineChildren)])),
|
||||
indent(concat([hardline, content])),
|
||||
hardline,
|
||||
closingLines
|
||||
])
|
||||
|
@ -3921,7 +3973,7 @@ function printJSXElement(path, options, print) {
|
|||
}
|
||||
|
||||
return conditionalGroup([
|
||||
group(concat([openingLines, fill(children), closingLines])),
|
||||
group(concat([openingLines, concat(children), closingLines])),
|
||||
multiLineElem
|
||||
]);
|
||||
}
|
||||
|
@ -4122,7 +4174,7 @@ function adjustClause(node, clause, forceSpace) {
|
|||
}
|
||||
|
||||
function nodeStr(node, options, isFlowOrTypeScriptDirectiveLiteral) {
|
||||
const raw = node.extra ? node.extra.raw : node.raw;
|
||||
const raw = rawText(node);
|
||||
// `rawContent` is the string exactly like it appeared in the input source
|
||||
// code, with its enclosing quote.
|
||||
const rawContent = raw.slice(1, -1);
|
||||
|
|
|
@ -495,9 +495,7 @@ Observable.of(process)
|
|||
.takeUntil(exit);
|
||||
|
||||
// Comments disappear inside of JSX
|
||||
<div>
|
||||
{/* Some comment */}
|
||||
</div>;
|
||||
<div>{/* Some comment */}</div>;
|
||||
|
||||
// Comments in JSX tag are placed in a non optimal way
|
||||
<div
|
||||
|
@ -596,23 +594,15 @@ exports[`jsx.js 1`] = `
|
|||
|
||||
<div>{/*<div> Some very v ery very very long line to break line width limit </div>*/}</div>;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
<div>
|
||||
{/* comment */}
|
||||
</div>;
|
||||
<div>{/* comment */}</div>;
|
||||
|
||||
<div>
|
||||
{/* comment */}
|
||||
</div>;
|
||||
<div>{/* comment */}</div>;
|
||||
|
||||
<div>
|
||||
{/* comment
|
||||
*/}
|
||||
</div>;
|
||||
<div>{/* comment
|
||||
*/}</div>;
|
||||
|
||||
<div>
|
||||
{a /* comment
|
||||
*/}
|
||||
</div>;
|
||||
<div>{a /* comment
|
||||
*/}</div>;
|
||||
|
||||
<div>
|
||||
{
|
||||
|
@ -622,13 +612,9 @@ exports[`jsx.js 1`] = `
|
|||
}
|
||||
</div>;
|
||||
|
||||
<div>
|
||||
{/* comment */}
|
||||
</div>;
|
||||
<div>{/* comment */}</div>;
|
||||
|
||||
<div>
|
||||
{/* comment */}
|
||||
</div>;
|
||||
<div>{/* comment */}</div>;
|
||||
|
||||
<div>
|
||||
{
|
||||
|
|
|
@ -99,8 +99,7 @@ var App = React.createClass({
|
|||
|
||||
return (
|
||||
<div>
|
||||
{foo(x, y)}
|
||||
{foo(z, x)} // error, since z: number
|
||||
{foo(x, y)}{foo(z, x)} // error, since z: number
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -164,8 +163,7 @@ var App = require("App.react");
|
|||
|
||||
var app = (
|
||||
<App y={42}>
|
||||
{" "}// error, y: number but foo expects string in App.react
|
||||
Some text.
|
||||
{" "}// error, y: number but foo expects string in App.react Some text.
|
||||
</App>
|
||||
);
|
||||
|
||||
|
|
|
@ -865,11 +865,7 @@ var ReactClass = React.createClass({
|
|||
render: function(): any {
|
||||
// Any state access here seems to make state any
|
||||
this.state;
|
||||
return (
|
||||
<div>
|
||||
{this.state.bar.qux}
|
||||
</div>
|
||||
);
|
||||
return <div>{this.state.bar.qux}</div>;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -741,11 +741,7 @@ class Bar extends React.Component {
|
|||
test: number
|
||||
};
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.props.test}
|
||||
</div>
|
||||
);
|
||||
return <div>{this.props.test}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,9 @@ comp2A = (
|
|||
);
|
||||
|
||||
const comp3 = (
|
||||
<div style={styles} key="something">Bump to next line without parens</div>
|
||||
<div style={styles} key="something">
|
||||
Bump to next line without parens
|
||||
</div>
|
||||
);
|
||||
|
||||
const comp4 = (
|
||||
|
|
|
@ -98,73 +98,35 @@ regression_extra_newline_2 = (
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
keep = (
|
||||
<p>
|
||||
Welcome to the <strong>Universal React Starter-kyt</strong>.
|
||||
This starter kyt should serve as the base for an advanced,
|
||||
server-rendered React app.
|
||||
Welcome to the <strong>Universal React Starter-kyt</strong>. This starter
|
||||
kyt should serve as the base for an advanced, server-rendered React app.
|
||||
</p>
|
||||
);
|
||||
|
||||
newlines_text = (
|
||||
<div>
|
||||
hi
|
||||
there
|
||||
how
|
||||
newlines_text = <div>hi there how are you are you fine today?</div>;
|
||||
|
||||
are you
|
||||
|
||||
are you fine today?
|
||||
</div>
|
||||
);
|
||||
|
||||
newlines_text_spaced = (
|
||||
<div>
|
||||
|
||||
space above
|
||||
|
||||
space below
|
||||
|
||||
</div>
|
||||
);
|
||||
newlines_text_spaced = <div>space above space below</div>;
|
||||
|
||||
newlines_elems_spaced = (
|
||||
<div>
|
||||
|
||||
<span>space above</span>
|
||||
|
||||
<span>space below</span>
|
||||
|
||||
</div>
|
||||
);
|
||||
|
||||
newlines_mixed = (
|
||||
<div>
|
||||
hi
|
||||
<span>there</span>
|
||||
|
||||
how
|
||||
|
||||
are <strong>you</strong>
|
||||
|
||||
are you fine today?
|
||||
hi<span>there</span>how are <strong>you</strong>are you fine today?
|
||||
</div>
|
||||
);
|
||||
|
||||
newlines_elems = (
|
||||
<div>
|
||||
<div>
|
||||
|
||||
<div />
|
||||
|
||||
</div>
|
||||
|
||||
hi
|
||||
|
||||
<div />
|
||||
|
||||
<span />
|
||||
|
||||
<Big />
|
||||
|
||||
hi<div /><span /><Big />
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -193,8 +155,6 @@ exports[`windows.js 1`] = `
|
|||
Text
|
||||
</div>
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
<div>
|
||||
Text
|
||||
</div>;
|
||||
<div>Text</div>;
|
||||
|
||||
`;
|
||||
|
|
|
@ -123,7 +123,14 @@ break_components = (
|
|||
<div>
|
||||
<Foo />
|
||||
<Bar>
|
||||
<p>foo<span>bar bar bar</span></p><h1><span><em>yep</em></span></h1>
|
||||
<p>
|
||||
foo<span>bar bar bar</span>
|
||||
</p>
|
||||
<h1>
|
||||
<span>
|
||||
<em>yep</em>
|
||||
</span>
|
||||
</h1>
|
||||
</Bar>
|
||||
<h2>nope</h2>
|
||||
</div>
|
||||
|
@ -182,7 +189,8 @@ not_broken_end = (
|
|||
|
||||
not_broken_begin = (
|
||||
<div>
|
||||
<br /> long text long text long text long text long text long text long text
|
||||
<br />
|
||||
{" "}long text long text long text long text long text long text long text
|
||||
long text<link>url</link> long text long text
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -90,11 +90,21 @@ long_open_long_children = (
|
|||
Hello world
|
||||
</BaseForm>
|
||||
<div>
|
||||
<div><div><div><div><div>hey hiya how are ya</div></div></div></div></div>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<div>hey hiya how are ya</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div><div attr="long" attr2="also long" attr3="gonna break" /></div>
|
||||
<div>
|
||||
<div attr="long" attr2="also long" attr3="gonna break" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
@ -86,7 +86,9 @@ const render2 = ({ styles }) =>
|
|||
</div>;
|
||||
|
||||
const render3 = ({ styles }) =>
|
||||
<div style={styles} key="something">Bump to next line without parens</div>;
|
||||
<div style={styles} key="something">
|
||||
Bump to next line without parens
|
||||
</div>;
|
||||
|
||||
const render4 = ({ styles }) =>
|
||||
<div style={styles} key="something">
|
||||
|
@ -133,20 +135,28 @@ const render6 = ({ styles }) =>
|
|||
|
||||
const render7 = () =>
|
||||
<div>
|
||||
<span /><span>Dont break each elem onto its own line.</span> <span />
|
||||
<div /> <div />
|
||||
<span /><span>Dont break each elem onto its own line.</span> <span /><div />{" "}
|
||||
<div />
|
||||
</div>;
|
||||
|
||||
const render7A = () =>
|
||||
<div>
|
||||
<div /><div /><div />
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
</div>;
|
||||
|
||||
const render7B = () =>
|
||||
<div>
|
||||
<span> <span /> Dont break plz</span>
|
||||
<span><span />Dont break plz</span>
|
||||
<span>Dont break plz<span /></span>
|
||||
<span>
|
||||
{" "}<span /> Dont break plz
|
||||
</span>
|
||||
<span>
|
||||
<span />Dont break plz
|
||||
</span>
|
||||
<span>
|
||||
Dont break plz<span />
|
||||
</span>
|
||||
</div>;
|
||||
|
||||
const render8 = props => <div>{props.text}</div>;
|
||||
|
|
|
@ -162,6 +162,107 @@ jsx_around_multiline_element_second_pass = (
|
|||
After
|
||||
</div>
|
||||
);
|
||||
|
||||
convert_space_expressions =
|
||||
<div>{" "}</div>
|
||||
|
||||
x =
|
||||
<div>
|
||||
<first />
|
||||
<second />
|
||||
<third />
|
||||
<fourth />
|
||||
<fifth />
|
||||
<sixth />
|
||||
</div>
|
||||
|
||||
const Abc = () => {
|
||||
return (
|
||||
<div>
|
||||
Please state your
|
||||
{" "}
|
||||
<b>name</b>
|
||||
{" "}
|
||||
and
|
||||
{" "}
|
||||
<b>occupation</b>
|
||||
{" "}
|
||||
for the board of directors.
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
x = <div id="moo">Some stuff here</div>
|
||||
|
||||
headers_and_paragraphs = (
|
||||
<div>
|
||||
<h2>First</h2>
|
||||
<p>The first paragraph.</p>
|
||||
|
||||
<h2>Second</h2>
|
||||
<p>The second paragraph.</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
no_text_one_tag_per_line =
|
||||
<div>
|
||||
<first /><second />
|
||||
</div>
|
||||
|
||||
with_text_fill_line =
|
||||
<div>
|
||||
Text <first /><second />
|
||||
</div>
|
||||
|
||||
line_after_br =
|
||||
<div>
|
||||
Text<br />
|
||||
More text <br />
|
||||
And more<br />
|
||||
</div>
|
||||
|
||||
line_after_br_2 = <div>A<br />B<br />C</div>
|
||||
|
||||
br_followed_by_whitespace = <div><br /> text</div>
|
||||
|
||||
dont_preserve_blank_lines_when_jsx_contains_text =
|
||||
<div>
|
||||
|
||||
<div>Zeroth</div>
|
||||
|
||||
<div>First</div>
|
||||
|
||||
Second
|
||||
|
||||
</div>
|
||||
|
||||
multiple_expressions =
|
||||
<div>
|
||||
{header}
|
||||
{body}
|
||||
{footer}
|
||||
</div>
|
||||
|
||||
single_expression_child_tags =
|
||||
<div>
|
||||
You currently have <strong>{dashboardStr}</strong> and <strong>{userStr}</strong>
|
||||
</div>
|
||||
|
||||
expression_does_not_break =
|
||||
<div>texty text text text text text text text text text text text {this.props.type} </div>
|
||||
|
||||
// FIXME
|
||||
br_triggers_expression_break =
|
||||
<div><br />text text text text text text text text text text text {this.props.type} </div>
|
||||
|
||||
jsx_whitespace_after_tag =
|
||||
<div>
|
||||
<span a="a" b="b">
|
||||
{variable}
|
||||
</span>
|
||||
{" "}
|
||||
({variable})
|
||||
</div>
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Wrapping text
|
||||
x = (
|
||||
|
@ -182,8 +283,12 @@ x = (
|
|||
// Wrapping tags
|
||||
x = (
|
||||
<div>
|
||||
<first>f</first><first>f</first><first>f</first><first>f</first>
|
||||
<first>f</first><first>f</first>
|
||||
<first>f</first>
|
||||
<first>f</first>
|
||||
<first>f</first>
|
||||
<first>f</first>
|
||||
<first>f</first>
|
||||
<first>f</first>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -223,7 +328,7 @@ x = (
|
|||
x = (
|
||||
<div>
|
||||
before {stuff} after {stuff} after {stuff} after {stuff} after {stuff} after{" "}
|
||||
{stuff} {stuff} {stuff} after {stuff} after
|
||||
{stuff} {stuff} {stuff} after {stuff} after
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -241,14 +346,11 @@ function DiffOverview(props) {
|
|||
<div className="alert alert-info">
|
||||
<p>
|
||||
This diff overview is computed against the current list of records in
|
||||
this collection and the list it contained on <b>
|
||||
{humanDate(since)}
|
||||
</b>.
|
||||
this collection and the list it contained on <b>{humanDate(since)}</b>.
|
||||
</p>
|
||||
<p>
|
||||
<b>Note:</b> <code>last_modified</code> and <code>schema</code> record
|
||||
metadata
|
||||
are omitted for easier review.
|
||||
metadata are omitted for easier review.
|
||||
</p>
|
||||
</div>
|
||||
<Diff source={source} target={target} />
|
||||
|
@ -277,23 +379,13 @@ x = (
|
|||
|
||||
x = (
|
||||
<div>
|
||||
<div>
|
||||
First
|
||||
</div>
|
||||
Second
|
||||
<div>
|
||||
Third
|
||||
</div>
|
||||
<div>First</div>Second<div>Third</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
x = (
|
||||
<div>
|
||||
First{" "}
|
||||
<div>
|
||||
Second
|
||||
</div>{" "}
|
||||
Third
|
||||
First <div>Second</div> Third
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -320,12 +412,7 @@ no_leading_or_trailing_whitespace = (
|
|||
|
||||
facebook_translation_leave_text_around_tag = (
|
||||
<div>
|
||||
<span>
|
||||
First
|
||||
</span>,
|
||||
(<span>
|
||||
Second
|
||||
</span>)
|
||||
<span>First</span>, (<span>Second</span>)
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -366,15 +453,7 @@ solitary_whitespace = (
|
|||
|
||||
jsx_whitespace_on_newline = (
|
||||
<div>
|
||||
<div>
|
||||
First
|
||||
</div>{" "}
|
||||
<div>
|
||||
Second
|
||||
</div>{" "}
|
||||
<div>
|
||||
Third
|
||||
</div>
|
||||
<div>First</div> <div>Second</div> <div>Third</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -402,4 +481,121 @@ jsx_around_multiline_element_second_pass = (
|
|||
</div>
|
||||
);
|
||||
|
||||
convert_space_expressions = <div> </div>;
|
||||
|
||||
x = (
|
||||
<div>
|
||||
<first />
|
||||
<second />
|
||||
<third />
|
||||
<fourth />
|
||||
<fifth />
|
||||
<sixth />
|
||||
</div>
|
||||
);
|
||||
|
||||
const Abc = () => {
|
||||
return (
|
||||
<div>
|
||||
Please state your <b>name</b> and <b>occupation</b> for the board of
|
||||
directors.
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
x = <div id="moo">Some stuff here</div>;
|
||||
|
||||
headers_and_paragraphs = (
|
||||
<div>
|
||||
<h2>First</h2>
|
||||
<p>The first paragraph.</p>
|
||||
|
||||
<h2>Second</h2>
|
||||
<p>The second paragraph.</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
no_text_one_tag_per_line = (
|
||||
<div>
|
||||
<first />
|
||||
<second />
|
||||
</div>
|
||||
);
|
||||
|
||||
with_text_fill_line = (
|
||||
<div>
|
||||
Text <first /><second />
|
||||
</div>
|
||||
);
|
||||
|
||||
line_after_br = (
|
||||
<div>
|
||||
Text<br />
|
||||
More text <br />
|
||||
And more<br />
|
||||
</div>
|
||||
);
|
||||
|
||||
line_after_br_2 = (
|
||||
<div>
|
||||
A<br />
|
||||
B<br />
|
||||
C
|
||||
</div>
|
||||
);
|
||||
|
||||
br_followed_by_whitespace = (
|
||||
<div>
|
||||
<br />
|
||||
{" "}text
|
||||
</div>
|
||||
);
|
||||
|
||||
dont_preserve_blank_lines_when_jsx_contains_text = (
|
||||
<div>
|
||||
<div>Zeroth</div><div>First</div>Second
|
||||
</div>
|
||||
);
|
||||
|
||||
multiple_expressions = (
|
||||
<div>
|
||||
{header}
|
||||
{body}
|
||||
{footer}
|
||||
</div>
|
||||
);
|
||||
|
||||
single_expression_child_tags = (
|
||||
<div>
|
||||
You currently have <strong>{dashboardStr}</strong> and{" "}
|
||||
<strong>{userStr}</strong>
|
||||
</div>
|
||||
);
|
||||
|
||||
expression_does_not_break = (
|
||||
<div>
|
||||
texty text text text text text text text text text text text{" "}
|
||||
{this.props.type}{" "}
|
||||
</div>
|
||||
);
|
||||
|
||||
// FIXME
|
||||
br_triggers_expression_break = (
|
||||
<div>
|
||||
<br />
|
||||
text text text text text text text text text text text {
|
||||
this.props.type
|
||||
}{" "}
|
||||
</div>
|
||||
);
|
||||
|
||||
jsx_whitespace_after_tag = (
|
||||
<div>
|
||||
<span a="a" b="b">
|
||||
{variable}
|
||||
</span>{" "}
|
||||
({variable})
|
||||
</div>
|
||||
);
|
||||
|
||||
`;
|
||||
|
|
|
@ -159,3 +159,104 @@ jsx_around_multiline_element_second_pass = (
|
|||
After
|
||||
</div>
|
||||
);
|
||||
|
||||
convert_space_expressions =
|
||||
<div>{" "}</div>
|
||||
|
||||
x =
|
||||
<div>
|
||||
<first />
|
||||
<second />
|
||||
<third />
|
||||
<fourth />
|
||||
<fifth />
|
||||
<sixth />
|
||||
</div>
|
||||
|
||||
const Abc = () => {
|
||||
return (
|
||||
<div>
|
||||
Please state your
|
||||
{" "}
|
||||
<b>name</b>
|
||||
{" "}
|
||||
and
|
||||
{" "}
|
||||
<b>occupation</b>
|
||||
{" "}
|
||||
for the board of directors.
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
x = <div id="moo">Some stuff here</div>
|
||||
|
||||
headers_and_paragraphs = (
|
||||
<div>
|
||||
<h2>First</h2>
|
||||
<p>The first paragraph.</p>
|
||||
|
||||
<h2>Second</h2>
|
||||
<p>The second paragraph.</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
no_text_one_tag_per_line =
|
||||
<div>
|
||||
<first /><second />
|
||||
</div>
|
||||
|
||||
with_text_fill_line =
|
||||
<div>
|
||||
Text <first /><second />
|
||||
</div>
|
||||
|
||||
line_after_br =
|
||||
<div>
|
||||
Text<br />
|
||||
More text <br />
|
||||
And more<br />
|
||||
</div>
|
||||
|
||||
line_after_br_2 = <div>A<br />B<br />C</div>
|
||||
|
||||
br_followed_by_whitespace = <div><br /> text</div>
|
||||
|
||||
dont_preserve_blank_lines_when_jsx_contains_text =
|
||||
<div>
|
||||
|
||||
<div>Zeroth</div>
|
||||
|
||||
<div>First</div>
|
||||
|
||||
Second
|
||||
|
||||
</div>
|
||||
|
||||
multiple_expressions =
|
||||
<div>
|
||||
{header}
|
||||
{body}
|
||||
{footer}
|
||||
</div>
|
||||
|
||||
single_expression_child_tags =
|
||||
<div>
|
||||
You currently have <strong>{dashboardStr}</strong> and <strong>{userStr}</strong>
|
||||
</div>
|
||||
|
||||
expression_does_not_break =
|
||||
<div>texty text text text text text text text text text text text {this.props.type} </div>
|
||||
|
||||
// FIXME
|
||||
br_triggers_expression_break =
|
||||
<div><br />text text text text text text text text text text text {this.props.type} </div>
|
||||
|
||||
jsx_whitespace_after_tag =
|
||||
<div>
|
||||
<span a="a" b="b">
|
||||
{variable}
|
||||
</span>
|
||||
{" "}
|
||||
({variable})
|
||||
</div>
|
||||
|
|
|
@ -27,20 +27,8 @@ zero_width_space = <div>][</div>
|
|||
// Treated as whitespace in JSX
|
||||
spaces = <div>] [</div>;
|
||||
tabs = <div>] [</div>;
|
||||
slash_n = (
|
||||
<div>
|
||||
]
|
||||
|
||||
[
|
||||
</div>
|
||||
);
|
||||
slash_r = (
|
||||
<div>
|
||||
]
|
||||
|
||||
[
|
||||
</div>
|
||||
);
|
||||
slash_n = <div>] [</div>;
|
||||
slash_r = <div>] [</div>;
|
||||
|
||||
// Not treated as whitespace in JSX
|
||||
// NOTE: Some of the space characters here won't show up in an editor,
|
||||
|
|
|
@ -128,13 +128,7 @@ exports[`expression.js 1`] = `
|
|||
value={option}
|
||||
/>;
|
||||
|
||||
<ParentComponent
|
||||
prop={
|
||||
<Child>
|
||||
test
|
||||
</Child>
|
||||
}
|
||||
/>;
|
||||
<ParentComponent prop={<Child>test</Child>} />;
|
||||
|
||||
`;
|
||||
|
||||
|
@ -148,9 +142,7 @@ const aDiv = (
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
const aDiv = (
|
||||
/* $FlowFixMe */
|
||||
<div className="foo">
|
||||
Foo bar
|
||||
</div>
|
||||
<div className="foo">Foo bar</div>
|
||||
);
|
||||
|
||||
`;
|
||||
|
@ -283,7 +275,8 @@ onClick={() => {
|
|||
a;
|
||||
}}
|
||||
>
|
||||
{header}{showSort}
|
||||
{header}
|
||||
{showSort}
|
||||
</td>;
|
||||
|
||||
<td
|
||||
|
@ -359,23 +352,11 @@ const Labels = {
|
|||
};
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
const Labels = {
|
||||
label1: (
|
||||
<fbt>
|
||||
Label 1
|
||||
</fbt>
|
||||
),
|
||||
label1: <fbt>Label 1</fbt>,
|
||||
|
||||
label2: (
|
||||
<fbt>
|
||||
Label 2
|
||||
</fbt>
|
||||
),
|
||||
label2: <fbt>Label 2</fbt>,
|
||||
|
||||
label3: (
|
||||
<fbt>
|
||||
Label 3
|
||||
</fbt>
|
||||
)
|
||||
label3: <fbt>Label 3</fbt>
|
||||
};
|
||||
|
||||
`;
|
||||
|
|
|
@ -31,14 +31,10 @@ raw_amp = <span>foo & bar</span>
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
many_nbsp = <div> </div>;
|
||||
single_nbsp = <div> </div>;
|
||||
nbsp_with_newline = (
|
||||
<div>
|
||||
|
||||
</div>
|
||||
);
|
||||
nbsp_with_newline = <div> </div>;
|
||||
|
||||
many_raw_nbsp = <div> </div>;
|
||||
many_raw_spaces = <div> </div>;
|
||||
many_raw_spaces = <div> </div>;
|
||||
|
||||
amp = <span>foo & bar</span>;
|
||||
raw_amp = <span>foo & bar</span>;
|
||||
|
@ -62,14 +58,10 @@ raw_amp = <span>foo & bar</span>
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
many_nbsp = <div> </div>;
|
||||
single_nbsp = <div> </div>;
|
||||
nbsp_with_newline = (
|
||||
<div>
|
||||
|
||||
</div>
|
||||
);
|
||||
nbsp_with_newline = <div> </div>;
|
||||
|
||||
many_raw_nbsp = <div> </div>;
|
||||
many_raw_spaces = <div> </div>;
|
||||
many_raw_spaces = <div> </div>;
|
||||
|
||||
amp = <span>foo & bar</span>;
|
||||
raw_amp = <span>foo & bar</span>;
|
||||
|
|
|
@ -30,17 +30,9 @@ var example2 = <div>
|
|||
/*test*/
|
||||
</div>;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
var example1 = (
|
||||
<div>
|
||||
https://test
|
||||
</div>
|
||||
);
|
||||
var example1 = <div>https://test</div>;
|
||||
|
||||
var example2 = (
|
||||
<div>
|
||||
/*test*/
|
||||
</div>
|
||||
);
|
||||
var example2 = <div>/*test*/</div>;
|
||||
|
||||
`;
|
||||
|
||||
|
|
|
@ -38,10 +38,7 @@ const MyCoolList = ({ things }) =>
|
|||
|
||||
const MyCoolThing = ({ thingo }) => <li>{thingo}</li>;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
const MyCoolList = ({ things }) =>
|
||||
<ul>
|
||||
{things.map(MyCoolThing)}
|
||||
</ul>;
|
||||
const MyCoolList = ({ things }) => <ul>{things.map(MyCoolThing)}</ul>;
|
||||
|
||||
const MyCoolThing = ({ thingo }) => <li>{thingo}</li>;
|
||||
|
||||
|
|
Loading…
Reference in New Issue