@@ -6,13 +6,6 @@ interface ProcessedMethod {
6
6
signature : string
7
7
}
8
8
9
- interface BalancedSymbolResult {
10
- /** The extracted content including the opening and closing symbols */
11
- content : string
12
- /** The remaining text after the closing symbol */
13
- rest : string
14
- }
15
-
16
9
function cleanParameterTypes ( params : string ) : string {
17
10
debugLog ( undefined , 'params' , `Cleaning parameters: ${ params } ` )
18
11
@@ -146,7 +139,7 @@ export function extractDtsTypes(sourceCode: string): string {
146
139
state . dtsLines . forEach ( ( line ) => {
147
140
if ( line . trim ( ) && ! line . startsWith ( 'import' ) ) {
148
141
trackTypeUsage ( line , state . importTracking )
149
- trackValueUsage ( line , state . importTracking , state . dtsLines )
142
+ trackValueUsage ( line , state . importTracking )
150
143
}
151
144
} )
152
145
@@ -466,34 +459,85 @@ function extractFunctionType(value: string): string | null {
466
459
*/
467
460
function generateOptimizedImports ( state : ImportTrackingState ) : string [ ] {
468
461
const imports : string [ ] = [ ]
462
+ const seenImports = new Set < string > ( )
469
463
470
- // Generate type imports
464
+ debugLog ( undefined , 'import-gen' , `Generating optimized imports. Default export value: ${ state . defaultExportValue } ` )
465
+
466
+ // Handle type imports first
471
467
for ( const [ module , types ] of state . typeImports ) {
472
- const usedTypes = Array . from ( types )
473
- . filter ( t => state . usedTypes . has ( t ) )
468
+ const typeImports = Array . from ( types )
469
+ . filter ( t => state . usedTypes . has ( t ) || state . exportedValues ?. has ( t ) )
470
+ . map ( ( t ) => {
471
+ const alias = state . valueAliases . get ( t )
472
+ return alias ? `${ t } as ${ alias } ` : t
473
+ } )
474
474
. sort ( )
475
475
476
- if ( usedTypes . length > 0 ) {
477
- imports . push ( `import type { ${ usedTypes . join ( ', ' ) } } from '${ module } '` )
476
+ if ( typeImports . length > 0 ) {
477
+ const importStatement = `import type { ${ typeImports . join ( ', ' ) } } from '${ module } '`
478
+ if ( ! seenImports . has ( importStatement ) ) {
479
+ imports . push ( importStatement )
480
+ seenImports . add ( importStatement )
481
+ debugLog ( undefined , 'import-add' , `Added type import: ${ importStatement } ` )
482
+ }
483
+ }
484
+ }
485
+
486
+ // Group value imports by module
487
+ const moduleImports = new Map < string , Set < string > > ( )
488
+ const importAliases = new Map < string , string > ( )
489
+
490
+ // Handle default export
491
+ if ( state . defaultExportValue ) {
492
+ const originalName = Array . from ( state . valueAliases . entries ( ) )
493
+ . find ( ( [ alias ] ) => alias === state . defaultExportValue ) ?. [ 1 ]
494
+
495
+ if ( originalName ) {
496
+ debugLog ( undefined , 'import-default' , `Found original name ${ originalName } for default export alias ${ state . defaultExportValue } ` )
497
+ const module = state . importSources . get ( originalName )
498
+ if ( module ) {
499
+ if ( ! moduleImports . has ( module ) ) {
500
+ moduleImports . set ( module , new Set ( ) )
501
+ }
502
+ moduleImports . get ( module ) ! . add ( originalName )
503
+ importAliases . set ( originalName , state . defaultExportValue )
504
+ }
478
505
}
479
506
}
480
507
481
- // Generate value imports
508
+ // Handle regular value imports
482
509
for ( const [ module , values ] of state . valueImports ) {
483
510
const usedValues = Array . from ( values )
484
- . filter ( v => state . usedValues . has ( v ) )
485
- // Only include values that appear in actual declarations
486
- . filter ( v => dtsLines . some ( line =>
487
- line . includes ( `declare ${ v } ` )
488
- || line . includes ( `export declare ${ v } ` )
489
- || line . includes ( `export { ${ v } ` )
490
- || line . includes ( `, ${ v } ` )
491
- || line . includes ( `${ v } }` ) ,
492
- ) )
493
- . sort ( )
511
+ . filter ( ( v ) => {
512
+ const isUsed = state . usedValues . has ( v )
513
+ || state . exportedValues ?. has ( v )
514
+ || v === state . defaultExportValue
515
+ debugLog ( undefined , 'import-filter' , `Checking ${ v } : used=${ isUsed } ` )
516
+ return isUsed
517
+ } )
494
518
495
519
if ( usedValues . length > 0 ) {
496
- imports . push ( `import { ${ usedValues . join ( ', ' ) } } from '${ module } '` )
520
+ if ( ! moduleImports . has ( module ) ) {
521
+ moduleImports . set ( module , new Set ( ) )
522
+ }
523
+ usedValues . forEach ( v => moduleImports . get ( module ) ! . add ( v ) )
524
+ }
525
+ }
526
+
527
+ // Generate value import statements
528
+ for ( const [ module , values ] of moduleImports ) {
529
+ const importParts = Array . from ( values ) . map ( ( value ) => {
530
+ const alias = importAliases . get ( value )
531
+ return alias ? `${ value } as ${ alias } ` : value
532
+ } ) . sort ( )
533
+
534
+ if ( importParts . length > 0 ) {
535
+ const importStatement = `import { ${ importParts . join ( ', ' ) } } from '${ module } '`
536
+ if ( ! seenImports . has ( importStatement ) ) {
537
+ imports . push ( importStatement )
538
+ seenImports . add ( importStatement )
539
+ debugLog ( undefined , 'import-add' , `Added value import: ${ importStatement } ` )
540
+ }
497
541
}
498
542
}
499
543
@@ -555,19 +599,32 @@ function formatOutput(state: ProcessingState): string {
555
599
// Deduplicate and format imports
556
600
state . dtsLines
557
601
. filter ( line => line . startsWith ( 'import' ) )
558
- . forEach ( imp => imports . add ( imp ) )
602
+ . forEach ( imp => imports . add ( imp . replace ( / ; + $ / , '' ) ) ) // Remove any existing semicolons
559
603
560
- state . dtsLines = [
561
- ...Array . from ( imports ) ,
604
+ // Get all non-import lines
605
+ const declarations = state . dtsLines
606
+ . filter ( line => ! line . startsWith ( 'import' ) )
607
+ . map ( line => line . replace ( / ; + $ / , '' ) ) // Clean up any multiple semicolons
608
+
609
+ // Add default exports from state.defaultExports
610
+ const defaultExports = Array . from ( state . defaultExports )
611
+ . map ( exp => exp . replace ( / ; + $ / , '' ) ) // Clean up any multiple semicolons
612
+
613
+ // Reconstruct the output with single semicolons where needed
614
+ const output = [
615
+ ...Array . from ( imports ) . map ( imp => `${ imp } ;` ) ,
616
+ '' ,
617
+ ...declarations . map ( decl => decl . trim ( ) !== '' ? `${ decl } ;` : '' ) ,
562
618
'' ,
563
- ...state . dtsLines . filter ( line => ! line . startsWith ( 'import' ) ) ,
619
+ ...defaultExports . map ( exp => ` ${ exp } ;` ) ,
564
620
]
565
621
566
622
// Remove comments and normalize whitespace
567
- return `${ state . dtsLines
623
+ return `${ output
568
624
. map ( line => line . replace ( / \/ \* [ \s \S ] * ?\* \/ | \/ \/ .* / g, '' ) )
569
625
. filter ( Boolean )
570
- . join ( '\n' ) } \n`
626
+ . join ( '\n' )
627
+ } \n`
571
628
}
572
629
573
630
/**
@@ -630,8 +687,11 @@ function createImportTrackingState(): ImportTrackingState {
630
687
return {
631
688
typeImports : new Map ( ) ,
632
689
valueImports : new Map ( ) ,
690
+ valueAliases : new Map ( ) ,
633
691
usedTypes : new Set ( ) ,
634
692
usedValues : new Set ( ) ,
693
+ exportedValues : null ,
694
+ defaultExportValue : null ,
635
695
}
636
696
}
637
697
@@ -1276,6 +1336,9 @@ function processDefaultExportBlock(cleanDeclaration: string, state: ProcessingSt
1276
1336
if ( ! cleanDeclaration . startsWith ( 'export default' ) )
1277
1337
return false
1278
1338
1339
+ const exportedValue = cleanDeclaration . replace ( / ^ e x p o r t \s + d e f a u l t \s + / , '' ) . replace ( / ; $ / , '' )
1340
+ state . importTracking . defaultExportValue = exportedValue
1341
+
1279
1342
// Store the complete default export statement
1280
1343
const defaultExport = cleanDeclaration . endsWith ( ';' )
1281
1344
? cleanDeclaration
@@ -1599,31 +1662,60 @@ function processSourceFile(content: string, state: ProcessingState): void {
1599
1662
/**
1600
1663
* Process imports and track their usage
1601
1664
*/
1602
- export function processImports ( line : string , state : ImportTrackingState ) : void {
1603
- // Handle type imports
1604
- const typeImportMatch = line . match ( / i m p o r t \s + t y p e \s * \{ ( [ ^ } ] + ) \} \s * f r o m \s * [ ' " ] ( [ ^ ' " ] + ) [ ' " ] / )
1665
+ function processImports ( line : string , state : ImportTrackingState ) : void {
1666
+ debugLog ( undefined , 'import-processing' , `Processing import line: ${ line } ` )
1667
+
1668
+ // Initialize collections if they don't exist
1669
+ if ( ! state . valueAliases )
1670
+ state . valueAliases = new Map ( )
1671
+ if ( ! state . exportedValues )
1672
+ state . exportedValues = new Set ( )
1673
+ if ( ! state . importSources )
1674
+ state . importSources = new Map ( )
1675
+
1676
+ // Handle type imports - more specific regex to catch type imports with and without braces
1677
+ const typeImportMatch = line . match ( / i m p o r t \s + t y p e \s * (?: \{ ( [ ^ } ] + ) \} | ( [ ^ ; \s ] + ) ) \s * f r o m \s * [ ' " ] ( [ ^ ' " ] + ) [ ' " ] / )
1605
1678
if ( typeImportMatch ) {
1606
- const [ , names , module ] = typeImportMatch
1679
+ const [ , bracedTypes , singleType , module ] = typeImportMatch
1680
+ const types = bracedTypes || singleType
1681
+ debugLog ( undefined , 'import-type' , `Found type imports from ${ module } : ${ types } ` )
1682
+
1607
1683
if ( ! state . typeImports . has ( module ) ) {
1608
1684
state . typeImports . set ( module , new Set ( ) )
1609
1685
}
1610
- names . split ( ',' ) . forEach ( ( name ) => {
1611
- const cleanName = name . trim ( ) . split ( / \s + a s \s + / ) . shift ( ) ! // Use shift() to get original name before 'as'
1612
- state . typeImports . get ( module ) ! . add ( cleanName )
1613
- } )
1686
+
1687
+ if ( types ) {
1688
+ types . split ( ',' ) . forEach ( ( type ) => {
1689
+ const [ original , alias ] = type . trim ( ) . split ( / \s + a s \s + / ) . map ( n => n . trim ( ) )
1690
+ state . typeImports . get ( module ) ! . add ( original )
1691
+ if ( alias ) {
1692
+ state . valueAliases . set ( alias , original )
1693
+ debugLog ( undefined , 'import-alias' , `Registered type alias: ${ original } as ${ alias } ` )
1694
+ }
1695
+ } )
1696
+ }
1614
1697
return
1615
1698
}
1616
1699
1617
- // Handle value imports
1700
+ // Handle value imports (rest of the code remains the same)
1618
1701
const valueImportMatch = line . match ( / i m p o r t \s * \{ ( [ ^ } ] + ) \} \s * f r o m \s * [ ' " ] ( [ ^ ' " ] + ) [ ' " ] / )
1619
1702
if ( valueImportMatch ) {
1620
1703
const [ , names , module ] = valueImportMatch
1704
+ debugLog ( undefined , 'import-value' , `Found value imports from ${ module } : ${ names } ` )
1705
+
1621
1706
if ( ! state . valueImports . has ( module ) ) {
1622
1707
state . valueImports . set ( module , new Set ( ) )
1623
1708
}
1709
+
1624
1710
names . split ( ',' ) . forEach ( ( name ) => {
1625
- const cleanName = name . trim ( ) . split ( / \s + a s \s + / ) . shift ( ) ! // Use shift() to get original name before 'as'
1626
- state . valueImports . get ( module ) ! . add ( cleanName )
1711
+ const [ original , alias ] = name . trim ( ) . split ( / \s + a s \s + / ) . map ( n => n . trim ( ) )
1712
+ state . valueImports . get ( module ) ! . add ( original )
1713
+ state . importSources . set ( original , module )
1714
+
1715
+ if ( alias ) {
1716
+ state . valueAliases . set ( alias , original )
1717
+ debugLog ( undefined , 'import-alias' , `Registered value alias: ${ original } as ${ alias } ` )
1718
+ }
1627
1719
} )
1628
1720
}
1629
1721
}
@@ -2073,35 +2165,6 @@ function processPropertyValue(value: string, indentLevel: number, state?: Proces
2073
2165
return 'unknown'
2074
2166
}
2075
2167
2076
- const REGEX = {
2077
- typePattern : / (?: t y p e o f \s + ) ? ( [ A - Z ] \w * (?: < [ ^ > ] + > ) ? ) | e x t e n d s \s + ( [ A - Z ] \w * (?: < [ ^ > ] + > ) ? ) / g,
2078
- } as const
2079
-
2080
- /**
2081
- * Track used types in declarations
2082
- */
2083
- function trackUsedTypes ( content : string , usedTypes : Set < string > ) : void {
2084
- let match : any
2085
- while ( ( match = REGEX . typePattern . exec ( content ) ) !== null ) {
2086
- const type = match [ 1 ] || match [ 2 ]
2087
- if ( type ) {
2088
- const [ baseType , ...genericParams ] = type . split ( / [ < > ] / )
2089
- if ( baseType && / ^ [ A - Z ] / . test ( baseType ) )
2090
- usedTypes . add ( baseType )
2091
-
2092
- if ( genericParams . length > 0 ) {
2093
- genericParams . forEach ( ( param : any ) => {
2094
- const nestedTypes = param . split ( / [ , \s ] / )
2095
- nestedTypes . forEach ( ( t : any ) => {
2096
- if ( / ^ [ A - Z ] / . test ( t ) )
2097
- usedTypes . add ( t )
2098
- } )
2099
- } )
2100
- }
2101
- }
2102
- }
2103
- }
2104
-
2105
2168
/**
2106
2169
* Track type usage in declarations
2107
2170
*/
@@ -2119,41 +2182,35 @@ function trackTypeUsage(content: string, state: ImportTrackingState): void {
2119
2182
/**
2120
2183
* Track value usage in declarations
2121
2184
*/
2122
- function trackValueUsage ( content : string , state : ImportTrackingState , dtsLines ?: string [ ] ) : void {
2185
+ function trackValueUsage ( content : string , state : ImportTrackingState ) : void {
2186
+ // Track exports
2187
+ const exportMatch = content . match ( / e x p o r t \s * \{ ( [ ^ } ] + ) \} / )
2188
+ if ( exportMatch ) {
2189
+ const exports = exportMatch [ 1 ] . split ( ',' ) . map ( e => e . trim ( ) )
2190
+ exports . forEach ( ( e ) => {
2191
+ const [ name ] = e . split ( / \s + a s \s + / )
2192
+ state . exportedValues . add ( name . trim ( ) )
2193
+ } )
2194
+ }
2195
+
2123
2196
// Track values in declarations
2124
2197
const patterns = [
2125
- // Export statements in declarations
2126
2198
/ e x p o r t \s + d e c l a r e \s + \{ \s * ( [ ^ } \s ] + ) (?: \s * , \s * [ ^ } \s ] + ) * \s * \} / g,
2127
- // Declared exports
2128
2199
/ e x p o r t \s + d e c l a r e \s + (?: c o n s t | f u n c t i o n | c l a s s ) \s + ( [ a - z A - Z _ $ ] [ \w $ ] * ) / g,
2129
- // Direct exports
2130
2200
/ e x p o r t \s + \{ \s * ( [ ^ } \s ] + ) (?: \s * , \s * [ ^ } \s ] + ) * \s * \} / g,
2131
2201
]
2132
2202
2133
2203
for ( const pattern of patterns ) {
2134
2204
let match
2135
2205
while ( ( match = pattern . exec ( content ) ) !== null ) {
2136
2206
const values = match [ 1 ] . split ( ',' ) . map ( v => v . trim ( ) )
2137
- for ( const value of values ) {
2207
+ values . forEach ( ( value ) => {
2138
2208
if ( ! [ 'type' , 'interface' , 'declare' , 'extends' , 'implements' , 'function' , 'const' , 'let' , 'var' ] . includes ( value ) ) {
2139
2209
state . usedValues . add ( value )
2140
2210
}
2141
- }
2211
+ } )
2142
2212
}
2143
2213
}
2144
-
2145
- // Track values in the final output lines if provided
2146
- if ( dtsLines ) {
2147
- dtsLines . forEach ( ( line ) => {
2148
- if ( line . includes ( 'declare' ) || line . includes ( 'export' ) ) {
2149
- // Look for exported values
2150
- const exportMatch = line . match ( / (?: e x p o r t | d e c l a r e ) \s + (?: c o n s t | f u n c t i o n | c l a s s ) \s + ( [ a - z A - Z _ $ ] [ \w $ ] * ) / )
2151
- if ( exportMatch ) {
2152
- state . usedValues . add ( exportMatch [ 1 ] )
2153
- }
2154
- }
2155
- } )
2156
- }
2157
2214
}
2158
2215
2159
2216
function debugLog ( state : ProcessingState | undefined , category : string , message : string ) : void {
0 commit comments