@@ -199,9 +199,8 @@ function extractBalancedSymbols(text: string, openSymbol: string, closeSymbol: s
199
199
* Extract complete function signature using regex
200
200
*/
201
201
function extractFunctionSignature ( declaration : string ) : FunctionSignature {
202
- // Remove comments and clean up the declaration
203
202
const cleanDeclaration = removeLeadingComments ( declaration ) . trim ( )
204
- const functionPattern = / ^ \s * ( e x p o r t \s + ) ? ( a s y n c \s + ) ? f u n c t i o n \s * (?: ( \* ) \s * ) ? ( [ ^ ( < \s ] + ) /
203
+ const functionPattern = / ^ \s * ( 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 $ ] * ) /
205
204
const functionMatch = cleanDeclaration . match ( functionPattern )
206
205
207
206
if ( ! functionMatch ) {
@@ -237,10 +236,10 @@ function extractFunctionSignature(declaration: string): FunctionSignature {
237
236
}
238
237
}
239
238
240
- // Extract return type - keep it exactly as specified
239
+ // Extract return type
241
240
let returnType = 'void'
242
241
if ( rest . startsWith ( ':' ) ) {
243
- const match = rest . match ( / ^ : \s * ( [ ^ { ] + ) / )
242
+ const match = rest . match ( / ^ : \s * ( [ ^ = > { ] + ) / )
244
243
if ( match ) {
245
244
returnType = match [ 1 ] . trim ( )
246
245
}
@@ -828,43 +827,65 @@ function inferReturnType(value: string, declaration: string): string {
828
827
const isAsync = declaration . startsWith ( 'async ' ) || value . includes ( 'async ' ) || ( value . includes ( '=>' ) && value . includes ( 'await' ) )
829
828
debugLog ( undefined , 'return-type' , `Is async method: ${ isAsync } ` )
830
829
831
- let effectiveReturnType = 'void'
830
+ // Check for generator functions
831
+ const isGenerator = declaration . includes ( 'function*' ) || value . includes ( 'function*' )
832
+
833
+ let effectiveReturnType = 'unknown'
832
834
833
835
// Check for known return patterns
834
836
if ( value . includes ( 'throw' ) ) {
835
837
effectiveReturnType = 'never'
836
838
}
837
- else if ( value . includes ( 'toISOString()' ) || value . includes ( 'toString()' ) ) {
839
+ else if ( value . includes ( 'toISOString()' ) ) {
838
840
effectiveReturnType = 'string'
839
841
}
840
842
else if ( value . includes ( 'Intl.NumberFormat' ) && value . includes ( 'format' ) ) {
841
843
effectiveReturnType = 'string'
842
844
}
843
- else if ( value . match ( / ^ \{ \s * \/ \/ [ ^ } ] * \} $ / ) || value . match ( / ^ \{ \s * \} $ / ) || value . match ( / ^ \{ \s * \/ \* [ \s \S ] * ?\* \/ \s * \} $ / ) ) {
844
- effectiveReturnType = 'void'
845
+ else if ( value . includes ( 'Promise.all' ) ) {
846
+ effectiveReturnType = 'Promise<unknown[]>'
847
+ }
848
+ else if ( value . includes ( 'fetch(' ) ) {
849
+ effectiveReturnType = 'Promise<unknown>'
845
850
}
846
851
else {
847
852
// Check for return statements
848
853
const returnMatch = value . match ( / r e t u r n \s + ( [ ^ ; \s ] + ) / )
849
854
if ( returnMatch ) {
850
855
const returnValue = returnMatch [ 1 ]
851
- if ( / ^ [ ' " ` ] / . test ( returnValue ) )
856
+ if ( returnValue . includes ( 'as ' ) ) {
857
+ const typeAssertionMatch = returnValue . match ( / a s \s + ( [ ^ ; \s ] + ) / )
858
+ if ( typeAssertionMatch ) {
859
+ effectiveReturnType = typeAssertionMatch [ 1 ]
860
+ }
861
+ }
862
+ else if ( / ^ [ ' " ` ] / . test ( returnValue ) ) {
852
863
effectiveReturnType = 'string'
853
- else if ( ! Number . isNaN ( Number ( returnValue ) ) )
864
+ }
865
+ else if ( ! Number . isNaN ( Number ( returnValue ) ) ) {
854
866
effectiveReturnType = 'number'
855
- else if ( returnValue === 'true' || returnValue === 'false' )
867
+ }
868
+ else if ( returnValue === 'true' || returnValue === 'false' ) {
856
869
effectiveReturnType = 'boolean'
857
- else if ( returnValue === 'null' )
870
+ }
871
+ else if ( returnValue === 'null' ) {
858
872
effectiveReturnType = 'null'
859
- else if ( returnValue === 'undefined' )
873
+ }
874
+ else if ( returnValue === 'undefined' ) {
860
875
effectiveReturnType = 'undefined'
861
- else effectiveReturnType = 'unknown'
876
+ }
877
+ else {
878
+ effectiveReturnType = 'unknown'
879
+ }
862
880
}
863
881
}
864
882
865
- // Wrap in Promise for async functions
866
- if ( isAsync && ! effectiveReturnType . includes ( 'Promise' ) ) {
867
- debugLog ( undefined , 'return-type' , `Wrapping ${ effectiveReturnType } in Promise for async method` )
883
+ // Handle generators
884
+ if ( isGenerator ) {
885
+ effectiveReturnType = `Generator<unknown, ${ effectiveReturnType } , unknown>`
886
+ }
887
+ // Handle async functions
888
+ else if ( isAsync && ! effectiveReturnType . includes ( 'Promise' ) ) {
868
889
effectiveReturnType = `Promise<${ effectiveReturnType } >`
869
890
}
870
891
@@ -921,7 +942,7 @@ export function isDefaultExport(line: string): boolean {
921
942
return line . trim ( ) . startsWith ( 'export default' )
922
943
}
923
944
924
- function isDeclarationStart ( line : string ) : boolean {
945
+ export function isDeclarationStart ( line : string ) : boolean {
925
946
return (
926
947
line . startsWith ( 'export ' )
927
948
|| line . startsWith ( 'interface ' )
@@ -933,6 +954,7 @@ function isDeclarationStart(line: string): boolean {
933
954
|| line . startsWith ( 'declare module' )
934
955
|| / ^ e x p o r t \s + (?: i n t e r f a c e | t y p e | c o n s t | f u n c t i o n | a s y n c \s + f u n c t i o n ) / . test ( line )
935
956
|| line . startsWith ( 'export async function' )
957
+ || line . startsWith ( 'export function' ) // Added this line
936
958
)
937
959
}
938
960
@@ -1045,7 +1067,7 @@ export function processBlock(lines: string[], comments: string[], state: Process
1045
1067
return
1046
1068
}
1047
1069
1048
- if ( cleanDeclaration . startsWith ( ' function' ) || cleanDeclaration . startsWith ( 'export function' ) ) {
1070
+ if ( / ^ ( e x p o r t \s + ) ? ( a s y n c \s + ) ? f u n c t i o n \s * ( \* ) ? / . test ( cleanDeclaration ) ) {
1049
1071
const isExported = cleanDeclaration . startsWith ( 'export' )
1050
1072
state . dtsLines . push ( processFunction ( declarationText , state . usedTypes , isExported ) )
1051
1073
return
@@ -1217,16 +1239,12 @@ function processSourceFile(content: string, state: ProcessingState): void {
1217
1239
const trimmedLine = line . trim ( )
1218
1240
1219
1241
// Track comments
1220
- if ( trimmedLine . startsWith ( '/*' ) ) {
1221
- currentComments . push ( line )
1222
- continue
1223
- }
1224
- if ( trimmedLine . startsWith ( '//' ) ) {
1242
+ if ( trimmedLine . startsWith ( '/*' ) || trimmedLine . startsWith ( '//' ) ) {
1225
1243
currentComments . push ( line )
1226
1244
continue
1227
1245
}
1228
1246
1229
- // Track brackets and parentheses for nesting depth
1247
+ // Start of a new declaration
1230
1248
if ( isDeclarationStart ( trimmedLine ) ) {
1231
1249
if ( inDeclaration && currentBlock . length > 0 ) {
1232
1250
processBlock ( currentBlock , currentComments , state )
@@ -1238,7 +1256,7 @@ function processSourceFile(content: string, state: ProcessingState): void {
1238
1256
inDeclaration = true
1239
1257
currentBlock = [ line ]
1240
1258
1241
- // Initialize depths for the first line
1259
+ // Update depths
1242
1260
parenDepth += ( line . match ( / \( / g) || [ ] ) . length
1243
1261
parenDepth -= ( line . match ( / \) / g) || [ ] ) . length
1244
1262
bracketDepth += ( line . match ( / \{ / g) || [ ] ) . length
@@ -1247,7 +1265,7 @@ function processSourceFile(content: string, state: ProcessingState): void {
1247
1265
continue
1248
1266
}
1249
1267
1250
- // If we're in a declaration, track the nesting
1268
+ // If in a declaration, collect lines
1251
1269
if ( inDeclaration ) {
1252
1270
currentBlock . push ( line )
1253
1271
@@ -1260,16 +1278,14 @@ function processSourceFile(content: string, state: ProcessingState): void {
1260
1278
// Check if the declaration is complete
1261
1279
const isComplete = (
1262
1280
parenDepth === 0
1263
- && bracketDepth === 0 && (
1281
+ && bracketDepth === 0
1282
+ && (
1264
1283
trimmedLine . endsWith ( ';' )
1265
1284
|| trimmedLine . endsWith ( '}' )
1266
- || trimmedLine . endsWith ( ',' )
1267
- || trimmedLine . match ( / \b a s \s + c o n s t [ , ; ] ? $ / )
1285
+ || ( ! trimmedLine . endsWith ( '{' ) && ! trimmedLine . endsWith ( ',' ) ) // Function overloads
1268
1286
)
1269
1287
)
1270
1288
1271
- debugLog ( state , 'source-processing' , `Line "${ trimmedLine } ": parenDepth=${ parenDepth } , bracketDepth=${ bracketDepth } , complete=${ isComplete } ` )
1272
-
1273
1289
if ( isComplete ) {
1274
1290
processBlock ( currentBlock , currentComments , state )
1275
1291
currentBlock = [ ]
@@ -1401,17 +1417,13 @@ export function processFunction(
1401
1417
usedTypes ?: Set < string > ,
1402
1418
isExported = true ,
1403
1419
) : string {
1404
- // Remove comments from the declaration for parsing
1405
1420
const cleanDeclaration = removeLeadingComments ( declaration ) . trim ( )
1406
1421
1407
- const {
1408
- name,
1409
- params,
1410
- returnType,
1411
- generics,
1412
- } = extractFunctionSignature ( cleanDeclaration )
1422
+ // Determine if the function has a body
1423
+ const hasBody = / \{ [ \s \S ] * \} $ / . test ( cleanDeclaration )
1424
+
1425
+ const { name, params, returnType, generics } = extractFunctionSignature ( cleanDeclaration )
1413
1426
1414
- // Track used types if provided
1415
1427
if ( usedTypes ) {
1416
1428
trackUsedTypes ( `${ generics } ${ params } ${ returnType } ` , usedTypes )
1417
1429
}
@@ -1424,15 +1436,17 @@ export function processFunction(
1424
1436
name ,
1425
1437
generics ,
1426
1438
`(${ params } )` ,
1427
- ':' ,
1428
- returnType ,
1429
- ';' ,
1430
1439
]
1431
1440
1441
+ if ( returnType && returnType !== 'void' ) {
1442
+ parts . push ( ':' , returnType )
1443
+ }
1444
+
1445
+ parts . push ( ';' )
1446
+
1432
1447
return parts
1433
1448
. filter ( Boolean )
1434
1449
. join ( ' ' )
1435
- // Include ':' in the character classes to handle spacing around colons
1436
1450
. replace ( / \s + ( [ < > ( ) , ; : ] ) / g, '$1' )
1437
1451
. replace ( / ( [ < > ( ) , ; : ] ) \s + / g, '$1 ' )
1438
1452
. replace ( / \s { 2 , } / g, ' ' )
0 commit comments