Skip to content

Commit 3bc99c9

Browse files
committed
Merge branch 'line-comment-semicolon'
2 parents 1b209a3 + eb29939 commit 3bc99c9

File tree

2 files changed

+84
-15
lines changed

2 files changed

+84
-15
lines changed

src/core/Formatter.js

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export default class Formatter {
1818
this.params = new Params(this.cfg.params);
1919
this.tokenizer = tokenizer;
2020
this.previousReservedWord = {};
21+
this.tokens = [];
22+
this.index = 0;
2123
}
2224

2325
/**
@@ -27,18 +29,20 @@ export default class Formatter {
2729
* @return {String} formatted query
2830
*/
2931
format(query) {
30-
const tokens = this.tokenizer.tokenize(query);
31-
const formattedQuery = this.getFormattedQueryFromTokens(tokens);
32+
this.tokens = this.tokenizer.tokenize(query);
33+
const formattedQuery = this.getFormattedQueryFromTokens();
3234

3335
return formattedQuery.trim();
3436
}
3537

36-
getFormattedQueryFromTokens(tokens) {
38+
getFormattedQueryFromTokens() {
3739
let formattedQuery = "";
3840

39-
tokens.forEach((token, index) => {
41+
this.tokens.forEach((token, index) => {
42+
this.index = index;
43+
4044
if (token.type === tokenTypes.WHITESPACE) {
41-
return;
45+
// ignore (we do our own whitespace formatting)
4246
}
4347
else if (token.type === tokenTypes.LINE_COMMENT) {
4448
formattedQuery = this.formatLineComment(token, formattedQuery);
@@ -59,7 +63,7 @@ export default class Formatter {
5963
this.previousReservedWord = token;
6064
}
6165
else if (token.type === tokenTypes.OPEN_PAREN) {
62-
formattedQuery = this.formatOpeningParentheses(tokens, index, formattedQuery);
66+
formattedQuery = this.formatOpeningParentheses(token, formattedQuery);
6367
}
6468
else if (token.type === tokenTypes.CLOSE_PAREN) {
6569
formattedQuery = this.formatClosingParentheses(token, formattedQuery);
@@ -116,15 +120,20 @@ export default class Formatter {
116120
}
117121

118122
// Opening parentheses increase the block indent level and start a new line
119-
formatOpeningParentheses(tokens, index, query) {
120-
// Take out the preceding space unless there was whitespace there in the original query or another opening parens
121-
const previousToken = tokens[index - 1];
122-
if (previousToken && previousToken.type !== tokenTypes.WHITESPACE && previousToken.type !== tokenTypes.OPEN_PAREN) {
123+
formatOpeningParentheses(token, query) {
124+
// Take out the preceding space unless there was whitespace there in the original query
125+
// or another opening parens or line comment
126+
const preserveWhitespaceFor = [
127+
tokenTypes.WHITESPACE,
128+
tokenTypes.OPEN_PAREN,
129+
tokenTypes.LINE_COMMENT,
130+
];
131+
if (!preserveWhitespaceFor.includes(this.previousToken().type)) {
123132
query = trimEnd(query);
124133
}
125-
query += tokens[index].value;
134+
query += token.value;
126135

127-
this.inlineBlock.beginIfPossible(tokens, index);
136+
this.inlineBlock.beginIfPossible(this.tokens, this.index);
128137

129138
if (!this.inlineBlock.isActive()) {
130139
this.indentation.increaseBlockLevel();
@@ -151,7 +160,7 @@ export default class Formatter {
151160

152161
// Commas start a new line (unless within inline parentheses or SQL "LIMIT" clause)
153162
formatComma(token, query) {
154-
query = trimEnd(query) + token.value + " ";
163+
query = this.trimTrailingWhitespace(query) + token.value + " ";
155164

156165
if (this.inlineBlock.isActive()) {
157166
return query;
@@ -165,11 +174,11 @@ export default class Formatter {
165174
}
166175

167176
formatWithSpaceAfter(token, query) {
168-
return trimEnd(query) + token.value + " ";
177+
return this.trimTrailingWhitespace(query) + token.value + " ";
169178
}
170179

171180
formatWithoutSpaces(token, query) {
172-
return trimEnd(query) + token.value;
181+
return this.trimTrailingWhitespace(query) + token.value;
173182
}
174183

175184
formatWithSpaces(token, query) {
@@ -179,4 +188,25 @@ export default class Formatter {
179188
addNewline(query) {
180189
return trimEnd(query) + "\n" + this.indentation.getIndent();
181190
}
191+
192+
trimTrailingWhitespace(query) {
193+
if (this.previousNonWhitespaceToken().type === tokenTypes.LINE_COMMENT) {
194+
return trimEnd(query) + "\n";
195+
}
196+
else {
197+
return trimEnd(query);
198+
}
199+
}
200+
201+
previousNonWhitespaceToken() {
202+
let n = 1;
203+
while (this.previousToken(n).type === tokenTypes.WHITESPACE) {
204+
n++;
205+
}
206+
return this.previousToken(n);
207+
}
208+
209+
previousToken(offset = 1) {
210+
return this.tokens[this.index - offset] || {};
211+
}
182212
}

test/StandardSqlFormatterTest.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,4 +352,43 @@ describe("StandardSqlFormatter", function() {
352352
" b --comment"
353353
);
354354
});
355+
356+
it("formats line comments followed by semicolon", function() {
357+
expect(sqlFormatter.format("SELECT a FROM b\n--comment\n;")).toBe(
358+
"SELECT\n" +
359+
" a\n" +
360+
"FROM\n" +
361+
" b --comment\n" +
362+
";"
363+
);
364+
});
365+
366+
it("formats line comments followed by comma", function() {
367+
expect(sqlFormatter.format("SELECT a --comment\n, b")).toBe(
368+
"SELECT\n" +
369+
" a --comment\n" +
370+
",\n" +
371+
" b"
372+
);
373+
});
374+
375+
it("formats line comments followed by close-paren", function() {
376+
expect(sqlFormatter.format("SELECT ( a --comment\n )")).toBe(
377+
"SELECT\n" +
378+
" (a --comment\n" +
379+
")"
380+
);
381+
});
382+
383+
it("formats line comments followed by open-paren", function() {
384+
expect(sqlFormatter.format("SELECT a --comment\n()")).toBe(
385+
"SELECT\n" +
386+
" a --comment\n" +
387+
" ()"
388+
);
389+
});
390+
391+
it("formats lonely semicolon", function() {
392+
expect(sqlFormatter.format(";")).toBe(";");
393+
});
355394
});

0 commit comments

Comments
 (0)