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 parens to head of ExpressionStatement instead of whole statement #14077

Merged
merged 1 commit into from Jan 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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"
Comment on lines +132 to +135
Copy link
Member

Choose a reason for hiding this comment

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

RecordExpression should be included?

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

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

No, #{}.toString() is valid.

) {
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