diff --git a/crates/oxc_ast/src/ast/js.rs b/crates/oxc_ast/src/ast/js.rs index c9c362bee..cfda1f6e5 100644 --- a/crates/oxc_ast/src/ast/js.rs +++ b/crates/oxc_ast/src/ast/js.rs @@ -1,7 +1,7 @@ use std::{cell::Cell, fmt, hash::Hash}; use oxc_allocator::{Box, Vec}; -use oxc_span::{Atom, GetSpan, SourceType, Span}; +use oxc_span::{Atom, SourceType, Span}; use oxc_syntax::{ operator::{ AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator, @@ -919,15 +919,6 @@ pub enum AssignmentTargetProperty<'a> { AssignmentTargetPropertyProperty(Box<'a, AssignmentTargetPropertyProperty<'a>>), } -impl<'a> GetSpan for AssignmentTargetProperty<'a> { - fn span(&self) -> Span { - match self { - Self::AssignmentTargetPropertyIdentifier(identifier) => identifier.span, - Self::AssignmentTargetPropertyProperty(literal) => literal.span, - } - } -} - /// Assignment Property - Identifier Reference #[derive(Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] @@ -1456,12 +1447,6 @@ pub struct BindingProperty<'a> { pub computed: bool, } -impl<'a> GetSpan for BindingProperty<'a> { - fn span(&self) -> Span { - self.span - } -} - #[derive(Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] pub struct ArrayPattern<'a> { diff --git a/crates/oxc_ast/src/ast_kind.rs b/crates/oxc_ast/src/ast_kind.rs index ba22b7e2b..40f6ac23b 100644 --- a/crates/oxc_ast/src/ast_kind.rs +++ b/crates/oxc_ast/src/ast_kind.rs @@ -75,6 +75,8 @@ pub enum AstKind<'a> { UnaryExpression(&'a UnaryExpression<'a>), UpdateExpression(&'a UpdateExpression<'a>), YieldExpression(&'a YieldExpression<'a>), + ImportExpression(&'a ImportExpression<'a>), + PrivateInExpression(&'a PrivateInExpression<'a>), ObjectProperty(&'a ObjectProperty<'a>), PropertyKey(&'a PropertyKey<'a>), @@ -328,6 +330,8 @@ impl<'a> GetSpan for AstKind<'a> { Self::UnaryExpression(x) => x.span, Self::UpdateExpression(x) => x.span, Self::YieldExpression(x) => x.span, + Self::ImportExpression(x) => x.span, + Self::PrivateInExpression(x) => x.span, Self::ObjectProperty(x) => x.span, Self::PropertyKey(x) => x.span(), @@ -488,6 +492,8 @@ impl<'a> AstKind<'a> { Self::UnaryExpression(expr) => format!("UnaryExpression({:?})", expr.operator).into(), Self::UpdateExpression(_) => "UpdateExpression".into(), Self::YieldExpression(_) => "YieldExpression".into(), + Self::ImportExpression(_) => "ImportExpression".into(), + Self::PrivateInExpression(_) => "PrivateInExpression".into(), Self::ObjectProperty(_) => "ObjectProperty".into(), Self::PropertyKey(_) => "PropertyKey".into(), diff --git a/crates/oxc_ast/src/span.rs b/crates/oxc_ast/src/span.rs index 773d82bff..59693f06c 100644 --- a/crates/oxc_ast/src/span.rs +++ b/crates/oxc_ast/src/span.rs @@ -104,6 +104,12 @@ impl<'a> GetSpan for BindingPattern<'a> { } } +impl<'a> GetSpan for BindingProperty<'a> { + fn span(&self) -> Span { + self.span + } +} + impl<'a> GetSpan for ClassElement<'a> { fn span(&self) -> Span { match self { @@ -217,6 +223,15 @@ impl<'a> GetSpan for AssignmentTarget<'a> { } } +impl<'a> GetSpan for AssignmentTargetProperty<'a> { + fn span(&self) -> Span { + match self { + Self::AssignmentTargetPropertyIdentifier(identifier) => identifier.span, + Self::AssignmentTargetPropertyProperty(literal) => literal.span, + } + } +} + impl<'a> GetSpan for Argument<'a> { fn span(&self) -> Span { match self { diff --git a/crates/oxc_prettier/src/format/mod.rs b/crates/oxc_prettier/src/format/mod.rs index 0943cac71..8e8be6550 100644 --- a/crates/oxc_prettier/src/format/mod.rs +++ b/crates/oxc_prettier/src/format/mod.rs @@ -525,11 +525,13 @@ impl<'a> Format<'a> for DebuggerStatement { impl<'a> Format<'a> for ModuleDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - if let ModuleDeclaration::ImportDeclaration(decl) = self { - decl.format(p) - } else { - module::print_export_declaration(p, self) - } + wrap!(p, self, ModuleDeclaration, { + if let ModuleDeclaration::ImportDeclaration(decl) = self { + decl.format(p) + } else { + module::print_export_declaration(p, self) + } + }) } } @@ -1331,14 +1333,16 @@ impl<'a> Format<'a> for PrivateFieldExpression<'a> { impl<'a> Format<'a> for CallExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - call_expression::print_call_expression( - p, - &self.callee, - &self.arguments, - self.optional, - &self.type_parameters, - /* is_new */ false, - ) + wrap!(p, self, CallExpression, { + call_expression::print_call_expression( + p, + &self.callee, + &self.arguments, + self.optional, + &self.type_parameters, + /* is_new */ false, + ) + }) } } @@ -1369,13 +1373,19 @@ impl<'a> Format<'a> for SpreadElement<'a> { impl<'a> Format<'a> for ArrayExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - array::print_array(p, &Array::ArrayExpression(self)) + wrap!(p, self, ArrayExpression, { array::print_array(p, &Array::ArrayExpression(self)) }) } } impl<'a> Format<'a> for ObjectExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - object::print_object_properties(p, &ObjectLike::ObjectExpression(self), &self.properties) + wrap!(p, self, ObjectExpression, { + object::print_object_properties( + p, + &ObjectLike::ObjectExpression(self), + &self.properties, + ) + }) } } @@ -1409,13 +1419,13 @@ impl<'a> Format<'a> for ObjectProperty<'a> { } if method { if let Expression::FunctionExpression(func_expr) = &self.value { - wrap!(p, func_expr, Function, { - parts.push(function::print_function( + parts.push(wrap!(p, func_expr, Function, { + function::print_function( p, func_expr, Some(self.key.span().source_text(p.source_text)), - )); - }); + ) + })); } } else { parts.push(format!(p, self.key)); @@ -1474,77 +1484,89 @@ impl<'a> Format<'a> for YieldExpression<'a> { impl<'a> Format<'a> for UpdateExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - if self.prefix { - array![p, ss!(self.operator.as_str()), format!(p, self.argument)] - } else { - array![p, format!(p, self.argument), ss!(self.operator.as_str())] - } + wrap!(p, self, UpdateExpression, { + if self.prefix { + array![p, ss!(self.operator.as_str()), format!(p, self.argument)] + } else { + array![p, format!(p, self.argument), ss!(self.operator.as_str())] + } + }) } } impl<'a> Format<'a> for UnaryExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(string!(p, self.operator.as_str())); - if self.operator.is_keyword() { - parts.push(ss!(" ")); - } - parts.push(format!(p, self.argument)); - Doc::Array(parts) + wrap!(p, self, UnaryExpression, { + let mut parts = p.vec(); + parts.push(string!(p, self.operator.as_str())); + if self.operator.is_keyword() { + parts.push(ss!(" ")); + } + parts.push(format!(p, self.argument)); + Doc::Array(parts) + }) } } impl<'a> Format<'a> for BinaryExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let doc = binaryish::print_binaryish_expression( - p, - &BinaryishLeft::Expression(&self.left), - BinaryishOperator::BinaryOperator(self.operator), - &self.right, - ); - group!(p, indent!(p, softline!(), doc), softline!()) + wrap!(p, self, BinaryExpression, { + let doc = binaryish::print_binaryish_expression( + p, + &BinaryishLeft::Expression(&self.left), + BinaryishOperator::BinaryOperator(self.operator), + &self.right, + ); + group!(p, indent!(p, softline!(), doc), softline!()) + }) } } impl<'a> Format<'a> for PrivateInExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - binaryish::print_binaryish_expression( - p, - &BinaryishLeft::PrivateIdentifier(&self.left), - BinaryishOperator::BinaryOperator(self.operator), - &self.right, - ) + wrap!(p, self, PrivateInExpression, { + binaryish::print_binaryish_expression( + p, + &BinaryishLeft::PrivateIdentifier(&self.left), + BinaryishOperator::BinaryOperator(self.operator), + &self.right, + ) + }) } } impl<'a> Format<'a> for LogicalExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let doc = binaryish::print_binaryish_expression( - p, - &BinaryishLeft::Expression(&self.left), - BinaryishOperator::LogicalOperator(self.operator), - &self.right, - ); - group!(p, indent!(p, softline!(), doc), softline!()) + wrap!(p, self, LogicalExpression, { + let doc = binaryish::print_binaryish_expression( + p, + &BinaryishLeft::Expression(&self.left), + BinaryishOperator::LogicalOperator(self.operator), + &self.right, + ); + group!(p, indent!(p, softline!(), doc), softline!()) + }) } } impl<'a> Format<'a> for ConditionalExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - ternary::print_ternary(p, self) + wrap!(p, self, ConditionalExpression, { ternary::print_ternary(p, self) }) } } impl<'a> Format<'a> for AssignmentExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - array![ - p, - format!(p, self.left), - ss!(" "), - string!(p, self.operator.as_str()), - ss!(" "), - format!(p, self.right) - ] + wrap!(p, self, AssignmentExpression, { + array![ + p, + format!(p, self.left), + ss!(" "), + string!(p, self.operator.as_str()), + ss!(" "), + format!(p, self.right) + ] + }) } } @@ -1643,42 +1665,39 @@ impl<'a> Format<'a> for AssignmentTargetPropertyProperty<'a> { impl<'a> Format<'a> for SequenceExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let docs = self.expressions.iter().map(|expr| expr.format(p)).collect::>(); - group![p, Doc::Array(p.join(Separator::CommaLine, docs))] + wrap!(p, self, SequenceExpression, { + let docs = + self.expressions.iter().map(|expr| expr.format(p)).collect::>(); + group![p, Doc::Array(p.join(Separator::CommaLine, docs))] + }) } } impl<'a> Format<'a> for ParenthesizedExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - // TODO: if shouldHug - // array![p, ss!("("), format!(p, self.expression), ss!(")")] - array![ - p, - ss!("("), - format!(p, self.expression), - // indent!(p, array![p, softline!(), ]), - // softline!(), - ss!(")") - ] + // TODO: This wrap need to be removed and all logic should go into `need_parens`. + wrap!(p, self, ParenthesizedExpression, { self.expression.format(p) }) } } impl<'a> Format<'a> for ImportExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(ss!("import")); - parts.push(ss!("(")); - parts.push(format!(p, self.source)); - if !self.arguments.is_empty() { - for arg in &self.arguments { - parts.push(ss!(",")); - parts.push(Doc::Line); - parts.push(format!(p, arg)); + wrap!(p, self, ImportExpression, { + let mut parts = p.vec(); + parts.push(ss!("import")); + parts.push(ss!("(")); + parts.push(format!(p, self.source)); + if !self.arguments.is_empty() { + for arg in &self.arguments { + parts.push(ss!(",")); + parts.push(Doc::Line); + parts.push(format!(p, arg)); + } } - } - parts.push(ss!(")")); + parts.push(ss!(")")); - Doc::Group(Group::new(parts, false)) + Doc::Group(Group::new(parts, false)) + }) } } @@ -1709,16 +1728,18 @@ impl<'a> Format<'a> for Super { impl<'a> Format<'a> for AwaitExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(ss!("await ")); - parts.push(format!(p, self.argument)); - Doc::Array(parts) + wrap!(p, self, AwaitExpression, { + let mut parts = p.vec(); + parts.push(ss!("await ")); + parts.push(format!(p, self.argument)); + Doc::Array(parts) + }) } } impl<'a> Format<'a> for ChainExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - format!(p, self.expression) + wrap!(p, self, ChainExpression, { format!(p, self.expression) }) } } @@ -1733,14 +1754,16 @@ impl<'a> Format<'a> for ChainElement<'a> { impl<'a> Format<'a> for NewExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - call_expression::print_call_expression( - p, - &self.callee, - &self.arguments, - false, - &self.type_parameters, - /* is_new */ true, - ) + wrap!(p, self, NewExpression, { + call_expression::print_call_expression( + p, + &self.callee, + &self.arguments, + false, + &self.type_parameters, + /* is_new */ true, + ) + }) } } diff --git a/crates/oxc_prettier/src/lib.rs b/crates/oxc_prettier/src/lib.rs index 6fcd9e98a..aa76358ab 100644 --- a/crates/oxc_prettier/src/lib.rs +++ b/crates/oxc_prettier/src/lib.rs @@ -8,6 +8,7 @@ mod comment; mod doc; mod format; mod macros; +mod need_parens; mod options; mod printer; diff --git a/crates/oxc_prettier/src/macros.rs b/crates/oxc_prettier/src/macros.rs index a5c07dd63..6d77adc56 100644 --- a/crates/oxc_prettier/src/macros.rs +++ b/crates/oxc_prettier/src/macros.rs @@ -105,8 +105,10 @@ macro_rules! if_break { #[macro_export] macro_rules! wrap { ($p:ident, $self:expr, $kind:ident, $block:block) => {{ - $p.enter_node(AstKind::$kind($p.alloc($self))); + let kind = AstKind::$kind($p.alloc($self)); + $p.enter_node(kind); let doc = $block; + let doc = $p.wrap_parens(doc, kind); $p.leave_node(); doc }}; diff --git a/crates/oxc_prettier/src/need_parens.rs b/crates/oxc_prettier/src/need_parens.rs new file mode 100644 index 000000000..f6e70c253 --- /dev/null +++ b/crates/oxc_prettier/src/need_parens.rs @@ -0,0 +1,46 @@ +use oxc_ast::AstKind; + +use crate::{array, doc::Doc, ss, Prettier}; + +impl<'a> Prettier<'a> { + pub(crate) fn wrap_parens(&self, doc: Doc<'a>, kind: AstKind<'a>) -> Doc<'a> { + if self.need_parens(kind) { + array![self, ss!("("), doc, ss!(")")] + } else { + doc + } + } + + fn need_parens(&self, kind: AstKind<'a>) -> bool { + match kind { + // Only statements don't need parentheses. + kind if kind.is_statement() => return false, + AstKind::SequenceExpression(_) => { + let parent = self.parent_kind(); + + if matches!(parent, AstKind::Program(_)) { + return false; + } + } + AstKind::ObjectExpression(_) => { + let parent = self.parent_kind(); + + if matches!(parent, AstKind::Program(_)) { + return true; + } + } + AstKind::AssignmentExpression(_) => { + let parent = self.parent_kind(); + + if matches!(parent, AstKind::ArrowExpression(arrow_expr) if arrow_expr.expression) { + return true; + } + } + // NOTE: This is a fallback which should be removed when all code are ported. + AstKind::ParenthesizedExpression(_) => return true, + _ => {} + } + + false + } +}