Skip to content

Commit 8188876

Browse files
jridgewellthorn0
authored andcommitted
Fix nullish coalescing parenthesis with mixed logical operators (prettier#6863)
* Fix nullish coalescing with mixed logical operators parenthesis Mixing nullish coalescing (`??`) with the other logical operators (`&&` and `||`) requires parenthesis to disambiguate the inteded short circuiting. Without it, it's a `SyntaxError`. Earlier drafts of the spec allowed mixing, but it was disallowed when we reached Stage 3. See https://v8.dev/features/nullish-coalescing#mixing-and-matching-operators * Update changelog * Fixes and cleanup * Update changelog
1 parent d4a7a47 commit 8188876

4 files changed

Lines changed: 48 additions & 6 deletions

File tree

CHANGELOG.unreleased.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -483,20 +483,23 @@ Previously, Prettier would sometimes ignore whitespace when formatting comments.
483483
</div>
484484
```
485485
486-
#### JavaScript: Update `??` precedence to match stage 3 proposal ([#6404] by [@vjeux])
486+
#### JavaScript: Update `??` precedence to match stage 3 proposal ([#6404] by [@vjeux], [#6863] by [@jridgewell])
487487
488-
We've updated Prettier's support for the nullish coalescing operator to match a spec update that no longer allows it to immediately contain, or be contained within an `&&` or `||` operation.
488+
We've updated Prettier's support for the nullish coalescing operator to match a spec update that no longer allows it to immediately contain, or be contained within, an `&&` or `||` operation.
489489
490490
<!-- prettier-ignore -->
491491
```js
492492
// Input
493-
(foo ?? baz) || baz;
493+
(foo ?? bar) || baz;
494+
(foo || bar) ?? baz;
494495

495496
// Output (Prettier stable)
496-
foo ?? baz || baz;
497+
foo ?? bar || baz;
498+
foo || bar ?? baz;
497499

498500
// Output (Prettier master)
499-
(foo ?? baz) || baz;
501+
(foo ?? bar) || baz;
502+
(foo || bar) ?? baz;
500503
```
501504
502505
Please note, as we update our parsers with versions that support this spec update, code without the parenthesis will throw a parse error.
@@ -1453,6 +1456,7 @@ async function f() {
14531456
[#6796]: https://github.com/prettier/prettier/pull/6796
14541457
[#6848]: https://github.com/prettier/prettier/pull/6848
14551458
[#6856]: https://github.com/prettier/prettier/pull/6856
1459+
[#6863]: https://github.com/prettier/prettier/pull/6863
14561460
[@brainkim]: https://github.com/brainkim
14571461
[@duailibe]: https://github.com/duailibe
14581462
[@gavinjoyce]: https://github.com/gavinjoyce
@@ -1474,3 +1478,4 @@ async function f() {
14741478
[@andersk]: https://github.com/andersk
14751479
[@lydell]: https://github.com/lydell
14761480
[@aymericbouzy]: https://github.com/aymericbouzy
1481+
[@jridgewell]: https://github.com/jridgewell

src/language-js/needs-parens.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,14 @@ function needsParens(path, options) {
354354
return true;
355355
}
356356

357-
if ((po === "||" || po === "??") && no === "&&") {
357+
if (
358+
(po === "??" && (no === "||" || no === "&&")) ||
359+
(no === "??" && (po === "||" || po === "&&"))
360+
) {
361+
return true;
362+
}
363+
364+
if (po === "||" && no === "&&") {
358365
return true;
359366
}
360367

tests/nullish_coalescing/__snapshots__/jsfmt.spec.js.snap

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,18 @@ const x = (foo, bar = foo ?? bar) => {};
1313
foo ? bar ?? foo : baz;
1414
1515
foo ?? (bar ?? baz);
16+
(foo ?? bar) ?? baz;
1617
18+
// Mixing ?? and (&& or ||) requires parens
19+
// It's a syntax error without it.
1720
(foo ?? baz) || baz;
21+
foo ?? (baz || baz);
22+
23+
(foo ?? baz) && baz;
24+
foo ?? (baz && baz);
25+
26+
(foo || baz) ?? baz;
27+
foo || (baz ?? baz);
1828
1929
(foo && baz) ?? baz;
2030
foo && (baz ?? baz);
@@ -27,8 +37,18 @@ const x = (foo, bar = foo ?? bar) => {};
2737
foo ? bar ?? foo : baz;
2838
2939
foo ?? (bar ?? baz);
40+
foo ?? bar ?? baz;
3041
42+
// Mixing ?? and (&& or ||) requires parens
43+
// It's a syntax error without it.
3144
(foo ?? baz) || baz;
45+
foo ?? (baz || baz);
46+
47+
(foo ?? baz) && baz;
48+
foo ?? (baz && baz);
49+
50+
(foo || baz) ?? baz;
51+
foo || (baz ?? baz);
3252
3353
(foo && baz) ?? baz;
3454
foo && (baz ?? baz);

tests/nullish_coalescing/nullish_coalesing_operator.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,18 @@ const x = (foo, bar = foo ?? bar) => {};
55
foo ? bar ?? foo : baz;
66

77
foo ?? (bar ?? baz);
8+
(foo ?? bar) ?? baz;
89

10+
// Mixing ?? and (&& or ||) requires parens
11+
// It's a syntax error without it.
912
(foo ?? baz) || baz;
13+
foo ?? (baz || baz);
14+
15+
(foo ?? baz) && baz;
16+
foo ?? (baz && baz);
17+
18+
(foo || baz) ?? baz;
19+
foo || (baz ?? baz);
1020

1121
(foo && baz) ?? baz;
1222
foo && (baz ?? baz);

0 commit comments

Comments
 (0)