@@ -200,14 +200,14 @@ function extractBalancedSymbols(text: string, openSymbol: string, closeSymbol: s
200200 */
201201function extractFunctionSignature ( declaration : string ) : FunctionSignature {
202202 // Remove comments and clean up the declaration
203- const cleanDeclaration = removeLeadingComments ( declaration ) . trim ( )
203+ const cleanDeclaration = removeLeadingComments ( declaration ) . trim ( ) . replace ( / ^ e x p o r t \s + / , '' ) // Remove leading export if present
204204
205- // Regex to match function declarations, including complex generics and export
206- const functionPattern = / ^ \s * ( e x p o r t \s + ) ? (?: d e c l a r e \s + ) ? (?: a s y n c \s + ) ? f u n c t i o n \s * ( \* ) ? \s * ( [ ^ \s ( < ] + ) /
205+ // Enhanced regex to capture async and generator functions
206+ const functionPattern = / ^ (?: a s y n c \s + ) ? f u n c t i o n \s * ( \* ) ? \s * ( [ a - z A - Z _ $ ] [ \w $ ] * ) (?: < ( [ ^ > ] * ) > ) ? \s * \( ( . * ? ) \) (?: \s * : \s * ( [ ^ { ; ] + ) ) ? / s
207207 const functionMatch = cleanDeclaration . match ( functionPattern )
208208
209209 if ( ! functionMatch ) {
210- console . error ( 'Function name could not be extracted from declaration:' , declaration )
210+ console . error ( 'Function name could not be extracted from declaration:' , cleanDeclaration )
211211 return {
212212 name : '' ,
213213 params : '' ,
@@ -216,46 +216,19 @@ function extractFunctionSignature(declaration: string): FunctionSignature {
216216 }
217217 }
218218
219- const name = functionMatch [ 3 ]
220- let rest = cleanDeclaration . slice ( cleanDeclaration . indexOf ( name ) + name . length ) . trim ( )
219+ const [ , isGenerator , name , generics = '' , params = '' , returnType = 'void' ] = functionMatch
221220
222- // Extract generics
223- let generics = ''
224- if ( rest . startsWith ( '<' ) ) {
225- const genericsResult = extractBalancedSymbols ( rest , '<' , '>' )
226- if ( genericsResult ) {
227- generics = genericsResult . content // This includes the angle brackets
228- rest = genericsResult . rest . trim ( )
229- }
230- }
231-
232- // Extract parameters
233- let params = ''
234- if ( rest . startsWith ( '(' ) ) {
235- const paramsResult = extractBalancedSymbols ( rest , '(' , ')' )
236- if ( paramsResult ) {
237- params = paramsResult . content . slice ( 1 , - 1 ) . trim ( )
238- rest = paramsResult . rest . trim ( )
239- }
240- }
241-
242- // Extract return type
243- let returnType = 'void'
244- if ( rest . startsWith ( ':' ) ) {
245- rest = rest . slice ( 1 ) . trim ( )
246- const returnTypeResult = extractReturnType ( rest )
247- debugLog ( undefined , 'return-type' , `Extracted return type: ${ returnTypeResult ?. returnType } ` )
248- if ( returnTypeResult ) {
249- returnType = returnTypeResult . returnType . trim ( )
250- rest = returnTypeResult . rest . trim ( )
251- }
221+ // Handle async generator functions
222+ let finalReturnType = returnType . trim ( )
223+ if ( isGenerator ) {
224+ finalReturnType = `AsyncGenerator<${ finalReturnType } , void, unknown>`
252225 }
253226
254227 return {
255228 name,
256229 params : cleanParameterTypes ( params ) ,
257- returnType : normalizeType ( returnType ) ,
258- generics,
230+ returnType : normalizeType ( finalReturnType ) ,
231+ generics : generics ? `< ${ generics } >` : '' ,
259232 }
260233}
261234
@@ -700,7 +673,7 @@ function inferArrayType(value: string, state?: ProcessingState, indentLevel = 0)
700673 return `readonly [${ tuples . join ( ', ' ) } ]`
701674 }
702675
703- const elementTypes = elements . map ( ( element , index ) => {
676+ const elementTypes = elements . map ( ( element ) => {
704677 const trimmed = element . trim ( )
705678 // debugLog(state, 'element-processing', `Processing element ${index}: "${trimmed}"`)
706679
@@ -907,6 +880,24 @@ export function isDefaultExport(line: string): boolean {
907880}
908881
909882function isDeclarationStart ( line : string ) : boolean {
883+ // Skip regex patterns
884+ if ( isRegexPattern ( line ) )
885+ return false
886+
887+ const validIdentifierRegex = / ^ [ a - z _ $ ] [ \w $ ] * $ / i
888+
889+ // Handle function declarations
890+ if ( line . startsWith ( 'function' ) || line . startsWith ( 'async function' ) ) {
891+ const nameMatch = line . match ( / f u n c t i o n \s + ( [ ^ ( < \s ] + ) / )
892+ return nameMatch ? validIdentifierRegex . test ( nameMatch [ 1 ] ) : false
893+ }
894+
895+ if ( line . startsWith ( 'export function' ) || line . startsWith ( 'export async function' ) ) {
896+ const nameMatch = line . match ( / f u n c t i o n \s + ( [ ^ ( < \s ] + ) / )
897+ return nameMatch ? validIdentifierRegex . test ( nameMatch [ 1 ] ) : false
898+ }
899+
900+ // Handle other declarations
910901 return (
911902 line . startsWith ( 'export ' )
912903 || line . startsWith ( 'interface ' )
@@ -922,6 +913,23 @@ function isDeclarationStart(line: string): boolean {
922913 )
923914}
924915
916+ function isRegexPattern ( line : string ) : boolean {
917+ return (
918+ line . includes ( '\\' )
919+ || line . includes ( '[^' )
920+ || line . includes ( '(?:' )
921+ || line . includes ( '(?=' )
922+ || line . includes ( '(?!' )
923+ || line . includes ( '\\s*' )
924+ || line . includes ( '\\w+' )
925+ || line . includes ( '\\d+' )
926+ || line . includes ( '(?<' )
927+ || line . includes ( '(?!' )
928+ || line . includes ( '(?<=' )
929+ || line . includes ( '(?<!' )
930+ )
931+ }
932+
925933/**
926934 * Check if a given type string represents a function type
927935 */
@@ -940,6 +948,18 @@ export function isDeclarationComplete(content: string | string[]): boolean {
940948 return / ; \s * $ / . test ( trimmedContent ) || / \} \s * $ / . test ( trimmedContent )
941949}
942950
951+ function isVariableInsideFunction ( line : string , state : ProcessingState ) : boolean {
952+ const trimmed = line . trim ( )
953+ return (
954+ state . currentScope === 'function'
955+ && ( trimmed . startsWith ( 'const ' )
956+ || trimmed . startsWith ( 'let ' )
957+ || trimmed . startsWith ( 'var ' )
958+ // Handle multiline variable declarations
959+ || / ^ (?: c o n s t | l e t | v a r ) \s + [ a - z A - Z _ $ ] [ \w $ ] * \s * (?: : | = ) / . test ( trimmed ) )
960+ )
961+ }
962+
943963function needsMultilineFormat ( types : string [ ] ) : boolean {
944964 return types . some ( type =>
945965 type . includes ( '\n' )
@@ -986,20 +1006,24 @@ function processBlock(lines: string[], comments: string[], state: ProcessingStat
9861006 const declarationText = lines . join ( '\n' )
9871007 const cleanDeclaration = removeLeadingComments ( declarationText ) . trim ( )
9881008
989- // Keep track of declaration for debugging
990- state . debug . currentProcessing = cleanDeclaration
9911009 debugLog ( state , 'block-processing' , `Full block content:\n${ cleanDeclaration } ` )
9921010
9931011 if ( ! cleanDeclaration ) {
9941012 debugLog ( state , 'block-processing' , 'Empty declaration block' )
9951013 return
9961014 }
9971015
998- // Try each processor in order
999- if ( processVariableBlock ( cleanDeclaration , lines , state ) )
1016+ // Early check for variables inside functions
1017+ if ( isVariableInsideFunction ( cleanDeclaration , state ) ) {
1018+ debugLog ( state , 'block-processing' , 'Skipping variable declaration inside function' )
10001019 return
1020+ }
1021+
1022+ // Try each processor in order
10011023 if ( processFunctionBlock ( cleanDeclaration , state ) )
10021024 return
1025+ if ( processVariableBlock ( cleanDeclaration , lines , state ) )
1026+ return
10031027 if ( processInterfaceBlock ( cleanDeclaration , declarationText , state ) )
10041028 return
10051029 if ( processTypeBlock ( cleanDeclaration , declarationText , state ) )
@@ -1013,7 +1037,6 @@ function processBlock(lines: string[], comments: string[], state: ProcessingStat
10131037 if ( processModuleBlock ( cleanDeclaration , declarationText , state ) )
10141038 return
10151039
1016- // Log any unhandled declarations
10171040 debugLog ( state , 'processing' , `Unhandled declaration type: ${ cleanDeclaration . split ( '\n' ) [ 0 ] } ` )
10181041}
10191042
@@ -1022,7 +1045,14 @@ function processVariableBlock(cleanDeclaration: string, lines: string[], state:
10221045 if ( ! variableMatch )
10231046 return false
10241047
1048+ // Double-check we're not inside a function
1049+ if ( isVariableInsideFunction ( cleanDeclaration , state ) ) {
1050+ debugLog ( state , 'variable-processing' , 'Skipping variable inside function' )
1051+ return true // Return true because we handled it (by skipping)
1052+ }
1053+
10251054 const isExported = cleanDeclaration . startsWith ( 'export' )
1055+
10261056 // Only process variables at the top level
10271057 if ( state . currentScope === 'top' ) {
10281058 const fullDeclaration = lines . join ( '\n' )
@@ -1035,26 +1065,33 @@ function processVariableBlock(cleanDeclaration: string, lines: string[], state:
10351065}
10361066
10371067function processFunctionBlock ( cleanDeclaration : string , state : ProcessingState ) : boolean {
1038- if ( ! / ^ ( e x p o r t \s + ) ? ( a s y n c \s + ) ? f u n c t i o n / . test ( cleanDeclaration ) )
1068+ // Check for function declarations including async and generator functions
1069+ if ( ! / ^ (?: e x p o r t \s + ) ? (?: a s y n c \s + ) ? f u n c t i o n \s * ( \* ) ? \s * [ a - z A - Z _ $ ] [ \w $ ] * / . test ( cleanDeclaration ) )
10391070 return false
10401071
10411072 debugLog ( state , 'block-processing' , 'Processing function declaration' )
10421073 const isExported = cleanDeclaration . startsWith ( 'export' )
10431074
1044- // Split block into separate function declarations if multiple exist
1045- const declarations = cleanDeclaration . split ( / e x p o r t f u n c t i o n | f u n c t i o n / )
1075+ // Split function declarations - handle export separately
1076+ const declarations = cleanDeclaration
1077+ . replace ( / ^ e x p o r t \s + / , '' ) // Remove leading export once
1078+ . split ( / \n e x p o r t \s + f u n c t i o n | \n f u n c t i o n / )
10461079 . filter ( Boolean )
1047- . map ( d => ( isExported ? `export function${ d } ` : `function${ d } ` ) )
1080+ . map ( d => d . trim ( ) )
1081+ . filter ( d => d . startsWith ( 'function' ) || d . startsWith ( 'async function' ) )
10481082
10491083 for ( const declaration of declarations ) {
10501084 // Process only the function signature for overloads and declarations
10511085 const signature = declaration . split ( '{' ) [ 0 ] . trim ( )
10521086 if ( signature ) {
10531087 const processed = processFunction ( signature , state . usedTypes , isExported )
1054- if ( processed )
1088+ if ( processed ) {
1089+ debugLog ( state , 'function-processing' , `Processed function: ${ processed } ` )
10551090 state . dtsLines . push ( processed )
1091+ }
10561092 }
10571093 }
1094+
10581095 return true
10591096}
10601097
@@ -1322,7 +1359,6 @@ function processSourceFile(content: string, state: ProcessingState): void {
13221359 let bracketDepth = 0
13231360 let parenDepth = 0
13241361 let inDeclaration = false
1325- // Ensure currentScope is initialized
13261362 state . currentScope = 'top'
13271363
13281364 for ( let i = 0 ; i < lines . length ; i ++ ) {
@@ -1353,9 +1389,8 @@ function processSourceFile(content: string, state: ProcessingState): void {
13531389 bracketDepth += ( line . match ( / \{ / g) || [ ] ) . length
13541390 bracketDepth -= ( line . match ( / \} / g) || [ ] ) . length
13551391
1356- // Check if we're entering a function scope
1392+ // Update scope
13571393 if ( / ^ ( e x p o r t \s + ) ? ( a s y n c \s + ) ? f u n c t i o n / . test ( trimmedLine ) ) {
1358- debugLog ( state , 'function-scope' , `Entering function scope: ${ trimmedLine } ` )
13591394 state . currentScope = 'function'
13601395 }
13611396
@@ -1372,28 +1407,26 @@ function processSourceFile(content: string, state: ProcessingState): void {
13721407 bracketDepth += ( line . match ( / \{ / g) || [ ] ) . length
13731408 bracketDepth -= ( line . match ( / \} / g) || [ ] ) . length
13741409
1375- // Check if the declaration is complete
1376- const isComplete = (
1377- parenDepth === 0
1378- && bracketDepth === 0
1379- && (
1410+ // Check if declaration is complete
1411+ if ( parenDepth === 0 && bracketDepth === 0 && ! trimmedLine . endsWith ( ',' ) ) {
1412+ const isComplete = (
13801413 trimmedLine . endsWith ( ';' )
13811414 || trimmedLine . endsWith ( '}' )
13821415 || ( ! trimmedLine . endsWith ( '{' ) && ! trimmedLine . endsWith ( ',' ) )
13831416 )
1384- )
1385-
1386- if ( isComplete ) {
1387- processBlock ( currentBlock , currentComments , state )
1388- currentBlock = [ ]
1389- currentComments = [ ]
1390- inDeclaration = false
1391- bracketDepth = 0
1392- parenDepth = 0
13931417
1394- // Reset scope after function ends
1395- if ( state . currentScope === 'function' ) {
1396- state . currentScope = 'top' // Reset currentScope here
1418+ if ( isComplete ) {
1419+ processBlock ( currentBlock , currentComments , state )
1420+ currentBlock = [ ]
1421+ currentComments = [ ]
1422+ inDeclaration = false
1423+ bracketDepth = 0
1424+ parenDepth = 0
1425+
1426+ // Reset scope after function ends
1427+ if ( state . currentScope === 'function' ) {
1428+ state . currentScope = 'top'
1429+ }
13971430 }
13981431 }
13991432 }
@@ -1515,49 +1548,45 @@ function processVariable(declaration: string, isExported: boolean, state: Proces
15151548 * Process function declarations with overloads
15161549 */
15171550function processFunction ( declaration : string , usedTypes ?: Set < string > , isExported = true ) : string {
1518- const cleanDeclaration = removeLeadingComments ( declaration ) . trim ( )
1519- const { name, params, returnType, generics } = extractFunctionSignature ( cleanDeclaration )
1520- debugLog ( undefined , 'process-function' , `Processing function declaration: ${ name } (${ params } ): ${ returnType } ` )
1551+ // Clean up declaration first
1552+ const cleanDeclaration = removeLeadingComments ( declaration ) . trim ( ) . replace ( / ^ e x p o r t \s + / , '' ) // Remove leading export if present
1553+
1554+ const signature = extractFunctionSignature ( cleanDeclaration )
15211555
1522- if ( ! name ) {
1523- console . error ( 'Function name could not be extracted from declaration:' , declaration )
1556+ if ( ! signature . name ) {
1557+ debugLog ( undefined , 'function-processing' , `Failed to process function: ${ cleanDeclaration } ` )
15241558 return ''
15251559 }
15261560
1561+ // Handle async functions
1562+ const isAsync = cleanDeclaration . includes ( 'async function' )
1563+ let returnType = signature . returnType
1564+ if ( isAsync && ! returnType . startsWith ( 'Promise<' ) && ! returnType . startsWith ( 'AsyncGenerator<' ) ) {
1565+ returnType = `Promise<${ returnType } >`
1566+ }
1567+
15271568 if ( usedTypes ) {
1528- trackUsedTypes ( `${ generics } ${ params } ${ returnType } ` , usedTypes )
1569+ trackUsedTypes ( `${ signature . generics } ${ signature . params } ${ returnType } ` , usedTypes )
15291570 }
15301571
1531- // Build the declaration string without function body
15321572 const parts = [
15331573 isExported ? 'export' : '' ,
15341574 'declare' ,
15351575 'function' ,
1536- name ,
1537- generics ,
1538- `(${ params } )` ,
1576+ signature . name ,
1577+ signature . generics ,
1578+ `(${ signature . params } )` ,
1579+ ':' ,
1580+ returnType ,
15391581 ]
15401582
1541- if ( returnType && returnType !== 'void' ) {
1542- parts . push ( ':' , returnType )
1543- }
1544-
1545- parts . push ( ';' )
1546-
1547- const ps = parts
1583+ return `${ parts
15481584 . filter ( Boolean )
15491585 . join ( ' ' )
1550- // Remove all spaces between name and parenthesis
15511586 . replace ( / ( \w + ) \s + \( / g, '$1(' )
1552- // Ensure no space before colon, one space after
15531587 . replace ( / \s * : \s * / g, ': ' )
1554- // Clean up spaces around semicolon
1555- . replace ( / \s * ; / g, ';' )
1556- . trim ( )
1557-
1558- debugLog ( undefined , 'process-function' , `Processed function declaration: ${ ps } ` )
1559-
1560- return ps
1588+ . replace ( / \s + ; / g, ';' )
1589+ . trim ( ) } ;`
15611590}
15621591
15631592/**
0 commit comments