rawsql-ts 0.24.1 → 0.24.2

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.
@@ -1,5 +1,5 @@
1
1
  import { CastStyle, ConstraintStyle, SourceAliasStyle, OrderByDefaultDirectionStyle } from '../parsers/SqlPrintTokenParser';
2
- import { CommaBreakStyle, AndBreakStyle, OrBreakStyle } from './SqlPrinter';
2
+ import { CommaBreakStyle, AndBreakStyle, OrBreakStyle, JoinOnBreakStyle } from './SqlPrinter';
3
3
  import { CommentExportMode } from '../types/Formatting';
4
4
  import { IndentCharOption, NewlineOption } from './LinePrinter';
5
5
  import { IdentifierEscapeOption, IdentifierEscapeTarget } from './FormatOptionResolver';
@@ -49,6 +49,8 @@ export interface BaseFormattingOptions {
49
49
  andBreak?: AndBreakStyle;
50
50
  /** Style for OR line breaks */
51
51
  orBreak?: OrBreakStyle;
52
+ /** Style for JOIN ON line breaks */
53
+ joinOnBreak?: JoinOnBreakStyle;
52
54
  /** Whether to export comments in formatted output */
53
55
  exportComment?: boolean | CommentExportMode;
54
56
  /** Comment formatting style */
@@ -73,6 +75,10 @@ export interface BaseFormattingOptions {
73
75
  insertColumnsOneLine?: boolean;
74
76
  /** Keep MERGE WHEN clause predicates on one line regardless of AND break settings */
75
77
  whenOneLine?: boolean;
78
+ /** Maximum rendered width for opt-in one-line constructs. Omit to keep legacy unlimited one-line behavior. */
79
+ oneLineMaxLength?: number;
80
+ /** Indent AND/OR continuation lines inside JOIN ON predicates */
81
+ joinConditionContinuationIndent?: boolean;
76
82
  /** Reorder JOIN ON column comparisons to follow table declaration order */
77
83
  joinConditionOrderByDeclaration?: boolean;
78
84
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SqlFormatter.js","sourceRoot":"","sources":["../../../src/transformers/SqlFormatter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SqlFormatter.js","sourceRoot":"","sources":["../../../src/transformers/SqlFormatter.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,12 @@ export type AndBreakStyle = 'none' | 'before' | 'after';
24
24
  * - 'after': Line break after OR
25
25
  */
26
26
  export type OrBreakStyle = 'none' | 'before' | 'after';
27
+ /**
28
+ * JoinOnBreakStyle determines whether JOIN ON starts on the JOIN line or its own indented line.
29
+ * - 'none': Keep ON inline with the JOIN target
30
+ * - 'before': Break before ON and indent the join condition
31
+ */
32
+ export type JoinOnBreakStyle = 'none' | 'before';
27
33
  /**
28
34
  * Options for configuring SqlPrinter formatting behavior
29
35
  */
@@ -68,6 +74,8 @@ export declare class SqlPrinter {
68
74
  andBreak: AndBreakStyle;
69
75
  /** OR break style: 'none', 'before', or 'after' */
70
76
  orBreak: OrBreakStyle;
77
+ /** JOIN ON break style: 'none' or 'before' */
78
+ joinOnBreak: JoinOnBreakStyle;
71
79
  /** Keyword case style: 'none', 'upper' | 'lower' */
72
80
  keywordCase: 'none' | 'upper' | 'lower';
73
81
  /** Comment export mode controlling how comments are emitted */
@@ -98,10 +106,18 @@ export declare class SqlPrinter {
98
106
  private insertColumnsOneLine;
99
107
  /** Whether to keep MERGE WHEN predicates on a single line */
100
108
  private whenOneLine;
109
+ /** Optional maximum width for opt-in one-line constructs */
110
+ private oneLineMaxLength?;
111
+ /** Whether to indent AND/OR continuation lines inside JOIN ON predicates */
112
+ private joinConditionContinuationIndent;
101
113
  /** Tracks nesting depth while formatting MERGE WHEN predicate segments */
102
114
  private mergeWhenPredicateDepth;
115
+ /** Tracks nesting depth while formatting JOIN ON condition segments */
116
+ private joinOnClauseDepth;
103
117
  /** Shared helper for oneline-specific formatting decisions */
104
118
  private onelineHelper;
119
+ /** Containers whose one-line rendering was rejected by oneLineMaxLength */
120
+ private expandedOneLineFallbackTokens;
105
121
  /** Pending line comment that needs a forced newline before next token */
106
122
  private pendingLineCommentBreak;
107
123
  /** Accumulates lines when reconstructing multi-line block comments inside CommentBlocks */
@@ -144,6 +160,7 @@ export declare class SqlPrinter {
144
160
  private handleAndOperatorToken;
145
161
  private handleParenthesisToken;
146
162
  private handleOrOperatorToken;
163
+ private getJoinConditionContinuationLevel;
147
164
  /**
148
165
  * Decide whether a parentheses group should increase indentation when inside nested structures.
149
166
  * We only expand groups that contain further parentheses so simple comparisons stay compact.
@@ -209,11 +226,13 @@ export declare class SqlPrinter {
209
226
  * Oneliner mode uses single spaces instead of actual newlines.
210
227
  */
211
228
  private isOnelineMode;
229
+ private normalizeOneLineMaxLength;
230
+ private fitsOneLineMaxLength;
212
231
  /**
213
232
  * Handles CTE tokens with one-liner formatting.
214
233
  * Creates a nested SqlPrinter instance for proper CTE oneline formatting.
215
234
  */
216
- private handleCteOnelineToken;
235
+ private tryHandleCteOnelineToken;
217
236
  /**
218
237
  * Creates a SqlPrinter instance configured for CTE oneline formatting.
219
238
  */
@@ -222,7 +241,9 @@ export declare class SqlPrinter {
222
241
  * Handles tokens with oneline formatting (parentheses, BETWEEN, VALUES, JOIN, CASE, subqueries).
223
242
  * Creates a unified oneline printer that formats everything as one line regardless of content type.
224
243
  */
225
- private handleOnelineToken;
244
+ private tryHandleOnelineToken;
245
+ private isBooleanParenExpression;
246
+ private containsLogicalOperator;
226
247
  private getClauseBreakIndentLevel;
227
248
  private isMergeActionContainer;
228
249
  private shouldBreakAfterOpeningParen;
@@ -30,11 +30,15 @@ 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 */
@@ -52,19 +56,22 @@ export class SqlPrinter {
52
56
  this.valuesCommaBreak = (_d = options === null || options === void 0 ? void 0 : options.valuesCommaBreak) !== null && _d !== void 0 ? _d : this.commaBreak;
53
57
  this.andBreak = (_e = options === null || options === void 0 ? void 0 : options.andBreak) !== null && _e !== void 0 ? _e : 'none';
54
58
  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';
59
+ this.joinOnBreak = (_g = options === null || options === void 0 ? void 0 : options.joinOnBreak) !== null && _g !== void 0 ? _g : 'none';
60
+ this.keywordCase = (_h = options === null || options === void 0 ? void 0 : options.keywordCase) !== null && _h !== void 0 ? _h : 'none';
56
61
  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;
62
+ this.withClauseStyle = (_j = options === null || options === void 0 ? void 0 : options.withClauseStyle) !== null && _j !== void 0 ? _j : 'standard';
63
+ this.commentStyle = (_k = options === null || options === void 0 ? void 0 : options.commentStyle) !== null && _k !== void 0 ? _k : 'block';
64
+ this.parenthesesOneLine = (_l = options === null || options === void 0 ? void 0 : options.parenthesesOneLine) !== null && _l !== void 0 ? _l : false;
65
+ this.betweenOneLine = (_m = options === null || options === void 0 ? void 0 : options.betweenOneLine) !== null && _m !== void 0 ? _m : false;
66
+ this.valuesOneLine = (_o = options === null || options === void 0 ? void 0 : options.valuesOneLine) !== null && _o !== void 0 ? _o : false;
67
+ this.joinOneLine = (_p = options === null || options === void 0 ? void 0 : options.joinOneLine) !== null && _p !== void 0 ? _p : false;
68
+ this.caseOneLine = (_q = options === null || options === void 0 ? void 0 : options.caseOneLine) !== null && _q !== void 0 ? _q : false;
69
+ this.subqueryOneLine = (_r = options === null || options === void 0 ? void 0 : options.subqueryOneLine) !== null && _r !== void 0 ? _r : false;
70
+ this.indentNestedParentheses = (_s = options === null || options === void 0 ? void 0 : options.indentNestedParentheses) !== null && _s !== void 0 ? _s : false;
71
+ this.insertColumnsOneLine = (_t = options === null || options === void 0 ? void 0 : options.insertColumnsOneLine) !== null && _t !== void 0 ? _t : false;
72
+ this.whenOneLine = (_u = options === null || options === void 0 ? void 0 : options.whenOneLine) !== null && _u !== void 0 ? _u : false;
73
+ this.oneLineMaxLength = this.normalizeOneLineMaxLength(options === null || options === void 0 ? void 0 : options.oneLineMaxLength);
74
+ this.joinConditionContinuationIndent = (_v = options === null || options === void 0 ? void 0 : options.joinConditionContinuationIndent) !== null && _v !== void 0 ? _v : false;
68
75
  const onelineOptions = {
69
76
  parenthesesOneLine: this.parenthesesOneLine,
70
77
  betweenOneLine: this.betweenOneLine,
@@ -78,7 +85,7 @@ export class SqlPrinter {
78
85
  this.onelineHelper = new OnelineFormattingHelper(onelineOptions);
79
86
  this.linePrinter = new LinePrinter(this.indentChar, this.indentSize, this.newline, this.commaBreak);
80
87
  // Initialize
81
- this.indentIncrementContainers = new Set((_u = options === null || options === void 0 ? void 0 : options.indentIncrementContainerTypes) !== null && _u !== void 0 ? _u : [
88
+ this.indentIncrementContainers = new Set((_w = options === null || options === void 0 ? void 0 : options.indentIncrementContainerTypes) !== null && _w !== void 0 ? _w : [
82
89
  SqlPrintTokenContainerType.SelectClause,
83
90
  SqlPrintTokenContainerType.ReturningClause,
84
91
  SqlPrintTokenContainerType.FromClause,
@@ -124,8 +131,10 @@ export class SqlPrinter {
124
131
  // initialize
125
132
  this.linePrinter = new LinePrinter(this.indentChar, this.indentSize, this.newline, this.commaBreak);
126
133
  this.insideWithClause = false; // Reset WITH clause context
134
+ this.joinOnClauseDepth = 0;
127
135
  this.pendingLineCommentBreak = null;
128
136
  this.smartCommentBlockBuilder = null;
137
+ this.expandedOneLineFallbackTokens = new WeakSet();
129
138
  if (this.linePrinter.lines.length > 0 && level !== this.linePrinter.lines[0].level) {
130
139
  this.linePrinter.lines[0].level = level;
131
140
  }
@@ -244,7 +253,7 @@ export class SqlPrinter {
244
253
  const current = this.linePrinter.getCurrentLine();
245
254
  const isCaseContext = this.isCaseContext(token.containerType);
246
255
  const nextCaseContextDepth = isCaseContext ? caseContextDepth + 1 : caseContextDepth;
247
- const shouldIndentNested = this.shouldIndentNestedParentheses(token, previousSiblingWasOpenParen);
256
+ let shouldIndentNested = this.shouldIndentNestedParentheses(token, previousSiblingWasOpenParen);
248
257
  // Handle different token types
249
258
  if (token.type === SqlPrintTokenType.keyword) {
250
259
  this.handleKeywordToken(token, level, parentContainerType, caseContextDepth);
@@ -281,16 +290,25 @@ export class SqlPrinter {
281
290
  this.handleCommentNewlineToken(token, commentLevel);
282
291
  }
283
292
  else if (token.containerType === SqlPrintTokenContainerType.CommonTable && this.withClauseStyle === 'cte-oneline') {
284
- this.handleCteOnelineToken(token, level);
285
- return; // Return early to avoid processing innerTokens
293
+ if (this.tryHandleCteOnelineToken(token, level)) {
294
+ return; // Return early to avoid processing innerTokens
295
+ }
286
296
  }
287
- else if (this.shouldFormatContainerAsOneline(token, shouldIndentNested)) {
288
- this.handleOnelineToken(token, level);
297
+ else if (this.shouldFormatContainerAsOneline(token, shouldIndentNested) && this.tryHandleOnelineToken(token, level)) {
289
298
  return; // Return early to avoid processing innerTokens
290
299
  }
291
300
  else if (!this.tryAppendInsertClauseTokenText(token.text, parentContainerType)) {
292
301
  this.linePrinter.appendText(token.text);
293
302
  }
303
+ if (token.containerType === SqlPrintTokenContainerType.JoinOnClause &&
304
+ this.joinOnBreak === 'before' &&
305
+ !this.isOnelineMode() &&
306
+ this.linePrinter.getCurrentLine().text.trim().length > 0) {
307
+ this.linePrinter.appendNewline(level + 1);
308
+ }
309
+ if (this.expandedOneLineFallbackTokens.has(token)) {
310
+ shouldIndentNested = true;
311
+ }
294
312
  // append keyword tokens(not indented)
295
313
  if (token.keywordTokens && token.keywordTokens.length > 0) {
296
314
  for (let i = 0; i < token.keywordTokens.length; i++) {
@@ -304,6 +322,9 @@ export class SqlPrinter {
304
322
  const delayIndentNewline = shouldIndentNested && token.containerType === SqlPrintTokenContainerType.ParenExpression;
305
323
  const isAlterTableStatement = token.containerType === SqlPrintTokenContainerType.AlterTableStatement;
306
324
  let deferAlterTableIndent = false;
325
+ if (token.containerType === SqlPrintTokenContainerType.JoinOnClause && this.joinOnBreak === 'before' && !this.isOnelineMode()) {
326
+ innerLevel = level + 1;
327
+ }
307
328
  const alignExplainChild = this.shouldAlignExplainStatementChild(parentContainerType, token.containerType);
308
329
  if (alignExplainChild) {
309
330
  // Keep EXPLAIN target statements flush left so they render like standalone statements.
@@ -356,6 +377,10 @@ export class SqlPrinter {
356
377
  let mergePredicateActive = isMergeWhenClause;
357
378
  let alterTableTableRendered = false;
358
379
  let alterTableIndentInserted = false;
380
+ const enteredJoinOnClause = token.containerType === SqlPrintTokenContainerType.JoinOnClause;
381
+ if (enteredJoinOnClause) {
382
+ this.joinOnClauseDepth++;
383
+ }
359
384
  for (let i = leadingCommentCount; i < token.innerTokens.length; i++) {
360
385
  const child = token.innerTokens[i];
361
386
  const nextChild = token.innerTokens[i + 1];
@@ -417,6 +442,9 @@ export class SqlPrinter {
417
442
  if (this.smartCommentBlockBuilder && this.smartCommentBlockBuilder.mode === 'line') {
418
443
  this.flushSmartCommentBlockBuilder();
419
444
  }
445
+ if (enteredJoinOnClause) {
446
+ this.joinOnClauseDepth--;
447
+ }
420
448
  // Exit WITH clause context when we finish processing WithClause container
421
449
  if (token.containerType === SqlPrintTokenContainerType.WithClause && this.withClauseStyle === 'full-oneline') {
422
450
  this.insideWithClause = false;
@@ -617,7 +645,7 @@ export class SqlPrinter {
617
645
  if (this.andBreak === 'before') {
618
646
  // Skip newline when inside WITH clause with full-oneline style
619
647
  if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
620
- this.linePrinter.appendNewline(level);
648
+ this.linePrinter.appendNewline(this.getJoinConditionContinuationLevel(level));
621
649
  }
622
650
  this.linePrinter.appendText(text);
623
651
  }
@@ -625,7 +653,7 @@ export class SqlPrinter {
625
653
  this.linePrinter.appendText(text);
626
654
  // Skip newline when inside WITH clause with full-oneline style
627
655
  if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
628
- this.linePrinter.appendNewline(level);
656
+ this.linePrinter.appendNewline(this.getJoinConditionContinuationLevel(level));
629
657
  }
630
658
  }
631
659
  else {
@@ -644,7 +672,9 @@ export class SqlPrinter {
644
672
  if (this.shouldBreakAfterOpeningParen(parentContainerType)) {
645
673
  this.linePrinter.appendNewline(level + 1);
646
674
  }
647
- else if (indentParentActive && !(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
675
+ else if (indentParentActive &&
676
+ parentContainerType === SqlPrintTokenContainerType.ParenExpression &&
677
+ !(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
648
678
  this.linePrinter.appendNewline(level);
649
679
  }
650
680
  }
@@ -656,7 +686,9 @@ export class SqlPrinter {
656
686
  this.linePrinter.appendText(token.text);
657
687
  return;
658
688
  }
659
- if (indentParentActive && !(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
689
+ if (indentParentActive &&
690
+ parentContainerType === SqlPrintTokenContainerType.ParenExpression &&
691
+ !(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
660
692
  const closingLevel = Math.max(level - 1, 0);
661
693
  this.linePrinter.appendNewline(closingLevel);
662
694
  }
@@ -678,7 +710,7 @@ export class SqlPrinter {
678
710
  if (this.orBreak === 'before') {
679
711
  // Insert a newline before OR unless WITH full-oneline mode suppresses breaks.
680
712
  if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
681
- this.linePrinter.appendNewline(level);
713
+ this.linePrinter.appendNewline(this.getJoinConditionContinuationLevel(level));
682
714
  }
683
715
  this.linePrinter.appendText(text);
684
716
  }
@@ -686,13 +718,22 @@ export class SqlPrinter {
686
718
  this.linePrinter.appendText(text);
687
719
  // Break after OR when multi-line formatting is active.
688
720
  if (!(this.insideWithClause && this.withClauseStyle === 'full-oneline')) {
689
- this.linePrinter.appendNewline(level);
721
+ this.linePrinter.appendNewline(this.getJoinConditionContinuationLevel(level));
690
722
  }
691
723
  }
692
724
  else {
693
725
  this.linePrinter.appendText(text);
694
726
  }
695
727
  }
728
+ getJoinConditionContinuationLevel(level) {
729
+ if (this.joinOnClauseDepth === 0) {
730
+ return level;
731
+ }
732
+ if (this.joinOnBreak === 'before') {
733
+ return level;
734
+ }
735
+ return this.joinConditionContinuationIndent ? level + 1 : level;
736
+ }
696
737
  /**
697
738
  * Decide whether a parentheses group should increase indentation when inside nested structures.
698
739
  * We only expand groups that contain further parentheses so simple comparisons stay compact.
@@ -704,6 +745,9 @@ export class SqlPrinter {
704
745
  if (token.containerType !== SqlPrintTokenContainerType.ParenExpression) {
705
746
  return false;
706
747
  }
748
+ if (this.expandedOneLineFallbackTokens.has(token)) {
749
+ return true;
750
+ }
707
751
  // Look for nested parentheses containers. If present, indent to highlight grouping.
708
752
  return previousSiblingWasOpenParen || token.innerTokens.some((child) => this.containsParenExpression(child));
709
753
  }
@@ -1287,16 +1331,36 @@ export class SqlPrinter {
1287
1331
  isOnelineMode() {
1288
1332
  return this.newline === ' ';
1289
1333
  }
1334
+ normalizeOneLineMaxLength(value) {
1335
+ if (value === undefined || !Number.isFinite(value) || value <= 0) {
1336
+ return undefined;
1337
+ }
1338
+ const normalized = Math.floor(value);
1339
+ return normalized > 0 ? normalized : undefined;
1340
+ }
1341
+ fitsOneLineMaxLength(text) {
1342
+ if (this.oneLineMaxLength === undefined) {
1343
+ return true;
1344
+ }
1345
+ const currentLine = this.linePrinter.getCurrentLine();
1346
+ const indentWidth = currentLine.level * this.indentSize * String(this.indentChar).length;
1347
+ return indentWidth + currentLine.text.length + text.length <= this.oneLineMaxLength;
1348
+ }
1290
1349
  /**
1291
1350
  * Handles CTE tokens with one-liner formatting.
1292
1351
  * Creates a nested SqlPrinter instance for proper CTE oneline formatting.
1293
1352
  */
1294
- handleCteOnelineToken(token, level) {
1353
+ tryHandleCteOnelineToken(token, level) {
1295
1354
  const onelinePrinter = this.createCteOnelinePrinter();
1296
1355
  const onelineResult = onelinePrinter.print(token, level);
1297
1356
  let cleanedResult = this.cleanDuplicateSpaces(onelineResult);
1298
1357
  cleanedResult = cleanedResult.replace(/\(\s+/g, '(').replace(/\s+\)/g, ' )');
1299
- this.linePrinter.appendText(cleanedResult.trim());
1358
+ const trimmedResult = cleanedResult.trim();
1359
+ if (!this.fitsOneLineMaxLength(trimmedResult)) {
1360
+ return false;
1361
+ }
1362
+ this.linePrinter.appendText(trimmedResult);
1363
+ return true;
1300
1364
  }
1301
1365
  /**
1302
1366
  * Creates a SqlPrinter instance configured for CTE oneline formatting.
@@ -1322,11 +1386,31 @@ export class SqlPrinter {
1322
1386
  * Handles tokens with oneline formatting (parentheses, BETWEEN, VALUES, JOIN, CASE, subqueries).
1323
1387
  * Creates a unified oneline printer that formats everything as one line regardless of content type.
1324
1388
  */
1325
- handleOnelineToken(token, level) {
1389
+ tryHandleOnelineToken(token, level) {
1326
1390
  const onelinePrinter = this.createOnelinePrinter();
1327
1391
  const onelineResult = onelinePrinter.print(token, level);
1328
1392
  const cleanedResult = this.cleanDuplicateSpaces(onelineResult);
1393
+ if (!this.fitsOneLineMaxLength(cleanedResult)) {
1394
+ if (this.isBooleanParenExpression(token)) {
1395
+ this.expandedOneLineFallbackTokens.add(token);
1396
+ }
1397
+ return false;
1398
+ }
1329
1399
  this.linePrinter.appendText(cleanedResult);
1400
+ return true;
1401
+ }
1402
+ isBooleanParenExpression(token) {
1403
+ if (token.containerType !== SqlPrintTokenContainerType.ParenExpression) {
1404
+ return false;
1405
+ }
1406
+ return this.containsLogicalOperator(token);
1407
+ }
1408
+ containsLogicalOperator(token) {
1409
+ if ((token.type === SqlPrintTokenType.operator || token.type === SqlPrintTokenType.keyword) &&
1410
+ ['and', 'or'].includes(token.text.toLowerCase())) {
1411
+ return true;
1412
+ }
1413
+ return token.innerTokens.some((child) => this.containsLogicalOperator(child));
1330
1414
  }
1331
1415
  getClauseBreakIndentLevel(parentType, level) {
1332
1416
  if (!parentType) {