diff --git a/crates/oxc_formatter/src/write/template.rs b/crates/oxc_formatter/src/write/template.rs index 4dbbe93b762e8..798bcddd7cf5c 100644 --- a/crates/oxc_formatter/src/write/template.rs +++ b/crates/oxc_formatter/src/write/template.rs @@ -223,6 +223,15 @@ pub(super) enum TemplateExpression<'a, 'b> { TSType(&'b AstNode<'a, TSType<'a>>), } +impl TemplateExpression<'_, '_> { + pub fn as_expression(&self) -> Option<&AstNode<'_, Expression<'_>>> { + match self { + Self::Expression(e) => Some(e), + Self::TSType(_) => None, + } + } +} + impl GetSpan for TemplateExpression<'_, '_> { fn span(&self) -> Span { match self { @@ -293,30 +302,25 @@ impl<'a> Format<'a> for FormatTemplateExpression<'a, '_> { } TemplateElementLayout::Fit => { // Determine if we should add indentation based on expression complexity - let indent = match self.expression { - TemplateExpression::Expression(e) => { - has_comment_in_expression - || match e.as_ref() { - Expression::StaticMemberExpression(_) - | Expression::ComputedMemberExpression(_) - | Expression::PrivateFieldExpression(_) - | Expression::ConditionalExpression(_) - | Expression::SequenceExpression(_) - | Expression::TSAsExpression(_) - | Expression::TSSatisfiesExpression(_) - | Expression::BinaryExpression(_) - | Expression::LogicalExpression(_) - | Expression::Identifier(_) => true, - Expression::ChainExpression(chain) => { - chain.expression.is_member_expression() - } - _ => false, + let indent = self.expression.as_expression().is_some_and(|e| { + has_comment_in_expression + || match e.as_ref() { + Expression::StaticMemberExpression(_) + | Expression::ComputedMemberExpression(_) + | Expression::PrivateFieldExpression(_) + | Expression::ConditionalExpression(_) + | Expression::SequenceExpression(_) + | Expression::TSAsExpression(_) + | Expression::TSSatisfiesExpression(_) + | Expression::BinaryExpression(_) + | Expression::LogicalExpression(_) + | Expression::Identifier(_) => true, + Expression::ChainExpression(chain) => { + chain.expression.is_member_expression() } - } - TemplateExpression::TSType(t) => { - self.options.after_new_line || is_complex_type(t.as_ref()) - } - }; + _ => false, + } + }); match &interned_expression { Some(element) if indent => { @@ -395,22 +399,6 @@ fn write_with_indention<'a, Content>( write!(f, [dedent_to_root(&format_aligned)]); } -/// Check if a TypeScript type is complex enough to warrant line breaks -#[inline] -fn is_complex_type(ts_type: &TSType) -> bool { - matches!( - ts_type, - TSType::TSConditionalType(_) - | TSType::TSMappedType(_) - | TSType::TSTypeLiteral(_) - | TSType::TSIntersectionType(_) - | TSType::TSUnionType(_) - | TSType::TSTupleType(_) - | TSType::TSArrayType(_) - | TSType::TSIndexedAccessType(_) - ) -} - #[derive(Debug)] enum EachTemplateElement<'a> { /// A significant value in the test each table. It's a row element. diff --git a/crates/oxc_formatter/tests/fixtures/ts/template-literal-type/issue-16136.ts b/crates/oxc_formatter/tests/fixtures/ts/template-literal-type/issue-16136.ts new file mode 100644 index 0000000000000..a3af9bde3e87d --- /dev/null +++ b/crates/oxc_formatter/tests/fixtures/ts/template-literal-type/issue-16136.ts @@ -0,0 +1,12 @@ +type templateLiteralType = `${ + TStringConvertedSoFar extends Capitalize + ? '_' + : '' +}`; + +type CamelToSnakeCase = + TCamelCaseString extends `${infer TStringConvertedSoFar}${infer TStringYetToConvert}` + ? `${TStringConvertedSoFar extends Capitalize + ? '_' + : ''}${Lowercase}${CamelToSnakeCase}` + : TCamelCaseString; \ No newline at end of file diff --git a/crates/oxc_formatter/tests/fixtures/ts/template-literal-type/issue-16136.ts.snap b/crates/oxc_formatter/tests/fixtures/ts/template-literal-type/issue-16136.ts.snap new file mode 100644 index 0000000000000..e26572b88043b --- /dev/null +++ b/crates/oxc_formatter/tests/fixtures/ts/template-literal-type/issue-16136.ts.snap @@ -0,0 +1,47 @@ +--- +source: crates/oxc_formatter/tests/fixtures/mod.rs +--- +==================== Input ==================== +type templateLiteralType = `${ + TStringConvertedSoFar extends Capitalize + ? '_' + : '' +}`; + +type CamelToSnakeCase = + TCamelCaseString extends `${infer TStringConvertedSoFar}${infer TStringYetToConvert}` + ? `${TStringConvertedSoFar extends Capitalize + ? '_' + : ''}${Lowercase}${CamelToSnakeCase}` + : TCamelCaseString; +==================== Output ==================== +------------------ +{ printWidth: 80 } +------------------ +type templateLiteralType = + `${TStringConvertedSoFar extends Capitalize + ? "_" + : ""}`; + +type CamelToSnakeCase = + TCamelCaseString extends `${infer TStringConvertedSoFar}${infer TStringYetToConvert}` + ? `${TStringConvertedSoFar extends Capitalize + ? "_" + : ""}${Lowercase}${CamelToSnakeCase}` + : TCamelCaseString; + +------------------- +{ printWidth: 100 } +------------------- +type templateLiteralType = `${TStringConvertedSoFar extends Capitalize + ? "_" + : ""}`; + +type CamelToSnakeCase = + TCamelCaseString extends `${infer TStringConvertedSoFar}${infer TStringYetToConvert}` + ? `${TStringConvertedSoFar extends Capitalize + ? "_" + : ""}${Lowercase}${CamelToSnakeCase}` + : TCamelCaseString; + +===================== End =====================