diff --git a/crates/oxc_prettier/src/format/js.rs b/crates/oxc_prettier/src/format/js.rs index 857aebe36..d317de893 100644 --- a/crates/oxc_prettier/src/format/js.rs +++ b/crates/oxc_prettier/src/format/js.rs @@ -11,8 +11,8 @@ use crate::{ format::{ print::{ array, arrow_function, assignment, binaryish, block, call_expression, class, function, - function_parameters, literal, misc, module, object, property, template_literal, - ternary, + function_parameters, literal, misc, module, object, property, statement, + template_literal, ternary, }, Format, }, @@ -129,29 +129,23 @@ impl<'a> Format<'a> for IfStatement<'a> { wrap!(p, self, IfStatement, { let mut parts = Vec::new_in(p.allocator); - let test_doc = self.test.format(p); - let consequent = self.consequent.format(p); - let consequent = misc::adjust_clause(p, &self.consequent, consequent, false); - - let opening = group!( + let consequent_doc = self.consequent.format(p); + parts.push(group!( p, [ text!("if ("), - group!(p, [indent!(p, [softline!(), test_doc]), softline!()]), + group!(p, [indent!(p, [softline!(), self.test.format(p)]), softline!()]), text!(")"), - consequent + misc::adjust_clause(p, &self.consequent, consequent_doc, false) ] - ); - parts.push(opening); + )); if let Some(alternate) = &self.alternate { let else_on_same_line = matches!(alternate, Statement::BlockStatement(_)); - if else_on_same_line { - parts.push(text!(" ")); - } else { - parts.push(hardline!(p)); - } + parts.push(if else_on_same_line { text!(" ") } else { hardline!(p) }); + parts.push(text!("else")); + let alternate_doc = alternate.format(p); parts.push(group!( p, @@ -178,46 +172,45 @@ impl<'a> Format<'a> for BlockStatement<'a> { impl<'a> Format<'a> for ForStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, ForStatement, { - let body = self.body.format(p); - let body = misc::adjust_clause(p, &self.body, body, false); + let body_doc = self.body.format(p); + let body_doc = misc::adjust_clause(p, &self.body, body_doc, false); if self.init.is_none() && self.test.is_none() && self.update.is_none() { - return group!(p, [text!("for (;;)"), body]); + return group!(p, [text!("for (;;)"), body_doc]); } - let parts_head = { - let mut parts_head = Vec::new_in(p.allocator); - parts_head.push(softline!()); - if let Some(init) = &self.init { - parts_head.push(init.format(p)); - } - parts_head.push(text!(";")); - parts_head.push(line!()); - if let Some(init) = &self.test { - parts_head.push(init.format(p)); - } - parts_head.push(text!(";")); - parts_head.push(line!()); - if let Some(init) = &self.update { - parts_head.push(init.format(p)); - } - indent!(p, parts_head) - }; + let mut init_test_update_parts = Vec::new_in(p.allocator); + init_test_update_parts.push(softline!()); + if let Some(init) = &self.init { + init_test_update_parts.push(match init { + ForStatementInit::VariableDeclaration(v) => v.format(p), + match_expression!(ForStatementInit) => init.to_expression().format(p), + }); + } + init_test_update_parts.push(text!(";")); + init_test_update_parts.push(line!()); + if let Some(init) = &self.test { + init_test_update_parts.push(init.format(p)); + } + init_test_update_parts.push(text!(";")); + init_test_update_parts.push(line!()); + if let Some(init) = &self.update { + init_test_update_parts.push(init.format(p)); + } - group!(p, [text!("for ("), group!(p, [parts_head, softline!()]), text!(")"), body]) + group!( + p, + [ + text!("for ("), + group!(p, [indent!(p, init_test_update_parts), softline!()]), + text!(")"), + body_doc + ] + ) }) } } -impl<'a> Format<'a> for ForStatementInit<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - ForStatementInit::VariableDeclaration(v) => v.format(p), - match_expression!(ForStatementInit) => self.to_expression().format(p), - } - } -} - impl<'a> Format<'a> for ForInStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, ForInStatement, { @@ -353,17 +346,15 @@ impl<'a> Format<'a> for SwitchStatement<'a> { wrap!(p, self, SwitchStatement, { let mut parts = Vec::new_in(p.allocator); - let mut header_parts = Vec::new_in(p.allocator); - - header_parts.push(text!("switch (")); - - let discriminant_doc = self.discriminant.format(p); - header_parts.push(indent!(p, [softline!(), discriminant_doc])); - - header_parts.push(softline!()); - header_parts.push(text!(")")); - - parts.push(group!(p, header_parts)); + parts.push(group!( + p, + [ + text!("switch ("), + indent!(p, [softline!(), self.discriminant.format(p)]), + softline!(), + text!(")"), + ] + )); parts.push(text!(" {")); @@ -397,38 +388,16 @@ impl<'a> Format<'a> for SwitchCase<'a> { parts.push(text!("default:")); } - let consequent: Vec<_> = Vec::from_iter_in( - self.consequent.iter().filter(|c| !matches!(c, Statement::EmptyStatement(_))), - p.allocator, - ); - let len = consequent.len(); - let is_only_one_block_statement = - len == 1 && matches!(self.consequent[0], Statement::BlockStatement(_)); + let len = + self.consequent.iter().filter(|c| !matches!(c, Statement::EmptyStatement(_))).count(); + if len != 0 { + let consequent_parts = + statement::print_statement_sequence(p, self.consequent.as_slice()); - let mut consequent_parts = Vec::new_in(p.allocator); - for i in 0..len { - let stmt = &consequent[i]; - - if i != 0 && matches!(stmt, Statement::BreakStatement(_)) { - let last_stmt = &consequent[i - 1]; - if p.is_next_line_empty(last_stmt.span()) { - consequent_parts.push(hardline!(p)); - } - } - - if is_only_one_block_statement { - consequent_parts.push(text!(" ")); + if len == 1 && matches!(self.consequent[0], Statement::BlockStatement(_)) { + parts.push(array!(p, [text!(" "), array!(p, consequent_parts)])); } else { - consequent_parts.push(hardline!(p)); - } - consequent_parts.push(stmt.format(p)); - } - - if !consequent_parts.is_empty() { - if is_only_one_block_statement { - parts.extend(consequent_parts); - } else { - parts.push(indent!(p, [group!(p, consequent_parts)])); + parts.push(indent!(p, [hardline!(p), array!(p, consequent_parts)])); } } @@ -484,17 +453,14 @@ impl<'a> Format<'a> for TryStatement<'a> { impl<'a> Format<'a> for CatchClause<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, CatchClause, { - let mut parts = Vec::new_in(p.allocator); - - parts.push(text!("catch ")); if let Some(param) = &self.param { - parts.push(text!("(")); - parts.push(param.pattern.format(p)); - parts.push(text!(") ")); + return array!( + p, + [text!("catch ("), param.pattern.format(p), text!(") "), self.body.format(p)] + ); } - parts.push(self.body.format(p)); - array!(p, parts) + array!(p, [text!("catch "), self.body.format(p)]) }) } } @@ -618,7 +584,16 @@ impl<'a> Format<'a> for VariableDeclaration<'a> { impl<'a> Format<'a> for VariableDeclarator<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, VariableDeclarator, { assignment::print_variable_declarator(p, self) }) + wrap!(p, self, VariableDeclarator, { + let left_doc = self.id.format(p); + assignment::print_assignment( + p, + assignment::AssignmentLikeNode::VariableDeclarator(self), + left_doc, + text!(" ="), + self.init.as_ref(), + ) + }) } } @@ -736,18 +711,11 @@ impl<'a> Format<'a> for WithClause<'a> { impl<'a> Format<'a> for ImportAttribute<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let key_doc = self.key.format(p); - let value_doc = self.value.format(p); - array!(p, [key_doc, text!(": "), value_doc]) - } -} - -impl<'a> Format<'a> for ImportAttributeKey<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::Identifier(ident) => ident.format(p), - Self::StringLiteral(literal) => literal.format(p), - } + let key_doc = match &self.key { + ImportAttributeKey::Identifier(ident) => ident.format(p), + ImportAttributeKey::StringLiteral(literal) => literal.format(p), + }; + group!(p, [group!(p, [key_doc]), text!(": "), self.value.format(p)]) } } @@ -805,16 +773,13 @@ impl<'a> Format<'a> for ExportAllDeclaration<'a> { impl<'a> Format<'a> for ExportDefaultDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - self.declaration.format(p) - } -} -impl<'a> Format<'a> for ExportDefaultDeclarationKind<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - match_expression!(Self) => self.to_expression().format(p), - Self::FunctionDeclaration(decl) => decl.format(p), - Self::ClassDeclaration(decl) => decl.format(p), - Self::TSInterfaceDeclaration(decl) => decl.format(p), + match &self.declaration { + match_expression!(ExportDefaultDeclarationKind) => { + self.declaration.to_expression().format(p) + } + ExportDefaultDeclarationKind::FunctionDeclaration(decl) => decl.format(p), + ExportDefaultDeclarationKind::ClassDeclaration(decl) => decl.format(p), + ExportDefaultDeclarationKind::TSInterfaceDeclaration(decl) => decl.format(p), } } } @@ -1225,11 +1190,10 @@ impl<'a> Format<'a> for YieldExpression<'a> { impl<'a> Format<'a> for UpdateExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, UpdateExpression, { + let argument_doc = self.argument.format(p); if self.prefix { - let argument_doc = self.argument.format(p); array!(p, [text!(self.operator.as_str()), argument_doc]) } else { - let argument_doc = self.argument.format(p); array!(p, [argument_doc, text!(self.operator.as_str())]) } }) @@ -1305,7 +1269,16 @@ impl<'a> Format<'a> for ConditionalExpression<'a> { impl<'a> Format<'a> for AssignmentExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, AssignmentExpression, { assignment::print_assignment_expression(p, self) }) + wrap!(p, self, AssignmentExpression, { + let left_doc = self.left.format(p); + assignment::print_assignment( + p, + assignment::AssignmentLikeNode::AssignmentExpression(self), + left_doc, + array!(p, [text!(" "), text!(self.operator.as_str())]), + Some(&self.right), + ) + }) } } @@ -1495,17 +1468,15 @@ impl<'a> Format<'a> for AwaitExpression<'a> { impl<'a> Format<'a> for ChainExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ChainExpression, { self.expression.format(p) }) - } -} - -impl<'a> Format<'a> for ChainElement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::CallExpression(expr) => expr.format(p), - Self::TSNonNullExpression(expr) => expr.format(p), - match_member_expression!(Self) => self.to_member_expression().format(p), - } + wrap!(p, self, ChainExpression, { + match &self.expression { + ChainElement::CallExpression(expr) => expr.format(p), + ChainElement::TSNonNullExpression(expr) => expr.format(p), + match_member_expression!(ChainElement) => { + self.expression.to_member_expression().format(p) + } + } + }) } } @@ -1522,9 +1493,7 @@ impl<'a> Format<'a> for NewExpression<'a> { impl<'a> Format<'a> for MetaProperty<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let meta_doc = self.meta.format(p); - let property_doc = self.property.format(p); - array!(p, [meta_doc, text!("."), property_doc]) + array!(p, [self.meta.format(p), text!("."), self.property.format(p)]) } } @@ -1555,8 +1524,7 @@ impl<'a> Format<'a> for ClassElement<'a> { impl<'a> Format<'a> for StaticBlock<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, StaticBlock, { - let block_doc = block::print_block(p, &self.body, None); - array!(p, [text!("static "), block_doc]) + array!(p, [text!("static "), block::print_block(p, &self.body, None)]) }) } } diff --git a/crates/oxc_prettier/src/format/print/assignment.rs b/crates/oxc_prettier/src/format/print/assignment.rs index ff16f7193..094723b3c 100644 --- a/crates/oxc_prettier/src/format/print/assignment.rs +++ b/crates/oxc_prettier/src/format/print/assignment.rs @@ -17,34 +17,6 @@ use crate::{ line, text, Format, Prettier, }; -pub fn print_assignment_expression<'a>( - p: &mut Prettier<'a>, - assignment_expr: &AssignmentExpression<'a>, -) -> Doc<'a> { - let left_doc = assignment_expr.left.format(p); - print_assignment( - p, - AssignmentLikeNode::AssignmentExpression(assignment_expr), - left_doc, - array!(p, [text!(" "), text!(assignment_expr.operator.as_str())]), - Some(&assignment_expr.right), - ) -} - -pub fn print_variable_declarator<'a>( - p: &mut Prettier<'a>, - variable_declarator: &VariableDeclarator<'a>, -) -> Doc<'a> { - let left_doc = variable_declarator.id.format(p); - print_assignment( - p, - AssignmentLikeNode::VariableDeclarator(variable_declarator), - left_doc, - text!(" ="), - variable_declarator.init.as_ref(), - ) -} - #[derive(Debug, Clone, Copy)] pub enum AssignmentLikeNode<'a, 'b> { AssignmentExpression(&'b AssignmentExpression<'a>), @@ -77,14 +49,14 @@ pub fn print_assignment<'a>( let layout = choose_layout(p, &node, &left_doc, right_expr); // TODO: set the layout in options so that when we print the right-hand side, we can refer to it. - let right_doc = if let Some(expr) = right_expr { expr.format(p) } else { array!(p, []) }; + let right_doc = if let Some(expr) = right_expr { expr.format(p) } else { text!("") }; match layout { Layout::BreakAfterOperator => { group!(p, [group!(p, [left_doc]), op, group!(p, [indent!(p, [line!(), right_doc])])]) } Layout::NeverBreakAfterOperator => { - group!(p, [group!(p, [left_doc]), op, text!(" "), group!(p, [right_doc])]) + group!(p, [group!(p, [left_doc]), op, text!(" "), right_doc]) } // First break right-hand side, then after operator Layout::Fluid => { diff --git a/crates/oxc_prettier/src/format/print/call_arguments.rs b/crates/oxc_prettier/src/format/print/call_arguments.rs index 20a3807e7..2934149d3 100644 --- a/crates/oxc_prettier/src/format/print/call_arguments.rs +++ b/crates/oxc_prettier/src/format/print/call_arguments.rs @@ -21,24 +21,15 @@ pub fn print_call_arguments<'a>( p: &mut Prettier<'a>, expression: &CallExpressionLike<'a, '_>, ) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(text!("(")); - - let callee = expression.callee(); let arguments = expression.arguments(); - let should_break = if matches!(expression, CallExpressionLike::CallExpression(_)) { - !is_commons_js_or_amd_call(expression.callee(), arguments) - } else { - true - }; if arguments.is_empty() { - parts.extend(p.print_inner_comment(Span::new(callee.span().end, expression.span().end))); - parts.push(text!(")")); - - return array!(p, parts); + return array!(p, [text!("("), text!(")")]); } + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("(")); + #[allow(clippy::cast_sign_loss)] let get_printed_arguments = |p: &mut Prettier<'a>, skip_index: isize| { let mut printed_arguments = Vec::new_in(p.allocator); @@ -195,6 +186,12 @@ pub fn print_call_arguments<'a>( let mut printed_arguments = get_printed_arguments(p, 0); + let should_break = if matches!(expression, CallExpressionLike::CallExpression(_)) { + !is_commons_js_or_amd_call(expression.callee(), arguments) + } else { + true + }; + if should_break { printed_arguments.insert(0, softline!()); parts.push(indent!(p, printed_arguments));