From 386ce500f6798b65a6803396dbf975dd0ad1b420 Mon Sep 17 00:00:00 2001 From: Yuji Sugiura Date: Thu, 12 Dec 2024 10:56:42 +0900 Subject: [PATCH 1/8] Export and use array::is_consisely_printed_array --- crates/oxc_prettier/src/format/array.rs | 7 +++++++ crates/oxc_prettier/src/format/call_arguments.rs | 2 ++ tasks/prettier_conformance/snapshots/prettier.js.snap.md | 3 +-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/oxc_prettier/src/format/array.rs b/crates/oxc_prettier/src/format/array.rs index e56a5a6c2f94c..9d6ffdc07f591 100644 --- a/crates/oxc_prettier/src/format/array.rs +++ b/crates/oxc_prettier/src/format/array.rs @@ -127,6 +127,13 @@ pub fn print_array<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc<'a> { array!(p, parts) } +pub(super) fn is_concisely_printed_array<'a>(arr: &Expression<'a>) -> bool { + match arr { + Expression::ArrayExpression(array) => Array::ArrayExpression(array).is_concisely_printed(), + _ => false, + } +} + 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( diff --git a/crates/oxc_prettier/src/format/call_arguments.rs b/crates/oxc_prettier/src/format/call_arguments.rs index 498e044abc960..3707a45c536ea 100644 --- a/crates/oxc_prettier/src/format/call_arguments.rs +++ b/crates/oxc_prettier/src/format/call_arguments.rs @@ -6,6 +6,7 @@ use oxc_syntax::operator::UnaryOperator; use crate::{ array, break_parent, conditional_group, format::{ + array::{is_concisely_printed_array, Array}, call_expression::{is_commons_js_or_amd_call, CallExpressionLike}, misc, }, @@ -247,6 +248,7 @@ fn should_expand_last_arg(args: &Vec<'_, Argument<'_>>) -> bool { && (args.len() != 2 || !matches!(penultimate_arg, Some(Argument::ArrowFunctionExpression(_))) || !matches!(last_arg, Expression::ArrayExpression(_))) + && !(args.len() > 1 && is_concisely_printed_array(&last_arg)) } fn is_hopefully_short_call_argument(mut node: &Expression) -> bool { diff --git a/tasks/prettier_conformance/snapshots/prettier.js.snap.md b/tasks/prettier_conformance/snapshots/prettier.js.snap.md index a1cca16314434..f4923de8023b3 100644 --- a/tasks/prettier_conformance/snapshots/prettier.js.snap.md +++ b/tasks/prettier_conformance/snapshots/prettier.js.snap.md @@ -1,4 +1,4 @@ -js compatibility: 240/641 (37.44%) +js compatibility: 241/641 (37.60%) # Failed @@ -317,7 +317,6 @@ js compatibility: 240/641 (37.44%) * js/last-argument-expansion/issue-10708.js * js/last-argument-expansion/issue-7518.js * js/last-argument-expansion/jsx.js -* js/last-argument-expansion/number-only-array.js * js/last-argument-expansion/overflow.js ### js/line-suffix-boundary From 0669e2fa7e2a6647944c7559a9b2e45c30ab7d8d Mon Sep 17 00:00:00 2001 From: Yuji Sugiura Date: Thu, 12 Dec 2024 10:57:01 +0900 Subject: [PATCH 2/8] Align to use pub(super) --- crates/oxc_prettier/src/format/array.rs | 4 ++-- crates/oxc_prettier/src/format/assignment.rs | 2 +- crates/oxc_prettier/src/format/call_arguments.rs | 2 +- crates/oxc_prettier/src/format/call_expression.rs | 8 ++++---- crates/oxc_prettier/src/format/class.rs | 2 +- crates/oxc_prettier/src/format/module.rs | 2 +- crates/oxc_prettier/src/format/object.rs | 2 +- crates/oxc_prettier/src/format/template_literal.rs | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/oxc_prettier/src/format/array.rs b/crates/oxc_prettier/src/format/array.rs index 9d6ffdc07f591..28b23fffe3d70 100644 --- a/crates/oxc_prettier/src/format/array.rs +++ b/crates/oxc_prettier/src/format/array.rs @@ -12,7 +12,7 @@ use crate::{ }; #[allow(clippy::enum_variant_names)] -pub enum Array<'a, 'b> { +pub(super) enum Array<'a, 'b> { ArrayExpression(&'b ArrayExpression<'a>), TSTupleType(&'b TSTupleType<'a>), ArrayPattern(&'b ArrayPattern<'a>), @@ -61,7 +61,7 @@ impl Array<'_, '_> { } } -pub fn print_array<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc<'a> { +pub(super) fn print_array<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc<'a> { if arr.len() == 0 { return print_empty_array_elements(p, arr); } diff --git a/crates/oxc_prettier/src/format/assignment.rs b/crates/oxc_prettier/src/format/assignment.rs index bac328f243996..944a970d15119 100644 --- a/crates/oxc_prettier/src/format/assignment.rs +++ b/crates/oxc_prettier/src/format/assignment.rs @@ -266,7 +266,7 @@ fn has_complex_type_annotation(expr: &AssignmentLikeNode) -> bool { false } -fn is_arrow_function_variable_declarator(expr: &AssignmentLikeNode) -> bool { +pub(super) fn is_arrow_function_variable_declarator(expr: &AssignmentLikeNode) -> bool { match expr { AssignmentLikeNode::VariableDeclarator(variable_declarator) => { if let Some(Expression::ArrowFunctionExpression(_)) = &variable_declarator.init { diff --git a/crates/oxc_prettier/src/format/call_arguments.rs b/crates/oxc_prettier/src/format/call_arguments.rs index 3707a45c536ea..2ef6b57feffff 100644 --- a/crates/oxc_prettier/src/format/call_arguments.rs +++ b/crates/oxc_prettier/src/format/call_arguments.rs @@ -17,7 +17,7 @@ use crate::{ Format, Prettier, }; -pub fn print_call_arguments<'a>( +pub(super) fn print_call_arguments<'a>( p: &mut Prettier<'a>, expression: &CallExpressionLike<'a, '_>, ) -> Doc<'a> { diff --git a/crates/oxc_prettier/src/format/call_expression.rs b/crates/oxc_prettier/src/format/call_expression.rs index 0b53d0d2afc61..3c96611da8429 100644 --- a/crates/oxc_prettier/src/format/call_expression.rs +++ b/crates/oxc_prettier/src/format/call_expression.rs @@ -10,7 +10,7 @@ pub(super) enum CallExpressionLike<'a, 'b> { } impl<'a> CallExpressionLike<'a, '_> { - pub fn is_new(&self) -> bool { + fn is_new(&self) -> bool { matches!(self, CallExpressionLike::NewExpression(_)) } @@ -21,7 +21,7 @@ impl<'a> CallExpressionLike<'a, '_> { } } - pub fn optional(&self) -> bool { + fn optional(&self) -> bool { match self { CallExpressionLike::CallExpression(call) => call.optional, CallExpressionLike::NewExpression(new) => false, @@ -35,7 +35,7 @@ impl<'a> CallExpressionLike<'a, '_> { } } - pub fn type_parameters( + fn type_parameters( &self, ) -> Option<&oxc_allocator::Box<'a, TSTypeParameterInstantiation<'a>>> { match self { @@ -80,7 +80,7 @@ pub(super) fn print_call_expression<'a>( } /// -pub fn is_commons_js_or_amd_call<'a>( +pub(super) fn is_commons_js_or_amd_call<'a>( callee: &Expression<'a>, arguments: &Vec<'a, Argument<'a>>, ) -> bool { diff --git a/crates/oxc_prettier/src/format/class.rs b/crates/oxc_prettier/src/format/class.rs index 1182b5e0cf8b8..efdcf2b53013c 100644 --- a/crates/oxc_prettier/src/format/class.rs +++ b/crates/oxc_prettier/src/format/class.rs @@ -135,7 +135,7 @@ pub(super) fn print_class_body<'a>(p: &mut Prettier<'a>, class_body: &ClassBody< } #[derive(Debug)] -pub enum ClassMemberish<'a, 'b> { +pub(super) enum ClassMemberish<'a, 'b> { PropertyDefinition(&'b PropertyDefinition<'a>), AccessorProperty(&'b AccessorProperty<'a>), } diff --git a/crates/oxc_prettier/src/format/module.rs b/crates/oxc_prettier/src/format/module.rs index c044d90bf3a3b..6850ff5270b2e 100644 --- a/crates/oxc_prettier/src/format/module.rs +++ b/crates/oxc_prettier/src/format/module.rs @@ -81,7 +81,7 @@ fn print_semicolon_after_export_declaration<'a>( } } -pub fn print_module_specifiers<'a, T: Format<'a>>( +pub(super) fn print_module_specifiers<'a, T: Format<'a>>( p: &mut Prettier<'a>, specifiers: &Vec<'a, T>, include_default: bool, diff --git a/crates/oxc_prettier/src/format/object.rs b/crates/oxc_prettier/src/format/object.rs index aa411fb2b9b8e..d4efd77ed7aa9 100644 --- a/crates/oxc_prettier/src/format/object.rs +++ b/crates/oxc_prettier/src/format/object.rs @@ -14,7 +14,7 @@ use crate::{ }; #[derive(Debug, Clone, Copy)] -pub enum ObjectLike<'a, 'b> { +pub(super) enum ObjectLike<'a, 'b> { Expression(&'b ObjectExpression<'a>), AssignmentTarget(&'b ObjectAssignmentTarget<'a>), Pattern(&'b ObjectPattern<'a>), diff --git a/crates/oxc_prettier/src/format/template_literal.rs b/crates/oxc_prettier/src/format/template_literal.rs index e3e2cb3d46213..eb438bb0d030d 100644 --- a/crates/oxc_prettier/src/format/template_literal.rs +++ b/crates/oxc_prettier/src/format/template_literal.rs @@ -4,7 +4,7 @@ use oxc_ast::ast::*; use crate::{array, format::Format, ir::Doc, text, Prettier}; #[allow(clippy::enum_variant_names)] -pub enum TemplateLiteralPrinter<'a, 'b> { +pub(super) enum TemplateLiteralPrinter<'a, 'b> { TemplateLiteral(&'b TemplateLiteral<'a>), TSTemplateLiteralType(&'b TSTemplateLiteralType<'a>), } From 13384afc358254d887b1a8058d7f61164f3f1e5a Mon Sep 17 00:00:00 2001 From: Yuji Sugiura Date: Thu, 12 Dec 2024 11:44:19 +0900 Subject: [PATCH 3/8] Clean up print_block --- crates/oxc_prettier/src/format/block.rs | 11 ++--------- crates/oxc_prettier/src/format/mod.rs | 13 +++++-------- crates/oxc_prettier/src/format/statement.rs | 3 +-- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/crates/oxc_prettier/src/format/block.rs b/crates/oxc_prettier/src/format/block.rs index 3db38f9b5f411..a86d2fc264a94 100644 --- a/crates/oxc_prettier/src/format/block.rs +++ b/crates/oxc_prettier/src/format/block.rs @@ -11,7 +11,7 @@ pub(super) fn print_block<'a>( let mut parts = Vec::new_in(p.allocator); parts.push(text!("{")); - if let Some(doc) = print_block_body(p, stmts, directives, true, false) { + if let Some(doc) = print_block_body(p, stmts, directives) { parts.push({ let mut parts = Vec::new_in(p.allocator); parts.extend(hardline!()); @@ -52,8 +52,6 @@ pub(super) fn print_block_body<'a>( p: &mut Prettier<'a>, stmts: &[Statement<'a>], directives: Option<&[Directive<'a>]>, - remove_last_statement_hardline: bool, - is_root: bool, ) -> Option> { let has_directives = directives.is_some_and(|directives| !directives.is_empty()); let has_body = stmts.iter().any(|stmt| !matches!(stmt, Statement::EmptyStatement(_))); @@ -71,12 +69,7 @@ pub(super) fn print_block_body<'a>( } if has_body { - parts.extend(statement::print_statement_sequence( - p, - stmts, - remove_last_statement_hardline, - !is_root, - )); + parts.extend(statement::print_statement_sequence(p, stmts)); } Some(array!(p, parts)) diff --git a/crates/oxc_prettier/src/format/mod.rs b/crates/oxc_prettier/src/format/mod.rs index 9f1bdcf63babd..c69af9ee6d100 100644 --- a/crates/oxc_prettier/src/format/mod.rs +++ b/crates/oxc_prettier/src/format/mod.rs @@ -57,18 +57,15 @@ impl<'a> Format<'a> for Program<'a> { wrap!(p, self, Program, { let mut parts = Vec::new_in(p.allocator); + // In Prettier, this is treated as a comment if let Some(hashbang) = &self.hashbang { parts.push(hashbang.format(p)); } - if let Some(doc) = block::print_block_body( - p, - &self.body, - Some(&self.directives), - false, - /* is_root */ true, - ) { - parts.push(doc); + if let Some(body_doc) = block::print_block_body(p, &self.body, Some(&self.directives)) { + parts.push(body_doc); + // XXX: Prettier seems to add this, but test results don't match + // parts.extend(hardline!()); } array!(p, parts) diff --git a/crates/oxc_prettier/src/format/statement.rs b/crates/oxc_prettier/src/format/statement.rs index 15b65e0b1a4ab..1637f6c8ef87f 100644 --- a/crates/oxc_prettier/src/format/statement.rs +++ b/crates/oxc_prettier/src/format/statement.rs @@ -7,8 +7,6 @@ use crate::{hardline, ir::Doc, Format, Prettier}; pub(super) fn print_statement_sequence<'a>( p: &mut Prettier<'a>, stmts: &[Statement<'a>], - remove_last_statement_hardline: bool, - skip_empty_statement: bool, ) -> Vec<'a, Doc<'a>> { let mut parts = Vec::new_in(p.allocator); @@ -24,6 +22,7 @@ pub(super) fn print_statement_sequence<'a>( if Some(stmt.span()) != last_statement_span { parts.extend(hardline!()); + if p.is_next_line_empty(stmt.span()) { parts.extend(hardline!()); } From 9a87d0f524c2fbd7d18262a4a55bc049a6d77f45 Mon Sep 17 00:00:00 2001 From: Yuji Sugiura Date: Thu, 12 Dec 2024 13:32:23 +0900 Subject: [PATCH 4/8] Fix throw or return --- crates/oxc_prettier/src/format/class.rs | 4 ++-- crates/oxc_prettier/src/format/function.rs | 3 --- crates/oxc_prettier/src/format/mod.rs | 15 +++++++++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/crates/oxc_prettier/src/format/class.rs b/crates/oxc_prettier/src/format/class.rs index efdcf2b53013c..48aa5e971f0d1 100644 --- a/crates/oxc_prettier/src/format/class.rs +++ b/crates/oxc_prettier/src/format/class.rs @@ -6,9 +6,9 @@ use oxc_span::GetSpan; use crate::{ array, - format::{assignment, assignment::AssignmentLikeNode, JoinSeparator}, + format::{assignment, assignment::AssignmentLikeNode}, group, hardline, if_break, indent, - ir::Doc, + ir::{Doc, JoinSeparator}, join, line, softline, text, Format, Prettier, }; diff --git a/crates/oxc_prettier/src/format/function.rs b/crates/oxc_prettier/src/format/function.rs index 6e25884a6de9b..7f8dea2c97a07 100644 --- a/crates/oxc_prettier/src/format/function.rs +++ b/crates/oxc_prettier/src/format/function.rs @@ -150,12 +150,9 @@ fn print_method_value<'a>(p: &mut Prettier<'a>, function: &Function<'a>) -> Doc< pub(super) fn print_return_or_throw_argument<'a>( p: &mut Prettier<'a>, argument: Option<&Expression<'a>>, - is_return: bool, ) -> Doc<'a> { let mut parts = Vec::new_in(p.allocator); - parts.push(text!(if is_return { "return" } else { "throw" })); - if let Some(argument) = argument { parts.push(text!(" ")); parts.push( diff --git a/crates/oxc_prettier/src/format/mod.rs b/crates/oxc_prettier/src/format/mod.rs index c69af9ee6d100..b8d311a86c000 100644 --- a/crates/oxc_prettier/src/format/mod.rs +++ b/crates/oxc_prettier/src/format/mod.rs @@ -464,7 +464,13 @@ impl<'a> Format<'a> for SwitchCase<'a> { impl<'a> Format<'a> for ReturnStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, ReturnStatement, { - function::print_return_or_throw_argument(p, self.argument.as_ref(), true) + array!( + p, + [ + text!("return"), + function::print_return_or_throw_argument(p, self.argument.as_ref()) + ] + ) }) } } @@ -523,7 +529,12 @@ impl<'a> Format<'a> for CatchClause<'a> { impl<'a> Format<'a> for ThrowStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - function::print_return_or_throw_argument(p, Some(&self.argument), false) + wrap!(p, self, ThrowStatement, { + array!( + p, + [text!("throw"), function::print_return_or_throw_argument(p, Some(&self.argument))] + ) + }) } } From fe9bb321ef739ef3d07225267f28d2595ab9268f Mon Sep 17 00:00:00 2001 From: Yuji Sugiura Date: Thu, 12 Dec 2024 13:45:47 +0900 Subject: [PATCH 5/8] Export function::print_method_value --- crates/oxc_prettier/src/format/function.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/oxc_prettier/src/format/function.rs b/crates/oxc_prettier/src/format/function.rs index 7f8dea2c97a07..4fe8ecf6fd526 100644 --- a/crates/oxc_prettier/src/format/function.rs +++ b/crates/oxc_prettier/src/format/function.rs @@ -119,7 +119,7 @@ pub(super) fn print_method<'a>(p: &mut Prettier<'a>, method: &MethodDefinition<' array!(p, parts) } -fn print_method_value<'a>(p: &mut Prettier<'a>, function: &Function<'a>) -> Doc<'a> { +pub(super) fn print_method_value<'a>(p: &mut Prettier<'a>, function: &Function<'a>) -> Doc<'a> { let mut parts = Vec::new_in(p.allocator); let parameters_doc = function.params.format(p); let should_group_parameters = should_group_function_parameters(function); From 20c3f7e63d8550f1949e16beae92bcdd06b66eb3 Mon Sep 17 00:00:00 2001 From: Yuji Sugiura Date: Thu, 12 Dec 2024 14:26:31 +0900 Subject: [PATCH 6/8] Rename print_object --- crates/oxc_prettier/src/format/mod.rs | 10 +++++----- crates/oxc_prettier/src/format/object.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/oxc_prettier/src/format/mod.rs b/crates/oxc_prettier/src/format/mod.rs index b8d311a86c000..e34ee3b950483 100644 --- a/crates/oxc_prettier/src/format/mod.rs +++ b/crates/oxc_prettier/src/format/mod.rs @@ -1057,7 +1057,7 @@ impl<'a> Format<'a> for TSTupleType<'a> { impl<'a> Format<'a> for TSTypeLiteral<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - object::print_object_properties(p, ObjectLike::TSTypeLiteral(self)) + object::print_object(p, ObjectLike::TSTypeLiteral(self)) } } @@ -1636,7 +1636,7 @@ impl<'a> Format<'a> for ImportNamespaceSpecifier<'a> { 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)); + let with_clause_doc = object::print_object(p, ObjectLike::WithClause(self)); array!(p, [attribute_keyword_doc, text!(" "), with_clause_doc]) } } @@ -2019,7 +2019,7 @@ impl<'a> Format<'a> for ArrayExpression<'a> { impl<'a> Format<'a> for ObjectExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, ObjectExpression, { - object::print_object_properties(p, ObjectLike::Expression(self)) + object::print_object(p, ObjectLike::Expression(self)) }) } } @@ -2338,7 +2338,7 @@ impl<'a> Format<'a> for AssignmentTargetMaybeDefault<'a> { impl<'a> Format<'a> for ObjectAssignmentTarget<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - object::print_object_properties(p, ObjectLike::AssignmentTarget(self)) + object::print_object(p, ObjectLike::AssignmentTarget(self)) } } @@ -2904,7 +2904,7 @@ impl<'a> Format<'a> for BindingPattern<'a> { impl<'a> Format<'a> for ObjectPattern<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, ObjectPattern, { - object::print_object_properties(p, ObjectLike::Pattern(self)) + object::print_object(p, ObjectLike::Pattern(self)) }) } } diff --git a/crates/oxc_prettier/src/format/object.rs b/crates/oxc_prettier/src/format/object.rs index d4efd77ed7aa9..6d4efa95f8a30 100644 --- a/crates/oxc_prettier/src/format/object.rs +++ b/crates/oxc_prettier/src/format/object.rs @@ -98,7 +98,7 @@ impl<'a, 'b> ObjectLike<'a, 'b> { } } -pub(super) fn print_object_properties<'a>( +pub(super) fn print_object<'a>( p: &mut Prettier<'a>, object: ObjectLike<'a, '_>, ) -> Doc<'a> { From f515cb81a218d147f35b1b625ef1b089464c9ae1 Mon Sep 17 00:00:00 2001 From: Yuji Sugiura Date: Fri, 13 Dec 2024 15:22:25 +0900 Subject: [PATCH 7/8] Arrange directories --- crates/oxc_prettier/src/format/js.rs | 1757 ++++++++++ crates/oxc_prettier/src/format/jsx.rs | 270 ++ crates/oxc_prettier/src/format/mod.rs | 3114 +---------------- .../src/format/{ => print}/array.rs | 6 +- .../src/format/{ => print}/arrow_function.rs | 2 +- .../src/format/{ => print}/assignment.rs | 12 +- .../src/format/{ => print}/binaryish.rs | 4 +- .../src/format/{ => print}/block.rs | 6 +- .../src/format/{ => print}/call_arguments.rs | 4 +- .../src/format/{ => print}/call_expression.rs | 14 +- .../src/format/{ => print}/class.rs | 24 +- .../src/format/{ => print}/function.rs | 12 +- .../format/{ => print}/function_parameters.rs | 6 +- .../src/format/{ => print}/misc.rs | 6 +- crates/oxc_prettier/src/format/print/mod.rs | 18 + .../src/format/{ => print}/module.rs | 7 +- .../src/format/{ => print}/object.rs | 14 +- .../src/format/{ => print}/property.rs | 6 +- .../src/format/{ => print}/statement.rs | 2 +- .../src/format/{ => print}/string.rs | 6 +- .../format/{ => print}/template_literal.rs | 4 +- .../src/format/{ => print}/ternary.rs | 2 +- crates/oxc_prettier/src/format/typescript.rs | 1085 ++++++ 23 files changed, 3195 insertions(+), 3186 deletions(-) create mode 100644 crates/oxc_prettier/src/format/js.rs create mode 100644 crates/oxc_prettier/src/format/jsx.rs rename crates/oxc_prettier/src/format/{ => print}/array.rs (98%) rename crates/oxc_prettier/src/format/{ => print}/arrow_function.rs (96%) rename crates/oxc_prettier/src/format/{ => print}/assignment.rs (97%) rename crates/oxc_prettier/src/format/{ => print}/binaryish.rs (97%) rename crates/oxc_prettier/src/format/{ => print}/block.rs (93%) rename crates/oxc_prettier/src/format/{ => print}/call_arguments.rs (99%) rename crates/oxc_prettier/src/format/{ => print}/call_expression.rs (89%) rename crates/oxc_prettier/src/format/{ => print}/class.rs (94%) rename crates/oxc_prettier/src/format/{ => print}/function.rs (90%) rename crates/oxc_prettier/src/format/{ => print}/function_parameters.rs (97%) rename crates/oxc_prettier/src/format/{ => print}/misc.rs (87%) create mode 100644 crates/oxc_prettier/src/format/print/mod.rs rename crates/oxc_prettier/src/format/{ => print}/module.rs (96%) rename crates/oxc_prettier/src/format/{ => print}/object.rs (95%) rename crates/oxc_prettier/src/format/{ => print}/property.rs (78%) rename crates/oxc_prettier/src/format/{ => print}/statement.rs (94%) rename crates/oxc_prettier/src/format/{ => print}/string.rs (93%) rename crates/oxc_prettier/src/format/{ => print}/template_literal.rs (94%) rename crates/oxc_prettier/src/format/{ => print}/ternary.rs (80%) create mode 100644 crates/oxc_prettier/src/format/typescript.rs diff --git a/crates/oxc_prettier/src/format/js.rs b/crates/oxc_prettier/src/format/js.rs new file mode 100644 index 0000000000000..c64ea002a27d7 --- /dev/null +++ b/crates/oxc_prettier/src/format/js.rs @@ -0,0 +1,1757 @@ +use std::borrow::Cow; + +use cow_utils::CowUtils; +use oxc_allocator::Vec; +use oxc_ast::{ast::*, AstKind}; +use oxc_span::GetSpan; +use oxc_syntax::identifier::{is_identifier_name, is_line_terminator}; + +use crate::{ + array, dynamic_text, + format::{ + print::{ + array, arrow_function, assignment, binaryish, block, call_expression, class, function, + function_parameters, misc, module, object, property, string, template_literal, ternary, + }, + Format, + }, + group, hardline, indent, + ir::{Doc, JoinSeparator}, + join, line, softline, text, wrap, Prettier, +}; + +impl<'a> Format<'a> for Program<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, Program, { + let mut parts = Vec::new_in(p.allocator); + + // In Prettier, this is treated as a comment + if let Some(hashbang) = &self.hashbang { + parts.push(hashbang.format(p)); + } + + if let Some(body_doc) = block::print_block_body(p, &self.body, Some(&self.directives)) { + parts.push(body_doc); + // XXX: Prettier seems to add this, but test results don't match + // parts.extend(hardline!()); + } + + array!(p, parts) + }) + } +} + +impl<'a> Format<'a> for Hashbang<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + 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(hardline!()); + } + } + array!(p, parts) + } +} + +impl<'a> Format<'a> for Directive<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + parts.push(dynamic_text!( + p, + string::print_string(p, self.directive.as_str(), p.options.single_quote,) + )); + if let Some(semi) = p.semi() { + parts.push(semi); + } + parts.extend(hardline!()); + array!(p, parts) + } +} + +impl<'a> Format<'a> for Statement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + Self::BlockStatement(stmt) => stmt.format(p), + Self::BreakStatement(stmt) => stmt.format(p), + Self::ContinueStatement(stmt) => stmt.format(p), + Self::DebuggerStatement(stmt) => stmt.format(p), + Self::DoWhileStatement(stmt) => stmt.format(p), + Self::EmptyStatement(stmt) => stmt.format(p), + Self::ExpressionStatement(stmt) => stmt.format(p), + Self::ForInStatement(stmt) => stmt.format(p), + Self::ForOfStatement(stmt) => stmt.format(p), + Self::ForStatement(stmt) => stmt.format(p), + Self::IfStatement(stmt) => stmt.format(p), + Self::LabeledStatement(stmt) => stmt.format(p), + Self::ReturnStatement(stmt) => stmt.format(p), + Self::SwitchStatement(stmt) => stmt.format(p), + Self::ThrowStatement(stmt) => stmt.format(p), + Self::TryStatement(stmt) => stmt.format(p), + Self::WhileStatement(stmt) => stmt.format(p), + Self::WithStatement(stmt) => stmt.format(p), + match_module_declaration!(Self) => self.to_module_declaration().format(p), + match_declaration!(Self) => self.to_declaration().format(p), + } + } +} + +impl<'a> Format<'a> for ExpressionStatement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ExpressionStatement, { + let mut parts = Vec::new_in(p.allocator); + parts.push(self.expression.format(p)); + if let Some(semi) = p.semi() { + parts.push(semi); + } + array!(p, parts) + }) + } +} + +impl<'a> Format<'a> for EmptyStatement { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("") + } +} + +impl<'a> Format<'a> for IfStatement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, IfStatement, { + let mut parts = Vec::new_in(p.allocator); + + let test_doc = self.test.format(p); + let consequent = self.consequent.format(p); + let consequent = misc::adjust_clause(p, &self.consequent, consequent, false); + + let opening = group!( + p, + [ + 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(text!(" ")); + } else { + parts.extend(hardline!()); + } + parts.push(text!("else")); + let alternate_doc = alternate.format(p); + parts.push(group!( + p, + [misc::adjust_clause( + p, + alternate, + alternate_doc, + matches!(alternate, Statement::IfStatement(_)), + )] + )); + } + + array!(p, parts) + }) + } +} + +impl<'a> Format<'a> for BlockStatement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, BlockStatement, { block::print_block(p, &self.body, None) }) + } +} + +impl<'a> Format<'a> for ForStatement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ForStatement, { + let body = self.body.format(p); + let body = misc::adjust_clause(p, &self.body, body, false); + + if self.init.is_none() && self.test.is_none() && self.update.is_none() { + return group!(p, [text!("for (;;)"), body]); + } + + let parts_head = { + let mut parts_head = Vec::new_in(p.allocator); + parts_head.push(softline!()); + if let Some(init) = &self.init { + parts_head.push(init.format(p)); + } + parts_head.push(text!(";")); + parts_head.push(line!()); + if let Some(init) = &self.test { + parts_head.push(init.format(p)); + } + parts_head.push(text!(";")); + parts_head.push(line!()); + if let Some(init) = &self.update { + parts_head.push(init.format(p)); + } + indent!(p, parts_head) + }; + + group!(p, [text!("for ("), group!(p, [parts_head, softline!()]), text!(")"), body,]) + }) + } +} + +impl<'a> Format<'a> for ForStatementInit<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + ForStatementInit::VariableDeclaration(v) => v.format(p), + match_expression!(ForStatementInit) => self.to_expression().format(p), + } + } +} + +impl<'a> Format<'a> for ForInStatement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ForInStatement, { + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("for (")); + parts.push(self.left.format(p)); + parts.push(text!(" in ")); + parts.push(self.right.format(p)); + parts.push(text!(")")); + let body = self.body.format(p); + parts.push(misc::adjust_clause(p, &self.body, body, false)); + group!(p, parts) + }) + } +} + +impl<'a> Format<'a> for ForOfStatement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ForOfStatement, { + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("for")); + if self.r#await { + parts.push(text!(" await")); + } + parts.push(text!(" (")); + parts.push(self.left.format(p)); + parts.push(text!(" of ")); + parts.push(self.right.format(p)); + parts.push(text!(")")); + let body = self.body.format(p); + parts.push(misc::adjust_clause(p, &self.body, body, false)); + group!(p, parts) + }) + } +} + +impl<'a> Format<'a> for ForStatementLeft<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + ForStatementLeft::VariableDeclaration(v) => v.format(p), + match_assignment_target!(ForStatementLeft) => self.to_assignment_target().format(p), + } + } +} + +impl<'a> Format<'a> for WhileStatement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, WhileStatement, { + let mut parts = Vec::new_in(p.allocator); + + parts.push(text!("while (")); + let test_doc = self.test.format(p); + 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)); + + group!(p, parts) + }) + } +} + +impl<'a> Format<'a> for DoWhileStatement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, DoWhileStatement, { + 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 = group!(p, [text!("do"), clause]); + + parts.push(do_body); + + if matches!(self.body, Statement::BlockStatement(_)) { + parts.push(text!(" ")); + } else { + parts.extend(hardline!()); + } + + parts.push(text!("while (")); + let test_doc = self.test.format(p); + parts.push(group!(p, [indent!(p, [softline!(), test_doc]), softline!()])); + parts.push(text!(")")); + if let Some(semi) = p.semi() { + parts.push(semi); + } + + array!(p, parts) + }) + } +} + +impl<'a> Format<'a> for ContinueStatement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("continue")); + + if let Some(label) = &self.label { + parts.push(text!(" ")); + parts.push(label.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for BreakStatement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("break")); + + if let Some(label) = &self.label { + parts.push(text!(" ")); + parts.push(label.format(p)); + } + + if p.options.semi { + parts.push(text!(";")); + } + + 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 = Vec::new_in(p.allocator); + + let mut header_parts = Vec::new_in(p.allocator); + + header_parts.push(text!("switch (")); + + let discriminant_doc = self.discriminant.format(p); + header_parts.push(indent!(p, [softline!(), discriminant_doc])); + + header_parts.push(softline!()); + header_parts.push(text!(")")); + + parts.push(group!(p, header_parts)); + + parts.push(text!(" {")); + + 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 = Vec::new_in(p.allocator); + parts.extend(hardline!()); + parts.push(case.format(p)); + indent!(p, parts) + }); + if i != len - 1 && p.is_next_line_empty(case.span) { + cases_parts.extend(hardline!()); + } + } + parts.extend(cases_parts); + + parts.extend(hardline!()); + parts.push(text!("}")); + + array!(p, parts) + }) + } +} + +impl<'a> Format<'a> for SwitchCase<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + if let Some(test) = &self.test { + parts.push(text!("case ")); + parts.push(test.format(p)); + parts.push(text!(":")); + } else { + parts.push(text!("default:")); + } + + let consequent: Vec<_> = Vec::from_iter_in( + self.consequent.iter().filter(|c| !matches!(c, Statement::EmptyStatement(_))), + p.allocator, + ); + let len = consequent.len(); + let is_only_one_block_statement = + len == 1 && matches!(self.consequent[0], Statement::BlockStatement(_)); + + let 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(hardline!()); + } + } + + if is_only_one_block_statement { + consequent_parts.push(text!(" ")); + } else { + consequent_parts.extend(hardline!()); + } + consequent_parts.push(stmt.format(p)); + } + + if !consequent_parts.is_empty() { + if is_only_one_block_statement { + parts.extend(consequent_parts); + } else { + parts.push(indent!(p, [group!(p, consequent_parts)])); + } + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for ReturnStatement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ReturnStatement, { + array!( + p, + [ + text!("return"), + function::print_return_or_throw_argument(p, self.argument.as_ref()) + ] + ) + }) + } +} + +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 array!(p, [label_doc, text!(":;")]); + } + + let label_doc = self.label.format(p); + let body_doc = self.body.format(p); + 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 = Vec::new_in(p.allocator); + + parts.push(text!("try ")); + parts.push(self.block.format(p)); + if let Some(handler) = &self.handler { + parts.push(text!(" ")); + parts.push(handler.format(p)); + } + if let Some(finalizer) = &self.finalizer { + parts.push(text!(" finally ")); + parts.push(finalizer.format(p)); + } + + array!(p, parts) + }) + } +} + +impl<'a> Format<'a> for CatchClause<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, CatchClause, { + let mut parts = Vec::new_in(p.allocator); + + parts.push(text!("catch ")); + if let Some(param) = &self.param { + parts.push(text!("(")); + parts.push(param.pattern.format(p)); + parts.push(text!(") ")); + } + parts.push(self.body.format(p)); + + array!(p, parts) + }) + } +} + +impl<'a> Format<'a> for ThrowStatement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ThrowStatement, { + array!( + p, + [text!("throw"), function::print_return_or_throw_argument(p, Some(&self.argument))] + ) + }) + } +} + +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); + group!( + p, + [ + 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 = Vec::new_in(p.allocator); + parts.push(text!("debugger")); + + if p.options.semi { + parts.push(text!(";")); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for ModuleDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ModuleDeclaration, { + if let ModuleDeclaration::ImportDeclaration(decl) = self { + decl.format(p) + } else { + module::print_export_declaration(p, self) + } + }) + } +} + +impl<'a> Format<'a> for Declaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + Self::VariableDeclaration(stmt) => stmt.format(p), + Self::FunctionDeclaration(stmt) => stmt.format(p), + Self::ClassDeclaration(decl) => decl.format(p), + Self::TSTypeAliasDeclaration(decl) => decl.format(p), + Self::TSInterfaceDeclaration(decl) => decl.format(p), + Self::TSEnumDeclaration(decl) => decl.format(p), + Self::TSModuleDeclaration(decl) => decl.format(p), + Self::TSImportEqualsDeclaration(decl) => decl.format(p), + } + } +} + +impl<'a> Format<'a> for VariableDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, VariableDeclaration, { + // We generally want to terminate all variable declarations with a + // semicolon, except when they in the () part of for loops. + let parent_for_loop = match p.parent_kind() { + AstKind::ForStatement(stmt) => Some(stmt.body.span()), + AstKind::ForInStatement(stmt) => Some(stmt.body.span()), + AstKind::ForOfStatement(stmt) => Some(stmt.body.span()), + _ => None, + }; + + let kind = self.kind.as_str(); + + let mut parts = Vec::new_in(p.allocator); + + if self.declare { + parts.push(text!("declare ")); + } + + 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 = Vec::new_in(p.allocator); + if i != 0 { + d_parts.push(text!(",")); + if is_hardline { + d_parts.extend(hardline!()); + } else { + d_parts.push(line!()); + } + } + d_parts.push(decl.format(p)); + indent!(p, d_parts) + } else { + decl.format(p) + } + })); + + if !parent_for_loop.is_some_and(|span| span != self.span) { + if let Some(semi) = p.semi() { + parts.push(semi); + } + } + + group!(p, parts) + }) + } +} + +impl<'a> Format<'a> for VariableDeclarator<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, VariableDeclarator, { assignment::print_variable_declarator(p, self) }) + } +} + +impl<'a> Format<'a> for Function<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, Function, { function::print_function(p, self, None) }) + } +} + +impl<'a> Format<'a> for FunctionBody<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, FunctionBody, { + block::print_block(p, &self.statements, Some(&self.directives)) + }) + } +} + +impl<'a> Format<'a> for FormalParameters<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, FormalParameters, { + function_parameters::print_function_parameters(p, self) + }) + } +} + +impl<'a> Format<'a> for FormalParameter<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, FormalParameter, { self.pattern.format(p) }) + } +} + +impl<'a> Format<'a> for ImportDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("import")); + if self.import_kind.is_type() { + parts.push(text!(" type")); + } + + if let Some(specifiers) = &self.specifiers { + let is_default = specifiers.first().is_some_and(|x| { + matches!(x, ImportDeclarationSpecifier::ImportDefaultSpecifier(_)) + }); + + let validate_namespace = |x: &ImportDeclarationSpecifier| { + matches!(x, ImportDeclarationSpecifier::ImportNamespaceSpecifier(_)) + }; + + let is_namespace = specifiers.first().is_some_and(validate_namespace) + || specifiers.get(1).is_some_and(validate_namespace); + + parts.push(module::print_module_specifiers(p, specifiers, is_default, is_namespace)); + parts.push(text!(" from")); + } + parts.push(text!(" ")); + parts.push(self.source.format(p)); + + if let Some(with_clause) = &self.with_clause { + parts.push(text!(" ")); + parts.push(with_clause.format(p)); + } + + if let Some(semi) = p.semi() { + parts.push(semi); + } + array!(p, parts) + } +} + +impl<'a> Format<'a> for ImportDeclarationSpecifier<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + Self::ImportSpecifier(specifier) => specifier.format(p), + Self::ImportDefaultSpecifier(specifier) => specifier.format(p), + Self::ImportNamespaceSpecifier(specifier) => specifier.format(p), + } + } +} + +impl<'a> Format<'a> for ImportSpecifier<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + 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); + array!(p, [typed, local_doc]) + } else { + let imported_doc = self.imported.format(p); + let local_doc = self.local.format(p); + array!(p, [typed, imported_doc, text!(" as "), local_doc]) + } + } +} + +impl<'a> Format<'a> for ImportDefaultSpecifier<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + self.local.format(p) + } +} + +impl<'a> Format<'a> for ImportNamespaceSpecifier<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let local_doc = self.local.format(p); + array!(p, [text!("* as "), local_doc]) + } +} + +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(p, object::ObjectLike::WithClause(self)); + array!(p, [attribute_keyword_doc, text!(" "), with_clause_doc]) + } +} + +impl<'a> Format<'a> for ImportAttribute<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let key_doc = self.key.format(p); + let value_doc = self.value.format(p); + array!(p, [key_doc, text!(": "), value_doc]) + } +} + +impl<'a> Format<'a> for ImportAttributeKey<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + Self::Identifier(ident) => ident.format(p), + Self::StringLiteral(literal) => literal.format(p), + } + } +} + +impl<'a> Format<'a> for ExportNamedDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + if let Some(decl) = &self.declaration { + parts.push(text!(" ")); + parts.push(decl.format(p)); + } else { + parts.push(module::print_module_specifiers( + p, + &self.specifiers, + /* include_default */ false, + /* include_namespace */ false, + )); + } + array!(p, parts) + } +} + +impl<'a> Format<'a> for ExportSpecifier<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + if self.exported.span() == self.local.span() { + self.local.format(p) + } else { + let local_doc = self.local.format(p); + let exported_doc = self.exported.format(p); + array!(p, [local_doc, text!(" as "), exported_doc]) + } + } +} + +impl<'a> Format<'a> for ModuleExportName<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + Self::IdentifierName(ident) => ident.format(p), + Self::IdentifierReference(ident) => ident.format(p), + Self::StringLiteral(literal) => literal.format(p), + } + } +} + +impl<'a> Format<'a> for ExportAllDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + parts.push(text!(" *")); + if let Some(exported) = &self.exported { + parts.push(text!(" as ")); + parts.push(exported.format(p)); + } + array!(p, parts) + } +} + +impl<'a> Format<'a> for ExportDefaultDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + self.declaration.format(p) + } +} +impl<'a> Format<'a> for ExportDefaultDeclarationKind<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + match_expression!(Self) => self.to_expression().format(p), + Self::FunctionDeclaration(decl) => decl.format(p), + Self::ClassDeclaration(decl) => decl.format(p), + Self::TSInterfaceDeclaration(decl) => decl.format(p), + } + } +} + +impl<'a> Format<'a> for Expression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + Self::BooleanLiteral(lit) => lit.format(p), + Self::NullLiteral(lit) => lit.format(p), + Self::NumericLiteral(lit) => lit.format(p), + Self::BigIntLiteral(lit) => lit.format(p), + Self::RegExpLiteral(lit) => lit.format(p), + Self::StringLiteral(lit) => lit.format(p), + Self::Identifier(ident) => ident.format(p), + Self::ThisExpression(expr) => expr.format(p), + match_member_expression!(Self) => self.to_member_expression().format(p), + Self::CallExpression(expr) => expr.format(p), + Self::ArrayExpression(expr) => expr.format(p), + Self::ObjectExpression(expr) => expr.format(p), + Self::FunctionExpression(expr) => expr.format(p), + Self::ArrowFunctionExpression(expr) => expr.format(p), + Self::YieldExpression(expr) => expr.format(p), + Self::UpdateExpression(expr) => expr.format(p), + Self::UnaryExpression(expr) => expr.format(p), + Self::BinaryExpression(expr) => expr.format(p), + Self::PrivateInExpression(expr) => expr.format(p), + Self::LogicalExpression(expr) => expr.format(p), + Self::ConditionalExpression(expr) => expr.format(p), + Self::AssignmentExpression(expr) => expr.format(p), + Self::SequenceExpression(expr) => expr.format(p), + Self::ParenthesizedExpression(expr) => expr.format(p), + Self::ImportExpression(expr) => expr.format(p), + Self::TemplateLiteral(literal) => literal.format(p), + Self::TaggedTemplateExpression(expr) => expr.format(p), + Self::Super(sup) => sup.format(p), + Self::AwaitExpression(expr) => expr.format(p), + Self::ChainExpression(expr) => expr.format(p), + Self::NewExpression(expr) => expr.format(p), + Self::MetaProperty(expr) => expr.format(p), + Self::ClassExpression(expr) => expr.format(p), + Self::JSXElement(el) => el.format(p), + Self::JSXFragment(fragment) => fragment.format(p), + Self::TSAsExpression(expr) => expr.format(p), + Self::TSSatisfiesExpression(expr) => expr.format(p), + Self::TSTypeAssertion(expr) => expr.format(p), + Self::TSNonNullExpression(expr) => expr.format(p), + Self::TSInstantiationExpression(expr) => expr.format(p), + } + } +} + +impl<'a> Format<'a> for IdentifierReference<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + 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> { + 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, { dynamic_text!(p, self.name.as_str()) }) + } +} + +impl<'a> Format<'a> for LabelIdentifier<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + dynamic_text!(p, self.name.as_str()) + } +} + +impl<'a> Format<'a> for BooleanLiteral { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!(if self.value { "true" } else { "false" }) + } +} + +impl<'a> Format<'a> for NullLiteral { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("null") + } +} + +impl<'a> Format<'a> for NumericLiteral<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, NumericLiteral, { + // See https://github.com/prettier/prettier/blob/3.3.3/src/utils/print-number.js + // Perf: the regexes from prettier code above are ported to manual search for performance reasons. + let mut string = self.span.source_text(p.source_text).cow_to_ascii_lowercase(); + + // Remove unnecessary plus and zeroes from scientific notation. + if let Some((head, tail)) = string.split_once('e') { + let negative = if tail.starts_with('-') { "-" } else { "" }; + let trimmed = tail.trim_start_matches(['+', '-']).trim_start_matches('0'); + if trimmed.starts_with(|c: char| c.is_ascii_digit()) { + string = Cow::Owned(std::format!("{head}e{negative}{trimmed}")); + } + } + + // Remove unnecessary scientific notation (1e0). + if let Some((head, tail)) = string.split_once('e') { + if tail.trim_start_matches(['+', '-']).trim_start_matches('0').is_empty() { + string = Cow::Owned(head.to_string()); + } + } + + // Make sure numbers always start with a digit. + if string.starts_with('.') { + string = Cow::Owned(std::format!("0{string}")); + } + + // Remove extraneous trailing decimal zeroes. + if let Some((head, tail)) = string.split_once('.') { + if let Some((head_e, tail_e)) = tail.split_once('e') { + if !head_e.is_empty() { + let trimmed = head_e.trim_end_matches('0'); + if trimmed.is_empty() { + string = Cow::Owned(std::format!("{head}.0e{tail_e}")); + } else { + string = Cow::Owned(std::format!("{head}.{trimmed}e{tail_e}")); + } + } + } else if !tail.is_empty() { + let trimmed = tail.trim_end_matches('0'); + if trimmed.is_empty() { + string = Cow::Owned(std::format!("{head}.0")); + } else { + string = Cow::Owned(std::format!("{head}.{trimmed}")); + } + } + } + + // Remove trailing dot. + if let Some((head, tail)) = string.split_once('.') { + if tail.is_empty() { + string = Cow::Owned(head.to_string()); + } else if tail.starts_with('e') { + string = Cow::Owned(std::format!("{head}{tail}")); + } + } + + dynamic_text!(p, &string) + }) + } +} + +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) => 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 = 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)); + array!(p, parts) + } +} + +impl<'a> Format<'a> for StringLiteral<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'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 + 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> { + text!("this") + } +} + +impl<'a> Format<'a> for MemberExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, MemberExpression, { + match self { + Self::ComputedMemberExpression(expr) => expr.format(p), + Self::StaticMemberExpression(expr) => expr.format(p), + Self::PrivateFieldExpression(expr) => expr.format(p), + } + }) + } +} + +impl<'a> Format<'a> for ComputedMemberExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + parts.push(self.object.format(p)); + if self.optional { + parts.push(text!("?.")); + } + parts.push(text!("[")); + parts.push(self.expression.format(p)); + 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 = Vec::new_in(p.allocator); + parts.push(self.object.format(p)); + if self.optional { + parts.push(text!("?")); + } + parts.push(text!(".")); + parts.push(self.property.format(p)); + array!(p, parts) + } +} + +impl<'a> Format<'a> for PrivateFieldExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + parts.push(self.object.format(p)); + parts.push(if self.optional { text!("?.") } else { text!(".") }); + parts.push(self.field.format(p)); + array!(p, parts) + } +} + +impl<'a> Format<'a> for CallExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, CallExpression, { + call_expression::print_call_expression( + p, + &call_expression::CallExpressionLike::CallExpression(self), + ) + }) + } +} + +impl<'a> Format<'a> for Argument<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + match_expression!(Self) => self.to_expression().format(p), + Self::SpreadElement(expr) => expr.format(p), + } + } +} + +impl<'a> Format<'a> for ArrayExpressionElement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + Self::SpreadElement(expr) => expr.format(p), + match_expression!(Self) => self.to_expression().format(p), + Self::Elision(elision) => text!(""), + } + } +} + +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); + array!(p, [text!("..."), argument_doc]) + }) + } +} + +impl<'a> Format<'a> for ArrayExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ArrayExpression, { + array::print_array(p, &array::Array::ArrayExpression(self)) + }) + } +} + +impl<'a> Format<'a> for ObjectExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ObjectExpression, { + object::print_object(p, object::ObjectLike::Expression(self)) + }) + } +} + +impl<'a> Format<'a> for ObjectPropertyKind<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + ObjectPropertyKind::ObjectProperty(prop) => prop.format(p), + ObjectPropertyKind::SpreadProperty(prop) => prop.format(p), + } + } +} + +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 = Vec::new_in(p.allocator); + let mut method = self.method; + match self.kind { + PropertyKind::Get => { + parts.push(text!("get ")); + method = true; + } + PropertyKind::Set => { + parts.push(text!("set ")); + method = true; + } + PropertyKind::Init => (), + } + if method { + if let Expression::FunctionExpression(func_expr) = &self.value { + parts.push(wrap!(p, func_expr, Function, { + function::print_function( + p, + func_expr, + Some(self.key.span().source_text(p.source_text)), + ) + })); + } + } else { + parts.push(self.key.format(p)); + parts.push(text!(": ")); + parts.push(self.value.format(p)); + } + return group!(p, parts); + } + + if self.shorthand { + return self.value.format(p); + } + + let left_doc = if self.computed { + let key_doc = self.key.format(p); + array!(p, [text!("["), key_doc, text!("]")]) + } else { + self.key.format(p) + }; + + assignment::print_assignment( + p, + assignment::AssignmentLikeNode::ObjectProperty(self), + left_doc, + text!(":"), + Some(&self.value), + ) + }) + } +} + +impl<'a> Format<'a> for PropertyKey<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let is_parent_computed = match p.current_kind() { + AstKind::MethodDefinition(node) => node.computed, + AstKind::PropertyDefinition(node) => node.computed, + _ => false, + }; + if is_parent_computed { + 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(text!("]")); + return array!(p, parts); + } + + wrap!(p, self, PropertyKey, { + // Perf: Cache the result of `need_quote` to avoid checking it in each PropertyKey + let need_quote = p.options.quote_props.consistent() + && match p.parent_parent_kind() { + Some(AstKind::ObjectExpression(a)) => a.properties.iter().any(|x| match x { + ObjectPropertyKind::ObjectProperty(p) => { + property::is_property_key_has_quote(&p.key) + } + ObjectPropertyKind::SpreadProperty(_) => false, + }), + Some(AstKind::ClassBody(a)) => a.body.iter().any(|x| match x { + ClassElement::PropertyDefinition(p) => { + property::is_property_key_has_quote(&p.key) + } + _ => false, + }), + _ => false, + }; + + match self { + PropertyKey::StaticIdentifier(ident) => { + if need_quote { + dynamic_text!( + p, + string::print_string(p, &ident.name, p.options.single_quote) + ) + } else { + ident.format(p) + } + } + PropertyKey::PrivateIdentifier(ident) => ident.format(p), + PropertyKey::StringLiteral(literal) => { + // This does not pass quotes/objects.js + // because prettier uses the function `isEs5IdentifierName` based on unicode version 3, + // but `is_identifier_name` uses the latest unicode version. + if is_identifier_name(literal.value.as_str()) + && (p.options.quote_props.as_needed() + || (p.options.quote_props.consistent()/* && !needsQuoteProps.get(parent) */)) + { + dynamic_text!(p, literal.value.as_str()) + } else { + dynamic_text!( + p, + string::print_string(p, literal.value.as_str(), p.options.single_quote,) + ) + } + } + PropertyKey::NumericLiteral(literal) => { + if need_quote { + dynamic_text!( + p, + string::print_string(p, &literal.raw_str(), p.options.single_quote) + ) + } else { + literal.format(p) + } + } + PropertyKey::Identifier(ident) => { + let ident_doc = ident.format(p); + array!(p, [text!("["), ident_doc, text!("]")]) + } + match_expression!(PropertyKey) => self.to_expression().format(p), + } + }) + } +} + +impl<'a> Format<'a> for ArrowFunctionExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ArrowFunctionExpression, { arrow_function::print_arrow_function(p, self) }) + } +} + +impl<'a> Format<'a> for YieldExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, YieldExpression, { + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("yield")); + if self.delegate { + parts.push(text!("*")); + } + if let Some(argument) = &self.argument { + parts.push(text!(" ")); + parts.push(argument.format(p)); + } + array!(p, parts) + }) + } +} + +impl<'a> Format<'a> for UpdateExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, UpdateExpression, { + if self.prefix { + let argument_doc = self.argument.format(p); + array!(p, [text!(self.operator.as_str()), argument_doc]) + } else { + let argument_doc = self.argument.format(p); + array!(p, [argument_doc, text!(self.operator.as_str())]) + } + }) + } +} + +impl<'a> Format<'a> for UnaryExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, UnaryExpression, { + let mut parts = Vec::new_in(p.allocator); + parts.push(dynamic_text!(p, self.operator.as_str())); + if self.operator.is_keyword() { + parts.push(text!(" ")); + } + parts.push(self.argument.format(p)); + array!(p, parts) + }) + } +} + +impl<'a> Format<'a> for BinaryExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, BinaryExpression, { + let doc = binaryish::print_binaryish_expression( + p, + &self.left, + self.operator.into(), + &self.right, + ); + if misc::in_parentheses(p.parent_kind(), p.source_text, self.span) { + group!(p, [indent!(p, [softline!(), doc]), softline!(),]) + } else { + doc + } + }) + } +} + +impl<'a> Format<'a> for PrivateInExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, PrivateInExpression, { + let left_doc = self.left.format(p); + let right_doc = self.right.format(p); + array!(p, [left_doc, text!(" "), text!(self.operator.as_str()), text!(" "), right_doc]) + }) + } +} + +impl<'a> Format<'a> for LogicalExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, LogicalExpression, { + let doc = binaryish::print_binaryish_expression( + p, + &self.left, + self.operator.into(), + &self.right, + ); + + if misc::in_parentheses(p.parent_kind(), p.source_text, self.span) { + group!(p, [indent!(p, [softline!(), doc]), softline!()]) + } else { + doc + } + }) + } +} + +impl<'a> Format<'a> for ConditionalExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ConditionalExpression, { ternary::print_ternary(p, self) }) + } +} + +impl<'a> Format<'a> for AssignmentExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, AssignmentExpression, { assignment::print_assignment_expression(p, self) }) + } +} + +impl<'a> Format<'a> for AssignmentTarget<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + match_simple_assignment_target!(Self) => self.to_simple_assignment_target().format(p), + match_assignment_target_pattern!(Self) => self.to_assignment_target_pattern().format(p), + } + } +} + +impl<'a> Format<'a> for SimpleAssignmentTarget<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + Self::AssignmentTargetIdentifier(ident) => ident.format(p), + match_member_expression!(Self) => self.to_member_expression().format(p), + Self::TSAsExpression(expr) => expr.format(p), + Self::TSSatisfiesExpression(expr) => expr.format(p), + Self::TSNonNullExpression(expr) => expr.format(p), + Self::TSTypeAssertion(expr) => expr.format(p), + Self::TSInstantiationExpression(expr) => expr.format(p), + } + } +} + +impl<'a> Format<'a> for AssignmentTargetPattern<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + Self::ArrayAssignmentTarget(target) => target.format(p), + Self::ObjectAssignmentTarget(target) => target.format(p), + } + } +} + +impl<'a> Format<'a> for ArrayAssignmentTarget<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + array::print_array(p, &array::Array::ArrayAssignmentTarget(self)) + } +} + +impl<'a> Format<'a> for AssignmentTargetMaybeDefault<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + match_assignment_target!(AssignmentTargetMaybeDefault) => { + self.to_assignment_target().format(p) + } + AssignmentTargetMaybeDefault::AssignmentTargetWithDefault(v) => v.format(p), + } + } +} + +impl<'a> Format<'a> for ObjectAssignmentTarget<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + object::print_object(p, object::ObjectLike::AssignmentTarget(self)) + } +} + +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); + array!(p, [binding_doc, text!(" = "), init_doc]) + } +} + +impl<'a> Format<'a> for AssignmentTargetProperty<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + Self::AssignmentTargetPropertyIdentifier(ident) => ident.format(p), + Self::AssignmentTargetPropertyProperty(prop) => prop.format(p), + } + } +} + +impl<'a> Format<'a> for AssignmentTargetPropertyIdentifier<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + parts.push(self.binding.format(p)); + if let Some(init) = &self.init { + parts.push(text!(" = ")); + parts.push(init.format(p)); + } + array!(p, parts) + } +} + +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); + 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); + array!(p, [text!("..."), target_doc]) + } +} + +impl<'a> Format<'a> for SequenceExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, SequenceExpression, { + let docs = + self.expressions.iter().map(|expr| expr.format(p)).collect::>(); + group!(p, [join!(p, JoinSeparator::CommaLine, docs)]) + }) + } +} + +impl<'a> Format<'a> for ParenthesizedExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + unreachable!("Parser preserve_parens option need to be set to false."); + } +} + +impl<'a> Format<'a> for ImportExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ImportExpression, { + 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(text!(",")); + indent_parts.push(line!()); + indent_parts.push(arg.format(p)); + } + } + parts.push(group!(p, [indent!(p, indent_parts)])); + parts.push(softline!()); + parts.push(text!(")")); + + group!(p, parts) + }) + } +} + +impl<'a> Format<'a> for TemplateLiteral<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + template_literal::print_template_literal( + p, + &template_literal::TemplateLiteralPrinter::TemplateLiteral(self), + ) + } +} + +impl<'a> Format<'a> for TemplateElement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + // TODO: `replaceEndOfLine` + 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 = Vec::new_in(p.allocator); + + parts.push(self.tag.format(p)); + + if let Some(type_parameters) = &self.type_parameters { + parts.push(text!("<")); + parts.push(type_parameters.format(p)); + parts.push(text!(">")); + } + + parts.push(self.quasi.format(p)); + + array!(p, parts) + }) + } +} + +impl<'a> Format<'a> for Super { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + 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 = Vec::new_in(p.allocator); + parts.push(text!("await ")); + parts.push(self.argument.format(p)); + array!(p, parts) + }) + } +} + +impl<'a> Format<'a> for ChainExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ChainExpression, { self.expression.format(p) }) + } +} + +impl<'a> Format<'a> for ChainElement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + Self::CallExpression(expr) => expr.format(p), + Self::TSNonNullExpression(expr) => expr.format(p), + match_member_expression!(Self) => self.to_member_expression().format(p), + } + } +} + +impl<'a> Format<'a> for NewExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, NewExpression, { + call_expression::print_call_expression( + p, + &call_expression::CallExpressionLike::NewExpression(self), + ) + }) + } +} + +impl<'a> Format<'a> for MetaProperty<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let meta_doc = self.meta.format(p); + let property_doc = self.property.format(p); + array!(p, [meta_doc, text!("."), property_doc]) + } +} + +impl<'a> Format<'a> for Class<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, Class, { class::print_class(p, self) }) + } +} + +impl<'a> Format<'a> for ClassBody<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ClassBody, { class::print_class_body(p, self) }) + } +} + +impl<'a> Format<'a> for ClassElement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + ClassElement::StaticBlock(c) => c.format(p), + ClassElement::MethodDefinition(c) => c.format(p), + ClassElement::PropertyDefinition(c) => c.format(p), + ClassElement::AccessorProperty(c) => c.format(p), + ClassElement::TSIndexSignature(c) => c.format(p), + } + } +} + +impl<'a> Format<'a> for StaticBlock<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, StaticBlock, { + let block_doc = block::print_block(p, &self.body, None); + array!(p, [text!("static "), block_doc]) + }) + } +} + +impl<'a> Format<'a> for MethodDefinition<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, MethodDefinition, { function::print_method(p, self) }) + } +} + +impl<'a> Format<'a> for PropertyDefinition<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, PropertyDefinition, { + class::print_class_property(p, &class::ClassMemberish::PropertyDefinition(self)) + }) + } +} + +impl<'a> Format<'a> for AccessorProperty<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + class::print_class_property(p, &class::ClassMemberish::AccessorProperty(self)) + } +} + +impl<'a> Format<'a> for PrivateIdentifier<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + 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 = Vec::new_in(p.allocator); + parts.push(match self.kind { + BindingPatternKind::BindingIdentifier(ref ident) => ident.format(p), + BindingPatternKind::ObjectPattern(ref pattern) => pattern.format(p), + BindingPatternKind::ArrayPattern(ref pattern) => pattern.format(p), + BindingPatternKind::AssignmentPattern(ref pattern) => pattern.format(p), + }); + + if self.optional { + parts.push(text!("?")); + } + + if let Some(typ) = &self.type_annotation { + let type_annotation_doc = typ.type_annotation.format(p); + parts.push(array!(p, [text!(": "), type_annotation_doc])); + } + array!(p, parts) + } +} + +impl<'a> Format<'a> for ObjectPattern<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ObjectPattern, { + object::print_object(p, object::ObjectLike::Pattern(self)) + }) + } +} + +impl<'a> Format<'a> for BindingProperty<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + if self.shorthand { + self.value.format(p) + } else { + let key_doc = self.key.format(p); + let value_doc = self.value.format(p); + group!(p, [key_doc, text!(": "), value_doc]) + } + } +} + +impl<'a> Format<'a> for BindingRestElement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let argument_doc = self.argument.format(p); + array!(p, [text!("..."), argument_doc]) + } +} + +impl<'a> Format<'a> for ArrayPattern<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, ArrayPattern, { array::print_array(p, &array::Array::ArrayPattern(self)) }) + } +} + +impl<'a> Format<'a> for AssignmentPattern<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, AssignmentPattern, { + let left_doc = self.left.format(p); + let right_doc = self.right.format(p); + array!(p, [left_doc, text!(" = "), right_doc]) + }) + } +} + +impl<'a> Format<'a> for RegExpFlags { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut string = std::vec::Vec::with_capacity(self.iter().count()); + if self.contains(Self::D) { + string.push('d'); + } + if self.contains(Self::G) { + string.push('g'); + } + if self.contains(Self::I) { + string.push('i'); + } + if self.contains(Self::M) { + string.push('m'); + } + if self.contains(Self::S) { + string.push('s'); + } + if self.contains(Self::U) { + string.push('u'); + } + if self.contains(Self::V) { + string.push('v'); + } + if self.contains(Self::Y) { + string.push('y'); + } + let sorted = string.iter().collect::(); + dynamic_text!(p, &sorted) + } +} diff --git a/crates/oxc_prettier/src/format/jsx.rs b/crates/oxc_prettier/src/format/jsx.rs new file mode 100644 index 0000000000000..bbbb154377b44 --- /dev/null +++ b/crates/oxc_prettier/src/format/jsx.rs @@ -0,0 +1,270 @@ +use oxc_allocator::Vec; +use oxc_ast::ast::*; + +use crate::{ + array, dynamic_text, + format::Format, + group, hardline, indent, + ir::{Doc, JoinSeparator}, + join, line, softline, text, wrap, Prettier, +}; + +impl<'a> Format<'a> for JSXIdentifier<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + dynamic_text!(p, self.name.as_str()) + } +} + +impl<'a> Format<'a> for JSXMemberExpressionObject<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + JSXMemberExpressionObject::IdentifierReference(it) => it.format(p), + JSXMemberExpressionObject::MemberExpression(it) => it.format(p), + JSXMemberExpressionObject::ThisExpression(it) => it.format(p), + } + } +} + +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); + array!(p, [object_doc, text!("."), property_doc]) + } +} + +impl<'a> Format<'a> for JSXElementName<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + JSXElementName::Identifier(it) => it.format(p), + JSXElementName::IdentifierReference(it) => it.format(p), + JSXElementName::MemberExpression(it) => it.format(p), + JSXElementName::NamespacedName(it) => it.format(p), + JSXElementName::ThisExpression(it) => it.format(p), + } + } +} + +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); + array!(p, [namespace_doc, text!(":"), property_doc]) + } +} + +impl<'a> Format<'a> for JSXAttributeName<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + JSXAttributeName::Identifier(it) => it.format(p), + JSXAttributeName::NamespacedName(it) => it.format(p), + } + } +} + +impl<'a> Format<'a> for JSXAttribute<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + parts.push(self.name.format(p)); + + if let Some(value) = &self.value { + parts.push(text!("=")); + parts.push(value.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for JSXEmptyExpression { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("") + } +} + +impl<'a> Format<'a> for JSXExpression<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + JSXExpression::EmptyExpression(it) => it.format(p), + match_member_expression!(Self) => self.to_member_expression().format(p), + JSXExpression::BooleanLiteral(it) => it.format(p), + JSXExpression::NullLiteral(it) => it.format(p), + JSXExpression::NumericLiteral(it) => it.format(p), + JSXExpression::BigIntLiteral(it) => it.format(p), + JSXExpression::RegExpLiteral(it) => it.format(p), + JSXExpression::StringLiteral(it) => it.format(p), + JSXExpression::TemplateLiteral(it) => it.format(p), + JSXExpression::Identifier(it) => it.format(p), + JSXExpression::MetaProperty(it) => it.format(p), + JSXExpression::Super(it) => it.format(p), + JSXExpression::ArrayExpression(it) => it.format(p), + JSXExpression::ArrowFunctionExpression(it) => it.format(p), + JSXExpression::AssignmentExpression(it) => it.format(p), + JSXExpression::AwaitExpression(it) => it.format(p), + JSXExpression::BinaryExpression(it) => it.format(p), + JSXExpression::CallExpression(it) => it.format(p), + JSXExpression::ChainExpression(it) => it.format(p), + JSXExpression::ClassExpression(it) => it.format(p), + JSXExpression::ConditionalExpression(it) => it.format(p), + JSXExpression::FunctionExpression(it) => it.format(p), + JSXExpression::ImportExpression(it) => it.format(p), + JSXExpression::LogicalExpression(it) => it.format(p), + JSXExpression::NewExpression(it) => it.format(p), + JSXExpression::ObjectExpression(it) => it.format(p), + JSXExpression::ParenthesizedExpression(it) => it.format(p), + JSXExpression::SequenceExpression(it) => it.format(p), + JSXExpression::TaggedTemplateExpression(it) => it.format(p), + JSXExpression::ThisExpression(it) => it.format(p), + JSXExpression::UnaryExpression(it) => it.format(p), + JSXExpression::UpdateExpression(it) => it.format(p), + JSXExpression::YieldExpression(it) => it.format(p), + JSXExpression::PrivateInExpression(it) => it.format(p), + JSXExpression::JSXElement(it) => it.format(p), + JSXExpression::JSXFragment(it) => it.format(p), + JSXExpression::TSAsExpression(it) => it.format(p), + JSXExpression::TSSatisfiesExpression(it) => it.format(p), + JSXExpression::TSTypeAssertion(it) => it.format(p), + JSXExpression::TSNonNullExpression(it) => it.format(p), + JSXExpression::TSInstantiationExpression(it) => it.format(p), + } + } +} + +impl<'a> Format<'a> for JSXExpressionContainer<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let expression_doc = self.expression.format(p); + array!(p, [text!("{"), expression_doc, text!("}")]) + } +} + +impl<'a> Format<'a> for JSXAttributeValue<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + JSXAttributeValue::Element(it) => it.format(p), + JSXAttributeValue::ExpressionContainer(it) => it.format(p), + JSXAttributeValue::Fragment(it) => it.format(p), + JSXAttributeValue::StringLiteral(it) => it.format(p), + } + } +} + +impl<'a> Format<'a> for JSXSpreadAttribute<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let argument_doc = self.argument.format(p); + array!(p, [text!("..."), argument_doc]) + } +} + +impl<'a> Format<'a> for JSXAttributeItem<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + JSXAttributeItem::Attribute(it) => it.format(p), + JSXAttributeItem::SpreadAttribute(it) => it.format(p), + } + } +} + +impl<'a> Format<'a> for JSXOpeningElement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + parts.push(text!("<")); + parts.push(self.name.format(p)); + + if let Some(type_parameters) = &self.type_parameters { + parts.push(type_parameters.format(p)); + } + + for attribute in &self.attributes { + parts.push(text!(" ")); + parts.push(attribute.format(p)); + } + + if self.self_closing { + parts.push(text!(" ")); + parts.push(text!("/")); + } + + parts.push(text!(">")); + + 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); + array!(p, [text!("")]) + } +} + +impl<'a> Format<'a> for JSXElement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + parts.push(self.opening_element.format(p)); + + for child in &self.children { + parts.push(child.format(p)); + } + + if let Some(closing_element) = &self.closing_element { + parts.push(closing_element.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for JSXOpeningFragment { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("<>") + } +} + +impl<'a> Format<'a> for JSXClosingFragment { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("") + } +} + +impl<'a> Format<'a> for JSXText<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + 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); + array!(p, [text!("..."), expression_doc]) + } +} + +impl<'a> Format<'a> for JSXChild<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + JSXChild::Element(it) => it.format(p), + JSXChild::ExpressionContainer(it) => it.format(p), + JSXChild::Fragment(it) => it.format(p), + JSXChild::Spread(it) => it.format(p), + JSXChild::Text(it) => it.format(p), + } + } +} + +impl<'a> Format<'a> for JSXFragment<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + parts.push(self.opening_fragment.format(p)); + + for child in &self.children { + parts.push(child.format(p)); + } + + parts.push(self.closing_fragment.format(p)); + + array!(p, parts) + } +} diff --git a/crates/oxc_prettier/src/format/mod.rs b/crates/oxc_prettier/src/format/mod.rs index e34ee3b950483..ba573c8f36767 100644 --- a/crates/oxc_prettier/src/format/mod.rs +++ b/crates/oxc_prettier/src/format/mod.rs @@ -1,3115 +1,11 @@ -//! Formatting logic -//! -//! References: -//! * +mod js; +mod jsx; +mod print; +mod typescript; -mod array; -mod arrow_function; -mod assignment; -mod binaryish; -mod block; -mod call_arguments; -mod call_expression; -mod class; -mod function; -mod function_parameters; -mod misc; -mod module; -mod object; -mod property; -mod statement; -mod string; -mod template_literal; -mod ternary; - -use std::borrow::Cow; - -use cow_utils::CowUtils; -use oxc_allocator::{Box, Vec}; -use oxc_ast::{ast::*, AstKind}; -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}, - group, hardline, indent, - ir::{Doc, JoinSeparator}, - join, line, softline, text, wrap, Prettier, -}; +use crate::{ir::Doc, Prettier}; pub trait Format<'a> { #[must_use] fn format(&self, p: &mut Prettier<'a>) -> Doc<'a>; } - -impl<'a, T> Format<'a> for Box<'a, T> -where - T: Format<'a>, -{ - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - (**self).format(p) - } -} - -impl<'a> Format<'a> for Program<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, Program, { - let mut parts = Vec::new_in(p.allocator); - - // In Prettier, this is treated as a comment - if let Some(hashbang) = &self.hashbang { - parts.push(hashbang.format(p)); - } - - if let Some(body_doc) = block::print_block_body(p, &self.body, Some(&self.directives)) { - parts.push(body_doc); - // XXX: Prettier seems to add this, but test results don't match - // parts.extend(hardline!()); - } - - array!(p, parts) - }) - } -} - -impl<'a> Format<'a> for Hashbang<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - 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(hardline!()); - } - } - array!(p, parts) - } -} - -impl<'a> Format<'a> for Directive<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(dynamic_text!( - p, - string::print_string(p, self.directive.as_str(), p.options.single_quote,) - )); - if let Some(semi) = p.semi() { - parts.push(semi); - } - parts.extend(hardline!()); - array!(p, parts) - } -} - -impl<'a> Format<'a> for Statement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::BlockStatement(stmt) => stmt.format(p), - Self::BreakStatement(stmt) => stmt.format(p), - Self::ContinueStatement(stmt) => stmt.format(p), - Self::DebuggerStatement(stmt) => stmt.format(p), - Self::DoWhileStatement(stmt) => stmt.format(p), - Self::EmptyStatement(stmt) => stmt.format(p), - Self::ExpressionStatement(stmt) => stmt.format(p), - Self::ForInStatement(stmt) => stmt.format(p), - Self::ForOfStatement(stmt) => stmt.format(p), - Self::ForStatement(stmt) => stmt.format(p), - Self::IfStatement(stmt) => stmt.format(p), - Self::LabeledStatement(stmt) => stmt.format(p), - Self::ReturnStatement(stmt) => stmt.format(p), - Self::SwitchStatement(stmt) => stmt.format(p), - Self::ThrowStatement(stmt) => stmt.format(p), - Self::TryStatement(stmt) => stmt.format(p), - Self::WhileStatement(stmt) => stmt.format(p), - Self::WithStatement(stmt) => stmt.format(p), - match_module_declaration!(Self) => self.to_module_declaration().format(p), - match_declaration!(Self) => self.to_declaration().format(p), - } - } -} - -impl<'a> Format<'a> for ExpressionStatement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ExpressionStatement, { - let mut parts = Vec::new_in(p.allocator); - parts.push(self.expression.format(p)); - if let Some(semi) = p.semi() { - parts.push(semi); - } - array!(p, parts) - }) - } -} - -impl<'a> Format<'a> for EmptyStatement { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("") - } -} - -impl<'a> Format<'a> for IfStatement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, IfStatement, { - let mut parts = Vec::new_in(p.allocator); - - let test_doc = self.test.format(p); - let consequent = self.consequent.format(p); - let consequent = misc::adjust_clause(p, &self.consequent, consequent, false); - - let opening = group!( - p, - [ - 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(text!(" ")); - } else { - parts.extend(hardline!()); - } - parts.push(text!("else")); - let alternate_doc = alternate.format(p); - parts.push(group!( - p, - [misc::adjust_clause( - p, - alternate, - alternate_doc, - matches!(alternate, Statement::IfStatement(_)), - )] - )); - } - - array!(p, parts) - }) - } -} - -impl<'a> Format<'a> for BlockStatement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, BlockStatement, { block::print_block(p, &self.body, None) }) - } -} - -impl<'a> Format<'a> for ForStatement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ForStatement, { - let body = self.body.format(p); - let body = misc::adjust_clause(p, &self.body, body, false); - - if self.init.is_none() && self.test.is_none() && self.update.is_none() { - return group!(p, [text!("for (;;)"), body]); - } - - let parts_head = { - let mut parts_head = Vec::new_in(p.allocator); - parts_head.push(softline!()); - if let Some(init) = &self.init { - parts_head.push(init.format(p)); - } - parts_head.push(text!(";")); - parts_head.push(line!()); - if let Some(init) = &self.test { - parts_head.push(init.format(p)); - } - parts_head.push(text!(";")); - parts_head.push(line!()); - if let Some(init) = &self.update { - parts_head.push(init.format(p)); - } - indent!(p, parts_head) - }; - - group!(p, [text!("for ("), group!(p, [parts_head, softline!()]), text!(")"), body,]) - }) - } -} - -impl<'a> Format<'a> for ForStatementInit<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - ForStatementInit::VariableDeclaration(v) => v.format(p), - match_expression!(ForStatementInit) => self.to_expression().format(p), - } - } -} - -impl<'a> Format<'a> for ForInStatement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ForInStatement, { - let mut parts = Vec::new_in(p.allocator); - parts.push(text!("for (")); - parts.push(self.left.format(p)); - parts.push(text!(" in ")); - parts.push(self.right.format(p)); - parts.push(text!(")")); - let body = self.body.format(p); - parts.push(misc::adjust_clause(p, &self.body, body, false)); - group!(p, parts) - }) - } -} - -impl<'a> Format<'a> for ForOfStatement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ForOfStatement, { - let mut parts = Vec::new_in(p.allocator); - parts.push(text!("for")); - if self.r#await { - parts.push(text!(" await")); - } - parts.push(text!(" (")); - parts.push(self.left.format(p)); - parts.push(text!(" of ")); - parts.push(self.right.format(p)); - parts.push(text!(")")); - let body = self.body.format(p); - parts.push(misc::adjust_clause(p, &self.body, body, false)); - group!(p, parts) - }) - } -} - -impl<'a> Format<'a> for ForStatementLeft<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - ForStatementLeft::VariableDeclaration(v) => v.format(p), - match_assignment_target!(ForStatementLeft) => self.to_assignment_target().format(p), - } - } -} - -impl<'a> Format<'a> for WhileStatement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, WhileStatement, { - let mut parts = Vec::new_in(p.allocator); - - parts.push(text!("while (")); - let test_doc = self.test.format(p); - 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)); - - group!(p, parts) - }) - } -} - -impl<'a> Format<'a> for DoWhileStatement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, DoWhileStatement, { - 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 = group!(p, [text!("do"), clause]); - - parts.push(do_body); - - if matches!(self.body, Statement::BlockStatement(_)) { - parts.push(text!(" ")); - } else { - parts.extend(hardline!()); - } - - parts.push(text!("while (")); - let test_doc = self.test.format(p); - parts.push(group!(p, [indent!(p, [softline!(), test_doc]), softline!()])); - parts.push(text!(")")); - if let Some(semi) = p.semi() { - parts.push(semi); - } - - array!(p, parts) - }) - } -} - -impl<'a> Format<'a> for ContinueStatement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(text!("continue")); - - if let Some(label) = &self.label { - parts.push(text!(" ")); - parts.push(label.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for BreakStatement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(text!("break")); - - if let Some(label) = &self.label { - parts.push(text!(" ")); - parts.push(label.format(p)); - } - - if p.options.semi { - parts.push(text!(";")); - } - - 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 = Vec::new_in(p.allocator); - - let mut header_parts = Vec::new_in(p.allocator); - - header_parts.push(text!("switch (")); - - let discriminant_doc = self.discriminant.format(p); - header_parts.push(indent!(p, [softline!(), discriminant_doc])); - - header_parts.push(softline!()); - header_parts.push(text!(")")); - - parts.push(group!(p, header_parts)); - - parts.push(text!(" {")); - - 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 = Vec::new_in(p.allocator); - parts.extend(hardline!()); - parts.push(case.format(p)); - indent!(p, parts) - }); - if i != len - 1 && p.is_next_line_empty(case.span) { - cases_parts.extend(hardline!()); - } - } - parts.extend(cases_parts); - - parts.extend(hardline!()); - parts.push(text!("}")); - - array!(p, parts) - }) - } -} - -impl<'a> Format<'a> for SwitchCase<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - if let Some(test) = &self.test { - parts.push(text!("case ")); - parts.push(test.format(p)); - parts.push(text!(":")); - } else { - parts.push(text!("default:")); - } - - let consequent: Vec<_> = Vec::from_iter_in( - self.consequent.iter().filter(|c| !matches!(c, Statement::EmptyStatement(_))), - p.allocator, - ); - let len = consequent.len(); - let is_only_one_block_statement = - len == 1 && matches!(self.consequent[0], Statement::BlockStatement(_)); - - let 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(hardline!()); - } - } - - if is_only_one_block_statement { - consequent_parts.push(text!(" ")); - } else { - consequent_parts.extend(hardline!()); - } - consequent_parts.push(stmt.format(p)); - } - - if !consequent_parts.is_empty() { - if is_only_one_block_statement { - parts.extend(consequent_parts); - } else { - parts.push(indent!(p, [group!(p, consequent_parts)])); - } - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for ReturnStatement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ReturnStatement, { - array!( - p, - [ - text!("return"), - function::print_return_or_throw_argument(p, self.argument.as_ref()) - ] - ) - }) - } -} - -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 array!(p, [label_doc, text!(":;")]); - } - - let label_doc = self.label.format(p); - let body_doc = self.body.format(p); - 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 = Vec::new_in(p.allocator); - - parts.push(text!("try ")); - parts.push(self.block.format(p)); - if let Some(handler) = &self.handler { - parts.push(text!(" ")); - parts.push(handler.format(p)); - } - if let Some(finalizer) = &self.finalizer { - parts.push(text!(" finally ")); - parts.push(finalizer.format(p)); - } - - array!(p, parts) - }) - } -} - -impl<'a> Format<'a> for CatchClause<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, CatchClause, { - let mut parts = Vec::new_in(p.allocator); - - parts.push(text!("catch ")); - if let Some(param) = &self.param { - parts.push(text!("(")); - parts.push(param.pattern.format(p)); - parts.push(text!(") ")); - } - parts.push(self.body.format(p)); - - array!(p, parts) - }) - } -} - -impl<'a> Format<'a> for ThrowStatement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ThrowStatement, { - array!( - p, - [text!("throw"), function::print_return_or_throw_argument(p, Some(&self.argument))] - ) - }) - } -} - -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); - group!( - p, - [ - 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 = Vec::new_in(p.allocator); - parts.push(text!("debugger")); - - if p.options.semi { - parts.push(text!(";")); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for ModuleDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ModuleDeclaration, { - if let ModuleDeclaration::ImportDeclaration(decl) = self { - decl.format(p) - } else { - module::print_export_declaration(p, self) - } - }) - } -} - -impl<'a> Format<'a> for Declaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::VariableDeclaration(stmt) => stmt.format(p), - Self::FunctionDeclaration(stmt) => stmt.format(p), - Self::ClassDeclaration(decl) => decl.format(p), - Self::TSTypeAliasDeclaration(decl) => decl.format(p), - Self::TSInterfaceDeclaration(decl) => decl.format(p), - Self::TSEnumDeclaration(decl) => decl.format(p), - Self::TSModuleDeclaration(decl) => decl.format(p), - Self::TSImportEqualsDeclaration(decl) => decl.format(p), - } - } -} - -impl<'a> Format<'a> for VariableDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, VariableDeclaration, { - // We generally want to terminate all variable declarations with a - // semicolon, except when they in the () part of for loops. - let parent_for_loop = match p.parent_kind() { - AstKind::ForStatement(stmt) => Some(stmt.body.span()), - AstKind::ForInStatement(stmt) => Some(stmt.body.span()), - AstKind::ForOfStatement(stmt) => Some(stmt.body.span()), - _ => None, - }; - - let kind = self.kind.as_str(); - - let mut parts = Vec::new_in(p.allocator); - - if self.declare { - parts.push(text!("declare ")); - } - - 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 = Vec::new_in(p.allocator); - if i != 0 { - d_parts.push(text!(",")); - if is_hardline { - d_parts.extend(hardline!()); - } else { - d_parts.push(line!()); - } - } - d_parts.push(decl.format(p)); - indent!(p, d_parts) - } else { - decl.format(p) - } - })); - - if !parent_for_loop.is_some_and(|span| span != self.span) { - if let Some(semi) = p.semi() { - parts.push(semi); - } - } - - group!(p, parts) - }) - } -} - -impl<'a> Format<'a> for VariableDeclarator<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, VariableDeclarator, { assignment::print_variable_declarator(p, self) }) - } -} - -impl<'a> Format<'a> for TSTypeAliasDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - if self.declare { - parts.push(text!("declare ")); - } - - parts.push(text!("type ")); - parts.push(self.id.format(p)); - - if let Some(params) = &self.type_parameters { - parts.push(params.format(p)); - } - - parts.push(text!(" = ")); - parts.push(self.type_annotation.format(p)); - - if let Some(semi) = p.semi() { - parts.push(semi); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSType<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - TSType::TSAnyKeyword(v) => v.format(p), - TSType::TSBigIntKeyword(v) => v.format(p), - TSType::TSBooleanKeyword(v) => v.format(p), - TSType::TSIntrinsicKeyword(v) => v.format(p), - TSType::TSNeverKeyword(v) => v.format(p), - TSType::TSNullKeyword(v) => v.format(p), - TSType::TSNumberKeyword(v) => v.format(p), - TSType::TSObjectKeyword(v) => v.format(p), - TSType::TSStringKeyword(v) => v.format(p), - TSType::TSSymbolKeyword(v) => v.format(p), - TSType::TSThisType(v) => v.format(p), - TSType::TSUndefinedKeyword(v) => v.format(p), - TSType::TSUnknownKeyword(v) => v.format(p), - TSType::TSVoidKeyword(v) => v.format(p), - TSType::TSArrayType(v) => v.format(p), - TSType::TSConditionalType(v) => v.format(p), - TSType::TSConstructorType(v) => v.format(p), - TSType::TSFunctionType(v) => v.format(p), - TSType::TSImportType(v) => v.format(p), - TSType::TSIndexedAccessType(v) => v.format(p), - TSType::TSInferType(v) => v.format(p), - TSType::TSIntersectionType(v) => v.format(p), - TSType::TSLiteralType(v) => v.format(p), - TSType::TSMappedType(v) => v.format(p), - TSType::TSNamedTupleMember(v) => v.format(p), - TSType::TSQualifiedName(v) => v.format(p), - TSType::TSTemplateLiteralType(v) => v.format(p), - TSType::TSTupleType(v) => v.format(p), - TSType::TSTypeLiteral(v) => v.format(p), - TSType::TSTypeOperatorType(v) => v.format(p), - TSType::TSTypePredicate(v) => v.format(p), - TSType::TSTypeQuery(v) => v.format(p), - TSType::TSTypeReference(v) => v.format(p), - TSType::TSUnionType(v) => v.format(p), - TSType::TSParenthesizedType(v) => v.format(p), - TSType::JSDocNullableType(v) => v.format(p), - TSType::JSDocNonNullableType(v) => v.format(p), - TSType::JSDocUnknownType(v) => v.format(p), - } - } -} - -impl<'a> Format<'a> for TSAnyKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("any") - } -} - -impl<'a> Format<'a> for TSBigIntKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("bigint") - } -} - -impl<'a> Format<'a> for TSBooleanKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("boolean") - } -} - -impl<'a> Format<'a> for TSIntrinsicKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("intrinsic") - } -} - -impl<'a> Format<'a> for TSNeverKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("never") - } -} - -impl<'a> Format<'a> for TSNullKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("null") - } -} - -impl<'a> Format<'a> for TSNumberKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("number") - } -} - -impl<'a> Format<'a> for TSObjectKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("object") - } -} - -impl<'a> Format<'a> for TSStringKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("string") - } -} - -impl<'a> Format<'a> for TSSymbolKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("symbol") - } -} - -impl<'a> Format<'a> for TSThisType { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("this") - } -} - -impl<'a> Format<'a> for TSUndefinedKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("undefined") - } -} - -impl<'a> Format<'a> for TSUnknownKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("unknown") - } -} - -impl<'a> Format<'a> for TSVoidKeyword { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - 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); - 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 = Vec::new_in(p.allocator); - - parts.push(self.check_type.format(p)); - parts.push(text!(" extends ")); - parts.push(self.extends_type.format(p)); - parts.push(text!(" ? ")); - parts.push(self.true_type.format(p)); - parts.push(text!(" : ")); - parts.push(self.false_type.format(p)); - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSConstructorType<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - if self.r#abstract { - parts.push(text!("abstract ")); - } - parts.push(text!("new ")); - parts.push(self.params.format(p)); - let type_annotation_doc = self.return_type.type_annotation.format(p); - 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 = Vec::new_in(p.allocator); - - if let Some(type_parameters) = &self.type_parameters { - parts.push(type_parameters.format(p)); - } - - parts.push(self.params.format(p)); - - parts.push(text!(" => ")); - parts.push(self.return_type.type_annotation.format(p)); - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSThisParameter<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(text!("this")); - - if let Some(type_annotation) = &self.type_annotation { - parts.push(text!(": ")); - parts.push(type_annotation.type_annotation.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSImportType<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - if self.is_type_of { - parts.push(text!("typeof ")); - } - - parts.push(text!("import(")); - parts.push(self.parameter.format(p)); - // ToDo: attributes - parts.push(text!(")")); - - if let Some(qualifier) = &self.qualifier { - parts.push(text!(".")); - parts.push(qualifier.format(p)); - } - - if let Some(type_parameters) = &self.type_parameters { - parts.push(type_parameters.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSIndexedAccessType<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(self.object_type.format(p)); - parts.push(text!("[")); - parts.push(self.index_type.format(p)); - 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); - 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 = Vec::new_in(p.allocator); - let mut add_symbol = false; - - for ts_type in &self.types { - if add_symbol { - parts.push(text!(" & ")); - } else { - add_symbol = true; - } - - parts.push(ts_type.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSLiteralType<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match &self.literal { - TSLiteral::BooleanLiteral(v) => v.format(p), - TSLiteral::NullLiteral(v) => v.format(p), - TSLiteral::NumericLiteral(v) => v.format(p), - TSLiteral::BigIntLiteral(v) => v.format(p), - TSLiteral::RegExpLiteral(v) => v.format(p), - TSLiteral::StringLiteral(v) => v.format(p), - TSLiteral::TemplateLiteral(v) => v.format(p), - TSLiteral::UnaryExpression(v) => v.format(p), - } - } -} - -impl<'a> Format<'a> for TSMappedType<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts: Vec<'_, Doc<'_>> = Vec::new_in(p.allocator); - - match self.readonly { - TSMappedTypeModifierOperator::Plus => parts.push(text!("+readonly ")), - TSMappedTypeModifierOperator::Minus => parts.push(text!("-readonly ")), - TSMappedTypeModifierOperator::True => parts.push(text!("readonly ")), - TSMappedTypeModifierOperator::None => (), - } - - parts.push(text!("[")); - parts.push(self.type_parameter.format(p)); - - if let Some(name_type) = &self.name_type { - parts.push(text!(" as ")); - parts.push(name_type.format(p)); - } - - parts.push(text!("]")); - - match self.optional { - 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(text!(": ")); - parts.push(type_annotation.format(p)); - } - - 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 = Vec::new_in(p.allocator); - - parts.push(self.label.format(p)); - - if self.optional { - parts.push(text!("?")); - } - - parts.push(text!(": ")); - parts.push(self.element_type.format(p)); - - 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); - 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); - array!(p, [type_annotation_doc, text!("?")]) - } -} - -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); - array!(p, [left_doc, text!("."), right_doc]) - } -} - -impl<'a> Format<'a> for TSTemplateLiteralType<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - template_literal::print_template_literal( - p, - &TemplateLiteralPrinter::TSTemplateLiteralType(self), - ) - } -} - -impl<'a> Format<'a> for TSTupleType<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - array::print_array(p, &Array::TSTupleType(self)) - } -} - -impl<'a> Format<'a> for TSTypeLiteral<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - object::print_object(p, ObjectLike::TSTypeLiteral(self)) - } -} - -impl<'a> Format<'a> for TSTypeOperator<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - parts.push(text!(self.operator.to_str())); - parts.push(text!(" ")); - parts.push(self.type_annotation.format(p)); - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSTypePredicate<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - if self.asserts { - parts.push(text!("asserts ")); - } - parts.push(self.parameter_name.format(p)); - - if let Some(type_annotation) = &self.type_annotation { - parts.push(text!(" is ")); - parts.push(type_annotation.type_annotation.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSTypePredicateName<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - TSTypePredicateName::Identifier(it) => it.format(p), - TSTypePredicateName::This(it) => it.format(p), - } - } -} - -impl<'a> Format<'a> for TSTypeQuery<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - parts.push(text!("typeof ")); - - match &self.expr_name { - TSTypeQueryExprName::TSImportType(import_type) => parts.push(import_type.format(p)), - TSTypeQueryExprName::IdentifierReference(identifier_reference) => { - parts.push(identifier_reference.format(p)); - } - TSTypeQueryExprName::QualifiedName(qualified_name) => { - parts.push(qualified_name.format(p)); - } - } - - if let Some(type_parameters) = &self.type_parameters { - parts.push(type_parameters.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSTypeReference<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - 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)); - } - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSParenthesizedType<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, TSParenthesizedType, { self.type_annotation.format(p) }) - } -} - -impl<'a> Format<'a> for TSUnionType<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - let mut add_symbol = false; - - for ts_type in &self.types { - if add_symbol { - parts.push(text!(" | ")); - } else { - add_symbol = true; - } - - parts.push(ts_type.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for JSDocNullableType<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - line!() - } -} - -impl<'a> Format<'a> for JSDocNonNullableType<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - line!() - } -} - -impl<'a> Format<'a> for JSDocUnknownType { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - line!() - } -} - -impl<'a> Format<'a> for TSInterfaceDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - if self.declare { - parts.push(text!("declare ")); - } - - 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(text!(" ")); - - if let Some(extends) = &self.extends { - if extends.len() > 0 { - let mut extends_parts = Vec::new_in(p.allocator); - let mut display_comma = false; - - extends_parts.push(text!("extends ")); - - for extend in extends { - if display_comma { - extends_parts.push(text!(", ")); - } else { - display_comma = true; - } - - extends_parts.push(extend.expression.format(p)); - if let Some(type_parameters) = &extend.type_parameters { - extends_parts.push(type_parameters.format(p)); - } - } - - parts.extend(extends_parts); - parts.push(text!(" ")); - } - } - - parts.push(text!("{")); - if self.body.body.len() > 0 { - let mut indent_parts = Vec::new_in(p.allocator); - for sig in &self.body.body { - indent_parts.extend(hardline!()); - indent_parts.push(sig.format(p)); - - if let Some(semi) = p.semi() { - indent_parts.push(semi); - } - } - parts.push(indent!(p, indent_parts)); - parts.extend(hardline!()); - } - 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 = Vec::new_in(p.allocator); - if self.declare { - parts.push(text!("declare ")); - } - if self.r#const { - parts.push(text!("const ")); - } - parts.push(text!("enum ")); - parts.push(self.id.format(p)); - parts.push(text!(" {")); - if self.members.len() > 0 { - let mut indent_parts = Vec::new_in(p.allocator); - for member in &self.members { - indent_parts.extend(hardline!()); - indent_parts.push(member.format(p)); - } - parts.push(indent!(p, indent_parts)); - parts.extend(hardline!()); - } - parts.push(text!("}")); - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSEnumMember<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(self.id.format(p)); - - if let Some(initializer) = &self.initializer { - parts.push(text!(" = ")); - parts.push(initializer.format(p)); - } - - parts.push(text!(",")); - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSEnumMemberName<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - TSEnumMemberName::Identifier(identifier) => identifier.format(p), - TSEnumMemberName::String(string_literal) => string_literal.format(p), - } - } -} - -impl<'a> Format<'a> for TSModuleDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - if self.declare { - parts.push(text!("declare ")); - } - - parts.push(text!(self.kind.as_str())); - parts.push(text!(" ")); - parts.push(self.id.format(p)); - parts.push(text!(" {")); - - if let Some(body) = &self.body { - if !body.is_empty() { - let mut indent_parts = Vec::new_in(p.allocator); - - indent_parts.extend(hardline!()); - indent_parts.push(body.format(p)); - - parts.push(indent!(p, indent_parts)); - parts.extend(hardline!()); - } - } - - parts.push(text!("}")); - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSModuleDeclarationName<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - TSModuleDeclarationName::Identifier(identifier) => identifier.format(p), - TSModuleDeclarationName::StringLiteral(string_literal) => string_literal.format(p), - } - } -} - -impl<'a> Format<'a> for TSModuleDeclarationBody<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - TSModuleDeclarationBody::TSModuleBlock(module_block) => module_block.format(p), - TSModuleDeclarationBody::TSModuleDeclaration(module_declaration) => { - module_declaration.format(p) - } - } - } -} - -impl<'a> Format<'a> for TSModuleBlock<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - let mut add_line = false; - - for body_part in &self.body { - if add_line { - parts.push(line!()); - } else { - add_line = true; - } - - parts.push(body_part.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSImportEqualsDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - parts.push(text!("import ")); - - if self.import_kind == ImportOrExportKind::Type { - parts.push(text!("type ")); - } - - parts.push(self.id.format(p)); - parts.push(text!(" = ")); - parts.push(self.module_reference.format(p)); - - if let Some(semi) = p.semi() { - parts.push(semi); - } - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSModuleReference<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - TSModuleReference::IdentifierReference(it) => it.format(p), - TSModuleReference::QualifiedName(it) => it.format(p), - TSModuleReference::ExternalModuleReference(v) => v.format(p), - } - } -} - -impl<'a> Format<'a> for TSTypeName<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - TSTypeName::IdentifierReference(it) => it.format(p), - TSTypeName::QualifiedName(it) => it.format(p), - } - } -} - -impl<'a> Format<'a> for TSExternalModuleReference<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let expression_doc = self.expression.format(p); - 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 = Vec::new_in(p.allocator); - - if self.r#in { - parts.push(text!("in ")); - } - - if self.out { - parts.push(text!("out ")); - } - - parts.push(self.name.format(p)); - - if let Some(constraint) = &self.constraint { - parts.push(text!(" extends ")); - parts.push(constraint.format(p)); - } - - if let Some(default) = &self.default { - parts.push(text!(" = ")); - parts.push(default.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSTypeParameterDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - let mut print_comma = false; - - parts.push(text!("<")); - - for param in &self.params { - if print_comma { - parts.push(text!(", ")); - } else { - print_comma = true; - } - - parts.push(param.format(p)); - } - - parts.push(text!(">")); - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSTypeParameterInstantiation<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - let mut print_comma = false; - - parts.push(text!("<")); - - for param in &self.params { - if print_comma { - parts.push(text!(", ")); - } else { - print_comma = true; - } - - parts.push(param.format(p)); - } - - parts.push(text!(">")); - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSTupleElement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - TSTupleElement::TSOptionalType(it) => it.format(p), - TSTupleElement::TSRestType(it) => it.format(p), - TSTupleElement::TSAnyKeyword(it) => it.format(p), - TSTupleElement::TSBigIntKeyword(it) => it.format(p), - TSTupleElement::TSBooleanKeyword(it) => it.format(p), - TSTupleElement::TSIntrinsicKeyword(it) => it.format(p), - TSTupleElement::TSNeverKeyword(it) => it.format(p), - TSTupleElement::TSNullKeyword(it) => it.format(p), - TSTupleElement::TSNumberKeyword(it) => it.format(p), - TSTupleElement::TSObjectKeyword(it) => it.format(p), - TSTupleElement::TSStringKeyword(it) => it.format(p), - TSTupleElement::TSSymbolKeyword(it) => it.format(p), - TSTupleElement::TSUndefinedKeyword(it) => it.format(p), - TSTupleElement::TSUnknownKeyword(it) => it.format(p), - TSTupleElement::TSVoidKeyword(it) => it.format(p), - TSTupleElement::TSArrayType(it) => it.format(p), - TSTupleElement::TSConditionalType(it) => it.format(p), - TSTupleElement::TSConstructorType(it) => it.format(p), - TSTupleElement::TSFunctionType(it) => it.format(p), - TSTupleElement::TSImportType(it) => it.format(p), - TSTupleElement::TSIndexedAccessType(it) => it.format(p), - TSTupleElement::TSInferType(it) => it.format(p), - TSTupleElement::TSIntersectionType(it) => it.format(p), - TSTupleElement::TSLiteralType(it) => it.format(p), - TSTupleElement::TSMappedType(it) => it.format(p), - TSTupleElement::TSNamedTupleMember(it) => it.format(p), - TSTupleElement::TSQualifiedName(it) => it.format(p), - TSTupleElement::TSTemplateLiteralType(it) => it.format(p), - TSTupleElement::TSThisType(it) => it.format(p), - TSTupleElement::TSTupleType(it) => it.format(p), - TSTupleElement::TSTypeLiteral(it) => it.format(p), - TSTupleElement::TSTypeOperatorType(it) => it.format(p), - TSTupleElement::TSTypePredicate(it) => it.format(p), - TSTupleElement::TSTypeQuery(it) => it.format(p), - TSTupleElement::TSTypeReference(it) => it.format(p), - TSTupleElement::TSUnionType(it) => it.format(p), - TSTupleElement::TSParenthesizedType(it) => it.format(p), - TSTupleElement::JSDocNullableType(it) => it.format(p), - TSTupleElement::JSDocNonNullableType(it) => it.format(p), - TSTupleElement::JSDocUnknownType(it) => it.format(p), - } - } -} - -impl<'a> Format<'a> for Function<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, Function, { function::print_function(p, self, None) }) - } -} - -impl<'a> Format<'a> for FunctionBody<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, FunctionBody, { - block::print_block(p, &self.statements, Some(&self.directives)) - }) - } -} - -impl<'a> Format<'a> for FormalParameters<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, FormalParameters, { - function_parameters::print_function_parameters(p, self) - }) - } -} - -impl<'a> Format<'a> for FormalParameter<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, FormalParameter, { self.pattern.format(p) }) - } -} - -impl<'a> Format<'a> for ImportDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(text!("import")); - if self.import_kind.is_type() { - parts.push(text!(" type")); - } - - if let Some(specifiers) = &self.specifiers { - let is_default = specifiers.first().is_some_and(|x| { - matches!(x, ImportDeclarationSpecifier::ImportDefaultSpecifier(_)) - }); - - let validate_namespace = |x: &ImportDeclarationSpecifier| { - matches!(x, ImportDeclarationSpecifier::ImportNamespaceSpecifier(_)) - }; - - let is_namespace = specifiers.first().is_some_and(validate_namespace) - || specifiers.get(1).is_some_and(validate_namespace); - - parts.push(module::print_module_specifiers(p, specifiers, is_default, is_namespace)); - parts.push(text!(" from")); - } - parts.push(text!(" ")); - parts.push(self.source.format(p)); - - if let Some(with_clause) = &self.with_clause { - parts.push(text!(" ")); - parts.push(with_clause.format(p)); - } - - if let Some(semi) = p.semi() { - parts.push(semi); - } - array!(p, parts) - } -} - -impl<'a> Format<'a> for ImportDeclarationSpecifier<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::ImportSpecifier(specifier) => specifier.format(p), - Self::ImportDefaultSpecifier(specifier) => specifier.format(p), - Self::ImportNamespaceSpecifier(specifier) => specifier.format(p), - } - } -} - -impl<'a> Format<'a> for ImportSpecifier<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - 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); - array!(p, [typed, local_doc]) - } else { - let imported_doc = self.imported.format(p); - let local_doc = self.local.format(p); - array!(p, [typed, imported_doc, text!(" as "), local_doc]) - } - } -} - -impl<'a> Format<'a> for ImportDefaultSpecifier<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - self.local.format(p) - } -} - -impl<'a> Format<'a> for ImportNamespaceSpecifier<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let local_doc = self.local.format(p); - array!(p, [text!("* as "), local_doc]) - } -} - -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(p, ObjectLike::WithClause(self)); - array!(p, [attribute_keyword_doc, text!(" "), with_clause_doc]) - } -} - -impl<'a> Format<'a> for ImportAttribute<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let key_doc = self.key.format(p); - let value_doc = self.value.format(p); - array!(p, [key_doc, text!(": "), value_doc]) - } -} - -impl<'a> Format<'a> for ImportAttributeKey<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::Identifier(ident) => ident.format(p), - Self::StringLiteral(literal) => literal.format(p), - } - } -} - -impl<'a> Format<'a> for ExportNamedDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - if let Some(decl) = &self.declaration { - parts.push(text!(" ")); - parts.push(decl.format(p)); - } else { - parts.push(module::print_module_specifiers( - p, - &self.specifiers, - /* include_default */ false, - /* include_namespace */ false, - )); - } - 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); - 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); - array!(p, [text!(" as namespace "), id_doc, text!(";")]) - } -} - -impl<'a> Format<'a> for ExportSpecifier<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - if self.exported.span() == self.local.span() { - self.local.format(p) - } else { - let local_doc = self.local.format(p); - let exported_doc = self.exported.format(p); - array!(p, [local_doc, text!(" as "), exported_doc]) - } - } -} - -impl<'a> Format<'a> for ModuleExportName<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::IdentifierName(ident) => ident.format(p), - Self::IdentifierReference(ident) => ident.format(p), - Self::StringLiteral(literal) => literal.format(p), - } - } -} - -impl<'a> Format<'a> for ExportAllDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(text!(" *")); - if let Some(exported) = &self.exported { - parts.push(text!(" as ")); - parts.push(exported.format(p)); - } - array!(p, parts) - } -} - -impl<'a> Format<'a> for ExportDefaultDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - self.declaration.format(p) - } -} -impl<'a> Format<'a> for ExportDefaultDeclarationKind<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - match_expression!(Self) => self.to_expression().format(p), - Self::FunctionDeclaration(decl) => decl.format(p), - Self::ClassDeclaration(decl) => decl.format(p), - Self::TSInterfaceDeclaration(decl) => decl.format(p), - } - } -} - -impl<'a> Format<'a> for Expression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::BooleanLiteral(lit) => lit.format(p), - Self::NullLiteral(lit) => lit.format(p), - Self::NumericLiteral(lit) => lit.format(p), - Self::BigIntLiteral(lit) => lit.format(p), - Self::RegExpLiteral(lit) => lit.format(p), - Self::StringLiteral(lit) => lit.format(p), - Self::Identifier(ident) => ident.format(p), - Self::ThisExpression(expr) => expr.format(p), - match_member_expression!(Self) => self.to_member_expression().format(p), - Self::CallExpression(expr) => expr.format(p), - Self::ArrayExpression(expr) => expr.format(p), - Self::ObjectExpression(expr) => expr.format(p), - Self::FunctionExpression(expr) => expr.format(p), - Self::ArrowFunctionExpression(expr) => expr.format(p), - Self::YieldExpression(expr) => expr.format(p), - Self::UpdateExpression(expr) => expr.format(p), - Self::UnaryExpression(expr) => expr.format(p), - Self::BinaryExpression(expr) => expr.format(p), - Self::PrivateInExpression(expr) => expr.format(p), - Self::LogicalExpression(expr) => expr.format(p), - Self::ConditionalExpression(expr) => expr.format(p), - Self::AssignmentExpression(expr) => expr.format(p), - Self::SequenceExpression(expr) => expr.format(p), - Self::ParenthesizedExpression(expr) => expr.format(p), - Self::ImportExpression(expr) => expr.format(p), - Self::TemplateLiteral(literal) => literal.format(p), - Self::TaggedTemplateExpression(expr) => expr.format(p), - Self::Super(sup) => sup.format(p), - Self::AwaitExpression(expr) => expr.format(p), - Self::ChainExpression(expr) => expr.format(p), - Self::NewExpression(expr) => expr.format(p), - Self::MetaProperty(expr) => expr.format(p), - Self::ClassExpression(expr) => expr.format(p), - Self::JSXElement(el) => el.format(p), - Self::JSXFragment(fragment) => fragment.format(p), - Self::TSAsExpression(expr) => expr.format(p), - Self::TSSatisfiesExpression(expr) => expr.format(p), - Self::TSTypeAssertion(expr) => expr.format(p), - Self::TSNonNullExpression(expr) => expr.format(p), - Self::TSInstantiationExpression(expr) => expr.format(p), - } - } -} - -impl<'a> Format<'a> for IdentifierReference<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - 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> { - 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, { dynamic_text!(p, self.name.as_str()) }) - } -} - -impl<'a> Format<'a> for LabelIdentifier<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - dynamic_text!(p, self.name.as_str()) - } -} - -impl<'a> Format<'a> for BooleanLiteral { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!(if self.value { "true" } else { "false" }) - } -} - -impl<'a> Format<'a> for NullLiteral { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("null") - } -} - -impl<'a> Format<'a> for NumericLiteral<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, NumericLiteral, { - // See https://github.com/prettier/prettier/blob/3.3.3/src/utils/print-number.js - // Perf: the regexes from prettier code above are ported to manual search for performance reasons. - let mut string = self.span.source_text(p.source_text).cow_to_ascii_lowercase(); - - // Remove unnecessary plus and zeroes from scientific notation. - if let Some((head, tail)) = string.split_once('e') { - let negative = if tail.starts_with('-') { "-" } else { "" }; - let trimmed = tail.trim_start_matches(['+', '-']).trim_start_matches('0'); - if trimmed.starts_with(|c: char| c.is_ascii_digit()) { - string = Cow::Owned(std::format!("{head}e{negative}{trimmed}")); - } - } - - // Remove unnecessary scientific notation (1e0). - if let Some((head, tail)) = string.split_once('e') { - if tail.trim_start_matches(['+', '-']).trim_start_matches('0').is_empty() { - string = Cow::Owned(head.to_string()); - } - } - - // Make sure numbers always start with a digit. - if string.starts_with('.') { - string = Cow::Owned(std::format!("0{string}")); - } - - // Remove extraneous trailing decimal zeroes. - if let Some((head, tail)) = string.split_once('.') { - if let Some((head_e, tail_e)) = tail.split_once('e') { - if !head_e.is_empty() { - let trimmed = head_e.trim_end_matches('0'); - if trimmed.is_empty() { - string = Cow::Owned(std::format!("{head}.0e{tail_e}")); - } else { - string = Cow::Owned(std::format!("{head}.{trimmed}e{tail_e}")); - } - } - } else if !tail.is_empty() { - let trimmed = tail.trim_end_matches('0'); - if trimmed.is_empty() { - string = Cow::Owned(std::format!("{head}.0")); - } else { - string = Cow::Owned(std::format!("{head}.{trimmed}")); - } - } - } - - // Remove trailing dot. - if let Some((head, tail)) = string.split_once('.') { - if tail.is_empty() { - string = Cow::Owned(head.to_string()); - } else if tail.starts_with('e') { - string = Cow::Owned(std::format!("{head}{tail}")); - } - } - - dynamic_text!(p, &string) - }) - } -} - -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) => 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 = 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)); - array!(p, parts) - } -} - -impl<'a> Format<'a> for StringLiteral<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'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 - 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> { - text!("this") - } -} - -impl<'a> Format<'a> for MemberExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, MemberExpression, { - match self { - Self::ComputedMemberExpression(expr) => expr.format(p), - Self::StaticMemberExpression(expr) => expr.format(p), - Self::PrivateFieldExpression(expr) => expr.format(p), - } - }) - } -} - -impl<'a> Format<'a> for ComputedMemberExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(self.object.format(p)); - if self.optional { - parts.push(text!("?.")); - } - parts.push(text!("[")); - parts.push(self.expression.format(p)); - 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 = Vec::new_in(p.allocator); - parts.push(self.object.format(p)); - if self.optional { - parts.push(text!("?")); - } - parts.push(text!(".")); - parts.push(self.property.format(p)); - array!(p, parts) - } -} - -impl<'a> Format<'a> for PrivateFieldExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(self.object.format(p)); - parts.push(if self.optional { text!("?.") } else { text!(".") }); - parts.push(self.field.format(p)); - array!(p, parts) - } -} - -impl<'a> Format<'a> for CallExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, CallExpression, { - call_expression::print_call_expression( - p, - &call_expression::CallExpressionLike::CallExpression(self), - ) - }) - } -} - -impl<'a> Format<'a> for Argument<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - match_expression!(Self) => self.to_expression().format(p), - Self::SpreadElement(expr) => expr.format(p), - } - } -} - -impl<'a> Format<'a> for ArrayExpressionElement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::SpreadElement(expr) => expr.format(p), - match_expression!(Self) => self.to_expression().format(p), - Self::Elision(elision) => text!(""), - } - } -} - -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); - array!(p, [text!("..."), argument_doc]) - }) - } -} - -impl<'a> Format<'a> for ArrayExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ArrayExpression, { array::print_array(p, &Array::ArrayExpression(self)) }) - } -} - -impl<'a> Format<'a> for ObjectExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ObjectExpression, { - object::print_object(p, ObjectLike::Expression(self)) - }) - } -} - -impl<'a> Format<'a> for ObjectPropertyKind<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - ObjectPropertyKind::ObjectProperty(prop) => prop.format(p), - ObjectPropertyKind::SpreadProperty(prop) => prop.format(p), - } - } -} - -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 = Vec::new_in(p.allocator); - let mut method = self.method; - match self.kind { - PropertyKind::Get => { - parts.push(text!("get ")); - method = true; - } - PropertyKind::Set => { - parts.push(text!("set ")); - method = true; - } - PropertyKind::Init => (), - } - if method { - if let Expression::FunctionExpression(func_expr) = &self.value { - parts.push(wrap!(p, func_expr, Function, { - function::print_function( - p, - func_expr, - Some(self.key.span().source_text(p.source_text)), - ) - })); - } - } else { - parts.push(self.key.format(p)); - parts.push(text!(": ")); - parts.push(self.value.format(p)); - } - return group!(p, parts); - } - - if self.shorthand { - return self.value.format(p); - } - - let left_doc = if self.computed { - let key_doc = self.key.format(p); - array!(p, [text!("["), key_doc, text!("]")]) - } else { - self.key.format(p) - }; - - assignment::print_assignment( - p, - assignment::AssignmentLikeNode::ObjectProperty(self), - left_doc, - text!(":"), - Some(&self.value), - ) - }) - } -} - -impl<'a> Format<'a> for PropertyKey<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let is_parent_computed = match p.current_kind() { - AstKind::MethodDefinition(node) => node.computed, - AstKind::PropertyDefinition(node) => node.computed, - _ => false, - }; - if is_parent_computed { - 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(text!("]")); - return array!(p, parts); - } - - wrap!(p, self, PropertyKey, { - // Perf: Cache the result of `need_quote` to avoid checking it in each PropertyKey - let need_quote = p.options.quote_props.consistent() - && match p.parent_parent_kind() { - Some(AstKind::ObjectExpression(a)) => a.properties.iter().any(|x| match x { - ObjectPropertyKind::ObjectProperty(p) => { - property::is_property_key_has_quote(&p.key) - } - ObjectPropertyKind::SpreadProperty(_) => false, - }), - Some(AstKind::ClassBody(a)) => a.body.iter().any(|x| match x { - ClassElement::PropertyDefinition(p) => { - property::is_property_key_has_quote(&p.key) - } - _ => false, - }), - _ => false, - }; - - match self { - PropertyKey::StaticIdentifier(ident) => { - if need_quote { - dynamic_text!( - p, - string::print_string(p, &ident.name, p.options.single_quote) - ) - } else { - ident.format(p) - } - } - PropertyKey::PrivateIdentifier(ident) => ident.format(p), - PropertyKey::StringLiteral(literal) => { - // This does not pass quotes/objects.js - // because prettier uses the function `isEs5IdentifierName` based on unicode version 3, - // but `is_identifier_name` uses the latest unicode version. - if is_identifier_name(literal.value.as_str()) - && (p.options.quote_props.as_needed() - || (p.options.quote_props.consistent()/* && !needsQuoteProps.get(parent) */)) - { - dynamic_text!(p, literal.value.as_str()) - } else { - dynamic_text!( - p, - string::print_string(p, literal.value.as_str(), p.options.single_quote,) - ) - } - } - PropertyKey::NumericLiteral(literal) => { - if need_quote { - dynamic_text!( - p, - string::print_string(p, &literal.raw_str(), p.options.single_quote) - ) - } else { - literal.format(p) - } - } - PropertyKey::Identifier(ident) => { - let ident_doc = ident.format(p); - array!(p, [text!("["), ident_doc, text!("]")]) - } - match_expression!(PropertyKey) => self.to_expression().format(p), - } - }) - } -} - -impl<'a> Format<'a> for ArrowFunctionExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ArrowFunctionExpression, { arrow_function::print_arrow_function(p, self) }) - } -} - -impl<'a> Format<'a> for YieldExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, YieldExpression, { - let mut parts = Vec::new_in(p.allocator); - parts.push(text!("yield")); - if self.delegate { - parts.push(text!("*")); - } - if let Some(argument) = &self.argument { - parts.push(text!(" ")); - parts.push(argument.format(p)); - } - array!(p, parts) - }) - } -} - -impl<'a> Format<'a> for UpdateExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, UpdateExpression, { - if self.prefix { - let argument_doc = self.argument.format(p); - array!(p, [text!(self.operator.as_str()), argument_doc]) - } else { - let argument_doc = self.argument.format(p); - array!(p, [argument_doc, text!(self.operator.as_str())]) - } - }) - } -} - -impl<'a> Format<'a> for UnaryExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, UnaryExpression, { - let mut parts = Vec::new_in(p.allocator); - parts.push(dynamic_text!(p, self.operator.as_str())); - if self.operator.is_keyword() { - parts.push(text!(" ")); - } - parts.push(self.argument.format(p)); - array!(p, parts) - }) - } -} - -impl<'a> Format<'a> for BinaryExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, BinaryExpression, { - let doc = binaryish::print_binaryish_expression( - p, - &self.left, - self.operator.into(), - &self.right, - ); - if misc::in_parentheses(p.parent_kind(), p.source_text, self.span) { - group!(p, [indent!(p, [softline!(), doc]), softline!(),]) - } else { - doc - } - }) - } -} - -impl<'a> Format<'a> for PrivateInExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, PrivateInExpression, { - let left_doc = self.left.format(p); - let right_doc = self.right.format(p); - array!(p, [left_doc, text!(" "), text!(self.operator.as_str()), text!(" "), right_doc]) - }) - } -} - -impl<'a> Format<'a> for LogicalExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, LogicalExpression, { - let doc = binaryish::print_binaryish_expression( - p, - &self.left, - self.operator.into(), - &self.right, - ); - - if misc::in_parentheses(p.parent_kind(), p.source_text, self.span) { - group!(p, [indent!(p, [softline!(), doc]), softline!()]) - } else { - doc - } - }) - } -} - -impl<'a> Format<'a> for ConditionalExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ConditionalExpression, { ternary::print_ternary(p, self) }) - } -} - -impl<'a> Format<'a> for AssignmentExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, AssignmentExpression, { assignment::print_assignment_expression(p, self) }) - } -} - -impl<'a> Format<'a> for AssignmentTarget<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - match_simple_assignment_target!(Self) => self.to_simple_assignment_target().format(p), - match_assignment_target_pattern!(Self) => self.to_assignment_target_pattern().format(p), - } - } -} - -impl<'a> Format<'a> for SimpleAssignmentTarget<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::AssignmentTargetIdentifier(ident) => ident.format(p), - match_member_expression!(Self) => self.to_member_expression().format(p), - Self::TSAsExpression(expr) => expr.format(p), - Self::TSSatisfiesExpression(expr) => expr.format(p), - Self::TSNonNullExpression(expr) => expr.format(p), - Self::TSTypeAssertion(expr) => expr.format(p), - Self::TSInstantiationExpression(expr) => expr.format(p), - } - } -} - -impl<'a> Format<'a> for AssignmentTargetPattern<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::ArrayAssignmentTarget(target) => target.format(p), - Self::ObjectAssignmentTarget(target) => target.format(p), - } - } -} - -impl<'a> Format<'a> for ArrayAssignmentTarget<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - array::print_array(p, &Array::ArrayAssignmentTarget(self)) - } -} - -impl<'a> Format<'a> for AssignmentTargetMaybeDefault<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - match_assignment_target!(AssignmentTargetMaybeDefault) => { - self.to_assignment_target().format(p) - } - AssignmentTargetMaybeDefault::AssignmentTargetWithDefault(v) => v.format(p), - } - } -} - -impl<'a> Format<'a> for ObjectAssignmentTarget<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - object::print_object(p, ObjectLike::AssignmentTarget(self)) - } -} - -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); - array!(p, [binding_doc, text!(" = "), init_doc]) - } -} - -impl<'a> Format<'a> for AssignmentTargetProperty<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::AssignmentTargetPropertyIdentifier(ident) => ident.format(p), - Self::AssignmentTargetPropertyProperty(prop) => prop.format(p), - } - } -} - -impl<'a> Format<'a> for AssignmentTargetPropertyIdentifier<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(self.binding.format(p)); - if let Some(init) = &self.init { - parts.push(text!(" = ")); - parts.push(init.format(p)); - } - array!(p, parts) - } -} - -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); - 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); - array!(p, [text!("..."), target_doc]) - } -} - -impl<'a> Format<'a> for SequenceExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, SequenceExpression, { - let docs = - self.expressions.iter().map(|expr| expr.format(p)).collect::>(); - group!(p, [join!(p, JoinSeparator::CommaLine, docs)]) - }) - } -} - -impl<'a> Format<'a> for ParenthesizedExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - unreachable!("Parser preserve_parens option need to be set to false."); - } -} - -impl<'a> Format<'a> for ImportExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ImportExpression, { - 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(text!(",")); - indent_parts.push(line!()); - indent_parts.push(arg.format(p)); - } - } - parts.push(group!(p, [indent!(p, indent_parts)])); - parts.push(softline!()); - parts.push(text!(")")); - - group!(p, parts) - }) - } -} - -impl<'a> Format<'a> for TemplateLiteral<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - template_literal::print_template_literal(p, &TemplateLiteralPrinter::TemplateLiteral(self)) - } -} - -impl<'a> Format<'a> for TemplateElement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - // TODO: `replaceEndOfLine` - 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 = Vec::new_in(p.allocator); - - parts.push(self.tag.format(p)); - - if let Some(type_parameters) = &self.type_parameters { - parts.push(text!("<")); - parts.push(type_parameters.format(p)); - parts.push(text!(">")); - } - - parts.push(self.quasi.format(p)); - - array!(p, parts) - }) - } -} - -impl<'a> Format<'a> for Super { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - 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 = Vec::new_in(p.allocator); - parts.push(text!("await ")); - parts.push(self.argument.format(p)); - array!(p, parts) - }) - } -} - -impl<'a> Format<'a> for ChainExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ChainExpression, { self.expression.format(p) }) - } -} - -impl<'a> Format<'a> for ChainElement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - Self::CallExpression(expr) => expr.format(p), - Self::TSNonNullExpression(expr) => expr.format(p), - match_member_expression!(Self) => self.to_member_expression().format(p), - } - } -} - -impl<'a> Format<'a> for NewExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, NewExpression, { - call_expression::print_call_expression( - p, - &call_expression::CallExpressionLike::NewExpression(self), - ) - }) - } -} - -impl<'a> Format<'a> for MetaProperty<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let meta_doc = self.meta.format(p); - let property_doc = self.property.format(p); - array!(p, [meta_doc, text!("."), property_doc]) - } -} - -impl<'a> Format<'a> for Class<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, Class, { class::print_class(p, self) }) - } -} - -impl<'a> Format<'a> for ClassBody<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ClassBody, { class::print_class_body(p, self) }) - } -} - -impl<'a> Format<'a> for ClassElement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - ClassElement::StaticBlock(c) => c.format(p), - ClassElement::MethodDefinition(c) => c.format(p), - ClassElement::PropertyDefinition(c) => c.format(p), - ClassElement::AccessorProperty(c) => c.format(p), - ClassElement::TSIndexSignature(c) => c.format(p), - } - } -} - -impl<'a> Format<'a> for TSClassImplements<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - parts.push(self.expression.format(p)); - - if let Some(type_parameters) = &self.type_parameters { - parts.push(type_parameters.format(p)); - } - - array!(p, parts) - } -} - -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); - array!(p, [text!("<"), type_annotation_doc, text!(">"), expression_doc]) - } -} - -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); - array!(p, [expression_doc, text!(" satisfies "), type_annotation_doc]) - } -} - -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); - 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); - array!(p, [expression_doc, text!("!")]) - } -} - -impl<'a> Format<'a> for JSXIdentifier<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - dynamic_text!(p, self.name.as_str()) - } -} - -impl<'a> Format<'a> for JSXMemberExpressionObject<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - JSXMemberExpressionObject::IdentifierReference(it) => it.format(p), - JSXMemberExpressionObject::MemberExpression(it) => it.format(p), - JSXMemberExpressionObject::ThisExpression(it) => it.format(p), - } - } -} - -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); - array!(p, [object_doc, text!("."), property_doc]) - } -} - -impl<'a> Format<'a> for JSXElementName<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - JSXElementName::Identifier(it) => it.format(p), - JSXElementName::IdentifierReference(it) => it.format(p), - JSXElementName::MemberExpression(it) => it.format(p), - JSXElementName::NamespacedName(it) => it.format(p), - JSXElementName::ThisExpression(it) => it.format(p), - } - } -} - -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); - array!(p, [namespace_doc, text!(":"), property_doc]) - } -} - -impl<'a> Format<'a> for JSXAttributeName<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - JSXAttributeName::Identifier(it) => it.format(p), - JSXAttributeName::NamespacedName(it) => it.format(p), - } - } -} - -impl<'a> Format<'a> for JSXAttribute<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - parts.push(self.name.format(p)); - - if let Some(value) = &self.value { - parts.push(text!("=")); - parts.push(value.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for JSXEmptyExpression { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("") - } -} - -impl<'a> Format<'a> for JSXExpression<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - JSXExpression::EmptyExpression(it) => it.format(p), - match_member_expression!(Self) => self.to_member_expression().format(p), - JSXExpression::BooleanLiteral(it) => it.format(p), - JSXExpression::NullLiteral(it) => it.format(p), - JSXExpression::NumericLiteral(it) => it.format(p), - JSXExpression::BigIntLiteral(it) => it.format(p), - JSXExpression::RegExpLiteral(it) => it.format(p), - JSXExpression::StringLiteral(it) => it.format(p), - JSXExpression::TemplateLiteral(it) => it.format(p), - JSXExpression::Identifier(it) => it.format(p), - JSXExpression::MetaProperty(it) => it.format(p), - JSXExpression::Super(it) => it.format(p), - JSXExpression::ArrayExpression(it) => it.format(p), - JSXExpression::ArrowFunctionExpression(it) => it.format(p), - JSXExpression::AssignmentExpression(it) => it.format(p), - JSXExpression::AwaitExpression(it) => it.format(p), - JSXExpression::BinaryExpression(it) => it.format(p), - JSXExpression::CallExpression(it) => it.format(p), - JSXExpression::ChainExpression(it) => it.format(p), - JSXExpression::ClassExpression(it) => it.format(p), - JSXExpression::ConditionalExpression(it) => it.format(p), - JSXExpression::FunctionExpression(it) => it.format(p), - JSXExpression::ImportExpression(it) => it.format(p), - JSXExpression::LogicalExpression(it) => it.format(p), - JSXExpression::NewExpression(it) => it.format(p), - JSXExpression::ObjectExpression(it) => it.format(p), - JSXExpression::ParenthesizedExpression(it) => it.format(p), - JSXExpression::SequenceExpression(it) => it.format(p), - JSXExpression::TaggedTemplateExpression(it) => it.format(p), - JSXExpression::ThisExpression(it) => it.format(p), - JSXExpression::UnaryExpression(it) => it.format(p), - JSXExpression::UpdateExpression(it) => it.format(p), - JSXExpression::YieldExpression(it) => it.format(p), - JSXExpression::PrivateInExpression(it) => it.format(p), - JSXExpression::JSXElement(it) => it.format(p), - JSXExpression::JSXFragment(it) => it.format(p), - JSXExpression::TSAsExpression(it) => it.format(p), - JSXExpression::TSSatisfiesExpression(it) => it.format(p), - JSXExpression::TSTypeAssertion(it) => it.format(p), - JSXExpression::TSNonNullExpression(it) => it.format(p), - JSXExpression::TSInstantiationExpression(it) => it.format(p), - } - } -} - -impl<'a> Format<'a> for JSXExpressionContainer<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let expression_doc = self.expression.format(p); - array!(p, [text!("{"), expression_doc, text!("}")]) - } -} - -impl<'a> Format<'a> for JSXAttributeValue<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - JSXAttributeValue::Element(it) => it.format(p), - JSXAttributeValue::ExpressionContainer(it) => it.format(p), - JSXAttributeValue::Fragment(it) => it.format(p), - JSXAttributeValue::StringLiteral(it) => it.format(p), - } - } -} - -impl<'a> Format<'a> for JSXSpreadAttribute<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let argument_doc = self.argument.format(p); - array!(p, [text!("..."), argument_doc]) - } -} - -impl<'a> Format<'a> for JSXAttributeItem<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - JSXAttributeItem::Attribute(it) => it.format(p), - JSXAttributeItem::SpreadAttribute(it) => it.format(p), - } - } -} - -impl<'a> Format<'a> for JSXOpeningElement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - parts.push(text!("<")); - parts.push(self.name.format(p)); - - if let Some(type_parameters) = &self.type_parameters { - parts.push(type_parameters.format(p)); - } - - for attribute in &self.attributes { - parts.push(text!(" ")); - parts.push(attribute.format(p)); - } - - if self.self_closing { - parts.push(text!(" ")); - parts.push(text!("/")); - } - - parts.push(text!(">")); - - 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); - array!(p, [text!("")]) - } -} - -impl<'a> Format<'a> for JSXElement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - parts.push(self.opening_element.format(p)); - - for child in &self.children { - parts.push(child.format(p)); - } - - if let Some(closing_element) = &self.closing_element { - parts.push(closing_element.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for JSXOpeningFragment { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("<>") - } -} - -impl<'a> Format<'a> for JSXClosingFragment { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - text!("") - } -} - -impl<'a> Format<'a> for JSXText<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - 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); - array!(p, [text!("..."), expression_doc]) - } -} - -impl<'a> Format<'a> for JSXChild<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - JSXChild::Element(it) => it.format(p), - JSXChild::ExpressionContainer(it) => it.format(p), - JSXChild::Fragment(it) => it.format(p), - JSXChild::Spread(it) => it.format(p), - JSXChild::Text(it) => it.format(p), - } - } -} - -impl<'a> Format<'a> for JSXFragment<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - parts.push(self.opening_fragment.format(p)); - - for child in &self.children { - parts.push(child.format(p)); - } - - parts.push(self.closing_fragment.format(p)); - - array!(p, parts) - } -} - -impl<'a> Format<'a> for StaticBlock<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, StaticBlock, { - let block_doc = block::print_block(p, &self.body, None); - array!(p, [text!("static "), block_doc]) - }) - } -} - -impl<'a> Format<'a> for MethodDefinition<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, MethodDefinition, { function::print_method(p, self) }) - } -} - -impl<'a> Format<'a> for PropertyDefinition<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, PropertyDefinition, { - class::print_class_property(p, &class::ClassMemberish::PropertyDefinition(self)) - }) - } -} - -impl<'a> Format<'a> for AccessorProperty<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - class::print_class_property(p, &class::ClassMemberish::AccessorProperty(self)) - } -} - -impl<'a> Format<'a> for PrivateIdentifier<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - 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 = Vec::new_in(p.allocator); - parts.push(match self.kind { - BindingPatternKind::BindingIdentifier(ref ident) => ident.format(p), - BindingPatternKind::ObjectPattern(ref pattern) => pattern.format(p), - BindingPatternKind::ArrayPattern(ref pattern) => pattern.format(p), - BindingPatternKind::AssignmentPattern(ref pattern) => pattern.format(p), - }); - - if self.optional { - parts.push(text!("?")); - } - - if let Some(typ) = &self.type_annotation { - let type_annotation_doc = typ.type_annotation.format(p); - parts.push(array!(p, [text!(": "), type_annotation_doc])); - } - array!(p, parts) - } -} - -impl<'a> Format<'a> for ObjectPattern<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ObjectPattern, { - object::print_object(p, ObjectLike::Pattern(self)) - }) - } -} - -impl<'a> Format<'a> for BindingProperty<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - if self.shorthand { - self.value.format(p) - } else { - let key_doc = self.key.format(p); - let value_doc = self.value.format(p); - group!(p, [key_doc, text!(": "), value_doc]) - } - } -} - -impl<'a> Format<'a> for BindingRestElement<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let argument_doc = self.argument.format(p); - array!(p, [text!("..."), argument_doc]) - } -} - -impl<'a> Format<'a> for ArrayPattern<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, ArrayPattern, { array::print_array(p, &Array::ArrayPattern(self)) }) - } -} - -impl<'a> Format<'a> for AssignmentPattern<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - wrap!(p, self, AssignmentPattern, { - let left_doc = self.left.format(p); - let right_doc = self.right.format(p); - array!(p, [left_doc, text!(" = "), right_doc]) - }) - } -} - -impl<'a> Format<'a> for RegExpFlags { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut string = std::vec::Vec::with_capacity(self.iter().count()); - if self.contains(Self::D) { - string.push('d'); - } - if self.contains(Self::G) { - string.push('g'); - } - if self.contains(Self::I) { - string.push('i'); - } - if self.contains(Self::M) { - string.push('m'); - } - if self.contains(Self::S) { - string.push('s'); - } - if self.contains(Self::U) { - string.push('u'); - } - if self.contains(Self::V) { - string.push('v'); - } - if self.contains(Self::Y) { - string.push('y'); - } - let sorted = string.iter().collect::(); - dynamic_text!(p, &sorted) - } -} - -impl<'a> Format<'a> for TSIndexSignature<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - if self.readonly { - parts.push(text!("readonly ")); - } - - parts.push(text!("[")); - for param in &self.parameters { - parts.push(param.format(p)); - } - parts.push(text!("]: ")); - parts.push(self.type_annotation.type_annotation.format(p)); - - 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); - 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 = Vec::new_in(p.allocator); - if self.readonly { - parts.push(text!("readonly ")); - } - parts.push(self.key.format(p)); - if let Some(ty) = &self.type_annotation { - if self.optional { - parts.push(text!("?")); - } - parts.push(text!(":")); - parts.push(text!(" ")); - parts.push(ty.type_annotation.format(p)); - } - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSCallSignatureDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - if let Some(type_parameters) = &self.type_parameters { - parts.push(type_parameters.format(p)); - } - - parts.push(self.params.format(p)); - - if let Some(return_type) = &self.return_type { - parts.push(text!(": ")); - parts.push(return_type.type_annotation.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSConstructSignatureDeclaration<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - parts.push(text!("new ")); - - if let Some(type_parameters) = &self.type_parameters { - parts.push(type_parameters.format(p)); - } - - parts.push(self.params.format(p)); - - if let Some(return_type) = &self.return_type { - parts.push(text!(": ")); - parts.push(return_type.type_annotation.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSMethodSignature<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = Vec::new_in(p.allocator); - - if self.computed { - parts.push(text!("[")); - } - - parts.push(self.key.format(p)); - - if self.computed { - parts.push(text!("]")); - } - - if self.optional { - parts.push(text!("?")); - } - - if let Some(type_parameters) = &self.type_parameters { - parts.push(type_parameters.format(p)); - } - - parts.push(self.params.format(p)); - - if let Some(return_type) = &self.return_type { - parts.push(text!(": ")); - parts.push(return_type.type_annotation.format(p)); - } - - array!(p, parts) - } -} - -impl<'a> Format<'a> for TSSignature<'a> { - fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - match self { - TSSignature::TSIndexSignature(it) => it.format(p), - TSSignature::TSPropertySignature(it) => it.format(p), - TSSignature::TSCallSignatureDeclaration(it) => it.format(p), - TSSignature::TSConstructSignatureDeclaration(it) => it.format(p), - TSSignature::TSMethodSignature(it) => it.format(p), - } - } -} - -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); - array!(p, [expression_doc, text!(" as "), type_annotation_doc]) - } -} diff --git a/crates/oxc_prettier/src/format/array.rs b/crates/oxc_prettier/src/format/print/array.rs similarity index 98% rename from crates/oxc_prettier/src/format/array.rs rename to crates/oxc_prettier/src/format/print/array.rs index 28b23fffe3d70..37563d6ab5d50 100644 --- a/crates/oxc_prettier/src/format/array.rs +++ b/crates/oxc_prettier/src/format/print/array.rs @@ -12,7 +12,7 @@ use crate::{ }; #[allow(clippy::enum_variant_names)] -pub(super) enum Array<'a, 'b> { +pub enum Array<'a, 'b> { ArrayExpression(&'b ArrayExpression<'a>), TSTupleType(&'b TSTupleType<'a>), ArrayPattern(&'b ArrayPattern<'a>), @@ -61,7 +61,7 @@ impl Array<'_, '_> { } } -pub(super) fn print_array<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc<'a> { +pub fn print_array<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc<'a> { if arr.len() == 0 { return print_empty_array_elements(p, arr); } @@ -127,7 +127,7 @@ pub(super) fn print_array<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc< array!(p, parts) } -pub(super) fn is_concisely_printed_array<'a>(arr: &Expression<'a>) -> bool { +pub fn is_concisely_printed_array<'a>(arr: &Expression<'a>) -> bool { match arr { Expression::ArrayExpression(array) => Array::ArrayExpression(array).is_concisely_printed(), _ => false, diff --git a/crates/oxc_prettier/src/format/arrow_function.rs b/crates/oxc_prettier/src/format/print/arrow_function.rs similarity index 96% rename from crates/oxc_prettier/src/format/arrow_function.rs rename to crates/oxc_prettier/src/format/print/arrow_function.rs index 62bc0e66c4d92..9c0bbe6c7a673 100644 --- a/crates/oxc_prettier/src/format/arrow_function.rs +++ b/crates/oxc_prettier/src/format/print/arrow_function.rs @@ -3,7 +3,7 @@ use oxc_ast::ast::*; use crate::{array, group, ir::Doc, text, Format, Prettier}; -pub(super) fn print_arrow_function<'a>( +pub fn print_arrow_function<'a>( p: &mut Prettier<'a>, expr: &ArrowFunctionExpression<'a>, ) -> Doc<'a> { diff --git a/crates/oxc_prettier/src/format/assignment.rs b/crates/oxc_prettier/src/format/print/assignment.rs similarity index 97% rename from crates/oxc_prettier/src/format/assignment.rs rename to crates/oxc_prettier/src/format/print/assignment.rs index 944a970d15119..ff16f71934b4d 100644 --- a/crates/oxc_prettier/src/format/assignment.rs +++ b/crates/oxc_prettier/src/format/print/assignment.rs @@ -11,13 +11,13 @@ use oxc_ast::{ use crate::{ array, - format::{binaryish::should_inline_logical_expression, class::ClassMemberish}, + format::print::{binaryish::should_inline_logical_expression, class::ClassMemberish}, group, indent, indent_if_break, ir::Doc, line, text, Format, Prettier, }; -pub(super) fn print_assignment_expression<'a>( +pub fn print_assignment_expression<'a>( p: &mut Prettier<'a>, assignment_expr: &AssignmentExpression<'a>, ) -> Doc<'a> { @@ -31,7 +31,7 @@ pub(super) fn print_assignment_expression<'a>( ) } -pub(super) fn print_variable_declarator<'a>( +pub fn print_variable_declarator<'a>( p: &mut Prettier<'a>, variable_declarator: &VariableDeclarator<'a>, ) -> Doc<'a> { @@ -46,7 +46,7 @@ pub(super) fn print_variable_declarator<'a>( } #[derive(Debug, Clone, Copy)] -pub(super) enum AssignmentLikeNode<'a, 'b> { +pub enum AssignmentLikeNode<'a, 'b> { AssignmentExpression(&'b AssignmentExpression<'a>), VariableDeclarator(&'b VariableDeclarator<'a>), PropertyDefinition(&'b PropertyDefinition<'a>), @@ -67,7 +67,7 @@ impl<'a, 'b> From> for AssignmentLikeNode<'a, 'b> { } } -pub(super) fn print_assignment<'a>( +pub fn print_assignment<'a>( p: &mut Prettier<'a>, node: AssignmentLikeNode<'a, '_>, left_doc: Doc<'a>, @@ -266,7 +266,7 @@ fn has_complex_type_annotation(expr: &AssignmentLikeNode) -> bool { false } -pub(super) fn is_arrow_function_variable_declarator(expr: &AssignmentLikeNode) -> bool { +pub fn is_arrow_function_variable_declarator(expr: &AssignmentLikeNode) -> bool { match expr { AssignmentLikeNode::VariableDeclarator(variable_declarator) => { if let Some(Expression::ArrowFunctionExpression(_)) = &variable_declarator.init { diff --git a/crates/oxc_prettier/src/format/binaryish.rs b/crates/oxc_prettier/src/format/print/binaryish.rs similarity index 97% rename from crates/oxc_prettier/src/format/binaryish.rs rename to crates/oxc_prettier/src/format/print/binaryish.rs index 63ba25f6cef6e..5e03bb2937ee6 100644 --- a/crates/oxc_prettier/src/format/binaryish.rs +++ b/crates/oxc_prettier/src/format/print/binaryish.rs @@ -7,7 +7,7 @@ use crate::{ text, Format, Prettier, }; -pub(super) fn print_binaryish_expression<'a>( +pub fn print_binaryish_expression<'a>( p: &mut Prettier<'a>, left: &Expression<'a>, operator: BinaryishOperator, @@ -120,7 +120,7 @@ fn print_binaryish_expressions<'a>( parts } -pub(super) fn should_inline_logical_expression(expr: &Expression) -> bool { +pub fn should_inline_logical_expression(expr: &Expression) -> bool { let Expression::LogicalExpression(logical_expr) = expr else { return false }; if let Expression::ObjectExpression(obj_expr) = &logical_expr.right { diff --git a/crates/oxc_prettier/src/format/block.rs b/crates/oxc_prettier/src/format/print/block.rs similarity index 93% rename from crates/oxc_prettier/src/format/block.rs rename to crates/oxc_prettier/src/format/print/block.rs index a86d2fc264a94..d54868dfeebc8 100644 --- a/crates/oxc_prettier/src/format/block.rs +++ b/crates/oxc_prettier/src/format/print/block.rs @@ -1,9 +1,9 @@ use oxc_allocator::Vec; use oxc_ast::{ast::*, AstKind}; -use crate::{array, format::statement, hardline, indent, ir::Doc, text, Format, Prettier}; +use crate::{array, format::print::statement, hardline, indent, ir::Doc, text, Format, Prettier}; -pub(super) fn print_block<'a>( +pub fn print_block<'a>( p: &mut Prettier<'a>, stmts: &[Statement<'a>], directives: Option<&[Directive<'a>]>, @@ -48,7 +48,7 @@ pub(super) fn print_block<'a>( array!(p, parts) } -pub(super) fn print_block_body<'a>( +pub fn print_block_body<'a>( p: &mut Prettier<'a>, stmts: &[Statement<'a>], directives: Option<&[Directive<'a>]>, diff --git a/crates/oxc_prettier/src/format/call_arguments.rs b/crates/oxc_prettier/src/format/print/call_arguments.rs similarity index 99% rename from crates/oxc_prettier/src/format/call_arguments.rs rename to crates/oxc_prettier/src/format/print/call_arguments.rs index 2ef6b57feffff..cfe313753a0d5 100644 --- a/crates/oxc_prettier/src/format/call_arguments.rs +++ b/crates/oxc_prettier/src/format/print/call_arguments.rs @@ -5,7 +5,7 @@ use oxc_syntax::operator::UnaryOperator; use crate::{ array, break_parent, conditional_group, - format::{ + format::print::{ array::{is_concisely_printed_array, Array}, call_expression::{is_commons_js_or_amd_call, CallExpressionLike}, misc, @@ -17,7 +17,7 @@ use crate::{ Format, Prettier, }; -pub(super) fn print_call_arguments<'a>( +pub fn print_call_arguments<'a>( p: &mut Prettier<'a>, expression: &CallExpressionLike<'a, '_>, ) -> Doc<'a> { diff --git a/crates/oxc_prettier/src/format/call_expression.rs b/crates/oxc_prettier/src/format/print/call_expression.rs similarity index 89% rename from crates/oxc_prettier/src/format/call_expression.rs rename to crates/oxc_prettier/src/format/print/call_expression.rs index 3c96611da8429..cb12b998faa78 100644 --- a/crates/oxc_prettier/src/format/call_expression.rs +++ b/crates/oxc_prettier/src/format/print/call_expression.rs @@ -2,9 +2,11 @@ use oxc_allocator::Vec; use oxc_ast::ast::*; use oxc_span::{GetSpan, Span}; -use crate::{format::call_arguments::print_call_arguments, group, ir::Doc, text, Format, Prettier}; +use crate::{ + format::print::call_arguments::print_call_arguments, group, ir::Doc, text, Format, Prettier, +}; -pub(super) enum CallExpressionLike<'a, 'b> { +pub enum CallExpressionLike<'a, 'b> { CallExpression(&'b CallExpression<'a>), NewExpression(&'b NewExpression<'a>), } @@ -35,9 +37,7 @@ impl<'a> CallExpressionLike<'a, '_> { } } - fn type_parameters( - &self, - ) -> Option<&oxc_allocator::Box<'a, TSTypeParameterInstantiation<'a>>> { + fn type_parameters(&self) -> Option<&oxc_allocator::Box<'a, TSTypeParameterInstantiation<'a>>> { match self { CallExpressionLike::CallExpression(call) => call.type_parameters.as_ref(), CallExpressionLike::NewExpression(new) => new.type_parameters.as_ref(), @@ -54,7 +54,7 @@ impl GetSpan for CallExpressionLike<'_, '_> { } } -pub(super) fn print_call_expression<'a>( +pub fn print_call_expression<'a>( p: &mut Prettier<'a>, expression: &CallExpressionLike<'a, '_>, ) -> Doc<'a> { @@ -80,7 +80,7 @@ pub(super) fn print_call_expression<'a>( } /// -pub(super) fn is_commons_js_or_amd_call<'a>( +pub fn is_commons_js_or_amd_call<'a>( callee: &Expression<'a>, arguments: &Vec<'a, Argument<'a>>, ) -> bool { diff --git a/crates/oxc_prettier/src/format/class.rs b/crates/oxc_prettier/src/format/print/class.rs similarity index 94% rename from crates/oxc_prettier/src/format/class.rs rename to crates/oxc_prettier/src/format/print/class.rs index 48aa5e971f0d1..1784b76802901 100644 --- a/crates/oxc_prettier/src/format/class.rs +++ b/crates/oxc_prettier/src/format/print/class.rs @@ -6,13 +6,13 @@ use oxc_span::GetSpan; use crate::{ array, - format::{assignment, assignment::AssignmentLikeNode}, + format::print::assignment::{print_assignment, AssignmentLikeNode}, group, hardline, if_break, indent, ir::{Doc, JoinSeparator}, join, line, softline, text, Format, Prettier, }; -pub(super) fn print_class<'a>(p: &mut Prettier<'a>, class: &Class<'a>) -> Doc<'a> { +pub fn print_class<'a>(p: &mut Prettier<'a>, class: &Class<'a>) -> Doc<'a> { 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); @@ -23,14 +23,14 @@ pub(super) fn print_class<'a>(p: &mut Prettier<'a>, class: &Class<'a>) -> Doc<'a // @link let group_mode = class.implements.as_ref().is_some_and(|v| !v.is_empty()); - if let Some(super_class) = &class.super_class { + if let Some(_class) = &class.super_class { let mut extend_parts = Vec::new_in(p.allocator); extend_parts.push(text!("extends ")); - extend_parts.push(super_class.format(p)); + extend_parts.push(_class.format(p)); - if let Some(super_type_parameters) = &class.super_type_parameters { - extend_parts.push(super_type_parameters.format(p)); + if let Some(_type_parameters) = &class.super_type_parameters { + extend_parts.push(_type_parameters.format(p)); } extend_parts.push(text!(" ")); @@ -92,7 +92,7 @@ pub(super) fn print_class<'a>(p: &mut Prettier<'a>, class: &Class<'a>) -> Doc<'a array!(p, parts) } -pub(super) fn print_class_body<'a>(p: &mut Prettier<'a>, class_body: &ClassBody<'a>) -> Doc<'a> { +pub fn print_class_body<'a>(p: &mut Prettier<'a>, class_body: &ClassBody<'a>) -> Doc<'a> { let mut parts_inner = Vec::new_in(p.allocator); for (i, node) in class_body.body.iter().enumerate() { @@ -135,7 +135,7 @@ pub(super) fn print_class_body<'a>(p: &mut Prettier<'a>, class_body: &ClassBody< } #[derive(Debug)] -pub(super) enum ClassMemberish<'a, 'b> { +pub enum ClassMemberish<'a, 'b> { PropertyDefinition(&'b PropertyDefinition<'a>), AccessorProperty(&'b AccessorProperty<'a>), } @@ -243,10 +243,7 @@ impl<'a> ClassMemberish<'a, '_> { } } -pub(super) fn print_class_property<'a>( - p: &mut Prettier<'a>, - node: &ClassMemberish<'a, '_>, -) -> Doc<'a> { +pub fn print_class_property<'a>(p: &mut Prettier<'a>, node: &ClassMemberish<'a, '_>) -> Doc<'a> { let mut parts = Vec::new_in(p.allocator); if let Some(decarators) = node.decorators() { @@ -300,8 +297,7 @@ pub(super) fn print_class_property<'a>( ClassMemberish::PropertyDefinition(v) => AssignmentLikeNode::PropertyDefinition(v), ClassMemberish::AccessorProperty(v) => AssignmentLikeNode::AccessorProperty(v), }; - let mut result = - assignment::print_assignment(p, node, array!(p, parts), text!(" ="), right_expr); + let mut result = print_assignment(p, node, array!(p, parts), text!(" ="), right_expr); if p.options.semi { let mut parts = Vec::new_in(p.allocator); diff --git a/crates/oxc_prettier/src/format/function.rs b/crates/oxc_prettier/src/format/print/function.rs similarity index 90% rename from crates/oxc_prettier/src/format/function.rs rename to crates/oxc_prettier/src/format/print/function.rs index 4fe8ecf6fd526..d09d2c5e3676b 100644 --- a/crates/oxc_prettier/src/format/function.rs +++ b/crates/oxc_prettier/src/format/print/function.rs @@ -2,11 +2,11 @@ use oxc_allocator::Vec; use oxc_ast::ast::*; use crate::{ - array, dynamic_text, format::function_parameters::should_group_function_parameters, group, - if_break, indent, ir::Doc, softline, text, Format, Prettier, + array, dynamic_text, format::print::function_parameters::should_group_function_parameters, + group, if_break, indent, ir::Doc, softline, text, Format, Prettier, }; -pub(super) fn print_function<'a>( +pub fn print_function<'a>( p: &mut Prettier<'a>, func: &Function<'a>, property_name: Option<&'a str>, @@ -70,7 +70,7 @@ pub(super) fn print_function<'a>( array!(p, parts) } -pub(super) fn print_method<'a>(p: &mut Prettier<'a>, method: &MethodDefinition<'a>) -> Doc<'a> { +pub fn print_method<'a>(p: &mut Prettier<'a>, method: &MethodDefinition<'a>) -> Doc<'a> { let mut parts = Vec::new_in(p.allocator); if let Some(accessibility) = &method.accessibility { @@ -119,7 +119,7 @@ pub(super) fn print_method<'a>(p: &mut Prettier<'a>, method: &MethodDefinition<' array!(p, parts) } -pub(super) fn print_method_value<'a>(p: &mut Prettier<'a>, function: &Function<'a>) -> Doc<'a> { +pub fn print_method_value<'a>(p: &mut Prettier<'a>, function: &Function<'a>) -> Doc<'a> { let mut parts = Vec::new_in(p.allocator); let parameters_doc = function.params.format(p); let should_group_parameters = should_group_function_parameters(function); @@ -147,7 +147,7 @@ pub(super) fn print_method_value<'a>(p: &mut Prettier<'a>, function: &Function<' array!(p, parts) } -pub(super) fn print_return_or_throw_argument<'a>( +pub fn print_return_or_throw_argument<'a>( p: &mut Prettier<'a>, argument: Option<&Expression<'a>>, ) -> Doc<'a> { diff --git a/crates/oxc_prettier/src/format/function_parameters.rs b/crates/oxc_prettier/src/format/print/function_parameters.rs similarity index 97% rename from crates/oxc_prettier/src/format/function_parameters.rs rename to crates/oxc_prettier/src/format/print/function_parameters.rs index 5b969dab6acd1..84ffeaeb14169 100644 --- a/crates/oxc_prettier/src/format/function_parameters.rs +++ b/crates/oxc_prettier/src/format/print/function_parameters.rs @@ -6,7 +6,7 @@ use crate::{ text, Format, Prettier, }; -pub(super) fn should_hug_the_only_function_parameter( +pub fn should_hug_the_only_function_parameter( p: &mut Prettier<'_>, params: &FormalParameters<'_>, ) -> bool { @@ -57,7 +57,7 @@ pub(super) fn should_hug_the_only_function_parameter( } } -pub(super) fn print_function_parameters<'a>( +pub fn print_function_parameters<'a>( p: &mut Prettier<'a>, params: &FormalParameters<'a>, ) -> Doc<'a> { @@ -154,7 +154,7 @@ pub(super) fn print_function_parameters<'a>( } } -pub(super) fn should_group_function_parameters(func: &Function) -> bool { +pub fn should_group_function_parameters(func: &Function) -> bool { let Some(return_type) = &func.return_type else { return false; }; diff --git a/crates/oxc_prettier/src/format/misc.rs b/crates/oxc_prettier/src/format/print/misc.rs similarity index 87% rename from crates/oxc_prettier/src/format/misc.rs rename to crates/oxc_prettier/src/format/print/misc.rs index 37e47552c0938..70a11210d01cc 100644 --- a/crates/oxc_prettier/src/format/misc.rs +++ b/crates/oxc_prettier/src/format/print/misc.rs @@ -3,7 +3,7 @@ use oxc_span::Span; use crate::{array, indent, ir::Doc, line, text, Prettier}; -pub(super) fn adjust_clause<'a>( +pub fn adjust_clause<'a>( p: &Prettier<'a>, node: &Statement<'a>, clause: Doc<'a>, @@ -20,11 +20,11 @@ pub(super) fn adjust_clause<'a>( indent!(p, [line!(), clause]) } -pub(super) fn has_new_line_in_range(text: &str, start: u32, end: u32) -> bool { +pub fn has_new_line_in_range(text: &str, start: u32, end: u32) -> bool { text[(start as usize)..(end as usize)].contains('\n') } -pub(super) fn in_parentheses(kind: AstKind, text: &str, span: Span) -> bool { +pub fn in_parentheses(kind: AstKind, text: &str, span: Span) -> bool { if matches!( kind, AstKind::IfStatement(_) diff --git a/crates/oxc_prettier/src/format/print/mod.rs b/crates/oxc_prettier/src/format/print/mod.rs new file mode 100644 index 0000000000000..411902c3e0b46 --- /dev/null +++ b/crates/oxc_prettier/src/format/print/mod.rs @@ -0,0 +1,18 @@ +pub mod array; +pub mod arrow_function; +pub mod assignment; +pub mod binaryish; +pub mod block; +pub mod call_arguments; +pub mod call_expression; +pub mod class; +pub mod function; +pub mod function_parameters; +pub mod misc; +pub mod module; +pub mod object; +pub mod property; +pub mod statement; +pub mod string; +pub mod template_literal; +pub mod ternary; diff --git a/crates/oxc_prettier/src/format/module.rs b/crates/oxc_prettier/src/format/print/module.rs similarity index 96% rename from crates/oxc_prettier/src/format/module.rs rename to crates/oxc_prettier/src/format/print/module.rs index 6850ff5270b2e..5cd7d61bd4398 100644 --- a/crates/oxc_prettier/src/format/module.rs +++ b/crates/oxc_prettier/src/format/print/module.rs @@ -9,10 +9,7 @@ use crate::{ join, line, softline, text, Format, Prettier, }; -pub(super) fn print_export_declaration<'a>( - p: &mut Prettier<'a>, - decl: &ModuleDeclaration<'a>, -) -> Doc<'a> { +pub fn print_export_declaration<'a>(p: &mut Prettier<'a>, decl: &ModuleDeclaration<'a>) -> Doc<'a> { debug_assert!(decl.is_export()); let mut parts = Vec::new_in(p.allocator); @@ -81,7 +78,7 @@ fn print_semicolon_after_export_declaration<'a>( } } -pub(super) fn print_module_specifiers<'a, T: Format<'a>>( +pub fn print_module_specifiers<'a, T: Format<'a>>( p: &mut Prettier<'a>, specifiers: &Vec<'a, T>, include_default: bool, diff --git a/crates/oxc_prettier/src/format/object.rs b/crates/oxc_prettier/src/format/print/object.rs similarity index 95% rename from crates/oxc_prettier/src/format/object.rs rename to crates/oxc_prettier/src/format/print/object.rs index 6d4efa95f8a30..568f87305cfe3 100644 --- a/crates/oxc_prettier/src/format/object.rs +++ b/crates/oxc_prettier/src/format/print/object.rs @@ -1,20 +1,17 @@ use oxc_allocator::Vec; -use oxc_ast::{ - ast::{ObjectAssignmentTarget, ObjectExpression, ObjectPattern, TSTypeLiteral, WithClause}, - AstKind, -}; +use oxc_ast::{ast::*, AstKind}; use oxc_span::Span; use crate::{ array, - format::{function_parameters, misc}, + format::print::{function_parameters, misc}, group, if_break, indent, ir::Doc, line, softline, text, Format, Prettier, }; #[derive(Debug, Clone, Copy)] -pub(super) enum ObjectLike<'a, 'b> { +pub enum ObjectLike<'a, 'b> { Expression(&'b ObjectExpression<'a>), AssignmentTarget(&'b ObjectAssignmentTarget<'a>), Pattern(&'b ObjectPattern<'a>), @@ -98,10 +95,7 @@ impl<'a, 'b> ObjectLike<'a, 'b> { } } -pub(super) fn print_object<'a>( - p: &mut Prettier<'a>, - object: ObjectLike<'a, '_>, -) -> Doc<'a> { +pub fn print_object<'a>(p: &mut Prettier<'a>, object: ObjectLike<'a, '_>) -> Doc<'a> { let left_brace = text!("{"); let right_brace = text!("}"); diff --git a/crates/oxc_prettier/src/format/property.rs b/crates/oxc_prettier/src/format/print/property.rs similarity index 78% rename from crates/oxc_prettier/src/format/property.rs rename to crates/oxc_prettier/src/format/print/property.rs index 993cbdd861d89..59a60323d4baf 100644 --- a/crates/oxc_prettier/src/format/property.rs +++ b/crates/oxc_prettier/src/format/print/property.rs @@ -1,16 +1,16 @@ use oxc_ast::ast::PropertyKey; use oxc_syntax::identifier::is_identifier_name; -pub(super) fn is_property_key_has_quote(key: &PropertyKey<'_>) -> bool { +pub fn is_property_key_has_quote(key: &PropertyKey<'_>) -> bool { matches!(key, PropertyKey::StringLiteral(literal) if is_string_prop_safe_to_unquote(literal.value.as_str())) } -pub(super) fn is_string_prop_safe_to_unquote(value: &str) -> bool { +pub fn is_string_prop_safe_to_unquote(value: &str) -> bool { !is_identifier_name(value) && !is_simple_number(value) } // Matches “simple” numbers like `123` and `2.5` but not `1_000`, `1e+100` or `0b10`. -pub(super) fn is_simple_number(str: &str) -> bool { +pub fn is_simple_number(str: &str) -> bool { let mut bytes = str.as_bytes().iter(); let mut has_dot = false; bytes.next().is_some_and(u8::is_ascii_digit) diff --git a/crates/oxc_prettier/src/format/statement.rs b/crates/oxc_prettier/src/format/print/statement.rs similarity index 94% rename from crates/oxc_prettier/src/format/statement.rs rename to crates/oxc_prettier/src/format/print/statement.rs index 1637f6c8ef87f..8aeeb0cae1907 100644 --- a/crates/oxc_prettier/src/format/statement.rs +++ b/crates/oxc_prettier/src/format/print/statement.rs @@ -4,7 +4,7 @@ use oxc_span::GetSpan; use crate::{hardline, ir::Doc, Format, Prettier}; -pub(super) fn print_statement_sequence<'a>( +pub fn print_statement_sequence<'a>( p: &mut Prettier<'a>, stmts: &[Statement<'a>], ) -> Vec<'a, Doc<'a>> { diff --git a/crates/oxc_prettier/src/format/string.rs b/crates/oxc_prettier/src/format/print/string.rs similarity index 93% rename from crates/oxc_prettier/src/format/string.rs rename to crates/oxc_prettier/src/format/print/string.rs index 56f8f92b17419..c48ba8ff36279 100644 --- a/crates/oxc_prettier/src/format/string.rs +++ b/crates/oxc_prettier/src/format/print/string.rs @@ -55,11 +55,7 @@ fn make_string<'a>(p: &Prettier<'a>, raw_text: &str, enclosing_quote: char) -> S result } -pub(super) fn print_string<'a>( - p: &Prettier<'a>, - raw_text: &str, - prefer_single_quote: bool, -) -> &'a str { +pub fn print_string<'a>(p: &Prettier<'a>, raw_text: &str, prefer_single_quote: bool) -> &'a str { let enclosing_quote = get_preferred_quote(raw_text, prefer_single_quote); make_string(p, raw_text, enclosing_quote).into_bump_str() } diff --git a/crates/oxc_prettier/src/format/template_literal.rs b/crates/oxc_prettier/src/format/print/template_literal.rs similarity index 94% rename from crates/oxc_prettier/src/format/template_literal.rs rename to crates/oxc_prettier/src/format/print/template_literal.rs index eb438bb0d030d..2fe678a27c681 100644 --- a/crates/oxc_prettier/src/format/template_literal.rs +++ b/crates/oxc_prettier/src/format/print/template_literal.rs @@ -4,7 +4,7 @@ use oxc_ast::ast::*; use crate::{array, format::Format, ir::Doc, text, Prettier}; #[allow(clippy::enum_variant_names)] -pub(super) enum TemplateLiteralPrinter<'a, 'b> { +pub enum TemplateLiteralPrinter<'a, 'b> { TemplateLiteral(&'b TemplateLiteral<'a>), TSTemplateLiteralType(&'b TSTemplateLiteralType<'a>), } @@ -29,7 +29,7 @@ impl<'a> TemplateLiteralPrinter<'a, '_> { } } -pub(super) fn print_template_literal<'a, 'b>( +pub fn print_template_literal<'a, 'b>( p: &mut Prettier<'a>, template_literal: &'b TemplateLiteralPrinter<'a, 'b>, ) -> Doc<'a> { diff --git a/crates/oxc_prettier/src/format/ternary.rs b/crates/oxc_prettier/src/format/print/ternary.rs similarity index 80% rename from crates/oxc_prettier/src/format/ternary.rs rename to crates/oxc_prettier/src/format/print/ternary.rs index 0e9551ff5391e..5809c798e9b1d 100644 --- a/crates/oxc_prettier/src/format/ternary.rs +++ b/crates/oxc_prettier/src/format/print/ternary.rs @@ -2,7 +2,7 @@ use oxc_ast::ast::*; 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> { +pub 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); diff --git a/crates/oxc_prettier/src/format/typescript.rs b/crates/oxc_prettier/src/format/typescript.rs new file mode 100644 index 0000000000000..a900c63e75e9f --- /dev/null +++ b/crates/oxc_prettier/src/format/typescript.rs @@ -0,0 +1,1085 @@ +use oxc_allocator::Vec; +use oxc_ast::ast::*; +use oxc_span::GetSpan; + +use crate::{ + array, dynamic_text, + format::{ + print::{array, object, template_literal}, + Format, + }, + group, hardline, indent, + ir::{Doc, JoinSeparator}, + join, line, softline, text, wrap, Prettier, +}; + +impl<'a> Format<'a> for TSTypeAliasDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + if self.declare { + parts.push(text!("declare ")); + } + + parts.push(text!("type ")); + parts.push(self.id.format(p)); + + if let Some(params) = &self.type_parameters { + parts.push(params.format(p)); + } + + parts.push(text!(" = ")); + parts.push(self.type_annotation.format(p)); + + if let Some(semi) = p.semi() { + parts.push(semi); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSType<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + TSType::TSAnyKeyword(v) => v.format(p), + TSType::TSBigIntKeyword(v) => v.format(p), + TSType::TSBooleanKeyword(v) => v.format(p), + TSType::TSIntrinsicKeyword(v) => v.format(p), + TSType::TSNeverKeyword(v) => v.format(p), + TSType::TSNullKeyword(v) => v.format(p), + TSType::TSNumberKeyword(v) => v.format(p), + TSType::TSObjectKeyword(v) => v.format(p), + TSType::TSStringKeyword(v) => v.format(p), + TSType::TSSymbolKeyword(v) => v.format(p), + TSType::TSThisType(v) => v.format(p), + TSType::TSUndefinedKeyword(v) => v.format(p), + TSType::TSUnknownKeyword(v) => v.format(p), + TSType::TSVoidKeyword(v) => v.format(p), + TSType::TSArrayType(v) => v.format(p), + TSType::TSConditionalType(v) => v.format(p), + TSType::TSConstructorType(v) => v.format(p), + TSType::TSFunctionType(v) => v.format(p), + TSType::TSImportType(v) => v.format(p), + TSType::TSIndexedAccessType(v) => v.format(p), + TSType::TSInferType(v) => v.format(p), + TSType::TSIntersectionType(v) => v.format(p), + TSType::TSLiteralType(v) => v.format(p), + TSType::TSMappedType(v) => v.format(p), + TSType::TSNamedTupleMember(v) => v.format(p), + TSType::TSQualifiedName(v) => v.format(p), + TSType::TSTemplateLiteralType(v) => v.format(p), + TSType::TSTupleType(v) => v.format(p), + TSType::TSTypeLiteral(v) => v.format(p), + TSType::TSTypeOperatorType(v) => v.format(p), + TSType::TSTypePredicate(v) => v.format(p), + TSType::TSTypeQuery(v) => v.format(p), + TSType::TSTypeReference(v) => v.format(p), + TSType::TSUnionType(v) => v.format(p), + TSType::TSParenthesizedType(v) => v.format(p), + TSType::JSDocNullableType(v) => v.format(p), + TSType::JSDocNonNullableType(v) => v.format(p), + TSType::JSDocUnknownType(v) => v.format(p), + } + } +} + +impl<'a> Format<'a> for TSAnyKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("any") + } +} + +impl<'a> Format<'a> for TSBigIntKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("bigint") + } +} + +impl<'a> Format<'a> for TSBooleanKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("boolean") + } +} + +impl<'a> Format<'a> for TSIntrinsicKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("intrinsic") + } +} + +impl<'a> Format<'a> for TSNeverKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("never") + } +} + +impl<'a> Format<'a> for TSNullKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("null") + } +} + +impl<'a> Format<'a> for TSNumberKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("number") + } +} + +impl<'a> Format<'a> for TSObjectKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("object") + } +} + +impl<'a> Format<'a> for TSStringKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("string") + } +} + +impl<'a> Format<'a> for TSSymbolKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("symbol") + } +} + +impl<'a> Format<'a> for TSThisType { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("this") + } +} + +impl<'a> Format<'a> for TSUndefinedKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("undefined") + } +} + +impl<'a> Format<'a> for TSUnknownKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + text!("unknown") + } +} + +impl<'a> Format<'a> for TSVoidKeyword { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + 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); + 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 = Vec::new_in(p.allocator); + + parts.push(self.check_type.format(p)); + parts.push(text!(" extends ")); + parts.push(self.extends_type.format(p)); + parts.push(text!(" ? ")); + parts.push(self.true_type.format(p)); + parts.push(text!(" : ")); + parts.push(self.false_type.format(p)); + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSConstructorType<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + if self.r#abstract { + parts.push(text!("abstract ")); + } + parts.push(text!("new ")); + parts.push(self.params.format(p)); + let type_annotation_doc = self.return_type.type_annotation.format(p); + 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 = Vec::new_in(p.allocator); + + if let Some(type_parameters) = &self.type_parameters { + parts.push(type_parameters.format(p)); + } + + parts.push(self.params.format(p)); + + parts.push(text!(" => ")); + parts.push(self.return_type.type_annotation.format(p)); + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSThisParameter<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + parts.push(text!("this")); + + if let Some(type_annotation) = &self.type_annotation { + parts.push(text!(": ")); + parts.push(type_annotation.type_annotation.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSImportType<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + if self.is_type_of { + parts.push(text!("typeof ")); + } + + parts.push(text!("import(")); + parts.push(self.parameter.format(p)); + // ToDo: attributes + parts.push(text!(")")); + + if let Some(qualifier) = &self.qualifier { + parts.push(text!(".")); + parts.push(qualifier.format(p)); + } + + if let Some(type_parameters) = &self.type_parameters { + parts.push(type_parameters.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSIndexedAccessType<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + parts.push(self.object_type.format(p)); + parts.push(text!("[")); + parts.push(self.index_type.format(p)); + 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); + 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 = Vec::new_in(p.allocator); + let mut add_symbol = false; + + for ts_type in &self.types { + if add_symbol { + parts.push(text!(" & ")); + } else { + add_symbol = true; + } + + parts.push(ts_type.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSLiteralType<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match &self.literal { + TSLiteral::BooleanLiteral(v) => v.format(p), + TSLiteral::NullLiteral(v) => v.format(p), + TSLiteral::NumericLiteral(v) => v.format(p), + TSLiteral::BigIntLiteral(v) => v.format(p), + TSLiteral::RegExpLiteral(v) => v.format(p), + TSLiteral::StringLiteral(v) => v.format(p), + TSLiteral::TemplateLiteral(v) => v.format(p), + TSLiteral::UnaryExpression(v) => v.format(p), + } + } +} + +impl<'a> Format<'a> for TSMappedType<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts: Vec<'_, Doc<'_>> = Vec::new_in(p.allocator); + + match self.readonly { + TSMappedTypeModifierOperator::Plus => parts.push(text!("+readonly ")), + TSMappedTypeModifierOperator::Minus => parts.push(text!("-readonly ")), + TSMappedTypeModifierOperator::True => parts.push(text!("readonly ")), + TSMappedTypeModifierOperator::None => (), + } + + parts.push(text!("[")); + parts.push(self.type_parameter.format(p)); + + if let Some(name_type) = &self.name_type { + parts.push(text!(" as ")); + parts.push(name_type.format(p)); + } + + parts.push(text!("]")); + + match self.optional { + 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(text!(": ")); + parts.push(type_annotation.format(p)); + } + + 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 = Vec::new_in(p.allocator); + + parts.push(self.label.format(p)); + + if self.optional { + parts.push(text!("?")); + } + + parts.push(text!(": ")); + parts.push(self.element_type.format(p)); + + 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); + 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); + array!(p, [type_annotation_doc, text!("?")]) + } +} + +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); + array!(p, [left_doc, text!("."), right_doc]) + } +} + +impl<'a> Format<'a> for TSTemplateLiteralType<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + template_literal::print_template_literal( + p, + &template_literal::TemplateLiteralPrinter::TSTemplateLiteralType(self), + ) + } +} + +impl<'a> Format<'a> for TSTupleType<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + array::print_array(p, &array::Array::TSTupleType(self)) + } +} + +impl<'a> Format<'a> for TSTypeLiteral<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + object::print_object(p, object::ObjectLike::TSTypeLiteral(self)) + } +} + +impl<'a> Format<'a> for TSTypeOperator<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + parts.push(text!(self.operator.to_str())); + parts.push(text!(" ")); + parts.push(self.type_annotation.format(p)); + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSTypePredicate<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + if self.asserts { + parts.push(text!("asserts ")); + } + parts.push(self.parameter_name.format(p)); + + if let Some(type_annotation) = &self.type_annotation { + parts.push(text!(" is ")); + parts.push(type_annotation.type_annotation.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSTypePredicateName<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + TSTypePredicateName::Identifier(it) => it.format(p), + TSTypePredicateName::This(it) => it.format(p), + } + } +} + +impl<'a> Format<'a> for TSTypeQuery<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + parts.push(text!("typeof ")); + + match &self.expr_name { + TSTypeQueryExprName::TSImportType(import_type) => parts.push(import_type.format(p)), + TSTypeQueryExprName::IdentifierReference(identifier_reference) => { + parts.push(identifier_reference.format(p)); + } + TSTypeQueryExprName::QualifiedName(qualified_name) => { + parts.push(qualified_name.format(p)); + } + } + + if let Some(type_parameters) = &self.type_parameters { + parts.push(type_parameters.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSTypeReference<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + 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)); + } + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSParenthesizedType<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + wrap!(p, self, TSParenthesizedType, { self.type_annotation.format(p) }) + } +} + +impl<'a> Format<'a> for TSUnionType<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + let mut add_symbol = false; + + for ts_type in &self.types { + if add_symbol { + parts.push(text!(" | ")); + } else { + add_symbol = true; + } + + parts.push(ts_type.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for JSDocNullableType<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + line!() + } +} + +impl<'a> Format<'a> for JSDocNonNullableType<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + line!() + } +} + +impl<'a> Format<'a> for JSDocUnknownType { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + line!() + } +} + +impl<'a> Format<'a> for TSInterfaceDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + if self.declare { + parts.push(text!("declare ")); + } + + 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(text!(" ")); + + if let Some(extends) = &self.extends { + if extends.len() > 0 { + let mut extends_parts = Vec::new_in(p.allocator); + let mut display_comma = false; + + extends_parts.push(text!("extends ")); + + for extend in extends { + if display_comma { + extends_parts.push(text!(", ")); + } else { + display_comma = true; + } + + extends_parts.push(extend.expression.format(p)); + if let Some(type_parameters) = &extend.type_parameters { + extends_parts.push(type_parameters.format(p)); + } + } + + parts.extend(extends_parts); + parts.push(text!(" ")); + } + } + + parts.push(text!("{")); + if self.body.body.len() > 0 { + let mut indent_parts = Vec::new_in(p.allocator); + for sig in &self.body.body { + indent_parts.extend(hardline!()); + indent_parts.push(sig.format(p)); + + if let Some(semi) = p.semi() { + indent_parts.push(semi); + } + } + parts.push(indent!(p, indent_parts)); + parts.extend(hardline!()); + } + 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 = Vec::new_in(p.allocator); + if self.declare { + parts.push(text!("declare ")); + } + if self.r#const { + parts.push(text!("const ")); + } + parts.push(text!("enum ")); + parts.push(self.id.format(p)); + parts.push(text!(" {")); + if self.members.len() > 0 { + let mut indent_parts = Vec::new_in(p.allocator); + for member in &self.members { + indent_parts.extend(hardline!()); + indent_parts.push(member.format(p)); + } + parts.push(indent!(p, indent_parts)); + parts.extend(hardline!()); + } + parts.push(text!("}")); + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSEnumMember<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + parts.push(self.id.format(p)); + + if let Some(initializer) = &self.initializer { + parts.push(text!(" = ")); + parts.push(initializer.format(p)); + } + + parts.push(text!(",")); + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSEnumMemberName<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + TSEnumMemberName::Identifier(identifier) => identifier.format(p), + TSEnumMemberName::String(string_literal) => string_literal.format(p), + } + } +} + +impl<'a> Format<'a> for TSModuleDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + if self.declare { + parts.push(text!("declare ")); + } + + parts.push(text!(self.kind.as_str())); + parts.push(text!(" ")); + parts.push(self.id.format(p)); + parts.push(text!(" {")); + + if let Some(body) = &self.body { + if !body.is_empty() { + let mut indent_parts = Vec::new_in(p.allocator); + + indent_parts.extend(hardline!()); + indent_parts.push(body.format(p)); + + parts.push(indent!(p, indent_parts)); + parts.extend(hardline!()); + } + } + + parts.push(text!("}")); + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSModuleDeclarationName<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + TSModuleDeclarationName::Identifier(identifier) => identifier.format(p), + TSModuleDeclarationName::StringLiteral(string_literal) => string_literal.format(p), + } + } +} + +impl<'a> Format<'a> for TSModuleDeclarationBody<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + TSModuleDeclarationBody::TSModuleBlock(module_block) => module_block.format(p), + TSModuleDeclarationBody::TSModuleDeclaration(module_declaration) => { + module_declaration.format(p) + } + } + } +} + +impl<'a> Format<'a> for TSModuleBlock<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + let mut add_line = false; + + for body_part in &self.body { + if add_line { + parts.push(line!()); + } else { + add_line = true; + } + + parts.push(body_part.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSImportEqualsDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + parts.push(text!("import ")); + + if self.import_kind == ImportOrExportKind::Type { + parts.push(text!("type ")); + } + + parts.push(self.id.format(p)); + parts.push(text!(" = ")); + parts.push(self.module_reference.format(p)); + + if let Some(semi) = p.semi() { + parts.push(semi); + } + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSModuleReference<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + TSModuleReference::IdentifierReference(it) => it.format(p), + TSModuleReference::QualifiedName(it) => it.format(p), + TSModuleReference::ExternalModuleReference(v) => v.format(p), + } + } +} + +impl<'a> Format<'a> for TSTypeName<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + TSTypeName::IdentifierReference(it) => it.format(p), + TSTypeName::QualifiedName(it) => it.format(p), + } + } +} + +impl<'a> Format<'a> for TSExternalModuleReference<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let expression_doc = self.expression.format(p); + 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 = Vec::new_in(p.allocator); + + if self.r#in { + parts.push(text!("in ")); + } + + if self.out { + parts.push(text!("out ")); + } + + parts.push(self.name.format(p)); + + if let Some(constraint) = &self.constraint { + parts.push(text!(" extends ")); + parts.push(constraint.format(p)); + } + + if let Some(default) = &self.default { + parts.push(text!(" = ")); + parts.push(default.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSTypeParameterDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + let mut print_comma = false; + + parts.push(text!("<")); + + for param in &self.params { + if print_comma { + parts.push(text!(", ")); + } else { + print_comma = true; + } + + parts.push(param.format(p)); + } + + parts.push(text!(">")); + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSTypeParameterInstantiation<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + let mut print_comma = false; + + parts.push(text!("<")); + + for param in &self.params { + if print_comma { + parts.push(text!(", ")); + } else { + print_comma = true; + } + + parts.push(param.format(p)); + } + + parts.push(text!(">")); + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSTupleElement<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + TSTupleElement::TSOptionalType(it) => it.format(p), + TSTupleElement::TSRestType(it) => it.format(p), + TSTupleElement::TSAnyKeyword(it) => it.format(p), + TSTupleElement::TSBigIntKeyword(it) => it.format(p), + TSTupleElement::TSBooleanKeyword(it) => it.format(p), + TSTupleElement::TSIntrinsicKeyword(it) => it.format(p), + TSTupleElement::TSNeverKeyword(it) => it.format(p), + TSTupleElement::TSNullKeyword(it) => it.format(p), + TSTupleElement::TSNumberKeyword(it) => it.format(p), + TSTupleElement::TSObjectKeyword(it) => it.format(p), + TSTupleElement::TSStringKeyword(it) => it.format(p), + TSTupleElement::TSSymbolKeyword(it) => it.format(p), + TSTupleElement::TSUndefinedKeyword(it) => it.format(p), + TSTupleElement::TSUnknownKeyword(it) => it.format(p), + TSTupleElement::TSVoidKeyword(it) => it.format(p), + TSTupleElement::TSArrayType(it) => it.format(p), + TSTupleElement::TSConditionalType(it) => it.format(p), + TSTupleElement::TSConstructorType(it) => it.format(p), + TSTupleElement::TSFunctionType(it) => it.format(p), + TSTupleElement::TSImportType(it) => it.format(p), + TSTupleElement::TSIndexedAccessType(it) => it.format(p), + TSTupleElement::TSInferType(it) => it.format(p), + TSTupleElement::TSIntersectionType(it) => it.format(p), + TSTupleElement::TSLiteralType(it) => it.format(p), + TSTupleElement::TSMappedType(it) => it.format(p), + TSTupleElement::TSNamedTupleMember(it) => it.format(p), + TSTupleElement::TSQualifiedName(it) => it.format(p), + TSTupleElement::TSTemplateLiteralType(it) => it.format(p), + TSTupleElement::TSThisType(it) => it.format(p), + TSTupleElement::TSTupleType(it) => it.format(p), + TSTupleElement::TSTypeLiteral(it) => it.format(p), + TSTupleElement::TSTypeOperatorType(it) => it.format(p), + TSTupleElement::TSTypePredicate(it) => it.format(p), + TSTupleElement::TSTypeQuery(it) => it.format(p), + TSTupleElement::TSTypeReference(it) => it.format(p), + TSTupleElement::TSUnionType(it) => it.format(p), + TSTupleElement::TSParenthesizedType(it) => it.format(p), + TSTupleElement::JSDocNullableType(it) => it.format(p), + TSTupleElement::JSDocNonNullableType(it) => it.format(p), + TSTupleElement::JSDocUnknownType(it) => it.format(p), + } + } +} + +impl<'a> Format<'a> for TSExportAssignment<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let expression_doc = self.expression.format(p); + 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); + array!(p, [text!(" as namespace "), id_doc, text!(";")]) + } +} + +impl<'a> Format<'a> for TSClassImplements<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + parts.push(self.expression.format(p)); + + if let Some(type_parameters) = &self.type_parameters { + parts.push(type_parameters.format(p)); + } + + array!(p, parts) + } +} + +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); + array!(p, [text!("<"), type_annotation_doc, text!(">"), expression_doc]) + } +} + +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); + array!(p, [expression_doc, text!(" satisfies "), type_annotation_doc]) + } +} + +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); + 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); + array!(p, [expression_doc, text!("!")]) + } +} + +impl<'a> Format<'a> for TSIndexSignature<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + if self.readonly { + parts.push(text!("readonly ")); + } + + parts.push(text!("[")); + for param in &self.parameters { + parts.push(param.format(p)); + } + parts.push(text!("]: ")); + parts.push(self.type_annotation.type_annotation.format(p)); + + 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); + 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 = Vec::new_in(p.allocator); + if self.readonly { + parts.push(text!("readonly ")); + } + parts.push(self.key.format(p)); + if let Some(ty) = &self.type_annotation { + if self.optional { + parts.push(text!("?")); + } + parts.push(text!(":")); + parts.push(text!(" ")); + parts.push(ty.type_annotation.format(p)); + } + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSCallSignatureDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + if let Some(type_parameters) = &self.type_parameters { + parts.push(type_parameters.format(p)); + } + + parts.push(self.params.format(p)); + + if let Some(return_type) = &self.return_type { + parts.push(text!(": ")); + parts.push(return_type.type_annotation.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSConstructSignatureDeclaration<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + parts.push(text!("new ")); + + if let Some(type_parameters) = &self.type_parameters { + parts.push(type_parameters.format(p)); + } + + parts.push(self.params.format(p)); + + if let Some(return_type) = &self.return_type { + parts.push(text!(": ")); + parts.push(return_type.type_annotation.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSMethodSignature<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + let mut parts = Vec::new_in(p.allocator); + + if self.computed { + parts.push(text!("[")); + } + + parts.push(self.key.format(p)); + + if self.computed { + parts.push(text!("]")); + } + + if self.optional { + parts.push(text!("?")); + } + + if let Some(type_parameters) = &self.type_parameters { + parts.push(type_parameters.format(p)); + } + + parts.push(self.params.format(p)); + + if let Some(return_type) = &self.return_type { + parts.push(text!(": ")); + parts.push(return_type.type_annotation.format(p)); + } + + array!(p, parts) + } +} + +impl<'a> Format<'a> for TSSignature<'a> { + fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { + match self { + TSSignature::TSIndexSignature(it) => it.format(p), + TSSignature::TSPropertySignature(it) => it.format(p), + TSSignature::TSCallSignatureDeclaration(it) => it.format(p), + TSSignature::TSConstructSignatureDeclaration(it) => it.format(p), + TSSignature::TSMethodSignature(it) => it.format(p), + } + } +} + +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); + array!(p, [expression_doc, text!(" as "), type_annotation_doc]) + } +} From 22661b81cf9c625d87ff80ae5a64fa9c1e375675 Mon Sep 17 00:00:00 2001 From: Yuji Sugiura Date: Fri, 13 Dec 2024 15:41:00 +0900 Subject: [PATCH 8/8] Fix clippy --- crates/oxc_prettier/src/format/print/array.rs | 2 +- crates/oxc_prettier/src/format/print/call_arguments.rs | 2 +- crates/oxc_prettier/src/format/print/class.rs | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/oxc_prettier/src/format/print/array.rs b/crates/oxc_prettier/src/format/print/array.rs index 37563d6ab5d50..806ab05e27dc9 100644 --- a/crates/oxc_prettier/src/format/print/array.rs +++ b/crates/oxc_prettier/src/format/print/array.rs @@ -127,7 +127,7 @@ pub fn print_array<'a>(p: &mut Prettier<'a>, arr: &Array<'a, '_>) -> Doc<'a> { array!(p, parts) } -pub fn is_concisely_printed_array<'a>(arr: &Expression<'a>) -> bool { +pub fn is_concisely_printed_array(arr: &Expression) -> bool { match arr { Expression::ArrayExpression(array) => Array::ArrayExpression(array).is_concisely_printed(), _ => false, diff --git a/crates/oxc_prettier/src/format/print/call_arguments.rs b/crates/oxc_prettier/src/format/print/call_arguments.rs index cfe313753a0d5..337476debd2e1 100644 --- a/crates/oxc_prettier/src/format/print/call_arguments.rs +++ b/crates/oxc_prettier/src/format/print/call_arguments.rs @@ -248,7 +248,7 @@ fn should_expand_last_arg(args: &Vec<'_, Argument<'_>>) -> bool { && (args.len() != 2 || !matches!(penultimate_arg, Some(Argument::ArrowFunctionExpression(_))) || !matches!(last_arg, Expression::ArrayExpression(_))) - && !(args.len() > 1 && is_concisely_printed_array(&last_arg)) + && !(args.len() > 1 && is_concisely_printed_array(last_arg)) } fn is_hopefully_short_call_argument(mut node: &Expression) -> bool { diff --git a/crates/oxc_prettier/src/format/print/class.rs b/crates/oxc_prettier/src/format/print/class.rs index 1784b76802901..577d7c6eaf953 100644 --- a/crates/oxc_prettier/src/format/print/class.rs +++ b/crates/oxc_prettier/src/format/print/class.rs @@ -23,14 +23,14 @@ pub fn print_class<'a>(p: &mut Prettier<'a>, class: &Class<'a>) -> Doc<'a> { // @link let group_mode = class.implements.as_ref().is_some_and(|v| !v.is_empty()); - if let Some(_class) = &class.super_class { + if let Some(super_class) = &class.super_class { let mut extend_parts = Vec::new_in(p.allocator); extend_parts.push(text!("extends ")); - extend_parts.push(_class.format(p)); + extend_parts.push(super_class.format(p)); - if let Some(_type_parameters) = &class.super_type_parameters { - extend_parts.push(_type_parameters.format(p)); + if let Some(super_type_parameters) = &class.super_type_parameters { + extend_parts.push(super_type_parameters.format(p)); } extend_parts.push(text!(" "));