From 0ce7ce7ff4b512d2cb9efe7815b8ceb15b025e9a Mon Sep 17 00:00:00 2001 From: Yuji Sugiura <6259812+leaysgur@users.noreply.github.com> Date: Wed, 4 Dec 2024 17:58:00 +0900 Subject: [PATCH] refactor(prettier): Revive doc macro (#7639) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As @Boshen advised, reintroduced the macro. https://github.com/oxc-project/oxc/pull/7639/files#diff-18e08d6e3a6853a2ae1a973ab1615ee04ed585638eef92c8c1e49f7814f6193f It feels addictive...! 🤩 --- crates/oxc_prettier/src/comments/print.rs | 9 +- crates/oxc_prettier/src/format/array.rs | 101 +- .../oxc_prettier/src/format/arrow_function.rs | 20 +- crates/oxc_prettier/src/format/assignment.rs | 44 +- crates/oxc_prettier/src/format/binaryish.rs | 48 +- crates/oxc_prettier/src/format/block.rs | 31 +- .../oxc_prettier/src/format/call_arguments.rs | 157 +-- .../src/format/call_expression.rs | 14 +- crates/oxc_prettier/src/format/class.rs | 153 ++- crates/oxc_prettier/src/format/function.rs | 106 +- .../src/format/function_parameters.rs | 64 +- crates/oxc_prettier/src/format/misc.rs | 8 +- crates/oxc_prettier/src/format/mod.rs | 1003 ++++++++--------- crates/oxc_prettier/src/format/module.rs | 75 +- crates/oxc_prettier/src/format/object.rs | 41 +- crates/oxc_prettier/src/format/statement.rs | 11 +- .../src/format/template_literal.rs | 19 +- crates/oxc_prettier/src/format/ternary.rs | 20 +- crates/oxc_prettier/src/ir/builder.rs | 146 --- crates/oxc_prettier/src/ir/doc.rs | 39 +- crates/oxc_prettier/src/ir/mod.rs | 2 - crates/oxc_prettier/src/lib.rs | 21 +- crates/oxc_prettier/src/macros.rs | 302 ++++- crates/oxc_prettier/src/printer/mod.rs | 11 +- 24 files changed, 1261 insertions(+), 1184 deletions(-) delete mode 100644 crates/oxc_prettier/src/ir/builder.rs diff --git a/crates/oxc_prettier/src/comments/print.rs b/crates/oxc_prettier/src/comments/print.rs index a8f5cb5025b2d..317f70c7d1c11 100644 --- a/crates/oxc_prettier/src/comments/print.rs +++ b/crates/oxc_prettier/src/comments/print.rs @@ -1,10 +1,7 @@ use oxc_allocator::Vec; use oxc_span::Span; -use crate::{ - ir::{Doc, DocBuilder}, - Prettier, -}; +use crate::{ir::Doc, Prettier}; use super::{CommentFlags, DanglingCommentsPrintOptions}; @@ -17,7 +14,7 @@ impl<'a> Prettier<'a> { after: Option>, ) -> Doc<'a> { if before.is_some() || after.is_some() { - let mut parts = self.vec(); + let mut parts = Vec::new_in(self.allocator); if let Some(doc) = before { parts.push(doc); } @@ -46,7 +43,7 @@ impl<'a> Prettier<'a> { #[must_use] pub(crate) fn print_inner_comment(&mut self, _span: Span) -> Vec<'a, Doc<'a>> { - self.vec() + Vec::new_in(self.allocator) } #[must_use] diff --git a/crates/oxc_prettier/src/format/array.rs b/crates/oxc_prettier/src/format/array.rs index 77fb6b2bcfe82..e56a5a6c2f94c 100644 --- a/crates/oxc_prettier/src/format/array.rs +++ b/crates/oxc_prettier/src/format/array.rs @@ -1,11 +1,14 @@ +use oxc_allocator::Vec; use oxc_ast::ast::*; use oxc_span::{GetSpan, Span}; use oxc_syntax::operator::UnaryOperator; use crate::{ + array, comments::{CommentFlags, DanglingCommentsPrintOptions}, - ir::{Doc, DocBuilder}, - p_vec, Format, Prettier, + fill, group, hardline, if_break, indent, + ir::Doc, + line, softline, text, Format, Prettier, }; #[allow(clippy::enum_variant_names)] @@ -80,32 +83,32 @@ pub fn print_array<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc<'a> { let trailing_comma_fn = |p: &Prettier<'a>| { if !can_have_trailing_comma { - p.text("") + text!("") } else if needs_forced_trailing_comma { - p.text(",") + text!(",") } else if should_use_concise_formatting { - p.if_break(p.text(","), p.text(""), Some(id)) + if_break!(p, text!(","), text!(""), Some(id)) } else { - p.if_break(p.text(","), p.text(""), None) + if_break!(p, text!(",")) } }; - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); let group = { - let mut group = p.vec(); - group.push(p.text("[")); + let mut group = Vec::new_in(p.allocator); + group.push(text!("[")); let indent_parts = { - let mut indent_parts = p.vec(); - indent_parts.push(p.softline()); + let mut indent_parts = Vec::new_in(p.allocator); + indent_parts.push(softline!()); indent_parts.push(if should_use_concise_formatting { print_array_elements_concisely(p, arr, trailing_comma_fn) } else { let trailing_comma = trailing_comma_fn(p); let elements = print_array_elements(p, arr); - p.array(p_vec!(p, elements, trailing_comma)) + array!(p, [elements, trailing_comma]) }); if let Some(dangling_comments) = p.print_dangling_comments(arr.span(), None) { indent_parts.push(dangling_comments); @@ -113,39 +116,37 @@ pub fn print_array<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc<'a> { indent_parts }; - group.push(p.indent(indent_parts)); - group.push(p.softline()); - group.push(p.text("]")); + group.push(indent!(p, indent_parts)); + group.push(softline!()); + group.push(text!("]")); - p.array(group) + group }; - parts.push(p.group_with_opts(group, should_break(arr), Some(id))); + parts.push(group!(p, group, should_break(arr), Some(id))); - p.array(parts) + array!(p, parts) } fn print_empty_array_elements<'a>(p: &mut Prettier<'a>, array: &Array<'a, '_>) -> Doc<'a> { let dangling_options = DanglingCommentsPrintOptions::default().with_ident(true); p.print_dangling_comments(array.span(), Some(&dangling_options)).map_or_else( - || p.text("[]"), - |dangling_comments| { - p.group(p.array(p_vec!(p, p.text("["), dangling_comments, p.softline(), p.text("]")))) - }, + || text!("[]"), + |dangling_comments| group!(p, [text!("["), dangling_comments, softline!(), text!("]")]), ) } fn print_array_elements<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); match arr { Array::ArrayExpression(array) => { for (i, element) in array.elements.iter().enumerate() { parts.push(element.format(p)); let is_last = i == array.elements.len() - 1; if !is_last { - parts.push(p.text(",")); - parts.push(p.line()); + parts.push(text!(",")); + parts.push(line!()); if !element.is_elision() && is_line_after_element_empty(p, element.span().end) { - parts.push(p.softline()); + parts.push(softline!()); } } } @@ -153,8 +154,8 @@ fn print_array_elements<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc<'a Array::TSTupleType(tuple) => { for (i, element) in tuple.element_types.iter().enumerate() { if i > 0 && i < tuple.element_types.len() { - parts.push(p.text(",")); - parts.push(p.line()); + parts.push(text!(",")); + parts.push(line!()); } parts.push(element.format(p)); @@ -166,24 +167,24 @@ fn print_array_elements<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc<'a for (i, element) in array_pat.elements.iter().enumerate() { if let Some(binding_pat) = element { let binding_pat_doc = binding_pat.format(p); - parts.push(p.group(binding_pat_doc)); + parts.push(group!(p, [binding_pat_doc])); } if i == len - 1 && !has_rest { break; } - parts.push(p.text(",")); - parts.push(p.line()); + parts.push(text!(",")); + parts.push(line!()); } if let Some(rest) = &array_pat.rest { let rest_doc = rest.format(p); - parts.push(p.group(rest_doc)); + parts.push(group!(p, [rest_doc])); } } Array::ArrayAssignmentTarget(array_pat) => { for (i, element) in array_pat.elements.iter().enumerate() { if i > 0 && i < array_pat.elements.len() { - parts.push(p.text(",")); - parts.push(p.line()); + parts.push(text!(",")); + parts.push(line!()); } if let Some(binding_pat) = element { @@ -192,14 +193,14 @@ fn print_array_elements<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc<'a } if let Some(rest) = &array_pat.rest { - parts.push(p.text(",")); - parts.push(p.line()); + parts.push(text!(",")); + parts.push(line!()); parts.push(rest.format(p)); } } } - p.array(parts) + array!(p, parts) } fn print_array_elements_concisely<'a, F>( @@ -210,42 +211,42 @@ fn print_array_elements_concisely<'a, F>( where F: Fn(&Prettier<'a>) -> Doc<'a>, { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if let Array::ArrayExpression(arr) = arr { for (i, element) in arr.elements.iter().enumerate() { let is_last = i == arr.elements.len() - 1; let element_doc = element.format(p); let part = if is_last { - p.array(p_vec!(p, element_doc, trailing_comma_fn(p))) + array!(p, [element_doc, trailing_comma_fn(p)]) } else { - p.array(p_vec!(p, element_doc, p.text(","))) + array!(p, [element_doc, text!(",")]) }; parts.push(part); if !is_last { if is_line_after_element_empty(p, element.span().end) { - let mut space_parts = p.vec(); - space_parts.extend(p.hardline()); - space_parts.extend(p.hardline()); - parts.push(p.array(space_parts)); + let mut space_parts = Vec::new_in(p.allocator); + space_parts.extend(hardline!()); + space_parts.extend(hardline!()); + parts.push(array!(p, space_parts)); } else if arr.elements.get(i + 1).is_some_and(|next| { p.has_comment(next.span(), CommentFlags::Leading | CommentFlags::Line) }) { - let mut space_parts = p.vec(); - space_parts.extend(p.hardline()); - parts.push(p.array(space_parts)); + let mut space_parts = Vec::new_in(p.allocator); + space_parts.extend(hardline!()); + parts.push(array!(p, space_parts)); } else { - parts.push(p.line()); + parts.push(line!()); } } } } else { // TODO: implement let elements = print_array_elements(p, arr); - p.array(p_vec!(p, elements, trailing_comma_fn(p))); + array!(p, [elements, trailing_comma_fn(p)]); } - p.fill(parts) + fill!(p, parts) } fn should_break(array: &Array) -> bool { diff --git a/crates/oxc_prettier/src/format/arrow_function.rs b/crates/oxc_prettier/src/format/arrow_function.rs index a2672875b584c..62bc0e66c4d92 100644 --- a/crates/oxc_prettier/src/format/arrow_function.rs +++ b/crates/oxc_prettier/src/format/arrow_function.rs @@ -1,22 +1,20 @@ +use oxc_allocator::Vec; use oxc_ast::ast::*; -use crate::{ - ir::{Doc, DocBuilder}, - Format, Prettier, -}; +use crate::{array, group, ir::Doc, text, Format, Prettier}; pub(super) fn print_arrow_function<'a>( p: &mut Prettier<'a>, expr: &ArrowFunctionExpression<'a>, ) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if !p.options.semi && p.options.arrow_parens.is_always() { - parts.push(p.text(";")); + parts.push(text!(";")); } if expr.r#async { - parts.push(p.text("async ")); + parts.push(text!("async ")); } if let Some(type_params) = &expr.type_parameters { @@ -24,14 +22,14 @@ pub(super) fn print_arrow_function<'a>( } let params_doc = expr.params.format(p); - parts.push(p.group(params_doc)); + parts.push(group!(p, [params_doc])); if let Some(return_type) = &expr.return_type { - parts.push(p.text(": ")); + parts.push(text!(": ")); parts.push(return_type.type_annotation.format(p)); } - parts.push(p.text(" => ")); + parts.push(text!(" => ")); if expr.expression { let stmt = &expr.body.statements[0]; @@ -45,5 +43,5 @@ pub(super) fn print_arrow_function<'a>( parts.push(expr.body.format(p)); } - p.array(parts) + array!(p, parts) } diff --git a/crates/oxc_prettier/src/format/assignment.rs b/crates/oxc_prettier/src/format/assignment.rs index 29d494d58e699..bac328f243996 100644 --- a/crates/oxc_prettier/src/format/assignment.rs +++ b/crates/oxc_prettier/src/format/assignment.rs @@ -1,3 +1,4 @@ +use oxc_allocator::Vec; use oxc_ast::{ ast::{ match_member_expression, AccessorProperty, Argument, AssignmentExpression, @@ -9,9 +10,11 @@ use oxc_ast::{ }; use crate::{ + array, format::{binaryish::should_inline_logical_expression, class::ClassMemberish}, - ir::{Doc, DocBuilder}, - p_vec, Format, Prettier, + group, indent, indent_if_break, + ir::Doc, + line, text, Format, Prettier, }; pub(super) fn print_assignment_expression<'a>( @@ -23,7 +26,7 @@ pub(super) fn print_assignment_expression<'a>( p, AssignmentLikeNode::AssignmentExpression(assignment_expr), left_doc, - p.array(p_vec!(p, p.space(), p.text(assignment_expr.operator.as_str()))), + array!(p, [text!(" "), text!(assignment_expr.operator.as_str())]), Some(&assignment_expr.right), ) } @@ -37,7 +40,7 @@ pub(super) fn print_variable_declarator<'a>( p, AssignmentLikeNode::VariableDeclarator(variable_declarator), left_doc, - p.text(" ="), + text!(" ="), variable_declarator.init.as_ref(), ) } @@ -74,42 +77,37 @@ pub(super) 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 { p.array(p.vec()) }; + let right_doc = if let Some(expr) = right_expr { expr.format(p) } else { array!(p, []) }; match layout { - Layout::BreakAfterOperator => p.group(p.array(p_vec!( - p, - p.group(left_doc), - op, - p.group(p.indent(p_vec!(p, p.line(), right_doc))) - ))), + Layout::BreakAfterOperator => { + group!(p, [group!(p, [left_doc]), op, group!(p, [indent!(p, [line!(), right_doc])])]) + } Layout::NeverBreakAfterOperator => { - p.group(p.array(p_vec!(p, p.group(left_doc), op, p.space(), p.group(right_doc)))) + group!(p, [group!(p, [left_doc]), op, text!(" "), group!(p, [right_doc])]) } // First break right-hand side, then after operator Layout::Fluid => { let group_id = p.next_id(); let after_op = { - let mut parts = p.vec(); - parts.push(p.indent(p_vec!(p, p.line()))); - p.group_with_opts(p.array(parts), false, Some(group_id)) + let mut parts = Vec::new_in(p.allocator); + parts.push(indent!(p, [line!()])); + group!(p, parts, false, Some(group_id)) }; - let right_doc = { p.indent_if_break(p.group(right_doc), group_id) }; + let right_doc = { indent_if_break!(p, group!(p, [right_doc]), group_id) }; - p.group(p.array(p_vec!(p, p.group(left_doc), op, after_op, right_doc))) - } - Layout::BreakLhs => { - p.group(p.array(p_vec!(p, left_doc, op, p.space(), p.group(right_doc)))) + group!(p, [group!(p, [left_doc]), op, after_op, right_doc]) } + Layout::BreakLhs => group!(p, [left_doc, op, text!(" "), group!(p, [right_doc])]), // Parts of assignment chains aren't wrapped in groups. // Once one of them breaks, the chain breaks too. - Layout::Chain => p.array(p_vec!(p, p.group(left_doc), op, p.line(), right_doc)), + Layout::Chain => array!(p, [group!(p, [left_doc]), op, line!(), right_doc]), Layout::ChainTail => { - p.array(p_vec!(p, p.group(left_doc), op, p.indent(p_vec!(p, p.line(), right_doc)))) + array!(p, [group!(p, [left_doc]), op, indent!(p, [line!(), right_doc])]) } - Layout::ChainTailArrowChain => p.array(p_vec!(p, p.group(left_doc), op, right_doc)), + Layout::ChainTailArrowChain => array!(p, [group!(p, [left_doc]), op, right_doc]), Layout::OnlyLeft => left_doc, } } diff --git a/crates/oxc_prettier/src/format/binaryish.rs b/crates/oxc_prettier/src/format/binaryish.rs index d4d7bcd9c6558..63ba25f6cef6e 100644 --- a/crates/oxc_prettier/src/format/binaryish.rs +++ b/crates/oxc_prettier/src/format/binaryish.rs @@ -3,10 +3,8 @@ use oxc_ast::{ast::*, AstKind}; use oxc_span::GetSpan; use crate::{ - binaryish::BinaryishOperator, - comments::CommentFlags, - ir::{Doc, DocBuilder}, - Format, Prettier, + array, binaryish::BinaryishOperator, comments::CommentFlags, group, indent, ir::Doc, line, + text, Format, Prettier, }; pub(super) fn print_binaryish_expression<'a>( @@ -27,14 +25,14 @@ pub(super) fn print_binaryish_expression<'a>( let parts = print_binaryish_expressions(p, left, operator, right); if is_inside_parenthesis { - return p.array(parts); + return array!(p, parts); } // Avoid indenting sub-expressions in some cases where the first sub-expression is already // indented accordingly. We should indent sub-expressions where the first case isn't indented. let should_not_indent = matches!(parent_kind, AstKind::ReturnStatement(_)); if should_not_indent { - return p.group(p.array(parts)); + return group!(p, parts); } let first_group_index = parts.iter().position(|part| { @@ -46,8 +44,8 @@ pub(super) fn print_binaryish_expression<'a>( // Separate the leftmost expression, possibly with its leading comments. let first_group_index = first_group_index.map_or(1, |index| index + 1); - let mut group = p.vec(); - let mut rest = p.vec(); + let mut group = Vec::new_in(p.allocator); + let mut rest = Vec::new_in(p.allocator); for (i, part) in parts.into_iter().enumerate() { if i < first_group_index { group.push(part); @@ -55,8 +53,8 @@ pub(super) fn print_binaryish_expression<'a>( rest.push(part); } } - group.push(p.indent(rest)); - p.group(p.array(group)) + group.push(indent!(p, rest)); + group!(p, group) } fn print_binaryish_expressions<'a>( @@ -65,7 +63,7 @@ fn print_binaryish_expressions<'a>( operator: BinaryishOperator, right: &Expression<'a>, ) -> Vec<'a, Doc<'a>> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); let left_operator = match left { Expression::LogicalExpression(e) => Some(BinaryishOperator::LogicalOperator(e.operator)), @@ -77,35 +75,35 @@ fn print_binaryish_expressions<'a>( parts.push(match left { Expression::BinaryExpression(e) => { let expr_doc = print_binaryish_expressions(p, &e.left, e.operator.into(), &e.right); - p.array(expr_doc) + array!(p, expr_doc) } Expression::LogicalExpression(e) => { let expr_doc = print_binaryish_expressions(p, &e.left, e.operator.into(), &e.right); - p.array(expr_doc) + array!(p, expr_doc) } _ => unreachable!(), }); } else { let left_doc = left.format(p); - parts.push(p.group(left_doc)); + parts.push(group!(p, [left_doc])); } let should_inline = should_inline_logical_expression(right); let line_before_operator = false; let right = if should_inline { - let mut parts = p.vec(); - parts.push(p.text(operator.as_str())); - parts.push(p.space()); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!(operator.as_str())); + parts.push(text!(" ")); parts.push(right.format(p)); parts } else { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if line_before_operator { - parts.push(p.line()); + parts.push(line!()); } - parts.push(p.text(operator.as_str())); - parts.push(if line_before_operator { p.space() } else { p.line() }); + parts.push(text!(operator.as_str())); + parts.push(if line_before_operator { text!(" ") } else { line!() }); parts.push(right.format(p)); parts }; @@ -114,14 +112,10 @@ fn print_binaryish_expressions<'a>( let should_group = should_break; if !line_before_operator { - parts.push(p.space()); + parts.push(text!(" ")); } - parts.push(if should_group { - p.group_with_opts(p.array(right), should_break, None) - } else { - p.array(right) - }); + parts.push(if should_group { group!(p, right, should_break, None) } else { array!(p, right) }); parts } diff --git a/crates/oxc_prettier/src/format/block.rs b/crates/oxc_prettier/src/format/block.rs index aa25511507ca7..3db38f9b5f411 100644 --- a/crates/oxc_prettier/src/format/block.rs +++ b/crates/oxc_prettier/src/format/block.rs @@ -1,26 +1,24 @@ +use oxc_allocator::Vec; use oxc_ast::{ast::*, AstKind}; -use crate::{ - format::statement, - ir::{Doc, DocBuilder}, - Format, Prettier, -}; +use crate::{array, format::statement, hardline, indent, ir::Doc, text, Format, Prettier}; pub(super) fn print_block<'a>( p: &mut Prettier<'a>, stmts: &[Statement<'a>], directives: Option<&[Directive<'a>]>, ) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.text("{")); + let mut parts = Vec::new_in(p.allocator); + + parts.push(text!("{")); if let Some(doc) = print_block_body(p, stmts, directives, true, false) { parts.push({ - let mut parts = p.vec(); - parts.extend(p.hardline()); + let mut parts = Vec::new_in(p.allocator); + parts.extend(hardline!()); parts.push(doc); - p.indent(parts) + indent!(p, parts) }); - parts.extend(p.hardline()); + parts.extend(hardline!()); } else { let parent = p.parent_kind(); let parent_parent = p.parent_parent_kind(); @@ -42,11 +40,12 @@ pub(super) fn print_block<'a>( && !matches!(p.parent_parent_kind(), Some(AstKind::TryStatement(stmt)) if stmt.finalizer.is_some())) || matches!(p.current_kind(), AstKind::StaticBlock(_))) { - parts.extend(p.hardline()); + parts.extend(hardline!()); } } - parts.push(p.text("}")); - p.array(parts) + parts.push(text!("}")); + + array!(p, parts) } pub(super) fn print_block_body<'a>( @@ -63,7 +62,7 @@ pub(super) fn print_block_body<'a>( return None; } - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if has_directives { if let Some(directives) = directives { @@ -80,5 +79,5 @@ pub(super) fn print_block_body<'a>( )); } - Some(p.array(parts)) + Some(array!(p, parts)) } diff --git a/crates/oxc_prettier/src/format/call_arguments.rs b/crates/oxc_prettier/src/format/call_arguments.rs index 689a05dd0b50a..498e044abc960 100644 --- a/crates/oxc_prettier/src/format/call_arguments.rs +++ b/crates/oxc_prettier/src/format/call_arguments.rs @@ -4,12 +4,14 @@ use oxc_span::{GetSpan, Span}; use oxc_syntax::operator::UnaryOperator; use crate::{ + array, break_parent, conditional_group, format::{ call_expression::{is_commons_js_or_amd_call, CallExpressionLike}, misc, }, - ir::{Doc, DocBuilder}, - p_vec, + group, hardline, if_break, indent, + ir::Doc, + line, softline, text, utils::will_break, Format, Prettier, }; @@ -18,8 +20,8 @@ pub fn print_call_arguments<'a>( p: &mut Prettier<'a>, expression: &CallExpressionLike<'a, '_>, ) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.text("(")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("(")); let callee = expression.callee(); let arguments = expression.arguments(); @@ -31,13 +33,14 @@ pub fn print_call_arguments<'a>( if arguments.is_empty() { parts.extend(p.print_inner_comment(Span::new(callee.span().end, expression.span().end))); - parts.push(p.text(")")); - return p.array(parts); + parts.push(text!(")")); + + return array!(p, parts); } #[allow(clippy::cast_sign_loss)] let get_printed_arguments = |p: &mut Prettier<'a>, skip_index: isize| { - let mut printed_arguments = p.vec(); + let mut printed_arguments = Vec::new_in(p.allocator); let mut len = arguments.len(); let arguments: Box> = match skip_index { _ if skip_index > 0 => { @@ -55,36 +58,38 @@ pub fn print_call_arguments<'a>( for (i, element) in arguments { let doc = element.format(p); - let mut arg = p.vec(); + let mut arg = Vec::new_in(p.allocator); arg.push(doc); if i < len - 1 { - arg.push(p.text(",")); + arg.push(text!(",")); if p.is_next_line_empty(element.span()) { - arg.extend(p.hardline()); - arg.extend(p.hardline()); + arg.extend(hardline!()); + arg.extend(hardline!()); } else { - arg.push(p.line()); + arg.push(line!()); } } - printed_arguments.push(p.array(arg)); + printed_arguments.push(array!(p, arg)); } printed_arguments }; let all_args_broken_out = |p: &mut Prettier<'a>| { - let mut parts = p.vec(); - parts.push(p.text("(")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("(")); let arguments_doc = get_printed_arguments(p, 0); - parts.push(p.indent(p_vec!( + parts.push(indent!( p, - p.line(), - p.array(arguments_doc), - if p.should_print_all_comma() { p.text(",") } else { p.text("") } - ))); - parts.push(p.line()); - parts.push(p.text(")")); - p.group_with_opts(p.array(parts), true, None) + [ + line!(), + array!(p, arguments_doc), + if p.should_print_all_comma() { text!(",") } else { text!("") } + ] + )); + parts.push(line!()); + parts.push(text!(")")); + group!(p, parts, true, None) }; if should_expand_first_arg(arguments) { @@ -96,22 +101,28 @@ pub fn print_call_arguments<'a>( let last_doc = get_printed_arguments(p, 1).pop().unwrap(); let all_args_broken_out_doc = all_args_broken_out(p); - return p.array(p_vec!( + return array!( p, - p.break_parent(), - p.conditional_group( - p.array(p_vec!( + [ + break_parent!(), + conditional_group!( p, - p.text("("), - p.group_with_opts(first_doc, true, None), - p.text(", "), - last_doc, - p.text(")"), - )), - vec![all_args_broken_out_doc], - None - ) - )); + [ + array!( + p, + [ + text!("("), + group!(p, [first_doc], true, None), + text!(", "), + last_doc, + text!(")"), + ] + ), + all_args_broken_out_doc + ] + ) + ] + ); } } @@ -122,8 +133,8 @@ pub fn print_call_arguments<'a>( } if !printed_arguments.is_empty() { - printed_arguments.push(p.text(",")); - printed_arguments.push(p.line()); + printed_arguments.push(text!(",")); + printed_arguments.push(line!()); } let get_last_doc = |p: &mut Prettier<'a>| { @@ -137,60 +148,68 @@ pub fn print_call_arguments<'a>( if will_break(&mut last_doc) { let all_args_broken_out_doc = all_args_broken_out(p); - return p.array(p_vec!( + return array!( p, - p.break_parent(), - p.conditional_group( - p.array(p_vec!( + [ + break_parent!(), + conditional_group!( p, - p.text("("), - p.array(printed_arguments), - p.group_with_opts(last_doc, true, None), - p.text(")") - )), - vec![all_args_broken_out_doc], - None - ), - )); + [ + array!( + p, + [ + text!("("), + array!(p, printed_arguments), + group!(p, [last_doc], true, None), + text!(")") + ] + ), + all_args_broken_out_doc + ] + ), + ] + ); } let printed_arguments2 = get_printed_arguments(p, -1); let last_doc2 = get_last_doc(p); let all_args_broken_out_doc = all_args_broken_out(p); - return p.conditional_group( - p.array(p_vec!(p, p.text("("), p.array(printed_arguments), last_doc, p.text(")"))), - vec![ - p.array(p_vec!( + return conditional_group!( + p, + [ + array!(p, [text!("("), array!(p, printed_arguments), last_doc, text!(")")]), + array!( p, - p.text("("), - p.array(printed_arguments2), - p.group_with_opts(last_doc2, true, None), - p.text(")") - )), + [ + text!("("), + array!(p, printed_arguments2), + group!(p, [last_doc2], true, None), + text!(")") + ] + ), all_args_broken_out_doc, - ], - None, + ] ); } let mut printed_arguments = get_printed_arguments(p, 0); if should_break { - printed_arguments.insert(0, p.softline()); - parts.push(p.indent(printed_arguments)); - parts.push(p.if_break(p.text(","), p.text(""), None)); - parts.push(p.softline()); + printed_arguments.insert(0, softline!()); + parts.push(indent!(p, printed_arguments)); + parts.push(if_break!(p, text!(","))); + parts.push(softline!()); } else { parts.extend(printed_arguments); } - parts.push(p.text(")")); + parts.push(text!(")")); let should_break = should_break && arguments.iter().any(|arg| { misc::has_new_line_in_range(p.source_text, arg.span().start, arg.span().end) }); - p.group_with_opts(p.array(parts), should_break, None) + group!(p, parts, should_break, None) } /// * Reference diff --git a/crates/oxc_prettier/src/format/call_expression.rs b/crates/oxc_prettier/src/format/call_expression.rs index 17cfb46c12163..0b53d0d2afc61 100644 --- a/crates/oxc_prettier/src/format/call_expression.rs +++ b/crates/oxc_prettier/src/format/call_expression.rs @@ -2,11 +2,7 @@ use oxc_allocator::Vec; use oxc_ast::ast::*; use oxc_span::{GetSpan, Span}; -use crate::{ - format::call_arguments::print_call_arguments, - ir::{Doc, DocBuilder}, - Format, Prettier, -}; +use crate::{format::call_arguments::print_call_arguments, group, ir::Doc, text, Format, Prettier}; pub(super) enum CallExpressionLike<'a, 'b> { CallExpression(&'b CallExpression<'a>), @@ -62,10 +58,10 @@ pub(super) fn print_call_expression<'a>( p: &mut Prettier<'a>, expression: &CallExpressionLike<'a, '_>, ) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if expression.is_new() { - parts.push(p.text("new ")); + parts.push(text!("new ")); }; parts.push(expression.callee().format(p)); @@ -75,12 +71,12 @@ pub(super) fn print_call_expression<'a>( } if expression.optional() { - parts.push(p.text("?.")); + parts.push(text!("?.")); } parts.push(print_call_arguments(p, expression)); - p.group(p.array(parts)) + group!(p, parts) } /// diff --git a/crates/oxc_prettier/src/format/class.rs b/crates/oxc_prettier/src/format/class.rs index 26a73219dc056..1182b5e0cf8b8 100644 --- a/crates/oxc_prettier/src/format/class.rs +++ b/crates/oxc_prettier/src/format/class.rs @@ -1,18 +1,21 @@ use std::ops::Add; +use oxc_allocator::Vec; use oxc_ast::ast::*; use oxc_span::GetSpan; use crate::{ - format::{assignment, assignment::AssignmentLikeNode, Separator}, - ir::{Doc, DocBuilder}, - p_vec, Format, Prettier, + array, + format::{assignment, assignment::AssignmentLikeNode, JoinSeparator}, + group, hardline, if_break, indent, + ir::Doc, + join, line, softline, text, Format, Prettier, }; pub(super) fn print_class<'a>(p: &mut Prettier<'a>, class: &Class<'a>) -> Doc<'a> { - let mut parts = p.vec(); - let mut heritage_clauses_parts = p.vec(); - let mut group_parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); + let mut heritage_clauses_parts = Vec::new_in(p.allocator); + let mut group_parts = Vec::new_in(p.allocator); // Keep old behaviour of extends in same line // If there is only on extends and there are not comments @@ -21,41 +24,41 @@ pub(super) fn print_class<'a>(p: &mut Prettier<'a>, class: &Class<'a>) -> Doc<'a let group_mode = class.implements.as_ref().is_some_and(|v| !v.is_empty()); if let Some(super_class) = &class.super_class { - let mut extend_parts = p.vec(); + let mut extend_parts = Vec::new_in(p.allocator); - extend_parts.push(p.text("extends ")); + extend_parts.push(text!("extends ")); extend_parts.push(super_class.format(p)); if let Some(super_type_parameters) = &class.super_type_parameters { extend_parts.push(super_type_parameters.format(p)); } - extend_parts.push(p.space()); + extend_parts.push(text!(" ")); if group_mode { - heritage_clauses_parts.push(p.softline()); + heritage_clauses_parts.push(softline!()); } - heritage_clauses_parts.push(p.array(extend_parts)); + heritage_clauses_parts.push(array!(p, extend_parts)); } heritage_clauses_parts.push(print_heritage_clauses_implements(p, class)); for decorator in &class.decorators { - parts.push(p.text("@")); + parts.push(text!("@")); parts.push(decorator.expression.format(p)); - parts.extend(p.hardline()); + parts.extend(hardline!()); } if class.declare { - parts.push(p.text("declare ")); + parts.push(text!("declare ")); } if class.r#abstract { - parts.push(p.text("abstract ")); + parts.push(text!("abstract ")); } - parts.push(p.text("class ")); + parts.push(text!("class ")); if let Some(id) = &class.id { group_parts.push(id.format(p)); @@ -66,35 +69,31 @@ pub(super) fn print_class<'a>(p: &mut Prettier<'a>, class: &Class<'a>) -> Doc<'a } if class.id.is_some() || class.type_parameters.is_some() { - group_parts.push(p.space()); + group_parts.push(text!(" ")); } if group_mode { let printend_parts_group = if should_indent_only_heritage_clauses(class) { - p.array(p_vec!( - p, - p.array(group_parts), - p.indent(p_vec!(p, p.array(heritage_clauses_parts))) - )) + array!(p, [array!(p, group_parts), indent!(p, heritage_clauses_parts)]) } else { - p.indent(p_vec!(p, p.array(group_parts), p.group(p.array(heritage_clauses_parts)))) + indent!(p, [array!(p, group_parts), group!(p, heritage_clauses_parts)]) }; parts.push(printend_parts_group); if !class.body.body.is_empty() && has_multiple_heritage(class) { - parts.extend(p.hardline()); + parts.extend(hardline!()); } } else { - parts.push(p.array(p_vec!(p, p.array(group_parts), p.array(heritage_clauses_parts)))); + parts.push(array!(p, [array!(p, group_parts), array!(p, heritage_clauses_parts)])); } parts.push(class.body.format(p)); - p.array(parts) + array!(p, parts) } pub(super) fn print_class_body<'a>(p: &mut Prettier<'a>, class_body: &ClassBody<'a>) -> Doc<'a> { - let mut parts_inner = p.vec(); + let mut parts_inner = Vec::new_in(p.allocator); for (i, node) in class_body.body.iter().enumerate() { parts_inner.push(node.format(p)); @@ -103,36 +102,36 @@ pub(super) fn print_class_body<'a>(p: &mut Prettier<'a>, class_body: &ClassBody< && node.is_property() && should_print_semicolon_after_class_property(node, class_body.body.get(i + 1)) { - parts_inner.push(p.text(";")); + parts_inner.push(text!(";")); } if i < class_body.body.len() - 1 { - parts_inner.extend(p.hardline()); + parts_inner.extend(hardline!()); if p.is_next_line_empty(node.span()) { - parts_inner.extend(p.hardline()); + parts_inner.extend(hardline!()); } } } // TODO: if there are any dangling comments, print them - let mut parts = p.vec(); - parts.push(p.text("{")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("{")); if !parts_inner.is_empty() { let indent = { - let mut parts = p.vec(); - parts.extend(p.hardline()); - parts.push(p.array(parts_inner)); - p.indent(parts) + let mut parts = Vec::new_in(p.allocator); + parts.extend(hardline!()); + parts.push(array!(p, parts_inner)); + indent!(p, parts) }; - parts.push(p.array(p_vec!(p, indent))); - parts.extend(p.hardline()); + parts.push(array!(p, [indent])); + parts.extend(hardline!()); } - parts.push(p.text("}")); + parts.push(text!("}")); - p.array(parts) + array!(p, parts) } #[derive(Debug)] @@ -227,10 +226,8 @@ impl<'a> ClassMemberish<'a, '_> { fn format_accessibility(&self, p: &mut Prettier<'a>) -> Option> { match self { - ClassMemberish::AccessorProperty(def) => def.accessibility.map(|v| p.text(v.as_str())), - ClassMemberish::PropertyDefinition(def) => { - def.accessibility.map(|v| p.text(v.as_str())) - } + ClassMemberish::AccessorProperty(def) => def.accessibility.map(|v| text!(v.as_str())), + ClassMemberish::PropertyDefinition(def) => def.accessibility.map(|v| text!(v.as_str())), } } @@ -250,51 +247,51 @@ pub(super) fn print_class_property<'a>( p: &mut Prettier<'a>, node: &ClassMemberish<'a, '_>, ) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if let Some(decarators) = node.decorators() { for decorator in decarators { - parts.push(p.text("@")); + parts.push(text!("@")); parts.push(decorator.expression.format(p)); - parts.extend(p.hardline()); + parts.extend(hardline!()); } } if let Some(accessibility) = node.format_accessibility(p) { parts.push(accessibility); - parts.push(p.space()); + parts.push(text!(" ")); } if node.is_declare() { - parts.push(p.text("declare ")); + parts.push(text!("declare ")); } if node.is_static() { - parts.push(p.text("static ")); + parts.push(text!("static ")); } if node.is_abstract() { - parts.push(p.text("abstract ")); + parts.push(text!("abstract ")); } if node.is_override() { - parts.push(p.text("override ")); + parts.push(text!("override ")); } if node.is_readonly() { - parts.push(p.text("readonly ")); + parts.push(text!("readonly ")); } parts.push(node.format_key(p)); if node.is_optional() { - parts.push(p.text("?")); + parts.push(text!("?")); } else if node.is_definite() { - parts.push(p.text("!")); + parts.push(text!("!")); } if let Some(type_annotation) = node.format_type_annotation(p) { - parts.push(p.text(": ")); + parts.push(text!(": ")); parts.push(type_annotation); } @@ -304,13 +301,13 @@ pub(super) fn print_class_property<'a>( ClassMemberish::AccessorProperty(v) => AssignmentLikeNode::AccessorProperty(v), }; let mut result = - assignment::print_assignment(p, node, p.array(parts), p.text(" ="), right_expr); + assignment::print_assignment(p, node, array!(p, parts), text!(" ="), right_expr); if p.options.semi { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(result); - parts.push(p.text(";")); - result = p.array(parts); + parts.push(text!(";")); + result = array!(p, parts); } result } @@ -379,45 +376,37 @@ fn should_print_semicolon_after_class_property<'a>( * @link */ fn print_heritage_clauses_implements<'a>(p: &mut Prettier<'a>, class: &Class<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if class.implements.is_none() { - return p.array(parts); + return array!(p, parts); } let implements = class.implements.as_ref().unwrap(); if implements.len() == 0 { - return p.array(parts); + return array!(p, parts); } if should_indent_only_heritage_clauses(class) { - parts.push(p.if_break( - p.line(), - p.text(""), - None, // ToDo - how to attach group id - )); + parts.push(if_break!(p, line!())); } else if class.super_class.is_some() { - parts.extend(p.hardline()); + parts.extend(hardline!()); } else { - parts.push(p.softline()); + parts.push(softline!()); } - parts.push(p.text("implements ")); + parts.push(text!("implements ")); - let implements_docs = implements.iter().map(|v| v.format(p)).collect(); + let implements_docs = implements.iter().map(|v| v.format(p)).collect::>(); - parts.push(p.indent(p_vec!( + parts.push(indent!( p, - p.group(p.array(p_vec!( - p, - p.softline(), - p.array(p.join(Separator::CommaLine, implements_docs)), - ))) - ))); - parts.push(p.space()); - - p.group(p.array(parts)) + [group!(p, [softline!(), join!(p, JoinSeparator::CommaLine, implements_docs),])] + )); + parts.push(text!(" ")); + + group!(p, parts) } fn should_indent_only_heritage_clauses(class: &Class) -> bool { diff --git a/crates/oxc_prettier/src/format/function.rs b/crates/oxc_prettier/src/format/function.rs index e572384172df6..6e25884a6de9b 100644 --- a/crates/oxc_prettier/src/format/function.rs +++ b/crates/oxc_prettier/src/format/function.rs @@ -1,9 +1,9 @@ +use oxc_allocator::Vec; use oxc_ast::ast::*; use crate::{ - format::function_parameters::should_group_function_parameters, - ir::{Doc, DocBuilder}, - p_vec, Format, Prettier, + array, dynamic_text, format::function_parameters::should_group_function_parameters, group, + if_break, indent, ir::Doc, softline, text, Format, Prettier, }; pub(super) fn print_function<'a>( @@ -11,29 +11,29 @@ pub(super) fn print_function<'a>( func: &Function<'a>, property_name: Option<&'a str>, ) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if func.declare { - parts.push(p.text("declare ")); + parts.push(text!("declare ")); } if func.r#async { - parts.push(p.text("async ")); + parts.push(text!("async ")); } if let Some(name) = property_name { - parts.push(p.dynamic_text(name)); + parts.push(dynamic_text!(p, name)); } else { - parts.push(p.text("function")); + parts.push(text!("function")); if func.generator { - parts.push(p.text("*")); + parts.push(text!("*")); } - parts.push(p.text(" ")); + parts.push(text!(" ")); } if let Some(id) = &func.id { - parts.push(p.dynamic_text(id.name.as_str())); + parts.push(dynamic_text!(p, id.name.as_str())); } if let Some(type_params) = &func.type_parameters { @@ -41,21 +41,24 @@ pub(super) fn print_function<'a>( } // Prettier has `returnTypeDoc` to group together, write this for keep same with prettier. let params_doc = func.params.format(p); - parts.push(p.group({ - if should_group_function_parameters(func) { - p.group(params_doc) - } else { - params_doc - } - })); + parts.push(group!( + p, + [{ + if should_group_function_parameters(func) { + group!(p, [params_doc]) + } else { + params_doc + } + }] + )); if let Some(return_type) = &func.return_type { - parts.push(p.text(": ")); + parts.push(text!(": ")); parts.push(return_type.type_annotation.format(p)); } if let Some(body) = &func.body { - parts.push(p.space()); + parts.push(text!(" ")); parts.push(body.format(p)); } if func.is_ts_declare_function() || func.body.is_none() { @@ -64,84 +67,84 @@ pub(super) fn print_function<'a>( } } - p.array(parts) + array!(p, parts) } pub(super) fn print_method<'a>(p: &mut Prettier<'a>, method: &MethodDefinition<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if let Some(accessibility) = &method.accessibility { - parts.push(p.text(accessibility.as_str())); - parts.push(p.space()); + parts.push(text!(accessibility.as_str())); + parts.push(text!(" ")); } if method.r#static { - parts.push(p.text("static ")); + parts.push(text!("static ")); } if matches!(method.r#type, MethodDefinitionType::TSAbstractMethodDefinition) { - parts.push(p.text("abstract ")); + parts.push(text!("abstract ")); } if method.r#override { - parts.push(p.text("override ")); + parts.push(text!("override ")); } match method.kind { MethodDefinitionKind::Constructor | MethodDefinitionKind::Method => {} MethodDefinitionKind::Get => { - parts.push(p.text("get ")); + parts.push(text!("get ")); } MethodDefinitionKind::Set => { - parts.push(p.text("set ")); + parts.push(text!("set ")); } } if method.value.r#async { - parts.push(p.text("async ")); + parts.push(text!("async ")); } if method.value.generator { - parts.push(p.text("*")); + parts.push(text!("*")); } parts.push(method.key.format(p)); if method.optional { - parts.push(p.text("?")); + parts.push(text!("?")); } parts.push(print_method_value(p, &method.value)); - p.array(parts) + array!(p, parts) } fn print_method_value<'a>(p: &mut Prettier<'a>, function: &Function<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); let parameters_doc = function.params.format(p); let should_group_parameters = should_group_function_parameters(function); let parameters_doc = - if should_group_parameters { p.group(parameters_doc) } else { parameters_doc }; + if should_group_parameters { group!(p, [parameters_doc]) } else { parameters_doc }; if let Some(type_parameters) = &function.type_parameters { parts.push(type_parameters.format(p)); } - parts.push(p.group(parameters_doc)); + parts.push(group!(p, [parameters_doc])); if let Some(ret_typ) = &function.return_type { - parts.push(p.text(": ")); + parts.push(text!(": ")); parts.push(ret_typ.type_annotation.format(p)); } if let Some(body) = &function.body { - parts.push(p.space()); + parts.push(text!(" ")); parts.push(body.format(p)); } else if p.options.semi { - parts.push(p.text(";")); + parts.push(text!(";")); } - p.array(parts) + array!(p, parts) } pub(super) fn print_return_or_throw_argument<'a>( @@ -149,22 +152,24 @@ pub(super) fn print_return_or_throw_argument<'a>( argument: Option<&Expression<'a>>, is_return: bool, ) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); - parts.push(p.text(if is_return { "return" } else { "throw" })); + parts.push(text!(if is_return { "return" } else { "throw" })); if let Some(argument) = argument { - parts.push(p.space()); + parts.push(text!(" ")); parts.push( if argument.is_binaryish() || matches!(argument, Expression::SequenceExpression(_)) { let argument_doc = argument.format(p); - p.group(p.array(p_vec!( + group!( p, - p.if_break(p.text("("), p.text(""), None), - p.indent(p_vec!(p, p.softline(), argument_doc)), - p.softline(), - p.if_break(p.text(")"), p.text(""), None), - ))) + [ + if_break!(p, text!("(")), + indent!(p, [softline!(), argument_doc]), + softline!(), + if_break!(p, text!(")")), + ] + ) } else { argument.format(p) }, @@ -174,5 +179,6 @@ pub(super) fn print_return_or_throw_argument<'a>( if let Some(semi) = p.semi() { parts.push(semi); } - p.array(parts) + + array!(p, parts) } diff --git a/crates/oxc_prettier/src/format/function_parameters.rs b/crates/oxc_prettier/src/format/function_parameters.rs index a82805a78739f..5b969dab6acd1 100644 --- a/crates/oxc_prettier/src/format/function_parameters.rs +++ b/crates/oxc_prettier/src/format/function_parameters.rs @@ -1,9 +1,9 @@ +use oxc_allocator::Vec; use oxc_ast::{ast::*, AstKind}; use crate::{ - comments::CommentFlags, - ir::{Doc, DocBuilder}, - p_vec, Format, Prettier, + array, comments::CommentFlags, group, hardline, if_break, indent, ir::Doc, line, softline, + text, Format, Prettier, }; pub(super) fn should_hug_the_only_function_parameter( @@ -61,17 +61,17 @@ pub(super) fn print_function_parameters<'a>( p: &mut Prettier<'a>, params: &FormalParameters<'a>, ) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); let is_arrow_function = matches!(p.parent_kind(), AstKind::ArrowFunctionExpression(_)); let need_parens = !is_arrow_function || p.options.arrow_parens.is_always() || params.items.len() != 1; if need_parens { - parts.push(p.text("(")); + parts.push(text!("(")); } let should_hug_the_only_function_parameter = should_hug_the_only_function_parameter(p, params); - let mut printed = p.vec(); + let mut printed = Vec::new_in(p.allocator); let len = params.items.len(); let has_rest = params.rest.is_some(); @@ -80,15 +80,15 @@ pub(super) fn print_function_parameters<'a>( parts.push(this_param.format(p)); if params.items.len() > 0 { - printed.push(p.text(",")); + printed.push(text!(",")); if should_hug_the_only_function_parameter { - printed.push(p.space()); + printed.push(text!(" ")); } else if p.is_next_line_empty(this_param.span) { - printed.extend(p.hardline()); - printed.extend(p.hardline()); + printed.extend(hardline!()); + printed.extend(hardline!()); } else { - printed.push(p.line()); + printed.push(line!()); } } } @@ -96,30 +96,30 @@ pub(super) fn print_function_parameters<'a>( for (i, param) in params.items.iter().enumerate() { if let Some(accessibility) = ¶m.accessibility { - printed.push(p.text(accessibility.as_str())); - printed.push(p.space()); + printed.push(text!(accessibility.as_str())); + printed.push(text!(" ")); } if param.r#override { - printed.push(p.text("override ")); + printed.push(text!("override ")); } if param.readonly { - printed.push(p.text("readonly ")); + printed.push(text!("readonly ")); } printed.push(param.format(p)); if i == len - 1 && !has_rest { break; } - printed.push(p.text(",")); + printed.push(text!(",")); if should_hug_the_only_function_parameter { - printed.push(p.space()); + printed.push(text!(" ")); } else if p.is_next_line_empty(param.span) { - printed.extend(p.hardline()); - printed.extend(p.hardline()); + printed.extend(hardline!()); + printed.extend(hardline!()); } else { - printed.push(p.line()); + printed.push(line!()); } } if let Some(rest) = ¶ms.rest { @@ -127,30 +127,30 @@ pub(super) fn print_function_parameters<'a>( } if should_hug_the_only_function_parameter { - let mut parts = p.vec(); - parts.push(p.text("(")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("(")); parts.extend(printed); - parts.push(p.text(")")); - return p.array(parts); + parts.push(text!(")")); + return array!(p, parts); } - let mut indented = p.vec(); - indented.push(p.softline()); + let mut indented = Vec::new_in(p.allocator); + indented.push(softline!()); indented.extend(printed); - let indented = p.indent(p_vec!(p, p.array(indented))); + let indented = indent!(p, indented); parts.push(indented); let skip_dangling_comma = params.rest.is_some() || matches!(p.parent_kind(), AstKind::Function(func) if func.this_param.is_some()); - parts.push(p.if_break(p.text(if skip_dangling_comma { "" } else { "," }), p.text(""), None)); - parts.push(p.softline()); + parts.push(if_break!(p, text!(if skip_dangling_comma { "" } else { "," }))); + parts.push(softline!()); if need_parens { - parts.push(p.text(")")); + parts.push(text!(")")); } if p.args.expand_first_arg { - p.array(parts) + array!(p, parts) } else { - p.group(p.array(parts)) + group!(p, parts) } } diff --git a/crates/oxc_prettier/src/format/misc.rs b/crates/oxc_prettier/src/format/misc.rs index e65155392608e..37e47552c0938 100644 --- a/crates/oxc_prettier/src/format/misc.rs +++ b/crates/oxc_prettier/src/format/misc.rs @@ -1,7 +1,7 @@ use oxc_ast::{ast::*, AstKind}; use oxc_span::Span; -use crate::{ir::Doc, p_vec, DocBuilder, Prettier}; +use crate::{array, indent, ir::Doc, line, text, Prettier}; pub(super) fn adjust_clause<'a>( p: &Prettier<'a>, @@ -10,14 +10,14 @@ pub(super) fn adjust_clause<'a>( force_space: bool, ) -> Doc<'a> { if matches!(node, Statement::EmptyStatement(_)) { - return p.text(";"); + return text!(";"); } if matches!(node, Statement::BlockStatement(_)) || force_space { - return p.array(p_vec!(p, p.space(), clause)); + return array!(p, [text!(" "), clause]); } - p.indent(p_vec!(p, p.line(), clause)) + indent!(p, [line!(), clause]) } pub(super) fn has_new_line_in_range(text: &str, start: u32, end: u32) -> bool { diff --git a/crates/oxc_prettier/src/format/mod.rs b/crates/oxc_prettier/src/format/mod.rs index e135d7f8f3dfa..efe70237c1032 100644 --- a/crates/oxc_prettier/src/format/mod.rs +++ b/crates/oxc_prettier/src/format/mod.rs @@ -31,9 +31,11 @@ use oxc_span::GetSpan; use oxc_syntax::identifier::{is_identifier_name, is_line_terminator}; use crate::{ + array, dynamic_text, format::{array::Array, object::ObjectLike, template_literal::TemplateLiteralPrinter}, - ir::{Doc, DocBuilder, Separator}, - p_vec, wrap, Prettier, + group, hardline, indent, + ir::{Doc, JoinSeparator}, + join, line, softline, text, wrap, Prettier, }; pub trait Format<'a> { @@ -53,7 +55,7 @@ where impl<'a> Format<'a> for Program<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, Program, { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if let Some(hashbang) = &self.hashbang { parts.push(hashbang.format(p)); @@ -69,39 +71,38 @@ impl<'a> Format<'a> for Program<'a> { parts.push(doc); } - p.array(parts) + array!(p, parts) }) } } impl<'a> Format<'a> for Hashbang<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.dynamic_text(self.span.source_text(p.source_text))); - parts.extend(p.hardline()); + let mut parts = Vec::new_in(p.allocator); + parts.push(dynamic_text!(p, self.span.source_text(p.source_text))); + parts.extend(hardline!()); // Preserve original newline if let Some(c) = p.source_text[self.span.end as usize..].chars().nth(1) { if is_line_terminator(c) { - parts.extend(p.hardline()); + parts.extend(hardline!()); } } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for Directive<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.dynamic_text(string::print_string( + let mut parts = Vec::new_in(p.allocator); + parts.push(dynamic_text!( p, - self.directive.as_str(), - p.options.single_quote, - ))); + string::print_string(p, self.directive.as_str(), p.options.single_quote,) + )); if let Some(semi) = p.semi() { parts.push(semi); } - parts.extend(p.hardline()); - p.array(parts) + parts.extend(hardline!()); + array!(p, parts) } } @@ -135,62 +136,63 @@ impl<'a> Format<'a> for Statement<'a> { impl<'a> Format<'a> for ExpressionStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, ExpressionStatement, { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.expression.format(p)); if let Some(semi) = p.semi() { parts.push(semi); } - p.array(parts) + array!(p, parts) }) } } impl<'a> Format<'a> for EmptyStatement { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("") + text!("") } } impl<'a> Format<'a> for IfStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, IfStatement, { - let mut parts = p.vec(); + 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 = p.group(p.array(p_vec!( + let opening = group!( p, - p.text("if ("), - p.group(p.array(p_vec!( - p, - p.indent(p_vec!(p, p.softline(), test_doc)), - p.softline(), - ))), - p.text(")"), - consequent - ))); + [ + text!("if ("), + group!(p, [indent!(p, [softline!(), test_doc]), softline!(),]), + text!(")"), + consequent + ] + ); 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(p.space()); + parts.push(text!(" ")); } else { - parts.extend(p.hardline()); + parts.extend(hardline!()); } - parts.push(p.text("else")); + parts.push(text!("else")); let alternate_doc = alternate.format(p); - parts.push(p.group(misc::adjust_clause( + parts.push(group!( p, - alternate, - alternate_doc, - matches!(alternate, Statement::IfStatement(_)), - ))); + [misc::adjust_clause( + p, + alternate, + alternate_doc, + matches!(alternate, Statement::IfStatement(_)), + )] + )); } - p.array(parts) + array!(p, parts) }) } } @@ -208,35 +210,29 @@ impl<'a> Format<'a> for ForStatement<'a> { let body = misc::adjust_clause(p, &self.body, body, false); if self.init.is_none() && self.test.is_none() && self.update.is_none() { - return p.group(p.array(p_vec!(p, p.text("for (;;)"), body))); + return group!(p, [text!("for (;;)"), body]); } let parts_head = { - let mut parts_head = p.vec(); - parts_head.push(p.softline()); + 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(p.text(";")); - parts_head.push(p.line()); + parts_head.push(text!(";")); + parts_head.push(line!()); if let Some(init) = &self.test { parts_head.push(init.format(p)); } - parts_head.push(p.text(";")); - parts_head.push(p.line()); + parts_head.push(text!(";")); + parts_head.push(line!()); if let Some(init) = &self.update { parts_head.push(init.format(p)); } - p.indent(parts_head) + indent!(p, parts_head) }; - p.group(p.array(p_vec!( - p, - p.text("for ("), - p.group(p.array(p_vec!(p, parts_head, p.softline()))), - p.text(")"), - body, - ))) + group!(p, [text!("for ("), group!(p, [parts_head, softline!()]), text!(")"), body,]) }) } } @@ -253,15 +249,15 @@ impl<'a> Format<'a> for ForStatementInit<'a> { impl<'a> Format<'a> for ForInStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, ForInStatement, { - let mut parts = p.vec(); - parts.push(p.text("for (")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("for (")); parts.push(self.left.format(p)); - parts.push(p.text(" in ")); + parts.push(text!(" in ")); parts.push(self.right.format(p)); - parts.push(p.text(")")); + parts.push(text!(")")); let body = self.body.format(p); parts.push(misc::adjust_clause(p, &self.body, body, false)); - p.group(p.array(parts)) + group!(p, parts) }) } } @@ -269,19 +265,19 @@ impl<'a> Format<'a> for ForInStatement<'a> { impl<'a> Format<'a> for ForOfStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, ForOfStatement, { - let mut parts = p.vec(); - parts.push(p.text("for")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("for")); if self.r#await { - parts.push(p.text(" await")); + parts.push(text!(" await")); } - parts.push(p.text(" (")); + parts.push(text!(" (")); parts.push(self.left.format(p)); - parts.push(p.text(" of ")); + parts.push(text!(" of ")); parts.push(self.right.format(p)); - parts.push(p.text(")")); + parts.push(text!(")")); let body = self.body.format(p); parts.push(misc::adjust_clause(p, &self.body, body, false)); - p.group(p.array(parts)) + group!(p, parts) }) } } @@ -298,21 +294,17 @@ impl<'a> Format<'a> for ForStatementLeft<'a> { impl<'a> Format<'a> for WhileStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, WhileStatement, { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); - parts.push(p.text("while (")); + parts.push(text!("while (")); let test_doc = self.test.format(p); - parts.push(p.group(p.array(p_vec!( - p, - p.indent(p_vec!(p, p.softline(), test_doc)), - p.softline(), - )))); - parts.push(p.text(")")); + parts.push(group!(p, [indent!(p, [softline!(), test_doc]), softline!(),])); + parts.push(text!(")")); let body = self.body.format(p); parts.push(misc::adjust_clause(p, &self.body, body, false)); - p.group(p.array(parts)) + group!(p, parts) }) } } @@ -320,121 +312,117 @@ impl<'a> Format<'a> for WhileStatement<'a> { impl<'a> Format<'a> for DoWhileStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, DoWhileStatement, { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); let clause = self.body.format(p); let clause = misc::adjust_clause(p, &self.body, clause, false); - let do_body = p.group(p.array(p_vec!(p, p.text("do"), clause))); + let do_body = group!(p, [text!("do"), clause]); parts.push(do_body); if matches!(self.body, Statement::BlockStatement(_)) { - parts.push(p.space()); + parts.push(text!(" ")); } else { - parts.extend(p.hardline()); + parts.extend(hardline!()); } - parts.push(p.text("while (")); + parts.push(text!("while (")); let test_doc = self.test.format(p); - parts.push(p.group(p.array(p_vec!( - p, - p.indent(p_vec!(p, p.softline(), test_doc)), - p.softline() - )))); - parts.push(p.text(")")); + parts.push(group!(p, [indent!(p, [softline!(), test_doc]), softline!()])); + parts.push(text!(")")); if let Some(semi) = p.semi() { parts.push(semi); } - p.array(parts) + array!(p, parts) }) } } impl<'a> Format<'a> for ContinueStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.text("continue")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("continue")); if let Some(label) = &self.label { - parts.push(p.space()); + parts.push(text!(" ")); parts.push(label.format(p)); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for BreakStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.text("break")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("break")); if let Some(label) = &self.label { - parts.push(p.space()); + parts.push(text!(" ")); parts.push(label.format(p)); } if p.options.semi { - parts.push(p.text(";")); + parts.push(text!(";")); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for SwitchStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, SwitchStatement, { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); - let mut header_parts = p.vec(); + let mut header_parts = Vec::new_in(p.allocator); - header_parts.push(p.text("switch (")); + header_parts.push(text!("switch (")); let discriminant_doc = self.discriminant.format(p); - header_parts.push(p.indent(p_vec!(p, p.softline(), discriminant_doc))); + header_parts.push(indent!(p, [softline!(), discriminant_doc])); - header_parts.push(p.softline()); - header_parts.push(p.text(")")); + header_parts.push(softline!()); + header_parts.push(text!(")")); - parts.push(p.group(p.array(header_parts))); + parts.push(group!(p, header_parts)); - parts.push(p.text(" {")); + parts.push(text!(" {")); - let mut cases_parts = p.vec(); + let mut cases_parts = Vec::new_in(p.allocator); let len = self.cases.len(); for (i, case) in self.cases.iter().enumerate() { cases_parts.push({ - let mut parts = p.vec(); - parts.extend(p.hardline()); + let mut parts = Vec::new_in(p.allocator); + parts.extend(hardline!()); parts.push(case.format(p)); - p.indent(parts) + indent!(p, parts) }); if i != len - 1 && p.is_next_line_empty(case.span) { - cases_parts.extend(p.hardline()); + cases_parts.extend(hardline!()); } } parts.extend(cases_parts); - parts.extend(p.hardline()); - parts.push(p.text("}")); + parts.extend(hardline!()); + parts.push(text!("}")); - p.array(parts) + array!(p, parts) }) } } impl<'a> Format<'a> for SwitchCase<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if let Some(test) = &self.test { - parts.push(p.text("case ")); + parts.push(text!("case ")); parts.push(test.format(p)); - parts.push(p.text(":")); + parts.push(text!(":")); } else { - parts.push(p.text("default:")); + parts.push(text!("default:")); } let consequent: Vec<_> = Vec::from_iter_in( @@ -445,21 +433,21 @@ impl<'a> Format<'a> for SwitchCase<'a> { let is_only_one_block_statement = len == 1 && matches!(self.consequent[0], Statement::BlockStatement(_)); - let mut consequent_parts = p.vec(); + 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.extend(p.hardline()); + consequent_parts.extend(hardline!()); } } if is_only_one_block_statement { - consequent_parts.push(p.space()); + consequent_parts.push(text!(" ")); } else { - consequent_parts.extend(p.hardline()); + consequent_parts.extend(hardline!()); } consequent_parts.push(stmt.format(p)); } @@ -468,11 +456,11 @@ impl<'a> Format<'a> for SwitchCase<'a> { if is_only_one_block_statement { parts.extend(consequent_parts); } else { - parts.push(p.indent(p_vec!(p, p.group(p.array(consequent_parts))))); + parts.push(indent!(p, [group!(p, consequent_parts)])); } } - p.array(parts) + array!(p, parts) } } @@ -488,32 +476,32 @@ impl<'a> Format<'a> for LabeledStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { if matches!(self.body, Statement::EmptyStatement(_)) { let label_doc = self.label.format(p); - return p.array(p_vec!(p, label_doc, p.text(":;"))); + return array!(p, [label_doc, text!(":;")]); } let label_doc = self.label.format(p); let body_doc = self.body.format(p); - p.array(p_vec!(p, label_doc, p.text(": "), body_doc)) + array!(p, [label_doc, text!(": "), body_doc]) } } impl<'a> Format<'a> for TryStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, TryStatement, { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); - parts.push(p.text("try ")); + parts.push(text!("try ")); parts.push(self.block.format(p)); if let Some(handler) = &self.handler { - parts.push(p.space()); + parts.push(text!(" ")); parts.push(handler.format(p)); } if let Some(finalizer) = &self.finalizer { - parts.push(p.text(" finally ")); + parts.push(text!(" finally ")); parts.push(finalizer.format(p)); } - p.array(parts) + array!(p, parts) }) } } @@ -521,17 +509,17 @@ 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 = p.vec(); + let mut parts = Vec::new_in(p.allocator); - parts.push(p.text("catch ")); + parts.push(text!("catch ")); if let Some(param) = &self.param { - parts.push(p.text("(")); + parts.push(text!("(")); parts.push(param.pattern.format(p)); - parts.push(p.text(") ")); + parts.push(text!(") ")); } parts.push(self.body.format(p)); - p.array(parts) + array!(p, parts) }) } } @@ -546,26 +534,28 @@ impl<'a> Format<'a> for WithStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let object_doc = self.object.format(p); let body_doc = self.body.format(p); - p.group(p.array(p_vec!( + group!( p, - p.text("with ("), - object_doc, - p.text(")"), - misc::adjust_clause(p, &self.body, body_doc, false) - ))) + [ + text!("with ("), + object_doc, + text!(")"), + misc::adjust_clause(p, &self.body, body_doc, false) + ] + ) } } impl<'a> Format<'a> for DebuggerStatement { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.text("debugger")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("debugger")); if p.options.semi { - parts.push(p.text(";")); + parts.push(text!(";")); } - p.array(parts) + array!(p, parts) } } @@ -610,31 +600,31 @@ impl<'a> Format<'a> for VariableDeclaration<'a> { let kind = self.kind.as_str(); - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if self.declare { - parts.push(p.text("declare ")); + parts.push(text!("declare ")); } - parts.push(p.text(kind)); - parts.push(p.space()); + parts.push(text!(kind)); + parts.push(text!(" ")); let is_hardline = !p.parent_kind().is_iteration_statement() && self.declarations.iter().all(|decl| decl.init.is_some()); let decls_len = self.declarations.len(); parts.extend(self.declarations.iter().enumerate().map(|(i, decl)| { if decls_len > 1 { - let mut d_parts = p.vec(); + let mut d_parts = Vec::new_in(p.allocator); if i != 0 { - d_parts.push(p.text(",")); + d_parts.push(text!(",")); if is_hardline { - d_parts.extend(p.hardline()); + d_parts.extend(hardline!()); } else { - d_parts.push(p.line()); + d_parts.push(line!()); } } d_parts.push(decl.format(p)); - p.indent(d_parts) + indent!(p, d_parts) } else { decl.format(p) } @@ -646,7 +636,7 @@ impl<'a> Format<'a> for VariableDeclaration<'a> { } } - p.group(p.array(parts)) + group!(p, parts) }) } } @@ -659,27 +649,27 @@ impl<'a> Format<'a> for VariableDeclarator<'a> { impl<'a> Format<'a> for TSTypeAliasDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if self.declare { - parts.push(p.text("declare ")); + parts.push(text!("declare ")); } - parts.push(p.text("type ")); + parts.push(text!("type ")); parts.push(self.id.format(p)); if let Some(params) = &self.type_parameters { parts.push(params.format(p)); } - parts.push(p.text(" = ")); + parts.push(text!(" = ")); parts.push(self.type_annotation.format(p)); if let Some(semi) = p.semi() { parts.push(semi); } - p.array(parts) + array!(p, parts) } } @@ -730,128 +720,128 @@ impl<'a> Format<'a> for TSType<'a> { impl<'a> Format<'a> for TSAnyKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("any") + text!("any") } } impl<'a> Format<'a> for TSBigIntKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("bigint") + text!("bigint") } } impl<'a> Format<'a> for TSBooleanKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("boolean") + text!("boolean") } } impl<'a> Format<'a> for TSIntrinsicKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("intrinsic") + text!("intrinsic") } } impl<'a> Format<'a> for TSNeverKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("never") + text!("never") } } impl<'a> Format<'a> for TSNullKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("null") + text!("null") } } impl<'a> Format<'a> for TSNumberKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("number") + text!("number") } } impl<'a> Format<'a> for TSObjectKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("object") + text!("object") } } impl<'a> Format<'a> for TSStringKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("string") + text!("string") } } impl<'a> Format<'a> for TSSymbolKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("symbol") + text!("symbol") } } impl<'a> Format<'a> for TSThisType { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("this") + text!("this") } } impl<'a> Format<'a> for TSUndefinedKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("undefined") + text!("undefined") } } impl<'a> Format<'a> for TSUnknownKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("unknown") + text!("unknown") } } impl<'a> Format<'a> for TSVoidKeyword { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("void") + text!("void") } } impl<'a> Format<'a> for TSArrayType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let element_type_doc = self.element_type.format(p); - p.array(p_vec!(p, element_type_doc, p.text("[]"))) + array!(p, [element_type_doc, text!("[]")]) } } impl<'a> Format<'a> for TSConditionalType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.check_type.format(p)); - parts.push(p.text(" extends ")); + parts.push(text!(" extends ")); parts.push(self.extends_type.format(p)); - parts.push(p.text(" ? ")); + parts.push(text!(" ? ")); parts.push(self.true_type.format(p)); - parts.push(p.text(" : ")); + parts.push(text!(" : ")); parts.push(self.false_type.format(p)); - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSConstructorType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if self.r#abstract { - parts.push(p.text("abstract ")); + parts.push(text!("abstract ")); } - parts.push(p.text("new ")); + parts.push(text!("new ")); parts.push(self.params.format(p)); let type_annotation_doc = self.return_type.type_annotation.format(p); - parts.push(p.array(p_vec!(p, p.text(" => "), type_annotation_doc))); - p.array(parts) + parts.push(array!(p, [text!(" => "), type_annotation_doc])); + array!(p, parts) } } impl<'a> Format<'a> for TSFunctionType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if let Some(type_parameters) = &self.type_parameters { parts.push(type_parameters.format(p)); @@ -859,42 +849,42 @@ impl<'a> Format<'a> for TSFunctionType<'a> { parts.push(self.params.format(p)); - parts.push(p.text(" => ")); + parts.push(text!(" => ")); parts.push(self.return_type.type_annotation.format(p)); - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSThisParameter<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.text("this")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("this")); if let Some(type_annotation) = &self.type_annotation { - parts.push(p.text(": ")); + parts.push(text!(": ")); parts.push(type_annotation.type_annotation.format(p)); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSImportType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if self.is_type_of { - parts.push(p.text("typeof ")); + parts.push(text!("typeof ")); } - parts.push(p.text("import(")); + parts.push(text!("import(")); parts.push(self.parameter.format(p)); // ToDo: attributes - parts.push(p.text(")")); + parts.push(text!(")")); if let Some(qualifier) = &self.qualifier { - parts.push(p.text(".")); + parts.push(text!(".")); parts.push(qualifier.format(p)); } @@ -902,36 +892,36 @@ impl<'a> Format<'a> for TSImportType<'a> { parts.push(type_parameters.format(p)); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSIndexedAccessType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.object_type.format(p)); - parts.push(p.text("[")); + parts.push(text!("[")); parts.push(self.index_type.format(p)); - parts.push(p.text("]")); - p.array(parts) + parts.push(text!("]")); + array!(p, parts) } } impl<'a> Format<'a> for TSInferType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let type_parameter_doc = self.type_parameter.format(p); - p.array(p_vec!(p, p.text("infer "), type_parameter_doc)) + array!(p, [text!("infer "), type_parameter_doc]) } } impl<'a> Format<'a> for TSIntersectionType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); let mut add_symbol = false; for ts_type in &self.types { if add_symbol { - parts.push(p.text(" & ")); + parts.push(text!(" & ")); } else { add_symbol = true; } @@ -939,7 +929,7 @@ impl<'a> Format<'a> for TSIntersectionType<'a> { parts.push(ts_type.format(p)); } - p.array(parts) + array!(p, parts) } } @@ -960,76 +950,77 @@ impl<'a> Format<'a> for TSLiteralType<'a> { impl<'a> Format<'a> for TSMappedType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts: Vec<'_, Doc<'_>> = p.vec(); + let mut parts: Vec<'_, Doc<'_>> = Vec::new_in(p.allocator); match self.readonly { - TSMappedTypeModifierOperator::Plus => parts.push(p.text("+readonly ")), - TSMappedTypeModifierOperator::Minus => parts.push(p.text("-readonly ")), - TSMappedTypeModifierOperator::True => parts.push(p.text("readonly ")), + TSMappedTypeModifierOperator::Plus => parts.push(text!("+readonly ")), + TSMappedTypeModifierOperator::Minus => parts.push(text!("-readonly ")), + TSMappedTypeModifierOperator::True => parts.push(text!("readonly ")), TSMappedTypeModifierOperator::None => (), } - parts.push(p.text("[")); + parts.push(text!("[")); parts.push(self.type_parameter.format(p)); if let Some(name_type) = &self.name_type { - parts.push(p.text(" as ")); + parts.push(text!(" as ")); parts.push(name_type.format(p)); } - parts.push(p.text("]")); + parts.push(text!("]")); match self.optional { - TSMappedTypeModifierOperator::Plus => parts.push(p.text("+?")), - TSMappedTypeModifierOperator::Minus => parts.push(p.text("-?")), - TSMappedTypeModifierOperator::True => parts.push(p.text("?")), + TSMappedTypeModifierOperator::Plus => parts.push(text!("+?")), + TSMappedTypeModifierOperator::Minus => parts.push(text!("-?")), + TSMappedTypeModifierOperator::True => parts.push(text!("?")), TSMappedTypeModifierOperator::None => (), } if let Some(type_annotation) = &self.type_annotation { - parts.push(p.text(": ")); + parts.push(text!(": ")); parts.push(type_annotation.format(p)); } - let mut result = p.vec(); - result.push(p.text("{ ")); - - // TODO: check ident/grouping in method/method-signature.ts - result.push(p.group(p.array(parts))); - result.push(p.text(" }")); - - p.array(result) + array!( + p, + [ + text!("{ "), + // TODO: check ident/grouping in method/method-signature.ts + group!(p, parts), + text!(" }") + ] + ) } } impl<'a> Format<'a> for TSNamedTupleMember<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.label.format(p)); if self.optional { - parts.push(p.text("?")); + parts.push(text!("?")); } - parts.push(p.text(": ")); + parts.push(text!(": ")); parts.push(self.element_type.format(p)); - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSRestType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let type_annotation_doc = self.type_annotation.format(p); - p.array(p_vec!(p, p.text("..."), type_annotation_doc)) + array!(p, [text!("..."), type_annotation_doc]) } } impl<'a> Format<'a> for TSOptionalType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let type_annotation_doc = self.type_annotation.format(p); - p.array(p_vec!(p, type_annotation_doc, p.text("?"))) + array!(p, [type_annotation_doc, text!("?")]) } } @@ -1037,7 +1028,7 @@ impl<'a> Format<'a> for TSQualifiedName<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let left_doc = self.left.format(p); let right_doc = self.right.format(p); - p.array(p_vec!(p, left_doc, p.text("."), right_doc)) + array!(p, [left_doc, text!("."), right_doc]) } } @@ -1064,31 +1055,31 @@ impl<'a> Format<'a> for TSTypeLiteral<'a> { impl<'a> Format<'a> for TSTypeOperator<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); - parts.push(p.text(self.operator.to_str())); - parts.push(p.space()); + parts.push(text!(self.operator.to_str())); + parts.push(text!(" ")); parts.push(self.type_annotation.format(p)); - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSTypePredicate<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if self.asserts { - parts.push(p.text("asserts ")); + parts.push(text!("asserts ")); } parts.push(self.parameter_name.format(p)); if let Some(type_annotation) = &self.type_annotation { - parts.push(p.text(" is ")); + parts.push(text!(" is ")); parts.push(type_annotation.type_annotation.format(p)); } - p.array(parts) + array!(p, parts) } } @@ -1103,9 +1094,9 @@ impl<'a> Format<'a> for TSTypePredicateName<'a> { impl<'a> Format<'a> for TSTypeQuery<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); - parts.push(p.text("typeof ")); + parts.push(text!("typeof ")); match &self.expr_name { TSTypeQueryExprName::TSImportType(import_type) => parts.push(import_type.format(p)), @@ -1121,18 +1112,18 @@ impl<'a> Format<'a> for TSTypeQuery<'a> { parts.push(type_parameters.format(p)); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSTypeReference<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.type_name.format(p)); if let Some(params) = &self.type_parameters { parts.push(params.format(p)); } - p.array(parts) + array!(p, parts) } } @@ -1144,12 +1135,12 @@ impl<'a> Format<'a> for TSParenthesizedType<'a> { impl<'a> Format<'a> for TSUnionType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); let mut add_symbol = false; for ts_type in &self.types { if add_symbol { - parts.push(p.text(" | ")); + parts.push(text!(" | ")); } else { add_symbol = true; } @@ -1157,55 +1148,55 @@ impl<'a> Format<'a> for TSUnionType<'a> { parts.push(ts_type.format(p)); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for JSDocNullableType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.line() + line!() } } impl<'a> Format<'a> for JSDocNonNullableType<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.line() + line!() } } impl<'a> Format<'a> for JSDocUnknownType { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.line() + line!() } } impl<'a> Format<'a> for TSInterfaceDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if self.declare { - parts.push(p.text("declare ")); + parts.push(text!("declare ")); } - parts.push(p.text("interface ")); + parts.push(text!("interface ")); parts.push(self.id.format(p)); if let Some(type_parameters) = &self.type_parameters { parts.push(type_parameters.format(p)); } - parts.push(p.space()); + parts.push(text!(" ")); if let Some(extends) = &self.extends { if extends.len() > 0 { - let mut extends_parts = p.vec(); + let mut extends_parts = Vec::new_in(p.allocator); let mut display_comma = false; - extends_parts.push(p.text("extends ")); + extends_parts.push(text!("extends ")); for extend in extends { if display_comma { - extends_parts.push(p.text(", ")); + extends_parts.push(text!(", ")); } else { display_comma = true; } @@ -1217,69 +1208,69 @@ impl<'a> Format<'a> for TSInterfaceDeclaration<'a> { } parts.extend(extends_parts); - parts.push(p.space()); + parts.push(text!(" ")); } } - parts.push(p.text("{")); + parts.push(text!("{")); if self.body.body.len() > 0 { - let mut indent_parts = p.vec(); + let mut indent_parts = Vec::new_in(p.allocator); for sig in &self.body.body { - indent_parts.extend(p.hardline()); + indent_parts.extend(hardline!()); indent_parts.push(sig.format(p)); if let Some(semi) = p.semi() { indent_parts.push(semi); } } - parts.push(p.indent(indent_parts)); - parts.extend(p.hardline()); + parts.push(indent!(p, indent_parts)); + parts.extend(hardline!()); } - parts.push(p.text("}")); - p.array(parts) + parts.push(text!("}")); + array!(p, parts) } } impl<'a> Format<'a> for TSEnumDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if self.declare { - parts.push(p.text("declare ")); + parts.push(text!("declare ")); } if self.r#const { - parts.push(p.text("const ")); + parts.push(text!("const ")); } - parts.push(p.text("enum ")); + parts.push(text!("enum ")); parts.push(self.id.format(p)); - parts.push(p.text(" {")); + parts.push(text!(" {")); if self.members.len() > 0 { - let mut indent_parts = p.vec(); + let mut indent_parts = Vec::new_in(p.allocator); for member in &self.members { - indent_parts.extend(p.hardline()); + indent_parts.extend(hardline!()); indent_parts.push(member.format(p)); } - parts.push(p.indent(indent_parts)); - parts.extend(p.hardline()); + parts.push(indent!(p, indent_parts)); + parts.extend(hardline!()); } - parts.push(p.text("}")); + parts.push(text!("}")); - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSEnumMember<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.id.format(p)); if let Some(initializer) = &self.initializer { - parts.push(p.text(" = ")); + parts.push(text!(" = ")); parts.push(initializer.format(p)); } - parts.push(p.text(",")); + parts.push(text!(",")); - p.array(parts) + array!(p, parts) } } @@ -1294,32 +1285,32 @@ impl<'a> Format<'a> for TSEnumMemberName<'a> { impl<'a> Format<'a> for TSModuleDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if self.declare { - parts.push(p.text("declare ")); + parts.push(text!("declare ")); } - parts.push(p.text(self.kind.as_str())); - parts.push(p.space()); + parts.push(text!(self.kind.as_str())); + parts.push(text!(" ")); parts.push(self.id.format(p)); - parts.push(p.text(" {")); + parts.push(text!(" {")); if let Some(body) = &self.body { if !body.is_empty() { - let mut indent_parts = p.vec(); + let mut indent_parts = Vec::new_in(p.allocator); - indent_parts.extend(p.hardline()); + indent_parts.extend(hardline!()); indent_parts.push(body.format(p)); - parts.push(p.indent(indent_parts)); - parts.extend(p.hardline()); + parts.push(indent!(p, indent_parts)); + parts.extend(hardline!()); } } - parts.push(p.text("}")); + parts.push(text!("}")); - p.array(parts) + array!(p, parts) } } @@ -1345,12 +1336,12 @@ impl<'a> Format<'a> for TSModuleDeclarationBody<'a> { impl<'a> Format<'a> for TSModuleBlock<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); let mut add_line = false; for body_part in &self.body { if add_line { - parts.push(p.line()); + parts.push(line!()); } else { add_line = true; } @@ -1358,28 +1349,28 @@ impl<'a> Format<'a> for TSModuleBlock<'a> { parts.push(body_part.format(p)); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSImportEqualsDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); - parts.push(p.text("import ")); + parts.push(text!("import ")); if self.import_kind == ImportOrExportKind::Type { - parts.push(p.text("type ")); + parts.push(text!("type ")); } parts.push(self.id.format(p)); - parts.push(p.text(" = ")); + parts.push(text!(" = ")); parts.push(self.module_reference.format(p)); if let Some(semi) = p.semi() { parts.push(semi); } - p.array(parts) + array!(p, parts) } } @@ -1405,48 +1396,48 @@ impl<'a> Format<'a> for TSTypeName<'a> { impl<'a> Format<'a> for TSExternalModuleReference<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let expression_doc = self.expression.format(p); - p.array(p_vec!(p, p.text("require("), expression_doc, p.text(")"))) + array!(p, [text!("require("), expression_doc, text!(")")]) } } impl<'a> Format<'a> for TSTypeParameter<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if self.r#in { - parts.push(p.text("in ")); + parts.push(text!("in ")); } if self.out { - parts.push(p.text("out ")); + parts.push(text!("out ")); } parts.push(self.name.format(p)); if let Some(constraint) = &self.constraint { - parts.push(p.text(" extends ")); + parts.push(text!(" extends ")); parts.push(constraint.format(p)); } if let Some(default) = &self.default { - parts.push(p.text(" = ")); + parts.push(text!(" = ")); parts.push(default.format(p)); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSTypeParameterDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); let mut print_comma = false; - parts.push(p.text("<")); + parts.push(text!("<")); for param in &self.params { if print_comma { - parts.push(p.text(", ")); + parts.push(text!(", ")); } else { print_comma = true; } @@ -1454,22 +1445,22 @@ impl<'a> Format<'a> for TSTypeParameterDeclaration<'a> { parts.push(param.format(p)); } - parts.push(p.text(">")); + parts.push(text!(">")); - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSTypeParameterInstantiation<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); let mut print_comma = false; - parts.push(p.text("<")); + parts.push(text!("<")); for param in &self.params { if print_comma { - parts.push(p.text(", ")); + parts.push(text!(", ")); } else { print_comma = true; } @@ -1477,9 +1468,9 @@ impl<'a> Format<'a> for TSTypeParameterInstantiation<'a> { parts.push(param.format(p)); } - parts.push(p.text(">")); + parts.push(text!(">")); - p.array(parts) + array!(p, parts) } } @@ -1560,10 +1551,10 @@ impl<'a> Format<'a> for FormalParameter<'a> { impl<'a> Format<'a> for ImportDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.text("import")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("import")); if self.import_kind.is_type() { - parts.push(p.text(" type")); + parts.push(text!(" type")); } if let Some(specifiers) = &self.specifiers { @@ -1579,20 +1570,20 @@ impl<'a> Format<'a> for ImportDeclaration<'a> { || specifiers.get(1).is_some_and(validate_namespace); parts.push(module::print_module_specifiers(p, specifiers, is_default, is_namespace)); - parts.push(p.text(" from")); + parts.push(text!(" from")); } - parts.push(p.space()); + parts.push(text!(" ")); parts.push(self.source.format(p)); if let Some(with_clause) = &self.with_clause { - parts.push(p.space()); + parts.push(text!(" ")); parts.push(with_clause.format(p)); } if let Some(semi) = p.semi() { parts.push(semi); } - p.array(parts) + array!(p, parts) } } @@ -1608,15 +1599,15 @@ impl<'a> Format<'a> for ImportDeclarationSpecifier<'a> { impl<'a> Format<'a> for ImportSpecifier<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let typed = if self.import_kind.is_type() { p.text("type ") } else { p.text("") }; + let typed = if self.import_kind.is_type() { text!("type ") } else { text!("") }; if self.imported.span() == self.local.span { let local_doc = self.local.format(p); - p.array(p_vec!(p, typed, local_doc)) + array!(p, [typed, local_doc]) } else { let imported_doc = self.imported.format(p); let local_doc = self.local.format(p); - p.array(p_vec!(p, typed, imported_doc, p.text(" as "), local_doc)) + array!(p, [typed, imported_doc, text!(" as "), local_doc]) } } } @@ -1630,7 +1621,7 @@ impl<'a> Format<'a> for ImportDefaultSpecifier<'a> { impl<'a> Format<'a> for ImportNamespaceSpecifier<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let local_doc = self.local.format(p); - p.array(p_vec!(p, p.text("* as "), local_doc)) + array!(p, [text!("* as "), local_doc]) } } @@ -1638,7 +1629,7 @@ impl<'a> Format<'a> for WithClause<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let attribute_keyword_doc = self.attributes_keyword.format(p); let with_clause_doc = object::print_object_properties(p, ObjectLike::WithClause(self)); - p.array(p_vec!(p, attribute_keyword_doc, p.space(), with_clause_doc)) + array!(p, [attribute_keyword_doc, text!(" "), with_clause_doc]) } } @@ -1646,7 +1637,7 @@ 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); - p.array(p_vec!(p, key_doc, p.text(": "), value_doc)) + array!(p, [key_doc, text!(": "), value_doc]) } } @@ -1661,9 +1652,9 @@ impl<'a> Format<'a> for ImportAttributeKey<'a> { impl<'a> Format<'a> for ExportNamedDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if let Some(decl) = &self.declaration { - parts.push(p.space()); + parts.push(text!(" ")); parts.push(decl.format(p)); } else { parts.push(module::print_module_specifiers( @@ -1673,21 +1664,21 @@ impl<'a> Format<'a> for ExportNamedDeclaration<'a> { /* include_namespace */ false, )); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSExportAssignment<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let expression_doc = self.expression.format(p); - p.array(p_vec!(p, p.text(" = "), expression_doc)) + array!(p, [text!(" = "), expression_doc]) } } impl<'a> Format<'a> for TSNamespaceExportDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let id_doc = self.id.format(p); - p.array(p_vec!(p, p.text(" as namespace "), id_doc, p.text(";"))) + array!(p, [text!(" as namespace "), id_doc, text!(";")]) } } @@ -1698,7 +1689,7 @@ impl<'a> Format<'a> for ExportSpecifier<'a> { } else { let local_doc = self.local.format(p); let exported_doc = self.exported.format(p); - p.array(p_vec!(p, local_doc, p.text(" as "), exported_doc)) + array!(p, [local_doc, text!(" as "), exported_doc]) } } } @@ -1715,13 +1706,13 @@ impl<'a> Format<'a> for ModuleExportName<'a> { impl<'a> Format<'a> for ExportAllDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.text(" *")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!(" *")); if let Some(exported) = &self.exported { - parts.push(p.text(" as ")); + parts.push(text!(" as ")); parts.push(exported.format(p)); } - p.array(parts) + array!(p, parts) } } @@ -1790,37 +1781,37 @@ impl<'a> Format<'a> for Expression<'a> { impl<'a> Format<'a> for IdentifierReference<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, IdentifierReference, { p.dynamic_text(self.name.as_str()) }) + wrap!(p, self, IdentifierReference, { dynamic_text!(p, self.name.as_str()) }) } } impl<'a> Format<'a> for IdentifierName<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.dynamic_text(self.name.as_str()) + dynamic_text!(p, self.name.as_str()) } } impl<'a> Format<'a> for BindingIdentifier<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, BindingIdentifier, { p.dynamic_text(self.name.as_str()) }) + wrap!(p, self, BindingIdentifier, { dynamic_text!(p, self.name.as_str()) }) } } impl<'a> Format<'a> for LabelIdentifier<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.dynamic_text(self.name.as_str()) + dynamic_text!(p, self.name.as_str()) } } impl<'a> Format<'a> for BooleanLiteral { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text(if self.value { "true" } else { "false" }) + text!(if self.value { "true" } else { "false" }) } } impl<'a> Format<'a> for NullLiteral { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("null") + text!("null") } } @@ -1882,7 +1873,7 @@ impl<'a> Format<'a> for NumericLiteral<'a> { } } - p.dynamic_text(&string) + dynamic_text!(p, &string) }) } } @@ -1890,20 +1881,20 @@ impl<'a> Format<'a> for NumericLiteral<'a> { impl<'a> Format<'a> for BigIntLiteral<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { match self.span.source_text(p.source_text).cow_to_ascii_lowercase() { - Cow::Borrowed(s) => p.dynamic_text(s), - Cow::Owned(s) => p.dynamic_text(&s), + Cow::Borrowed(s) => dynamic_text!(p, s), + Cow::Owned(s) => dynamic_text!(p, &s), } } } impl<'a> Format<'a> for RegExpLiteral<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.text("/")); - parts.push(p.dynamic_text(self.regex.pattern.source_text(p.source_text).as_ref())); - parts.push(p.text("/")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("/")); + parts.push(dynamic_text!(p, self.regex.pattern.source_text(p.source_text).as_ref())); + parts.push(text!("/")); parts.push(self.regex.flags.format(p)); - p.array(parts) + array!(p, parts) } } @@ -1912,14 +1903,14 @@ impl<'a> Format<'a> for StringLiteral<'a> { wrap!(p, self, StringLiteral, { let raw = &p.source_text[(self.span.start + 1) as usize..(self.span.end - 1) as usize]; // TODO: implement `makeString` from prettier/src/utils/print-string.js - p.dynamic_text(string::print_string(p, raw, p.options.single_quote)) + dynamic_text!(p, string::print_string(p, raw, p.options.single_quote)) }) } } impl<'a> Format<'a> for ThisExpression { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("this") + text!("this") } } @@ -1937,38 +1928,38 @@ impl<'a> Format<'a> for MemberExpression<'a> { impl<'a> Format<'a> for ComputedMemberExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.object.format(p)); if self.optional { - parts.push(p.text("?.")); + parts.push(text!("?.")); } - parts.push(p.text("[")); + parts.push(text!("[")); parts.push(self.expression.format(p)); - parts.push(p.text("]")); - p.array(parts) + parts.push(text!("]")); + array!(p, parts) } } impl<'a> Format<'a> for StaticMemberExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.object.format(p)); if self.optional { - parts.push(p.text("?")); + parts.push(text!("?")); } - parts.push(p.text(".")); + parts.push(text!(".")); parts.push(self.property.format(p)); - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for PrivateFieldExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.object.format(p)); - parts.push(if self.optional { p.text("?.") } else { p.text(".") }); + parts.push(if self.optional { text!("?.") } else { text!(".") }); parts.push(self.field.format(p)); - p.array(parts) + array!(p, parts) } } @@ -1997,7 +1988,7 @@ impl<'a> Format<'a> for ArrayExpressionElement<'a> { match self { Self::SpreadElement(expr) => expr.format(p), match_expression!(Self) => self.to_expression().format(p), - Self::Elision(elision) => p.text(""), + Self::Elision(elision) => text!(""), } } } @@ -2006,7 +1997,7 @@ impl<'a> Format<'a> for SpreadElement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, SpreadElement, { let argument_doc = self.argument.format(p); - p.array(p_vec!(p, p.text("..."), argument_doc)) + array!(p, [text!("..."), argument_doc]) }) } } @@ -2038,15 +2029,15 @@ impl<'a> Format<'a> for ObjectProperty<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, ObjectProperty, { if self.method || self.kind == PropertyKind::Get || self.kind == PropertyKind::Set { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); let mut method = self.method; match self.kind { PropertyKind::Get => { - parts.push(p.text("get ")); + parts.push(text!("get ")); method = true; } PropertyKind::Set => { - parts.push(p.text("set ")); + parts.push(text!("set ")); method = true; } PropertyKind::Init => (), @@ -2063,10 +2054,10 @@ impl<'a> Format<'a> for ObjectProperty<'a> { } } else { parts.push(self.key.format(p)); - parts.push(p.text(": ")); + parts.push(text!(": ")); parts.push(self.value.format(p)); } - return p.group(p.array(parts)); + return group!(p, parts); } if self.shorthand { @@ -2075,7 +2066,7 @@ impl<'a> Format<'a> for ObjectProperty<'a> { let left_doc = if self.computed { let key_doc = self.key.format(p); - p.array(p_vec!(p, p.text("["), key_doc, p.text("]"))) + array!(p, [text!("["), key_doc, text!("]")]) } else { self.key.format(p) }; @@ -2084,7 +2075,7 @@ impl<'a> Format<'a> for ObjectProperty<'a> { p, assignment::AssignmentLikeNode::ObjectProperty(self), left_doc, - p.text(":"), + text!(":"), Some(&self.value), ) }) @@ -2099,16 +2090,16 @@ impl<'a> Format<'a> for PropertyKey<'a> { _ => false, }; if is_parent_computed { - let mut parts = p.vec(); - parts.push(p.text("[")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("[")); let doc = match self { PropertyKey::StaticIdentifier(ident) => ident.format(p), PropertyKey::PrivateIdentifier(ident) => ident.format(p), match_expression!(PropertyKey) => self.to_expression().format(p), }; parts.push(doc); - parts.push(p.text("]")); - return p.array(parts); + parts.push(text!("]")); + return array!(p, parts); } wrap!(p, self, PropertyKey, { @@ -2133,7 +2124,10 @@ impl<'a> Format<'a> for PropertyKey<'a> { match self { PropertyKey::StaticIdentifier(ident) => { if need_quote { - p.dynamic_text(string::print_string(p, &ident.name, p.options.single_quote)) + dynamic_text!( + p, + string::print_string(p, &ident.name, p.options.single_quote) + ) } else { ident.format(p) } @@ -2147,25 +2141,27 @@ impl<'a> Format<'a> for PropertyKey<'a> { && (p.options.quote_props.as_needed() || (p.options.quote_props.consistent()/* && !needsQuoteProps.get(parent) */)) { - p.dynamic_text(literal.value.as_str()) + dynamic_text!(p, literal.value.as_str()) } else { - p.dynamic_text(string::print_string( + dynamic_text!( p, - literal.value.as_str(), - p.options.single_quote, - )) + string::print_string(p, literal.value.as_str(), p.options.single_quote,) + ) } } PropertyKey::NumericLiteral(literal) => { if need_quote { - p.dynamic_text(string::print_string(p, literal.raw, p.options.single_quote)) + dynamic_text!( + p, + string::print_string(p, literal.raw, p.options.single_quote) + ) } else { literal.format(p) } } PropertyKey::Identifier(ident) => { let ident_doc = ident.format(p); - p.array(p_vec!(p, p.text("["), ident_doc, p.text("]"))) + array!(p, [text!("["), ident_doc, text!("]")]) } match_expression!(PropertyKey) => self.to_expression().format(p), } @@ -2182,16 +2178,16 @@ impl<'a> Format<'a> for ArrowFunctionExpression<'a> { impl<'a> Format<'a> for YieldExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, YieldExpression, { - let mut parts = p.vec(); - parts.push(p.text("yield")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("yield")); if self.delegate { - parts.push(p.text("*")); + parts.push(text!("*")); } if let Some(argument) = &self.argument { - parts.push(p.space()); + parts.push(text!(" ")); parts.push(argument.format(p)); } - p.array(parts) + array!(p, parts) }) } } @@ -2201,10 +2197,10 @@ impl<'a> Format<'a> for UpdateExpression<'a> { wrap!(p, self, UpdateExpression, { if self.prefix { let argument_doc = self.argument.format(p); - p.array(p_vec!(p, p.text(self.operator.as_str()), argument_doc)) + array!(p, [text!(self.operator.as_str()), argument_doc]) } else { let argument_doc = self.argument.format(p); - p.array(p_vec!(p, argument_doc, p.text(self.operator.as_str()))) + array!(p, [argument_doc, text!(self.operator.as_str())]) } }) } @@ -2213,13 +2209,13 @@ impl<'a> Format<'a> for UpdateExpression<'a> { impl<'a> Format<'a> for UnaryExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, UnaryExpression, { - let mut parts = p.vec(); - parts.push(p.dynamic_text(self.operator.as_str())); + let mut parts = Vec::new_in(p.allocator); + parts.push(dynamic_text!(p, self.operator.as_str())); if self.operator.is_keyword() { - parts.push(p.space()); + parts.push(text!(" ")); } parts.push(self.argument.format(p)); - p.array(parts) + array!(p, parts) }) } } @@ -2234,7 +2230,7 @@ impl<'a> Format<'a> for BinaryExpression<'a> { &self.right, ); if misc::in_parentheses(p.parent_kind(), p.source_text, self.span) { - p.group(p.array(p_vec!(p, p.indent(p_vec!(p, p.softline(), doc)), p.softline(),))) + group!(p, [indent!(p, [softline!(), doc]), softline!(),]) } else { doc } @@ -2247,14 +2243,7 @@ impl<'a> Format<'a> for PrivateInExpression<'a> { wrap!(p, self, PrivateInExpression, { let left_doc = self.left.format(p); let right_doc = self.right.format(p); - p.array(p_vec!( - p, - left_doc, - p.space(), - p.text(self.operator.as_str()), - p.space(), - right_doc - )) + array!(p, [left_doc, text!(" "), text!(self.operator.as_str()), text!(" "), right_doc]) }) } } @@ -2270,7 +2259,7 @@ impl<'a> Format<'a> for LogicalExpression<'a> { ); if misc::in_parentheses(p.parent_kind(), p.source_text, self.span) { - p.group(p.array(p_vec!(p, p.indent(p_vec!(p, p.softline(), doc)), p.softline()))) + group!(p, [indent!(p, [softline!(), doc]), softline!()]) } else { doc } @@ -2349,7 +2338,7 @@ impl<'a> Format<'a> for AssignmentTargetWithDefault<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let binding_doc = self.binding.format(p); let init_doc = self.init.format(p); - p.array(p_vec!(p, binding_doc, p.text(" = "), init_doc)) + array!(p, [binding_doc, text!(" = "), init_doc]) } } @@ -2364,13 +2353,13 @@ impl<'a> Format<'a> for AssignmentTargetProperty<'a> { impl<'a> Format<'a> for AssignmentTargetPropertyIdentifier<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.binding.format(p)); if let Some(init) = &self.init { - parts.push(p.text(" = ")); + parts.push(text!(" = ")); parts.push(init.format(p)); } - p.array(parts) + array!(p, parts) } } @@ -2378,14 +2367,14 @@ impl<'a> Format<'a> for AssignmentTargetPropertyProperty<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let name_doc = self.name.format(p); let binding_doc = self.binding.format(p); - p.array(p_vec!(p, name_doc, p.text(": "), binding_doc)) + array!(p, [name_doc, text!(": "), binding_doc]) } } impl<'a> Format<'a> for AssignmentTargetRest<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let target_doc = self.target.format(p); - p.array(p_vec!(p, p.text("..."), target_doc)) + array!(p, [text!("..."), target_doc]) } } @@ -2394,7 +2383,7 @@ impl<'a> Format<'a> for SequenceExpression<'a> { wrap!(p, self, SequenceExpression, { let docs = self.expressions.iter().map(|expr| expr.format(p)).collect::>(); - p.group(p.array(p_vec!(p, p.array(p.join(Separator::CommaLine, docs))))) + group!(p, [join!(p, JoinSeparator::CommaLine, docs)]) }) } } @@ -2408,24 +2397,24 @@ impl<'a> Format<'a> for ParenthesizedExpression<'a> { impl<'a> Format<'a> for ImportExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, ImportExpression, { - let mut parts = p.vec(); - parts.push(p.text("import")); - parts.push(p.text("(")); - let mut indent_parts = p.vec(); - indent_parts.push(p.softline()); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("import")); + parts.push(text!("(")); + let mut indent_parts = Vec::new_in(p.allocator); + indent_parts.push(softline!()); indent_parts.push(self.source.format(p)); if !self.arguments.is_empty() { for arg in &self.arguments { - indent_parts.push(p.text(",")); - indent_parts.push(p.line()); + indent_parts.push(text!(",")); + indent_parts.push(line!()); indent_parts.push(arg.format(p)); } } - parts.push(p.group(p.indent(indent_parts))); - parts.push(p.softline()); - parts.push(p.text(")")); + parts.push(group!(p, [indent!(p, indent_parts)])); + parts.push(softline!()); + parts.push(text!(")")); - p.group(p.array(parts)) + group!(p, parts) }) } } @@ -2439,43 +2428,43 @@ impl<'a> Format<'a> for TemplateLiteral<'a> { impl<'a> Format<'a> for TemplateElement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { // TODO: `replaceEndOfLine` - p.dynamic_text(self.value.raw.as_str()) + dynamic_text!(p, self.value.raw.as_str()) } } impl<'a> Format<'a> for TaggedTemplateExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, TaggedTemplateExpression, { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.tag.format(p)); if let Some(type_parameters) = &self.type_parameters { - parts.push(p.text("<")); + parts.push(text!("<")); parts.push(type_parameters.format(p)); - parts.push(p.text(">")); + parts.push(text!(">")); } parts.push(self.quasi.format(p)); - p.array(parts) + array!(p, parts) }) } } impl<'a> Format<'a> for Super { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("super") + text!("super") } } impl<'a> Format<'a> for AwaitExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, AwaitExpression, { - let mut parts = p.vec(); - parts.push(p.text("await ")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("await ")); parts.push(self.argument.format(p)); - p.array(parts) + array!(p, parts) }) } } @@ -2511,7 +2500,7 @@ 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); - p.array(p_vec!(p, meta_doc, p.text("."), property_doc)) + array!(p, [meta_doc, text!("."), property_doc]) } } @@ -2541,7 +2530,7 @@ impl<'a> Format<'a> for ClassElement<'a> { impl<'a> Format<'a> for TSClassImplements<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.expression.format(p)); @@ -2549,7 +2538,7 @@ impl<'a> Format<'a> for TSClassImplements<'a> { parts.push(type_parameters.format(p)); } - p.array(parts) + array!(p, parts) } } @@ -2557,7 +2546,7 @@ impl<'a> Format<'a> for TSTypeAssertion<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let type_annotation_doc = self.type_annotation.format(p); let expression_doc = self.expression.format(p); - p.array(p_vec!(p, p.text("<"), type_annotation_doc, p.text(">"), expression_doc)) + array!(p, [text!("<"), type_annotation_doc, text!(">"), expression_doc]) } } @@ -2565,7 +2554,7 @@ impl<'a> Format<'a> for TSSatisfiesExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let expression_doc = self.expression.format(p); let type_annotation_doc = self.type_annotation.format(p); - p.array(p_vec!(p, expression_doc, p.text(" satisfies "), type_annotation_doc)) + array!(p, [expression_doc, text!(" satisfies "), type_annotation_doc]) } } @@ -2573,20 +2562,20 @@ impl<'a> Format<'a> for TSInstantiationExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let expression_doc = self.expression.format(p); let type_parameters_doc = self.type_parameters.format(p); - p.array(p_vec!(p, expression_doc, type_parameters_doc)) + array!(p, [expression_doc, type_parameters_doc]) } } impl<'a> Format<'a> for TSNonNullExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let expression_doc = self.expression.format(p); - p.array(p_vec!(p, expression_doc, p.text("!"))) + array!(p, [expression_doc, text!("!")]) } } impl<'a> Format<'a> for JSXIdentifier<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.dynamic_text(self.name.as_str()) + dynamic_text!(p, self.name.as_str()) } } @@ -2604,7 +2593,7 @@ impl<'a> Format<'a> for JSXMemberExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let object_doc = self.object.format(p); let property_doc = self.property.format(p); - p.array(p_vec!(p, object_doc, p.text("."), property_doc)) + array!(p, [object_doc, text!("."), property_doc]) } } @@ -2624,7 +2613,7 @@ impl<'a> Format<'a> for JSXNamespacedName<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let namespace_doc = self.namespace.format(p); let property_doc = self.property.format(p); - p.array(p_vec!(p, namespace_doc, p.text(":"), property_doc)) + array!(p, [namespace_doc, text!(":"), property_doc]) } } @@ -2639,21 +2628,21 @@ impl<'a> Format<'a> for JSXAttributeName<'a> { impl<'a> Format<'a> for JSXAttribute<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.name.format(p)); if let Some(value) = &self.value { - parts.push(p.text("=")); + parts.push(text!("=")); parts.push(value.format(p)); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for JSXEmptyExpression { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("") + text!("") } } @@ -2708,7 +2697,7 @@ impl<'a> Format<'a> for JSXExpression<'a> { impl<'a> Format<'a> for JSXExpressionContainer<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let expression_doc = self.expression.format(p); - p.array(p_vec!(p, p.text("{"), expression_doc, p.text("}"))) + array!(p, [text!("{"), expression_doc, text!("}")]) } } @@ -2726,7 +2715,7 @@ impl<'a> Format<'a> for JSXAttributeValue<'a> { impl<'a> Format<'a> for JSXSpreadAttribute<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let argument_doc = self.argument.format(p); - p.array(p_vec!(p, p.text("..."), argument_doc)) + array!(p, [text!("..."), argument_doc]) } } @@ -2741,9 +2730,9 @@ impl<'a> Format<'a> for JSXAttributeItem<'a> { impl<'a> Format<'a> for JSXOpeningElement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); - parts.push(p.text("<")); + parts.push(text!("<")); parts.push(self.name.format(p)); if let Some(type_parameters) = &self.type_parameters { @@ -2751,31 +2740,31 @@ impl<'a> Format<'a> for JSXOpeningElement<'a> { } for attribute in &self.attributes { - parts.push(p.space()); + parts.push(text!(" ")); parts.push(attribute.format(p)); } if self.self_closing { - parts.push(p.space()); - parts.push(p.text("/")); + parts.push(text!(" ")); + parts.push(text!("/")); } - parts.push(p.text(">")); + parts.push(text!(">")); - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for JSXClosingElement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let name_doc = self.name.format(p); - p.array(p_vec!(p, p.text(""))) + array!(p, [text!("")]) } } impl<'a> Format<'a> for JSXElement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.opening_element.format(p)); @@ -2787,32 +2776,32 @@ impl<'a> Format<'a> for JSXElement<'a> { parts.push(closing_element.format(p)); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for JSXOpeningFragment { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("<>") + text!("<>") } } impl<'a> Format<'a> for JSXClosingFragment { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.text("") + text!("") } } impl<'a> Format<'a> for JSXText<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - p.dynamic_text(self.value.as_str()) + dynamic_text!(p, self.value.as_str()) } } impl<'a> Format<'a> for JSXSpreadChild<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let expression_doc = self.expression.format(p); - p.array(p_vec!(p, p.text("..."), expression_doc)) + array!(p, [text!("..."), expression_doc]) } } @@ -2830,7 +2819,7 @@ impl<'a> Format<'a> for JSXChild<'a> { impl<'a> Format<'a> for JSXFragment<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(self.opening_fragment.format(p)); @@ -2840,7 +2829,7 @@ impl<'a> Format<'a> for JSXFragment<'a> { parts.push(self.closing_fragment.format(p)); - p.array(parts) + array!(p, parts) } } @@ -2848,7 +2837,7 @@ 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); - p.array(p_vec!(p, p.text("static "), block_doc)) + array!(p, [text!("static "), block_doc]) }) } } @@ -2875,16 +2864,16 @@ impl<'a> Format<'a> for AccessorProperty<'a> { impl<'a> Format<'a> for PrivateIdentifier<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.text("#")); - parts.push(p.dynamic_text(self.name.as_str())); - p.array(parts) + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("#")); + parts.push(dynamic_text!(p, self.name.as_str())); + array!(p, parts) } } impl<'a> Format<'a> for BindingPattern<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); parts.push(match self.kind { BindingPatternKind::BindingIdentifier(ref ident) => ident.format(p), BindingPatternKind::ObjectPattern(ref pattern) => pattern.format(p), @@ -2893,14 +2882,14 @@ impl<'a> Format<'a> for BindingPattern<'a> { }); if self.optional { - parts.push(p.text("?")); + parts.push(text!("?")); } if let Some(typ) = &self.type_annotation { let type_annotation_doc = typ.type_annotation.format(p); - parts.push(p.array(p_vec!(p, p.text(": "), type_annotation_doc))); + parts.push(array!(p, [text!(": "), type_annotation_doc])); } - p.array(parts) + array!(p, parts) } } @@ -2919,7 +2908,7 @@ impl<'a> Format<'a> for BindingProperty<'a> { } else { let key_doc = self.key.format(p); let value_doc = self.value.format(p); - p.group(p.array(p_vec!(p, key_doc, p.text(": "), value_doc))) + group!(p, [key_doc, text!(": "), value_doc]) } } } @@ -2927,7 +2916,7 @@ impl<'a> Format<'a> for BindingProperty<'a> { impl<'a> Format<'a> for BindingRestElement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let argument_doc = self.argument.format(p); - p.array(p_vec!(p, p.text("..."), argument_doc)) + array!(p, [text!("..."), argument_doc]) } } @@ -2942,7 +2931,7 @@ impl<'a> Format<'a> for AssignmentPattern<'a> { wrap!(p, self, AssignmentPattern, { let left_doc = self.left.format(p); let right_doc = self.right.format(p); - p.array(p_vec!(p, left_doc, p.text(" = "), right_doc)) + array!(p, [left_doc, text!(" = "), right_doc]) }) } } @@ -2975,58 +2964,58 @@ impl<'a> Format<'a> for RegExpFlags { string.push('y'); } let sorted = string.iter().collect::(); - p.dynamic_text(&sorted) + dynamic_text!(p, &sorted) } } impl<'a> Format<'a> for TSIndexSignature<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if self.readonly { - parts.push(p.text("readonly ")); + parts.push(text!("readonly ")); } - parts.push(p.text("[")); + parts.push(text!("[")); for param in &self.parameters { parts.push(param.format(p)); } - parts.push(p.text("]: ")); + parts.push(text!("]: ")); parts.push(self.type_annotation.type_annotation.format(p)); - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSIndexSignatureName<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let type_annotation_doc = self.type_annotation.type_annotation.format(p); - p.array(p_vec!(p, p.dynamic_text(self.name.as_str()), p.text(": "), type_annotation_doc)) + array!(p, [dynamic_text!(p, self.name.as_str()), text!(": "), type_annotation_doc]) } } impl<'a> Format<'a> for TSPropertySignature<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if self.readonly { - parts.push(p.text("readonly ")); + parts.push(text!("readonly ")); } parts.push(self.key.format(p)); if let Some(ty) = &self.type_annotation { if self.optional { - parts.push(p.text("?")); + parts.push(text!("?")); } - parts.push(p.text(":")); - parts.push(p.space()); + parts.push(text!(":")); + parts.push(text!(" ")); parts.push(ty.type_annotation.format(p)); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSCallSignatureDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if let Some(type_parameters) = &self.type_parameters { parts.push(type_parameters.format(p)); @@ -3035,19 +3024,19 @@ impl<'a> Format<'a> for TSCallSignatureDeclaration<'a> { parts.push(self.params.format(p)); if let Some(return_type) = &self.return_type { - parts.push(p.text(": ")); + parts.push(text!(": ")); parts.push(return_type.type_annotation.format(p)); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSConstructSignatureDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); - parts.push(p.text("new ")); + parts.push(text!("new ")); if let Some(type_parameters) = &self.type_parameters { parts.push(type_parameters.format(p)); @@ -3056,30 +3045,30 @@ impl<'a> Format<'a> for TSConstructSignatureDeclaration<'a> { parts.push(self.params.format(p)); if let Some(return_type) = &self.return_type { - parts.push(p.text(": ")); + parts.push(text!(": ")); parts.push(return_type.type_annotation.format(p)); } - p.array(parts) + array!(p, parts) } } impl<'a> Format<'a> for TSMethodSignature<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if self.computed { - parts.push(p.text("[")); + parts.push(text!("[")); } parts.push(self.key.format(p)); if self.computed { - parts.push(p.text("]")); + parts.push(text!("]")); } if self.optional { - parts.push(p.text("?")); + parts.push(text!("?")); } if let Some(type_parameters) = &self.type_parameters { @@ -3089,11 +3078,11 @@ impl<'a> Format<'a> for TSMethodSignature<'a> { parts.push(self.params.format(p)); if let Some(return_type) = &self.return_type { - parts.push(p.text(": ")); + parts.push(text!(": ")); parts.push(return_type.type_annotation.format(p)); } - p.array(parts) + array!(p, parts) } } @@ -3113,6 +3102,6 @@ impl<'a> Format<'a> for TSAsExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let expression_doc = self.expression.format(p); let type_annotation_doc = self.type_annotation.format(p); - p.array(p_vec!(p, expression_doc, p.text(" as "), type_annotation_doc)) + array!(p, [expression_doc, text!(" as "), type_annotation_doc]) } } diff --git a/crates/oxc_prettier/src/format/module.rs b/crates/oxc_prettier/src/format/module.rs index 2c554c828e494..c044d90bf3a3b 100644 --- a/crates/oxc_prettier/src/format/module.rs +++ b/crates/oxc_prettier/src/format/module.rs @@ -4,8 +4,9 @@ use oxc_allocator::Vec; use oxc_ast::ast::*; use crate::{ - ir::{Doc, DocBuilder, Separator}, - p_vec, Format, Prettier, + array, group, if_break, indent, + ir::{Doc, JoinSeparator}, + join, line, softline, text, Format, Prettier, }; pub(super) fn print_export_declaration<'a>( @@ -14,11 +15,11 @@ pub(super) fn print_export_declaration<'a>( ) -> Doc<'a> { debug_assert!(decl.is_export()); - let mut parts = p.vec(); - parts.push(p.text("export")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("export")); if decl.is_default_export() { - parts.push(p.text(" default ")); + parts.push(text!(" default ")); } parts.push(match decl { @@ -31,12 +32,12 @@ pub(super) fn print_export_declaration<'a>( }); if let Some(source) = decl.source() { - parts.push(p.text(" from ")); + parts.push(text!(" from ")); parts.push(source.format(p)); } if let Some(with_clause) = decl.with_clause() { - parts.push(p.space()); + parts.push(text!(" ")); parts.push(with_clause.format(p)); } @@ -44,7 +45,7 @@ pub(super) fn print_export_declaration<'a>( parts.push(doc); } - p.array(parts) + array!(p, parts) } fn print_semicolon_after_export_declaration<'a>( @@ -57,12 +58,12 @@ fn print_semicolon_after_export_declaration<'a>( match decl { ModuleDeclaration::ExportDefaultDeclaration(decl) => match decl.declaration { - match_expression!(ExportDefaultDeclarationKind) => Some(p.text(";")), + match_expression!(ExportDefaultDeclarationKind) => Some(text!(";")), _ => None, }, ModuleDeclaration::ExportNamedDeclaration(decl) => { let Some(declaration) = &decl.declaration else { - return Some(p.text(";")); + return Some(text!(";")); }; match declaration { @@ -70,11 +71,11 @@ fn print_semicolon_after_export_declaration<'a>( | Declaration::VariableDeclaration(_) | Declaration::ClassDeclaration(_) | Declaration::TSModuleDeclaration(_) => None, - _ => Some(p.text(";")), + _ => Some(text!(";")), } } ModuleDeclaration::ExportAllDeclaration(_) | ModuleDeclaration::TSExportAssignment(_) => { - Some(p.text(";")) + Some(text!(";")) } _ => None, } @@ -86,24 +87,24 @@ pub fn print_module_specifiers<'a, T: Format<'a>>( include_default: bool, include_namespace: bool, ) -> Doc<'a> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); if specifiers.is_empty() { - parts.push(p.text(" {}")); + parts.push(text!(" {}")); } else { - parts.push(p.space()); + parts.push(text!(" ")); let mut specifiers_iter: VecDeque<_> = specifiers.iter().collect(); if include_default { parts.push(specifiers_iter.pop_front().unwrap().format(p)); if !specifiers_iter.is_empty() { - parts.push(p.text(", ")); + parts.push(text!(", ")); } } if include_namespace { parts.push(specifiers_iter.pop_front().unwrap().format(p)); if !specifiers_iter.is_empty() { - parts.push(p.text(", ")); + parts.push(text!(", ")); } } @@ -113,35 +114,35 @@ pub fn print_module_specifiers<'a, T: Format<'a>>( if can_break { let docs = specifiers_iter.iter().map(|s| s.format(p)).collect::>(); - parts.push(p.group(p.array(p_vec!( + parts.push(group!( p, - p.text("{"), - p.indent(p_vec!( - p, - if p.options.bracket_spacing { p.line() } else { p.softline() }, - p.array(p.join(Separator::CommaLine, docs)) - )), - p.if_break( - p.text(if p.should_print_es5_comma() { "," } else { "" }), - p.text(""), - None, - ), - if p.options.bracket_spacing { p.line() } else { p.softline() }, - p.text("}"), - )))); + [ + text!("{"), + indent!( + p, + [ + if p.options.bracket_spacing { line!() } else { softline!() }, + join!(p, JoinSeparator::CommaLine, docs) + ] + ), + if_break!(p, text!(if p.should_print_es5_comma() { "," } else { "" })), + if p.options.bracket_spacing { line!() } else { softline!() }, + text!("}"), + ] + )); } else { - parts.push(p.text("{")); + parts.push(text!("{")); if p.options.bracket_spacing { - parts.push(p.space()); + parts.push(text!(" ")); } parts.extend(specifiers_iter.iter().map(|s| s.format(p))); if p.options.bracket_spacing { - parts.push(p.space()); + parts.push(text!(" ")); } - parts.push(p.text("}")); + parts.push(text!("}")); } } } - p.array(parts) + array!(p, parts) } diff --git a/crates/oxc_prettier/src/format/object.rs b/crates/oxc_prettier/src/format/object.rs index 6480142bc9e98..aa411fb2b9b8e 100644 --- a/crates/oxc_prettier/src/format/object.rs +++ b/crates/oxc_prettier/src/format/object.rs @@ -1,3 +1,4 @@ +use oxc_allocator::Vec; use oxc_ast::{ ast::{ObjectAssignmentTarget, ObjectExpression, ObjectPattern, TSTypeLiteral, WithClause}, AstKind, @@ -5,9 +6,11 @@ use oxc_ast::{ use oxc_span::Span; use crate::{ + array, format::{function_parameters, misc}, - ir::{Doc, DocBuilder}, - p_vec, Format, Prettier, + group, if_break, indent, + ir::Doc, + line, softline, text, Format, Prettier, }; #[derive(Debug, Clone, Copy)] @@ -99,34 +102,34 @@ pub(super) fn print_object_properties<'a>( p: &mut Prettier<'a>, object: ObjectLike<'a, '_>, ) -> Doc<'a> { - let left_brace = p.text("{"); - let right_brace = p.text("}"); + let left_brace = text!("{"); + let right_brace = text!("}"); let should_break = false; let member_separator = object.member_separator(p); let content = if object.is_empty() { - p.group(p.array(p_vec!(p, left_brace, p.softline(), right_brace))) + group!(p, [left_brace, softline!(), right_brace]) } else { - let mut parts = p.vec(); - parts.push(p.text("{")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("{")); let indent_parts = { let len = object.len(); let has_rest = object.has_rest(); - let mut indent_parts = p.vec(); + let mut indent_parts = Vec::new_in(p.allocator); - indent_parts.push(if p.options.bracket_spacing { p.line() } else { p.softline() }); + indent_parts.push(if p.options.bracket_spacing { line!() } else { softline!() }); - let object_docs = object.iter(p).collect::>(); + let object_docs = object.iter(p).collect::>(); for (i, doc) in object_docs.into_iter().enumerate() { indent_parts.push(doc); if i == len - 1 && !has_rest { break; } - indent_parts.push(p.text(member_separator)); - indent_parts.push(p.line()); + indent_parts.push(text!(member_separator)); + indent_parts.push(line!()); } match object { @@ -146,22 +149,22 @@ pub(super) fn print_object_properties<'a>( } indent_parts }; - parts.push(p.indent(indent_parts)); + parts.push(indent!(p, indent_parts)); if p.should_print_es5_comma() && match object { ObjectLike::Pattern(pattern) => pattern.rest.is_none(), _ => true, } { - parts.push(p.if_break(p.text(member_separator), p.text(""), None)); + parts.push(if_break!(p, text!(member_separator))); } - parts.push(if p.options.bracket_spacing { p.line() } else { p.softline() }); - parts.push(p.text("}")); + parts.push(if p.options.bracket_spacing { line!() } else { softline!() }); + parts.push(text!("}")); if matches!(p.current_kind(), AstKind::Program(_)) { let should_break = misc::has_new_line_in_range(p.source_text, object.span().start, object.span().end); - return p.group_with_opts(p.array(parts), should_break, None); + return group!(p, parts, should_break, None); } let parent_kind = p.parent_kind(); @@ -173,11 +176,11 @@ pub(super) fn print_object_properties<'a>( AstKind::AssignmentExpression(_) | AstKind::VariableDeclarator(_) )) { - p.array(parts) + array!(p, parts) } else { let should_break = misc::has_new_line_in_range(p.source_text, object.span().start, object.span().end); - p.group_with_opts(p.array(parts), should_break, None) + group!(p, parts, should_break, None) } }; diff --git a/crates/oxc_prettier/src/format/statement.rs b/crates/oxc_prettier/src/format/statement.rs index b44cf06ca913b..15b65e0b1a4ab 100644 --- a/crates/oxc_prettier/src/format/statement.rs +++ b/crates/oxc_prettier/src/format/statement.rs @@ -2,10 +2,7 @@ use oxc_allocator::Vec; use oxc_ast::ast::Statement; use oxc_span::GetSpan; -use crate::{ - ir::{Doc, DocBuilder}, - Format, Prettier, -}; +use crate::{hardline, ir::Doc, Format, Prettier}; pub(super) fn print_statement_sequence<'a>( p: &mut Prettier<'a>, @@ -13,7 +10,7 @@ pub(super) fn print_statement_sequence<'a>( remove_last_statement_hardline: bool, skip_empty_statement: bool, ) -> Vec<'a, Doc<'a>> { - let mut parts = p.vec(); + let mut parts = Vec::new_in(p.allocator); let last_statement_span = stmts.iter().rev().find(|s| !matches!(s, Statement::EmptyStatement(_))).map(GetSpan::span); @@ -26,9 +23,9 @@ pub(super) fn print_statement_sequence<'a>( parts.push(stmt.format(p)); if Some(stmt.span()) != last_statement_span { - parts.extend(p.hardline()); + parts.extend(hardline!()); if p.is_next_line_empty(stmt.span()) { - parts.extend(p.hardline()); + parts.extend(hardline!()); } } } diff --git a/crates/oxc_prettier/src/format/template_literal.rs b/crates/oxc_prettier/src/format/template_literal.rs index e7d23b1b6998b..e3e2cb3d46213 100644 --- a/crates/oxc_prettier/src/format/template_literal.rs +++ b/crates/oxc_prettier/src/format/template_literal.rs @@ -1,10 +1,7 @@ +use oxc_allocator::Vec; use oxc_ast::ast::*; -use crate::{ - format::Format, - ir::{Doc, DocBuilder}, - Prettier, -}; +use crate::{array, format::Format, ir::Doc, text, Prettier}; #[allow(clippy::enum_variant_names)] pub enum TemplateLiteralPrinter<'a, 'b> { @@ -36,8 +33,8 @@ pub(super) fn print_template_literal<'a, 'b>( p: &mut Prettier<'a>, template_literal: &'b TemplateLiteralPrinter<'a, 'b>, ) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.text("`")); + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("`")); for (index, quais) in template_literal.quasis().iter().enumerate() { parts.push(quais.format(p)); @@ -45,12 +42,12 @@ pub(super) fn print_template_literal<'a, 'b>( break; }; - parts.push(p.text("${")); + parts.push(text!("${")); parts.push(expr_doc); - parts.push(p.text("}")); + parts.push(text!("}")); } - parts.push(p.text("`")); + parts.push(text!("`")); - p.array(parts) + array!(p, parts) } diff --git a/crates/oxc_prettier/src/format/ternary.rs b/crates/oxc_prettier/src/format/ternary.rs index 91ec0f1877ba7..0e9551ff5391e 100644 --- a/crates/oxc_prettier/src/format/ternary.rs +++ b/crates/oxc_prettier/src/format/ternary.rs @@ -1,23 +1,17 @@ use oxc_ast::ast::*; -use crate::{ir::Doc, p_vec, DocBuilder, Format, Prettier}; +use crate::{group, indent, ir::Doc, line, text, Format, Prettier}; pub(super) fn print_ternary<'a>(p: &mut Prettier<'a>, expr: &ConditionalExpression<'a>) -> Doc<'a> { let test_doc = expr.test.format(p); let consequent_doc = expr.consequent.format(p); let alternate_doc = expr.alternate.format(p); - p.group(p.array(p_vec!( + group!( p, - test_doc, - p.indent(p_vec!( - p, - p.line(), - p.text("? "), - consequent_doc, - p.line(), - p.text(": "), - alternate_doc - )) - ))) + [ + test_doc, + indent!(p, [line!(), text!("? "), consequent_doc, line!(), text!(": "), alternate_doc]) + ] + ) } diff --git a/crates/oxc_prettier/src/ir/builder.rs b/crates/oxc_prettier/src/ir/builder.rs deleted file mode 100644 index 662d648aba0d7..0000000000000 --- a/crates/oxc_prettier/src/ir/builder.rs +++ /dev/null @@ -1,146 +0,0 @@ -use oxc_allocator::{Allocator, Box, IntoIn, String, Vec}; - -use crate::{ - ir::{Doc, Fill, Group, IfBreak, IndentIfBreak, Line}, - p_vec, GroupId, -}; - -#[derive(Clone, Copy)] -pub enum Separator { - Softline, - Hardline, - CommaLine, // [",", line] -} - -pub trait DocBuilder<'a> { - fn allocator(&self) -> &'a Allocator; - - #[inline] - fn vec(&self) -> Vec<'a, T> { - Vec::new_in(self.allocator()) - } - #[inline] - fn vec_single(&self, value: T) -> Vec<'a, T> { - let mut vec = Vec::with_capacity_in(1, self.allocator()); - vec.push(value); - vec - } - - fn text(&self, s: &'static str) -> Doc<'a> { - Doc::Str(s) - } - fn dynamic_text(&self, s: &str) -> Doc<'a> { - let s = String::from_str_in(s, self.allocator()).into_bump_str(); - Doc::Str(s) - } - fn space(&self) -> Doc<'a> { - Doc::Str(" ") - } - - fn line(&self) -> Doc<'a> { - Doc::Line(Line::default()) - } - /// Specify a line break. - /// The difference from line is that if the expression fits on one line, it will be replaced with nothing. - fn softline(&self) -> Doc<'a> { - Doc::Line(Line { soft: true, ..Line::default() }) - } - /// Specify a line break that is **always** included in the output, - /// no matter if the expression fits on one line or not. - fn hardline(&self) -> [Doc<'a>; 2] { - let hardline = Doc::Line(Line { hard: true, ..Line::default() }); - [hardline, Doc::BreakParent] - } - - fn indent(&self, contents: Vec<'a, Doc<'a>>) -> Doc<'a> { - Doc::Indent(contents) - } - - fn array(&self, contents: Vec<'a, Doc<'a>>) -> Doc<'a> { - Doc::Array(contents) - } - - fn fill(&self, contents: Vec<'a, Doc<'a>>) -> Doc<'a> { - Doc::Fill(Fill { contents }) - } - - fn if_break( - &self, - break_contents: Doc<'a>, - flat_contents: Doc<'a>, - group_id: Option, - ) -> Doc<'a> { - Doc::IfBreak(IfBreak { - break_contents: Box::new_in(break_contents, self.allocator()), - flat_contents: Box::new_in(flat_contents, self.allocator()), - group_id, - }) - } - - fn indent_if_break(&self, contents: Doc<'a>, group_id: GroupId) -> Doc<'a> { - Doc::IndentIfBreak(IndentIfBreak { - contents: Box::new_in(contents, self.allocator()), - group_id, - }) - } - - fn group(&self, contents: Doc<'a>) -> Doc<'a> { - Doc::Group(Group { - contents: self.vec_single(contents), - should_break: false, - expanded_states: None, - group_id: None, - }) - } - fn group_with_opts( - &self, - contents: Doc<'a>, - should_break: bool, - group_id: Option, - ) -> Doc<'a> { - Doc::Group(Group { - contents: self.vec_single(contents), - should_break, - expanded_states: None, - group_id, - }) - } - - fn conditional_group( - &self, - contents: Doc<'a>, - alternatives: std::vec::Vec>, - group_id: Option, - ) -> Doc<'a> { - let contents = self.vec_single(contents); - let expanded_states = Vec::from_iter_in(alternatives, self.allocator()); - Doc::Group(Group { - contents, - should_break: false, - expanded_states: Some(expanded_states), - group_id, - }) - } - - fn break_parent(&self) -> Doc<'a> { - Doc::BreakParent - } - - // TODO: Just use `Doc` instead of `Separator`...? - fn join(&self, separator: Separator, docs: std::vec::Vec>) -> Vec<'a, Doc<'a>> { - let mut parts = self.vec(); - for (i, doc) in docs.into_iter().enumerate() { - if i != 0 { - match separator { - Separator::Softline => parts.push(self.softline()), - Separator::Hardline => parts.extend(self.hardline()), - Separator::CommaLine => { - parts.push(self.array(p_vec!(self, self.text(","), self.line()))); - } - } - } - parts.push(doc); - } - parts - } -} diff --git a/crates/oxc_prettier/src/ir/doc.rs b/crates/oxc_prettier/src/ir/doc.rs index c6bfd50020a88..6338e8ae938e3 100644 --- a/crates/oxc_prettier/src/ir/doc.rs +++ b/crates/oxc_prettier/src/ir/doc.rs @@ -1,49 +1,20 @@ -//! Prettier IR -//! -//! References: -//! * - use oxc_allocator::{Box, Vec}; use crate::GroupId; /// IR for the pretty printing. -/// To produce, use the `DocBuilder` trait. +/// Direct use is discouraged, use the macro instead. #[derive(Debug)] pub enum Doc<'a> { - /// Strings are printed directly as is. - /// (however for the algorithm to work properly they shouldn't contain line break characters) Str(&'a str), - /// Arrays are used to concatenate a list of docs to be printed sequentially into a single doc. Array(Vec<'a, Doc<'a>>), - /// Mark a group of items which the printer should try to fit on one line. - /// This is the basic command to tell the printer when to break. - /// Groups are usually nested, and the printer will try to fit everything on one line, - /// but if it doesn't fit it will break the outermost group first and try again. - /// It will continue breaking groups until everything fits (or there are no more groups to break). Group(Group<'a>), - /// This is an alternative type of group which behaves like text layout: - /// it's going to add a break whenever the next element doesn't fit in the line anymore. - /// The difference with `group` is that it's not going to break all the separators, just the ones that are at the end of lines. Fill(Fill<'a>), - /// Print something if the current `group` or the current element of `fill` breaks and something else if it doesn't. IfBreak(IfBreak<'a>), - /// Include this anywhere to force all parent groups to break. BreakParent, - /// Specify a line break. - /// If an expression fits on one line, the line break will be replaced with a space. - /// Line breaks always indent the next line with the current level of indentation. Line(Line), - /// Increase the level of indentation. Indent(Vec<'a, Doc<'a>>), - /// An optimized version of `if_break(indent(doc), doc, { groupId })`. - /// It doesn't make sense to apply `indent_if_break` to the current group. - /// Because "indent if the current group is broken" is the normal behavior of indent. - /// That's why groupId is required. IndentIfBreak(IndentIfBreak<'a>), - /// This is used to implement trailing comments. - /// It's not practical to constantly check where the line ends to avoid accidentally printing some code at the end of a comment. - /// `lineSuffix` buffers docs passed to it and flushes them before any new line. LineSuffix(Vec<'a, Doc<'a>>), } @@ -109,3 +80,11 @@ impl<'a> Fill<'a> { self.contents } } + +// NOTE: Really needed? Just use `Doc` as a separator? +#[derive(Clone, Copy)] +pub enum JoinSeparator { + Softline, + Hardline, + CommaLine, // [",", line] +} diff --git a/crates/oxc_prettier/src/ir/mod.rs b/crates/oxc_prettier/src/ir/mod.rs index ab05969eb7295..6dcefa4e62d52 100644 --- a/crates/oxc_prettier/src/ir/mod.rs +++ b/crates/oxc_prettier/src/ir/mod.rs @@ -1,6 +1,4 @@ -mod builder; mod display; mod doc; -pub use builder::*; pub use doc::*; diff --git a/crates/oxc_prettier/src/lib.rs b/crates/oxc_prettier/src/lib.rs index 778c18d060eb2..e3abeafd47ffb 100644 --- a/crates/oxc_prettier/src/lib.rs +++ b/crates/oxc_prettier/src/lib.rs @@ -13,19 +13,13 @@ mod options; mod printer; mod utils; -use std::vec; - -use oxc_allocator::Allocator; +use oxc_allocator::{Allocator, Vec}; use oxc_ast::{ast::Program, AstKind}; use oxc_span::Span; use oxc_syntax::identifier::is_line_terminator; pub use crate::options::{ArrowParens, EndOfLine, PrettierOptions, QuoteProps, TrailingComma}; -use crate::{ - format::Format, - ir::{Doc, DocBuilder}, - printer::Printer, -}; +use crate::{format::Format, ir::Doc, printer::Printer}; type GroupId = u32; #[derive(Default)] @@ -55,19 +49,12 @@ pub struct Prettier<'a> { /// The stack of AST Nodes /// See - stack: Vec>, + stack: Vec<'a, AstKind<'a>>, group_id_builder: GroupIdBuilder, args: PrettierArgs, } -impl<'a> DocBuilder<'a> for Prettier<'a> { - #[inline] - fn allocator(&self) -> &'a Allocator { - self.allocator - } -} - impl<'a> Prettier<'a> { #[allow(clippy::needless_pass_by_value)] pub fn new(allocator: &'a Allocator, options: PrettierOptions) -> Self { @@ -75,7 +62,7 @@ impl<'a> Prettier<'a> { allocator, source_text: "", options, - stack: vec![], + stack: Vec::new_in(allocator), group_id_builder: GroupIdBuilder::default(), args: PrettierArgs::default(), } diff --git a/crates/oxc_prettier/src/macros.rs b/crates/oxc_prettier/src/macros.rs index ae0f967d219f5..ced992902c83d 100644 --- a/crates/oxc_prettier/src/macros.rs +++ b/crates/oxc_prettier/src/macros.rs @@ -1,15 +1,303 @@ -/// `p_vec!` macro, to support dynamic length of arguments. +//! Prettier IR builder macros +//! Ref: + +// NOTE: In addition to those defined here, there are still some that are not yet implemented. +// In terms of macro implementation, there are 2 forms: the most frequently used form and the most flexible form. + +/// Arrays are used to concatenate a list of `Doc`s to be printed sequentially into a single doc. +/// (In Prettier(.js) this is just an array literal.) +/// ``` +/// array!(p, [a, b, c]); +/// array!(p, vec); +/// ``` #[macro_export] -macro_rules! p_vec { - ($p:ident, $( $x:expr ),* $(,)?) => {{ - let mut temp_vec = $p.vec(); +macro_rules! array { + ($p:ident, [$( $x:expr ),* $(,)?]) => {{ + let mut temp_vec = oxc_allocator::Vec::new_in($p.allocator); $( temp_vec.push($x); )* - temp_vec + array!($p, temp_vec) + }}; + ($p:ident, $vec:expr) => {{ + $crate::ir::Doc::Array($vec) + }}; +} + +/// Strings are printed directly as is. +/// However for the algorithm to work properly they shouldn't contain line break characters. +/// (In Prettier(.js) this is just a string literal.) +/// ``` +/// text!("const"); +/// ``` +#[macro_export] +macro_rules! text { + ($str:expr) => {{ + let s: &'static str = $str; + $crate::ir::Doc::Str(s) + }}; +} + +/// Strings are printed directly as is. +/// However for the algorithm to work properly they shouldn't contain line break characters. +/// (In Prettier(.js) this is just a string literal.) +/// ``` +/// dynamic_text!(value.as_str()); +/// ``` +#[macro_export] +macro_rules! dynamic_text { + ($p:ident, $str:expr) => {{ + let s = oxc_allocator::String::from_str_in($str, $p.allocator).into_bump_str(); + $crate::ir::Doc::Str(s) }}; } +/// Mark a group of items which the printer should try to fit on one line. +/// This is the basic command to tell the printer when to break. +/// Groups are usually nested, and the printer will try to fit everything on one line, +/// but if it doesn't fit it will break the outermost group first and try again. +/// It will continue breaking groups until everything fits (or there are no more groups to break). +/// +/// A group is forced to break if it's created with the `should_break` option set to true or if it includes `break_parent`. +/// A hard and literal line breaks automatically include this so they always break parent groups. +/// Breaks are propagated to all parent groups, so if a deeply nested expression has a hard break, everything will break. +/// This only matters for "hard" breaks, i.e. newlines that are printed no matter what and can be statically analyzed. +/// +/// ``` +/// group!(p, [a, b, c], true, Some(group_id)); +/// group!(p, vec, true, None); +/// group!(p, [a, b, c]); +/// group!(p, vec); +/// ``` +#[macro_export] +macro_rules! group { + ($p:ident, [$( $x:expr ),* $(,)?], $should_break:expr, $group_id:expr) => {{ + let mut temp_vec = oxc_allocator::Vec::new_in($p.allocator); + $( + temp_vec.push($x); + )* + $crate::ir::Doc::Group($crate::ir::Group { + contents: temp_vec, + should_break: $should_break, + expanded_states: None, + group_id: $group_id, + }) + }}; + ($p:ident, $vec:expr, $should_break:expr, $group_id:expr) => {{ + $crate::ir::Doc::Group($crate::ir::Group { + contents: $vec, + should_break: $should_break, + expanded_states: None, + group_id: $group_id, + }) + }}; + ($p:ident, [$( $x:expr ),* $(,)?]) => {{ + let mut temp_vec = oxc_allocator::Vec::new_in($p.allocator); + $( + temp_vec.push($x); + )* + group!($p, temp_vec, false, None) + }}; + ($p:ident, $vec:expr) => {{ + group!($p, $vec, false, None) + }}; +} + +/// This should be used as last resort as it triggers an exponential complexity when nested. +/// This will try to print the first alternative, if it fit use it, otherwise go to the next one and so on. +/// The alternatives is an array of documents going from the least expanded (most flattened) representation first to the most expanded. +/// +/// ``` +/// conditional_group!(p, [a, b, c]); +/// ``` +#[macro_export] +macro_rules! conditional_group { + ($p:ident, [$doc:expr, $( $x:expr ),* $(,)?]) => {{ + let mut temp_single = oxc_allocator::Vec::with_capacity_in(1, $p.allocator); + temp_single.push($doc); + let mut temp_vec = oxc_allocator::Vec::new_in($p.allocator); + $( + temp_vec.push($x); + )* + + $crate::ir::Doc::Group($crate::ir::Group { + contents: temp_single, + should_break: false, + expanded_states: Some(temp_vec), + group_id: None, + }) + }}; +} + +/// This is an alternative type of group which behaves like text layout: +/// it's going to add a break whenever the next element doesn't fit in the line anymore. +/// The difference with `group` is that it's not going to break all the separators, just the ones that are at the end of lines. +/// +/// Expects the arguments to be an array of alternating content and line breaks. +/// In other words, elements with odd indices must be line breaks (e.g., `softline`). +/// +/// ``` +/// fill!(p, [a, line!(), b, line!(), c]); +/// fill!(p, vec); +/// ``` +#[macro_export] +macro_rules! fill { + ($p:ident, [$( $x:expr ),* $(,)?]) => {{ + let mut temp_vec = oxc_allocator::Vec::new_in($p.allocator); + $( + temp_vec.push($x); + )* + fill!($p, temp_vec) + }}; + ($p:ident, $vec:expr) => {{ + $crate::ir::Doc::Fill($crate::ir::Fill { contents: $vec }) + }}; +} + +/// Print something if the current group or the current element of fill breaks and something else if it doesn't. +/// `group_id` can be used to check another already printed group instead of the current group. +/// +/// If a `hardline` or `break_parent` is present within the possible contents, +/// the parent groups will be broken regardless of said content being printed, which might not be desirable. +/// This behaviour is a design limitation. +/// Usually the desired result can be achieved in a different way. +/// +/// ``` +/// if_break!(p, a, b, Some(group_id)); +/// if_break!(p, a); +/// ``` +#[macro_export] +macro_rules! if_break { + ($p:ident, $break:expr, $flat:expr, $group_id:expr) => {{ + $crate::ir::Doc::IfBreak($crate::ir::IfBreak { + break_contents: oxc_allocator::Box::new_in($break, $p.allocator), + flat_contents: oxc_allocator::Box::new_in($flat, $p.allocator), + group_id: $group_id, + }) + }}; + ($p:ident, $break:expr) => {{ + use $crate::text; + if_break!($p, $break, text!(""), None) + }}; +} + +/// Include this anywhere to force all parent groups to break. See `group` for more info. +/// +/// ``` +/// break_parent!(); +/// ``` +#[macro_export] +macro_rules! break_parent { + () => {{ + $crate::ir::Doc::BreakParent + }}; +} + +/// Join an array of docs with a separator. +/// +/// ``` +/// join!(p, JoinSeparator::Softline, vec); +/// ``` +#[macro_export] +macro_rules! join { + ($p:ident, $sep:expr, $vec:expr) => {{ + let mut parts = oxc_allocator::Vec::new_in($p.allocator); + for (i, doc) in $vec.into_iter().enumerate() { + if i != 0 { + match $sep { + $crate::ir::JoinSeparator::Softline => parts.push($crate::softline!()), + $crate::ir::JoinSeparator::Hardline => parts.extend($crate::hardline!()), + $crate::ir::JoinSeparator::CommaLine => { + parts.extend([$crate::text!(","), $crate::line!()]); + } + } + } + parts.push(doc); + } + $crate::ir::Doc::Array(parts) + }}; +} + +/// Specify a line break. +/// If an expression fits on one line, the line break will be replaced with a space. +/// Line breaks always indent the next line with the current level of indentation. +/// +/// ``` +/// line!(); +/// ``` +#[macro_export] +macro_rules! line { + () => {{ + $crate::ir::Doc::Line($crate::ir::Line::default()) + }}; +} + +/// Specify a line break. +/// The difference from line is that if the expression fits on one line, it will be replaced with nothing. +/// +/// ``` +/// softline!(); +/// ``` +#[macro_export] +macro_rules! softline { + () => {{ + $crate::ir::Doc::Line($crate::ir::Line { soft: true, ..Default::default() }) + }}; +} + +/// Specify a line break that is always included in the output, no matter if the expression fits on one line or not. +/// +/// ``` +/// hardline!(); +/// ``` +#[macro_export] +macro_rules! hardline { + () => {{ + let hardline = $crate::ir::Doc::Line($crate::ir::Line { hard: true, ..Default::default() }); + [hardline, $crate::ir::Doc::BreakParent] + }}; +} + +/// Increase the level of indentation. +/// +/// ``` +/// indent!(p, [a, b, c]); +/// indent!(p, vec); +/// ``` +#[macro_export] +macro_rules! indent { + ($p:ident, [$( $x:expr ),* $(,)?]) => {{ + let mut temp_vec = oxc_allocator::Vec::new_in($p.allocator); + $( + temp_vec.push($x); + )* + $crate::ir::Doc::Indent(temp_vec) + }}; + ($p:ident, $vec:expr) => {{ + $crate::ir::Doc::Indent($vec) + }}; +} + +/// An optimized version of `if_break(indent(doc), doc, group_id)`. +/// It doesn't make sense to apply `indent_if_break` to the current group, +/// because "indent if the current group is broken" is the normal behavior of indent. +/// That's why `group_id` is required. +/// +/// ``` +/// indent_if_break!(p, a, group_id); +/// ``` +#[macro_export] +macro_rules! indent_if_break { + ($p:ident, $doc:expr, $group_id:expr) => {{ + $crate::ir::Doc::IndentIfBreak($crate::ir::IndentIfBreak { + contents: oxc_allocator::Box::new_in($doc, $p.allocator), + group_id: $group_id, + }) + }}; +} + +// --- + /// `wrap!` macro, /// - to save the reference of the current node to be used as parent node later /// - to print parens and comments @@ -19,14 +307,14 @@ macro_rules! p_vec { #[macro_export] macro_rules! wrap { ($p:ident, $self:expr, $kind:ident, $block:block) => {{ - let kind = AstKind::$kind($p.alloc($self)); + let kind = oxc_ast::AstKind::$kind($p.alloc($self)); $p.enter_node(kind); let leading = $p.print_leading_comments(kind.span()); let doc = $block; let doc = if $p.need_parens(kind) { - $p.array(p_vec!($p, $p.text("("), doc, $p.text(")"))) + $crate::array!($p, [$crate::text!("("), doc, $crate::text!(")")]) } else { doc }; diff --git a/crates/oxc_prettier/src/printer/mod.rs b/crates/oxc_prettier/src/printer/mod.rs index 8a9a7690e1945..0adc776381fe3 100644 --- a/crates/oxc_prettier/src/printer/mod.rs +++ b/crates/oxc_prettier/src/printer/mod.rs @@ -11,7 +11,7 @@ use oxc_allocator::Allocator; use rustc_hash::FxHashMap; use crate::{ - ir::{Doc, DocBuilder, Fill, IfBreak, IndentIfBreak, Line}, + ir::{Doc, Fill, IfBreak, IndentIfBreak, Line}, printer::command::{Command, Indent, Mode}, GroupId, PrettierOptions, }; @@ -36,13 +36,6 @@ pub struct Printer<'a> { allocator: &'a Allocator, } -impl<'a> DocBuilder<'a> for Printer<'a> { - #[inline] - fn allocator(&self) -> &'a Allocator { - self.allocator - } -} - impl<'a> Printer<'a> { pub fn new( doc: Doc<'a>, @@ -292,7 +285,7 @@ impl<'a> Printer<'a> { let Some(second_content) = fill.dequeue() else { return; }; - let mut docs = self.vec(); + let mut docs = oxc_allocator::Vec::new_in(self.allocator); let content = content_flat_cmd.doc; docs.push(content); docs.push(whitespace_flat_cmd.doc);