Flow: Keep parentheses wrap specific FunctionTypeAnnotation (#6717)

Co-Authored-By: Georgii Dolzhykov <thorn.mailbox@gmail.com>
master
Sosuke Suzuki 2019-11-02 17:39:18 +09:00 committed by Simon Lydell
parent a28e5c94c4
commit cf32f29d41
6 changed files with 146 additions and 13 deletions

View File

@ -1294,6 +1294,21 @@ export class User {
}
```
#### Flow: Parentheses around arrow functions' return types that have `FunctionTypeAnnotation` nested in `ObjectTypeAnnotation` ([#6717] by [@sosukesuzuki])
This is a workaround for a [bug](https://github.com/facebook/flow/pull/8163) in the Flow parser. Without the parentheses, the parser throws an error.
```js
// Input
const example1 = (): { p: (string => string) } => (0: any);
// Output (Prettier stable)
const example1 = (): { p: string => string } => (0: any);
// Output (Prettier master)
const example1 = (): ({ p: string => string }) => (0: any);
```
[#5682]: https://github.com/prettier/prettier/pull/5682
[#6657]: https://github.com/prettier/prettier/pull/6657
[#5910]: https://github.com/prettier/prettier/pull/5910
@ -1336,6 +1351,7 @@ export class User {
[#6673]: https://github.com/prettier/prettier/pull/6673
[#6695]: https://github.com/prettier/prettier/pull/6695
[#6694]: https://github.com/prettier/prettier/pull/6694
[#6717]: https://github.com/prettier/prettier/pull/6717
[#6728]: https://github.com/prettier/prettier/pull/6728
[@brainkim]: https://github.com/brainkim
[@duailibe]: https://github.com/duailibe

View File

@ -7,7 +7,8 @@ const comments = require("./comments");
const {
getLeftSidePathName,
hasFlowShorthandAnnotationComment,
hasNakedLeftSide
hasNakedLeftSide,
hasNode
} = require("./utils");
function hasClosureCompilerTypeCastComment(text, path) {
@ -758,6 +759,12 @@ function needsParens(path, options) {
parent.type !== "TypeCastExpression" &&
parent.type !== "VariableDeclarator")
);
case "TypeAnnotation":
return (
name === "returnType" &&
parent.type === "ArrowFunctionExpression" &&
includesFunctionTypeInObjectType(node)
);
}
return false;
@ -814,6 +821,16 @@ function isStatement(node) {
);
}
function includesFunctionTypeInObjectType(node) {
return hasNode(
node,
n1 =>
(n1.type === "ObjectTypeAnnotation" &&
hasNode(n1, n2 => n2.type === "FunctionTypeAnnotation" || undefined)) ||
undefined
);
}
function endsWithRightBracket(node) {
switch (node.type) {
case "ObjectExpression":

View File

@ -912,6 +912,7 @@ module.exports = {
hasNakedLeftSide,
hasNewlineBetweenOrAfterDecorators,
hasNgSideEffect,
hasNode,
hasPrettierIgnore,
hasTrailingComment,
identity,

View File

@ -1,5 +1,73 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`in_object_type.js 1`] = `
====================================options=====================================
parsers: ["flow"]
printWidth: 80
| printWidth
=====================================input======================================
const example1 = (): ({ p: string => string }) => (0: any);
const example2 = (): ({ p: { p: string => string } }) => (0: any);
const example3 = (): ({ p: { p: { p: string => string } } }) => (0: any);
const example4 = (): ({ p: { p: ?{ p: string => string } } }) => (0: any);
const example5 = (): ({ p: { p: { p: string => string } | string } }) =>
(0: any);
const example6 = (): ({ p: { p: { p: string => string } & string } }) =>
(0: any);
const example7 = (): ({ p: { p: { p: [(string) => string, string] } } }) =>
(0: any);
function example8(): { p: string => string } {
return (0: any);
}
function example9(): { p: { p: string => string } } {
return (0: any);
}
function example10(): { p: { p: { p: string => string } } } {
return (0: any);
}
const example11 = (): ({ p: string => string } & string) => (0: any);
const example12 = (): ({ p: string => string } | string) => (0: any);
const example13 = (): ([{ p: string => string }, string]) => (0: any);
const example14 = (): ({ p: string => string }[]) => (0: any);
const example15 = (): ({ p: { p: { p: (string => string) & string } } }) =>
(0: any);
const example16 = (): ({ p: { p: { p: (string => string) | string } } }) =>
(0: any);
const example17 = (): (?{ p: string => string }) => (0: any);
=====================================output=====================================
const example1 = (): ({ p: string => string }) => (0: any);
const example2 = (): ({ p: { p: string => string } }) => (0: any);
const example3 = (): ({ p: { p: { p: string => string } } }) => (0: any);
const example4 = (): ({ p: { p: ?{ p: string => string } } }) => (0: any);
const example5 = (): ({ p: { p: { p: string => string } | string } }) =>
(0: any);
const example6 = (): ({ p: { p: { p: string => string } & string } }) =>
(0: any);
const example7 = (): ({ p: { p: { p: [(string) => string, string] } } }) =>
(0: any);
function example8(): { p: string => string } {
return (0: any);
}
function example9(): { p: { p: string => string } } {
return (0: any);
}
function example10(): { p: { p: { p: string => string } } } {
return (0: any);
}
const example11 = (): ({ p: string => string } & string) => (0: any);
const example12 = (): ({ p: string => string } | string) => (0: any);
const example13 = (): ([{ p: string => string }, string]) => (0: any);
const example14 = (): ({ p: string => string }[]) => (0: any);
const example15 = (): ({ p: { p: { p: (string => string) & string } } }) =>
(0: any);
const example16 = (): ({ p: { p: { p: (string => string) | string } } }) =>
(0: any);
const example17 = (): (?{ p: string => string }) => (0: any);
================================================================================
`;
exports[`issue-1249.js 1`] = `
====================================options=====================================
parsers: ["flow"]
@ -60,16 +128,18 @@ parsers: ["flow"]
printWidth: 80
| printWidth
=====================================input======================================
const f = (): (string => string) => {};
const f = (): (a | string => string) => {};
const f = (): (a & string => string) => {};
function f(): string => string {}
const f1 = (): (string => string) => {};
const f2 = (): ?(y => {a: b => c}) => (0: any);
const f3 = (): (a | string => string) => {};
const f4 = (): (a & string => string) => {};
function f5(): string => string {}
=====================================output=====================================
const f = (): (string => string) => {};
const f = (): a | (string => string) => {};
const f = (): a & (string => string) => {};
function f(): string => string {}
const f1 = (): (string => string) => {};
const f2 = (): (?(y) => { a: b => c }) => (0: any);
const f3 = (): a | (string => string) => {};
const f4 = (): a & (string => string) => {};
function f5(): string => string {}
================================================================================
`;

View File

@ -0,0 +1,28 @@
const example1 = (): ({ p: string => string }) => (0: any);
const example2 = (): ({ p: { p: string => string } }) => (0: any);
const example3 = (): ({ p: { p: { p: string => string } } }) => (0: any);
const example4 = (): ({ p: { p: ?{ p: string => string } } }) => (0: any);
const example5 = (): ({ p: { p: { p: string => string } | string } }) =>
(0: any);
const example6 = (): ({ p: { p: { p: string => string } & string } }) =>
(0: any);
const example7 = (): ({ p: { p: { p: [(string) => string, string] } } }) =>
(0: any);
function example8(): { p: string => string } {
return (0: any);
}
function example9(): { p: { p: string => string } } {
return (0: any);
}
function example10(): { p: { p: { p: string => string } } } {
return (0: any);
}
const example11 = (): ({ p: string => string } & string) => (0: any);
const example12 = (): ({ p: string => string } | string) => (0: any);
const example13 = (): ([{ p: string => string }, string]) => (0: any);
const example14 = (): ({ p: string => string }[]) => (0: any);
const example15 = (): ({ p: { p: { p: (string => string) & string } } }) =>
(0: any);
const example16 = (): ({ p: { p: { p: (string => string) | string } } }) =>
(0: any);
const example17 = (): (?{ p: string => string }) => (0: any);

View File

@ -1,4 +1,5 @@
const f = (): (string => string) => {};
const f = (): (a | string => string) => {};
const f = (): (a & string => string) => {};
function f(): string => string {}
const f1 = (): (string => string) => {};
const f2 = (): ?(y => {a: b => c}) => (0: any);
const f3 = (): (a | string => string) => {};
const f4 = (): (a & string => string) => {};
function f5(): string => string {}