Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions crates/tsv_svelte/src/printer/nodes/tags_doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,32 @@ impl<'a> Printer<'a> {
);

// Choose layout matching prettier's assignment layout selection.
if d.will_break(init_doc) {
// Init has forced breaks (ternary, multi-line template, etc.)
// Keep "= init" together — init's own breaks handle formatting.
d.concat(&[
d.text("{@const "),
id_doc,
d.text(" = "),
init_doc,
d.text("}"),
])
} else if Self::const_should_break_after_op(&tag.init) {
if Self::const_should_break_after_op(&tag.init) {
// Binary expressions, conditional with binary test, etc.
// Break-after-operator: group with line at "=" so the doc printer
// can break when the flat form exceeds print width.
// can break when the flat form exceeds print width. This takes
// precedence over the `will_break` keep-together branch below — a
// break-after-operator RHS still breaks after `=` even when it has a
// forced internal break (e.g. a conditional whose binary test carries
// a trailing line comment), matching prettier and our own TS
// assignment printer.
// Prettier ref: shouldBreakAfterOperator (assignment.js:196-259)
let rhs = d.concat(&[d.line(), init_doc]);
let rhs_indented = d.indent(rhs);
let assignment = d.group(d.concat(&[d.text(" ="), rhs_indented, d.text("}")]));

d.concat(&[d.text("{@const "), id_doc, assignment])
} else if d.will_break(init_doc) {
// Init has forced breaks (object/array/template, etc.) that aren't
// break-after-operator — keep "= init" together, init's own breaks
// handle formatting.
d.concat(&[
d.text("{@const "),
id_doc,
d.text(" = "),
init_doc,
d.text("}"),
])
} else {
// Fluid layout: break at `=` only when the full line exceeds
// print width. Uses indentIfBreak so the RHS is evaluated
Expand Down
6 changes: 4 additions & 2 deletions crates/tsv_ts/src/printer/calls/arg_comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,15 +524,17 @@ impl<'a> PartitionedComments<'a> {
/// Emit trailing comments (block then line) with leading spaces to a parts vector.
///
/// Used for comments that follow an argument, formatted as ` /* block */ // line`.
/// Line comments go through `line_suffix` (zero width) so they never count against
/// the argument's own group — flushing at the caller's following hardline (every
/// caller is a forced-multiline context). Prettier's `lineSuffix`.
pub fn emit_trailing_comments(&self, parts: &mut Vec<DocId>, printer: &Printer<'_>) {
let d = printer.d();
for comment in &self.trailing_block {
parts.push(d.text(" "));
parts.push(printer.build_comment_doc(comment));
}
for comment in &self.trailing_line {
parts.push(d.text(" "));
parts.push(printer.build_comment_doc(comment));
parts.push(printer.build_trailing_line_comment_doc(comment));
}
}

Expand Down
23 changes: 11 additions & 12 deletions crates/tsv_ts/src/printer/calls/call_formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1094,12 +1094,15 @@ pub(super) fn build_call_doc_with_wrapping(
}

if pc.has_trailing_line() {
// Trailing line comments: comma, comment, hardline
// Trailing line comments: comma, comment, hardline. The comment
// goes through `line_suffix` (zero width) so it never counts
// against the argument's own group — a long trailing comment
// can't force a binary/conditional arg to break (prettier's
// `lineSuffix`). It still renders after the comma at end-of-line.
force_expansion = true;
arg_parts.push(d.text(","));
for comment in &pc.trailing_line {
arg_parts.push(d.text(" "));
arg_parts.push(printer.build_comment_doc(comment));
arg_parts.push(printer.build_trailing_line_comment_doc(comment));
}
if has_blank_line {
arg_parts.push(d.literalline());
Expand Down Expand Up @@ -1202,15 +1205,11 @@ pub(super) fn build_call_doc_with_wrapping(
// comment means the call must break to multiple lines.
force_expansion = true;

// Arrays/objects have their own groups that decide internal expansion.
// Use line_suffix to exclude the comment from width calculations, so
// the array/object can stay inline even when the comment exceeds print_width.
// The force_expansion above ensures the call itself expands.
if is_array_or_object_unwrapped(arg) {
arg_parts.push(d.line_suffix(comments));
} else {
arg_parts.push(comments);
}
// A trailing line comment never counts toward width (prettier's
// `lineSuffix`), so the argument's own group (array/object, binary,
// conditional, …) can stay inline even when the comment exceeds
// print_width. The force_expansion above ensures the call expands.
arg_parts.push(d.line_suffix(comments));
has_trailing_comma_on_last = true;
} else if pc.has_trailing_block() {
// Trailing block comments: place relative to the source comma.
Expand Down
6 changes: 4 additions & 2 deletions crates/tsv_ts/src/printer/calls/new_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,9 +433,11 @@ impl<'a> Printer<'a> {
arg_parts.push(self.build_comment_doc(comment));
}
arg_parts.push(d.text(","));
// Line comment via `line_suffix` (zero width) so it never forces
// the argument's own group to break; flushes at the hardline
// before the closing paren (prettier's `lineSuffix`).
for comment in &pc.trailing_line {
arg_parts.push(d.text(" "));
arg_parts.push(self.build_comment_doc(comment));
arg_parts.push(self.build_trailing_line_comment_doc(comment));
}
has_trailing_comma_on_last = true;
} else if pc.has_trailing_block() {
Expand Down
35 changes: 29 additions & 6 deletions crates/tsv_ts/src/printer/comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1368,13 +1368,34 @@ impl<'a> Printer<'a> {
///
/// Used when line comments force multiline formatting (unions, tuples, etc.)
pub(crate) fn build_trailing_comments_multiline(&self, start: u32, end: u32) -> Vec<DocId> {
self.build_trailing_comments_multiline_ext(start, end, false)
}

/// As `build_trailing_comments_multiline`, but when `suffix_same_line_lines` is set
/// a same-line **line** comment is routed through `line_suffix` (zero width) so it
/// can't force the preceding element to break. Only safe where the following
/// separator lands on a *new* line (so the suffix flushes at that hardline without
/// crossing the separator) — true for the union's leading-`|` form, but NOT the
/// intersection's trailing-`&` form (a same-line `//` there would otherwise comment
/// out the `&`; that case is handled as a comment-position divergence instead).
pub(crate) fn build_trailing_comments_multiline_ext(
&self,
start: u32,
end: u32,
suffix_same_line_lines: bool,
) -> Vec<DocId> {
let d = self.d();
let mut parts = Vec::new();
for comment in comments_in_range(self.comments, start, end) {
if self.is_same_line(start, comment.span.start) {
// Same line as start: trailing comment (both block and line)
parts.push(d.text(" "));
parts.push(self.build_comment_doc(comment));
if suffix_same_line_lines {
// Block → inline (width counted); line → line_suffix (zero width).
parts.push(self.build_trailing_comment_doc(comment));
} else {
// Same line as start: trailing comment (block or line), inline.
parts.push(d.text(" "));
parts.push(self.build_comment_doc(comment));
}
} else {
// Own line comment (block or line)
parts.push(d.hardline());
Expand Down Expand Up @@ -2246,12 +2267,14 @@ impl<'a> Printer<'a> {
// Comma
parts.push(d.text(","));

// Same-line trailing comments after comma (line comments that consume the line)
// Same-line trailing comments after comma (line comments that consume the line).
// A line comment goes through `line_suffix` (zero width) so it never forces the
// preceding element to break; it flushes at the hardline below (prettier's
// `lineSuffix`). A block stays inline, width counted.
let mut after_comma_end = comma_pos + 1;
for comment in comments_in_range(self.comments, comma_pos + 1, next_start) {
if self.is_same_line(elem_end, comment.span.start) {
parts.push(d.text(" "));
parts.push(self.build_comment_doc(comment));
parts.push(self.build_trailing_comment_doc(comment));
after_comma_end = comment.span.end;
}
}
Expand Down
8 changes: 5 additions & 3 deletions crates/tsv_ts/src/printer/expressions/conditional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,13 @@ impl<'a> Printer<'a> {

let mut parts = vec![test];

// Comments between test and ? (inline after test)
// Comments between test and ? (inline after test). A line comment goes
// through `line_suffix` (zero width), so a long trailing comment never
// forces the test (e.g. a binary expression) to break — matching
// prettier's `lineSuffix`. Block comments stay inline, width counted.
let comments_before_q_end = question_pos.unwrap_or(consequent_start);
for comment in tsv_lang::comments_in_range(self.comments, test_end, comments_before_q_end) {
parts.push(d.text(" "));
parts.push(self.build_comment_doc(comment));
parts.push(self.build_trailing_comment_doc(comment));
}

// Start the indented part with ? on new line
Expand Down
19 changes: 9 additions & 10 deletions crates/tsv_ts/src/printer/expressions/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -725,9 +725,12 @@ impl<'a> Printer<'a> {
let has_newline_before = self.has_newline_between(pos, comment.span.start);

if is_first && !has_newline_before {
// First comment on same line as operator: `a && // comment`
parts.push(d.text(" "));
parts.push(self.build_comment_doc(comment));
// First comment on same line as operator: `a && // comment`. A
// line comment goes through `line_suffix` (zero width), so a long
// trailing comment never forces the preceding operand group to
// break — matching prettier's `lineSuffix`. Block comments stay
// inline, width counted.
parts.push(self.build_trailing_comment_doc(comment));
} else {
// Comment on its own line
parts.push(d.hardline());
Expand Down Expand Up @@ -1170,13 +1173,9 @@ impl<'a> Printer<'a> {
if self.has_newline_between(pos, comment.span.start) {
break;
}
if comment.is_block {
od.push(d.text(" "));
od.push(self.build_comment_doc(comment));
} else {
let suffix = d.concat(&[d.text(" "), self.build_comment_doc(comment)]);
od.push(d.line_suffix(suffix));
}
// Same-line trailing comment: block inline before the comma, line
// comment deferred via `line_suffix` to render after the comma.
od.push(self.build_trailing_comment_doc(comment));
pos = comment.span.end;
}
}
Expand Down
7 changes: 5 additions & 2 deletions crates/tsv_ts/src/printer/statements/control_flow/switch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,11 @@ impl<'a> Printer<'a> {
tsv_lang::comments_in_range(self.comments, case_label_end, inline_comment_end)
{
if self.is_same_line(case_label_end, comment.span.start) {
parts.push(d.text(" "));
parts.push(self.build_comment_doc(comment));
// A line comment goes through `line_suffix` (zero width) so it never
// forces the case test (e.g. a binary expression) to break; it flushes
// at the consequent's hardline (prettier's `lineSuffix`). A block stays
// inline, width counted.
parts.push(self.build_trailing_comment_doc(comment));
if !comment.is_block {
has_inline_line_comment = true;
}
Expand Down
8 changes: 6 additions & 2 deletions crates/tsv_ts/src/printer/statements/variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,14 @@ impl<'a> Printer<'a> {
if needs_hardline {
parts.push(d.hardline());
parts.push(d.text(INDENT));
parts.push(self.build_comment_doc(comment));
} else {
parts.push(d.text(" "));
// Same-line comment trailing the comma: a line comment
// goes through `line_suffix` (zero width) so it never
// forces the preceding declarator's value to break
// (prettier's `lineSuffix`); a block stays inline.
parts.push(self.build_trailing_comment_doc(comment));
}
parts.push(self.build_comment_doc(comment));
needs_hardline = !comment.is_block;
}
} else {
Expand Down
11 changes: 9 additions & 2 deletions crates/tsv_ts/src/printer/types/union_intersection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,8 +363,15 @@ impl<'a> Printer<'a> {
if let Some(pipe_pos) =
find_separator_position(self.source, prev_type_end, type_start, b'|')
{
// Comments before the pipe (trailing on previous type's line or on own lines)
parts.extend(self.build_trailing_comments_multiline(prev_type_end, pipe_pos));
// Comments before the pipe (trailing on previous type's line or on
// own lines). A same-line line comment is line_suffix'd (zero width)
// so it can't force the previous member to break — the leading-`|`
// form puts the next separator on a new line, where it flushes.
parts.extend(self.build_trailing_comments_multiline_ext(
prev_type_end,
pipe_pos,
true,
));

// Relocated paren leading line comments: trail prev member
for comment in &relocated_paren_leading {
Expand Down
Loading