Repository: dprint/dprint-plugin-typescript (rust)

Issue:
Extra trailing space in else branch of a conditional type
**Describe the bug**

Extra trailing space after ":" is inserted when formatting a conditional type + intersection type

dprint-plugin-typescript version: 0.84.1

**Input Code**

```ts
type Type<T = any> = T extends never ? never
    : // <--- here!
        & { ephemeral?: T }
        & (
            | Object_Type
            | Union_Type
            | Intersection_Type
            | Enum_Member_Type
            | Generic_Type
            | Primitive
            | Enum_Type
            | Array_Type
            | Tuple_Type
            | Any_Type
            | Custom_Type
        )
    ;
```

**Expected Output**

```ts
type Type<T = any> = T extends never ? never
  // <--- here!
  :
    & { ephemeral?: T }
    & (
      | Object_Type
      | Union_Type
      | Intersection_Type
      | Enum_Member_Type
      | Generic_Type
      | Primitive
      | Enum_Type
      | Array_Type
      | Tuple_Type
      | Any_Type
      | Custom_Type
    );

```

**Actual Output**

```ts
type Type<T = any> = T extends never ? never
  // <--- here!
  : 
    & { ephemeral?: T }
    & (
      | Object_Type
      | Union_Type
      | Intersection_Type
      | Enum_Member_Type
      | Generic_Type
      | Primitive
      | Enum_Type
      | Array_Type
      | Tuple_Type
      | Any_Type
      | Custom_Type
    );
```


Pull request:
fix: ensure no trailing space after colon token in conditional type
Closes #516

Patch:
diff --git a/src/generation/generate.rs b/src/generation/generate.rs
index 019ba82..3302362 100644
--- a/src/generation/generate.rs
+++ b/src/generation/generate.rs
@@ -2815,7 +2815,7 @@ fn gen_sequence_expr<'a>(node: &'a SeqExpr, context: &mut Context<'a>) -> PrintI
     GenSeparatedValuesParams {
       nodes: node.exprs.iter().map(|x| NodeOrSeparator::Node(x.into())).collect(),
       prefer_hanging: context.config.sequence_expression_prefer_hanging,
-      force_use_new_lines: false,
+      force_use_new_lines: is_node_definitely_above_line_width(node.range(), context),
       allow_blank_lines: false,
       separator: TrailingCommas::Never.into(),
       single_line_space_at_start: false,
@@ -5153,7 +5153,7 @@ fn gen_try_stmt<'a>(node: &'a TryStmt, context: &mut Context<'a>) -> PrintItems
 
 fn gen_var_decl<'a>(node: &'a VarDecl, context: &mut Context<'a>) -> PrintItems {
   let mut items = PrintItems::new();
-  let force_use_new_lines = get_use_new_lines(&node.decls, context);
+  let force_use_new_lines = get_use_new_lines(node, context);
   if node.declare() {
     items.push_str("declare ");
   }
@@ -5203,8 +5203,13 @@ fn gen_var_decl<'a>(node: &'a VarDecl, context: &mut Context<'a>) -> PrintItems
       }
   }
 
-  fn get_use_new_lines<'a>(decls: &[&'a VarDeclarator], context: &mut Context) -> bool {
-    get_use_new_lines_for_nodes(decls, context.config.variable_statement_prefer_single_line, context)
+  fn get_use_new_lines<'a>(node: &VarDecl, context: &mut Context) -> bool {
+    if get_use_new_lines_for_nodes(&node.decls, context.config.variable_statement_prefer_single_line, context) {
+      true
+    } else {
+      // probably minified code
+      node.decls.len() >= 2 && is_node_definitely_above_line_width(node.range(), context)
+    }
   }
 }
 
@@ -5327,7 +5332,8 @@ fn gen_conditional_type<'a>(node: &'a TsConditionalType, context: &mut Context<'
       let mut items = PrintItems::new();
       items.extend(question_comment_items.leading_line);
       if question_position == OperatorPosition::NextLine {
-        items.push_str("? ");
+        items.push_str("?");
+        items.push_signal(Signal::SpaceIfNotTrailing);
       }
       items.extend(ir_helpers::new_line_group(gen_node(node.true_type.into(), context)));
       if colon_position == OperatorPosition::SameLine {
@@ -5370,7 +5376,8 @@ fn gen_conditional_type<'a>(node: &'a TsConditionalType, context: &mut Context<'
     items.push_info(before_false_ln);
     items.extend(colon_comment_items.leading_line);
     if colon_position == OperatorPosition::NextLine {
-      items.push_str(": ");
+      items.push_str(":");
+      items.push_signal(Signal::SpaceIfNotTrailing);
     }
     items.extend(ir_helpers::new_line_group(gen_node(node.false_type.into(), context)));
     items
@@ -9382,6 +9389,8 @@ fn is_node_definitely_above_line_width<'a>(range: SourceRange, context: &Context
       if count > max_width {
         return true;
       }
+    } else if c == '\n' {
+      return false;
     }
   }
   false


Test patch:
diff --git a/tests/specs/issues/issue0516.txt b/tests/specs/issues/issue0516.txt
new file mode 100644
index 0000000..a82b87b
--- /dev/null
+++ b/tests/specs/issues/issue0516.txt
@@ -0,0 +1,37 @@
+~~ indentWidth: 2 ~~
+== should not have trailing space ==
+type Type<T = any> = T extends never ? never
+    :
+        & { ephemeral?: T }
+        & (
+            | Object_Type
+            | Union_Type
+            | Intersection_Type
+            | Enum_Member_Type
+            | Generic_Type
+            | Primitive
+            | Enum_Type
+            | Array_Type
+            | Tuple_Type
+            | Any_Type
+            | Custom_Type
+        )
+    ;
+
+[expect]
+type Type<T = any> = T extends never ? never
+  :
+    & { ephemeral?: T }
+    & (
+      | Object_Type
+      | Union_Type
+      | Intersection_Type
+      | Enum_Member_Type
+      | Generic_Type
+      | Primitive
+      | Enum_Type
+      | Array_Type
+      | Tuple_Type
+      | Any_Type
+      | Custom_Type
+    );