@@ -254,85 +254,85 @@ function scanString(state: State, endToken: Char): Token {
254
254
}
255
255
256
256
function getCustomParam ( state : State , paramTypes : ParamTypes ) : string | null | undefined {
257
- const matches = paramTypes ?. custom ?. map ( ( { regex } ) => {
258
- const reg = new RegExp ( `(?:${ regex } )` , 'u' ) ;
259
- return reg . exec ( state . input ) ;
257
+ const matches = paramTypes ?. custom ?. map ( ( regex ) => {
258
+ const reg = new RegExp ( `^ (?:${ regex } )` , 'u' ) ;
259
+ return reg . exec ( state . input . slice ( state . start ) ) ;
260
260
} ) . filter ( ( value ) => ! ! value ) [ 0 ] ;
261
261
262
262
return matches ? matches [ 0 ] : null ;
263
263
}
264
264
265
- function scanParameter ( state : State , dialect : Dialect , paramTypes ?: ParamTypes ) : Token {
266
- // user has defined wanted param types, so we only evaluate them
267
- if ( paramTypes ) {
268
- const curCh : any = state . input [ 0 ] ;
269
- let nextChar = peek ( state ) ;
270
- let matched = false
265
+ function scanCustomParameter ( state : State , dialect : Dialect , paramTypes : ParamTypes ) : Token {
271
266
272
- // this could be a named parameter that just starts with a number (ugh)
273
- if ( paramTypes . numbered && paramTypes . numbered . length && paramTypes . numbered . includes ( curCh ) ) {
274
- const maybeNumbers = state . input . slice ( 1 , state . input . length ) ;
275
- if ( nextChar !== null && ! isNaN ( Number ( nextChar ) ) && / ^ \d + $ / . test ( maybeNumbers ) ) {
276
- do {
277
- nextChar = read ( state ) ;
278
- } while ( nextChar !== null && ! isNaN ( Number ( nextChar ) ) && ! isWhitespace ( nextChar ) ) ;
279
-
280
- if ( nextChar !== null ) unread ( state ) ;
281
- matched = true ;
282
- }
283
- }
284
-
285
- if ( ! matched && paramTypes . named && paramTypes . named . length && paramTypes . named . includes ( curCh ) ) {
286
- if ( ! isQuotedIdentifier ( nextChar , dialect ) ) {
287
- while ( isAlphaNumeric ( peek ( state ) ) ) read ( state ) ;
288
- matched = true ;
289
- }
290
- }
291
-
292
- if ( ! matched && paramTypes . quoted && paramTypes . quoted . length && paramTypes . quoted . includes ( curCh ) ) {
293
- if ( isQuotedIdentifier ( nextChar , dialect ) ) {
294
- const endChars = new Map < string , string > ( [
295
- [ '"' , '"' ] ,
296
- [ '[' , ']' ] ,
297
- [ '`' , '`' ]
298
- ] ) ;
299
- const quoteChar = read ( state ) as string ;
300
- const end = endChars . get ( quoteChar ) ;
301
- // end when we reach the end quote
302
- while ( ( isAlphaNumeric ( peek ( state ) ) || peek ( state ) === ' ' ) && peek ( state ) != end ) read ( state ) ;
303
-
304
- // read the end quote
305
- read ( state ) ;
306
-
307
- matched = true ;
308
- }
309
- }
310
-
311
- if ( ! matched && paramTypes . custom && paramTypes . custom . length ) {
312
- const custom = getCustomParam ( state , paramTypes ) ;
267
+ const curCh : any = state . input [ state . start ] ;
268
+ let nextChar = peek ( state ) ;
269
+ let matched = false
313
270
314
- if ( custom ) {
315
- read ( state , custom . length ) ;
316
- matched = true ;
317
- }
318
- }
319
-
320
- if ( ! matched && curCh !== '?' && nextChar !== null ) { // not positional, panic
321
- return {
322
- type : 'parameter' ,
323
- value : 'unknown' ,
324
- start : state . start ,
325
- end : state . end
326
- }
327
- }
271
+ if ( paramTypes . numbered && paramTypes . numbered . length && paramTypes . numbered . includes ( curCh ) ) {
272
+ const endIndex = state . input . slice ( state . start ) . split ( '' ) . findIndex ( ( val ) => isWhitespace ( val ) ) ;
273
+ const maybeNumbers = state . input . slice ( state . start + 1 , endIndex > 0 ? state . start + endIndex : state . end + 1 ) ;
274
+ if ( nextChar !== null && ! isNaN ( Number ( nextChar ) ) && / ^ \d + $ / . test ( maybeNumbers ) ) {
275
+ let nextChar : Char = null ;
276
+ do {
277
+ nextChar = read ( state ) ;
278
+ } while ( nextChar !== null && ! isNaN ( Number ( nextChar ) ) && ! isWhitespace ( nextChar ) ) ;
328
279
329
- const value = state . input . slice ( state . start , state . position + 1 ) ;
280
+ if ( nextChar !== null ) unread ( state ) ;
281
+ matched = true ;
282
+ }
283
+ }
284
+
285
+ if ( ! matched && paramTypes . named && paramTypes . named . length && paramTypes . named . includes ( curCh ) ) {
286
+ if ( ! isQuotedIdentifier ( nextChar , dialect ) ) {
287
+ while ( isAlphaNumeric ( peek ( state ) ) ) read ( state ) ;
288
+ matched = true ;
289
+ }
290
+ }
291
+
292
+ if ( ! matched && paramTypes . quoted && paramTypes . quoted . length && paramTypes . quoted . includes ( curCh ) ) {
293
+ if ( isQuotedIdentifier ( nextChar , dialect ) ) {
294
+ const quoteChar = read ( state ) as string ;
295
+ // end when we reach the end quote
296
+ while ( ( isAlphaNumeric ( peek ( state ) ) || peek ( state ) === ' ' ) && peek ( state ) != ENDTOKENS [ quoteChar ] ) read ( state ) ;
297
+
298
+ // read the end quote
299
+ read ( state ) ;
300
+
301
+ matched = true ;
302
+ }
303
+ }
304
+
305
+ if ( ! matched && paramTypes . custom && paramTypes . custom . length ) {
306
+ const custom = getCustomParam ( state , paramTypes ) ;
307
+
308
+ if ( custom ) {
309
+ read ( state , custom . length ) ;
310
+ matched = true ;
311
+ }
312
+ }
313
+
314
+ if ( ! matched && ! paramTypes . positional ) { // not positional, panic
330
315
return {
331
316
type : 'parameter' ,
332
- value,
317
+ value : 'unknown' ,
333
318
start : state . start ,
334
- end : state . start + value . length - 1 ,
335
- } ;
319
+ end : state . end
320
+ }
321
+ }
322
+
323
+ const value = state . input . slice ( state . start , state . position + 1 ) ;
324
+ return {
325
+ type : 'parameter' ,
326
+ value,
327
+ start : state . start ,
328
+ end : state . start + value . length - 1 ,
329
+ } ;
330
+ }
331
+
332
+ function scanParameter ( state : State , dialect : Dialect , paramTypes ?: ParamTypes ) : Token {
333
+ // user has defined wanted param types, so we only evaluate them
334
+ if ( paramTypes ) {
335
+ return scanCustomParameter ( state , dialect , paramTypes ) ;
336
336
}
337
337
338
338
if ( [ 'mysql' , 'generic' , 'sqlite' ] . includes ( dialect ) ) {
@@ -495,17 +495,17 @@ function isString(ch: Char, dialect: Dialect): boolean {
495
495
}
496
496
497
497
function isCustomParam ( state : State , paramTypes : ParamTypes ) : boolean | undefined {
498
- return paramTypes ?. custom ?. some ( ( { regex } ) => {
499
- const reg = new RegExp ( `(?:${ regex } )` , 'uy' ) ;
500
- return reg . test ( state . input ) ;
498
+ return paramTypes ?. custom ?. some ( ( regex ) => {
499
+ const reg = new RegExp ( `^ (?:${ regex } )` , 'uy' ) ;
500
+ return reg . test ( state . input . slice ( state . start ) ) ;
501
501
} )
502
502
}
503
503
504
504
function isParameter ( ch : Char , state : State , dialect : Dialect , paramTypes ?: ParamTypes ) : boolean {
505
505
if ( paramTypes && ch !== null ) {
506
506
const curCh : any = ch ;
507
507
const nextChar = peek ( state ) ;
508
- if ( paramTypes . positional && ch === '?' && nextChar === null ) return true ;
508
+ if ( paramTypes . positional && ch === '?' && ( nextChar === null || isWhitespace ( nextChar ) ) ) return true ;
509
509
510
510
if ( paramTypes . numbered && paramTypes . numbered . length && paramTypes . numbered . includes ( curCh ) ) {
511
511
if ( nextChar !== null && ! isNaN ( Number ( nextChar ) ) ) {
0 commit comments