-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Respect paren + newline #2208
Comments
@vjeux some people can't use a mouse. Also, respecting parens still allows you to do the same thing you are right now. |
I just wanted to chime in here and say that, for whatever it's worth, this is the single biggest thing keeping me from using prettier from day to day. If prettier would respect my use of |
+1! This would also help with making {things.map(
thing =>
somePredicate ? <div>Some stuff</div> : <div>Some other stuff</div>
)}
// vs
// closer to an if-else, easier to logically group
{things.map(thing =>
somePredicate ? (
<div>Some stuff</div>
) : (
<div>Some other stuff</div>
)
)} I've also noticed that diffs are easier to read in this style, especially with GitHub intra-line highlighting. |
Why wouldn't prettier make the unilateral decision to have delimiters added or removed in certain situations? I thought the goal of prettier was to alleviate engineers from spending time on this sort of stuff. And maybe it's easier/cleaner/simpler to implement. There are good reasons to stick to @ryanflorence's style in the examples he presents. Can anybody come up with counter examples where you'd really want the current style? |
I've generally only run into this issue when dealing with JSX, but that might just be because ternaries and wrapping parens are more common in JSX. That said, it does feel like the "one last thing" that makes prettier feel not-quite-ready-yet, at least for projects using JSX. |
@ryanflorence does your atom vim emulation have the tag text object? I personally prefer ensuring consistent (removal of unnecessary) paren usage, but I wouldn't be angry if prettier respected some of them in certain situations. |
I like and use Prettier a lot, but when reading this I realized that I often mess up my |
This is especially painful with non-mouse based text editors like vim and emacs. |
This change would also have the added benefit of keeping clear and consistent indentation with closing parens/braces. When this is off my spidey-sense tingles and tells me I must have forgotten a closer somewhere. Per @ryanflorence's example: const Slider = ({ isOpen, title, children }) =>
<div>
<h1>{title}</h1>
{isOpen &&
<div>
{children}
</div>}
{/* broken indentation */}
</div>;
// broken indentation |
Fwiw, even with a mouse it's still easier to select maintaining parens + |
For those unfamiliar, the first example is actually the result of a recent change which some people were not thrilled about, myself included. The idea seems to be to remove parens everywhere possible, consistently, but I'm unclear on the motivation for that. At least for me, this seems to ignore important semantics/conventions (e.g. Airbnb style) which this issue and @taylorham's "spidey-sense" are specific manifestations of. I'd personally still like to see parens auto-included for all multi-line expressions (with possible, unconditional exceptions?) rather than conditionally maintaining them, but I would appreciate the consistency with curly-brace blocks in this proposal. |
@vjeux how do these things get decided? What does the "needs discussion" label mean? I have no idea if 50 👍's on the issue means anything, but I'm hopeful. I'm really excited about prettier with this one small adjustment. |
For semicolons, it seemed like the pattern was "people discussed it for ages, then someone made a PR that just added it, and it got merged"... |
To me Ryans suggestion will also make it easier to review changes, as the diff for moving a block around will not contain noise bracket modifications. |
It sounds like my issue #2180 is similar. |
Could someone try to implement parenthesis with ?: as displayed in the original post within prettier to see how it would look? |
@vjeux I haven't looked at prettier's codebase enough to know what things are hard and what are easy, but would this heuristic work?
or if that's too hard:
This would cover JSX arrow expressions and JSX expressions in ternaries, which seem to be the most common case. @ryanflorence is asking for "leave parens around if I put them there", but my understanding is that this is nontrivial to do in prettier (particularly because parens aren't a node in the AST). Is that correct? This isn't the first time I wished Babylon had a nonstandard node for parens just so you could differentiate this type of situation. If it did, then implementing what Ryan is asking for would probably be what had happened by default. |
I don't think that the solution of putting parenthesis if the user inputted them or dropping them if not is great. It's going to introduce inconsistencies within a codebase and is just a crutch because we want to support two different opinions. I've been quiet on this because I was focused on other things (TypeScript, CSS, GraphQL, CSS-in-JS, Website, Facebook rollout) but now that those are in order, it's time to look into parenthesis and JSX as it's the last thing that people are heavily in disagreement with the current way prettier is printing code. I would like to investigate how hard it would be to implement the following style for JSX and what are the unforeseen consequences. cond
? (
<div>
Text 1
</div>
) : (
<div>
Text 2
</div>
) Also I want to revisit dropping the parenthesis for arrow functions and figure in what other context JSX is being printed and if we need to do something about it. |
@vjeux a few "precendents" I see.
Prettier already allows for this type of inconsistency, it leaves both of these alone: if (bool) {
doStuff();
}
if (bool) doStuff(); But indeed, I'd be even happier if adding parens was the prettier opinion 😍
I tried to dig in a little but I have very little experience with ASTs. I didn't really get anywhere and some other stuff is on my plate now.
Are you doing this investigation or do we need to try to find somebody?
👍 I'm fine with this: cond
? (
<div>
Text 1
</div>
) : (
<div>
Text 2
</div>
) But would rather save some indentation and get it symmetrical with an if/else block cond ? (
<div>
Text 1
</div>
) : (
<div>
Text 2
</div>
) And need to account for more complex ternaries: cond ? (
<div>
Text 1
</div>
) : cond2 ? (
<div>
Text 2
</div>
) : (
<div>
Text 3
</div>
) That has perfect symmetry to if/else if/else.
|
For what it's worth, I would usually write this: cond ? (
<div>
Text 1
</div>
) : (
<div>
Text 2
</div>
) ( But I don't want to bikeshed too much. Here's the places where I (personally) find myself wanting parens around JSX:
const Something = ({ foo }) => (
<div>
{foo}
</div>
);
const Something = ({ foo }) => {
const calculatedFoo = foo + 2;
return (
<div>
{calculatedFoo}
</div>
);
};
// (in class body)
render() {
return (
<div>
{this.props.foo}
</div>
);
}
// (in class body)
render() {
const formattedFoo = (
<div className="bla">
{foo}
</div>
);
return (
<div>
{formattedFoo}
</div>
);
} When using a ternary within JSX (even if the ternary's consequent or alternate are not JSX) // in render method or functional component
const { isFoo, bar } = this.props;
return (
<div>
{isFoo ? (
"Foo ()"
) : (
<span>{bar}</span>
)}
</div>
); When using a ternary in a React render method where the outermost expression is not JSX (and the ternary's consequent or alternate may or may not be JSX) // in render method or functional component
const { isFoo, bar } = this.props;
return isFoo ? (
"Foo ()"
) : (
<span>{bar}</span>
); That last one is hard to detect, I know... There might be more edge cases but these are what I can think of off the top of my head right now. |
I'm heading to a ~2-week vacations in France, so hopefully trying to find somebody. But I'll be actively involved. |
The issue with cond ? (
<div>
Text 1
</div>
) : (
<div>
Text 2
</div>
) is that it's different from the way we print ternaries everywhere else inside of prettier. But that's worth exploring. |
I'd personally be fine with changing all ternary printing for the sake of this use case... but I recognize that change might carry some heavy weight, so it's probably not the right thing to do 😉 I might be able to take a stab at this (not at changing all ternaries- at the JSX examples described) on July 4th. |
I agree with @suchipi in that it’s worth testing out always printing multiline ternaries the @ryanflorence way, regardless of whether there’s JSX inside or not. Might turn out really nice (or not, but we’ll see). |
I'd say not if one or both expressions could be inlined (various variations): cond
? aaaaa
: bbbbb
cond ? a : b
cond
? aaaaa
: (
<div>
text
</div>
)
cond ? a : (
<div>
text
</div>
)
cond
? (
<div>
text
</div>
) : bbbb etc.. Effectively treating |
* Arrow Function Expressions returning JSX will now add parens when the JSX breaks * Conditional expressions within (or containing) JSX are formatted in a more natural way (for JSX), especiall when chained * JSX in logical expressions (|| or &&) is always wrapped in parens Fixes prettier#2208
I've made a PR that:
// Before
const MyThing = () =>
<div>
<span>Hi</span>
</div>;
// After
const MyThing = () => (
<div>
<span>Hi</span>
</div>
);
// Before
const MyThing = () =>
<div>
{isGood
? <div>
<span>"yeah it's good"</span>
</div>
: isOkay ? <div>it's okay</div> : null}
</div>;
// After:
const MyThing = () => (
<div>
{isGood ? (
<div>
<span>
"yeah it's good"
</span>
</div>
) : isOkay ? (
<div>it's okay</div>
) : (
null
)}
</div>
);
// Before:
<div>
{a || <span />}
</div>;
// After:
<div>
{a || (
<span />
)}
</div>; |
* Arrow Function Expressions returning JSX will now add parens when the JSX breaks * Conditional expressions within (or containing) JSX are formatted in a more natural way (for JSX), especiall when chained * JSX in logical expressions (|| or &&) is always wrapped in parens Fixes prettier#2208
Is there a flag to switch this new formatting off? I thought it's a bug at first and landed here. I don't use vim and i have no problems refactoring. All i see is that suddenly it stretches code into something that i wouldn't call an improvement. It was easy to read and glance over before, now it looks odd and noisy to me. It's actually the first time i can think of that prettier has produced code that's harder to read and looks machine translated. For us this is a major change that came out of the blue, we had to switch off prettier auto-formatting and it's the weirdest feeling to format by hand again. 🙁 |
@drcmda please move your comment to a new issue. (FWIW, I expect that issue will be closed, but it's helpful to be able to track community reaction – if lots of people agree with you, we may consider). |
Hi friends!
Been using prettier full time for a while now and it's prettier great. I'd like to request one change that I think makes refactoring less error prone: respect
(
+ newline the same wayif {
+ newline is treated.I think doing the same for multi-line expressions (which happen all the time in JSX) would be equally beneficial. Since using prettier, I am getting a lot more syntax errors as I refactor my code because it puts the code on the same lines as the syntax. JSX is the most affected part in my code since it's expression heavy, and also the most likely to be moved around as you build and refactor a UI.
Some examples
For example, consider this code:
Prettier changes it to:
If I am refactoring and move the
<div/>
somewhere else, maybe I'm inlining it into a different component, that semi-colon comes along with the div leading to syntax errors or in this case just a printed;
in the UI if you don't catch it.Additionally, the closing
}
in theisOpen
block gets put on the same line as the closing div, so refactoring that block is more likely to result in accidental syntax errors:If parens were respected like if block curlies
However, if the parens were respected (just like if block's curlies) we can just move stuff around w/o spending extra time adjusting syntax.
Ternaries are also much easier to work with if the parens are respected:
As compared to not respecting them:
I am not proposing prettier insert parens and new lines but rather, do what it does today, except when a developer puts a paren + newline in, respect it the same way an
if {
is respected.Thanks! 💙💙💙
The text was updated successfully, but these errors were encountered: