1
+ import Tokenizer from "sql-formatter/lib/src/lexer/Tokenizer" ;
1
2
import SQLTokeniser , { NameTypes } from "./tokens" ;
2
3
import { CTEReference , CallableReference , ClauseType , ClauseTypeWord , IRange , ObjectRef , QualifiedObject , StatementType , StatementTypeWord , Token } from "./types" ;
3
4
@@ -8,6 +9,15 @@ const tokenIs = (token: Token|undefined, type: string, value?: string) => {
8
9
export default class Statement {
9
10
public type : StatementType = StatementType . Unknown ;
10
11
private label : string | undefined ;
12
+ private _blockTokens : Token [ ] | undefined ;
13
+
14
+ private get blockTokens ( ) {
15
+ if ( ! this . _blockTokens ) {
16
+ this . _blockTokens = SQLTokeniser . createBlocks ( this . tokens . slice ( 0 ) ) ;
17
+ }
18
+
19
+ return this . _blockTokens ;
20
+ }
11
21
12
22
constructor ( public tokens : Token [ ] , public range : IRange ) {
13
23
this . tokens = this . tokens . filter ( newToken => newToken . type !== `newline` ) ;
@@ -101,62 +111,34 @@ export default class Statement {
101
111
return currentClause ;
102
112
}
103
113
104
- getBlockRangeAt ( offset : number ) {
105
- let start = - 1 ;
106
- let end = - 1 ;
107
-
108
- // Get the current token for the provided offset
109
- let i = this . tokens . findIndex ( ( token , i ) => ( offset >= token . range . start && offset <= token . range . end ) || ( offset > token . range . end && this . tokens [ i + 1 ] && offset < this . tokens [ i + 1 ] . range . start ) ) ;
110
-
111
- let depth = 0 ;
112
-
113
- if ( tokenIs ( this . tokens [ i ] , `closebracket` ) ) {
114
- i -- ;
115
- }
116
-
117
- if ( tokenIs ( this . tokens [ i ] , `openbracket` ) ) {
118
- start = i + 1 ;
119
- i ++ ;
120
- } else {
121
- for ( let x = i ; x >= 0 ; x -- ) {
122
- if ( tokenIs ( this . tokens [ x ] , `openbracket` ) ) {
123
- if ( depth === 0 ) {
124
- start = x + 1 ;
125
- break ;
114
+ getBlockRangeAt ( offset : number ) : IRange | undefined {
115
+ const blockContainsOffset = ( cOffset : number , block : Token [ ] ) : IRange | undefined => {
116
+ const tokenInOffset = block . find ( token => cOffset >= token . range . start && cOffset <= token . range . end ) ;
117
+ if ( tokenInOffset ) {
118
+ if ( tokenInOffset . type === `block` ) {
119
+ if ( tokenInOffset . block ! . length > 0 ) {
120
+ return blockContainsOffset ( cOffset , tokenInOffset . block ! ) ;
126
121
} else {
127
- depth -- ;
122
+ const rawEnd = this . tokens . findIndex ( token => token . range . end === tokenInOffset . range . end ) ;
123
+ return {
124
+ start : rawEnd ,
125
+ end : rawEnd
126
+ }
128
127
}
129
- } else
130
- if ( tokenIs ( this . tokens [ x ] , `closebracket` ) ) {
131
- depth ++ ;
132
- }
133
- }
134
- }
135
-
136
- depth = 0 ;
137
-
138
- for ( let x = i ; x <= this . tokens . length ; x ++ ) {
139
- if ( tokenIs ( this . tokens [ x ] , `openbracket` ) ) {
140
- depth ++ ;
141
- } else
142
- if ( tokenIs ( this . tokens [ x ] , `closebracket` ) ) {
143
- if ( depth === 0 ) {
144
- end = x ;
145
- break ;
146
128
} else {
147
- depth -- ;
129
+ const rawStart = this . tokens . findIndex ( token => token . range . start === block [ 0 ] . range . start ) ;
130
+ const rawEnd = this . tokens . findIndex ( token => token . range . end === block [ block . length - 1 ] . range . end ) ;
131
+ return {
132
+ start : rawStart ,
133
+ end : rawEnd + 1
134
+ } ;
148
135
}
149
136
}
150
- }
151
137
152
- if ( start === - 1 || end === - 1 ) {
153
138
return undefined ;
154
- } else {
155
- return {
156
- start,
157
- end
158
- }
159
139
}
140
+
141
+ return blockContainsOffset ( offset , this . blockTokens ) ;
160
142
}
161
143
162
144
getCallableDetail ( offset : number , withBlocks = false ) : CallableReference {
@@ -176,13 +158,22 @@ export default class Statement {
176
158
}
177
159
178
160
getBlockAt ( offset : number ) : Token [ ] {
179
- const range = this . getBlockRangeAt ( offset ) ;
161
+ const expandBlock = ( tokens : Token [ ] ) : Token [ ] => {
162
+ const block = tokens . filter ( token => token . type === `block` ) ;
163
+ if ( block . length > 0 ) {
164
+ return block . reduce ( ( acc , token ) => acc . concat ( expandBlock ( token . block ! ) ) , tokens ) ;
165
+ }
180
166
181
- if ( range ) {
182
- return this . tokens . slice ( range . start , range . end )
183
- } else {
184
- return [ ]
167
+ return tokens ;
168
+ }
169
+
170
+ let blockRange = this . getBlockRangeAt ( offset ) ;
171
+
172
+ if ( blockRange ) {
173
+ return expandBlock ( this . tokens . slice ( blockRange . start , blockRange . end ) ) ;
185
174
}
175
+
176
+ return [ ] ;
186
177
}
187
178
188
179
getReferenceByOffset ( offset : number ) {
@@ -227,7 +218,7 @@ export default class Statement {
227
218
getCTEReferences ( ) : CTEReference [ ] {
228
219
if ( this . type !== StatementType . With ) return [ ] ;
229
220
230
- const withBlocks = SQLTokeniser . createBlocks ( this . tokens . slice ( 0 ) ) ;
221
+ const withBlocks = this . blockTokens ;
231
222
232
223
let cteList : CTEReference [ ] = [ ] ;
233
224
0 commit comments