Wrap Stateless JSX Arrow Functions and Assignment in Parens (fixes part of #73)

master
Alex Rattray 2017-01-11 15:15:12 -08:00 committed by James Long
parent 31a07feb84
commit d91a28ef81
6 changed files with 233 additions and 82 deletions

View File

@ -343,12 +343,20 @@ function genericPrintNoParens(path, options, print) {
parts.push(" =>");
const body = path.call(print, "body");
const collapsed = concat([ concat(parts), " ", body ]);
if (n.body.type === "JSXElement") {
return group(collapsed);
}
return conditionalGroup([
concat([ concat(parts), " ", path.call(print, "body") ]),
concat([ concat(parts),
indent(options.tabWidth,
concat([line, path.call(print, "body")]))])
])
collapsed,
concat([
concat(parts),
indent(options.tabWidth, concat([ line, body ])),
]),
]);
case "MethodDefinition":
if (n.static) {
parts.push("static ");
@ -553,22 +561,8 @@ function genericPrintNoParens(path, options, print) {
case "ReturnStatement":
parts.push("return");
var arg = path.call(print, "argument");
if (n.argument) {
if (
namedTypes.JSXElement && namedTypes.JSXElement.check(n.argument) &&
hasHardLine(arg)
) {
parts.push(
" (",
indent(options.tabWidth, concat([ hardline, arg ])),
hardline,
")"
);
} else {
parts.push(" ", arg);
}
parts.push(" ", path.call(print, "argument"));
}
parts.push(";");
@ -1091,50 +1085,7 @@ function genericPrintNoParens(path, options, print) {
"}"
]));
case "JSXElement":
var openingLines = path.call(print, "openingElement");
if (n.openingElement.selfClosing) {
assert.ok(!n.closingElement);
return openingLines;
}
var children = [];
path.map(
function(childPath) {
var child = childPath.getValue();
if (
namedTypes.Literal.check(child) && typeof child.value === "string"
) {
if (/\S/.test(child.value)) {
const beginBreak = child.value.match(/^\s*\n/);
const endBreak = child.value.match(/\n\s*$/);
children.push(
beginBreak ? hardline : "",
child.value.replace(/^\s+|\s+$/g, ""),
endBreak ? hardline : ""
);
} else if (/\n/.test(child.value)) {
children.push(hardline);
}
} else {
children.push(print(childPath));
}
},
"children"
);
var mostChildren = children.slice(0, -1);
var closingLines = path.call(print, "closingElement");
return concat([
openingLines,
indent(options.tabWidth, concat(mostChildren)),
util.getLast(children) || "",
closingLines
]);
return printJSXElement(path, options, print);
case "JSXOpeningElement":
return group(
concat([
@ -2053,6 +2004,67 @@ function printMemberChain(node, options, print) {
}
}
function printJSXElement(path, options, print) {
const n = path.getValue();
var openingLines = path.call(print, "openingElement");
let elem;
if (n.openingElement.selfClosing) {
assert.ok(!n.closingElement);
elem = openingLines;
} else {
var children = [];
path.map(
function(childPath) {
var child = childPath.getValue();
if (
namedTypes.Literal.check(child) && typeof child.value === "string"
) {
if (/\S/.test(child.value)) {
const beginBreak = child.value.match(/^\s*\n/);
const endBreak = child.value.match(/\n\s*$/);
children.push(
beginBreak ? hardline : "",
child.value.replace(/^\s+|\s+$/g, ""),
endBreak ? hardline : ""
);
} else if (/\n/.test(child.value)) {
children.push(hardline);
}
} else {
children.push(print(childPath));
}
},
"children"
);
var mostChildren = children.slice(0, -1);
var closingLines = path.call(print, "closingElement");
elem = concat([
openingLines,
indent(options.tabWidth, concat(mostChildren)),
util.getLast(children) || "",
closingLines
]);
}
const parent = path.getParentNode();
if (!parent || parent.type === "JSXElement" || parent.type === "ExpressionStatement") {
return elem;
}
return multilineGroup(concat([
ifBreak("("),
indent(options.tabWidth, concat([ softline, elem ])),
softline,
ifBreak(")"),
]));
}
function adjustClause(clause, options, forceSpace) {
if (isCurlyBracket(clause) || forceSpace) {
return concat([ " ", clause ]);

View File

@ -39,9 +39,9 @@ var c: React.Element<any> = <div not_a_real_attr=\"asdf\" />;
// different attributes.
var d: React.Element<{ doesntmatch: string }> = <div not_a_real_attr=\"asdf\" />;
// No error as long as expectations are consistent, though.
var e: React.Element<{
not_a_real_attr: string
}> = <div not_a_real_attr=\"asdf\" />;
var e: React.Element<{ not_a_real_attr: string }> = (
<div not_a_real_attr=\"asdf\" />
);
"
`;

View File

@ -32,9 +32,9 @@ var b: React.Element<{ prop1: string }> = <CustomComponent prop=\"asdf\" />;
<div id={42} />;
// Error: (\`id\` prop) number ~> string
var c: React.Element<{ id: string }> = <div id=\"asdf\" />;
var d: React.Element<{
id: number
}> = <div id=\"asdf\" />; // Error: Props<{id:string}> ~> Props<{id:number}>
var d: React.Element<{ id: number }> = (
<div id=\"asdf\" />
); // Error: Props<{id:string}> ~> Props<{id:number}>
"
`;

View File

@ -13,18 +13,6 @@ function fn() {
"
`;
exports[`test method-chain.js 1`] = `
"method().then(x => x)
[\"abc\"](x => x)
[abc](x => x);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method()
.then(x => x)
[\"abc\"](x => x)
[abc](x => x);
"
`;
exports[`test exports.js 1`] = `
"export { value1, value2 as value2_renamed, value3, value4 as value4_renamed, value5 } from \"exports\";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -38,6 +26,121 @@ export {
"
`;
exports[`test jsx-multiline-assign.js 1`] = `
"const comp1 = (
<div style={styles} key=\"something\">
Keep the wrapping parens.
</div>
);
const comp2 = <div style={styles} key=\"something\">
Create wrapping parens.
</div>;
comp2A = <div style={styles} key=\"something\">
Create wrapping parens.
</div>;
const comp3 = <div style={styles} key=\"something\">Bump to next line without parens</div>;
const comp4 = <div style={styles} key=\"something\">Create wrapping parens and indent <strong>all the things</strong>.</div>;
const comp5 = <div>Keep it on one line.</div>;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const comp1 = (
<div style={styles} key=\"something\">
Keep the wrapping parens.
</div>
);
const comp2 = (
<div style={styles} key=\"something\">
Create wrapping parens.
</div>
);
comp2A = (
<div style={styles} key=\"something\">
Create wrapping parens.
</div>
);
const comp3 = (
<div style={styles} key=\"something\">Bump to next line without parens</div>
);
const comp4 = (
<div style={
styles
} key=\"something\">Create wrapping parens and indent<strong>all the things</strong>.</div>
);
const comp5 = <div>Keep it on one line.</div>;
"
`;
exports[`test jsx-stateless-arrow-fn.js 1`] = `
"const render1 = ({ styles }) => (
<div style={styles} key=\"something\">
Keep the wrapping parens. Put each key on its own line.
</div>
);
const render2 = ({ styles }) => <div style={styles} key=\"something\">
Create wrapping parens.
</div>;
const render3 = ({ styles }) => <div style={styles} key=\"something\">Bump to next line without parens</div>;
const render4 = ({ styles }) => <div style={styles} key=\"something\">Create wrapping parens and indent <strong>all the things</strong>.</div>;
const render5 = ({ styles }) => <div>Keep it on one line.</div>;
const notJSX = (aaaaaaaaaaaaaaaaa, bbbbbbbbbbb) => this.someLongCallWithParams(aaaaaa, bbbbbbb).anotherLongCallWithParams(cccccccccccc, dddddddddddddddddddddd)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const render1 = ({ styles }) => (
<div style={styles} key=\"something\">
Keep the wrapping parens. Put each key on its own line.
</div>
);
const render2 = ({ styles }) => (
<div style={styles} key=\"something\">
Create wrapping parens.
</div>
);
const render3 = ({ styles }) => (
<div style={styles} key=\"something\">Bump to next line without parens</div>
);
const render4 = ({ styles }) => (
<div style={
styles
} key=\"something\">Create wrapping parens and indent<strong>all the things</strong>.</div>
);
const render5 = ({ styles }) => <div>Keep it on one line.</div>;
const notJSX = (aaaaaaaaaaaaaaaaa, bbbbbbbbbbb) =>
this
.someLongCallWithParams(aaaaaa, bbbbbbb)
.anotherLongCallWithParams(cccccccccccc, dddddddddddddddddddddd);
"
`;
exports[`test method-chain.js 1`] = `
"method().then(x => x)
[\"abc\"](x => x)
[abc](x => x);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method()
.then(x => x)
[\"abc\"](x => x)
[abc](x => x);
"
`;
exports[`test optional-type-name.js 1`] = `
"type Foo = (any) => string

View File

@ -0,0 +1,19 @@
const comp1 = (
<div style={styles} key="something">
Keep the wrapping parens.
</div>
);
const comp2 = <div style={styles} key="something">
Create wrapping parens.
</div>;
comp2A = <div style={styles} key="something">
Create wrapping parens.
</div>;
const comp3 = <div style={styles} key="something">Bump to next line without parens</div>;
const comp4 = <div style={styles} key="something">Create wrapping parens and indent <strong>all the things</strong>.</div>;
const comp5 = <div>Keep it on one line.</div>;

View File

@ -0,0 +1,17 @@
const render1 = ({ styles }) => (
<div style={styles} key="something">
Keep the wrapping parens. Put each key on its own line.
</div>
);
const render2 = ({ styles }) => <div style={styles} key="something">
Create wrapping parens.
</div>;
const render3 = ({ styles }) => <div style={styles} key="something">Bump to next line without parens</div>;
const render4 = ({ styles }) => <div style={styles} key="something">Create wrapping parens and indent <strong>all the things</strong>.</div>;
const render5 = ({ styles }) => <div>Keep it on one line.</div>;
const notJSX = (aaaaaaaaaaaaaaaaa, bbbbbbbbbbb) => this.someLongCallWithParams(aaaaaa, bbbbbbb).anotherLongCallWithParams(cccccccccccc, dddddddddddddddddddddd)