fix(formatter_graphql): keep same line comments pending across intervening tokens (#24579)

Ensure consistent behavior across all formatters.

Line comments at the EOL are not included in the calculation of `print-width`.
This commit is contained in:
leaysgur committed 2026-07-16 01:37:30 +00:00
1 parent 589415c2b8
commit 5f76998fe7
4 files changed
+53 -4

No files matched your search

+16 -3
View File
@@ -156,11 +156,24 @@ pub fn write_dangling_comments(comments: &[Span], f: &mut GraphqlFormatter<'_, '
}
}
/// If the next pending comment sits on the same line as `prev_end`,
/// drain it and emit it as a trailing line-suffix comment (` # ...`).
/// If the next pending comment sits on the same line as `prev_end` and ends at or
/// before `upper` (the next piece of user content), drain it and emit it as a
/// trailing line-suffix comment (` # ...`).
///
/// The bound is what keeps a node from claiming a comment across later siblings:
/// in `f(a: 1, b: 2) # c` everything shares a line, but `# c` ends past `b`'s
/// start, so `a: 1` leaves it pending for the enclosing node's flush point
/// (the same bounds discipline as `oxc_formatter_css`).
/// `expand_parent()` keeps the enclosing container multi-line.
pub fn write_trailing_same_line_comment<'a>(prev_end: u32, f: &mut GraphqlFormatter<'_, 'a>) {
pub fn write_trailing_same_line_comment<'a>(
prev_end: u32,
upper: u32,
f: &mut GraphqlFormatter<'_, 'a>,
) {
let Some(span) = f.context().comments().peek() else { return };
if span.end > upper {
return;
}
let source = f.context().source_text();
if classify_gap(source.bytes_range(prev_end, span.start)) != Gap::None {
return;
@@ -79,7 +79,7 @@ where
let item_span = item.span();
let start = item_span.start;
if let Some(pe) = prev_end {
write_trailing_same_line_comment(pe, f);
write_trailing_same_line_comment(pe, start, f);
// Measure the gap up to the next pending comment (if it precedes the item),
// so a blank line in front of a leading comment is still preserved.
let anchor = f
@@ -11,3 +11,12 @@ type T {
# after last definition
# blank line above me
{
afterArgs(argumentOne: 1, argumentTwo: 2) # must NOT be claimed by argumentOne across `, ...)`
afterArgsLong(argumentOne: 1, argumentTwo: 2, argumentThree: 3) # long comment must not break the arguments either
midArgs(
argumentOne: 1 # directly after an argument: attaches here and keeps the list open
argumentTwo: 2
)
}
@@ -16,6 +16,15 @@ type T {
# blank line above me
{
afterArgs(argumentOne: 1, argumentTwo: 2) # must NOT be claimed by argumentOne across `, ...)`
afterArgsLong(argumentOne: 1, argumentTwo: 2, argumentThree: 3) # long comment must not break the arguments either
midArgs(
argumentOne: 1 # directly after an argument: attaches here and keeps the list open
argumentTwo: 2
)
}
==================== Output ====================
------------------
{ printWidth: 80 }
@@ -34,6 +43,15 @@ type T {
# blank line above me
{
afterArgs(argumentOne: 1, argumentTwo: 2) # must NOT be claimed by argumentOne across `, ...)`
afterArgsLong(argumentOne: 1, argumentTwo: 2, argumentThree: 3) # long comment must not break the arguments either
midArgs(
argumentOne: 1 # directly after an argument: attaches here and keeps the list open
argumentTwo: 2
)
}
-------------------
{ printWidth: 100 }
-------------------
@@ -51,4 +69,13 @@ type T {
# blank line above me
{
afterArgs(argumentOne: 1, argumentTwo: 2) # must NOT be claimed by argumentOne across `, ...)`
afterArgsLong(argumentOne: 1, argumentTwo: 2, argumentThree: 3) # long comment must not break the arguments either
midArgs(
argumentOne: 1 # directly after an argument: attaches here and keeps the list open
argumentTwo: 2
)
}
===================== End =====================