Skip to content

Commit

Permalink
Fix handling of parenthesis with {Optional}IndexedAccess (#11051)
Browse files Browse the repository at this point in the history
  • Loading branch information
gkz committed Jun 12, 2021
1 parent 1aa188e commit 14188ae
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 11 deletions.
27 changes: 27 additions & 0 deletions changelog_unreleased/flow/11051.md
@@ -0,0 +1,27 @@
#### Fix handling of parenthesis with Flow's {Optional}IndexedAccess (#11051 by @gkz)

Add parens when required.

<!-- prettier-ignore -->
```jsx
// Input
type A = (T & S)['bar'];
type B = (T | S)['bar'];
type C = (?T)['bar'];
type D = (typeof x)['bar'];
type E = (string => void)['bar'];

// Prettier stable
type A = T & S["bar"];
type B = T | S["bar"];
type C = ?T["bar"];
type D = typeof x["bar"];
type E = (string) => void["bar"];

// Prettier main
type A = (T & S)["bar"];
type B = (T | S)["bar"];
type C = (?T)["bar"];
type D = (typeof x)["bar"];
type E = ((string) => void)["bar"];
```
22 changes: 20 additions & 2 deletions src/language-js/needs-parens.js
Expand Up @@ -461,11 +461,19 @@ function needsParens(path, options) {
parent.type === "ArrayTypeAnnotation" ||
parent.type === "NullableTypeAnnotation" ||
parent.type === "IntersectionTypeAnnotation" ||
parent.type === "UnionTypeAnnotation"
parent.type === "UnionTypeAnnotation" ||
(name === "objectType" &&
(parent.type === "IndexedAccessType" ||
parent.type === "OptionalIndexedAccessType"))
);

case "NullableTypeAnnotation":
return parent.type === "ArrayTypeAnnotation";
return (
parent.type === "ArrayTypeAnnotation" ||
(name === "objectType" &&
(parent.type === "IndexedAccessType" ||
parent.type === "OptionalIndexedAccessType"))
);

case "FunctionTypeAnnotation": {
const ancestor =
Expand All @@ -477,6 +485,9 @@ function needsParens(path, options) {
ancestor.type === "UnionTypeAnnotation" ||
ancestor.type === "IntersectionTypeAnnotation" ||
ancestor.type === "ArrayTypeAnnotation" ||
(name === "objectType" &&
(ancestor.type === "IndexedAccessType" ||
ancestor.type === "OptionalIndexedAccessType")) ||
// We should check ancestor's parent to know whether the parentheses
// are really needed, but since ??T doesn't make sense this check
// will almost never be true.
Expand All @@ -495,6 +506,13 @@ function needsParens(path, options) {
case "OptionalIndexedAccessType":
return name === "objectType" && parent.type === "IndexedAccessType";

case "TypeofTypeAnnotation":
return (
name === "objectType" &&
(parent.type === "IndexedAccessType" ||
parent.type === "OptionalIndexedAccessType")
);

case "StringLiteral":
case "NumericLiteral":
case "Literal":
Expand Down
12 changes: 12 additions & 0 deletions tests/format/flow/indexed-access/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -9,8 +9,20 @@ trailingComma: "all"
=====================================input======================================
const x: Obj['bar'] = 1;
type A = (T & S)['bar'];
type B = (T | S)['bar'];
type C = (?T)['bar'];
type D = (typeof x)['bar'];
type E = (string => void)['bar'];
=====================================output=====================================
const x: Obj["bar"] = 1;
type A = (T & S)["bar"];
type B = (T | S)["bar"];
type C = (?T)["bar"];
type D = (typeof x)["bar"];
type E = ((string) => void)["bar"];
================================================================================
`;
6 changes: 6 additions & 0 deletions tests/format/flow/indexed-access/indexed-access.js
@@ -1 +1,7 @@
const x: Obj['bar'] = 1;

type A = (T & S)['bar'];
type B = (T | S)['bar'];
type C = (?T)['bar'];
type D = (typeof x)['bar'];
type E = (string => void)['bar'];
Expand Up @@ -8,21 +8,25 @@ trailingComma: "all"
| printWidth
=====================================input======================================
type A = Obj?.['foo'];
type B = Obj?.['foo']['bar'];
type C = Obj['foo']?.['bar'];
type D = (Obj?.['foo'])['bar'];
type E = (T & S)?.['bar'];
type F = (T | S)?.['bar'];
type G = (?T)?.['bar'];
type H = (typeof x)?.['bar'];
type I = (string => void)?.['bar'];
=====================================output=====================================
type A = Obj?.["foo"];
type B = Obj?.["foo"]["bar"];
type C = Obj["foo"]?.["bar"];
type D = (Obj?.["foo"])["bar"];
type E = (T & S)?.["bar"];
type F = (T | S)?.["bar"];
type G = (?T)?.["bar"];
type H = (typeof x)?.["bar"];
type I = ((string) => void)?.["bar"];
================================================================================
`;
@@ -1,7 +1,9 @@
type A = Obj?.['foo'];

type B = Obj?.['foo']['bar'];

type C = Obj['foo']?.['bar'];

type D = (Obj?.['foo'])['bar'];
type E = (T & S)?.['bar'];
type F = (T | S)?.['bar'];
type G = (?T)?.['bar'];
type H = (typeof x)?.['bar'];
type I = (string => void)?.['bar'];

0 comments on commit 14188ae

Please sign in to comment.