Skip to content

Commit

Permalink
fix(codegen): preserve parenthesis for ChainExpression (#6430)
Browse files Browse the repository at this point in the history
close: #6385

The fixing way was referenced from `esbuild`, it is according to these [states](https://github.com/evanw/esbuild/blob/332727499e62315cff4ecaff9fa8b86336555e46/internal/js_ast/js_ast.go#L590-L604
)(determined in the parser) to determine whether to print parenthesis

Due to differences in implementation details, we are unable to record certain information like `esbuild` does in its parser. But fortunately, The `ParenthesisExpression` AST is actually like what `esbuild` stored states.
  • Loading branch information
Dunqing committed Oct 13, 2024
1 parent c56343d commit 02bfbfe
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 6 deletions.
13 changes: 10 additions & 3 deletions crates/oxc_ast/src/precedence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use oxc_syntax::precedence::{GetPrecedence, Precedence};

use crate::ast::{
match_member_expression, AssignmentExpression, AwaitExpression, BinaryExpression,
CallExpression, ComputedMemberExpression, ConditionalExpression, Expression, ImportExpression,
LogicalExpression, MemberExpression, NewExpression, PrivateFieldExpression, SequenceExpression,
StaticMemberExpression, TSTypeAssertion, UnaryExpression, UpdateExpression, YieldExpression,
CallExpression, ChainExpression, ComputedMemberExpression, ConditionalExpression, Expression,
ImportExpression, LogicalExpression, MemberExpression, NewExpression, PrivateFieldExpression,
SequenceExpression, StaticMemberExpression, TSTypeAssertion, UnaryExpression, UpdateExpression,
YieldExpression,
};

impl<'a> GetPrecedence for Expression<'a> {
Expand Down Expand Up @@ -103,6 +104,12 @@ impl<'a> GetPrecedence for NewExpression<'a> {
}
}

impl<'a> GetPrecedence for ChainExpression<'a> {
fn precedence(&self) -> Precedence {
Precedence::Member
}
}

impl<'a> GetPrecedence for MemberExpression<'a> {
fn precedence(&self) -> Precedence {
Precedence::Member
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_codegen/src/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2047,12 +2047,12 @@ impl<'a> GenExpr for AwaitExpression<'a> {

impl<'a> GenExpr for ChainExpression<'a> {
fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
match &self.expression {
p.wrap(precedence >= Precedence::Postfix, |p| match &self.expression {
ChainElement::CallExpression(expr) => expr.print_expr(p, precedence, ctx),
match_member_expression!(ChainElement) => {
self.expression.to_member_expression().print_expr(p, precedence, ctx);
}
}
});
}
}

Expand Down
34 changes: 33 additions & 1 deletion crates/oxc_codegen/tests/integration/esbuild.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//! Tests ported from [esbuild](https://github.com/evanw/esbuild/blob/main/internal/js_printer/js_printer_test.go#L164)
//! Tests ported from `esbuild`
//! * <https://github.com/evanw/esbuild/blob/main/internal/js_printer/js_printer_test.go>
//! * <https://github.com/evanw/esbuild/blob/main/internal/js_parser/js_parser_test.go>
use crate::tester::{test, test_minify};

Expand Down Expand Up @@ -1155,3 +1157,33 @@ fn test_using() {
test_minify("await using x = y", "await using x=y;");
test_minify("await using x = y, z = _", "await using x=y,z=_;");
}

#[test]
fn test_preserve_optional_chain_parentheses() {
test("a?.b.c", "a?.b.c;\n");
test("(a?.b).c", "(a?.b).c;\n");
test("a?.b.c.d", "a?.b.c.d;\n");
test("(a?.b.c).d", "(a?.b.c).d;\n");
test("a?.b[c]", "a?.b[c];\n");
test("(a?.b)[c]", "(a?.b)[c];\n");
test("a?.b(c)", "a?.b(c);\n");
test("(a?.b)(c)", "(a?.b)(c);\n");

test("a?.[b][c]", "a?.[b][c];\n");
test("(a?.[b])[c]", "(a?.[b])[c];\n");
test("a?.[b][c][d]", "a?.[b][c][d];\n");
test("(a?.[b][c])[d]", "(a?.[b][c])[d];\n");
test("a?.[b].c", "a?.[b].c;\n");
test("(a?.[b]).c", "(a?.[b]).c;\n");
test("a?.[b](c)", "a?.[b](c);\n");
test("(a?.[b])(c)", "(a?.[b])(c);\n");

test("a?.(b)(c)", "a?.(b)(c);\n");
test("(a?.(b))(c)", "(a?.(b))(c);\n");
test("a?.(b)(c)(d)", "a?.(b)(c)(d);\n");
test("(a?.(b)(c))(d)", "(a?.(b)(c))(d);\n");
test("a?.(b).c", "a?.(b).c;\n");
test("(a?.(b)).c", "(a?.(b)).c;\n");
test("a?.(b)[c]", "a?.(b)[c];\n");
test("(a?.(b))[c]", "(a?.(b))[c];\n");
}

0 comments on commit 02bfbfe

Please sign in to comment.