1- import type { AliasMode } from 'src/types' ;
1+ import type { AliasMode , FormatOptions } from 'src/types' ;
2+ import AsTokenFactory from './AsTokenFactory' ;
23
3- import { isCommand , isToken , type Token , TokenType } from './token' ;
4+ import { isCommand , isToken , type Token , TokenType , EOF_TOKEN , isReserved } from './token' ;
45
5- export interface TokenStream {
6- isWithinSelect ( ) : boolean ;
7- getPreviousReservedToken ( ) : Token ;
8- tokenLookBehind ( n ?: number ) : Token ;
9- tokenLookAhead ( n ?: number ) : Token ;
10- }
11-
12- /** Decides addition and removal of AS tokens */
6+ /** Adds and removes AS tokens as configured by aliasAs option */
137export default class AliasAs {
14- constructor ( private aliasAs : AliasMode , private formatter : TokenStream ) { }
8+ private index = 0 ;
9+ private tokens : Token [ ] = [ ] ;
10+ private previousReservedToken : Token = EOF_TOKEN ;
11+ private previousCommandToken : Token = EOF_TOKEN ;
12+ private asTokenFactory : AsTokenFactory ;
13+ private aliasAs : AliasMode ;
14+
15+ constructor ( cfg : FormatOptions , tokens : Token [ ] ) {
16+ this . aliasAs = cfg . aliasAs ;
17+ this . asTokenFactory = new AsTokenFactory ( cfg . keywordCase , tokens ) ;
18+ this . tokens = tokens ;
19+ }
20+
21+ /** Returns tokens with AS tokens added/removed as needed */
22+ public process ( ) : Token [ ] {
23+ const processedTokens : Token [ ] = [ ] ;
24+
25+ for ( this . index = 0 ; this . index < this . tokens . length ; this . index ++ ) {
26+ const token = this . tokens [ this . index ] ;
27+
28+ if ( isReserved ( token ) ) {
29+ this . previousReservedToken = token ;
30+ if ( token . type === TokenType . RESERVED_COMMAND ) {
31+ this . previousCommandToken = token ;
32+ }
33+ }
34+
35+ if ( isToken . AS ( token ) ) {
36+ if ( ! this . shouldRemove ( ) ) {
37+ processedTokens . push ( token ) ;
38+ }
39+ } else if (
40+ token . type === TokenType . IDENT ||
41+ token . type === TokenType . NUMBER ||
42+ token . type === TokenType . STRING ||
43+ token . type === TokenType . VARIABLE
44+ ) {
45+ if ( this . shouldAddBefore ( token ) ) {
46+ processedTokens . push ( this . asTokenFactory . token ( ) ) ;
47+ }
48+
49+ processedTokens . push ( token ) ;
50+
51+ if ( this . shouldAddAfter ( ) ) {
52+ processedTokens . push ( this . asTokenFactory . token ( ) ) ;
53+ }
54+ } else {
55+ processedTokens . push ( token ) ;
56+ }
57+ }
58+
59+ return processedTokens ;
60+ }
1561
1662 /** True when AS keyword should be added *before* current token */
17- public shouldAddBefore ( token : Token ) : boolean {
63+ private shouldAddBefore ( token : Token ) : boolean {
1864 return this . isMissingTableAlias ( token ) || this . isMissingSelectColumnAlias ( token ) ;
1965 }
2066
@@ -31,7 +77,7 @@ export default class AliasAs {
3177 const nextToken = this . lookAhead ( ) ;
3278 return (
3379 ( this . aliasAs === 'always' || this . aliasAs === 'select' ) &&
34- this . formatter . isWithinSelect ( ) &&
80+ this . isWithinSelect ( ) &&
3581 token . type === TokenType . IDENT &&
3682 ( isToken . END ( prevToken ) ||
3783 ( ( prevToken . type === TokenType . IDENT || prevToken . type === TokenType . NUMBER ) &&
@@ -40,16 +86,16 @@ export default class AliasAs {
4086 }
4187
4288 /** True when AS keyword should be added *after* current token */
43- public shouldAddAfter ( ) : boolean {
89+ private shouldAddAfter ( ) : boolean {
4490 return this . isEdgeCaseCTE ( ) || this . isEdgeCaseCreateTable ( ) || this . isMissingTypeCastAs ( ) ;
4591 }
4692
4793 // checks for CAST(«expression» [AS] type)
4894 private isMissingTypeCastAs ( ) : boolean {
4995 return (
5096 this . aliasAs === 'never' &&
51- this . formatter . isWithinSelect ( ) &&
52- isToken . CAST ( this . formatter . getPreviousReservedToken ( ) ) &&
97+ this . isWithinSelect ( ) &&
98+ isToken . CAST ( this . getPreviousReservedToken ( ) ) &&
5399 isToken . AS ( this . lookAhead ( ) ) &&
54100 ( this . lookAhead ( 2 ) . type === TokenType . IDENT ||
55101 this . lookAhead ( 2 ) . type === TokenType . RESERVED_KEYWORD ) &&
@@ -79,23 +125,31 @@ export default class AliasAs {
79125 }
80126
81127 /* True when the current AS token should be discarded */
82- public shouldRemove ( ) : boolean {
128+ private shouldRemove ( ) : boolean {
83129 return this . aliasAs === 'never' || ( this . aliasAs === 'select' && this . isRemovableNonSelectAs ( ) ) ;
84130 }
85131
86132 private isRemovableNonSelectAs ( ) : boolean {
87133 return (
88134 this . lookBehind ( ) . value === ')' && // ) [AS] alias but not SELECT (a) [AS] alpha
89- ! this . formatter . isWithinSelect ( ) &&
135+ ! this . isWithinSelect ( ) &&
90136 this . lookAhead ( ) . value !== '(' // skip WITH foo [AS] ( ...
91137 ) ;
92138 }
93139
94- private lookBehind ( n ?: number ) : Token {
95- return this . formatter . tokenLookBehind ( n ) ;
140+ public getPreviousReservedToken ( ) : Token {
141+ return this . previousReservedToken ;
142+ }
143+
144+ public isWithinSelect ( ) : boolean {
145+ return isToken . SELECT ( this . previousCommandToken ) ;
146+ }
147+
148+ private lookBehind ( n = 1 ) : Token {
149+ return this . lookAhead ( - n ) ;
96150 }
97151
98- private lookAhead ( n ?: number ) : Token {
99- return this . formatter . tokenLookAhead ( n ) ;
152+ private lookAhead ( n = 1 ) : Token {
153+ return this . tokens [ this . index + n ] || EOF_TOKEN ;
100154 }
101155}
0 commit comments