11import Statement from "./statement" ;
22import SQLTokeniser from "./tokens" ;
3- import { Definition , ParsedEmbeddedStatement , StatementGroup , StatementType , StatementTypeWord , Token } from "./types" ;
3+ import { CallableReference , Definition , IRange , ParsedEmbeddedStatement , StatementGroup , StatementType , StatementTypeWord , Token } from "./types" ;
4+
5+
46
57export interface ParsedColumn {
6- columnName : string ;
7- aliasName ?: string ;
8- isAlias : boolean ;
9- type ?: string ;
8+ columnName : string ; // SQL-facing or physical name
9+ aliasName ?: string ; // always the real DB2 column name (zztype, zzvaleur, etc.)
10+ isAlias : boolean ; // true if alias name, false if physical name
11+ type ?: string ; // optional: char(5), varchar(20), etc.
1012}
1113
1214export interface ParsedTableEntry {
1315 tableName : string ;
14- systemTableName ?:string ;
16+ systemTableName ?:string ; // "mouni", "mouni3", "mylib/zz01pf", etc.
1517 columns : ParsedColumn [ ] ; // array of columns for that table
1618}
1719export interface ParsedTable {
1820 columns : ParsedColumn [ ] ;
1921}
20-
2122export default class Document {
2223 content : string ;
2324 statements : Statement [ ] ;
@@ -146,21 +147,28 @@ export default class Document {
146147
147148 getStatementGroups ( ) : StatementGroup [ ] {
148149 let groups : StatementGroup [ ] = [ ] ;
150+
149151 let currentGroup : Statement [ ] = [ ] ;
152+
150153 let depth = 0 ;
154+
151155 for ( const statement of this . statements ) {
152156 if ( statement . isCompoundEnd ( ) ) {
153157 if ( depth > 0 ) {
154- currentGroup . push ( statement ) ;
158+ currentGroup . push ( statement ) ;
159+
155160 depth -- ;
161+
156162 this . log ( `<` + `` . padEnd ( depth * 2 ) + Statement . formatSimpleTokens ( statement . tokens . slice ( 0 , 2 ) ) ) ;
157163 }
164+
158165 if ( depth === 0 ) {
159166 if ( currentGroup . length > 0 ) {
160167 groups . push ( {
161168 range : { start : currentGroup [ 0 ] . range . start , end : currentGroup [ currentGroup . length - 1 ] . range . end } ,
162169 statements : currentGroup
163170 } ) ;
171+
164172 currentGroup = [ ] ;
165173 }
166174 }
@@ -172,7 +180,9 @@ export default class Document {
172180 } else {
173181 currentGroup = [ statement ] ;
174182 }
183+
175184 depth ++ ;
185+
176186 } else {
177187 this . log ( ` ` + `` . padEnd ( depth * 2 ) + Statement . formatSimpleTokens ( statement . tokens . slice ( 0 , 2 ) ) ) ;
178188 if ( depth > 0 ) {
@@ -245,7 +255,7 @@ export default class Document {
245255 } )
246256 }
247257
248- removeEmbeddedAreas ( statement : Statement , snippetString ?: boolean ) : ParsedEmbeddedStatement {
258+ removeEmbeddedAreas ( statement : Statement , options : { replacement : `snippet` | `?` | `values` , values ?: any [ ] } = { replacement : `?` } ) : ParsedEmbeddedStatement {
249259 const areas = statement . getEmbeddedStatementAreas ( ) ;
250260
251261 const totalParameters = areas . filter ( a => a . type === `marker` ) . length ;
@@ -264,25 +274,73 @@ export default class Document {
264274 case `marker` :
265275 const markerContent = newContent . substring ( start , end ) ;
266276
267- newContent = newContent . substring ( 0 , start ) + ( snippetString ? `\${${ totalParameters - parameterCount } :${ markerContent } }` : `?` ) + newContent . substring ( end ) + ( snippetString ? `$0` : `` ) ;
277+ switch ( options . replacement ) {
278+ case `snippet` :
279+ newContent = newContent . substring ( 0 , start ) + `\${${ totalParameters - parameterCount } :${ markerContent } }` + newContent . substring ( end ) + `$0` ;
280+ break ;
281+ case `?` :
282+ newContent = newContent . substring ( 0 , start ) + `?` + newContent . substring ( end ) ;
283+ break ;
284+ case `values` :
285+ let valueIndex = totalParameters - parameterCount - 1 ;
286+ if ( options . values && options . values . length > valueIndex ) {
287+ let value = options . values [ valueIndex ] ;
288+
289+ if ( typeof value === `string` ) {
290+ value = `'${ value . replace ( / ' / g, `''` ) } '` ; // Escape single quotes in strings
291+ }
292+
293+ newContent = newContent . substring ( 0 , start ) + value + newContent . substring ( end ) ;
294+ } else {
295+ newContent = newContent . substring ( 0 , start ) + `?` + newContent . substring ( end ) ;
296+ }
297+ break ;
298+ }
268299
269300 parameterCount ++ ;
270301 break ;
271302
272303 case `remove` :
273- newContent = newContent . substring ( 0 , start ) + newContent . substring ( end + 1 ) ;
304+ newContent = newContent . substring ( 0 , start ) + newContent . substring ( end ) ;
305+ if ( newContent [ start - 1 ] === ` ` && newContent [ start ] === ` ` ) {
306+ newContent = newContent . substring ( 0 , start - 1 ) + newContent . substring ( start ) ;
307+ }
274308 break ;
275309 }
276310 }
277311
278312 return {
279313 changed : areas . length > 0 ,
280- content : newContent ,
314+ content : newContent . trim ( ) ,
281315 parameterCount
282316 } ;
283317 }
284318}
285319
320+
321+ export function getPositionData ( ref : CallableReference , offset : number ) {
322+ const paramCommas = ref . tokens . filter ( token => token . type === `comma` ) ;
323+
324+ let currentParm = paramCommas . findIndex ( t => offset < t . range . start ) ;
325+
326+ if ( currentParm === - 1 ) {
327+ currentParm = paramCommas . length ;
328+ }
329+
330+ const firstNamedPipe = ref . tokens . find ( ( token , i ) => token . type === `rightpipe` ) ;
331+ let firstNamedParameter = firstNamedPipe ? paramCommas . findIndex ( ( token , i ) => token . range . start > firstNamedPipe . range . start ) : undefined ;
332+
333+ if ( firstNamedParameter === - 1 ) {
334+ firstNamedParameter = undefined ;
335+ }
336+
337+ return {
338+ currentParm,
339+ currentCount : paramCommas . length + 1 ,
340+ firstNamedParameter
341+ } ;
342+ }
343+
286344function getSymbolsForStatements ( statements : Statement [ ] ) {
287345 let defintions : Definition [ ] = [ ] ;
288346
@@ -491,57 +549,38 @@ function parseSingleColumn(tokens: any[]) {
491549 const aliasForColumn : string [ ] = [ ] ;
492550 const normalIdentifiers : string [ ] = [ ] ;
493551
494- // ----------------------------------------------
495- // A) FIRST TOKEN CHECK → Alias name (only once)
496- // ----------------------------------------------
497- const first = tokens [ 0 ] ;
498- if ( first && first . type === "word" && ! isKeyword ( first . value ) ) {
499- aliasForColumn . push ( cleanIdentifier ( first . value ) ) ;
500- }
501-
502- // ----------------------------------------------
503- // B) Look for "FOR COLUMN realColumn"
504- // ----------------------------------------------
552+ // -------------------------------
553+ // A) Collect DB2 alias-for-column
554+ // -------------------------------
505555 for ( let i = 0 ; i < tokens . length ; i ++ ) {
506556 const t = tokens [ i ] . value ?. toLowerCase ( ) ;
557+ // IF first token is identifier/word/string → it's the alias name
558+ if ( tokens [ i ] . value === tokens [ 0 ] . value && tokens [ 0 ] . type === "word" )
559+ {
560+ aliasForColumn . push ( cleanIdentifier ( tokens [ 0 ] . value ) ) ;
561+ }
507562
508- if (
509- t === "for" &&
510- tokens [ i + 1 ] ?. value ?. toLowerCase ( ) === "column" &&
511- tokens [ i + 2 ]
512- ) {
513- normalIdentifiers . push ( cleanIdentifier ( tokens [ i + 2 ] . value ) ) ;
563+ // IF (FOR COLUMN realName)
564+ else if ( t === "for" && tokens [ i + 1 ] ?. value ?. toLowerCase ( ) === "column" ) {
565+ const real = tokens [ i + 2 ] ;
566+ if ( real ) normalIdentifiers . push ( cleanIdentifier ( real . value ) ) ;
514567 }
568+
515569 }
516570
517- // ----------------------------------------------
518- // C ) Return final structured result
519- // ----------------------------------------------
571+ // ------------------------
572+ // B ) Return everything
573+ // ------------------------
520574 return {
521575 aliasForColumn,
522576 normalIdentifiers,
523577 } ;
524578}
525579
526-
527580//-----------------------------------------------------------
528581// Helpers
529582//-----------------------------------------------------------
530583
531-
532584function cleanIdentifier ( name : string ) {
533585 return name . replace ( / ^ [ ` \[ " ' ] + | [ ` " \] ' ] + $ / g, "" ) ;
534- }
535-
536- function isKeyword ( val : string ) {
537- const keywords = [
538- "char" , "varchar" , "nvarchar" , "text" , "int" , "integer" , "bigint" ,
539- "decimal" , "numeric" , "float" , "real" , "double" ,
540- "date" , "datetime" , "timestamp" , "time" ,
541- "ccsid" , "default" , "constraint" , "primary" , "foreign" ,
542- "key" , "unique" , "check" , "not" , "null" , "for" , "column" ,
543- "references" , "on" , "update" , "delete" , "by"
544- ] ;
545-
546- return keywords . includes ( val . toLowerCase ( ) ) ;
547- }
586+ }
0 commit comments