Skip to content

Commit

Permalink
Add parens to head of ExpressionStatement instead of whole statement
Browse files Browse the repository at this point in the history
  • Loading branch information
fisker committed Dec 29, 2022
1 parent 201e02e commit 14c6671
Show file tree
Hide file tree
Showing 17 changed files with 89 additions and 65 deletions.
19 changes: 19 additions & 0 deletions changelog_unreleased/javascript/14077.md
@@ -0,0 +1,19 @@
#### Add parentheses to head of `ExpressionStatement` instead of the whole statement (#14077 by @fisker)

<!-- prettier-ignore -->
```jsx
// Input
({}).toString.call(foo) === "[object Array]"
? foo.forEach(iterateArray)
: iterateObject(foo);

// Prettier stable
({}.toString.call(foo) === "[object Array]"
? foo.forEach(iterateArray)
: iterateObject(foo));

// Prettier main
({}).toString.call(foo.forEach) === "[object Array]"
? foo.forEach(iterateArray)
: iterateObject(foo);
```
35 changes: 20 additions & 15 deletions src/language-js/needs-parens.js
Expand Up @@ -128,6 +128,26 @@ function needsParens(path, options) {
return false;
}

if (
node.type === "ObjectExpression" ||
node.type === "FunctionExpression" ||
node.type === "ClassExpression" ||
node.type === "DoExpression"
) {
const expression = path.findAncestor(
(node) => node.type === "ExpressionStatement"
)?.expression;
if (
expression &&
startsWithNoLookaheadToken(
expression,
(leftmostNode) => leftmostNode === node
)
) {
return true;
}
}

