Skip to content

Commit 62a1e45

Browse files
committed
fix: preserve trailing comments on the same line as their statement
Comments like 'SELECT 2; -- trailing note' now stay on one line instead of being split across two lines. The scanner detects when a comment has no newline between it and the preceding token, marks it as trailing, and the deparser appends it to the previous line.
1 parent 4710aae commit 62a1e45

5 files changed

Lines changed: 19 additions & 3 deletions

File tree

packages/parse/__tests__/__snapshots__/roundtrip.test.ts.snap

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ exports[`fixture round-trip (CST) edge-cases deparsed output matches snapshot 1`
2222
SELECT 1;
2323
2424
-- Inline comment after statement
25-
SELECT 2;
26-
-- trailing note
25+
SELECT 2; -- trailing note
2726
2827
-- Adjacent comments with no blank line
2928
-- first line

packages/parse/src/deparse.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@ export function deparseEnhanced(
4444

4545
for (const stmt of result.stmts) {
4646
if (isRawComment(stmt)) {
47-
lines.push(deparseComment(stmt.RawComment));
47+
const commentText = deparseComment(stmt.RawComment);
48+
if (stmt.RawComment.trailing && lines.length > 0) {
49+
// Trailing comment: append to the previous line
50+
lines[lines.length - 1] += ' ' + commentText;
51+
} else {
52+
lines.push(commentText);
53+
}
4854
} else if (isRawWhitespace(stmt)) {
4955
// Each blank line in the original source becomes an empty line in output.
5056
// The whitespace node represents N blank lines between content.

packages/parse/src/parse.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ function interleave(
8585
type: elem.value.type,
8686
text: elem.value.text,
8787
location: elem.value.start,
88+
...(elem.value.trailing ? { trailing: true } : {}),
8889
}
8990
}
9091
});

packages/parse/src/scanner.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export interface ScannedComment {
2121
start: number;
2222
/** Byte offset of the end of the comment (exclusive) */
2323
end: number;
24+
/** True if this comment is on the same line as a preceding token (trailing comment) */
25+
trailing: boolean;
2426
}
2527

2628
export interface ScannedWhitespace {
@@ -87,13 +89,19 @@ export function scanComments(sql: string): ScannedElement[] {
8789
}
8890

8991
if (token.tokenType === SQL_COMMENT) {
92+
// A comment is "trailing" if no newline exists between the previous
93+
// token's end and this comment's start (i.e. same line).
94+
const gapBeforeComment = sql.substring(prevEnd, token.start);
95+
const trailing = prevEnd > 0 && !gapBeforeComment.includes('\n');
96+
9097
elements.push({
9198
kind: 'comment',
9299
value: {
93100
type: 'line',
94101
text: sql.substring(token.start + 2, token.end), // strip --
95102
start: token.start,
96103
end: token.end,
104+
trailing,
97105
}
98106
});
99107
}

packages/parse/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export interface RawComment {
1212
text: string;
1313
/** Byte offset in the original source (for ordering) */
1414
location: number;
15+
/** True if this comment is on the same line as the preceding statement */
16+
trailing?: boolean;
1517
}
1618

1719
/**

0 commit comments

Comments
 (0)