rawsql-ts 0.11.37-beta → 0.11.38-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.min.js +54 -51
- package/dist/esm/index.min.js.map +3 -3
- package/dist/esm/src/models/Lexeme.d.ts +8 -0
- package/dist/esm/src/models/SqlComponent.d.ts +20 -0
- package/dist/esm/src/models/SqlComponent.js +46 -0
- package/dist/esm/src/models/SqlComponent.js.map +1 -1
- package/dist/esm/src/parsers/CommandExpressionParser.d.ts +9 -0
- package/dist/esm/src/parsers/CommandExpressionParser.js +118 -14
- package/dist/esm/src/parsers/CommandExpressionParser.js.map +1 -1
- package/dist/esm/src/parsers/CommonTableParser.d.ts +8 -0
- package/dist/esm/src/parsers/CommonTableParser.js +127 -35
- package/dist/esm/src/parsers/CommonTableParser.js.map +1 -1
- package/dist/esm/src/parsers/FromClauseParser.js +2 -2
- package/dist/esm/src/parsers/FromClauseParser.js.map +1 -1
- package/dist/esm/src/parsers/FullNameParser.js +13 -1
- package/dist/esm/src/parsers/FullNameParser.js.map +1 -1
- package/dist/esm/src/parsers/FunctionExpressionParser.js +37 -3
- package/dist/esm/src/parsers/FunctionExpressionParser.js.map +1 -1
- package/dist/esm/src/parsers/JoinClauseParser.d.ts +4 -0
- package/dist/esm/src/parsers/JoinClauseParser.js +54 -20
- package/dist/esm/src/parsers/JoinClauseParser.js.map +1 -1
- package/dist/esm/src/parsers/OrderByClauseParser.js +39 -8
- package/dist/esm/src/parsers/OrderByClauseParser.js.map +1 -1
- package/dist/esm/src/parsers/ParenExpressionParser.js +1 -1
- package/dist/esm/src/parsers/ParenExpressionParser.js.map +1 -1
- package/dist/esm/src/parsers/SelectClauseParser.d.ts +10 -0
- package/dist/esm/src/parsers/SelectClauseParser.js +124 -12
- package/dist/esm/src/parsers/SelectClauseParser.js.map +1 -1
- package/dist/esm/src/parsers/SelectQueryParser.d.ts +12 -0
- package/dist/esm/src/parsers/SelectQueryParser.js +277 -115
- package/dist/esm/src/parsers/SelectQueryParser.js.map +1 -1
- package/dist/esm/src/parsers/SourceAliasExpressionParser.js +15 -4
- package/dist/esm/src/parsers/SourceAliasExpressionParser.js.map +1 -1
- package/dist/esm/src/parsers/SourceParser.js +33 -2
- package/dist/esm/src/parsers/SourceParser.js.map +1 -1
- package/dist/esm/src/parsers/SqlPrintTokenParser.d.ts +62 -0
- package/dist/esm/src/parsers/SqlPrintTokenParser.js +700 -32
- package/dist/esm/src/parsers/SqlPrintTokenParser.js.map +1 -1
- package/dist/esm/src/parsers/SqlTokenizer.d.ts +1 -4
- package/dist/esm/src/parsers/SqlTokenizer.js +108 -52
- package/dist/esm/src/parsers/SqlTokenizer.js.map +1 -1
- package/dist/esm/src/parsers/ValueParser.d.ts +4 -0
- package/dist/esm/src/parsers/ValueParser.js +119 -20
- package/dist/esm/src/parsers/ValueParser.js.map +1 -1
- package/dist/esm/src/parsers/WithClauseParser.d.ts +4 -0
- package/dist/esm/src/parsers/WithClauseParser.js +64 -35
- package/dist/esm/src/parsers/WithClauseParser.js.map +1 -1
- package/dist/esm/src/tokenReaders/CommandTokenReader.js +9 -1
- package/dist/esm/src/tokenReaders/CommandTokenReader.js.map +1 -1
- package/dist/esm/src/transformers/LinePrinter.d.ts +17 -2
- package/dist/esm/src/transformers/LinePrinter.js +39 -10
- package/dist/esm/src/transformers/LinePrinter.js.map +1 -1
- package/dist/esm/src/transformers/SqlFormatter.d.ts +10 -0
- package/dist/esm/src/transformers/SqlFormatter.js +1 -1
- package/dist/esm/src/transformers/SqlFormatter.js.map +1 -1
- package/dist/esm/src/transformers/SqlPrinter.d.ts +6 -1
- package/dist/esm/src/transformers/SqlPrinter.js +76 -31
- package/dist/esm/src/transformers/SqlPrinter.js.map +1 -1
- package/dist/esm/src/utils/CommentEditor.d.ts +12 -5
- package/dist/esm/src/utils/CommentEditor.js +67 -28
- package/dist/esm/src/utils/CommentEditor.js.map +1 -1
- package/dist/esm/src/utils/stringUtils.js +21 -9
- package/dist/esm/src/utils/stringUtils.js.map +1 -1
- package/dist/esm/tsconfig.browser.tsbuildinfo +1 -1
- package/dist/index.min.js +54 -51
- package/dist/index.min.js.map +3 -3
- package/dist/src/models/Lexeme.d.ts +8 -0
- package/dist/src/models/SqlComponent.d.ts +20 -0
- package/dist/src/models/SqlComponent.js +46 -0
- package/dist/src/models/SqlComponent.js.map +1 -1
- package/dist/src/parsers/CommandExpressionParser.d.ts +9 -0
- package/dist/src/parsers/CommandExpressionParser.js +118 -14
- package/dist/src/parsers/CommandExpressionParser.js.map +1 -1
- package/dist/src/parsers/CommonTableParser.d.ts +8 -0
- package/dist/src/parsers/CommonTableParser.js +127 -35
- package/dist/src/parsers/CommonTableParser.js.map +1 -1
- package/dist/src/parsers/FromClauseParser.js +2 -2
- package/dist/src/parsers/FromClauseParser.js.map +1 -1
- package/dist/src/parsers/FullNameParser.js +13 -1
- package/dist/src/parsers/FullNameParser.js.map +1 -1
- package/dist/src/parsers/FunctionExpressionParser.js +37 -3
- package/dist/src/parsers/FunctionExpressionParser.js.map +1 -1
- package/dist/src/parsers/JoinClauseParser.d.ts +4 -0
- package/dist/src/parsers/JoinClauseParser.js +54 -20
- package/dist/src/parsers/JoinClauseParser.js.map +1 -1
- package/dist/src/parsers/OrderByClauseParser.js +39 -8
- package/dist/src/parsers/OrderByClauseParser.js.map +1 -1
- package/dist/src/parsers/ParenExpressionParser.js +1 -1
- package/dist/src/parsers/ParenExpressionParser.js.map +1 -1
- package/dist/src/parsers/SelectClauseParser.d.ts +10 -0
- package/dist/src/parsers/SelectClauseParser.js +124 -12
- package/dist/src/parsers/SelectClauseParser.js.map +1 -1
- package/dist/src/parsers/SelectQueryParser.d.ts +12 -0
- package/dist/src/parsers/SelectQueryParser.js +280 -115
- package/dist/src/parsers/SelectQueryParser.js.map +1 -1
- package/dist/src/parsers/SourceAliasExpressionParser.js +15 -4
- package/dist/src/parsers/SourceAliasExpressionParser.js.map +1 -1
- package/dist/src/parsers/SourceParser.js +33 -2
- package/dist/src/parsers/SourceParser.js.map +1 -1
- package/dist/src/parsers/SqlPrintTokenParser.d.ts +62 -0
- package/dist/src/parsers/SqlPrintTokenParser.js +700 -32
- package/dist/src/parsers/SqlPrintTokenParser.js.map +1 -1
- package/dist/src/parsers/SqlTokenizer.d.ts +1 -4
- package/dist/src/parsers/SqlTokenizer.js +108 -52
- package/dist/src/parsers/SqlTokenizer.js.map +1 -1
- package/dist/src/parsers/ValueParser.d.ts +4 -0
- package/dist/src/parsers/ValueParser.js +119 -20
- package/dist/src/parsers/ValueParser.js.map +1 -1
- package/dist/src/parsers/WithClauseParser.d.ts +4 -0
- package/dist/src/parsers/WithClauseParser.js +64 -35
- package/dist/src/parsers/WithClauseParser.js.map +1 -1
- package/dist/src/tokenReaders/CommandTokenReader.js +9 -1
- package/dist/src/tokenReaders/CommandTokenReader.js.map +1 -1
- package/dist/src/transformers/LinePrinter.d.ts +17 -2
- package/dist/src/transformers/LinePrinter.js +39 -10
- package/dist/src/transformers/LinePrinter.js.map +1 -1
- package/dist/src/transformers/SqlFormatter.d.ts +10 -0
- package/dist/src/transformers/SqlFormatter.js +4 -1
- package/dist/src/transformers/SqlFormatter.js.map +1 -1
- package/dist/src/transformers/SqlPrinter.d.ts +6 -1
- package/dist/src/transformers/SqlPrinter.js +76 -31
- package/dist/src/transformers/SqlPrinter.js.map +1 -1
- package/dist/src/utils/CommentEditor.d.ts +12 -5
- package/dist/src/utils/CommentEditor.js +67 -28
- package/dist/src/utils/CommentEditor.js.map +1 -1
- package/dist/src/utils/stringUtils.js +21 -9
- package/dist/src/utils/stringUtils.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -121,10 +121,31 @@ exports.PRESETS = {
|
|
|
121
121
|
},
|
|
122
122
|
};
|
|
123
123
|
class SqlPrintTokenParser {
|
|
124
|
+
static getSelfHandlingComponentTypes() {
|
|
125
|
+
if (!this._selfHandlingComponentTypes) {
|
|
126
|
+
this._selfHandlingComponentTypes = new Set([
|
|
127
|
+
SelectQuery_1.SimpleSelectQuery.kind,
|
|
128
|
+
Clause_1.SelectItem.kind,
|
|
129
|
+
ValueComponent_1.CaseKeyValuePair.kind,
|
|
130
|
+
ValueComponent_1.SwitchCaseArgument.kind,
|
|
131
|
+
ValueComponent_1.ColumnReference.kind,
|
|
132
|
+
ValueComponent_1.LiteralValue.kind,
|
|
133
|
+
ValueComponent_1.ParameterExpression.kind,
|
|
134
|
+
Clause_1.TableSource.kind,
|
|
135
|
+
Clause_1.SourceAliasExpression.kind,
|
|
136
|
+
ValueComponent_1.TypeValue.kind,
|
|
137
|
+
ValueComponent_1.FunctionCall.kind,
|
|
138
|
+
ValueComponent_1.IdentifierString.kind,
|
|
139
|
+
ValueComponent_1.QualifiedName.kind
|
|
140
|
+
]);
|
|
141
|
+
}
|
|
142
|
+
return this._selfHandlingComponentTypes;
|
|
143
|
+
}
|
|
124
144
|
constructor(options) {
|
|
125
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
145
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
126
146
|
this.handlers = new Map();
|
|
127
147
|
this.index = 1;
|
|
148
|
+
this.commentStyle = 'block';
|
|
128
149
|
if (options === null || options === void 0 ? void 0 : options.preset) {
|
|
129
150
|
const preset = options.preset;
|
|
130
151
|
options = { ...preset, ...options };
|
|
@@ -138,6 +159,7 @@ class SqlPrintTokenParser {
|
|
|
138
159
|
start: (_e = (_d = options === null || options === void 0 ? void 0 : options.identifierEscape) === null || _d === void 0 ? void 0 : _d.start) !== null && _e !== void 0 ? _e : '"',
|
|
139
160
|
end: (_g = (_f = options === null || options === void 0 ? void 0 : options.identifierEscape) === null || _f === void 0 ? void 0 : _f.end) !== null && _g !== void 0 ? _g : '"'
|
|
140
161
|
});
|
|
162
|
+
this.commentStyle = (_h = options === null || options === void 0 ? void 0 : options.commentStyle) !== null && _h !== void 0 ? _h : 'block';
|
|
141
163
|
this.handlers.set(ValueComponent_1.ValueList.kind, (expr) => this.visitValueList(expr));
|
|
142
164
|
this.handlers.set(ValueComponent_1.ColumnReference.kind, (expr) => this.visitColumnReference(expr));
|
|
143
165
|
this.handlers.set(ValueComponent_1.QualifiedName.kind, (expr) => this.visitQualifiedName(expr));
|
|
@@ -221,10 +243,23 @@ class SqlPrintTokenParser {
|
|
|
221
243
|
*/
|
|
222
244
|
visitBinarySelectQuery(arg) {
|
|
223
245
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '');
|
|
224
|
-
//
|
|
225
|
-
if (arg.
|
|
226
|
-
|
|
227
|
-
|
|
246
|
+
// Handle positioned comments for BinarySelectQuery (unified spec)
|
|
247
|
+
if (arg.positionedComments && arg.positionedComments.length > 0) {
|
|
248
|
+
this.addPositionedCommentsToToken(token, arg);
|
|
249
|
+
// Clear positioned comments to prevent duplicate processing
|
|
250
|
+
arg.positionedComments = null;
|
|
251
|
+
}
|
|
252
|
+
else if (arg.headerComments && arg.headerComments.length > 0) {
|
|
253
|
+
// Fallback to legacy headerComments if no positioned comments
|
|
254
|
+
// For smart comment style, treat headerComments as a single multi-line block
|
|
255
|
+
if (this.commentStyle === 'smart' && arg.headerComments.length > 1) {
|
|
256
|
+
const mergedHeaderComment = this.createHeaderMultiLineCommentBlock(arg.headerComments);
|
|
257
|
+
token.innerTokens.push(mergedHeaderComment);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
const headerCommentBlocks = this.createCommentBlocks(arg.headerComments);
|
|
261
|
+
token.innerTokens.push(...headerCommentBlocks);
|
|
262
|
+
}
|
|
228
263
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
229
264
|
}
|
|
230
265
|
token.innerTokens.push(this.visit(arg.left));
|
|
@@ -252,7 +287,25 @@ class SqlPrintTokenParser {
|
|
|
252
287
|
token.innerTokens.push(SqlPrintTokenParser.DOT_TOKEN);
|
|
253
288
|
}
|
|
254
289
|
}
|
|
255
|
-
|
|
290
|
+
// Handle name and its comments carefully
|
|
291
|
+
// We need to prevent double processing by temporarily clearing the name's comments,
|
|
292
|
+
// then process them at the QualifiedName level
|
|
293
|
+
const originalNameComments = arg.name.positionedComments;
|
|
294
|
+
const originalNameLegacyComments = arg.name.comments;
|
|
295
|
+
// Temporarily clear name's comments to prevent double processing
|
|
296
|
+
arg.name.positionedComments = null;
|
|
297
|
+
arg.name.comments = null;
|
|
298
|
+
const nameToken = arg.name.accept(this);
|
|
299
|
+
token.innerTokens.push(nameToken);
|
|
300
|
+
// Restore original comments
|
|
301
|
+
arg.name.positionedComments = originalNameComments;
|
|
302
|
+
arg.name.comments = originalNameLegacyComments;
|
|
303
|
+
// Apply the name's comments to the qualified name token
|
|
304
|
+
if (this.hasPositionedComments(arg.name) || this.hasLegacyComments(arg.name)) {
|
|
305
|
+
this.addComponentComments(token, arg.name);
|
|
306
|
+
}
|
|
307
|
+
// Also handle any comments directly on the QualifiedName itself
|
|
308
|
+
this.addComponentComments(token, arg);
|
|
256
309
|
return token;
|
|
257
310
|
}
|
|
258
311
|
visitPartitionByClause(arg) {
|
|
@@ -331,49 +384,312 @@ class SqlPrintTokenParser {
|
|
|
331
384
|
// Fallback (just in case)
|
|
332
385
|
return { token, params: [] };
|
|
333
386
|
}
|
|
387
|
+
/**
|
|
388
|
+
* Check if a component handles its own comments
|
|
389
|
+
*/
|
|
390
|
+
componentHandlesOwnComments(component) {
|
|
391
|
+
// First check if component has a handlesOwnComments method
|
|
392
|
+
if ('handlesOwnComments' in component && typeof component.handlesOwnComments === 'function') {
|
|
393
|
+
return component.handlesOwnComments();
|
|
394
|
+
}
|
|
395
|
+
return SqlPrintTokenParser.getSelfHandlingComponentTypes().has(component.getKind());
|
|
396
|
+
}
|
|
334
397
|
visit(arg) {
|
|
335
398
|
const handler = this.handlers.get(arg.getKind());
|
|
336
399
|
if (handler) {
|
|
337
400
|
const token = handler(arg);
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
? arg.handlesOwnComments()
|
|
341
|
-
: arg.getKind() === SelectQuery_1.SimpleSelectQuery.kind; // Fallback for existing SimpleSelectQuery
|
|
342
|
-
if (!handlesOwnComments) {
|
|
343
|
-
this.addCommentsToToken(token, arg.comments);
|
|
401
|
+
if (!this.componentHandlesOwnComments(arg)) {
|
|
402
|
+
this.addComponentComments(token, arg);
|
|
344
403
|
}
|
|
345
404
|
return token;
|
|
346
405
|
}
|
|
347
406
|
throw new Error(`[SqlPrintTokenParser] No handler for kind: ${arg.getKind().toString()}`);
|
|
348
407
|
}
|
|
408
|
+
/**
|
|
409
|
+
* Check if a component has positioned comments
|
|
410
|
+
*/
|
|
411
|
+
hasPositionedComments(component) {
|
|
412
|
+
var _a, _b;
|
|
413
|
+
return ((_b = (_a = component.positionedComments) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Check if a component has legacy comments
|
|
417
|
+
*/
|
|
418
|
+
hasLegacyComments(component) {
|
|
419
|
+
var _a, _b;
|
|
420
|
+
return ((_b = (_a = component.comments) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Centralized comment handling - checks positioned comments first, falls back to legacy
|
|
424
|
+
*/
|
|
425
|
+
addComponentComments(token, component) {
|
|
426
|
+
if (this.hasPositionedComments(component)) {
|
|
427
|
+
this.addPositionedCommentsToToken(token, component);
|
|
428
|
+
}
|
|
429
|
+
else if (this.hasLegacyComments(component)) {
|
|
430
|
+
this.addCommentsToToken(token, component.comments);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Adds positioned comment tokens to a SqlPrintToken for inline formatting
|
|
435
|
+
*/
|
|
436
|
+
addPositionedCommentsToToken(token, component) {
|
|
437
|
+
if (!this.hasPositionedComments(component)) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
// Handle 'before' comments - add inline at the beginning with spaces
|
|
441
|
+
const beforeComments = component.getPositionedComments('before');
|
|
442
|
+
if (beforeComments.length > 0) {
|
|
443
|
+
const commentBlocks = this.createCommentBlocks(beforeComments);
|
|
444
|
+
// Create a single inline sequence: /* comment */ content
|
|
445
|
+
const beforeTokens = [];
|
|
446
|
+
for (const commentBlock of commentBlocks) {
|
|
447
|
+
beforeTokens.push(commentBlock);
|
|
448
|
+
beforeTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.space, ' '));
|
|
449
|
+
}
|
|
450
|
+
// Insert before the existing content
|
|
451
|
+
token.innerTokens.unshift(...beforeTokens);
|
|
452
|
+
}
|
|
453
|
+
// Handle 'after' comments - add inline after the main content
|
|
454
|
+
const afterComments = component.getPositionedComments('after');
|
|
455
|
+
if (afterComments.length > 0) {
|
|
456
|
+
const commentBlocks = this.createCommentBlocks(afterComments);
|
|
457
|
+
// Append after comments with spaces for inline formatting
|
|
458
|
+
for (const commentBlock of commentBlocks) {
|
|
459
|
+
token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.space, ' '));
|
|
460
|
+
token.innerTokens.push(commentBlock);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
// Clear positioned comments to prevent duplicate processing (unified spec)
|
|
464
|
+
// Only clear for specific component types that are known to have duplication issues
|
|
465
|
+
const componentsWithDuplicationIssues = [
|
|
466
|
+
SqlPrintToken_1.SqlPrintTokenContainerType.CaseExpression,
|
|
467
|
+
SqlPrintToken_1.SqlPrintTokenContainerType.SwitchCaseArgument,
|
|
468
|
+
SqlPrintToken_1.SqlPrintTokenContainerType.CaseKeyValuePair,
|
|
469
|
+
SqlPrintToken_1.SqlPrintTokenContainerType.SelectClause, // SELECT clauses have manual + automatic processing
|
|
470
|
+
SqlPrintToken_1.SqlPrintTokenContainerType.LiteralValue,
|
|
471
|
+
SqlPrintToken_1.SqlPrintTokenContainerType.IdentifierString,
|
|
472
|
+
SqlPrintToken_1.SqlPrintTokenContainerType.DistinctOn,
|
|
473
|
+
SqlPrintToken_1.SqlPrintTokenContainerType.SourceAliasExpression,
|
|
474
|
+
SqlPrintToken_1.SqlPrintTokenContainerType.SimpleSelectQuery,
|
|
475
|
+
SqlPrintToken_1.SqlPrintTokenContainerType.WhereClause // WHERE clauses also have duplication issues
|
|
476
|
+
];
|
|
477
|
+
if (token.containerType && componentsWithDuplicationIssues.includes(token.containerType)) {
|
|
478
|
+
component.positionedComments = null;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
349
481
|
/**
|
|
350
482
|
* Adds comment tokens to a SqlPrintToken based on the comments array
|
|
351
483
|
*/
|
|
352
484
|
addCommentsToToken(token, comments) {
|
|
353
|
-
if (!comments || comments
|
|
485
|
+
if (!(comments === null || comments === void 0 ? void 0 : comments.length)) {
|
|
354
486
|
return;
|
|
355
487
|
}
|
|
356
|
-
//
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
488
|
+
// For multiple comments, create inline comment sequence instead of separate blocks
|
|
489
|
+
if (comments.length > 1) {
|
|
490
|
+
const inlineComments = this.createInlineCommentSequence(comments);
|
|
491
|
+
this.insertCommentBlocksWithSpacing(token, inlineComments);
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
// Create CommentBlock containers for single comment
|
|
495
|
+
const commentBlocks = this.createCommentBlocks(comments);
|
|
360
496
|
this.insertCommentBlocksWithSpacing(token, commentBlocks);
|
|
361
497
|
}
|
|
362
498
|
}
|
|
499
|
+
/**
|
|
500
|
+
* Creates inline comment sequence for multiple comments without newlines
|
|
501
|
+
*/
|
|
502
|
+
createInlineCommentSequence(comments) {
|
|
503
|
+
const commentTokens = [];
|
|
504
|
+
for (let i = 0; i < comments.length; i++) {
|
|
505
|
+
const comment = comments[i];
|
|
506
|
+
if (comment.trim()) {
|
|
507
|
+
// Add comment token directly
|
|
508
|
+
const commentToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.comment, this.formatBlockComment(comment));
|
|
509
|
+
commentTokens.push(commentToken);
|
|
510
|
+
// Add space between comments (except after last comment)
|
|
511
|
+
if (i < comments.length - 1) {
|
|
512
|
+
const spaceToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.space, ' ');
|
|
513
|
+
commentTokens.push(spaceToken);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return commentTokens;
|
|
518
|
+
}
|
|
363
519
|
/**
|
|
364
520
|
* Creates CommentBlock containers for the given comments.
|
|
365
521
|
* Each CommentBlock contains: Comment -> CommentNewline -> Space
|
|
366
522
|
* This structure supports both oneliner and multiline formatting modes.
|
|
367
523
|
*/
|
|
368
524
|
createCommentBlocks(comments) {
|
|
525
|
+
if (this.commentStyle === 'smart') {
|
|
526
|
+
return this.createSmartCommentBlocks(comments);
|
|
527
|
+
}
|
|
528
|
+
// Block style (default) - each comment gets its own block
|
|
369
529
|
const commentBlocks = [];
|
|
370
530
|
for (const comment of comments) {
|
|
371
|
-
|
|
531
|
+
// Accept comments that have content after trim OR are separator lines OR are empty (for structure preservation)
|
|
532
|
+
const trimmed = comment.trim();
|
|
533
|
+
const isSeparatorLine = /^[-=_+*#]+$/.test(trimmed);
|
|
534
|
+
if (trimmed || isSeparatorLine || comment === '') {
|
|
372
535
|
commentBlocks.push(this.createSingleCommentBlock(comment));
|
|
373
536
|
}
|
|
374
537
|
}
|
|
375
538
|
return commentBlocks;
|
|
376
539
|
}
|
|
540
|
+
/**
|
|
541
|
+
* Creates smart comment blocks by merging consecutive block comments into multi-line format
|
|
542
|
+
*/
|
|
543
|
+
createSmartCommentBlocks(comments) {
|
|
544
|
+
const commentBlocks = [];
|
|
545
|
+
const blockComments = [];
|
|
546
|
+
const flushBlockComments = () => {
|
|
547
|
+
if (blockComments.length > 0) {
|
|
548
|
+
if (blockComments.length === 1) {
|
|
549
|
+
// Single comment - keep as-is
|
|
550
|
+
commentBlocks.push(this.createSingleCommentBlock(blockComments[0]));
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
// Multiple consecutive comments - create multi-line block
|
|
554
|
+
commentBlocks.push(this.createMultiLineCommentBlock(blockComments));
|
|
555
|
+
}
|
|
556
|
+
blockComments.length = 0;
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
for (const comment of comments) {
|
|
560
|
+
const trimmed = comment.trim();
|
|
561
|
+
const isSeparatorLine = /^[-=_+*#]+$/.test(trimmed);
|
|
562
|
+
if (!trimmed && !isSeparatorLine && comment !== '') {
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
// Check if this is a block comment that should be merged
|
|
566
|
+
if (this.shouldMergeComment(trimmed)) {
|
|
567
|
+
blockComments.push(comment);
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
// Flush any accumulated block comments first
|
|
571
|
+
flushBlockComments();
|
|
572
|
+
// Add this comment as-is
|
|
573
|
+
commentBlocks.push(this.createSingleCommentBlock(comment));
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
// Flush any remaining block comments
|
|
577
|
+
flushBlockComments();
|
|
578
|
+
return commentBlocks;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Determines if a comment should be merged with consecutive comments
|
|
582
|
+
*/
|
|
583
|
+
shouldMergeComment(trimmed) {
|
|
584
|
+
const isSeparatorLine = /^[-=_+*#]+$/.test(trimmed);
|
|
585
|
+
// Don't merge line comments unless they are separator-only lines
|
|
586
|
+
if (!isSeparatorLine && trimmed.startsWith('--')) {
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
// Don't merge if it's already a proper multi-line block comment
|
|
590
|
+
if (trimmed.startsWith('/*') && trimmed.endsWith('*/') && trimmed.includes('\n')) {
|
|
591
|
+
return false;
|
|
592
|
+
}
|
|
593
|
+
// Merge all other content including separator lines, plain text, and single-line block comments
|
|
594
|
+
// Separator lines within comment blocks should be merged together
|
|
595
|
+
return true;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Creates a multi-line block comment structure from consecutive comments
|
|
599
|
+
* Returns a CommentBlock containing multiple comment lines for proper LinePrinter integration
|
|
600
|
+
*/
|
|
601
|
+
createMultiLineCommentBlock(comments) {
|
|
602
|
+
const lines = [];
|
|
603
|
+
for (const comment of comments) {
|
|
604
|
+
const trimmed = comment.trim();
|
|
605
|
+
// Remove existing /* */ markers if present and extract content
|
|
606
|
+
if (trimmed.startsWith('/*') && trimmed.endsWith('*/')) {
|
|
607
|
+
const content = trimmed.slice(2, -2);
|
|
608
|
+
if (content.trim()) {
|
|
609
|
+
// Sanitize the content (only remove /* and */)
|
|
610
|
+
const sanitized = content
|
|
611
|
+
.replace(/\*\//g, '*') // Remove */ sequences
|
|
612
|
+
.replace(/\/\*/g, '*'); // Remove /* sequences
|
|
613
|
+
// Split multi-line content and add each line
|
|
614
|
+
const contentLines = sanitized.split('\n').map(line => line.trim()).filter(line => line);
|
|
615
|
+
lines.push(...contentLines);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
else if (trimmed) {
|
|
619
|
+
// Sanitize plain text content
|
|
620
|
+
const sanitized = trimmed
|
|
621
|
+
.replace(/\*\//g, '*') // Remove */ sequences
|
|
622
|
+
.replace(/\/\*/g, '*'); // Remove /* sequences
|
|
623
|
+
// Split plain text content by lines
|
|
624
|
+
const contentLines = sanitized.split('\n').map(line => line.trim()).filter(line => line);
|
|
625
|
+
lines.push(...contentLines);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
// Create multi-line comment block structure
|
|
629
|
+
const commentBlock = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CommentBlock);
|
|
630
|
+
if (lines.length === 0) {
|
|
631
|
+
// Empty comment
|
|
632
|
+
const commentToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.comment, '/* */');
|
|
633
|
+
commentBlock.innerTokens.push(commentToken);
|
|
634
|
+
}
|
|
635
|
+
else {
|
|
636
|
+
// Opening /*
|
|
637
|
+
const openToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.comment, '/*');
|
|
638
|
+
commentBlock.innerTokens.push(openToken);
|
|
639
|
+
commentBlock.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.commentNewline, ''));
|
|
640
|
+
// Content lines (each as separate comment token)
|
|
641
|
+
for (const line of lines) {
|
|
642
|
+
const lineToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.comment, ` ${line}`);
|
|
643
|
+
commentBlock.innerTokens.push(lineToken);
|
|
644
|
+
commentBlock.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.commentNewline, ''));
|
|
645
|
+
}
|
|
646
|
+
// Closing */
|
|
647
|
+
const closeToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.comment, '*/');
|
|
648
|
+
commentBlock.innerTokens.push(closeToken);
|
|
649
|
+
}
|
|
650
|
+
// Add final newline and space for standard structure
|
|
651
|
+
commentBlock.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.commentNewline, ''));
|
|
652
|
+
commentBlock.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.space, ' '));
|
|
653
|
+
return commentBlock;
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Creates a multi-line comment block specifically for headerComments
|
|
657
|
+
* headerComments come as pre-split lines, so we handle them differently
|
|
658
|
+
*/
|
|
659
|
+
createHeaderMultiLineCommentBlock(headerComments) {
|
|
660
|
+
// Keep all lines including empty ones to preserve structure
|
|
661
|
+
const lines = headerComments;
|
|
662
|
+
// Create multi-line comment block structure
|
|
663
|
+
const commentBlock = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CommentBlock);
|
|
664
|
+
if (lines.length === 0) {
|
|
665
|
+
// Empty comment
|
|
666
|
+
const commentToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.comment, '/* */');
|
|
667
|
+
commentBlock.innerTokens.push(commentToken);
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
// Opening /*
|
|
671
|
+
const openToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.comment, '/*');
|
|
672
|
+
commentBlock.innerTokens.push(openToken);
|
|
673
|
+
commentBlock.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.commentNewline, ''));
|
|
674
|
+
// Content lines (each as separate comment token)
|
|
675
|
+
for (const line of lines) {
|
|
676
|
+
// Sanitize the line content
|
|
677
|
+
const sanitized = line
|
|
678
|
+
.replace(/\*\//g, '*') // Remove */ sequences
|
|
679
|
+
.replace(/\/\*/g, '*'); // Remove /* sequences
|
|
680
|
+
const lineToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.comment, ` ${sanitized}`);
|
|
681
|
+
commentBlock.innerTokens.push(lineToken);
|
|
682
|
+
commentBlock.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.commentNewline, ''));
|
|
683
|
+
}
|
|
684
|
+
// Closing */
|
|
685
|
+
const closeToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.comment, '*/');
|
|
686
|
+
commentBlock.innerTokens.push(closeToken);
|
|
687
|
+
}
|
|
688
|
+
// Add final newline and space for standard structure
|
|
689
|
+
commentBlock.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.commentNewline, ''));
|
|
690
|
+
commentBlock.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.space, ' '));
|
|
691
|
+
return commentBlock;
|
|
692
|
+
}
|
|
377
693
|
/**
|
|
378
694
|
* Creates a single CommentBlock with the standard structure:
|
|
379
695
|
* Comment -> CommentNewline -> Space
|
|
@@ -384,8 +700,8 @@ class SqlPrintTokenParser {
|
|
|
384
700
|
*/
|
|
385
701
|
createSingleCommentBlock(comment) {
|
|
386
702
|
const commentBlock = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CommentBlock);
|
|
387
|
-
// Add comment token
|
|
388
|
-
const commentToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.comment, this.
|
|
703
|
+
// Add comment token - preserve original format for line comments
|
|
704
|
+
const commentToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.comment, this.formatComment(comment));
|
|
389
705
|
commentBlock.innerTokens.push(commentToken);
|
|
390
706
|
// Add conditional newline token for multiline mode
|
|
391
707
|
const commentNewlineToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.commentNewline, '');
|
|
@@ -395,6 +711,40 @@ class SqlPrintTokenParser {
|
|
|
395
711
|
commentBlock.innerTokens.push(spaceToken);
|
|
396
712
|
return commentBlock;
|
|
397
713
|
}
|
|
714
|
+
/**
|
|
715
|
+
* Formats a comment, preserving line comment format for -- comments
|
|
716
|
+
* and converting others to block format for safety
|
|
717
|
+
*/
|
|
718
|
+
formatComment(comment) {
|
|
719
|
+
const trimmed = comment.trim();
|
|
720
|
+
// Smart style processing
|
|
721
|
+
if (this.commentStyle === 'smart') {
|
|
722
|
+
return this.formatCommentSmart(trimmed);
|
|
723
|
+
}
|
|
724
|
+
// Default block style processing
|
|
725
|
+
// If it's already a line comment, preserve it
|
|
726
|
+
// But exclude separator lines (lines with only dashes, equals, etc.)
|
|
727
|
+
if (trimmed.startsWith('--') && !/^--[-=_+*#]*$/.test(trimmed)) {
|
|
728
|
+
return trimmed;
|
|
729
|
+
}
|
|
730
|
+
// If it's already a block comment, preserve it (but sanitize)
|
|
731
|
+
if (trimmed.startsWith('/*') && trimmed.endsWith('*/')) {
|
|
732
|
+
// Pass the entire comment including /* and */ for proper sanitization
|
|
733
|
+
return this.formatBlockComment(trimmed);
|
|
734
|
+
}
|
|
735
|
+
// For plain text comments, convert to block format
|
|
736
|
+
return this.formatBlockComment(trimmed);
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Formats comments using smart style rules:
|
|
740
|
+
* - Only multi-line block comment merging is supported
|
|
741
|
+
* - Single-line comments remain as block comments (no dash conversion)
|
|
742
|
+
*/
|
|
743
|
+
formatCommentSmart(comment) {
|
|
744
|
+
// Smart style only affects multi-line comment merging at createSmartCommentBlocks level
|
|
745
|
+
// Individual comment formatting remains the same as block style
|
|
746
|
+
return this.formatBlockComment(comment);
|
|
747
|
+
}
|
|
398
748
|
/**
|
|
399
749
|
* Inserts comment blocks into a token and handles spacing logic.
|
|
400
750
|
* Adds separator spaces for clause-level containers and manages duplicate space removal.
|
|
@@ -420,6 +770,18 @@ class SqlPrintTokenParser {
|
|
|
420
770
|
token.innerTokens.unshift(SqlPrintTokenParser.SPACE_TOKEN, ...commentBlocks);
|
|
421
771
|
return;
|
|
422
772
|
}
|
|
773
|
+
// Special handling for IdentifierString to add space before comment
|
|
774
|
+
if (token.containerType === SqlPrintToken_1.SqlPrintTokenContainerType.IdentifierString) {
|
|
775
|
+
// Add space before comment if not already present
|
|
776
|
+
if (token.innerTokens.length > 0) {
|
|
777
|
+
const lastToken = token.innerTokens[token.innerTokens.length - 1];
|
|
778
|
+
if (lastToken.type !== SqlPrintToken_1.SqlPrintTokenType.space) {
|
|
779
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
token.innerTokens.push(...commentBlocks);
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
423
785
|
token.innerTokens.unshift(...commentBlocks);
|
|
424
786
|
// Add a separator space after comments only for certain container types
|
|
425
787
|
// where comments need to be separated from main content
|
|
@@ -442,6 +804,38 @@ class SqlPrintTokenParser {
|
|
|
442
804
|
}
|
|
443
805
|
}
|
|
444
806
|
}
|
|
807
|
+
/**
|
|
808
|
+
* Handles positioned comments for ParenExpression with special spacing rules.
|
|
809
|
+
* ParenExpression comments should be adjacent to parentheses without separator spaces.
|
|
810
|
+
*/
|
|
811
|
+
addPositionedCommentsToParenExpression(token, component) {
|
|
812
|
+
if (!component.positionedComments) {
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
// For ParenExpression: (/* comment */ content /* comment */)
|
|
816
|
+
// Comments should be placed immediately after opening paren and before closing paren
|
|
817
|
+
// Handle 'before' comments - place after opening parenthesis without space
|
|
818
|
+
const beforeComments = component.getPositionedComments('before');
|
|
819
|
+
if (beforeComments.length > 0) {
|
|
820
|
+
const commentBlocks = this.createCommentBlocks(beforeComments);
|
|
821
|
+
// Insert after opening paren (index 1) without separator space
|
|
822
|
+
let insertIndex = 1;
|
|
823
|
+
for (const commentBlock of commentBlocks) {
|
|
824
|
+
token.innerTokens.splice(insertIndex, 0, commentBlock);
|
|
825
|
+
insertIndex++;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
// Handle 'after' comments - place before closing parenthesis without space
|
|
829
|
+
const afterComments = component.getPositionedComments('after');
|
|
830
|
+
if (afterComments.length > 0) {
|
|
831
|
+
const commentBlocks = this.createCommentBlocks(afterComments);
|
|
832
|
+
// Insert before closing paren (last position) without separator space
|
|
833
|
+
const insertIndex = token.innerTokens.length;
|
|
834
|
+
for (const commentBlock of commentBlocks) {
|
|
835
|
+
token.innerTokens.splice(insertIndex - 1, 0, commentBlock);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
445
839
|
/**
|
|
446
840
|
* Determines whether a separator space should be added after comments for the given container type.
|
|
447
841
|
*
|
|
@@ -481,11 +875,21 @@ class SqlPrintTokenParser {
|
|
|
481
875
|
* Prevents SQL injection by removing dangerous comment sequences.
|
|
482
876
|
*/
|
|
483
877
|
formatBlockComment(comment) {
|
|
484
|
-
//
|
|
485
|
-
|
|
878
|
+
// Sanitize dangerous comment sequences to prevent SQL injection
|
|
879
|
+
let sanitizedComment = comment
|
|
486
880
|
.replace(/\*\//g, '*') // Remove comment close sequences
|
|
487
|
-
.replace(/\/\*/g, '*') // Remove comment open sequences
|
|
488
|
-
|
|
881
|
+
.replace(/\/\*/g, '*'); // Remove comment open sequences
|
|
882
|
+
// Check if this is a separator line (like ----------) before processing
|
|
883
|
+
const trimmed = sanitizedComment.trim();
|
|
884
|
+
const isSeparatorLine = /^[-=_+*#]+$/.test(trimmed);
|
|
885
|
+
if (isSeparatorLine) {
|
|
886
|
+
// For separator lines, preserve as-is (already sanitized above)
|
|
887
|
+
return `/* ${trimmed} */`;
|
|
888
|
+
}
|
|
889
|
+
// For multiline comments: convert newlines to spaces (security requirement)
|
|
890
|
+
sanitizedComment = sanitizedComment
|
|
891
|
+
.replace(/\r?\n/g, ' ') // Replace newlines with spaces
|
|
892
|
+
.replace(/\s+/g, ' ') // Collapse multiple spaces into single space
|
|
489
893
|
.trim(); // Remove leading/trailing whitespace
|
|
490
894
|
// Return empty string if comment becomes empty after sanitization
|
|
491
895
|
if (!sanitizedComment) {
|
|
@@ -506,10 +910,12 @@ class SqlPrintTokenParser {
|
|
|
506
910
|
visitColumnReference(arg) {
|
|
507
911
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.ColumnReference);
|
|
508
912
|
token.innerTokens.push(arg.qualifiedName.accept(this));
|
|
913
|
+
this.addComponentComments(token, arg);
|
|
509
914
|
return token;
|
|
510
915
|
}
|
|
511
916
|
visitFunctionCall(arg) {
|
|
512
917
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.FunctionCall);
|
|
918
|
+
this.addComponentComments(token, arg);
|
|
513
919
|
token.innerTokens.push(arg.qualifiedName.accept(this));
|
|
514
920
|
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
|
|
515
921
|
if (arg.argument) {
|
|
@@ -560,7 +966,13 @@ class SqlPrintTokenParser {
|
|
|
560
966
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.BinaryExpression);
|
|
561
967
|
token.innerTokens.push(this.visit(arg.left));
|
|
562
968
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
563
|
-
|
|
969
|
+
// Visit the operator to handle its comments properly
|
|
970
|
+
const operatorToken = this.visit(arg.operator);
|
|
971
|
+
const operatorLower = operatorToken.text.toLowerCase();
|
|
972
|
+
if (operatorLower === 'and' || operatorLower === 'or') {
|
|
973
|
+
operatorToken.type = SqlPrintToken_1.SqlPrintTokenType.operator;
|
|
974
|
+
}
|
|
975
|
+
token.innerTokens.push(operatorToken);
|
|
564
976
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
565
977
|
token.innerTokens.push(this.visit(arg.right));
|
|
566
978
|
return token;
|
|
@@ -581,18 +993,30 @@ class SqlPrintTokenParser {
|
|
|
581
993
|
else {
|
|
582
994
|
text = arg.value.toString();
|
|
583
995
|
}
|
|
584
|
-
|
|
996
|
+
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.value, text, SqlPrintToken_1.SqlPrintTokenContainerType.LiteralValue);
|
|
997
|
+
// Handle positioned comments for LiteralValue
|
|
998
|
+
if (arg.positionedComments && arg.positionedComments.length > 0) {
|
|
999
|
+
this.addPositionedCommentsToToken(token, arg);
|
|
1000
|
+
// Clear positioned comments to prevent duplicate processing
|
|
1001
|
+
arg.positionedComments = null;
|
|
1002
|
+
}
|
|
1003
|
+
else if (arg.comments && arg.comments.length > 0) {
|
|
1004
|
+
this.addCommentsToToken(token, arg.comments);
|
|
1005
|
+
}
|
|
1006
|
+
return token;
|
|
585
1007
|
}
|
|
586
1008
|
visitParameterExpression(arg) {
|
|
587
1009
|
// Create a parameter token and decorate it using the parameterDecorator
|
|
588
1010
|
arg.index = this.index;
|
|
589
1011
|
const text = this.parameterDecorator.decorate(arg.name.value, arg.index);
|
|
590
1012
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.parameter, text);
|
|
1013
|
+
this.addComponentComments(token, arg);
|
|
591
1014
|
this.index++;
|
|
592
1015
|
return token;
|
|
593
1016
|
}
|
|
594
1017
|
visitSwitchCaseArgument(arg) {
|
|
595
1018
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.SwitchCaseArgument);
|
|
1019
|
+
this.addComponentComments(token, arg);
|
|
596
1020
|
// Add each WHEN/THEN clause
|
|
597
1021
|
for (const kv of arg.cases) {
|
|
598
1022
|
// Create a new line for each WHEN clause
|
|
@@ -602,14 +1026,27 @@ class SqlPrintTokenParser {
|
|
|
602
1026
|
// Add ELSE clause if present
|
|
603
1027
|
if (arg.elseValue) {
|
|
604
1028
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
605
|
-
token.innerTokens.push(this.createElseToken(arg.elseValue));
|
|
1029
|
+
token.innerTokens.push(this.createElseToken(arg.elseValue, arg.comments));
|
|
1030
|
+
}
|
|
1031
|
+
// Add SwitchCaseArgument comments (END keyword) if present and no elseValue
|
|
1032
|
+
else if (arg.comments && arg.comments.length > 0) {
|
|
1033
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1034
|
+
const commentTokens = this.createInlineCommentSequence(arg.comments);
|
|
1035
|
+
token.innerTokens.push(...commentTokens);
|
|
606
1036
|
}
|
|
607
1037
|
return token;
|
|
608
1038
|
}
|
|
609
|
-
createElseToken(elseValue) {
|
|
1039
|
+
createElseToken(elseValue, switchCaseComments) {
|
|
610
1040
|
// Creates a token for the ELSE clause in a CASE expression.
|
|
611
1041
|
const elseToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.ElseClause); // Add the ELSE keyword
|
|
612
1042
|
elseToken.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'else'));
|
|
1043
|
+
// Add ELSE and END keyword comments if present
|
|
1044
|
+
// The switchCaseComments contains both ELSE and END comments in order ['e1', 'end']
|
|
1045
|
+
if (switchCaseComments && switchCaseComments.length > 0) {
|
|
1046
|
+
elseToken.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1047
|
+
const commentTokens = this.createInlineCommentSequence(switchCaseComments);
|
|
1048
|
+
elseToken.innerTokens.push(...commentTokens);
|
|
1049
|
+
}
|
|
613
1050
|
// Create a container for the ELSE value to enable proper indentation
|
|
614
1051
|
elseToken.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
615
1052
|
const elseValueContainer = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CaseElseValue);
|
|
@@ -619,12 +1056,24 @@ class SqlPrintTokenParser {
|
|
|
619
1056
|
}
|
|
620
1057
|
visitCaseKeyValuePair(arg) {
|
|
621
1058
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CaseKeyValuePair);
|
|
1059
|
+
// Handle positioned comments for CaseKeyValuePair
|
|
1060
|
+
if (arg.positionedComments && arg.positionedComments.length > 0) {
|
|
1061
|
+
this.addPositionedCommentsToToken(token, arg);
|
|
1062
|
+
// Clear positioned comments to prevent duplicate processing
|
|
1063
|
+
arg.positionedComments = null;
|
|
1064
|
+
}
|
|
622
1065
|
// Create WHEN clause
|
|
623
1066
|
token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'when'));
|
|
624
1067
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
625
1068
|
token.innerTokens.push(this.visit(arg.key)); // Create THEN clause
|
|
626
1069
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
627
1070
|
token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'then'));
|
|
1071
|
+
// Add THEN keyword comments if present
|
|
1072
|
+
if (arg.comments && arg.comments.length > 0) {
|
|
1073
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1074
|
+
const commentTokens = this.createInlineCommentSequence(arg.comments);
|
|
1075
|
+
token.innerTokens.push(...commentTokens);
|
|
1076
|
+
}
|
|
628
1077
|
// Create a container for the THEN value to enable proper indentation
|
|
629
1078
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
630
1079
|
const thenValueContainer = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CaseThenValue);
|
|
@@ -639,14 +1088,71 @@ class SqlPrintTokenParser {
|
|
|
639
1088
|
visitIdentifierString(arg) {
|
|
640
1089
|
// Create an identifier token and decorate it using the identifierDecorator
|
|
641
1090
|
const text = arg.name === "*" ? arg.name : this.identifierDecorator.decorate(arg.name);
|
|
1091
|
+
// Handle positioned comments for IdentifierString
|
|
1092
|
+
if (arg.positionedComments && arg.positionedComments.length > 0) {
|
|
1093
|
+
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.IdentifierString);
|
|
1094
|
+
// Add positioned comments
|
|
1095
|
+
this.addPositionedCommentsToToken(token, arg);
|
|
1096
|
+
// Clear positioned comments to prevent duplicate processing
|
|
1097
|
+
arg.positionedComments = null;
|
|
1098
|
+
// Add the identifier text as the main token
|
|
1099
|
+
const valueToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.value, text);
|
|
1100
|
+
token.innerTokens.push(valueToken);
|
|
1101
|
+
return token;
|
|
1102
|
+
}
|
|
1103
|
+
// If there are legacy comments, create a container instead of a simple value token
|
|
1104
|
+
if (arg.comments && arg.comments.length > 0) {
|
|
1105
|
+
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.IdentifierString);
|
|
1106
|
+
// Add the identifier text as the main token
|
|
1107
|
+
const valueToken = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.value, text);
|
|
1108
|
+
token.innerTokens.push(valueToken);
|
|
1109
|
+
// Add legacy comments to the token
|
|
1110
|
+
this.addComponentComments(token, arg);
|
|
1111
|
+
return token;
|
|
1112
|
+
}
|
|
642
1113
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.value, text, SqlPrintToken_1.SqlPrintTokenContainerType.IdentifierString);
|
|
643
1114
|
return token;
|
|
644
1115
|
}
|
|
645
1116
|
visitParenExpression(arg) {
|
|
646
1117
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.ParenExpression);
|
|
1118
|
+
// Handle positioned comments for ParenExpression - check both self and inner expression
|
|
1119
|
+
const hasOwnComments = arg.positionedComments && arg.positionedComments.length > 0;
|
|
1120
|
+
const hasInnerComments = arg.expression.positionedComments && arg.expression.positionedComments.length > 0;
|
|
1121
|
+
// Store inner comments for later processing and clear to prevent duplicate processing
|
|
1122
|
+
let innerBeforeComments = [];
|
|
1123
|
+
let innerAfterComments = [];
|
|
1124
|
+
if (hasInnerComments) {
|
|
1125
|
+
innerBeforeComments = arg.expression.getPositionedComments('before');
|
|
1126
|
+
innerAfterComments = arg.expression.getPositionedComments('after');
|
|
1127
|
+
arg.expression.positionedComments = null;
|
|
1128
|
+
}
|
|
1129
|
+
// Build basic structure first
|
|
647
1130
|
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
|
|
648
1131
|
token.innerTokens.push(this.visit(arg.expression));
|
|
649
1132
|
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
|
|
1133
|
+
// Now add positioned comments in the correct positions manually
|
|
1134
|
+
if (innerBeforeComments.length > 0) {
|
|
1135
|
+
const commentBlocks = this.createCommentBlocks(innerBeforeComments);
|
|
1136
|
+
// Insert after opening paren (index 1) without separator space
|
|
1137
|
+
let insertIndex = 1;
|
|
1138
|
+
for (const commentBlock of commentBlocks) {
|
|
1139
|
+
token.innerTokens.splice(insertIndex, 0, commentBlock);
|
|
1140
|
+
insertIndex++;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
if (innerAfterComments.length > 0) {
|
|
1144
|
+
const commentBlocks = this.createCommentBlocks(innerAfterComments);
|
|
1145
|
+
// Insert before closing paren (last position) without separator space
|
|
1146
|
+
const insertIndex = token.innerTokens.length;
|
|
1147
|
+
for (const commentBlock of commentBlocks) {
|
|
1148
|
+
token.innerTokens.splice(insertIndex - 1, 0, commentBlock);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
if (hasOwnComments) {
|
|
1152
|
+
this.addPositionedCommentsToParenExpression(token, arg);
|
|
1153
|
+
// Clear positioned comments to prevent duplicate processing in parent containers
|
|
1154
|
+
arg.positionedComments = null;
|
|
1155
|
+
}
|
|
650
1156
|
return token;
|
|
651
1157
|
}
|
|
652
1158
|
visitCastExpression(arg) {
|
|
@@ -658,6 +1164,12 @@ class SqlPrintTokenParser {
|
|
|
658
1164
|
}
|
|
659
1165
|
visitCaseExpression(arg) {
|
|
660
1166
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CaseExpression);
|
|
1167
|
+
// Handle positioned comments for CaseExpression (unified spec: positioned comments only)
|
|
1168
|
+
if (arg.positionedComments && arg.positionedComments.length > 0) {
|
|
1169
|
+
this.addPositionedCommentsToToken(token, arg);
|
|
1170
|
+
// Clear positioned comments to prevent duplicate processing
|
|
1171
|
+
arg.positionedComments = null;
|
|
1172
|
+
}
|
|
661
1173
|
// Add the CASE keyword
|
|
662
1174
|
token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'case'));
|
|
663
1175
|
// Add the condition if exists
|
|
@@ -746,6 +1258,7 @@ class SqlPrintTokenParser {
|
|
|
746
1258
|
}
|
|
747
1259
|
visitTypeValue(arg) {
|
|
748
1260
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.TypeValue);
|
|
1261
|
+
this.addComponentComments(token, arg);
|
|
749
1262
|
token.innerTokens.push(arg.qualifiedName.accept(this));
|
|
750
1263
|
if (arg.argument) {
|
|
751
1264
|
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
|
|
@@ -839,7 +1352,32 @@ class SqlPrintTokenParser {
|
|
|
839
1352
|
}
|
|
840
1353
|
visitSelectItem(arg) {
|
|
841
1354
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.SelectItem);
|
|
1355
|
+
// Preserve original positioned comments to avoid mutating the source object
|
|
1356
|
+
const originalSelectItemPositionedComments = arg.positionedComments;
|
|
1357
|
+
const originalValuePositionedComments = arg.value.positionedComments;
|
|
1358
|
+
// Clear positioned comments from the value to avoid duplication since SelectItem handles them
|
|
1359
|
+
arg.value.positionedComments = null;
|
|
1360
|
+
// Add 'before' positioned comments
|
|
1361
|
+
const beforeComments = arg.getPositionedComments('before');
|
|
1362
|
+
if (beforeComments.length > 0) {
|
|
1363
|
+
const commentTokens = this.createInlineCommentSequence(beforeComments);
|
|
1364
|
+
token.innerTokens.push(...commentTokens);
|
|
1365
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1366
|
+
}
|
|
1367
|
+
// Add the value (column name)
|
|
842
1368
|
token.innerTokens.push(this.visit(arg.value));
|
|
1369
|
+
// Add 'after' positioned comments for the value
|
|
1370
|
+
// Skip after comments if the value is ParenExpression (already handled in ParenExpression processing)
|
|
1371
|
+
const afterComments = arg.getPositionedComments('after');
|
|
1372
|
+
const isParenExpression = arg.value.constructor.name === 'ParenExpression';
|
|
1373
|
+
if (afterComments.length > 0 && !isParenExpression) {
|
|
1374
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1375
|
+
const commentTokens = this.createInlineCommentSequence(afterComments);
|
|
1376
|
+
token.innerTokens.push(...commentTokens);
|
|
1377
|
+
}
|
|
1378
|
+
// Restore original positioned comments to avoid side effects
|
|
1379
|
+
arg.positionedComments = originalSelectItemPositionedComments;
|
|
1380
|
+
arg.value.positionedComments = originalValuePositionedComments;
|
|
843
1381
|
if (!arg.identifier) {
|
|
844
1382
|
return token;
|
|
845
1383
|
}
|
|
@@ -852,13 +1390,70 @@ class SqlPrintTokenParser {
|
|
|
852
1390
|
}
|
|
853
1391
|
// Add alias if it is different from the default name
|
|
854
1392
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1393
|
+
// Handle AS keyword positioned comments (before AS)
|
|
1394
|
+
const asKeywordPositionedComments = 'asKeywordPositionedComments' in arg ? arg.asKeywordPositionedComments : null;
|
|
1395
|
+
if (asKeywordPositionedComments) {
|
|
1396
|
+
const beforeComments = asKeywordPositionedComments.filter((pc) => pc.position === 'before');
|
|
1397
|
+
if (beforeComments.length > 0) {
|
|
1398
|
+
for (const posComment of beforeComments) {
|
|
1399
|
+
const commentTokens = this.createInlineCommentSequence(posComment.comments);
|
|
1400
|
+
token.innerTokens.push(...commentTokens);
|
|
1401
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
855
1405
|
token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'as'));
|
|
1406
|
+
// Handle AS keyword positioned comments (after AS)
|
|
1407
|
+
if (asKeywordPositionedComments) {
|
|
1408
|
+
const afterComments = asKeywordPositionedComments.filter((pc) => pc.position === 'after');
|
|
1409
|
+
if (afterComments.length > 0) {
|
|
1410
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1411
|
+
for (const posComment of afterComments) {
|
|
1412
|
+
const commentTokens = this.createInlineCommentSequence(posComment.comments);
|
|
1413
|
+
token.innerTokens.push(...commentTokens);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
// Fallback: Add AS keyword legacy comments if present
|
|
1418
|
+
const asKeywordComments = 'asKeywordComments' in arg ? arg.asKeywordComments : null;
|
|
1419
|
+
if (asKeywordComments && asKeywordComments.length > 0) {
|
|
1420
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1421
|
+
const commentTokens = this.createInlineCommentSequence(asKeywordComments);
|
|
1422
|
+
token.innerTokens.push(...commentTokens);
|
|
1423
|
+
}
|
|
856
1424
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
857
|
-
|
|
1425
|
+
// Visit identifier to get alias with proper spacing
|
|
1426
|
+
const identifierToken = this.visit(arg.identifier);
|
|
1427
|
+
token.innerTokens.push(identifierToken);
|
|
1428
|
+
// Handle alias positioned comments (after alias)
|
|
1429
|
+
const aliasPositionedComments = 'aliasPositionedComments' in arg ? arg.aliasPositionedComments : null;
|
|
1430
|
+
if (aliasPositionedComments) {
|
|
1431
|
+
const afterComments = aliasPositionedComments.filter((pc) => pc.position === 'after');
|
|
1432
|
+
if (afterComments.length > 0) {
|
|
1433
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1434
|
+
for (const posComment of afterComments) {
|
|
1435
|
+
const commentTokens = this.createInlineCommentSequence(posComment.comments);
|
|
1436
|
+
token.innerTokens.push(...commentTokens);
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
// Fallback: Add alias legacy comments if present
|
|
1441
|
+
const aliasComments = arg.aliasComments;
|
|
1442
|
+
if (aliasComments && aliasComments.length > 0) {
|
|
1443
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1444
|
+
const commentTokens = this.createInlineCommentSequence(aliasComments);
|
|
1445
|
+
token.innerTokens.push(...commentTokens);
|
|
1446
|
+
}
|
|
858
1447
|
return token;
|
|
859
1448
|
}
|
|
860
1449
|
visitSelectClause(arg) {
|
|
861
1450
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'select', SqlPrintToken_1.SqlPrintTokenContainerType.SelectClause);
|
|
1451
|
+
// Handle positioned comments for SelectClause (unified spec)
|
|
1452
|
+
if (arg.positionedComments && arg.positionedComments.length > 0) {
|
|
1453
|
+
this.addPositionedCommentsToToken(token, arg);
|
|
1454
|
+
// Clear positioned comments to prevent duplicate processing
|
|
1455
|
+
arg.positionedComments = null;
|
|
1456
|
+
}
|
|
862
1457
|
// Handle hints and DISTINCT as part of the keyword line
|
|
863
1458
|
let selectKeywordText = 'select';
|
|
864
1459
|
// Add hint clauses immediately after SELECT (before DISTINCT)
|
|
@@ -906,6 +1501,12 @@ class SqlPrintTokenParser {
|
|
|
906
1501
|
}
|
|
907
1502
|
visitDistinct(arg) {
|
|
908
1503
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'distinct');
|
|
1504
|
+
// Handle positioned comments for Distinct (unified spec)
|
|
1505
|
+
if (arg.positionedComments && arg.positionedComments.length > 0) {
|
|
1506
|
+
this.addPositionedCommentsToToken(token, arg);
|
|
1507
|
+
// Clear positioned comments to prevent duplicate processing
|
|
1508
|
+
arg.positionedComments = null;
|
|
1509
|
+
}
|
|
909
1510
|
return token;
|
|
910
1511
|
}
|
|
911
1512
|
visitDistinctOn(arg) {
|
|
@@ -924,6 +1525,7 @@ class SqlPrintTokenParser {
|
|
|
924
1525
|
}
|
|
925
1526
|
fullName += arg.table.accept(this).text;
|
|
926
1527
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.value, fullName);
|
|
1528
|
+
this.addComponentComments(token, arg);
|
|
927
1529
|
// alias (if present and different from table name)
|
|
928
1530
|
if (arg.identifier && arg.identifier.name !== arg.table.name) {
|
|
929
1531
|
}
|
|
@@ -974,8 +1576,38 @@ class SqlPrintTokenParser {
|
|
|
974
1576
|
visitJoinClause(arg) {
|
|
975
1577
|
// Print join clause: [joinType] [lateral] [source] [on/using ...]
|
|
976
1578
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.JoinClause);
|
|
1579
|
+
// Handle JOIN keyword positioned comments (before JOIN)
|
|
1580
|
+
const joinKeywordPositionedComments = arg.joinKeywordPositionedComments;
|
|
1581
|
+
if (joinKeywordPositionedComments) {
|
|
1582
|
+
const beforeComments = joinKeywordPositionedComments.filter((pc) => pc.position === 'before');
|
|
1583
|
+
if (beforeComments.length > 0) {
|
|
1584
|
+
for (const posComment of beforeComments) {
|
|
1585
|
+
const commentTokens = this.createInlineCommentSequence(posComment.comments);
|
|
1586
|
+
token.innerTokens.push(...commentTokens);
|
|
1587
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
977
1591
|
// join type (e.g. inner join, left join, etc)
|
|
978
1592
|
token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, arg.joinType.value));
|
|
1593
|
+
// Handle JOIN keyword positioned comments (after JOIN)
|
|
1594
|
+
if (joinKeywordPositionedComments) {
|
|
1595
|
+
const afterComments = joinKeywordPositionedComments.filter((pc) => pc.position === 'after');
|
|
1596
|
+
if (afterComments.length > 0) {
|
|
1597
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1598
|
+
for (const posComment of afterComments) {
|
|
1599
|
+
const commentTokens = this.createInlineCommentSequence(posComment.comments);
|
|
1600
|
+
token.innerTokens.push(...commentTokens);
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
// Fallback: Add JOIN keyword legacy comments if present
|
|
1605
|
+
const joinKeywordComments = arg.joinKeywordComments;
|
|
1606
|
+
if (joinKeywordComments && joinKeywordComments.length > 0) {
|
|
1607
|
+
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1608
|
+
const commentTokens = this.createInlineCommentSequence(joinKeywordComments);
|
|
1609
|
+
token.innerTokens.push(...commentTokens);
|
|
1610
|
+
}
|
|
979
1611
|
if (arg.lateral) {
|
|
980
1612
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
981
1613
|
token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'lateral'));
|
|
@@ -1028,10 +1660,20 @@ class SqlPrintTokenParser {
|
|
|
1028
1660
|
}
|
|
1029
1661
|
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
|
|
1030
1662
|
}
|
|
1663
|
+
// Handle positioned comments for SourceAliasExpression (alias name comments)
|
|
1664
|
+
if (arg.positionedComments && arg.positionedComments.length > 0) {
|
|
1665
|
+
this.addPositionedCommentsToToken(token, arg);
|
|
1666
|
+
// Clear positioned comments to prevent duplicate processing
|
|
1667
|
+
arg.positionedComments = null;
|
|
1668
|
+
}
|
|
1669
|
+
else if (arg.comments && arg.comments.length > 0) {
|
|
1670
|
+
this.addCommentsToToken(token, arg.comments);
|
|
1671
|
+
}
|
|
1031
1672
|
return token;
|
|
1032
1673
|
}
|
|
1033
1674
|
visitWhereClause(arg) {
|
|
1034
1675
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'where', SqlPrintToken_1.SqlPrintTokenContainerType.WhereClause);
|
|
1676
|
+
this.addComponentComments(token, arg);
|
|
1035
1677
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1036
1678
|
token.innerTokens.push(this.visit(arg.condition));
|
|
1037
1679
|
return token;
|
|
@@ -1124,10 +1766,20 @@ class SqlPrintTokenParser {
|
|
|
1124
1766
|
token.innerTokens.push(arg.tables[i].accept(this));
|
|
1125
1767
|
}
|
|
1126
1768
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1769
|
+
this.addComponentComments(token, arg);
|
|
1127
1770
|
return token;
|
|
1128
1771
|
}
|
|
1129
1772
|
visitCommonTable(arg) {
|
|
1130
1773
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CommonTable);
|
|
1774
|
+
// Handle positioned comments for CommonTable (avoid duplication)
|
|
1775
|
+
if (arg.positionedComments && arg.positionedComments.length > 0) {
|
|
1776
|
+
this.addPositionedCommentsToToken(token, arg);
|
|
1777
|
+
// Clear positioned comments to prevent duplicate processing
|
|
1778
|
+
arg.positionedComments = null;
|
|
1779
|
+
}
|
|
1780
|
+
else if (arg.comments && arg.comments.length > 0) {
|
|
1781
|
+
this.addCommentsToToken(token, arg.comments);
|
|
1782
|
+
}
|
|
1131
1783
|
token.innerTokens.push(arg.aliasExpression.accept(this));
|
|
1132
1784
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1133
1785
|
token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'as'));
|
|
@@ -1151,14 +1803,27 @@ class SqlPrintTokenParser {
|
|
|
1151
1803
|
// query
|
|
1152
1804
|
visitSimpleQuery(arg) {
|
|
1153
1805
|
const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.SimpleSelectQuery);
|
|
1154
|
-
//
|
|
1806
|
+
// Handle positioned comments for SimpleSelectQuery (unified spec)
|
|
1155
1807
|
if (arg.headerComments && arg.headerComments.length > 0) {
|
|
1156
|
-
|
|
1157
|
-
|
|
1808
|
+
// Fallback to legacy headerComments if no positioned comments
|
|
1809
|
+
// For smart comment style, treat headerComments as a single multi-line block
|
|
1810
|
+
if (this.commentStyle === 'smart' && arg.headerComments.length > 1) {
|
|
1811
|
+
const mergedHeaderComment = this.createHeaderMultiLineCommentBlock(arg.headerComments);
|
|
1812
|
+
token.innerTokens.push(mergedHeaderComment);
|
|
1813
|
+
}
|
|
1814
|
+
else {
|
|
1815
|
+
const headerCommentBlocks = this.createCommentBlocks(arg.headerComments);
|
|
1816
|
+
token.innerTokens.push(...headerCommentBlocks);
|
|
1817
|
+
}
|
|
1158
1818
|
if (arg.withClause) {
|
|
1159
1819
|
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
|
|
1160
1820
|
}
|
|
1161
1821
|
}
|
|
1822
|
+
if (arg.positionedComments && arg.positionedComments.length > 0) {
|
|
1823
|
+
this.addPositionedCommentsToToken(token, arg);
|
|
1824
|
+
// Clear positioned comments to prevent duplicate processing
|
|
1825
|
+
arg.positionedComments = null;
|
|
1826
|
+
}
|
|
1162
1827
|
if (arg.withClause) {
|
|
1163
1828
|
token.innerTokens.push(arg.withClause.accept(this));
|
|
1164
1829
|
}
|
|
@@ -1375,4 +2040,7 @@ SqlPrintTokenParser.ARGUMENT_SPLIT_COMMA_TOKEN = new SqlPrintToken_1.SqlPrintTok
|
|
|
1375
2040
|
SqlPrintTokenParser.PAREN_OPEN_TOKEN = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.parenthesis, '(');
|
|
1376
2041
|
SqlPrintTokenParser.PAREN_CLOSE_TOKEN = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.parenthesis, ')');
|
|
1377
2042
|
SqlPrintTokenParser.DOT_TOKEN = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.dot, '.');
|
|
2043
|
+
// Set of component kinds that handle their own positioned comments
|
|
2044
|
+
// Note: Cannot use static readonly due to circular dependency issues with class initialization
|
|
2045
|
+
SqlPrintTokenParser._selfHandlingComponentTypes = null;
|
|
1378
2046
|
//# sourceMappingURL=SqlPrintTokenParser.js.map
|