Improve JSX output when there is a single expression (#2274)

master
Karl O'Keeffe 2017-06-27 03:05:34 +01:00 committed by Christopher Chedeau
parent 95a5f11be9
commit be600337eb
10 changed files with 143 additions and 47 deletions

View File

@ -3739,7 +3739,7 @@ function printJSXChildren(path, options, print, jsxWhitespace) {
children.push(jsxWhitespace);
}
} else {
// Ideally this would be a `softline` to allow a break between
// Ideally this would be a `hardline` to allow a break between
// tags and text.
// Unfortunately Facebook have a custom translation pipeline
// (https://github.com/prettier/prettier/issues/1581#issuecomment-300975032)
@ -3762,23 +3762,14 @@ function printJSXChildren(path, options, print, jsxWhitespace) {
children.push(jsxWhitespace);
}
} else {
// 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 next = n.children[i + 1];
const directlyFollowedByMeaningfulText =
next && isMeaningfulJSXText(next) && !/^[ \n\r\t]/.test(rawText(next));
const followedByJSXWhitespace = next && isJSXWhitespaceExpression(next);
if (directlyFollowedByMeaningfulText || followedByJSXWhitespace) {
// Potentially this could be a softline as well.
if (directlyFollowedByMeaningfulText) {
// Potentially this could be a hardline as well.
// See the comment above about the Facebook translation pipeline as
// to why this is an empty string.
children.push("");
@ -3837,11 +3828,30 @@ function printJSXElement(path, options, print) {
return openingLines;
}
// Convert `{" "}` to text nodes containing a space.
// This makes it easy to turn them into `jsxWhitespace` which
// can then print as either a space or `{" "}` when breaking.
n.children = n.children.map(child => {
if (isJSXWhitespaceExpression(child)) {
return {
type: "JSXText",
value: " ",
raw: " "
};
}
return child;
});
const parent = path.getParentNode();
const parentContainsText =
parent.type === "JSXElement" &&
parent.children.filter(child => isMeaningfulJSXText(child)).length > 0;
const containsTag =
n.children.filter(child => child.type === "JSXElement").length > 0;
const containsMultipleExpressions =
n.children.filter(child => child.type === "JSXExpressionContainer").length >
1;
const numExpressions = n.children.filter(
child => child.type === "JSXExpressionContainer"
).length;
const containsMultipleAttributes = n.openingElement.attributes.length > 1;
// Record any breaks. Should never go from true to false, only false to true.
@ -3849,7 +3859,7 @@ function printJSXElement(path, options, print) {
willBreak(openingLines) ||
containsTag ||
containsMultipleAttributes ||
containsMultipleExpressions;
(parentContainsText ? numExpressions > 1 : numExpressions > 0);
const rawJsxWhitespace = options.singleQuote ? "{' '}" : '{" "}';
const jsxWhitespace = ifBreak(concat([rawJsxWhitespace, softline]), " ");

View File

@ -304,7 +304,10 @@ export const bem = block =>
<FlatList
renderItem={(
info // $FlowExpectedError - bad widgetCount type 6, should be Object
) => <span>{info.item.widget.missingProp}</span>}
) =>
<span>
{info.item.widget.missingProp}
</span>}
data={data}
/>;

View File

@ -497,7 +497,9 @@ 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,15 +598,23 @@ 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>
{
@ -614,9 +624,13 @@ exports[`jsx.js 1`] = `
}
</div>;
<div>{/* comment */}</div>;
<div>
{/* comment */}
</div>;
<div>{/* comment */}</div>;
<div>
{/* comment */}
</div>;
<div>
{

View File

@ -222,8 +222,12 @@ declare function ExpectsProps(props: { name: string }, children: any): string;
declare function ExpectsChildrenTuple(props: any, children: [string]): string;
<ExpectsChildrenTuple />; // Error - mising child
<ExpectsChildrenTuple>Hi</ExpectsChildrenTuple>; // No error
<ExpectsChildrenTuple>{123}</ExpectsChildrenTuple>; // Error: number ~> string
<ExpectsChildrenTuple>Hi {"there"}</ExpectsChildrenTuple>; // Error: too many children
<ExpectsChildrenTuple>
{123}
</ExpectsChildrenTuple>; // Error: number ~> string
<ExpectsChildrenTuple>
Hi {"there"}
</ExpectsChildrenTuple>; // Error: too many children
declare function ExpectsChildrenArray(
props: any,
@ -231,8 +235,12 @@ declare function ExpectsChildrenArray(
): string;
<ExpectsChildrenArray />; // No error - 0 children is fine
<ExpectsChildrenArray>Hi</ExpectsChildrenArray>; // No error - 1 child is fine
<ExpectsChildrenArray>{123}</ExpectsChildrenArray>; // Error: number ~> string
<ExpectsChildrenArray>Hi {"there"}</ExpectsChildrenArray>; // No error - 2 children is fine
<ExpectsChildrenArray>
{123}
</ExpectsChildrenArray>; // Error: number ~> string
<ExpectsChildrenArray>
Hi {"there"}
</ExpectsChildrenArray>; // No error - 2 children is fine
`;

View File

@ -793,7 +793,11 @@ class Example extends React.Component {
props: { bar: string };
render() {
return <div>{this.props.bar}</div>;
return (
<div>
{this.props.bar}
</div>
);
}
}
@ -865,7 +869,11 @@ 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>
);
}
});
@ -973,7 +981,11 @@ var C = React.createClass({
render() {
this.setState({ y: 0 });
return <div>{this.state.z}</div>;
return (
<div>
{this.state.z}
</div>
);
}
});

