rawsql-ts 0.24.1 → 0.24.3

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 (54) hide show
  1. package/dist/esm/index.min.js +7 -7
  2. package/dist/esm/index.min.js.map +2 -2
  3. package/dist/esm/parsers/CommandExpressionParser.d.ts +2 -0
  4. package/dist/esm/parsers/CommandExpressionParser.js +49 -4
  5. package/dist/esm/parsers/CommandExpressionParser.js.map +1 -1
  6. package/dist/esm/parsers/HavingParser.js +6 -0
  7. package/dist/esm/parsers/HavingParser.js.map +1 -1
  8. package/dist/esm/parsers/JoinOnClauseParser.js +6 -0
  9. package/dist/esm/parsers/JoinOnClauseParser.js.map +1 -1
  10. package/dist/esm/parsers/LimitClauseParser.js +6 -0
  11. package/dist/esm/parsers/LimitClauseParser.js.map +1 -1
  12. package/dist/esm/parsers/OffsetClauseParser.js +6 -0
  13. package/dist/esm/parsers/OffsetClauseParser.js.map +1 -1
  14. package/dist/esm/parsers/OrderByClauseParser.d.ts +2 -0
  15. package/dist/esm/parsers/OrderByClauseParser.js +42 -29
  16. package/dist/esm/parsers/OrderByClauseParser.js.map +1 -1
  17. package/dist/esm/parsers/SqlPrintTokenParser.d.ts +3 -0
  18. package/dist/esm/parsers/SqlPrintTokenParser.js +70 -6
  19. package/dist/esm/parsers/SqlPrintTokenParser.js.map +1 -1
  20. package/dist/esm/parsers/ValueParser.js +5 -3
  21. package/dist/esm/parsers/ValueParser.js.map +1 -1
  22. package/dist/esm/transformers/SqlFormatter.d.ts +7 -1
  23. package/dist/esm/transformers/SqlFormatter.js.map +1 -1
  24. package/dist/esm/transformers/SqlPrinter.d.ts +32 -2
  25. package/dist/esm/transformers/SqlPrinter.js +255 -33
  26. package/dist/esm/transformers/SqlPrinter.js.map +1 -1
  27. package/dist/index.min.js +7 -7
  28. package/dist/index.min.js.map +2 -2
  29. package/dist/parsers/CommandExpressionParser.js +49 -4
  30. package/dist/parsers/CommandExpressionParser.js.map +1 -1
  31. package/dist/parsers/HavingParser.js +6 -0
  32. package/dist/parsers/HavingParser.js.map +1 -1
  33. package/dist/parsers/JoinOnClauseParser.js +6 -0
  34. package/dist/parsers/JoinOnClauseParser.js.map +1 -1
  35. package/dist/parsers/LimitClauseParser.js +6 -0
  36. package/dist/parsers/LimitClauseParser.js.map +1 -1
  37. package/dist/parsers/OffsetClauseParser.js +6 -0
  38. package/dist/parsers/OffsetClauseParser.js.map +1 -1
  39. package/dist/parsers/OrderByClauseParser.js +42 -29
  40. package/dist/parsers/OrderByClauseParser.js.map +1 -1
  41. package/dist/parsers/SqlPrintTokenParser.js +71 -6
  42. package/dist/parsers/SqlPrintTokenParser.js.map +1 -1
  43. package/dist/parsers/ValueParser.js +5 -3
  44. package/dist/parsers/ValueParser.js.map +1 -1
  45. package/dist/src/parsers/CommandExpressionParser.d.ts +2 -0
  46. package/dist/src/parsers/OrderByClauseParser.d.ts +2 -0
  47. package/dist/src/parsers/SqlPrintTokenParser.d.ts +3 -0
  48. package/dist/src/transformers/SqlFormatter.d.ts +7 -1
  49. package/dist/src/transformers/SqlPrinter.d.ts +32 -2
  50. package/dist/transformers/SqlFormatter.js.map +1 -1
  51. package/dist/transformers/SqlPrinter.js +255 -33
  52. package/dist/transformers/SqlPrinter.js.map +1 -1
  53. package/dist/tsconfig.browser.tsbuildinfo +1 -1
  54. package/package.json +1 -1
