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.
Files changed (46) hide show
  1. package/README.md +6 -6
  2. package/dist/esm/index.min.js +18 -9
  3. package/dist/esm/index.min.js.map +2 -2
  4. package/dist/esm/src/parsers/KeywordParser.js +4 -2
  5. package/dist/esm/src/parsers/KeywordParser.js.map +1 -1
  6. package/dist/esm/src/parsers/SqlPrintTokenParser.d.ts +11 -18
  7. package/dist/esm/src/parsers/SqlPrintTokenParser.js +126 -218
  8. package/dist/esm/src/parsers/SqlPrintTokenParser.js.map +1 -1
  9. package/dist/esm/src/parsers/SqlTokenizer.js +26 -13
  10. package/dist/esm/src/parsers/SqlTokenizer.js.map +1 -1
  11. package/dist/esm/src/transformers/LinePrinter.d.ts +1 -0
  12. package/dist/esm/src/transformers/LinePrinter.js +22 -1
  13. package/dist/esm/src/transformers/LinePrinter.js.map +1 -1
  14. package/dist/esm/src/transformers/SqlFormatter.d.ts +6 -4
  15. package/dist/esm/src/transformers/SqlFormatter.js +2 -2
  16. package/dist/esm/src/transformers/SqlFormatter.js.map +1 -1
  17. package/dist/esm/src/transformers/SqlPrinter.d.ts +40 -2
  18. package/dist/esm/src/transformers/SqlPrinter.js +489 -27
  19. package/dist/esm/src/transformers/SqlPrinter.js.map +1 -1
  20. package/dist/esm/src/utils/stringUtils.d.ts +1 -1
  21. package/dist/esm/src/utils/stringUtils.js +8 -2
  22. package/dist/esm/src/utils/stringUtils.js.map +1 -1
  23. package/dist/esm/tsconfig.browser.tsbuildinfo +1 -1
  24. package/dist/index.min.js +18 -9
  25. package/dist/index.min.js.map +2 -2
  26. package/dist/src/parsers/KeywordParser.js +4 -2
  27. package/dist/src/parsers/KeywordParser.js.map +1 -1
  28. package/dist/src/parsers/SqlPrintTokenParser.d.ts +11 -18
  29. package/dist/src/parsers/SqlPrintTokenParser.js +126 -218
  30. package/dist/src/parsers/SqlPrintTokenParser.js.map +1 -1
  31. package/dist/src/parsers/SqlTokenizer.js +26 -13
  32. package/dist/src/parsers/SqlTokenizer.js.map +1 -1
  33. package/dist/src/transformers/LinePrinter.d.ts +1 -0
  34. package/dist/src/transformers/LinePrinter.js +22 -1
  35. package/dist/src/transformers/LinePrinter.js.map +1 -1
  36. package/dist/src/transformers/SqlFormatter.d.ts +6 -4
  37. package/dist/src/transformers/SqlFormatter.js +2 -2
  38. package/dist/src/transformers/SqlFormatter.js.map +1 -1
  39. package/dist/src/transformers/SqlPrinter.d.ts +40 -2
  40. package/dist/src/transformers/SqlPrinter.js +489 -27
  41. package/dist/src/transformers/SqlPrinter.js.map +1 -1
  42. package/dist/src/utils/stringUtils.d.ts +1 -1
  43. package/dist/src/utils/stringUtils.js +8 -2
  44. package/dist/src/utils/stringUtils.js.map +1 -1
  45. package/dist/tsconfig.tsbuildinfo +1 -1
  46. 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.keywordCase = (_f = options === null || options === void 0 ? void 0 : options.keywordCase) !== null && _f !== void 0 ? _f : 'none';
45
- this.exportComment = (_g = options === null || options === void 0 ? void 0 : options.exportComment) !== null && _g !== void 0 ? _g : false;
46
- this.strictCommentPlacement = (_h = options === null || options === void 0 ? void 0 : options.strictCommentPlacement) !== null && _h !== void 0 ? _h : false;
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((_s = options === null || options === void 0 ? void 0 : options.indentIncrementContainerTypes) !== null && _s !== void 0 ? _s : [
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
- // Note: Smart comment processing is handled at SqlPrintTokenParser level
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
- // indent level up
168
- if (!this.isOnelineMode() && current.text !== '' && this.indentIncrementContainers.has(token.containerType)) {
169
- // Skip newline for any container when inside WITH clause with full-oneline style
170
- if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
171
- innerLevel++;
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
- this.appendToken(child, innerLevel, token.containerType, nextCaseContextDepth);
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 (innerLevel !== level) {
188
- // Skip newline for any container when inside WITH clause with full-oneline style
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/OR-based line breaks
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
  /**