Skip to content

fix: keep parentheses around an optional chain used as a member/call/new target#739

Open
sarathfrancis90 wants to merge 1 commit into
davidbonnet:mainfrom
sarathfrancis90:fix/optional-chain-parens
Open

fix: keep parentheses around an optional chain used as a member/call/new target#739
sarathfrancis90 wants to merge 1 commit into
davidbonnet:mainfrom
sarathfrancis90:fix/optional-chain-parens

Conversation

@sarathfrancis90

Copy link
Copy Markdown

generate drops the parentheses that terminate an optional chain when the chain is the object/callee of a member access, call, or new:

import { generate } from "astring";
import { parse } from "acorn";
const opts = { ecmaVersion: 2023 };
generate(parse("(a?.b).c", opts));      // "a?.b.c;"      ← wrong
generate(parse("new (a?.b)()", opts));  // "new a?.b();"  ← not even valid syntax

(a?.b).c and a?.b.c aren't equivalent: the parenthesized form ends the chain at a?.b, so .c runs unconditionally and throws when a is nullish; the unparenthesized form extends the chain and short-circuits to undefined.

The cause is that ChainExpression shares precedence (19) with MemberExpression/CallExpression/NewExpression, so the precedence-only check never parenthesizes it. This wraps the chain when it's the object/callee of those three nodes. a?.b.c (no terminating parens) is unaffected. Added the cases to the object syntax fixture.

…new target

A ChainExpression shares precedence with MemberExpression, CallExpression and
NewExpression, so generating one as the object or callee dropped the
parentheses that terminate the optional chain. `(a?.b).c` was emitted as
`a?.b.c`, which extends the chain over `.c` and changes the meaning: the
parenthesized form throws when `a` is nullish, the unparenthesized form
short-circuits to undefined. `new (a?.b)()` was emitted as `new a?.b()`,
which is not even valid syntax.

Wrap the chain in parentheses when it is the object/callee of a member
access, call or new expression.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant