-
-
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
Support better formatting for curried arrow functions #9992
Conversation
This comment has been minimized.
This comment has been minimized.
fooooooooooooooooooooooooooooooooooooooooooooooooooo( | ||
(action) => | ||
(next) => dispatch(action) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems not pretty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe no break before first level parameters more reasonable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you mean? Should be like below?:
fooooooooooooooooooooooooooooooooooooooooooooooooooo((action) =>
(next) => dispatch(action)
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I mean this, but I'm not sure. Better idea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer not breaking the chain if it fits on one line:
fooooooooooooooooooooooooooooooooooooooooooooooooooo(
(action) => (next) => dispatch(action)
);
And if the chain is long enough, then:
fooooooooooooooooooooooooooooooooooooooooooooooooooo(
(action) =>
(next) =>
(next) =>
(next) =>
(next) =>
(next) =>
(next) =>
dispatch(action)
);
This is similar to how Prettier formats binary expressions in call arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case, assign print like this?
const foo = (action) =>
(next) =>
(next) =>
(next) =>
(next) =>
(next) =>
(next) =>
dispatch(action)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assignments are complicated. To make the chain look uniform and to avoid dealing with edge cases (#2482), it's better to break after =
.
const foo =
(action) =>
(next) =>
(next) =>
(next) =>
(next) =>
(next) =>
(next) =>
dispatch(action)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you. I agree with thorn0's suggestions.
Can anyone review? |
src/language-js/utils.js
Outdated
@@ -1337,6 +1333,18 @@ function getComments(node, flags, fn) { | |||
const isNextLineEmpty = (node, { originalText }) => | |||
isNextLineEmptyAfterIndex(originalText, locEnd(node)); | |||
|
|||
function isCallLikeExpression(node) { | |||
return isCallOrOptionalCallExpression(node) || node.type === "NewExpression"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is silly, but can we add import()
too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prettier pr-9992
Playground link
--parser babel
--prose-wrap always
Input:
import( (argument1) =>
(argument2) =>
(argument3) =>
(argument4) =>
(argument5) =>
(argument6) =>
(argument7) =>
(argument8) =>
(argument9) =>
(argument10) =>
(argument11) =>
(argument12) => {
const foo = "foo";
return foo + "bar";
});
Output:
import(
(argument1) =>
(argument2) =>
(argument3) =>
(argument4) =>
(argument5) =>
(argument6) =>
(argument7) =>
(argument8) =>
(argument9) =>
(argument10) =>
(argument11) =>
(argument12) => {
const foo = "foo";
return foo + "bar";
}
);
Prettier pr-9992
Playground link
--parser meriyah
--prose-wrap always
Input:
import( (argument1) =>
(argument2) =>
(argument3) =>
(argument4) =>
(argument5) =>
(argument6) =>
(argument7) =>
(argument8) =>
(argument9) =>
(argument10) =>
(argument11) =>
(argument12) => {
const foo = "foo";
return foo + "bar";
});
Output:
import(
(argument1) =>
(argument2) =>
(argument3) =>
(argument4) =>
(argument5) =>
(argument6) =>
(argument7) =>
(argument8) =>
(argument9) =>
(argument10) =>
(argument11) =>
(argument12) => {
const foo = "foo";
return foo + "bar";
}
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot add ImportExpression
to isCallLikeExpression
because import(...)
isn't like call expression. But I changed to format import and curried functions in the same way as call expressions ( 2de96ba ).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, didn't see this, I think we should, we already treat it like CallExpression
everywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about #9992 (comment) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This why I added
prettier/src/language-js/utils.js
Lines 1210 to 1235 in 2f3fc24
const callArgumentsCache = new WeakMap(); | |
function getCallArguments(node) { | |
if (callArgumentsCache.has(node)) { | |
return callArgumentsCache.get(node); | |
} | |
const args = | |
node.type === "ImportExpression" | |
? // No parser except `babel` supports `import("./foo.json", { assert: { type: "json" } })` yet, | |
// And `babel` parser it as `CallExpression` | |
// We need add the second argument here | |
[node.source] | |
: node.arguments; | |
callArgumentsCache.set(node, args); | |
return args; | |
} | |
function iterateCallArgumentsPath(path, iteratee) { | |
const node = path.getValue(); | |
// See comment in `getCallArguments` | |
if (node.type === "ImportExpression") { | |
path.call((sourcePath) => iteratee(sourcePath, 0), "source"); | |
} else { | |
path.each(iteratee, "arguments"); | |
} | |
} |
node.arguments
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I'll fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done 6fb35ae
I need some more time to look into this. Sorry for the delay. |
I'm afraid this change might be too drastic. Before merging we need to test it on a couple of codebases that heavily use curried arrow functions. Anybody know of such projects we can use for testing? |
Looks very good overall. I have comments on two things. (1) What's the story behind this difference? Prettier pr-9992 --parser babel Input: const curryTest =
(argument1) =>
(argument2) => ({
foo: argument1,
bar: argument2,
});
const curryTest =
(argument1) =>
(argument2) =>
(argument3) => ({
foo: argument1,
bar: argument2,
});
Output: const curryTest =
(argument1) =>
(argument2) => ({
foo: argument1,
bar: argument2,
});
const curryTest =
(argument1) =>
(argument2) =>
(argument3) =>
({
foo: argument1,
bar: argument2,
}); (2) After playing with different examples, I decided that after all it's better to add another level of indentation to the body when the body is an expression. const curryTest =
(argument1) =>
(argument2) =>
(argument3) =>
argument1 + argument2 + argument3;
const foo =
(action) =>
(next) =>
(next) =>
(next) =>
(next) =>
(next) =>
(next) =>
({
foo: argument1,
bar: argument2,
}); Looks a bit better to me than the current output: const curryTest =
(argument1) =>
(argument2) =>
(argument3) =>
argument1 + argument2 + argument3;
const foo =
(action) =>
(next) =>
(next) =>
(next) =>
(next) =>
(next) =>
(next) =>
({
foo: argument1,
bar: argument2,
}); |
@sosukesuzuki I can't request your review because it's your PR, but please take a look. I tried to minimize the diff in prettier/prettier-regression-testing#40 and only fix what was reported in #9985.
request.get("https://preview-9992--prettier.netlify.app", (head) => (body) => {
console.log(head, body);
}); I'm not sure we have to keep it, but it looks intended. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't approve this PR on GitHub because I opened this.
But LGTM! Thank you!
Oops. Sure, it's a corner case, but assignment chains and arrow chains don't play well together: Prettier pr-9992 --parser babel
--print-width 75 Input: a=b=d=(
argumentOne,
argumentTwo,
argumentThree
) => restOfTheArguments123 => {
return "baz";
} Output: a =
b =
d =
(argumentOne, argumentTwo, argumentThree) =>
(restOfTheArguments123) => {
return "baz";
}; |
how do I rollback to the previous behavior? |
Am I correct in this not being toggleable / configurable? I'm surprised by how much this indentation to swaths of our codebase 😆 Personally I'm fine with the formatting (whatever's consistent) but I think something like this needs an "opt out" so people could upgrade prettier and delay the change. In the README, it'd be good to get more details on if this is tweakable somehow. |
You(users) cannot rollback to prev behavior. But if you have actual code examples made harder to read by this feature, you can report it as a bug. And it'll help us to improve formatting heuristics. |
I upgraded to 2.3 earlier today and after running export const createCombinedReducer = (): Reducer<State> =>
// Wrap root reducer to handle store reset actions
(state, action) => {
if (action.type === SystemAction.Reset) {
return rootReducer(undefined, action);
}
return rootReducer(state, action);
}; The reformatted version (100 chars wide) looks like this, which in my view is much uglier than before: export const createCombinedReducer =
(): Reducer<State> =>
// Wrap root reducer to handle store reset actions
(state, action) => {
if (action.type === SystemAction.Reset) {
return rootReducer(undefined, action);
}
return rootReducer(state, action);
}; If I remove the comment from line 3 it becomes something totally different again: export const createCombinedReducer = (): Reducer<State> => (state, action) => {
if (action.type === SystemAction.Reset) {
return rootReducer(undefined, action);
}
return rootReducer(state, action);
}; Is there a flag to disable moving P.S. |
…tier#9992 Changelog: None Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Description
Fixes #9985
Checklist
changelog_unreleased/*/XXXX.md
file followingchangelog_unreleased/TEMPLATE.md
.✨Try the playground for this PR✨