Address parentheses bugs for edge cases with call and new (#6148)

This commit is contained in:
Kevin Gibbons authored and Lucas Duailibe committed 2019-05-24 11:09:17 -03:00
1 parent e7d833966a
commit c03fcfedb1
6 files changed
+48 -12

No files matched your search

+26 -2
View File
@@ -325,7 +325,7 @@ export default (function log() {}).toString();
export default (function log() {} as typeof console.log);
```
### TypeScript: Keep necessary parentheses around non-null assertions. ([#6136] by [@sosukesuzuki], [#6140] by [@thorn0])
### TypeScript: Keep necessary parentheses around non-null assertions. ([#6136] by [@sosukesuzuki], [#6140] by [@thorn0], [#6148] by [@bakkot])
Previously, Prettier removed necessary parentheses around non-null assertions if the result of the assertion expression was called as a constructor.
@@ -338,7 +338,29 @@ const b = new (c()!)();
const b = new c()!();
// Output (Prettier master)
const b = new (c()!)();
const b = new (c())!();
```
### Javascript: Address parentheses bugs for edge cases with call and new. ([#6148] by [@bakkot])
Adding all and only the necessary parentheses when mixing `new` with function calls is tricky. This change fixes two issues where necessary parentheses were omitted and one when redundant parentheses were added.
<!-- prettier-ignore -->
```ts
// Input
new (x()``.y)();
new (x()!.y)();
new e[f().x].y()
// Output (Prettier stable)
new x()``.y();
new x()!.y();
new e[(f()).x].y();
// Output (Prettier master)
new (x())``.y();
new (x())!.y();
new e[f().x].y();
```
[#5979]: https://github.com/prettier/prettier/pull/5979
@@ -357,6 +379,7 @@ const b = new (c()!)();
[#6133]: https://github.com/prettier/prettier/pull/6133
[#6136]: https://github.com/prettier/prettier/pull/6136
[#6140]: https://github.com/prettier/prettier/pull/6140
[#6148]: https://github.com/prettier/prettier/pull/6148
[@belochub]: https://github.com/belochub
[@brainkim]: https://github.com/brainkim
[@duailibe]: https://github.com/duailibe
@@ -366,3 +389,4 @@ const b = new (c()!)();
[@jwbay]: https://github.com/jwbay
[@sosukesuzuki]: https://github.com/sosukesuzuki
[@thorn0]: https://github.com/thorn0
[@bakkot]: https://github.com/bakkot
+8 -8
View File
@@ -216,9 +216,16 @@ function needsParens(path, options) {
case "CallExpression": {
let firstParentNotMemberExpression = parent;
let i = 0;
// tagged templates are basically member expressions from a grammar perspective
// see https://tc39.github.io/ecma262/#prod-MemberExpression
// so are typescript's non-null assertions, though there's no grammar to point to
while (
firstParentNotMemberExpression &&
firstParentNotMemberExpression.type === "MemberExpression"
((firstParentNotMemberExpression.type === "MemberExpression" &&
firstParentNotMemberExpression.object ===
path.getParentNode(i - 1)) ||
firstParentNotMemberExpression.type === "TaggedTemplateExpression" ||
firstParentNotMemberExpression.type === "TSNonNullExpression")
) {
firstParentNotMemberExpression = path.getParentNode(++i);
}
@@ -725,13 +732,6 @@ function needsParens(path, options) {
return false;
}
return true;
case "TSNonNullExpression": {
return (
node.expression.type === "CallExpression" &&
parent.type === "NewExpression"
);
}
}
return false;
@@ -29,11 +29,17 @@ printWidth: 80
new (memoize.Cache || MapCache)
new (typeof this == "function" ? this : Dict())
new (createObj()).prop(a());
new (x()\`\`.y)();
new e[f().x].y();
new e[f()].y();
=====================================output=====================================
new (memoize.Cache || MapCache)();
new (typeof this == "function" ? this : Dict())();
new (createObj()).prop(a());
new (x())\`\`.y();
new e[f().x].y();
new e[f()].y();
================================================================================
`;
+3
View File
@@ -1,3 +1,6 @@
new (memoize.Cache || MapCache)
new (typeof this == "function" ? this : Dict())
new (createObj()).prop(a());
new (x()``.y)();
new e[f().x].y();
new e[f()].y();
@@ -62,6 +62,7 @@ const b = c!();
// parens are necessary if the expression result is called as a constructor
const c = new (d()!)();
const c = new (d()!);
const c = new (d()!.e)();
=====================================output=====================================
(a ? b : c)![tokenKey];
@@ -80,8 +81,9 @@ const a = b()!(); // parens aren't necessary
const b = c!();
// parens are necessary if the expression result is called as a constructor
const c = new (d()!)();
const c = new (d()!)();
const c = new (d())!();
const c = new (d())!();
const c = new (d())!.e();
================================================================================
`;
+1
View File
@@ -16,3 +16,4 @@ const b = c!();
// parens are necessary if the expression result is called as a constructor
const c = new (d()!)();
const c = new (d()!);
const c = new (d()!.e)();