Skip to content
This repository was archived by the owner on Jul 6, 2022. It is now read-only.

Commit c66bba0

Browse files
add jsdocs
1 parent 77cd467 commit c66bba0

28 files changed

Lines changed: 367 additions & 164 deletions

‎src/core/Formatter.ts‎

Lines changed: 147 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Tokenizer from './Tokenizer';
77
import type { FormatOptions } from '../sqlFormatter';
88
import { AliasMode, CommaPosition, KeywordMode, NewlineMode } from '../types';
99

10+
/** Main formatter class that produces a final output string from list of tokens */
1011
export 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 = /JOIN/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

Comments
 (0)