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