Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing parentheses to let #14000

Merged
merged 19 commits into from Dec 22, 2022
19 changes: 19 additions & 0 deletions changelog_unreleased/javascript/14000.md
@@ -0,0 +1,19 @@
#### Fix missing parentheses when assigning to property of variable named `let` (#14000 by @fisker)

<!-- prettier-ignore -->
```jsx
// Input
(let[0] = 2);

// Prettier stable
let[0] = 2;

// Prettier stable (second format)
SyntaxError: Unexpected token (1:5)
> 1 | let[0] = 2;
| ^
2 |

// Prettier main
(let)[0] = 2;
```
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -28,7 +28,7 @@
"@glimmer/syntax": "0.84.2",
"@iarna/toml": "2.2.5",
"@typescript-eslint/typescript-estree": "5.45.0",
"acorn": "8.8.0",
"acorn": "8.8.1",
"acorn-jsx": "5.3.2",
"angular-estree-parser": "2.5.1",
"angular-html-parser": "1.8.0",
Expand All @@ -44,7 +44,7 @@
"editorconfig": "0.15.3",
"editorconfig-to-prettier": "0.2.0",
"escape-string-regexp": "5.0.0",
"espree": "9.4.0",
"espree": "9.4.1",
"esutils": "2.0.3",
"fast-glob": "3.2.11",
"fast-json-stable-stringify": "2.1.0",
Expand Down
23 changes: 23 additions & 0 deletions src/language-js/needs-parens.js
Expand Up @@ -77,6 +77,17 @@ function needsParens(path, options) {
return true;
}

// `(let)[a] = 1`
if (
name === "object" &&
node.name === "let" &&
parent.type === "MemberExpression" &&
parent.computed &&
!parent.optional
) {
return path.callParent(isAssignmentExpressionLeft);
Copy link

@Josh-Cena Josh-Cena Dec 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you should detect assignment expressions. The syntax is

ExpressionStatement :
  [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }] Expression ;

So you should be looking at any expression statement that starts with let [, which I hope the if condition above sufficiently covers. Some more test cases:

playground

(let)[2];
a[1] + (let[2] = 2);

IMO, both should have no change, but at least the first one needs fix.

}

return false;
}

Expand Down Expand Up @@ -963,4 +974,16 @@ function shouldWrapFunctionForExportDefault(path, options) {
);
}

function isAssignmentExpressionLeft(path) {
const name = path.getName();
const parent = path.getParentNode();

// "OptionalMemberExpression" can't be here
if (name === "object" && parent.type === "MemberExpression") {
return path.callParent(isAssignmentExpressionLeft);
}

return name === "left" && parent.type === "AssignmentExpression";
}

module.exports = needsParens;
4 changes: 4 additions & 0 deletions tests/config/format-test.js
Expand Up @@ -41,6 +41,10 @@ const unstableTests = new Map(
"js/comments/html-like/comment.js",
"js/for/continue-and-break-comment-without-blocks.js",
"typescript/satisfies-operators/comments-unstable.ts",
[
"js/identifier/parentheses/let-in-assignment.js",
(options) => options.semi === false,
],
].map((fixture) => {
const [file, isUnstable = () => true] = Array.isArray(fixture)
? fixture
Expand Down