From 57a109af0ab82a1b188a70f6ae19f8af11799b21 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Fri, 23 Dec 2022 14:49:01 +0800 Subject: [PATCH] Add missing parentheses to `let` in `for..of` loop (#14044) Co-authored-by: Georgii Dolzhykov --- changelog_unreleased/javascript/14000.md | 2 +- src/language-js/needs-parens.js | 23 ++++++-- .../for-of/__snapshots__/jsfmt.spec.js.snap | 57 +++++++++++++++++++ tests/format/js/identifier/for-of/await.js | 5 ++ .../format/js/identifier/for-of/jsfmt.spec.js | 5 ++ tests/format/js/identifier/for-of/let.js | 11 ++++ 6 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 tests/format/js/identifier/for-of/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/format/js/identifier/for-of/await.js create mode 100644 tests/format/js/identifier/for-of/jsfmt.spec.js create mode 100644 tests/format/js/identifier/for-of/let.js diff --git a/changelog_unreleased/javascript/14000.md b/changelog_unreleased/javascript/14000.md index a8388fda0f1a..914800969a96 100644 --- a/changelog_unreleased/javascript/14000.md +++ b/changelog_unreleased/javascript/14000.md @@ -1,4 +1,4 @@ -#### Fix missing parentheses when an expression statement starts with `let[` (#14000 by @fisker, @thorn0) +#### Fix missing parentheses when an expression statement starts with `let[` (#14000, #14044 by @fisker, @thorn0) ```jsx diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index 7a31778038dc..02b8bf7ac1a6 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -67,16 +67,32 @@ function needsParens(path, options) { return true; } - // `for (async of []);` is invalid + // `for ((async) of []);` and `for ((let) of []);` if ( name === "left" && - node.name === "async" && + (node.name === "async" || node.name === "let") && parent.type === "ForOfStatement" && !parent.await ) { return true; } + // `for ((let.a) of []);` + if (node.name === "let") { + const expression = path.findAncestor( + (node) => node.type === "ForOfStatement" + )?.left; + if ( + expression && + startsWithNoLookaheadToken( + expression, + (leftmostNode) => leftmostNode === node + ) + ) { + return true; + } + } + // `(let)[a] = 1` if ( name === "object" && @@ -89,8 +105,7 @@ function needsParens(path, options) { (node) => node.type === "ExpressionStatement" || node.type === "ForStatement" || - node.type === "ForInStatement" || - node.type === "ForOfStatement" + node.type === "ForInStatement" ); const expression = !statement ? undefined diff --git a/tests/format/js/identifier/for-of/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/identifier/for-of/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1ccc4806b684 --- /dev/null +++ b/tests/format/js/identifier/for-of/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,57 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`await.js format 1`] = ` +====================================options===================================== +parsers: ["babel", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +async function a() { + for await((let).a of foo); + for await((let)[a] of foo); + for await((let)()[a] of foo); +} + +=====================================output===================================== +async function a() { + for await ((let).a of foo); + for await ((let)[a] of foo); + for await ((let)()[a] of foo); +} + +================================================================================ +`; + +exports[`let.js format 1`] = ` +====================================options===================================== +parsers: ["babel", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +for ((let) of foo); +for (foo of let); +for (foo of let.a); +for (foo of let[a]); +for ((let.a) of foo); +for ((let[a]) of foo); +for ((let)().a of foo); +for (letFoo of foo); + +for ((let.a) in foo); +for ((let[a]) in foo); + +=====================================output===================================== +for ((let) of foo); +for (foo of let); +for (foo of let.a); +for (foo of let[a]); +for ((let).a of foo); +for ((let)[a] of foo); +for ((let)().a of foo); +for (letFoo of foo); + +for (let.a in foo); +for ((let)[a] in foo); + +================================================================================ +`; diff --git a/tests/format/js/identifier/for-of/await.js b/tests/format/js/identifier/for-of/await.js new file mode 100644 index 000000000000..0fa9d0a508f1 --- /dev/null +++ b/tests/format/js/identifier/for-of/await.js @@ -0,0 +1,5 @@ +async function a() { + for await((let).a of foo); + for await((let)[a] of foo); + for await((let)()[a] of foo); +} diff --git a/tests/format/js/identifier/for-of/jsfmt.spec.js b/tests/format/js/identifier/for-of/jsfmt.spec.js new file mode 100644 index 000000000000..0e59aa341125 --- /dev/null +++ b/tests/format/js/identifier/for-of/jsfmt.spec.js @@ -0,0 +1,5 @@ +run_spec(__dirname, [ + "babel", + // "flow", + "typescript", +]); diff --git a/tests/format/js/identifier/for-of/let.js b/tests/format/js/identifier/for-of/let.js new file mode 100644 index 000000000000..5c2398ee26e0 --- /dev/null +++ b/tests/format/js/identifier/for-of/let.js @@ -0,0 +1,11 @@ +for ((let) of foo); +for (foo of let); +for (foo of let.a); +for (foo of let[a]); +for ((let.a) of foo); +for ((let[a]) of foo); +for ((let)().a of foo); +for (letFoo of foo); + +for ((let.a) in foo); +for ((let[a]) in foo);