@@ -30,15 +30,21 @@ export class SqlPrinter {
30
30
  * @param options Optional style settings for pretty printing
31
31
  */
32
32
  constructor(options) {
33
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
33
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
34
34
  /** Track whether we are currently inside a WITH clause for full-oneline formatting */
35
35
  this.insideWithClause = false;
36
36
  /** Tracks nesting depth while formatting MERGE WHEN predicate segments */
37
37
  this.mergeWhenPredicateDepth = 0;
38
+ /** Tracks nesting depth while formatting JOIN ON condition segments */
39
+ this.joinOnClauseDepth = 0;
40
+ /** Containers whose one-line rendering was rejected by oneLineMaxLength */
41
+ this.expandedOneLineFallbackTokens = new WeakSet();
38
42
  /** Pending line comment that needs a forced newline before next token */
39
43
  this.pendingLineCommentBreak = null;
40
44
  /** Accumulates lines when reconstructing multi-line block comments inside CommentBlocks */
41
45
  this.smartCommentBlockBuilder = null;
46
+ /** Tracks function calls whose arguments must expand because rendered comments are present */
47
+ this.commentedFunctionCallDepth = 0;
42
48
  // Resolve logical options to their control character representations before applying defaults.
43
49
  const resolvedIndentChar = resolveIndentCharOption(options === null || options === void 0 ? void 0 : options.indentChar);
44
50
  const resolvedNewline = resolveNewlineOption(options === null || options === void 0 ? void 0 : options.newline);
@@ -52,19 +58,22 @@ export class SqlPrinter {
52
58
  this.valuesCommaBreak = (_d = options === null || options === void 0 ? void 0 : options.valuesCommaBreak) !== null && _d !== void 0 ? _d : this.commaBreak;
53
59
  this.andBreak = (_e = options === null || options === void 0 ? void 0 : options.andBreak) !== null && _e !== void 0 ? _e : 'none';
54
60
  this.orBreak = (_f = options === null || options === void 0 ? void 0 : options.orBreak) !== null && _f !== void 0 ? _f : 'none';
55
- this.keywordCase = (_g = options === null || options === void 0 ? void 0 : options.keywordCase) !== null && _g !== void 0 ? _g : 'none';
61
+ this.joinOnBreak = (_g = options === null || options === void 0 ? void 0 : options.joinOnBreak) !== null && _g !== void 0 ? _g : 'none';
62
+ this.keywordCase = (_h = options === null || options === void 0 ? void 0 : options.keywordCase) !== null && _h !== void 0 ? _h : 'none';
56
63
  this.commentExportMode = this.resolveCommentExportMode(options === null || options === void 0 ? void 0 : options.exportComment);
57
- this.withClauseStyle = (_h = options === null || options === void 0 ? void 0 : options.withClauseStyle) !== null && _h !== void 0 ? _h : 'standard';
58
- this.commentStyle = (_j = options === null || options === void 0 ? void 0 : options.commentStyle) !== null && _j !== void 0 ? _j : 'block';
59
- this.parenthesesOneLine = (_k = options === null || options === void 0 ? void 0 : options.parenthesesOneLine) !== null && _k !== void 0 ? _k : false;
60
- this.betweenOneLine = (_l = options === null || options === void 0 ? void 0 : options.betweenOneLine) !== null && _l !== void 0 ? _l : false;
61
- this.valuesOneLine = (_m = options === null || options === void 0 ? void 0 : options.valuesOneLine) !== null && _m !== void 0 ? _m : false;
62
- this.joinOneLine = (_o = options === null || options === void 0 ? void 0 : options.joinOneLine) !== null && _o !== void 0 ? _o : false;
63
- this.caseOneLine = (_p = options === null || options === void 0 ? void 0 : options.caseOneLine) !== null && _p !== void 0 ? _p : false;
64
- this.subqueryOneLine = (_q = options === null || options === void 0 ? void 0 : options.subqueryOneLine) !== null && _q !== void 0 ? _q : false;
65
- this.indentNestedParentheses = (_r = options === null || options === void 0 ? void 0 : options.indentNestedParentheses) !== null && _r !== void 0 ? _r : false;
66
- this.insertColumnsOneLine = (_s = options === null || options === void 0 ? void 0 : options.insertColumnsOneLine) !== null && _s !== void 0 ? _s : false;
67
- this.whenOneLine = (_t = options === null || options === void 0 ? void 0 : options.whenOneLine) !== null && _t !== void 0 ? _t : false;
64
+ this.withClauseStyle = (_j = options === null || options === void 0 ? void 0 : options.withClauseStyle) !== null && _j !== void 0 ? _j : 'standard';
65
+ this.commentStyle = (_k = options === null || options === void 0 ? void 0 : options.commentStyle) !== null && _k !== void 0 ? _k : 'block';
66
+ this.parenthesesOneLine = (_l = options === null || options === void 0 ? void 0 : options.parenthesesOneLine) !== null && _l !== void 0 ? _l : false;
67
+ this.betweenOneLine = (_m = options === null || options === void 0 ? void 0 : options.betweenOneLine) !== null && _m !== void 0 ? _m : false;
68
+ this.valuesOneLine = (_o = options === null || options === void 0 ? void 0 : options.valuesOneLine) !== null && _o !== void 0 ? _o : false;
69
+ this.joinOneLine = (_p = options === null || options === void 0 ? void 0 : options.joinOneLine) !== null && _p !== void 0 ? _p : false;
70
+ this.caseOneLine = (_q = options === null || options === void 0 ? void 0 : options.caseOneLine) !== null && _q !== void 0 ? _q : false;
71
+ this.subqueryOneLine = (_r = options === null || options === void 0 ? void 0 : options.subqueryOneLine) !== null && _r !== void 0 ? _r : false;
72
+ this.indentNestedParentheses = (_s = options === null || options === void 0 ? void 0 : options.indentNestedParentheses) !== null && _s !== void 0 ? _s : false;
73
+ this.insertColumnsOneLine = (_t = options === null || options === void 0 ? void 0 : options.insertColumnsOneLine) !== null && _t !== void 0 ? _t : false;
74
+ this.whenOneLine = (_u = options === null || options === void 0 ? void 0 : options.whenOneLine) !== null && _u !== void 0 ? _u : false;
75
+ this.oneLineMaxLength = this.normalizeOneLineMaxLength(options === null || options === void 0 ? void 0 : options.oneLineMaxLength);
76
+ this.joinConditionContinuationIndent = (_v = options === null || options === void 0 ? void 0 : options.joinConditionContinuationIndent) !== null && _v !== void 0 ? _v : false;
68
77
  const onelineOptions = {
69
78
  parenthesesOneLine: this.parenthesesOneLine,
70
79
  betweenOneLine: this.betweenOneLine,
@@ -78,7 +87,7 @@ export class SqlPrinter {
78
87
  this.onelineHelper = new OnelineFormattingHelper(onelineOptions);
79
88
  this.linePrinter = new LinePrinter(this.indentChar, this.indentSize, this.newline, this.commaBreak);
80
89
  // Initialize
81
- this.indentIncrementContainers = new Set((_u = options === null || options === void 0 ? void 0 : options.indentIncrementContainerTypes) !== null && _u !== void 0 ? _u : [
90
+ this.indentIncrementContainers = new Set((_w = options === null || options === void 0 ? void 0 : options.indentIncrementContainerTypes) !== null && _w !== void 0 ? _w : [
82
91
  SqlPrintTokenContainerType.SelectClause,
83
92
  SqlPrintTokenContainerType.ReturningClause,
84
93
  SqlPrintTokenContainerType.FromClause,
@@ -124,8 +133,11 @@ export class SqlPrinter {
124
133
  // initialize
125
134
  this.linePrinter = new LinePrinter(this.indentChar, this.indentSize, this.newline, this.commaBreak);
126
135
  this.insideWithClause = false; // Reset WITH clause context
136
+ this.joinOnClauseDepth = 0;
127
137
  this.pendingLineCommentBreak = null;
128
138
  this.smartCommentBlockBuilder = null;
139
+ this.expandedOneLineFallbackTokens = new WeakSet();
140
+ this.commentedFunctionCallDepth = 0;
129
141
  if (this.linePrinter.lines.length > 0 && level !== this.linePrinter.lines[0].level) {
130
142
  this.linePrinter.lines[0].level = level;
131
143
  }
@@ -168,6 +180,7 @@ export class SqlPrinter {
168
180
  }
169
181
  }
170
182
  appendToken(token, level, parentContainerType, caseContextDepth = 0, indentParentActive = false, commentContext, previousSiblingWasOpenParen = false) {
183
+ var _a;
171
184
  // Track WITH clause context for full-oneline formatting
172
185
  const wasInsideWithClause = this.insideWithClause;
173
186
  if (token.containerType === SqlPrintTokenContainerType.WithClause && this.withClauseStyle === 'full-oneline') {
@@ -196,12 +209,16 @@ export class SqlPrinter {
196
209
  }
197
210
  }
198
211
  const hasRenderableLeadingComment = leadingCommentContexts.some(item => item.shouldRender);
212
+ const leadingCommentFollowsLogicalOperator = hasRenderableLeadingComment && this.currentLineEndsWithLogicalOperator();
199
213
  const leadingCommentIndentLevel = hasRenderableLeadingComment
200
- ? this.getLeadingCommentIndentLevel(parentContainerType, level)
214
+ ? this.getLeadingCommentIndentLevel(token.containerType === SqlPrintTokenContainerType.SelectItem
215
+ ? token.containerType
216
+ : parentContainerType, level)
201
217
  : null;
202
218
  if (hasRenderableLeadingComment
203
219
  && !this.isOnelineMode()
204
- && this.shouldAddNewlineBeforeLeadingComments(parentContainerType)) {
220
+ && this.shouldAddNewlineBeforeLeadingComments(parentContainerType)
221
+ && !this.shouldKeepLeadingCommentOnCommaLine()) {
205
222
  const currentLine = this.linePrinter.getCurrentLine();
206
223
  if (currentLine.text.trim().length > 0) {
207
224
  // Align the newline before leading comments with the intended comment indentation.
@@ -214,13 +231,26 @@ export class SqlPrinter {
214
231
  }
215
232
  // Keep leading comment processing aligned with its computed indentation level.
216
233
  this.appendToken(leading.token, leadingCommentIndentLevel !== null && leadingCommentIndentLevel !== void 0 ? leadingCommentIndentLevel : level, token.containerType, caseContextDepth, indentParentActive, leading.context, false);
234
+ if (token.containerType === SqlPrintTokenContainerType.SelectItem &&
235
+ ((_a = this.smartCommentBlockBuilder) === null || _a === void 0 ? void 0 : _a.mode) === 'line') {
236
+ this.flushSmartCommentBlockBuilder();
237
+ }
238
+ }
239
+ if (leadingCommentFollowsLogicalOperator &&
240
+ this.pendingLineCommentBreak === null &&
241
+ !this.isOnelineMode() &&
242
+ this.linePrinter.getCurrentLine().text.trim().endsWith('*/')) {
243
+ this.linePrinter.appendNewline(level + 1);
217
244
  }
218
245
  if (this.smartCommentBlockBuilder && token.containerType !== SqlPrintTokenContainerType.CommentBlock && token.type !== SqlPrintTokenType.commentNewline) {
219
246
  this.flushSmartCommentBlockBuilder();
220
247
  }
221
248
  if (this.pendingLineCommentBreak !== null) {
222
249
  if (!this.isOnelineMode()) {
223
- this.linePrinter.appendNewline(this.pendingLineCommentBreak);
250
+ const pendingBreakLevel = leadingCommentFollowsLogicalOperator
251
+ ? this.pendingLineCommentBreak + 1
252
+ : this.pendingLineCommentBreak;
253
+ this.linePrinter.appendNewline(pendingBreakLevel);
224
254
  }
225
255
  const shouldSkipToken = token.type === SqlPrintTokenType.commentNewline;
226
256
  this.pendingLineCommentBreak = null;
@@ -237,14 +267,22 @@ export class SqlPrinter {
237
267
  if (!this.shouldRenderComment(token, effectiveCommentContext)) {
238
268
  return;
239
269
  }
270
+ if (this.shouldKeepLeadingCommentOnCommaLine()) {
271
+ this.ensureTrailingSpace();
272
+ }
240
273
  const commentLevel = this.getCommentBaseIndentLevel(level, parentContainerType);
274
+ if (parentContainerType === SqlPrintTokenContainerType.SelectItem &&
275
+ effectiveCommentContext.position === 'leading' &&
276
+ this.linePrinter.getCurrentLine().text.trim() === '') {
277
+ this.linePrinter.getCurrentLine().level = commentLevel;
278
+ }
241
279
  this.handleCommentBlockContainer(token, commentLevel, effectiveCommentContext);
242
280
  return;
243
281
  }
244
282
  const current = this.linePrinter.getCurrentLine();
245
283
  const isCaseContext = this.isCaseContext(token.containerType);
246
284
  const nextCaseContextDepth = isCaseContext ? caseContextDepth + 1 : caseContextDepth;
247
- const shouldIndentNested = this.shouldIndentNestedParentheses(token, previousSiblingWasOpenParen);
285
+ let shouldIndentNested = this.shouldIndentNestedParentheses(token, previousSiblingWasOpenParen);
248
286
  // Handle different token types
249
287
  if (token.type === SqlPrintTokenType.keyword) {
250
288
  this.handleKeywordToken(token, level, parentContainerType, caseContextDepth);
@@ -252,6 +290,9 @@ export class SqlPrinter {
252
290
  else if (token.type === SqlPrintTokenType.comma) {
253
291
  this.handleCommaToken(token, level, parentContainerType);
254
292
  }
293
+ else if (token.type === SqlPrintTokenType.argumentSplitter) {
294
+ this.handleArgumentSplitterToken(token, level, parentContainerType);
295
+ }
255
296
  else if (token.type === SqlPrintTokenType.parenthesis) {
256
297
  this.handleParenthesisToken(token, level, indentParentActive, parentContainerType);
257
298
  }
@@ -281,16 +322,25 @@ export class SqlPrinter {
281
322
  this.handleCommentNewlineToken(token, commentLevel);
282
323
  }
283
324
  else if (token.containerType === SqlPrintTokenContainerType.CommonTable && this.withClauseStyle === 'cte-oneline') {
284
- this.handleCteOnelineToken(token, level);
285
- return; // Return early to avoid processing innerTokens
325
+ if (this.tryHandleCteOnelineToken(token, level)) {
326
+ return; // Return early to avoid processing innerTokens
327
+ }
286
328
  }
287
- else if (this.shouldFormatContainerAsOneline(token, shouldIndentNested)) {
288
- this.handleOnelineToken(token, level);
329
+ else if (this.shouldFormatContainerAsOneline(token, shouldIndentNested) && this.tryHandleOnelineToken(token, level)) {
289
330
  return; // Return early to avoid processing innerTokens
290
331
  }
291
332
  else if (!this.tryAppendInsertClauseTokenText(token.text, parentContainerType)) {
292
333
  this.linePrinter.appendText(token.text);
293
334
  }
335
+ if (token.containerType === SqlPrintTokenContainerType.JoinOnClause &&
336
+ this.joinOnBreak === 'before' &&
337
+ !this.isOnelineMode() &&
338
+ this.linePrinter.getCurrentLine().text.trim().length > 0) {
339
+ this.linePrinter.appendNewline(level + 1);
340
+ }
341
+ if (this.expandedOneLineFallbackTokens.has(token)) {
342
+ shouldIndentNested = true;
343
+ }
294
344
  // append keyword tokens(not indented)
295
345
  if (token.keywordTokens && token.keywordTokens.length > 0) {
296
346
  for (let i = 0; i < token.keywordTokens.length; i++) {
@@ -304,6 +354,9 @@ export class SqlPrinter {
304
354
  const delayIndentNewline = shouldIndentNested && token.containerType === SqlPrintTokenContainerType.ParenExpression;
305
355
  const isAlterTableStatement = token.containerType === SqlPrintTokenContainerType.AlterTableStatement;
306
356
  let deferAlterTableIndent = false;
357
+ if (token.containerType === SqlPrintTokenContainerType.JoinOnClause && this.joinOnBreak === 'before' && !this.isOnelineMode()) {
358
+ innerLevel = level + 1;
359
+ }
307
360
  const alignExplainChild = this.shouldAlignExplainStatementChild(parentContainerType, token.containerType);
308
361
  if (alignExplainChild) {
309
362
  // Keep EXPLAIN target statements flush left so they render like standalone statements.
@@ -356,6 +409,15 @@ export class SqlPrinter {
356
409
  let mergePredicateActive = isMergeWhenClause;
357
410
  let alterTableTableRendered = false;
358
411
  let alterTableIndentInserted = false;
412
+ const enteredJoinOnClause = token.containerType === SqlPrintTokenContainerType.JoinOnClause;
413
+ if (enteredJoinOnClause) {
414
+ this.joinOnClauseDepth++;
415
+ }
416
+ const enteredCommentedFunctionCall = this.shouldExpandCommentedFunctionCall(token);
417
+ if (enteredCommentedFunctionCall) {
418
+ this.commentedFunctionCallDepth++;
419
+ }
420
+ const enteredLogicalOperatorWithComment = this.isLogicalOperatorWithComment(token);
359
421
  for (let i = leadingCommentCount; i < token.innerTokens.length; i++) {
360
422
  const child = token.innerTokens[i];
361
423
  const nextChild = token.innerTokens[i + 1];
@@ -406,7 +468,10 @@ export class SqlPrinter {
406
468
  const childCommentContext = child.containerType === SqlPrintTokenContainerType.CommentBlock
407
469
  ? { position: 'inline', isTopLevelContainer: containerIsTopLevel }
408
470
  : undefined;
409
- this.appendToken(child, innerLevel, token.containerType, nextCaseContextDepth, childIndentParentActive, childCommentContext, previousChildWasOpenParen);
471
+ const childLevel = enteredCommentedFunctionCall && child.containerType === SqlPrintTokenContainerType.ValueList
472
+ ? innerLevel + 1
473
+ : innerLevel;
474
+ this.appendToken(child, childLevel, token.containerType, nextCaseContextDepth, childIndentParentActive, childCommentContext, previousChildWasOpenParen);
410
475
  if (inMergePredicate) {
411
476
  this.mergeWhenPredicateDepth--;
412
477
  }
@@ -414,9 +479,24 @@ export class SqlPrinter {
414
479
  mergePredicateActive = false;
415
480
  }
416
481
  }
482
+ if (enteredLogicalOperatorWithComment && !this.isOnelineMode()) {
483
+ const currentLine = this.linePrinter.getCurrentLine();
484
+ if (currentLine.text.trim() === '') {
485
+ currentLine.level = level + 1;
486
+ }
487
+ else {
488
+ this.linePrinter.appendNewline(level + 1);
489
+ }
490
+ }
417
491
  if (this.smartCommentBlockBuilder && this.smartCommentBlockBuilder.mode === 'line') {
418
492
  this.flushSmartCommentBlockBuilder();
419
493
  }
494
+ if (enteredJoinOnClause) {
495
+ this.joinOnClauseDepth--;
496
+ }
497
+ if (enteredCommentedFunctionCall) {
498
+ this.commentedFunctionCallDepth--;
499
+ }
420
500
  // Exit WITH clause context when we finish processing WithClause container
421
501
  if (token.containerType === SqlPrintTokenContainerType.WithClause && this.withClauseStyle === 'full-oneline') {
422
502
  this.insideWithClause = false;
@@ -444,6 +524,27 @@ export class SqlPrinter {
444
524
  return false;
445
525
  }
446
526
  }
527
+ shouldExpandCommentedFunctionCall(token) {
528
+ return this.commentExportMode !== 'none' &&
529
+ token.containerType === SqlPrintTokenContainerType.FunctionCall &&
530
+ token.innerTokens.some(child => child.containerType === SqlPrintTokenContainerType.ValueList &&
531
+ this.containsCommentBlock(child));
532
+ }
533
+ containsCommentBlock(token) {
534
+ if (token.containerType === SqlPrintTokenContainerType.CommentBlock) {
535
+ return true;
536
+ }
537
+ return token.innerTokens.some(child => this.containsCommentBlock(child));
538
+ }
539
+ isLogicalOperatorWithComment(token) {
540
+ return this.containsCommentBlock(token) &&
541
+ token.type === SqlPrintTokenType.operator &&
542
+ ['and', 'or'].includes(token.text.toLowerCase());
543
+ }
544
+ currentLineEndsWithLogicalOperator() {
545
+ const trimmed = this.linePrinter.getCurrentLine().text.trim().toLowerCase();
546
+ return trimmed === 'and' || trimmed === 'or';
547
+ }
447
548
  isCaseContext(containerType) {
448
549
  switch (containerType) {
449
550
  case SqlPrintTokenContainerType.CaseExpression:
@@ -603,6 +704,14 @@ export class SqlPrinter {
603
704
  this.linePrinter.appendText(text);
604
705
  }
605
706
  }
707
+ handleArgumentSplitterToken(token, level, parentContainerType) {
708
+ this.linePrinter.appendText(token.text);
709
+ if (this.commentedFunctionCallDepth > 0 &&
710
+ parentContainerType === SqlPrintTokenContainerType.ValueList &&
711
+ !this.isOnelineMode()) {
712
+ this.linePrinter.appendNewline(level);
713
+ }
714
+ }
606
715
  handleAndOperatorToken(token, level, parentContainerType, caseContextDepth = 0) {
607
716
  const text = this.applyKeywordCase(token.text);
608
717
  if (caseContextDepth > 0) {
@@ -617,7 +726,7 @@ export class SqlPrinter {
617
726
  if (this.andBreak === 'before') {
618
727
  // Skip newline when inside WITH clause with full-oneline style
619
728
  if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
620
- this.linePrinter.appendNewline(level);
729
+ this.linePrinter.appendNewline(this.getJoinConditionContinuationLevel(level));
621
730
  }
622
731
  this.linePrinter.appendText(text);
623
732
  }
@@ -625,7 +734,7 @@ export class SqlPrinter {
625
734
  this.linePrinter.appendText(text);
626
735
  // Skip newline when inside WITH clause with full-oneline style
627
736
  if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
628
- this.linePrinter.appendNewline(level);
737
+ this.linePrinter.appendNewline(this.getJoinConditionContinuationLevel(level));
629
738
  }
630
739
  }
631
740
  else {
@@ -635,6 +744,12 @@ export class SqlPrinter {
635
744
  handleParenthesisToken(token, level, indentParentActive, parentContainerType) {
636
745
  if (token.text === '(') {
637
746
  this.linePrinter.appendText(token.text);
747
+ if (this.commentedFunctionCallDepth > 0 &&
748
+ parentContainerType === SqlPrintTokenContainerType.FunctionCall &&
749
+ !this.isOnelineMode()) {
750
+ this.linePrinter.appendNewline(level + 1);
751
+ return;
752
+ }
638
753
  if ((parentContainerType === SqlPrintTokenContainerType.InsertClause ||
639
754
  parentContainerType === SqlPrintTokenContainerType.MergeInsertAction) &&
640
755
  this.insertColumnsOneLine) {
@@ -644,19 +759,29 @@ export class SqlPrinter {
644
759
  if (this.shouldBreakAfterOpeningParen(parentContainerType)) {
645
760
  this.linePrinter.appendNewline(level + 1);
646
761
  }
647
- else if (indentParentActive && !(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
762
+ else if (indentParentActive &&
763
+ parentContainerType === SqlPrintTokenContainerType.ParenExpression &&
764
+ !(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
648
765
  this.linePrinter.appendNewline(level);
649
766
  }
650
767
  }
651
768
  return;
652
769
  }
653
770
  if (token.text === ')' && !this.isOnelineMode()) {
771
+ if (this.commentedFunctionCallDepth > 0 &&
772
+ parentContainerType === SqlPrintTokenContainerType.FunctionCall) {
773
+ this.linePrinter.appendNewline(level);
774
+ this.linePrinter.appendText(token.text);
775
+ return;
776
+ }
654
777
  if (this.shouldBreakBeforeClosingParen(parentContainerType)) {
655
778
  this.linePrinter.appendNewline(Math.max(level, 0));
656
779
  this.linePrinter.appendText(token.text);
657
780
  return;
658
781
  }
659
- if (indentParentActive && !(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
782
+ if (indentParentActive &&
783
+ parentContainerType === SqlPrintTokenContainerType.ParenExpression &&
784
+ !(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
660
785
  const closingLevel = Math.max(level - 1, 0);
661
786
  this.linePrinter.appendNewline(closingLevel);
662
787
  }
@@ -678,7 +803,7 @@ export class SqlPrinter {
678
803
  if (this.orBreak === 'before') {
679
804
  // Insert a newline before OR unless WITH full-oneline mode suppresses breaks.
680
805
  if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
681
- this.linePrinter.appendNewline(level);
806
+ this.linePrinter.appendNewline(this.getJoinConditionContinuationLevel(level));
682
807
  }
683
808
  this.linePrinter.appendText(text);
684
809
  }
@@ -686,13 +811,22 @@ export class SqlPrinter {
686
811
  this.linePrinter.appendText(text);
687
812
  // Break after OR when multi-line formatting is active.
688
813
  if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
689
- this.linePrinter.appendNewline(level);
814
+ this.linePrinter.appendNewline(this.getJoinConditionContinuationLevel(level));
690
815
  }
691
816
  }
692
817
  else {
693
818
  this.linePrinter.appendText(text);
694
819
  }
695
820
  }
821
+ getJoinConditionContinuationLevel(level) {
822
+ if (this.joinOnClauseDepth === 0) {
823
+ return level;
824
+ }
825
+ if (this.joinOnBreak === 'before') {
826
+ return level;
827
+ }
828
+ return this.joinConditionContinuationIndent ? level + 1 : level;
829
+ }
696
830
  /**
697
831
  * Decide whether a parentheses group should increase indentation when inside nested structures.
698
832
  * We only expand groups that contain further parentheses so simple comparisons stay compact.
@@ -704,6 +838,9 @@ export class SqlPrinter {
704
838
  if (token.containerType !== SqlPrintTokenContainerType.ParenExpression) {
705
839
  return false;
706
840
  }
841
+ if (this.expandedOneLineFallbackTokens.has(token)) {
842
+ return true;
843
+ }
707
844
  // Look for nested parentheses containers. If present, indent to highlight grouping.
708
845
  return previousSiblingWasOpenParen || token.innerTokens.some((child) => this.containsParenExpression(child));
709
846
  }
@@ -750,6 +887,12 @@ export class SqlPrinter {
750
887
  if (this.smartCommentBlockBuilder && this.smartCommentBlockBuilder.mode === 'line') {
751
888
  this.flushSmartCommentBlockBuilder();
752
889
  }
890
+ if (this.commentedFunctionCallDepth > 0 &&
891
+ parentContainerType === SqlPrintTokenContainerType.ValueList &&
892
+ (previousToken === null || previousToken === void 0 ? void 0 : previousToken.type) === SqlPrintTokenType.argumentSplitter &&
893
+ !this.isOnelineMode()) {
894
+ return;
895
+ }
753
896
  const currentLineText = this.linePrinter.getCurrentLine().text;
754
897
  if (this.onelineHelper.shouldSkipInsertClauseSpace(parentContainerType, nextToken, currentLineText)) {
755
898
  return;
@@ -974,6 +1117,11 @@ export class SqlPrinter {
974
1117
  }
975
1118
  return;
976
1119
  }
1120
+ const emptyBlockCommentText = this.getEmptyBlockCommentText(token);
1121
+ if (emptyBlockCommentText !== null) {
1122
+ this.linePrinter.appendText(emptyBlockCommentText);
1123
+ return;
1124
+ }
977
1125
  const lines = this.collectCommentBlockLines(token);
978
1126
  if (lines.length === 0 && !this.smartCommentBlockBuilder) {
979
1127
  // No meaningful content; treat as empty line comment to preserve spacing
@@ -995,6 +1143,18 @@ export class SqlPrinter {
995
1143
  this.smartCommentBlockBuilder.lines.push(...lines);
996
1144
  }
997
1145
  }
1146
+ getEmptyBlockCommentText(token) {
1147
+ var _a;
1148
+ const commentTokens = ((_a = token.innerTokens) !== null && _a !== void 0 ? _a : []).filter(child => child.type === SqlPrintTokenType.comment);
1149
+ if (commentTokens.length !== 1) {
1150
+ return null;
1151
+ }
1152
+ const trimmed = commentTokens[0].text.trim();
1153
+ if (!trimmed.startsWith('/*') || !trimmed.endsWith('*/')) {
1154
+ return null;
1155
+ }
1156
+ return trimmed.slice(2, -2).trim() === '' ? trimmed : null;
1157
+ }
998
1158
  normalizeSmartBlockLine(raw) {
999
1159
  // Remove trailing whitespace that only carries formatting artifacts
1000
1160
  let line = raw.replace(/\s+$/g, '');
@@ -1070,7 +1230,12 @@ export class SqlPrinter {
1070
1230
  }
1071
1231
  const content = this.extractLineCommentContent(trimmed);
1072
1232
  if (content !== null) {
1073
- lines.push(content);
1233
+ if (!content && trimmed.startsWith('/*') && trimmed.endsWith('*/')) {
1234
+ lines.push(this.sanitizeCommentLine(this.escapeCommentDelimiters(trimmed)));
1235
+ }
1236
+ else {
1237
+ lines.push(content);
1238
+ }
1074
1239
  }
1075
1240
  }
1076
1241
  }
@@ -1256,6 +1421,10 @@ export class SqlPrinter {
1256
1421
  if (parentType === SqlPrintTokenContainerType.SelectClause) {
1257
1422
  return true;
1258
1423
  }
1424
+ if (parentType === SqlPrintTokenContainerType.OrderByItem ||
1425
+ parentType === SqlPrintTokenContainerType.GroupByClause) {
1426
+ return true;
1427
+ }
1259
1428
  if (parentType === SqlPrintTokenContainerType.ExplainStatement) {
1260
1429
  // Ensure EXPLAIN targets print header comments on a dedicated line.
1261
1430
  return true;
@@ -1266,6 +1435,13 @@ export class SqlPrinter {
1266
1435
  return false;
1267
1436
  }
1268
1437
  getLeadingCommentIndentLevel(parentType, currentLevel) {
1438
+ if (parentType === SqlPrintTokenContainerType.SelectItem) {
1439
+ return currentLevel;
1440
+ }
1441
+ if (parentType === SqlPrintTokenContainerType.OrderByItem ||
1442
+ parentType === SqlPrintTokenContainerType.GroupByClause) {
1443
+ return currentLevel;
1444
+ }
1269
1445
  if (parentType === SqlPrintTokenContainerType.TupleExpression) {
1270
1446
  return currentLevel + 1;
1271
1447
  }
@@ -1280,6 +1456,12 @@ export class SqlPrinter {
1280
1456
  }
1281
1457
  return currentLevel;
1282
1458
  }
1459
+ shouldKeepLeadingCommentOnCommaLine() {
1460
+ if (this.commaBreak !== 'before') {
1461
+ return false;
1462
+ }
1463
+ return this.linePrinter.getCurrentLine().text.trim() === ',';
1464
+ }
1283
1465
  /**
1284
1466
  * Determines if the printer is in oneliner mode.
1285
1467
  * Oneliner mode uses single spaces instead of actual newlines.
@@ -1287,16 +1469,36 @@ export class SqlPrinter {
1287
1469
  isOnelineMode() {
1288
1470
  return this.newline === ' ';
1289
1471
  }
1472
+ normalizeOneLineMaxLength(value) {
1473
+ if (value === undefined || !Number.isFinite(value) || value <= 0) {
1474
+ return undefined;
1475
+ }
1476
+ const normalized = Math.floor(value);
1477
+ return normalized > 0 ? normalized : undefined;
1478
+ }
1479
+ fitsOneLineMaxLength(text) {
1480
+ if (this.oneLineMaxLength === undefined) {
1481
+ return true;
1482
+ }
1483
+ const currentLine = this.linePrinter.getCurrentLine();
1484
+ const indentWidth = currentLine.level * this.indentSize * String(this.indentChar).length;
1485
+ return indentWidth + currentLine.text.length + text.length <= this.oneLineMaxLength;
1486
+ }
1290
1487
  /**
1291
1488
  * Handles CTE tokens with one-liner formatting.
1292
1489
  * Creates a nested SqlPrinter instance for proper CTE oneline formatting.
1293
1490
  */
1294
- handleCteOnelineToken(token, level) {
1491
+ tryHandleCteOnelineToken(token, level) {
1295
1492
  const onelinePrinter = this.createCteOnelinePrinter();
1296
1493
  const onelineResult = onelinePrinter.print(token, level);
1297
1494
  let cleanedResult = this.cleanDuplicateSpaces(onelineResult);
1298
1495
  cleanedResult = cleanedResult.replace(/\(\s+/g, '(').replace(/\s+\)/g, ' )');
1299
- this.linePrinter.appendText(cleanedResult.trim());
1496
+ const trimmedResult = cleanedResult.trim();
1497
+ if (!this.fitsOneLineMaxLength(trimmedResult)) {
1498
+ return false;
1499
+ }
1500
+ this.linePrinter.appendText(trimmedResult);
1501
+ return true;
1300
1502
  }
1301
1503
  /**
1302
1504
  * Creates a SqlPrinter instance configured for CTE oneline formatting.
@@ -1322,11 +1524,31 @@ export class SqlPrinter {
1322
1524
  * Handles tokens with oneline formatting (parentheses, BETWEEN, VALUES, JOIN, CASE, subqueries).
1323
1525
  * Creates a unified oneline printer that formats everything as one line regardless of content type.
1324
1526
  */
1325
- handleOnelineToken(token, level) {
1527
+ tryHandleOnelineToken(token, level) {
1326
1528
  const onelinePrinter = this.createOnelinePrinter();
1327
1529
  const onelineResult = onelinePrinter.print(token, level);
1328
1530
  const cleanedResult = this.cleanDuplicateSpaces(onelineResult);
1531
+ if (!this.fitsOneLineMaxLength(cleanedResult)) {
1532
+ if (this.isBooleanParenExpression(token)) {
1533
+ this.expandedOneLineFallbackTokens.add(token);
1534
+ }
1535
+ return false;
1536
+ }
1329
1537
  this.linePrinter.appendText(cleanedResult);
1538
+ return true;
1539
+ }
1540
+ isBooleanParenExpression(token) {
1541
+ if (token.containerType !== SqlPrintTokenContainerType.ParenExpression) {
1542
+ return false;
1543
+ }
1544
+ return this.containsLogicalOperator(token);
1545
+ }
1546
+ containsLogicalOperator(token) {
1547
+ if ((token.type === SqlPrintTokenType.operator || token.type === SqlPrintTokenType.keyword) &&
1548
+ ['and', 'or'].includes(token.text.toLowerCase())) {
1549
+ return true;
1550
+ }
1551
+ return token.innerTokens.some((child) => this.containsLogicalOperator(child));
1330
1552
  }
1331
1553
  getClauseBreakIndentLevel(parentType, level) {
1332
1554
  if (!parentType) {