From 120197e370dde6df9961adc9603344434d93b658 Mon Sep 17 00:00:00 2001 From: divybot Date: Thu, 28 May 2026 15:26:39 +0000 Subject: [PATCH] fix: surround template literal type expressions with newlines on multi-line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a template literal type's `${...}` placeholder contains an expression that does not fit on a single line (notably a `TsUnionType` or `TsIntersectionType`), the generator broke on the separator (`|` / `&`) without adding the surrounding newlines + indent that `BinExpr`, `CondExpr`, etc. already trigger. This produced output like export type SortSelector = `${ | typeof Descending | typeof Ascending}${SortItems}`; instead of export type SortSelector = `${ typeof Descending | typeof Ascending }${SortItems}`; Adding `TsUnionType` and `TsIntersectionType` to `get_possible_surround_newlines` reuses the existing `surround_with_newlines_indented_if_multi_line` codepath, so the union expression stays on one line whenever it fits inside the indented inner column and otherwise gets a clean indented block — matching how `BinExpr` is already handled. Closes denoland/deno#29868 --- src/generation/generate.rs | 1 + .../specs/types/TplLitType/TplLitType_All.txt | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/generation/generate.rs b/src/generation/generate.rs index 7fb3a332..119454db 100644 --- a/src/generation/generate.rs +++ b/src/generation/generate.rs @@ -3279,6 +3279,7 @@ fn gen_template_literal<'a>(quasis: Vec>, exprs: Vec>, context Node::OptChainExpr(expr) => get_possible_surround_newlines(expr.base.as_node()), Node::CondExpr(_) => true, Node::BinExpr(_) => true, + Node::TsUnionType(_) | Node::TsIntersectionType(_) => true, Node::MemberExpr(expr) => !keep_member_expr_on_one_line(expr), Node::CallExpr(expr) => !keep_call_expr_on_one_line(expr.into()), Node::OptCall(expr) => !keep_call_expr_on_one_line(expr.into()), diff --git a/tests/specs/types/TplLitType/TplLitType_All.txt b/tests/specs/types/TplLitType/TplLitType_All.txt index 4a9f5632..52145bd3 100644 --- a/tests/specs/types/TplLitType/TplLitType_All.txt +++ b/tests/specs/types/TplLitType/TplLitType_All.txt @@ -1,5 +1,28 @@ +~~ lineWidth: 80, indentWidth: 2 ~~ == should format a template literal type == type Test = `${string & keyof T}Changed`; [expect] type Test = `${string & keyof T}Changed`; + +== should keep union template literal type expression on one line when it fits == +type Foo = `${typeof X | typeof Y}__${typeof Z | typeof W}`; + +[expect] +type Foo = `${typeof X | typeof Y}__${typeof Z | typeof W}`; + +== should surround union template literal type expression with newlines when too long == +export type SortSelector = `${typeof Descending | typeof Ascending}${SortItems}`; + +[expect] +export type SortSelector = `${ + typeof Descending | typeof Ascending +}${SortItems}`; + +== should surround intersection template literal type expression with newlines when too long == +export type IntersectionTpl = `${typeof Descending & typeof Ascending}${SortItems}`; + +[expect] +export type IntersectionTpl = `${ + typeof Descending & typeof Ascending +}${SortItems}`;