Address parentheses bugs for edge cases with call and new (#6148)
This commit is contained in:
1 parent
e7d833966a
commit
c03fcfedb1
6 files changed
+48
-12
No files matched your search
+26
-2
@@ -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
|
||||
@@ -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();
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
@@ -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();
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
@@ -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)();
|
||||
Reference in new issue
Block a user