@@ -7,6 +7,7 @@ import Tokenizer from './Tokenizer';
77import type { FormatOptions } from '../sqlFormatter' ;
88import { AliasMode , CommaPosition , KeywordMode , NewlineMode } from '../types' ;
99
10+ /** Main formatter class that produces a final output string from list of tokens */
1011export default class Formatter {
1112 cfg : FormatOptions & { tenSpace ?: boolean } ;
1213 newline : FormatOptions [ 'newline' ] ;
@@ -22,14 +23,14 @@ export default class Formatter {
2223 index : number ;
2324
2425 /**
25- * @param {FormatOptions } cfg
26- * @param {String } cfg.language
27- * @param {String } cfg.indent
28- * @param {Boolean } cfg.uppercase
29- * @param {NewlineMode } cfg.newline
30- * @param {Integer } cfg.lineWidth
31- * @param {Integer } cfg.linesBetweenQueries
32- * @param {ParamItems | string[] } cfg.params
26+ * @param {FormatOptions } cfg - config object
27+ * @param {string } cfg.language - the current SQL dialect
28+ * @param {string } cfg.indent - the indentation string, either tabs or a number of spaces
29+ * @param {Boolean } cfg.uppercase - whether to use uppercase keywords
30+ * @param {NewlineMode } cfg.newline - setting to control when to break onto newlines
31+ * @param {Integer } cfg.lineWidth - the maximum line width before breaking
32+ * @param {Integer } cfg.linesBetweenQueries - the number of blank lines between each query
33+ * @param {ParamItems | string[] } cfg.params - placeholder tokens to substitute
3334 */
3435 constructor ( cfg : FormatOptions ) {
3536 this . cfg = cfg ;
@@ -59,7 +60,7 @@ export default class Formatter {
5960 /**
6061 * Reprocess and modify a token based on parsed context.
6162 *
62- * @param {Token } token The token to modify
63+ * @param {Token } token - The token to modify
6364 * @return {Token } new token or the original
6465 */
6566 tokenOverride ( token : Token ) : Token {
@@ -70,8 +71,7 @@ export default class Formatter {
7071 /**
7172 * Formats whitespace in a SQL string to make it easier to read.
7273 *
73- * @param {String } query The SQL query string
74- * @return {String } formatted query
74+ * @param {string } query - The SQL query string
7575 */
7676 format ( query : string ) : string {
7777 this . tokens = this . tokenizer ( ) . tokenize ( query ) ;
@@ -81,7 +81,11 @@ export default class Formatter {
8181 return finalQuery . replace ( / ^ \n * / u, '' ) . trimEnd ( ) ;
8282 }
8383
84- postFormat ( query : string ) {
84+ /**
85+ * Does post-processing on the formatted query.
86+ * @param {string } query - the query string produced from `this.format`
87+ */
88+ postFormat ( query : string ) : string {
8589 if ( this . cfg . tabulateAlias ) {
8690 query = this . formatAliasPositions ( query ) ;
8791 }
@@ -92,7 +96,11 @@ export default class Formatter {
9296 return query ;
9397 }
9498
95- formatCommaPositions ( query : string ) {
99+ /**
100+ * Handles comma placement - either before, after or tabulated
101+ * @param {string } query - input query string
102+ */
103+ formatCommaPositions ( query : string ) : string {
96104 // const trailingComma = /,$/;
97105 const lines = query . split ( '\n' ) ;
98106 let newQuery : string [ ] = [ ] ;
@@ -137,7 +145,11 @@ export default class Formatter {
137145 return newQuery . join ( '\n' ) ;
138146 }
139147
140- formatAliasPositions ( query : string ) {
148+ /**
149+ * Handles select alias placement - tabulates if enabled
150+ * @param {string } query - input query string
151+ */
152+ formatAliasPositions ( query : string ) : string {
141153 const lines = query . split ( '\n' ) ;
142154
143155 let newQuery : string [ ] = [ ] ;
@@ -186,7 +198,11 @@ export default class Formatter {
186198 return newQuery . join ( '\n' ) ;
187199 }
188200
189- getFormattedQueryFromTokens ( ) {
201+ /**
202+ * Performs main construction of query from token list, delegates to other methods for formatting based on token criteria
203+ * @return {string } formatted query
204+ */
205+ getFormattedQueryFromTokens ( ) : string {
190206 let formattedQuery = '' ;
191207
192208 for ( this . index = 0 ; this . index < this . tokens . length ; this . index ++ ) {
@@ -233,7 +249,12 @@ export default class Formatter {
233249 return formattedQuery . replace ( new RegExp ( ZWS , 'ugim' ) , ' ' ) ;
234250 }
235251
236- formatWord = ( token : Token , query : string ) : string => {
252+ /**
253+ * Formats word tokens + any potential AS tokens for aliases
254+ * @param {Token } token - current token
255+ * @param {string } query - formatted query so far
256+ */
257+ formatWord ( token : Token , query : string ) : string {
237258 const prevToken = this . tokenLookBehind ( ) ;
238259 const nextToken = this . tokenLookAhead ( ) ;
239260 const asToken = { type : TokenType . RESERVED_KEYWORD , value : this . cfg . uppercase ? 'AS' : 'as' } ;
@@ -287,9 +308,14 @@ export default class Formatter {
287308 }
288309
289310 return finalQuery ;
290- } ;
311+ }
291312
292- checkNewline = ( index : number ) => {
313+ /**
314+ * Checks if a newline should currently be inserted
315+ * @param {number } index - index of current token
316+ * @return {boolean } Whether or not a newline should be inserted
317+ */
318+ checkNewline ( index : number ) : boolean {
293319 const tail = this . tokens . slice ( index + 1 ) ;
294320 const nextTokens = tail . slice (
295321 0 ,
@@ -342,21 +368,29 @@ export default class Formatter {
342368 }
343369
344370 return true ;
345- } ;
371+ }
346372
347- formatLineComment ( token : Token , query : string ) {
373+ /** Formats a line comment onto query */
374+ formatLineComment ( token : Token , query : string ) : string {
348375 return this . addNewline ( query + this . show ( token ) ) ;
349376 }
350377
351- formatBlockComment ( token : Token , query : string ) {
378+ /** Formats a block comment onto query */
379+ formatBlockComment ( token : Token , query : string ) : string {
352380 return this . addNewline ( this . addNewline ( query ) + this . indentComment ( token . value ) ) ;
353381 }
354382
355- indentComment ( comment : string ) {
383+ /** Aligns comment to current indentation level */
384+ indentComment ( comment : string ) : string {
356385 return comment . replace ( / \n [ \t ] * / gu, '\n' + this . indentation . getIndent ( ) + ' ' ) ;
357386 }
358387
359- formatCommand ( token : Token , query : string ) {
388+ /**
389+ * Formats a Reserved Command onto query, increasing indentation level where necessary
390+ * @param {Token } token - current token
391+ * @param {string } query - formatted query so far
392+ */
393+ formatCommand ( token : Token , query : string ) : string {
360394 this . indentation . decreaseTopLevel ( ) ;
361395
362396 query = this . addNewline ( query ) ;
@@ -378,7 +412,12 @@ export default class Formatter {
378412 return query ;
379413 }
380414
381- formatBinaryCommand ( token : Token , query : string ) {
415+ /**
416+ * Formats a Reserved Binary Command onto query, joining neighbouring tokens
417+ * @param {Token } token - current token
418+ * @param {string } query - formatted query so far
419+ */
420+ formatBinaryCommand ( token : Token , query : string ) : string {
382421 const isJoin = / J O I N / i. test ( token . value ) ;
383422 if ( ! isJoin || this . cfg . tenSpace ) {
384423 // decrease for boolean set operators or in tenSpace modes
@@ -388,7 +427,12 @@ export default class Formatter {
388427 return isJoin ? query + ' ' : this . addNewline ( query ) ;
389428 }
390429
391- formatKeyword ( token : Token , query : string ) {
430+ /**
431+ * Formats a Reserved Keyword onto query, skipping AS if disabled
432+ * @param {Token } token - current token
433+ * @param {string } query - formatted query so far
434+ */
435+ formatKeyword ( token : Token , query : string ) : string {
392436 if (
393437 isToken . AS ( token ) &&
394438 ( this . cfg . aliasAs === AliasMode . never || // skip all AS if never
@@ -404,7 +448,21 @@ export default class Formatter {
404448 return this . formatWithSpaces ( token , query ) ;
405449 }
406450
407- formatOperator ( token : Token , query : string ) {
451+ /**
452+ * Formats a Reserved Dependent Clause token onto query, supporting the keyword that precedes it
453+ * @param {Token } token - current token
454+ * @param {string } query - formatted query so far
455+ */
456+ formatDependentClause ( token : Token , query : string ) : string {
457+ return this . addNewline ( query ) + this . equalizeWhitespace ( this . show ( token ) ) + ' ' ;
458+ }
459+
460+ /**
461+ * Formats an Operator onto query, following rules for specific characters
462+ * @param {Token } token - current token
463+ * @param {string } query - formatted query so far
464+ */
465+ formatOperator ( token : Token , query : string ) : string {
408466 // special operator
409467 if ( token . value === ',' ) {
410468 return this . formatComma ( token , query ) ;
@@ -426,11 +484,12 @@ export default class Formatter {
426484 return this . formatWithSpaces ( token , query ) ;
427485 }
428486
429- formatDependentClause ( token : Token , query : string ) {
430- return this . addNewline ( query ) + this . equalizeWhitespace ( this . show ( token ) ) + ' ' ;
431- }
432-
433- formatLogicalOperator ( token : Token , query : string ) {
487+ /**
488+ * Formats a Logical Operator onto query, joining boolean conditions
489+ * @param {Token } token - current token
490+ * @param {string } query - formatted query so far
491+ */
492+ formatLogicalOperator ( token : Token , query : string ) : string {
434493 if ( isToken . AND ( token ) && isToken . BETWEEN ( this . tokenLookBehind ( 2 ) ) ) {
435494 return this . formatWithSpaces ( token , query ) ;
436495 }
@@ -451,13 +510,17 @@ export default class Formatter {
451510 }
452511 }
453512
454- // Replace any sequence of whitespace characters with single space
455- equalizeWhitespace ( string : string ) {
513+ /** Replace any sequence of whitespace characters with single space */
514+ equalizeWhitespace ( string : string ) : string {
456515 return string . replace ( / \s + / gu, ' ' ) ;
457516 }
458517
459- // Opening parentheses increase the block indent level and start a new line
460- formatBlockStart ( token : Token , query : string ) {
518+ /**
519+ * Formats a Block Start token (left paren/bracket/brace, CASE) onto query, beginning an Inline Block or increasing indentation where necessary
520+ * @param {Token } token - current token
521+ * @param {string } query - formatted query so far
522+ */
523+ formatBlockStart ( token : Token , query : string ) : string {
461524 if ( isToken . CASE ( token ) ) {
462525 query = this . formatWithSpaces ( token , query ) ;
463526 } else {
@@ -489,8 +552,12 @@ export default class Formatter {
489552 return query ;
490553 }
491554
492- // Closing parentheses decrease the block indent level
493- formatBlockEnd ( token : Token , query : string ) {
555+ /**
556+ * Formats a Block End token (right paren/bracket/brace, END) onto query, closing an Inline Block or decreasing indentation where necessary
557+ * @param {Token } token - current token
558+ * @param {string } query - formatted query so far
559+ */
560+ formatBlockEnd ( token : Token , query : string ) : string {
494561 if ( this . inlineBlock . isActive ( ) ) {
495562 this . inlineBlock . end ( ) ;
496563 if ( isToken . END ( token ) ) {
@@ -512,12 +579,21 @@ export default class Formatter {
512579 }
513580 }
514581
515- formatPlaceholder ( token : Token , query : string ) {
582+ /**
583+ * Formats a Placeholder item onto query, to be replaced with the value of the placeholder
584+ * @param {Token } token - current token
585+ * @param {string } query - formatted query so far
586+ */
587+ formatPlaceholder ( token : Token , query : string ) : string {
516588 return query + this . params . get ( token ) + ' ' ;
517589 }
518590
519- // Commas start a new line (unless within inline parentheses or SQL "LIMIT" clause)
520- formatComma ( token : Token , query : string ) {
591+ /**
592+ * Formats a comma Operator onto query, ending line unless in an Inline Block
593+ * @param {Token } token - current token
594+ * @param {string } query - formatted query so far
595+ */
596+ formatComma ( token : Token , query : string ) : string {
521597 query = trimSpacesEnd ( query ) + this . show ( token ) + ' ' ;
522598
523599 if ( this . inlineBlock . isActive ( ) ) {
@@ -531,17 +607,34 @@ export default class Formatter {
531607 }
532608 }
533609
534- formatWithoutSpaces ( token : Token , query : string ) {
610+ /** Simple append of token onto query */
611+ formatWithoutSpaces ( token : Token , query : string ) : string {
535612 return trimSpacesEnd ( query ) + this . show ( token ) ;
536613 }
537614
538- formatWithSpaces ( token : Token , query : string , preserve : 'before' | 'after' | 'both' = 'both' ) {
539- const before = preserve === 'after' ? trimSpacesEnd ( query ) : query ;
540- const after = preserve === 'before' ? '' : ' ' ;
615+ /**
616+ * Add token onto query with spaces - either before, after, or both
617+ * @param {Token } token - current token
618+ * @param {string } query - formatted query so far
619+ * @param {'before' | 'after' | 'both' } addSpace - where to add spaces around token
620+ * @return {string } token string with specified spaces
621+ */
622+ formatWithSpaces (
623+ token : Token ,
624+ query : string ,
625+ addSpace : 'before' | 'after' | 'both' = 'both'
626+ ) : string {
627+ const before = addSpace === 'after' ? trimSpacesEnd ( query ) : query ;
628+ const after = addSpace === 'before' ? '' : ' ' ;
541629 return before + this . show ( token ) + after ;
542630 }
543631
544- formatQuerySeparator ( token : Token , query : string ) {
632+ /**
633+ * Format Delimiter token onto query, adding newlines accoring to `this.cfg.linesBetweenQueries`
634+ * @param {Token } token - current token
635+ * @param {string } query - formatted query so far
636+ */
637+ formatQuerySeparator ( token : Token , query : string ) : string {
545638 this . indentation . resetIndentation ( ) ;
546639 query = trimSpacesEnd ( query ) ;
547640 if ( this . cfg . semicolonNewline ) {
@@ -553,8 +646,8 @@ export default class Formatter {
553646 return query + this . show ( token ) + '\n' . repeat ( this . cfg . linesBetweenQueries + 1 ) ;
554647 }
555648
556- // Converts token to string ( uppercasing it if needed)
557- show ( token : Token ) {
649+ /** Converts token to string, uppercasing if enabled */
650+ show ( token : Token ) : string {
558651 if (
559652 isReserved ( token ) ||
560653 token . type === TokenType . BLOCK_START ||
@@ -566,16 +659,18 @@ export default class Formatter {
566659 }
567660 }
568661
569- addNewline ( query : string ) {
662+ /** Inserts a newline onto the query */
663+ addNewline ( query : string ) : string {
570664 query = trimSpacesEnd ( query ) ;
571665 if ( ! query . endsWith ( '\n' ) ) {
572666 query += '\n' ;
573667 }
574668 return query + this . indentation . getIndent ( ) ;
575669 }
576670
577- tenSpacedToken ( token : Token ) {
578- const addBuffer = ( string : String , bufferLength = 9 ) =>
671+ /** Produces a 10-char wide version of reserved token for TenSpace modes */
672+ tenSpacedToken ( token : Token ) : Token {
673+ const addBuffer = ( string : string , bufferLength = 9 ) =>
579674 ZWS . repeat ( Math . max ( bufferLength - string . length , 0 ) ) ;
580675 if ( this . cfg . tenSpace ) {
581676 let bufferItem = token . value ; // store which part of keyword receives 10-space buffer
@@ -596,10 +691,12 @@ export default class Formatter {
596691 return token ;
597692 }
598693
694+ /** Fetches nth previous token from the token stream */
599695 tokenLookBehind ( n = 1 ) {
600696 return this . tokens [ this . index - n ] ;
601697 }
602698
699+ /** Fetches nth next token from the token stream */
603700 tokenLookAhead ( n = 1 ) {
604701 return this . tokens [ this . index + n ] ;
605702 }
0 commit comments