switch (parent.type) {
case "ParenthesizedExpression":
return false;
Expand Down Expand Up @@ -201,21 +221,6 @@ function needsParens(path, options) {
}
break;
}
case "ExpressionStatement": {
if (
startsWithNoLookaheadToken(
node,
(node) =>
node.type === "ObjectExpression" ||
node.type === "FunctionExpression" ||
node.type === "ClassExpression" ||
node.type === "DoExpression"
)
) {
return true;
}
break;
}
case "ArrowFunctionExpression": {
if (
name === "body" &&
Expand Down
8 changes: 4 additions & 4 deletions tests/format/flow-repo/arith/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -168,7 +168,7 @@ let tests = [
x + ""; // error
"" + x; // error
x + {}; // error
({} + x); // error
({}) + x; // error
},
// when one side is a string or number and the other is invalid, we
Expand Down Expand Up @@ -344,10 +344,10 @@ let tests = [
"foo" < 1; // error
"foo" < "bar";
1 < { foo: 1 }; // error
({ foo: 1 } < 1); // error
({ foo: 1 } < { foo: 1 }); // error
({ foo: 1 }) < 1; // error
({ foo: 1 }) < { foo: 1 }; // error
"foo" < { foo: 1 }; // error
({ foo: 1 } < "foo"); // error
({ foo: 1 }) < "foo"; // error
var x = (null: ?number);
1 < x; // 2 errors: null !~> number; undefined !~> number
Expand Down
Expand Up @@ -98,7 +98,7 @@ let tests = [
function () {
null in {}; // error
void 0 in {}; // error
({} in {}); // error
({}) in {}; // error
[] in {}; // error
false in []; // error
},
Expand Down
Expand Up @@ -160,7 +160,7 @@ function foo() {
function bar(f: () => void) {
f(); // passing global object as \`this\`
({ f }.f()); // passing container object as \`this\`
({ f }).f(); // passing container object as \`this\`
}
bar(foo); // error, since \`this\` is used non-trivially in \`foo\`
Expand Down
16 changes: 8 additions & 8 deletions tests/format/js/classes/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -111,10 +111,10 @@ printWidth: 80
(class a extends b {}) + 1;
=====================================output=====================================
(class {} + 1);
(class a {} + 1);
(class extends b {} + 1);
(class a extends b {} + 1);
(class {}) + 1;
(class a {}) + 1;
(class extends b {}) + 1;
(class a extends b {}) + 1;
================================================================================
`;
Expand All @@ -128,7 +128,7 @@ printWidth: 80
(class {})(class {});
=====================================output=====================================
(class {}(class {}));
(class {})(class {});
================================================================================
`;
Expand Down Expand Up @@ -225,8 +225,8 @@ printWidth: 80
(class {}).a;
=====================================output=====================================
(class {}[1]);
(class {}.a);
(class {})[1];
(class {}).a;
================================================================================
`;
Expand Down Expand Up @@ -356,7 +356,7 @@ printWidth: 80
if (1) (class {}) ? 1 : 2;
=====================================output=====================================
if (1) (class {} ? 1 : 2);
if (1) (class {}) ? 1 : 2;
================================================================================
`;
Expand Up @@ -387,14 +387,14 @@ semi: false
(@deco class {}).name;
=====================================output=====================================
;((
;(
@deco
class Foo {}
).name)
;((
).name
;(
@deco
class {}
).name)
).name
================================================================================
`;
Expand All @@ -409,14 +409,14 @@ printWidth: 80
(@deco class {}).name;
=====================================output=====================================
((
(
@deco
class Foo {}
).name);
((
).name;
(
@deco
class {}
).name);
).name;
================================================================================
`;
Expand Down
2 changes: 1 addition & 1 deletion tests/format/js/do/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -252,7 +252,7 @@ function foo() {
}
(do {});
(do {} + 1);
(do {}) + 1;
1 + do {};
() => do {};
Expand Down
4 changes: 2 additions & 2 deletions tests/format/js/function/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -19,15 +19,15 @@ a + function() {};
new function() {};
=====================================output=====================================
(function () {}.length);
(function () {}).length;
typeof function () {};
export default (function () {})();
(function () {})()\`\`;
(function () {})\`\`;
new (function () {})();
(function () {});
a = function f() {} || b;
(function () {} && a);
(function () {}) && a;
a + function () {};
new (function () {})();
Expand Down
4 changes: 2 additions & 2 deletions tests/format/js/method-chain/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -1522,8 +1522,8 @@ method()
["abc"]((x) => x)
[abc]((x) => x);
({}.a().b());
({}.a().b());
({}).a().b();
({}).a().b();
================================================================================
`;
Expand Down
8 changes: 4 additions & 4 deletions tests/format/js/no-semi/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -727,9 +727,9 @@ x
x
;(() => {})()
x
;({ a: 1 }.entries())
;({ a: 1 }).entries()
x
;({ a: 1 }.entries())
;({ a: 1 }).entries()
x
;<Hello />
x
Expand Down Expand Up @@ -910,9 +910,9 @@ x;
x;
(() => {})();
x;
({ a: 1 }.entries());
({ a: 1 }).entries();
x;
({ a: 1 }.entries());
({ a: 1 }).entries();
x;
<Hello />;
x;
Expand Down
10 changes: 5 additions & 5 deletions tests/format/js/objects/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -129,12 +129,12 @@ const a3 = {
=====================================output=====================================
() => ({}\`\`);
({}\`\`);
({})\`\`;
a = () => ({}.x);
({} && a, b);
({}::b, 0);
({}::b()\`\`[""].c++ && 0 ? 0 : 0, 0);
({}(), 0);
({}) && a, b;
({})::b, 0;
({})::b()\`\`[""].c++ && 0 ? 0 : 0, 0;
({})(), 0;
({} = 0);
({} = 0), 1;
Expand Down
Expand Up @@ -172,8 +172,8 @@ a = () => ({}?.b() && a);
(x) => ({}?.().b);
(x) => ({}?.b());
(x) => ({}?.b.b);
({}?.a().b());
({ a: 1 }?.entries());
({})?.a().b();
({ a: 1 })?.entries();
new (foo?.bar)();
new (foo?.bar())();
Expand Down
4 changes: 2 additions & 2 deletions tests/format/js/template/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -391,7 +391,7 @@ async function f() {
b()\`\`;
// "ClassExpression"
(class {}\`\`);
(class {})\`\`;
// "ConditionalExpression"
(b ? c : d)\`\`;
Expand All @@ -409,7 +409,7 @@ b.c\`\`;
new B()\`\`;
// "ObjectExpression"
({}\`\`);
({})\`\`;
// "SequenceExpression"
(b, c)\`\`;
Expand Down
4 changes: 2 additions & 2 deletions tests/format/typescript/as/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -81,14 +81,14 @@ export default class Column<T> extends (RcTable.Column as React.ComponentClass<
>) {}
export const MobxTypedForm = class extends (Form as { new (): any }) {};
export abstract class MobxTypedForm1 extends (Form as { new (): any }) {}
({} as {});
({}) as {};
function* g() {
const test = (yield "foo") as number;
}
async function g1() {
const test = (await "foo") as number;
}
({} as X);
({}) as X;
() => ({} as X);
const state = JSON.stringify({
next: window.location.href,
Expand Down
Expand Up @@ -35,9 +35,9 @@ const f = ((a) => {
log(a);
})!;
if (a) ({ a, ...b }.a()!.c());
if (a) ({ a, ...b }).a()!.c();
(function () {}!());
(function () {})!();
class a extends ({}!) {}
Expand Down
Expand Up @@ -282,7 +282,7 @@ let obj: { f(s: string): void } & Record<string, unknown> = {
g(s) {},
} satisfies { g(s: string): void } & Record<string, unknown>
;({ f(x) {} } satisfies { f(s: string): void })
;({ f(x) {} }) satisfies { f(s: string): void }
const car = {
start() {},
Expand Down Expand Up @@ -354,7 +354,7 @@ let obj: { f(s: string): void } & Record<string, unknown> = {
g(s) {},
} satisfies { g(s: string): void } & Record<string, unknown>;
({ f(x) {} } satisfies { f(s: string): void });
({ f(x) {} }) satisfies { f(s: string): void };
const car = {
start() {},
Expand Down Expand Up @@ -742,8 +742,8 @@ foo satisfies unknown as Bar;
foo as unknown satisfies Bar;
=====================================output=====================================
;({} satisfies {})
;({} satisfies X)
;({}) satisfies {}
;({}) satisfies X
;() => ({} satisfies X)
this.isTabActionBar((e.target || e.srcElement) satisfies HTMLElement)
Expand Down Expand Up @@ -798,8 +798,8 @@ foo satisfies unknown as Bar;
foo as unknown satisfies Bar;
=====================================output=====================================
({} satisfies {});
({} satisfies X);
({}) satisfies {};
({}) satisfies X;
() => ({} satisfies X);
this.isTabActionBar((e.target || e.srcElement) satisfies HTMLElement);
Expand Down

0 comments on commit 14c6671

Please sign in to comment.