diff --git a/crates/oxc_formatter/src/utils/assignment_like.rs b/crates/oxc_formatter/src/utils/assignment_like.rs index a01be5a530df7..d1a75a1814005 100644 --- a/crates/oxc_formatter/src/utils/assignment_like.rs +++ b/crates/oxc_formatter/src/utils/assignment_like.rs @@ -446,7 +446,7 @@ impl<'a> AssignmentLike<'a, '_> { &self, is_left_short: bool, left_may_break: bool, - f: &Formatter<'_, 'a>, + f: &mut Formatter<'_, 'a>, ) -> AssignmentLikeLayout { let right_expression = self.get_right_expression(); if let Some(expr) = right_expression { @@ -610,7 +610,7 @@ impl<'a> AssignmentLike<'a, '_> { &self, right_expression: Option<&AstNode<'a, Expression<'a>>>, is_left_short: bool, - f: &Formatter<'_, 'a>, + f: &mut Formatter<'_, 'a>, ) -> bool { let comments = f.context().comments(); if let Some(right_expression) = right_expression { @@ -707,7 +707,7 @@ impl<'a> AssignmentLike<'a, '_> { fn should_break_after_operator<'a>( right: &AstNode<'a, Expression<'a>>, is_left_short: bool, - f: &Formatter<'_, 'a>, + f: &mut Formatter<'_, 'a>, ) -> bool { if right.is_jsx() { return false; @@ -919,7 +919,7 @@ impl<'a> Format<'a> for WithAssignmentLayout<'a, '_> { /// [Prettier applies]: fn is_poorly_breakable_member_or_call_chain<'a>( expression: &AstNode<'a, Expression<'a>>, - f: &Formatter<'_, 'a>, + f: &mut Formatter<'_, 'a>, ) -> bool { let threshold = f.options().line_width.value() / 4; @@ -1060,47 +1060,30 @@ fn is_short_argument(argument: &Expression, threshold: u16, f: &Formatter) -> bo /// We need it to decide if `CallExpression` with the type arguments is breakable or not. /// If the type arguments is complex the function call is breakable. /// -/// NOTE: This function does not follow Prettier exactly. -////// +/// fn is_complex_type_arguments<'a>( - type_arguments: &TSTypeParameterInstantiation<'a>, - f: &Formatter<'_, 'a>, + type_arguments: &AstNode<'a, TSTypeParameterInstantiation<'a>>, + f: &mut Formatter<'_, 'a>, ) -> bool { - let is_complex_ts_type = |ts_type: &TSType| match ts_type { - TSType::TSUnionType(_) | TSType::TSIntersectionType(_) | TSType::TSTypeLiteral(_) => true, - // Check for newlines after `{` in mapped types, as it will expand to multiple lines if so - TSType::TSMappedType(mapped) => f.source_text().has_newline_after(mapped.span.start + 1), - _ => false, - }; - - let is_complex_type_reference = |reference: &TSTypeReference| { - reference.type_arguments.as_ref().is_some_and(|type_arguments| { - type_arguments.params.iter().any(|param| match param { - TSType::TSTypeLiteral(literal) => literal.members.len() > 1, - _ => false, - }) - }) - }; - let params = &type_arguments.params; if params.len() > 1 { return true; } - // NOTE: Prettier checks `willBreak(print(typeArgs))` here. - // Our equivalent is `type_arguments.memoized().inspect(f).will_break()`, - // but we avoid using it because: - // - `inspect(f)` (= `f.intern()`) will update the comment counting state in `f` - // - And resulted IRs are discarded after this check - // So we approximate it by checking if the type arguments contain complex types. - if params.first().is_some_and(|param| match param { - TSType::TSTypeReference(reference) => is_complex_type_reference(reference), - ts_type => is_complex_ts_type(ts_type), + if params.first().is_some_and(|param| { + matches!( + param, + TSType::TSUnionType(_) | TSType::TSIntersectionType(_) | TSType::TSTypeLiteral(_) + ) }) { return true; } - f.comments().has_comment_in_span(type_arguments.span) + // Prettier: `willBreak(print(typeArgsKeyName))` + // NOTE: `f.intern()` would normally advance the comment cursor, but the caller + // (`is_poorly_breakable_member_or_call_chain`) already guards with + // `has_comment_in_span(call_expressions[0].span)`, so no comments exist here. + f.intern(type_arguments).is_some_and(|e| e.will_break()) } /// [Prettier applies]: