refactor(prettier): Verify current implementation with refactoring (#8412)

Part of #5068 

I think I will be able to grasp the current implementation status after
a few more iterations... 🏃🏻
This commit is contained in:
Yuji Sugiura 2025-01-10 18:31:33 +09:00 committed by GitHub
parent 0efc845c97
commit a93e27aca0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 118 additions and 181 deletions

View file

@ -11,8 +11,8 @@ use crate::{
format::{ format::{
print::{ print::{
array, arrow_function, assignment, binaryish, block, call_expression, class, function, array, arrow_function, assignment, binaryish, block, call_expression, class, function,
function_parameters, literal, misc, module, object, property, template_literal, function_parameters, literal, misc, module, object, property, statement,
ternary, template_literal, ternary,
}, },
Format, Format,
}, },
@ -129,29 +129,23 @@ impl<'a> Format<'a> for IfStatement<'a> {
wrap!(p, self, IfStatement, { wrap!(p, self, IfStatement, {
let mut parts = Vec::new_in(p.allocator); let mut parts = Vec::new_in(p.allocator);
let test_doc = self.test.format(p); let consequent_doc = self.consequent.format(p);
let consequent = self.consequent.format(p); parts.push(group!(
let consequent = misc::adjust_clause(p, &self.consequent, consequent, false);
let opening = group!(
p, p,
[ [
text!("if ("), text!("if ("),
group!(p, [indent!(p, [softline!(), test_doc]), softline!()]), group!(p, [indent!(p, [softline!(), self.test.format(p)]), softline!()]),
text!(")"), text!(")"),
consequent misc::adjust_clause(p, &self.consequent, consequent_doc, false)
] ]
); ));
parts.push(opening);
if let Some(alternate) = &self.alternate { if let Some(alternate) = &self.alternate {
let else_on_same_line = matches!(alternate, Statement::BlockStatement(_)); let else_on_same_line = matches!(alternate, Statement::BlockStatement(_));
if else_on_same_line { parts.push(if else_on_same_line { text!(" ") } else { hardline!(p) });
parts.push(text!(" "));
} else {
parts.push(hardline!(p));
}
parts.push(text!("else")); parts.push(text!("else"));
let alternate_doc = alternate.format(p); let alternate_doc = alternate.format(p);
parts.push(group!( parts.push(group!(
p, p,
@ -178,43 +172,42 @@ impl<'a> Format<'a> for BlockStatement<'a> {
impl<'a> Format<'a> for ForStatement<'a> { impl<'a> Format<'a> for ForStatement<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
wrap!(p, self, ForStatement, { wrap!(p, self, ForStatement, {
let body = self.body.format(p); let body_doc = self.body.format(p);
let body = misc::adjust_clause(p, &self.body, body, false); let body_doc = misc::adjust_clause(p, &self.body, body_doc, false);
if self.init.is_none() && self.test.is_none() && self.update.is_none() { if self.init.is_none() && self.test.is_none() && self.update.is_none() {
return group!(p, [text!("for (;;)"), body]); return group!(p, [text!("for (;;)"), body_doc]);
} }
let parts_head = { let mut init_test_update_parts = Vec::new_in(p.allocator);
let mut parts_head = Vec::new_in(p.allocator); init_test_update_parts.push(softline!());
parts_head.push(softline!());
if let Some(init) = &self.init { if let Some(init) = &self.init {
parts_head.push(init.format(p)); init_test_update_parts.push(match init {
}
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), ForStatementInit::VariableDeclaration(v) => v.format(p),
match_expression!(ForStatementInit) => self.to_expression().format(p), match_expression!(ForStatementInit) => init.to_expression().format(p),
});
} }
init_test_update_parts.push(text!(";"));
init_test_update_parts.push(line!());
if let Some(init) = &self.test {
init_test_update_parts.push(init.format(p));
}
init_test_update_parts.push(text!(";"));
init_test_update_parts.push(line!());
if let Some(init) = &self.update {
init_test_update_parts.push(init.format(p));
}
group!(
p,
[
text!("for ("),
group!(p, [indent!(p, init_test_update_parts), softline!()]),
text!(")"),
body_doc
]
)
})
} }
} }
@ -353,17 +346,15 @@ impl<'a> Format<'a> for SwitchStatement<'a> {
wrap!(p, self, SwitchStatement, { wrap!(p, self, SwitchStatement, {
let mut parts = Vec::new_in(p.allocator); let mut parts = Vec::new_in(p.allocator);
let mut header_parts = Vec::new_in(p.allocator); parts.push(group!(
p,
header_parts.push(text!("switch (")); [
text!("switch ("),
let discriminant_doc = self.discriminant.format(p); indent!(p, [softline!(), self.discriminant.format(p)]),
header_parts.push(indent!(p, [softline!(), discriminant_doc])); softline!(),
text!(")"),
header_parts.push(softline!()); ]
header_parts.push(text!(")")); ));
parts.push(group!(p, header_parts));
parts.push(text!(" {")); parts.push(text!(" {"));
@ -397,38 +388,16 @@ impl<'a> Format<'a> for SwitchCase<'a> {
parts.push(text!("default:")); parts.push(text!("default:"));
} }
let consequent: Vec<_> = Vec::from_iter_in( let len =
self.consequent.iter().filter(|c| !matches!(c, Statement::EmptyStatement(_))), self.consequent.iter().filter(|c| !matches!(c, Statement::EmptyStatement(_))).count();
p.allocator, if len != 0 {
); let consequent_parts =
let len = consequent.len(); statement::print_statement_sequence(p, self.consequent.as_slice());
let is_only_one_block_statement =
len == 1 && matches!(self.consequent[0], Statement::BlockStatement(_));
let mut consequent_parts = Vec::new_in(p.allocator); if len == 1 && matches!(self.consequent[0], Statement::BlockStatement(_)) {
for i in 0..len { parts.push(array!(p, [text!(" "), array!(p, consequent_parts)]));
let stmt = &consequent[i];
if i != 0 && matches!(stmt, Statement::BreakStatement(_)) {
let last_stmt = &consequent[i - 1];
if p.is_next_line_empty(last_stmt.span()) {
consequent_parts.push(hardline!(p));
}
}
if is_only_one_block_statement {
consequent_parts.push(text!(" "));
} else { } else {
consequent_parts.push(hardline!(p)); parts.push(indent!(p, [hardline!(p), array!(p, consequent_parts)]));
}
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)]));
} }
} }
@ -484,17 +453,14 @@ impl<'a> Format<'a> for TryStatement<'a> {
impl<'a> Format<'a> for CatchClause<'a> { impl<'a> Format<'a> for CatchClause<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
wrap!(p, self, CatchClause, { wrap!(p, self, CatchClause, {
let mut parts = Vec::new_in(p.allocator);
parts.push(text!("catch "));
if let Some(param) = &self.param { if let Some(param) = &self.param {
parts.push(text!("(")); return array!(
parts.push(param.pattern.format(p)); p,
parts.push(text!(") ")); [text!("catch ("), param.pattern.format(p), text!(") "), self.body.format(p)]
);
} }
parts.push(self.body.format(p));
array!(p, parts) array!(p, [text!("catch "), self.body.format(p)])
}) })
} }
} }
@ -618,7 +584,16 @@ impl<'a> Format<'a> for VariableDeclaration<'a> {
impl<'a> Format<'a> for VariableDeclarator<'a> { impl<'a> Format<'a> for VariableDeclarator<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
wrap!(p, self, VariableDeclarator, { assignment::print_variable_declarator(p, self) }) wrap!(p, self, VariableDeclarator, {
let left_doc = self.id.format(p);
assignment::print_assignment(
p,
assignment::AssignmentLikeNode::VariableDeclarator(self),
left_doc,
text!(" ="),
self.init.as_ref(),
)
})
} }
} }
@ -736,18 +711,11 @@ impl<'a> Format<'a> for WithClause<'a> {
impl<'a> Format<'a> for ImportAttribute<'a> { impl<'a> Format<'a> for ImportAttribute<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
let key_doc = self.key.format(p); let key_doc = match &self.key {
let value_doc = self.value.format(p); ImportAttributeKey::Identifier(ident) => ident.format(p),
array!(p, [key_doc, text!(": "), value_doc]) ImportAttributeKey::StringLiteral(literal) => literal.format(p),
} };
} group!(p, [group!(p, [key_doc]), text!(": "), self.value.format(p)])
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),
}
} }
} }
@ -805,16 +773,13 @@ impl<'a> Format<'a> for ExportAllDeclaration<'a> {
impl<'a> Format<'a> for ExportDefaultDeclaration<'a> { impl<'a> Format<'a> for ExportDefaultDeclaration<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
self.declaration.format(p) match &self.declaration {
match_expression!(ExportDefaultDeclarationKind) => {
self.declaration.to_expression().format(p)
} }
} ExportDefaultDeclarationKind::FunctionDeclaration(decl) => decl.format(p),
impl<'a> Format<'a> for ExportDefaultDeclarationKind<'a> { ExportDefaultDeclarationKind::ClassDeclaration(decl) => decl.format(p),
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { ExportDefaultDeclarationKind::TSInterfaceDeclaration(decl) => decl.format(p),
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),
} }
} }
} }
@ -1225,11 +1190,10 @@ impl<'a> Format<'a> for YieldExpression<'a> {
impl<'a> Format<'a> for UpdateExpression<'a> { impl<'a> Format<'a> for UpdateExpression<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
wrap!(p, self, UpdateExpression, { wrap!(p, self, UpdateExpression, {
if self.prefix {
let argument_doc = self.argument.format(p); let argument_doc = self.argument.format(p);
if self.prefix {
array!(p, [text!(self.operator.as_str()), argument_doc]) array!(p, [text!(self.operator.as_str()), argument_doc])
} else { } else {
let argument_doc = self.argument.format(p);
array!(p, [argument_doc, text!(self.operator.as_str())]) array!(p, [argument_doc, text!(self.operator.as_str())])
} }
}) })
@ -1305,7 +1269,16 @@ impl<'a> Format<'a> for ConditionalExpression<'a> {
impl<'a> Format<'a> for AssignmentExpression<'a> { impl<'a> Format<'a> for AssignmentExpression<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
wrap!(p, self, AssignmentExpression, { assignment::print_assignment_expression(p, self) }) wrap!(p, self, AssignmentExpression, {
let left_doc = self.left.format(p);
assignment::print_assignment(
p,
assignment::AssignmentLikeNode::AssignmentExpression(self),
left_doc,
array!(p, [text!(" "), text!(self.operator.as_str())]),
Some(&self.right),
)
})
} }
} }
@ -1495,17 +1468,15 @@ impl<'a> Format<'a> for AwaitExpression<'a> {
impl<'a> Format<'a> for ChainExpression<'a> { impl<'a> Format<'a> for ChainExpression<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
wrap!(p, self, ChainExpression, { self.expression.format(p) }) wrap!(p, self, ChainExpression, {
match &self.expression {
ChainElement::CallExpression(expr) => expr.format(p),
ChainElement::TSNonNullExpression(expr) => expr.format(p),
match_member_expression!(ChainElement) => {
self.expression.to_member_expression().format(p)
} }
}
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),
} }
})
} }
} }
@ -1522,9 +1493,7 @@ impl<'a> Format<'a> for NewExpression<'a> {
impl<'a> Format<'a> for MetaProperty<'a> { impl<'a> Format<'a> for MetaProperty<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
let meta_doc = self.meta.format(p); array!(p, [self.meta.format(p), text!("."), self.property.format(p)])
let property_doc = self.property.format(p);
array!(p, [meta_doc, text!("."), property_doc])
} }
} }
@ -1555,8 +1524,7 @@ impl<'a> Format<'a> for ClassElement<'a> {
impl<'a> Format<'a> for StaticBlock<'a> { impl<'a> Format<'a> for StaticBlock<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
wrap!(p, self, StaticBlock, { wrap!(p, self, StaticBlock, {
let block_doc = block::print_block(p, &self.body, None); array!(p, [text!("static "), block::print_block(p, &self.body, None)])
array!(p, [text!("static "), block_doc])
}) })
} }
} }

