@@ -26,35 +26,36 @@ export function processDeclarations(
26
26
const defaultExport : string [ ] = [ ]
27
27
28
28
for ( const decl of exports ) {
29
- const lines = decl . text . split ( '\n' ) . map ( line => line . trim ( ) ) . filter ( line => line )
30
-
31
- for ( const line of lines ) {
32
- if ( line . startsWith ( 'export default' ) ) {
33
- defaultExport . push ( line . endsWith ( ';' ) ? line : line + ';' )
34
- } else if ( line . startsWith ( 'export type {' ) || line . startsWith ( 'export {' ) ) {
35
- // Extract exported items from the line
36
- const match = line . match ( / e x p o r t \s + (?: t y p e \s + ) ? \{ \s * ( [ ^ } ] + ) \s * \} / )
37
- if ( match ) {
38
- const items = match [ 1 ] . split ( ',' ) . map ( item => item . trim ( ) )
39
- for ( const item of items ) {
40
- exportedItems . add ( item )
41
- }
42
- }
43
- const statement = line . endsWith ( ';' ) ? line : line + ';'
44
- if ( ! exportStatements . includes ( statement ) ) {
45
- exportStatements . push ( statement )
46
- }
47
- } else if ( line . startsWith ( 'export ' ) ) {
48
- const statement = line . endsWith ( ';' ) ? line : line + ';'
49
- if ( ! exportStatements . includes ( statement ) ) {
50
- exportStatements . push ( statement )
29
+ if ( decl . text . startsWith ( 'export default' ) ) {
30
+ const statement = decl . text . endsWith ( ';' ) ? decl . text : decl . text + ';'
31
+ defaultExport . push ( statement )
32
+ } else {
33
+ // Handle multi-line export statements properly
34
+ let exportText = decl . text . trim ( )
35
+
36
+ // Clean up the export text and ensure it ends with semicolon
37
+ if ( ! exportText . endsWith ( ';' ) ) {
38
+ exportText += ';'
39
+ }
40
+
41
+ // Extract exported items for tracking
42
+ const match = exportText . match ( / e x p o r t \s + (?: t y p e \s + ) ? \{ \s * ( [ ^ } ] + ) \s * \} / )
43
+ if ( match ) {
44
+ const items = match [ 1 ] . split ( ',' ) . map ( item => item . trim ( ) )
45
+ for ( const item of items ) {
46
+ exportedItems . add ( item )
51
47
}
52
48
}
49
+
50
+ if ( ! exportStatements . includes ( exportText ) ) {
51
+ exportStatements . push ( exportText )
52
+ }
53
53
}
54
54
}
55
55
56
56
// Filter imports to only include those that are used in exports or declarations
57
57
const usedImports = new Set < string > ( )
58
+ const usedImportItems = new Set < string > ( )
58
59
59
60
// Check which imports are needed based on exported functions and types
60
61
for ( const func of functions ) {
@@ -67,23 +68,59 @@ export function processDeclarations(
67
68
const importedItems = importMatch [ 1 ] . split ( ',' ) . map ( item => item . trim ( ) )
68
69
for ( const item of importedItems ) {
69
70
if ( funcDeclaration . includes ( item ) ) {
70
- usedImports . add ( imp . text )
71
+ usedImportItems . add ( item )
71
72
}
72
73
}
73
74
}
74
75
}
75
76
}
76
77
}
77
78
78
- // Check which imports are needed for interfaces and types (check all, not just exported)
79
+ // Check which imports are needed for exported variables
80
+ for ( const variable of variables ) {
81
+ if ( variable . isExported ) {
82
+ for ( const imp of imports ) {
83
+ // Handle mixed imports like: import { collect, type Collection } from 'module'
84
+ const importText = imp . text
85
+ const typeMatches = importText . match ( / t y p e \s + ( [ A - Z a - z _ $ ] [ A - Z a - z 0 - 9 _ $ ] * ) / g)
86
+ const valueMatches = importText . match ( / i m p o r t \s + \{ ( [ ^ } ] + ) \} / )
87
+
88
+ // Check type imports
89
+ if ( typeMatches ) {
90
+ for ( const typeMatch of typeMatches ) {
91
+ const typeName = typeMatch . replace ( 'type ' , '' ) . trim ( )
92
+ if ( variable . text . includes ( typeName ) ) {
93
+ usedImportItems . add ( typeName )
94
+ }
95
+ }
96
+ }
97
+
98
+ // Check value imports
99
+ if ( valueMatches ) {
100
+ const imports = valueMatches [ 1 ] . split ( ',' ) . map ( item =>
101
+ item . replace ( / t y p e \s + / , '' ) . trim ( )
102
+ )
103
+ for ( const importName of imports ) {
104
+ if ( variable . text . includes ( importName ) ) {
105
+ usedImportItems . add ( importName )
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+
113
+ // Check which imports are needed for interfaces and types (only exported ones)
79
114
for ( const iface of interfaces ) {
80
- for ( const imp of imports ) {
81
- const importMatch = imp . text . match ( / i m p o r t \s + (?: t y p e \s + ) ? \{ ? \s * ( [ ^ } ] + ) \s * \} ? \s + f r o m / )
82
- if ( importMatch ) {
83
- const importedItems = importMatch [ 1 ] . split ( ',' ) . map ( item => item . trim ( ) )
84
- for ( const item of importedItems ) {
85
- if ( iface . text . includes ( item ) ) {
86
- usedImports . add ( imp . text )
115
+ if ( iface . isExported ) {
116
+ for ( const imp of imports ) {
117
+ const importMatch = imp . text . match ( / i m p o r t \s + (?: t y p e \s + ) ? \{ ? \s * ( [ ^ } ] + ) \s * \} ? \s + f r o m / )
118
+ if ( importMatch ) {
119
+ const importedItems = importMatch [ 1 ] . split ( ',' ) . map ( item => item . trim ( ) )
120
+ for ( const item of importedItems ) {
121
+ if ( iface . text . includes ( item ) ) {
122
+ usedImportItems . add ( item )
123
+ }
87
124
}
88
125
}
89
126
}
@@ -98,7 +135,7 @@ export function processDeclarations(
98
135
const importedItems = importMatch [ 1 ] . split ( ',' ) . map ( item => item . trim ( ) )
99
136
for ( const item of importedItems ) {
100
137
if ( type . text . includes ( item ) ) {
101
- usedImports . add ( imp . text )
138
+ usedImportItems . add ( item )
102
139
}
103
140
}
104
141
}
@@ -110,30 +147,58 @@ export function processDeclarations(
110
147
for ( const item of exportedItems ) {
111
148
for ( const imp of imports ) {
112
149
if ( imp . text . includes ( item ) ) {
113
- usedImports . add ( imp . text )
150
+ // Extract the specific items from this import
151
+ const importMatch = imp . text . match ( / i m p o r t \s + (?: t y p e \s + ) ? \{ ? \s * ( [ ^ } ] + ) \s * \} ? \s + f r o m / )
152
+ if ( importMatch ) {
153
+ const importedItems = importMatch [ 1 ] . split ( ',' ) . map ( item => item . trim ( ) )
154
+ for ( const importedItem of importedItems ) {
155
+ if ( item === importedItem ) {
156
+ usedImportItems . add ( importedItem )
157
+ }
158
+ }
159
+ }
114
160
}
115
161
}
116
162
}
117
163
118
164
// Also check for value imports that are re-exported
119
165
for ( const exp of exports ) {
120
- if ( exp . text . includes ( 'export { generate }' ) ) {
121
- // Find the import for generate
122
- for ( const imp of imports ) {
123
- if ( imp . text . includes ( '{ generate }' ) ) {
124
- usedImports . add ( imp . text )
166
+ for ( const imp of imports ) {
167
+ const importMatch = imp . text . match ( / i m p o r t \s + (?: t y p e \s + ) ? \{ ? \s * ( [ ^ } ] + ) \s * \} ? \s + f r o m / )
168
+ if ( importMatch ) {
169
+ const importedItems = importMatch [ 1 ] . split ( ',' ) . map ( item => item . trim ( ) )
170
+ for ( const importedItem of importedItems ) {
171
+ if ( exp . text . includes ( importedItem ) ) {
172
+ usedImportItems . add ( importedItem )
173
+ }
125
174
}
126
175
}
127
176
}
128
177
}
129
178
130
- // Process and add used imports first
179
+ // Create filtered imports based on actually used items
131
180
const processedImports : string [ ] = [ ]
132
181
for ( const imp of imports ) {
133
- if ( usedImports . has ( imp . text ) ) {
134
- const processed = processImportDeclaration ( imp )
135
- if ( processed && processed . trim ( ) ) {
136
- processedImports . push ( processed )
182
+ const importMatch = imp . text . match ( / i m p o r t \s + (?: t y p e \s + ) ? \{ ? \s * ( [ ^ } ] + ) \s * \} ? \s + f r o m \s + [ ' " ] ( [ ^ ' " ] + ) [ ' " ] / )
183
+ if ( importMatch ) {
184
+ const importedItems = importMatch [ 1 ] . split ( ',' ) . map ( item => item . trim ( ) )
185
+ const usedItems = importedItems . filter ( item => {
186
+ const cleanItem = item . replace ( / ^ t y p e \s + / , '' ) . trim ( )
187
+ return usedImportItems . has ( cleanItem )
188
+ } )
189
+
190
+ if ( usedItems . length > 0 ) {
191
+ const source = importMatch [ 2 ]
192
+ const hasTypeImports = usedItems . some ( item => item . startsWith ( 'type ' ) )
193
+ const hasValueImports = usedItems . some ( item => ! item . startsWith ( 'type ' ) )
194
+
195
+ let importStatement = 'import '
196
+ if ( hasTypeImports && ! hasValueImports ) {
197
+ importStatement += 'type '
198
+ }
199
+ importStatement += `{ ${ usedItems . join ( ', ' ) } } from '${ source } ';`
200
+
201
+ processedImports . push ( importStatement )
137
202
}
138
203
}
139
204
}
@@ -983,4 +1048,4 @@ function inferFunctionType(value: string, inUnion: boolean = false): string {
983
1048
984
1049
const funcType = '() => unknown'
985
1050
return inUnion ? `(${ funcType } )` : funcType
986
- }
1051
+ }
0 commit comments