@@ -29,6 +29,13 @@ export class ImportManager {
29
29
new Map < ts . ImportDeclaration , { propertyName ?: ts . Identifier , importName : ts . Identifier } [ ] > ( ) ;
30
30
/** Map of source-files and their previously used identifier names. */
31
31
private usedIdentifierNames = new Map < ts . SourceFile , string [ ] > ( ) ;
32
+ /** Map of source files and the new imports that have to be added to them. */
33
+ private newImports : Map < ts . SourceFile , {
34
+ importStartIndex : number ,
35
+ defaultImports : Map < string , ts . Identifier > ,
36
+ namedImports : Map < string , ts . ImportSpecifier [ ] > ,
37
+ } > = new Map ( ) ;
38
+
32
39
/**
33
40
* Array of previously resolved symbol imports. Cache can be re-used to return
34
41
* the same identifier without checking the source-file again.
@@ -142,37 +149,34 @@ export class ImportManager {
142
149
}
143
150
144
151
let identifier : ts . Identifier | null = null ;
145
- let newImport : ts . ImportDeclaration | null = null ;
152
+
153
+ if ( ! this . newImports . has ( sourceFile ) ) {
154
+ this . newImports . set ( sourceFile , {
155
+ importStartIndex,
156
+ defaultImports : new Map ( ) ,
157
+ namedImports : new Map ( ) ,
158
+ } ) ;
159
+ }
146
160
147
161
if ( symbolName ) {
148
162
const propertyIdentifier = ts . factory . createIdentifier ( symbolName ) ;
149
163
const generatedUniqueIdentifier = this . _getUniqueIdentifier ( sourceFile , symbolName ) ;
150
164
const needsGeneratedUniqueName = generatedUniqueIdentifier . text !== symbolName ;
165
+ const importMap = this . newImports . get ( sourceFile ) ! . namedImports ;
151
166
identifier = needsGeneratedUniqueName ? generatedUniqueIdentifier : propertyIdentifier ;
152
167
153
- newImport = createImportDeclaration (
154
- undefined ,
155
- ts . factory . createImportClause (
156
- false , undefined ,
157
- ts . factory . createNamedImports ( [ ts . factory . createImportSpecifier (
158
- false , needsGeneratedUniqueName ? propertyIdentifier : undefined , identifier ) ] ) ) ,
159
- ts . factory . createStringLiteral ( moduleName ) ) ;
168
+ if ( ! importMap . has ( moduleName ) ) {
169
+ importMap . set ( moduleName , [ ] ) ;
170
+ }
171
+
172
+ importMap . get ( moduleName ) ! . push ( ts . factory . createImportSpecifier (
173
+ false , needsGeneratedUniqueName ? propertyIdentifier : undefined , identifier ) ) ;
160
174
} else {
175
+ const importMap = this . newImports . get ( sourceFile ) ! . defaultImports ;
161
176
identifier = this . _getUniqueIdentifier ( sourceFile , 'defaultExport' ) ;
162
- newImport = createImportDeclaration (
163
- undefined , ts . factory . createImportClause ( false , identifier , undefined ) ,
164
- ts . factory . createStringLiteral ( moduleName ) ) ;
177
+ importMap . set ( moduleName , identifier ) ;
165
178
}
166
179
167
- const newImportText = this . printer . printNode ( ts . EmitHint . Unspecified , newImport , sourceFile ) ;
168
- // If the import is generated at the start of the source file, we want to add
169
- // a new-line after the import. Otherwise if the import is generated after an
170
- // existing import, we need to prepend a new-line so that the import is not on
171
- // the same line as the existing import anchor.
172
- this . getUpdateRecorder ( sourceFile )
173
- . addNewImport (
174
- importStartIndex , importStartIndex === 0 ? `${ newImportText } \n` : `\n${ newImportText } ` ) ;
175
-
176
180
// Keep track of all generated imports so that we don't generate duplicate
177
181
// similar imports as these can't be statically analyzed in the source-file yet.
178
182
this . importCache . push ( { sourceFile, symbolName, moduleName, identifier} ) ;
@@ -200,6 +204,30 @@ export class ImportManager {
200
204
this . printer . printNode ( ts . EmitHint . Unspecified , newNamedBindings , sourceFile ) ;
201
205
recorder . updateExistingImport ( namedBindings , newNamedBindingsText ) ;
202
206
} ) ;
207
+
208
+ this . newImports . forEach ( ( { importStartIndex, defaultImports, namedImports} , sourceFile ) => {
209
+ const recorder = this . getUpdateRecorder ( sourceFile ) ;
210
+
211
+ defaultImports . forEach ( ( identifier , moduleName ) => {
212
+ const newImport = createImportDeclaration (
213
+ undefined , ts . factory . createImportClause ( false , identifier , undefined ) ,
214
+ ts . factory . createStringLiteral ( moduleName ) ) ;
215
+
216
+ recorder . addNewImport (
217
+ importStartIndex , this . _getNewImportText ( importStartIndex , newImport , sourceFile ) ) ;
218
+ } ) ;
219
+
220
+ namedImports . forEach ( ( specifiers , moduleName ) => {
221
+ const newImport = createImportDeclaration (
222
+ undefined ,
223
+ ts . factory . createImportClause (
224
+ false , undefined , ts . factory . createNamedImports ( specifiers ) ) ,
225
+ ts . factory . createStringLiteral ( moduleName ) ) ;
226
+
227
+ recorder . addNewImport (
228
+ importStartIndex , this . _getNewImportText ( importStartIndex , newImport , sourceFile ) ) ;
229
+ } ) ;
230
+ } ) ;
203
231
}
204
232
205
233
/** Gets an unique identifier with a base name for the given source file. */
@@ -260,6 +288,19 @@ export class ImportManager {
260
288
}
261
289
return commentRanges [ commentRanges . length - 1 ] ! . end ;
262
290
}
291
+
292
+ /** Gets the text that should be added to the file for a newly-created import declaration. */
293
+ private _getNewImportText (
294
+ importStartIndex : number , newImport : ts . ImportDeclaration ,
295
+ sourceFile : ts . SourceFile ) : string {
296
+ const text = this . printer . printNode ( ts . EmitHint . Unspecified , newImport , sourceFile ) ;
297
+
298
+ // If the import is generated at the start of the source file, we want to add
299
+ // a new-line after the import. Otherwise if the import is generated after an
300
+ // existing import, we need to prepend a new-line so that the import is not on
301
+ // the same line as the existing import anchor
302
+ return importStartIndex === 0 ? `${ text } \n` : `\n${ text } ` ;
303
+ }
263
304
}
264
305
265
306
/**
0 commit comments