Skip to content

Commit 3256b55

Browse files
fix: keep a space when densing "-" before a negative operand
denseOperators removed the spaces around a "-" operator even when the operand that follows it starts with another "-" (a unary minus or a negative number literal). That glues the two together into "--", which re-parses as a line comment and silently drops the rest of the line: format("SELECT 1 - -1 AS x", { denseOperators: true }) => "SELECT\n 1--1 AS x" // "--1 AS x" is now a comment Guard against this in the layout: when a token that starts with "-" would be placed directly after one that ends with "-", keep a single space so the "--" comment marker can never form. Formatting is idempotent again.
1 parent c087896 commit 3256b55

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

src/formatter/Layout.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,22 @@ export default class Layout {
5757
this.items.push(WS.SINGLE_INDENT);
5858
break;
5959
default:
60+
// Don't glue a token starting with "-" directly onto one ending with
61+
// "-": that forms "--", which re-parses as a line comment and
62+
// swallows the rest of the line (e.g. densing "a - -b" into "a--b").
63+
if (typeof item === 'string' && item.startsWith('-') && this.lastTokenEndsWith('-')) {
64+
this.items.push(WS.SPACE);
65+
}
6066
this.items.push(item);
6167
}
6268
}
6369
}
6470

71+
private lastTokenEndsWith(suffix: string): boolean {
72+
const lastItem = last(this.items);
73+
return typeof lastItem === 'string' && lastItem.endsWith(suffix);
74+
}
75+
6576
private trimHorizontalWhitespace() {
6677
while (isHorizontalWhitespace(last(this.items))) {
6778
this.items.pop();

test/features/operators.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ export default function supportsOperators(
4040
});
4141
});
4242

43+
it('does not glue a - in front of a negative operand into a line comment in dense mode', () => {
44+
// "a - -b" / "1 - -1" must not be densed into "a--b" / "1--1": the "--"
45+
// would re-parse as a line comment and silently swallow the rest of the line.
46+
['SELECT a - -b', 'SELECT 1 - -1'].forEach(sql => {
47+
const result = format(sql, { denseOperators: true });
48+
expect(result).not.toContain('--');
49+
// ...and formatting stays idempotent.
50+
expect(format(result, { denseOperators: true })).toBe(result);
51+
});
52+
});
53+
4354
(cfg.logicalOperators || ['AND', 'OR']).forEach(op => {
4455
it(`supports ${op} operator`, () => {
4556
const result = format(`SELECT true ${op} false AS foo;`);

0 commit comments

Comments
 (0)