View File

@ -741,7 +741,11 @@ class Bar extends React.Component {
test: number
};
render() {
return <div>{this.props.test}</div>;
return (
<div>
{this.props.test}
</div>
);
}
}
@ -1619,9 +1623,17 @@ var Example = React.createClass({
},
render() {
if (typeof this.props.prop === "string") {
return <div>{this.props.prop}</div>;
return (
<div>
{this.props.prop}
</div>
);
} else {
return <div>{this.props.prop.toFixed(2)}</div>;
return (
<div>
{this.props.prop.toFixed(2)}
</div>
);
}
}
});

View File

@ -38,7 +38,11 @@ var HelloLocal = React.createClass({
},
render: function(): React.Element<*> {
return <div>{this.props.name}</div>;
return (
<div>
{this.props.name}
</div>
);
}
});
@ -82,7 +86,11 @@ var Hello = React.createClass({
},
render: function(): React.Element<*> {
return <div>{this.props.name}</div>;
return (
<div>
{this.props.name}
</div>
);
}
});
@ -128,7 +136,11 @@ class HelloLocal extends React.Component<void, { name: string }, void> {
name: React.PropTypes.string.isRequired
};
render(): React.Element<*> {
return <div>{this.props.name}</div>;
return (
<div>
{this.props.name}
</div>
);
}
}
@ -174,7 +186,11 @@ class Hello extends React.Component<void, { name: string }, void> {
};
render(): React.Element<*> {
return <div>{this.props.name}</div>;
return (
<div>
{this.props.name}
</div>
);
}
}
@ -220,7 +236,11 @@ class HelloLocal extends React.Component<void, Props, void> {
props: Props;
render(): React.Element<*> {
return <div>{this.props.name}</div>;
return (
<div>
{this.props.name}
</div>
);
}
}
@ -266,7 +286,11 @@ class Hello extends React.Component<{}, Props, void> {
static defaultProps: {};
render(): React.Element<*> {
return <div>{this.props.name}</div>;
return (
<div>
{this.props.name}
</div>
);
}
}

View File

@ -160,9 +160,14 @@ const render7B = () =>
</span>
</div>;
const render8 = props => <div>{props.text}</div>;
const render8 = props =>
<div>
{props.text}
</div>;
const render9 = props =>
<div>{props.looooooooooooooooooooooooooooooong_text}</div>;
<div>
{props.looooooooooooooooooooooooooooooong_text}
</div>;
const render10 = props =>
<div>
{props.even_looooooooooooooooooooooooooooooooooooooooooonger_contents}

View File

@ -284,7 +284,9 @@ const els = items.map(item => (
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const els = items.map(item =>
<div className="whatever">
<span>{children}</span>
<span>
{children}
</span>
</div>
);

View File

@ -38,9 +38,15 @@ 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>;
const MyCoolThing = ({ thingo }) =>
<li>
{thingo}
</li>;
`;