View file

@ -17,34 +17,6 @@ use crate::{
line, text, Format, Prettier, line, text, Format, Prettier,
}; };
pub fn print_assignment_expression<'a>(
p: &mut Prettier<'a>,
assignment_expr: &AssignmentExpression<'a>,
) -> Doc<'a> {
let left_doc = assignment_expr.left.format(p);
print_assignment(
p,
AssignmentLikeNode::AssignmentExpression(assignment_expr),
left_doc,
array!(p, [text!(" "), text!(assignment_expr.operator.as_str())]),
Some(&assignment_expr.right),
)
}
pub fn print_variable_declarator<'a>(
p: &mut Prettier<'a>,
variable_declarator: &VariableDeclarator<'a>,
) -> Doc<'a> {
let left_doc = variable_declarator.id.format(p);
print_assignment(
p,
AssignmentLikeNode::VariableDeclarator(variable_declarator),
left_doc,
text!(" ="),
variable_declarator.init.as_ref(),
)
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum AssignmentLikeNode<'a, 'b> { pub enum AssignmentLikeNode<'a, 'b> {
AssignmentExpression(&'b AssignmentExpression<'a>), AssignmentExpression(&'b AssignmentExpression<'a>),
@ -77,14 +49,14 @@ pub fn print_assignment<'a>(
let layout = choose_layout(p, &node, &left_doc, right_expr); let layout = choose_layout(p, &node, &left_doc, right_expr);
// TODO: set the layout in options so that when we print the right-hand side, we can refer to it. // TODO: set the layout in options so that when we print the right-hand side, we can refer to it.
let right_doc = if let Some(expr) = right_expr { expr.format(p) } else { array!(p, []) }; let right_doc = if let Some(expr) = right_expr { expr.format(p) } else { text!("") };
match layout { match layout {
Layout::BreakAfterOperator => { Layout::BreakAfterOperator => {
group!(p, [group!(p, [left_doc]), op, group!(p, [indent!(p, [line!(), right_doc])])]) group!(p, [group!(p, [left_doc]), op, group!(p, [indent!(p, [line!(), right_doc])])])
} }
Layout::NeverBreakAfterOperator => { Layout::NeverBreakAfterOperator => {
group!(p, [group!(p, [left_doc]), op, text!(" "), group!(p, [right_doc])]) group!(p, [group!(p, [left_doc]), op, text!(" "), right_doc])
} }
// First break right-hand side, then after operator // First break right-hand side, then after operator
Layout::Fluid => { Layout::Fluid => {

View file

@ -21,24 +21,15 @@ pub fn print_call_arguments<'a>(
p: &mut Prettier<'a>, p: &mut Prettier<'a>,
expression: &CallExpressionLike<'a, '_>, expression: &CallExpressionLike<'a, '_>,
) -> Doc<'a> { ) -> Doc<'a> {
let mut parts = Vec::new_in(p.allocator);
parts.push(text!("("));
let callee = expression.callee();
let arguments = expression.arguments(); let arguments = expression.arguments();
let should_break = if matches!(expression, CallExpressionLike::CallExpression(_)) {
!is_commons_js_or_amd_call(expression.callee(), arguments)
} else {
true
};
if arguments.is_empty() { if arguments.is_empty() {
parts.extend(p.print_inner_comment(Span::new(callee.span().end, expression.span().end))); return array!(p, [text!("("), text!(")")]);
parts.push(text!(")"));
return array!(p, parts);
} }
let mut parts = Vec::new_in(p.allocator);
parts.push(text!("("));
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
let get_printed_arguments = |p: &mut Prettier<'a>, skip_index: isize| { let get_printed_arguments = |p: &mut Prettier<'a>, skip_index: isize| {
let mut printed_arguments = Vec::new_in(p.allocator); let mut printed_arguments = Vec::new_in(p.allocator);
@ -195,6 +186,12 @@ pub fn print_call_arguments<'a>(
let mut printed_arguments = get_printed_arguments(p, 0); let mut printed_arguments = get_printed_arguments(p, 0);
let should_break = if matches!(expression, CallExpressionLike::CallExpression(_)) {
!is_commons_js_or_amd_call(expression.callee(), arguments)
} else {
true
};
if should_break { if should_break {
printed_arguments.insert(0, softline!()); printed_arguments.insert(0, softline!());
parts.push(indent!(p, printed_arguments)); parts.push(indent!(p, printed_arguments));