Handle exception in needs parens with optional chaining (#16500)

Co-authored-by: fisker Cheung <lionkay@gmail.com>
This commit is contained in:
Sung Ye Inandfisker Cheung authored and GitHub committed 2024-07-27 15:11:27 +08:00
1 parent 3548153a4b
commit 4a39c117d1
7 files changed
+376 -15

No files matched your search

+16
View File
@@ -0,0 +1,16 @@
#### Add missing parentheses in tagged template literals (#16500 by @syi0808)
<!-- prettier-ignore -->
```jsx
// Input
(String?.raw)``;
(getTag?.())``;
// Prettier stable
String?.raw``;
getTag?.()``;
// Prettier main
(String?.raw)``;
(getTag?.())``;
```
@@ -0,0 +1,16 @@
#### Add missing parentheses in tagged template literals (#16500 by @syi0808)
<!-- prettier-ignore -->
```jsx
// Input
(String?.raw!)``;
(String?.raw)!``;
// Prettier stable
String?.raw!``;
String?.raw!``;
// Prettier main
(String?.raw)!``;
(String?.raw)!``;
```
+83 -15
View File
@@ -945,6 +945,7 @@ function needsParens(path, options) {
}
}
}
return false;
case "BindExpression":
@@ -1177,6 +1178,9 @@ Matches following cases:
new (a?.b)();
new (a?.())();
(a?.b)``;
(a?.())``;
```
*/
/**
@@ -1184,18 +1188,76 @@ new (a?.())();
* @returns {boolean}
*/
function shouldAddParenthesesToChainElement(path) {
// Babel, this was implemented before #13735, can use `path.match` as estree does
const { node, parent, grandparent, key } = path;
if (
(node.type === "OptionalMemberExpression" ||
node.type === "OptionalCallExpression") &&
((key === "object" && parent.type === "MemberExpression") ||
(key === "callee" &&
(parent.type === "CallExpression" ||
parent.type === "NewExpression")) ||
(parent.type === "TSNonNullExpression" &&
grandparent.type === "MemberExpression" &&
grandparent.object === parent))
// ESTree
path.match(
undefined,
(node, name) => name === "expression" && node.type === "ChainExpression",
(node, name) =>
name === "tag" && node.type === "TaggedTemplateExpression",
) ||
// Babel
path.match(
(node) =>
node.type === "OptionalCallExpression" ||
node.type === "OptionalMemberExpression",
(node, name) =>
name === "tag" && node.type === "TaggedTemplateExpression",
) ||
// Babel-ts
// (a?.b)!``;
// (a?.b!)``;
path.match(
(node) =>
node.type === "OptionalCallExpression" ||
node.type === "OptionalMemberExpression",
(node, name) =>
name === "expression" && node.type === "TSNonNullExpression",
(node, name) =>
name === "tag" && node.type === "TaggedTemplateExpression",
) ||
// case (a?.b)!``; in Typescript
path.match(
undefined,
(node, name) => name === "expression" && node.type === "ChainExpression",
(node, name) =>
name === "expression" && node.type === "TSNonNullExpression",
(node, name) =>
name === "tag" && node.type === "TaggedTemplateExpression",
) ||
// case (a?.b!)``; in Typescript
path.match(
undefined,
(node, name) =>
name === "expression" && node.type === "TSNonNullExpression",
(node, name) => name === "expression" && node.type === "ChainExpression",
(node, name) =>
name === "tag" && node.type === "TaggedTemplateExpression",
)
) {
return true;
}
if (
path.match(
(node) =>
node.type === "OptionalMemberExpression" ||
node.type === "OptionalCallExpression",
(node, name) =>
(name === "object" && node.type === "MemberExpression") ||
(name === "callee" &&
(node.type === "CallExpression" || node.type === "NewExpression")),
) ||
path.match(
(node) =>
node.type === "OptionalMemberExpression" ||
node.type === "OptionalCallExpression",
(node, name) =>
name === "expression" && node.type === "TSNonNullExpression",
(node, name) =>
(name === "object" && node.type === "MemberExpression") ||
(name === "callee" && node.type === "CallExpression"),
)
) {
return true;
}
@@ -1203,7 +1265,8 @@ function shouldAddParenthesesToChainElement(path) {
// ESTree, same logic as babel
if (
path.match(
() => node.type === "CallExpression" || node.type === "MemberExpression",
(node) =>
node.type === "CallExpression" || node.type === "MemberExpression",
(node, name) => name === "expression" && node.type === "ChainExpression",
) &&
(path.match(
@@ -1222,7 +1285,9 @@ function shouldAddParenthesesToChainElement(path) {
undefined,
(node, name) =>
name === "expression" && node.type === "TSNonNullExpression",
(node, name) => name === "object" && node.type === "MemberExpression",
(node, name) =>
(name === "object" && node.type === "MemberExpression") ||
(name === "callee" && node.type === "CallExpression"),
))
) {
return true;
@@ -1232,11 +1297,14 @@ function shouldAddParenthesesToChainElement(path) {
// Use this to align with babel
if (
path.match(
() => node.type === "CallExpression" || node.type === "MemberExpression",
(node) =>
node.type === "CallExpression" || node.type === "MemberExpression",
(node, name) =>
name === "expression" && node.type === "TSNonNullExpression",
(node, name) => name === "expression" && node.type === "ChainExpression",
(node, name) => name === "object" && node.type === "MemberExpression",
(node, name) =>
(name === "object" && node.type === "MemberExpression") ||
(name === "callee" && node.type === "CallExpression"),
)
) {
return true;
@@ -126,6 +126,54 @@ const randomFuncion = (value) => {
================================================================================
`;
exports[`tagged-template-literals.js format 1`] = `
====================================options=====================================
parsers: ["babel", "typescript", "flow"]
printWidth: 80
| printWidth
=====================================input======================================
// Member expressions
(a?.b) \`\`;
(a.b?.c) \`\`;
(a?.b.c) \`\`;
(a[b?.c]) \`\`;
((a?.b).c) \`\`;
(a[b?.()]) \`\`;
((a?.b).c) \`\`;
((a?.()).b) \`\`;
// Call expressions
(a?.()) \`\`;
(a.b.c?.()) \`\`;
(a.b?.c()) \`\`;
(a?.b.c()) \`\`;
(a(b?.c)) \`\`;
((a?.b)()) \`\`;
((a?.())()) \`\`;
=====================================output=====================================
// Member expressions
(a?.b)\`\`;
(a.b?.c)\`\`;
(a?.b.c)\`\`;
a[b?.c]\`\`;
(a?.b).c\`\`;
a[b?.()]\`\`;
(a?.b).c\`\`;
(a?.()).b\`\`;
// Call expressions
(a?.())\`\`;
(a.b.c?.())\`\`;
(a.b?.c())\`\`;
(a?.b.c())\`\`;
a(b?.c)\`\`;
(a?.b)()\`\`;
(a?.())()\`\`;
================================================================================
`;
exports[`test.js format 1`] = `
====================================options=====================================
parsers: ["babel", "typescript", "flow"]
@@ -0,0 +1,18 @@
// Member expressions
(a?.b) ``;
(a.b?.c) ``;
(a?.b.c) ``;
(a[b?.c]) ``;
((a?.b).c) ``;
(a[b?.()]) ``;
((a?.b).c) ``;
((a?.()).b) ``;
// Call expressions
(a?.()) ``;
(a.b.c?.()) ``;
(a.b?.c()) ``;
(a?.b.c()) ``;
(a(b?.c)) ``;
((a?.b)()) ``;
((a?.())()) ``;
@@ -1,5 +1,139 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`non-null-tagged-template-literals.ts format 1`] = `
====================================options=====================================
parsers: ["typescript"]
printWidth: 80
| printWidth
=====================================input======================================
// Member expressions
(a?.b)! \`\`;
(a?.b!) \`\`;
(a!?.b) \`\`;
(a.b?.c)! \`\`;
(a.b?.c!) \`\`;
(a.b!?.c) \`\`;
(a!.b?.c) \`\`;
(a?.b.c)! \`\`;
(a?.b.c!) \`\`;
(a?.b!.c) \`\`;
(a!?.b.c) \`\`;
(a[b?.c])! \`\`;
(a[b?.c]!) \`\`;
(a[b?.c!]) \`\`;
(a[b!?.c]) \`\`;
((a?.b).c)! \`\`;
((a?.b).c!) \`\`;
((a?.b!).c) \`\`;
((a!?.b).c) \`\`;
(a[b?.()])! \`\`;
(a[b?.()]!) \`\`;
(a[b?.()!]) \`\`;
(a[b!?.()]) \`\`;
(a![b?.()]) \`\`;
((a?.b).c)! \`\`;
((a?.b).c!) \`\`;
((a?.b)!.c) \`\`;
((a?.b!).c) \`\`;
((a!?.b).c) \`\`;
((a?.()).b)! \`\`;
((a?.()).b!) \`\`;
((a?.())!.b) \`\`;
((a?.()!).b) \`\`;
((a!?.()).b) \`\`;
// Call expressions
(a?.())! \`\`;
(a?.()!) \`\`;
(a!?.()) \`\`;
(a.b.c?.())! \`\`;
(a.b.c?.()!) \`\`;
(a.b.c!?.()) \`\`;
(a.b?.c())! \`\`;
(a.b?.c()!) \`\`;
(a.b!?.c()) \`\`;
(a?.b.c())! \`\`;
(a?.b.c()!) \`\`;
(a?.b!.c()) \`\`;
(a(b?.c))! \`\`;
(a(b?.c)!) \`\`;
(a(b?.c!)) \`\`;
((a?.b)())! \`\`;
((a?.b)()!) \`\`;
((a?.b)!()) \`\`;
((a?.b!)()) \`\`;
((a?.())())! \`\`;
((a?.())()!) \`\`;
((a?.())!()) \`\`;
((a?.()!)()) \`\`;
((a!?.())()) \`\`;
=====================================output=====================================
// Member expressions
(a?.b)!\`\`;
(a?.b)!\`\`;
(a!?.b)\`\`;
(a.b?.c)!\`\`;
(a.b?.c)!\`\`;
(a.b!?.c)\`\`;
(a!.b?.c)\`\`;
(a?.b.c)!\`\`;
(a?.b.c)!\`\`;
(a?.b!.c)\`\`;
(a!?.b.c)\`\`;
a[b?.c]!\`\`;
a[b?.c]!\`\`;
a[b?.c!]\`\`;
a[b!?.c]\`\`;
(a?.b).c!\`\`;
(a?.b).c!\`\`;
(a?.b)!.c\`\`;
(a!?.b).c\`\`;
a[b?.()]!\`\`;
a[b?.()]!\`\`;
a[b?.()!]\`\`;
a[b!?.()]\`\`;
a![b?.()]\`\`;
(a?.b).c!\`\`;
(a?.b).c!\`\`;
(a?.b)!.c\`\`;
(a?.b)!.c\`\`;
(a!?.b).c\`\`;
(a?.()).b!\`\`;
(a?.()).b!\`\`;
(a?.())!.b\`\`;
(a?.())!.b\`\`;
(a!?.()).b\`\`;
// Call expressions
(a?.())!\`\`;
(a?.())!\`\`;
(a!?.())\`\`;
(a.b.c?.())!\`\`;
(a.b.c?.())!\`\`;
(a.b.c!?.())\`\`;
(a.b?.c())!\`\`;
(a.b?.c())!\`\`;
(a.b!?.c())\`\`;
(a?.b.c())!\`\`;
(a?.b.c())!\`\`;
(a?.b!.c())\`\`;
a(b?.c)!\`\`;
a(b?.c)!\`\`;
a(b?.c!)\`\`;
(a?.b)()!\`\`;
(a?.b)()!\`\`;
(a?.b)!()\`\`;
(a?.b)!()\`\`;
(a?.())()!\`\`;
(a?.())()!\`\`;
(a?.())!()\`\`;
(a?.())!()\`\`;
(a!?.())()\`\`;
================================================================================
`;
exports[`test.ts format 1`] = `
====================================options=====================================
parsers: ["typescript"]
@@ -0,0 +1,61 @@
// Member expressions
(a?.b)! ``;
(a?.b!) ``;
(a!?.b) ``;
(a.b?.c)! ``;
(a.b?.c!) ``;
(a.b!?.c) ``;
(a!.b?.c) ``;
(a?.b.c)! ``;
(a?.b.c!) ``;
(a?.b!.c) ``;
(a!?.b.c) ``;
(a[b?.c])! ``;
(a[b?.c]!) ``;
(a[b?.c!]) ``;
(a[b!?.c]) ``;
((a?.b).c)! ``;
((a?.b).c!) ``;
((a?.b!).c) ``;
((a!?.b).c) ``;
(a[b?.()])! ``;
(a[b?.()]!) ``;
(a[b?.()!]) ``;
(a[b!?.()]) ``;
(a![b?.()]) ``;
((a?.b).c)! ``;
((a?.b).c!) ``;
((a?.b)!.c) ``;
((a?.b!).c) ``;
((a!?.b).c) ``;
((a?.()).b)! ``;
((a?.()).b!) ``;
((a?.())!.b) ``;
((a?.()!).b) ``;
((a!?.()).b) ``;
// Call expressions
(a?.())! ``;
(a?.()!) ``;
(a!?.()) ``;
(a.b.c?.())! ``;
(a.b.c?.()!) ``;
(a.b.c!?.()) ``;
(a.b?.c())! ``;
(a.b?.c()!) ``;
(a.b!?.c()) ``;
(a?.b.c())! ``;
(a?.b.c()!) ``;
(a?.b!.c()) ``;
(a(b?.c))! ``;
(a(b?.c)!) ``;
(a(b?.c!)) ``;
((a?.b)())! ``;
((a?.b)()!) ``;
((a?.b)!()) ``;
((a?.b!)()) ``;
((a?.())())! ``;
((a?.())()!) ``;
((a?.())!()) ``;
((a?.()!)()) ``;
((a!?.())()) ``;