rawsql-ts 0.11.41-beta → 0.11.43-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/esm/index.min.js +18 -9
- package/dist/esm/index.min.js.map +2 -2
- package/dist/esm/src/parsers/KeywordParser.js +4 -2
- package/dist/esm/src/parsers/KeywordParser.js.map +1 -1
- package/dist/esm/src/parsers/SqlPrintTokenParser.d.ts +11 -18
- package/dist/esm/src/parsers/SqlPrintTokenParser.js +126 -218
- package/dist/esm/src/parsers/SqlPrintTokenParser.js.map +1 -1
- package/dist/esm/src/parsers/SqlTokenizer.js +26 -13
- package/dist/esm/src/parsers/SqlTokenizer.js.map +1 -1
- package/dist/esm/src/transformers/LinePrinter.d.ts +1 -0
- package/dist/esm/src/transformers/LinePrinter.js +22 -1
- package/dist/esm/src/transformers/LinePrinter.js.map +1 -1
- package/dist/esm/src/transformers/SqlFormatter.d.ts +6 -4
- package/dist/esm/src/transformers/SqlFormatter.js +2 -2
- package/dist/esm/src/transformers/SqlFormatter.js.map +1 -1
- package/dist/esm/src/transformers/SqlPrinter.d.ts +40 -2
- package/dist/esm/src/transformers/SqlPrinter.js +489 -27
- package/dist/esm/src/transformers/SqlPrinter.js.map +1 -1
- package/dist/esm/src/utils/stringUtils.d.ts +1 -1
- package/dist/esm/src/utils/stringUtils.js +8 -2
- package/dist/esm/src/utils/stringUtils.js.map +1 -1
- package/dist/esm/tsconfig.browser.tsbuildinfo +1 -1
- package/dist/index.min.js +18 -9
- package/dist/index.min.js.map +2 -2
- package/dist/src/parsers/KeywordParser.js +4 -2
- package/dist/src/parsers/KeywordParser.js.map +1 -1
- package/dist/src/parsers/SqlPrintTokenParser.d.ts +11 -18
- package/dist/src/parsers/SqlPrintTokenParser.js +126 -218
- package/dist/src/parsers/SqlPrintTokenParser.js.map +1 -1
- package/dist/src/parsers/SqlTokenizer.js +26 -13
- package/dist/src/parsers/SqlTokenizer.js.map +1 -1
- package/dist/src/transformers/LinePrinter.d.ts +1 -0
- package/dist/src/transformers/LinePrinter.js +22 -1
- package/dist/src/transformers/LinePrinter.js.map +1 -1
- package/dist/src/transformers/SqlFormatter.d.ts +6 -4
- package/dist/src/transformers/SqlFormatter.js +2 -2
- package/dist/src/transformers/SqlFormatter.js.map +1 -1
- package/dist/src/transformers/SqlPrinter.d.ts +40 -2
- package/dist/src/transformers/SqlPrinter.js +489 -27
- package/dist/src/transformers/SqlPrinter.js.map +1 -1
- package/dist/src/utils/stringUtils.d.ts +1 -1
- package/dist/src/utils/stringUtils.js +8 -2
- package/dist/src/utils/stringUtils.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -29,9 +29,13 @@ class SqlPrinter {
|
|
|
29
29
|
* @param options Optional style settings for pretty printing
|
|
30
30
|
*/
|
|
31
31
|
constructor(options) {
|
|
32
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
32
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
33
33
|
/** Track whether we are currently inside a WITH clause for full-oneline formatting */
|
|
34
34
|
this.insideWithClause = false;
|
|
35
|
+
/** Pending line comment that needs a forced newline before next token */
|
|
36
|
+
this.pendingLineCommentBreak = null;
|
|
37
|
+
/** Accumulates lines when reconstructing multi-line block comments inside CommentBlocks */
|
|
38
|
+
this.smartCommentBlockBuilder = null;
|
|
35
39
|
// Resolve logical options to their control character representations before applying defaults.
|
|
36
40
|
const resolvedIndentChar = (0, FormatOptionResolver_1.resolveIndentCharOption)(options === null || options === void 0 ? void 0 : options.indentChar);
|
|
37
41
|
const resolvedNewline = (0, FormatOptionResolver_1.resolveNewlineOption)(options === null || options === void 0 ? void 0 : options.newline);
|
|
@@ -44,9 +48,9 @@ class SqlPrinter {
|
|
|
44
48
|
this.cteCommaBreak = (_c = options === null || options === void 0 ? void 0 : options.cteCommaBreak) !== null && _c !== void 0 ? _c : this.commaBreak;
|
|
45
49
|
this.valuesCommaBreak = (_d = options === null || options === void 0 ? void 0 : options.valuesCommaBreak) !== null && _d !== void 0 ? _d : this.commaBreak;
|
|
46
50
|
this.andBreak = (_e = options === null || options === void 0 ? void 0 : options.andBreak) !== null && _e !== void 0 ? _e : 'none';
|
|
47
|
-
this.
|
|
48
|
-
this.
|
|
49
|
-
this.
|
|
51
|
+
this.orBreak = (_f = options === null || options === void 0 ? void 0 : options.orBreak) !== null && _f !== void 0 ? _f : 'none';
|
|
52
|
+
this.keywordCase = (_g = options === null || options === void 0 ? void 0 : options.keywordCase) !== null && _g !== void 0 ? _g : 'none';
|
|
53
|
+
this.exportComment = (_h = options === null || options === void 0 ? void 0 : options.exportComment) !== null && _h !== void 0 ? _h : false;
|
|
50
54
|
this.withClauseStyle = (_j = options === null || options === void 0 ? void 0 : options.withClauseStyle) !== null && _j !== void 0 ? _j : 'standard';
|
|
51
55
|
this.commentStyle = (_k = options === null || options === void 0 ? void 0 : options.commentStyle) !== null && _k !== void 0 ? _k : 'block';
|
|
52
56
|
this.parenthesesOneLine = (_l = options === null || options === void 0 ? void 0 : options.parenthesesOneLine) !== null && _l !== void 0 ? _l : false;
|
|
@@ -55,9 +59,10 @@ class SqlPrinter {
|
|
|
55
59
|
this.joinOneLine = (_p = options === null || options === void 0 ? void 0 : options.joinOneLine) !== null && _p !== void 0 ? _p : false;
|
|
56
60
|
this.caseOneLine = (_q = options === null || options === void 0 ? void 0 : options.caseOneLine) !== null && _q !== void 0 ? _q : false;
|
|
57
61
|
this.subqueryOneLine = (_r = options === null || options === void 0 ? void 0 : options.subqueryOneLine) !== null && _r !== void 0 ? _r : false;
|
|
62
|
+
this.indentNestedParentheses = (_s = options === null || options === void 0 ? void 0 : options.indentNestedParentheses) !== null && _s !== void 0 ? _s : false;
|
|
58
63
|
this.linePrinter = new LinePrinter_1.LinePrinter(this.indentChar, this.indentSize, this.newline, this.commaBreak);
|
|
59
64
|
// Initialize
|
|
60
|
-
this.indentIncrementContainers = new Set((
|
|
65
|
+
this.indentIncrementContainers = new Set((_t = options === null || options === void 0 ? void 0 : options.indentIncrementContainerTypes) !== null && _t !== void 0 ? _t : [
|
|
61
66
|
SqlPrintToken_1.SqlPrintTokenContainerType.SelectClause,
|
|
62
67
|
SqlPrintToken_1.SqlPrintTokenContainerType.FromClause,
|
|
63
68
|
SqlPrintToken_1.SqlPrintTokenContainerType.WhereClause,
|
|
@@ -98,13 +103,15 @@ class SqlPrinter {
|
|
|
98
103
|
// initialize
|
|
99
104
|
this.linePrinter = new LinePrinter_1.LinePrinter(this.indentChar, this.indentSize, this.newline, this.commaBreak);
|
|
100
105
|
this.insideWithClause = false; // Reset WITH clause context
|
|
106
|
+
this.pendingLineCommentBreak = null;
|
|
107
|
+
this.smartCommentBlockBuilder = null;
|
|
101
108
|
if (this.linePrinter.lines.length > 0 && level !== this.linePrinter.lines[0].level) {
|
|
102
109
|
this.linePrinter.lines[0].level = level;
|
|
103
110
|
}
|
|
104
|
-
this.appendToken(token, level, undefined, 0);
|
|
111
|
+
this.appendToken(token, level, undefined, 0, false);
|
|
105
112
|
return this.linePrinter.print();
|
|
106
113
|
}
|
|
107
|
-
appendToken(token, level, parentContainerType, caseContextDepth = 0) {
|
|
114
|
+
appendToken(token, level, parentContainerType, caseContextDepth = 0, indentParentActive = false) {
|
|
108
115
|
// Track WITH clause context for full-oneline formatting
|
|
109
116
|
const wasInsideWithClause = this.insideWithClause;
|
|
110
117
|
if (token.containerType === SqlPrintToken_1.SqlPrintTokenContainerType.WithClause && this.withClauseStyle === 'full-oneline') {
|
|
@@ -113,9 +120,27 @@ class SqlPrinter {
|
|
|
113
120
|
if (this.shouldSkipToken(token)) {
|
|
114
121
|
return;
|
|
115
122
|
}
|
|
123
|
+
if (this.smartCommentBlockBuilder && token.containerType !== SqlPrintToken_1.SqlPrintTokenContainerType.CommentBlock && token.type !== SqlPrintToken_1.SqlPrintTokenType.commentNewline) {
|
|
124
|
+
this.flushSmartCommentBlockBuilder();
|
|
125
|
+
}
|
|
126
|
+
if (this.pendingLineCommentBreak !== null) {
|
|
127
|
+
if (!this.isOnelineMode()) {
|
|
128
|
+
this.linePrinter.appendNewline(this.pendingLineCommentBreak);
|
|
129
|
+
}
|
|
130
|
+
const shouldSkipToken = token.type === SqlPrintToken_1.SqlPrintTokenType.commentNewline;
|
|
131
|
+
this.pendingLineCommentBreak = null;
|
|
132
|
+
if (shouldSkipToken) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (token.containerType === SqlPrintToken_1.SqlPrintTokenContainerType.CommentBlock) {
|
|
137
|
+
this.handleCommentBlockContainer(token, level);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
116
140
|
const current = this.linePrinter.getCurrentLine();
|
|
117
141
|
const isCaseContext = this.isCaseContext(token.containerType);
|
|
118
142
|
const nextCaseContextDepth = isCaseContext ? caseContextDepth + 1 : caseContextDepth;
|
|
143
|
+
const shouldIndentNested = this.shouldIndentNestedParentheses(token);
|
|
119
144
|
// Handle different token types
|
|
120
145
|
if (token.type === SqlPrintToken_1.SqlPrintTokenType.keyword) {
|
|
121
146
|
this.handleKeywordToken(token, level, parentContainerType, caseContextDepth);
|
|
@@ -123,18 +148,21 @@ class SqlPrinter {
|
|
|
123
148
|
else if (token.type === SqlPrintToken_1.SqlPrintTokenType.comma) {
|
|
124
149
|
this.handleCommaToken(token, level, parentContainerType);
|
|
125
150
|
}
|
|
151
|
+
else if (token.type === SqlPrintToken_1.SqlPrintTokenType.parenthesis) {
|
|
152
|
+
this.handleParenthesisToken(token, level, indentParentActive);
|
|
153
|
+
}
|
|
126
154
|
else if (token.type === SqlPrintToken_1.SqlPrintTokenType.operator && token.text.toLowerCase() === 'and') {
|
|
127
155
|
this.handleAndOperatorToken(token, level, parentContainerType, caseContextDepth);
|
|
128
156
|
}
|
|
157
|
+
else if (token.type === SqlPrintToken_1.SqlPrintTokenType.operator && token.text.toLowerCase() === 'or') {
|
|
158
|
+
this.handleOrOperatorToken(token, level, parentContainerType, caseContextDepth);
|
|
159
|
+
}
|
|
129
160
|
else if (token.containerType === "JoinClause") {
|
|
130
161
|
this.handleJoinClauseToken(token, level);
|
|
131
162
|
}
|
|
132
163
|
else if (token.type === SqlPrintToken_1.SqlPrintTokenType.comment) {
|
|
133
|
-
// Handle comments as regular tokens - let the standard processing handle everything
|
|
134
164
|
if (this.exportComment) {
|
|
135
|
-
|
|
136
|
-
// via positioned comments system, so we don't need additional processing here
|
|
137
|
-
this.linePrinter.appendText(token.text);
|
|
165
|
+
this.printCommentToken(token.text, level, parentContainerType);
|
|
138
166
|
}
|
|
139
167
|
}
|
|
140
168
|
else if (token.type === SqlPrintToken_1.SqlPrintTokenType.space) {
|
|
@@ -147,7 +175,7 @@ class SqlPrinter {
|
|
|
147
175
|
this.handleCteOnelineToken(token, level);
|
|
148
176
|
return; // Return early to avoid processing innerTokens
|
|
149
177
|
}
|
|
150
|
-
else if ((token.containerType === SqlPrintToken_1.SqlPrintTokenContainerType.ParenExpression && this.parenthesesOneLine) ||
|
|
178
|
+
else if ((token.containerType === SqlPrintToken_1.SqlPrintTokenContainerType.ParenExpression && this.parenthesesOneLine && !shouldIndentNested) ||
|
|
151
179
|
(token.containerType === SqlPrintToken_1.SqlPrintTokenContainerType.BetweenExpression && this.betweenOneLine) ||
|
|
152
180
|
(token.containerType === SqlPrintToken_1.SqlPrintTokenContainerType.Values && this.valuesOneLine) ||
|
|
153
181
|
(token.containerType === SqlPrintToken_1.SqlPrintTokenContainerType.JoinOnClause && this.joinOneLine) ||
|
|
@@ -163,21 +191,34 @@ class SqlPrinter {
|
|
|
163
191
|
if (token.keywordTokens && token.keywordTokens.length > 0) {
|
|
164
192
|
for (let i = 0; i < token.keywordTokens.length; i++) {
|
|
165
193
|
const keywordToken = token.keywordTokens[i];
|
|
166
|
-
this.appendToken(keywordToken, level, token.containerType, nextCaseContextDepth);
|
|
194
|
+
this.appendToken(keywordToken, level, token.containerType, nextCaseContextDepth, indentParentActive);
|
|
167
195
|
}
|
|
168
196
|
}
|
|
169
197
|
let innerLevel = level;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
198
|
+
let increasedIndent = false;
|
|
199
|
+
const shouldIncreaseIndent = this.indentIncrementContainers.has(token.containerType) || shouldIndentNested;
|
|
200
|
+
const delayIndentNewline = shouldIndentNested && token.containerType === SqlPrintToken_1.SqlPrintTokenContainerType.ParenExpression;
|
|
201
|
+
if (!this.isOnelineMode() && shouldIncreaseIndent) {
|
|
202
|
+
if (this.insideWithClause && this.withClauseStyle === 'full-oneline') {
|
|
203
|
+
// Keep everything on one line for full-oneline WITH clauses.
|
|
204
|
+
}
|
|
205
|
+
else if (delayIndentNewline) {
|
|
206
|
+
innerLevel = level + 1;
|
|
207
|
+
increasedIndent = true;
|
|
208
|
+
}
|
|
209
|
+
else if (current.text !== '') {
|
|
210
|
+
innerLevel = level + 1;
|
|
211
|
+
increasedIndent = true;
|
|
175
212
|
this.linePrinter.appendNewline(innerLevel);
|
|
176
213
|
}
|
|
177
214
|
}
|
|
178
215
|
for (let i = 0; i < token.innerTokens.length; i++) {
|
|
179
216
|
const child = token.innerTokens[i];
|
|
180
|
-
|
|
217
|
+
const childIndentParentActive = token.containerType === SqlPrintToken_1.SqlPrintTokenContainerType.ParenExpression ? shouldIndentNested : indentParentActive;
|
|
218
|
+
this.appendToken(child, innerLevel, token.containerType, nextCaseContextDepth, childIndentParentActive);
|
|
219
|
+
}
|
|
220
|
+
if (this.smartCommentBlockBuilder && this.smartCommentBlockBuilder.mode === 'line') {
|
|
221
|
+
this.flushSmartCommentBlockBuilder();
|
|
181
222
|
}
|
|
182
223
|
// Exit WITH clause context when we finish processing WithClause container
|
|
183
224
|
if (token.containerType === SqlPrintToken_1.SqlPrintTokenContainerType.WithClause && this.withClauseStyle === 'full-oneline') {
|
|
@@ -187,11 +228,8 @@ class SqlPrinter {
|
|
|
187
228
|
return; // Return early to avoid additional newline below
|
|
188
229
|
}
|
|
189
230
|
// indent level down
|
|
190
|
-
if (
|
|
191
|
-
|
|
192
|
-
if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
|
|
193
|
-
this.linePrinter.appendNewline(level);
|
|
194
|
-
}
|
|
231
|
+
if (increasedIndent && shouldIncreaseIndent && !(this.insideWithClause && this.withClauseStyle === 'full-oneline') && !delayIndentNewline) {
|
|
232
|
+
this.linePrinter.appendNewline(level);
|
|
195
233
|
}
|
|
196
234
|
}
|
|
197
235
|
isCaseContext(containerType) {
|
|
@@ -234,6 +272,10 @@ class SqlPrinter {
|
|
|
234
272
|
this.handleAndOperatorToken(token, level, parentContainerType, caseContextDepth);
|
|
235
273
|
return;
|
|
236
274
|
}
|
|
275
|
+
else if (lower === 'or' && this.orBreak !== 'none') {
|
|
276
|
+
this.handleOrOperatorToken(token, level, parentContainerType, caseContextDepth);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
237
279
|
const text = this.applyKeywordCase(token.text);
|
|
238
280
|
if (caseContextDepth > 0) {
|
|
239
281
|
this.linePrinter.appendText(text);
|
|
@@ -279,6 +321,9 @@ class SqlPrinter {
|
|
|
279
321
|
if (previousCommaBreak !== 'after') {
|
|
280
322
|
this.linePrinter.commaBreak = 'after';
|
|
281
323
|
}
|
|
324
|
+
if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
|
|
325
|
+
this.linePrinter.appendNewline(level);
|
|
326
|
+
}
|
|
282
327
|
this.linePrinter.appendText(text);
|
|
283
328
|
if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
|
|
284
329
|
this.linePrinter.appendNewline(level);
|
|
@@ -325,6 +370,79 @@ class SqlPrinter {
|
|
|
325
370
|
this.linePrinter.appendText(text);
|
|
326
371
|
}
|
|
327
372
|
}
|
|
373
|
+
handleParenthesisToken(token, level, indentParentActive) {
|
|
374
|
+
if (token.text === '(') {
|
|
375
|
+
this.linePrinter.appendText(token.text);
|
|
376
|
+
if (indentParentActive && !this.isOnelineMode()) {
|
|
377
|
+
if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
|
|
378
|
+
this.linePrinter.appendNewline(level);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
if (token.text === ')' && indentParentActive && !this.isOnelineMode()) {
|
|
384
|
+
// Align closing parenthesis with the outer indentation level when nested groups expand.
|
|
385
|
+
const closingLevel = Math.max(level - 1, 0);
|
|
386
|
+
if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
|
|
387
|
+
this.linePrinter.appendNewline(closingLevel);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
this.linePrinter.appendText(token.text);
|
|
391
|
+
}
|
|
392
|
+
handleOrOperatorToken(token, level, parentContainerType, caseContextDepth = 0) {
|
|
393
|
+
const text = this.applyKeywordCase(token.text);
|
|
394
|
+
// Leave OR untouched inside CASE branches to preserve inline evaluation order.
|
|
395
|
+
if (caseContextDepth > 0) {
|
|
396
|
+
this.linePrinter.appendText(text);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
if (this.orBreak === 'before') {
|
|
400
|
+
// Insert a newline before OR unless WITH full-oneline mode suppresses breaks.
|
|
401
|
+
if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
|
|
402
|
+
this.linePrinter.appendNewline(level);
|
|
403
|
+
}
|
|
404
|
+
this.linePrinter.appendText(text);
|
|
405
|
+
}
|
|
406
|
+
else if (this.orBreak === 'after') {
|
|
407
|
+
this.linePrinter.appendText(text);
|
|
408
|
+
// Break after OR when multi-line formatting is active.
|
|
409
|
+
if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
|
|
410
|
+
this.linePrinter.appendNewline(level);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
this.linePrinter.appendText(text);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Decide whether a parentheses group should increase indentation when inside nested structures.
|
|
419
|
+
* We only expand groups that contain further parentheses so simple comparisons stay compact.
|
|
420
|
+
*/
|
|
421
|
+
shouldIndentNestedParentheses(token) {
|
|
422
|
+
if (!this.indentNestedParentheses) {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
if (token.containerType !== SqlPrintToken_1.SqlPrintTokenContainerType.ParenExpression) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
// Look for nested parentheses containers. If present, indent to highlight grouping.
|
|
429
|
+
return token.innerTokens.some((child) => this.containsParenExpression(child));
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Recursively inspect descendants to find additional parentheses groups.
|
|
433
|
+
* Helps detect complex boolean groups like ((A) OR (B) OR (C)).
|
|
434
|
+
*/
|
|
435
|
+
containsParenExpression(token) {
|
|
436
|
+
if (token.containerType === SqlPrintToken_1.SqlPrintTokenContainerType.ParenExpression) {
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
for (const child of token.innerTokens) {
|
|
440
|
+
if (this.containsParenExpression(child)) {
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
328
446
|
handleJoinClauseToken(token, level) {
|
|
329
447
|
const text = this.applyKeywordCase(token.text);
|
|
330
448
|
// before join clause, add newline (skip when inside WITH clause with full-oneline style)
|
|
@@ -338,6 +456,9 @@ class SqlPrinter {
|
|
|
338
456
|
* Skips spaces in CommentBlocks when in specific CTE modes to prevent duplication.
|
|
339
457
|
*/
|
|
340
458
|
handleSpaceToken(token, parentContainerType) {
|
|
459
|
+
if (this.smartCommentBlockBuilder && this.smartCommentBlockBuilder.mode === 'line') {
|
|
460
|
+
this.flushSmartCommentBlockBuilder();
|
|
461
|
+
}
|
|
341
462
|
if (this.shouldSkipCommentBlockSpace(parentContainerType)) {
|
|
342
463
|
const currentLine = this.linePrinter.getCurrentLine();
|
|
343
464
|
if (currentLine.text !== '' && !currentLine.text.endsWith(' ')) {
|
|
@@ -356,6 +477,337 @@ class SqlPrinter {
|
|
|
356
477
|
this.insideWithClause &&
|
|
357
478
|
this.withClauseStyle === 'full-oneline';
|
|
358
479
|
}
|
|
480
|
+
printCommentToken(text, level, parentContainerType) {
|
|
481
|
+
const trimmed = text.trim();
|
|
482
|
+
if (!trimmed) {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
if (this.commentStyle === 'smart' && parentContainerType === SqlPrintToken_1.SqlPrintTokenContainerType.CommentBlock) {
|
|
486
|
+
if (this.handleSmartCommentBlockToken(text, trimmed, level)) {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
if (this.commentStyle === 'smart') {
|
|
491
|
+
const normalized = this.normalizeCommentForSmart(trimmed);
|
|
492
|
+
if (normalized.lines.length > 1 || normalized.forceBlock) {
|
|
493
|
+
const blockText = this.buildBlockComment(normalized.lines, level);
|
|
494
|
+
this.linePrinter.appendText(blockText);
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
const content = normalized.lines[0];
|
|
498
|
+
const lineText = content ? `-- ${content}` : '--';
|
|
499
|
+
if (parentContainerType === SqlPrintToken_1.SqlPrintTokenContainerType.CommentBlock) {
|
|
500
|
+
this.linePrinter.appendText(lineText);
|
|
501
|
+
this.pendingLineCommentBreak = level;
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
this.linePrinter.appendText(lineText);
|
|
505
|
+
this.linePrinter.appendNewline(level);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
if (trimmed.startsWith('/*') && trimmed.endsWith('*/')) {
|
|
511
|
+
if (/\r?\n/.test(trimmed)) {
|
|
512
|
+
// Keep multi-line block comments intact by normalizing line endings once.
|
|
513
|
+
const newlineReplacement = this.isOnelineMode() ? ' ' : (typeof this.newline === 'string' ? this.newline : '\n');
|
|
514
|
+
const normalized = trimmed.replace(/\r?\n/g, newlineReplacement);
|
|
515
|
+
this.linePrinter.appendText(normalized);
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
this.linePrinter.appendText(trimmed);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
this.linePrinter.appendText(trimmed);
|
|
523
|
+
}
|
|
524
|
+
if (trimmed.startsWith('--')) {
|
|
525
|
+
if (parentContainerType === SqlPrintToken_1.SqlPrintTokenContainerType.CommentBlock) {
|
|
526
|
+
this.pendingLineCommentBreak = level;
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
this.linePrinter.appendNewline(level);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
handleSmartCommentBlockToken(raw, trimmed, level) {
|
|
535
|
+
if (!this.smartCommentBlockBuilder) {
|
|
536
|
+
if (trimmed === '/*') {
|
|
537
|
+
// Begin assembling a multi-line block comment that is emitted as split tokens
|
|
538
|
+
this.smartCommentBlockBuilder = { lines: [], level, mode: 'block' };
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
const lineContent = this.extractLineCommentContent(trimmed);
|
|
542
|
+
if (lineContent !== null) {
|
|
543
|
+
this.smartCommentBlockBuilder = {
|
|
544
|
+
lines: [lineContent],
|
|
545
|
+
level,
|
|
546
|
+
mode: 'line',
|
|
547
|
+
};
|
|
548
|
+
return true;
|
|
549
|
+
}
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
if (this.smartCommentBlockBuilder.mode === 'block') {
|
|
553
|
+
if (trimmed === '*/') {
|
|
554
|
+
const { lines, level: blockLevel } = this.smartCommentBlockBuilder;
|
|
555
|
+
const blockText = this.buildBlockComment(lines, blockLevel);
|
|
556
|
+
this.linePrinter.appendText(blockText);
|
|
557
|
+
this.pendingLineCommentBreak = blockLevel;
|
|
558
|
+
this.smartCommentBlockBuilder = null;
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
this.smartCommentBlockBuilder.lines.push(this.normalizeSmartBlockLine(raw));
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
564
|
+
const content = this.extractLineCommentContent(trimmed);
|
|
565
|
+
if (content !== null) {
|
|
566
|
+
this.smartCommentBlockBuilder.lines.push(content);
|
|
567
|
+
return true;
|
|
568
|
+
}
|
|
569
|
+
this.flushSmartCommentBlockBuilder();
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
handleCommentBlockContainer(token, level) {
|
|
573
|
+
var _a;
|
|
574
|
+
if (!this.exportComment) {
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
if (this.commentStyle !== 'smart') {
|
|
578
|
+
const rawLines = this.extractRawCommentBlockLines(token);
|
|
579
|
+
if (rawLines.length > 0) {
|
|
580
|
+
const normalizedBlocks = rawLines.map(line => `/* ${line} */`).join(' ');
|
|
581
|
+
const hasTrailingSpace = (_a = token.innerTokens) === null || _a === void 0 ? void 0 : _a.some(child => child.type === SqlPrintToken_1.SqlPrintTokenType.space && child.text.includes(' '));
|
|
582
|
+
this.linePrinter.appendText(hasTrailingSpace ? `${normalizedBlocks} ` : normalizedBlocks);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
for (const child of token.innerTokens) {
|
|
586
|
+
this.appendToken(child, level, token.containerType, 0, false);
|
|
587
|
+
}
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
const lines = this.collectCommentBlockLines(token);
|
|
591
|
+
if (lines.length === 0 && !this.smartCommentBlockBuilder) {
|
|
592
|
+
// No meaningful content; treat as empty line comment to preserve spacing
|
|
593
|
+
this.smartCommentBlockBuilder = {
|
|
594
|
+
lines: [''],
|
|
595
|
+
level,
|
|
596
|
+
mode: 'line',
|
|
597
|
+
};
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
if (!this.smartCommentBlockBuilder || this.smartCommentBlockBuilder.mode !== 'line') {
|
|
601
|
+
this.smartCommentBlockBuilder = {
|
|
602
|
+
lines: [...lines],
|
|
603
|
+
level,
|
|
604
|
+
mode: 'line',
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
this.smartCommentBlockBuilder.lines.push(...lines);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
normalizeSmartBlockLine(raw) {
|
|
612
|
+
// Remove trailing whitespace that only carries formatting artifacts
|
|
613
|
+
let line = raw.replace(/\s+$/g, '');
|
|
614
|
+
if (!line) {
|
|
615
|
+
return '';
|
|
616
|
+
}
|
|
617
|
+
if (line.startsWith(' ')) {
|
|
618
|
+
line = line.slice(2);
|
|
619
|
+
}
|
|
620
|
+
if (line.startsWith('* ')) {
|
|
621
|
+
return line.slice(2);
|
|
622
|
+
}
|
|
623
|
+
if (line === '*') {
|
|
624
|
+
return '';
|
|
625
|
+
}
|
|
626
|
+
if (line.startsWith('*')) {
|
|
627
|
+
return line.slice(1);
|
|
628
|
+
}
|
|
629
|
+
return line;
|
|
630
|
+
}
|
|
631
|
+
extractLineCommentContent(trimmed) {
|
|
632
|
+
if (trimmed.startsWith('--')) {
|
|
633
|
+
return trimmed.slice(2).trimStart();
|
|
634
|
+
}
|
|
635
|
+
if (trimmed.startsWith('/*') && trimmed.endsWith('*/')) {
|
|
636
|
+
const inner = trimmed.slice(2, -2).trim();
|
|
637
|
+
return inner;
|
|
638
|
+
}
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
641
|
+
flushSmartCommentBlockBuilder() {
|
|
642
|
+
var _a;
|
|
643
|
+
if (!this.smartCommentBlockBuilder) {
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
const { lines, level, mode } = this.smartCommentBlockBuilder;
|
|
647
|
+
if (mode === 'line') {
|
|
648
|
+
if (lines.length > 1) {
|
|
649
|
+
const blockText = this.buildBlockComment(lines, level);
|
|
650
|
+
this.linePrinter.appendText(blockText);
|
|
651
|
+
}
|
|
652
|
+
else {
|
|
653
|
+
const content = (_a = lines[0]) !== null && _a !== void 0 ? _a : '';
|
|
654
|
+
const lineText = content ? `-- ${content}` : '--';
|
|
655
|
+
this.linePrinter.appendText(lineText);
|
|
656
|
+
}
|
|
657
|
+
if (!this.isOnelineMode()) {
|
|
658
|
+
this.linePrinter.appendNewline(level);
|
|
659
|
+
}
|
|
660
|
+
this.pendingLineCommentBreak = null;
|
|
661
|
+
}
|
|
662
|
+
this.smartCommentBlockBuilder = null;
|
|
663
|
+
}
|
|
664
|
+
collectCommentBlockLines(token) {
|
|
665
|
+
var _a;
|
|
666
|
+
const lines = [];
|
|
667
|
+
let collectingBlock = false;
|
|
668
|
+
for (const child of (_a = token.innerTokens) !== null && _a !== void 0 ? _a : []) {
|
|
669
|
+
if (child.type === SqlPrintToken_1.SqlPrintTokenType.comment) {
|
|
670
|
+
const trimmed = child.text.trim();
|
|
671
|
+
if (trimmed === '/*') {
|
|
672
|
+
collectingBlock = true;
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
if (trimmed === '*/') {
|
|
676
|
+
collectingBlock = false;
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
if (collectingBlock) {
|
|
680
|
+
lines.push(this.normalizeSmartBlockLine(child.text));
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
const content = this.extractLineCommentContent(trimmed);
|
|
684
|
+
if (content !== null) {
|
|
685
|
+
lines.push(content);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return lines;
|
|
690
|
+
}
|
|
691
|
+
extractRawCommentBlockLines(token) {
|
|
692
|
+
var _a;
|
|
693
|
+
const lines = [];
|
|
694
|
+
let collectingBlock = false;
|
|
695
|
+
for (const child of (_a = token.innerTokens) !== null && _a !== void 0 ? _a : []) {
|
|
696
|
+
if (child.type === SqlPrintToken_1.SqlPrintTokenType.comment) {
|
|
697
|
+
const text = child.text;
|
|
698
|
+
const trimmed = text.trim();
|
|
699
|
+
if (trimmed === '/*') {
|
|
700
|
+
collectingBlock = true;
|
|
701
|
+
continue;
|
|
702
|
+
}
|
|
703
|
+
if (trimmed === '*/') {
|
|
704
|
+
collectingBlock = false;
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
if (collectingBlock) {
|
|
708
|
+
if (trimmed.length > 0) {
|
|
709
|
+
lines.push(trimmed);
|
|
710
|
+
}
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
return lines;
|
|
716
|
+
}
|
|
717
|
+
normalizeCommentForSmart(text) {
|
|
718
|
+
const trimmed = text.trim();
|
|
719
|
+
let source = trimmed;
|
|
720
|
+
let forceBlock = false;
|
|
721
|
+
if (trimmed.startsWith('--')) {
|
|
722
|
+
source = trimmed.slice(2);
|
|
723
|
+
}
|
|
724
|
+
else if (trimmed.startsWith('/*') && trimmed.endsWith('*/')) {
|
|
725
|
+
const inner = trimmed.slice(2, -2);
|
|
726
|
+
const normalizedInner = inner.replace(/\r?\n/g, '\n');
|
|
727
|
+
if (normalizedInner.includes('\n')) {
|
|
728
|
+
forceBlock = true;
|
|
729
|
+
source = inner;
|
|
730
|
+
}
|
|
731
|
+
else {
|
|
732
|
+
source = inner;
|
|
733
|
+
if (!source.trim()) {
|
|
734
|
+
source = trimmed;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
const escaped = this.escapeCommentDelimiters(source);
|
|
739
|
+
const normalized = escaped.replace(/\r?\n/g, '\n');
|
|
740
|
+
const rawSegments = normalized.split('\n');
|
|
741
|
+
const processedLines = [];
|
|
742
|
+
const processedRaw = [];
|
|
743
|
+
for (const segment of rawSegments) {
|
|
744
|
+
const rawTrimmed = segment.trim();
|
|
745
|
+
const sanitized = this.sanitizeCommentLine(segment);
|
|
746
|
+
if (sanitized.length > 0) {
|
|
747
|
+
processedLines.push(sanitized);
|
|
748
|
+
processedRaw.push(rawTrimmed);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
let lines = processedLines;
|
|
752
|
+
if (lines.length === 0) {
|
|
753
|
+
lines = [''];
|
|
754
|
+
}
|
|
755
|
+
if (!forceBlock && lines.length === 1 && !lines[0] && trimmed.startsWith('/*') && trimmed.endsWith('*/')) {
|
|
756
|
+
const escapedFull = this.escapeCommentDelimiters(trimmed);
|
|
757
|
+
lines = [this.sanitizeCommentLine(escapedFull)];
|
|
758
|
+
}
|
|
759
|
+
if (!forceBlock && lines.length > 1) {
|
|
760
|
+
forceBlock = true;
|
|
761
|
+
}
|
|
762
|
+
lines = lines.map((line, index) => {
|
|
763
|
+
var _a;
|
|
764
|
+
if (/^[-=_+*#]+$/.test(line)) {
|
|
765
|
+
const rawLine = (_a = processedRaw[index]) !== null && _a !== void 0 ? _a : line;
|
|
766
|
+
const normalizedRaw = rawLine.replace(/\s+/g, '');
|
|
767
|
+
if (normalizedRaw.length >= line.length) {
|
|
768
|
+
return normalizedRaw;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
return line;
|
|
772
|
+
});
|
|
773
|
+
return { lines, forceBlock };
|
|
774
|
+
}
|
|
775
|
+
buildBlockComment(lines, level) {
|
|
776
|
+
var _a, _b, _c;
|
|
777
|
+
if (lines.length <= 1) {
|
|
778
|
+
const content = (_a = lines[0]) !== null && _a !== void 0 ? _a : '';
|
|
779
|
+
return content ? `/* ${content} */` : '/* */';
|
|
780
|
+
}
|
|
781
|
+
const newline = this.newline === ' ' ? '\n' : this.newline;
|
|
782
|
+
const currentLevel = (_c = (_b = this.linePrinter.getCurrentLine()) === null || _b === void 0 ? void 0 : _b.level) !== null && _c !== void 0 ? _c : level;
|
|
783
|
+
const baseIndent = this.getIndentString(currentLevel);
|
|
784
|
+
const unitIndent = ' ';
|
|
785
|
+
const innerIndent = baseIndent + unitIndent;
|
|
786
|
+
const body = lines.map(line => `${innerIndent}${line}`).join(newline);
|
|
787
|
+
const closing = `${baseIndent}*/`;
|
|
788
|
+
return `/*${newline}${body}${newline}${closing}`;
|
|
789
|
+
}
|
|
790
|
+
getIndentString(level) {
|
|
791
|
+
if (level <= 0) {
|
|
792
|
+
return '';
|
|
793
|
+
}
|
|
794
|
+
if (this.indentSize <= 0) {
|
|
795
|
+
return ' '.repeat(level);
|
|
796
|
+
}
|
|
797
|
+
const unit = typeof this.indentChar === 'string' ? this.indentChar : '';
|
|
798
|
+
return unit.repeat(this.indentSize * level);
|
|
799
|
+
}
|
|
800
|
+
sanitizeCommentLine(content) {
|
|
801
|
+
let sanitized = content;
|
|
802
|
+
sanitized = sanitized.replace(/\u2028|\u2029/g, ' ');
|
|
803
|
+
sanitized = sanitized.replace(/\s+/g, ' ').trim();
|
|
804
|
+
return sanitized;
|
|
805
|
+
}
|
|
806
|
+
escapeCommentDelimiters(content) {
|
|
807
|
+
return content
|
|
808
|
+
.replace(/\/\*/g, '\\/\\*')
|
|
809
|
+
.replace(/\*\//g, '*\\/');
|
|
810
|
+
}
|
|
359
811
|
/**
|
|
360
812
|
* Handles commentNewline tokens with conditional newline behavior.
|
|
361
813
|
* In multiline mode (newline !== ' '), adds a newline after comments.
|
|
@@ -363,6 +815,14 @@ class SqlPrinter {
|
|
|
363
815
|
* Skips newlines in CTE modes (full-oneline, cte-oneline) to maintain one-line format.
|
|
364
816
|
*/
|
|
365
817
|
handleCommentNewlineToken(token, level) {
|
|
818
|
+
if (this.smartCommentBlockBuilder) {
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
if (this.pendingLineCommentBreak !== null) {
|
|
822
|
+
this.linePrinter.appendNewline(this.pendingLineCommentBreak);
|
|
823
|
+
this.pendingLineCommentBreak = null;
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
366
826
|
if (this.shouldSkipCommentNewline()) {
|
|
367
827
|
return;
|
|
368
828
|
}
|
|
@@ -408,10 +868,11 @@ class SqlPrinter {
|
|
|
408
868
|
cteCommaBreak: this.cteCommaBreak,
|
|
409
869
|
valuesCommaBreak: this.valuesCommaBreak,
|
|
410
870
|
andBreak: this.andBreak,
|
|
871
|
+
orBreak: this.orBreak,
|
|
411
872
|
keywordCase: this.keywordCase,
|
|
412
873
|
exportComment: false,
|
|
413
|
-
strictCommentPlacement: this.strictCommentPlacement,
|
|
414
874
|
withClauseStyle: 'standard', // Prevent recursive processing
|
|
875
|
+
indentNestedParentheses: false,
|
|
415
876
|
});
|
|
416
877
|
}
|
|
417
878
|
/**
|
|
@@ -437,10 +898,10 @@ class SqlPrinter {
|
|
|
437
898
|
commaBreak: 'none', // Disable comma-based line breaks
|
|
438
899
|
cteCommaBreak: this.cteCommaBreak,
|
|
439
900
|
valuesCommaBreak: 'none',
|
|
440
|
-
andBreak: 'none', // Disable AND
|
|
901
|
+
andBreak: 'none', // Disable AND-based line breaks
|
|
902
|
+
orBreak: 'none', // Disable OR-based line breaks
|
|
441
903
|
keywordCase: this.keywordCase,
|
|
442
904
|
exportComment: this.exportComment,
|
|
443
|
-
strictCommentPlacement: this.strictCommentPlacement,
|
|
444
905
|
withClauseStyle: 'standard',
|
|
445
906
|
parenthesesOneLine: false, // Prevent recursive processing (avoid infinite loops)
|
|
446
907
|
betweenOneLine: false, // Prevent recursive processing (avoid infinite loops)
|
|
@@ -448,6 +909,7 @@ class SqlPrinter {
|
|
|
448
909
|
joinOneLine: false, // Prevent recursive processing (avoid infinite loops)
|
|
449
910
|
caseOneLine: false, // Prevent recursive processing (avoid infinite loops)
|
|
450
911
|
subqueryOneLine: false, // Prevent recursive processing (avoid infinite loops)
|
|
912
|
+
indentNestedParentheses: false,
|
|
451
913
|
});
|
|
452
914
|
}
|
|
453
915
|
/**
|