@@ -29,6 +29,13 @@ export class ImportManager {
2929 new Map < ts . ImportDeclaration , { propertyName ?: ts . Identifier , importName : ts . Identifier } [ ] > ( ) ;
3030 /** Map of source-files and their previously used identifier names. */
3131 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+
3239 /**
3340 * Array of previously resolved symbol imports. Cache can be re-used to return
3441 * the same identifier without checking the source-file again.
@@ -142,37 +149,34 @@ export class ImportManager {
142149 }
143150
144151 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+ }
146160
147161 if ( symbolName ) {
148162 const propertyIdentifier = ts . factory . createIdentifier ( symbolName ) ;
149163 const generatedUniqueIdentifier = this . _getUniqueIdentifier ( sourceFile , symbolName ) ;
150164 const needsGeneratedUniqueName = generatedUniqueIdentifier . text !== symbolName ;
165+ const importMap = this . newImports . get ( sourceFile ) ! . namedImports ;
151166 identifier = needsGeneratedUniqueName ? generatedUniqueIdentifier : propertyIdentifier ;
152167
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 ) ) ;
160174 } else {
175+ const importMap = this . newImports . get ( sourceFile ) ! . defaultImports ;
161176 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 ) ;
165178 }
166179
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-
176180 // Keep track of all generated imports so that we don't generate duplicate
177181 // similar imports as these can't be statically analyzed in the source-file yet.
178182 this . importCache . push ( { sourceFile, symbolName, moduleName, identifier} ) ;
@@ -200,6 +204,30 @@ export class ImportManager {
200204 this . printer . printNode ( ts . EmitHint . Unspecified , newNamedBindings , sourceFile ) ;
201205 recorder . updateExistingImport ( namedBindings , newNamedBindingsText ) ;
202206 } ) ;
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+ } ) ;
203231 }
204232
205233 /** Gets an unique identifier with a base name for the given source file. */
@@ -260,6 +288,19 @@ export class ImportManager {
260288 }
261289 return commentRanges [ commentRanges . length - 1 ] ! . end ;
262290 }
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+ }
263304}
264305
265306/**
0 commit comments