@@ -13,6 +13,8 @@ import {
13
13
NoopChange ,
14
14
createReplaceChange ,
15
15
ReplaceChange ,
16
+ RemoveChange ,
17
+ createRemoveChange ,
16
18
} from './change' ;
17
19
import { Path } from '@angular-devkit/core' ;
18
20
@@ -650,7 +652,7 @@ export function replaceImport(
650
652
importFrom : string ,
651
653
importAsIs : string ,
652
654
importToBe : string
653
- ) : ReplaceChange [ ] {
655
+ ) : ( ReplaceChange | RemoveChange ) [ ] {
654
656
const imports = sourceFile . statements
655
657
. filter ( ts . isImportDeclaration )
656
658
. filter (
@@ -663,32 +665,67 @@ export function replaceImport(
663
665
return [ ] ;
664
666
}
665
667
666
- const changes = imports
667
- . map ( p => ( p . importClause ! . namedBindings ! as ts . NamedImports ) . elements )
668
- . reduce ( ( imports , curr ) => imports . concat ( curr ) , [ ] as ts . ImportSpecifier [ ] )
669
- . map ( specifier => {
670
- if ( ! ts . isImportSpecifier ( specifier ) ) {
671
- return { hit : false } ;
668
+ const importText = ( specifier : ts . ImportSpecifier ) => {
669
+ if ( specifier . name . text ) {
670
+ return specifier . name . text ;
671
+ }
672
+
673
+ // if import is renamed
674
+ if ( specifier . propertyName && specifier . propertyName . text ) {
675
+ return specifier . propertyName . text ;
676
+ }
677
+
678
+ return '' ;
679
+ } ;
680
+
681
+ const changes = imports . map ( p => {
682
+ const importSpecifiers = ( p . importClause ! . namedBindings ! as ts . NamedImports )
683
+ . elements ;
684
+
685
+ const isAlreadyImported = importSpecifiers
686
+ . map ( importText )
687
+ . includes ( importToBe ) ;
688
+
689
+ const importChanges = importSpecifiers . map ( ( specifier , index ) => {
690
+ const text = importText ( specifier ) ;
691
+
692
+ // import is not the one we're looking for, can be skipped
693
+ if ( text !== importAsIs ) {
694
+ return undefined ;
672
695
}
673
696
674
- if ( specifier . name . text === importAsIs ) {
675
- return { hit : true , specifier, text : specifier . name . text } ;
697
+ // identifier has not been imported, simply replace the old text with the new text
698
+ if ( ! isAlreadyImported ) {
699
+ return createReplaceChange (
700
+ sourceFile ,
701
+ specifier ! ,
702
+ importAsIs ,
703
+ importToBe
704
+ ) ;
676
705
}
677
706
678
- // if import is renamed
679
- if (
680
- specifier . propertyName &&
681
- specifier . propertyName . text === importAsIs
682
- ) {
683
- return { hit : true , specifier, text : specifier . propertyName . text } ;
707
+ const nextIdentifier = importSpecifiers [ index + 1 ] ;
708
+ // identifer is not the last, also clean up the comma
709
+ if ( nextIdentifier ) {
710
+ return createRemoveChange (
711
+ sourceFile ,
712
+ specifier ,
713
+ specifier . getStart ( sourceFile ) ,
714
+ nextIdentifier . getStart ( sourceFile )
715
+ ) ;
684
716
}
685
717
686
- return { hit : false } ;
687
- } )
688
- . filter ( ( { hit } ) => hit )
689
- . map ( ( { specifier, text } ) =>
690
- createReplaceChange ( sourceFile , specifier ! , text ! , importToBe )
691
- ) ;
718
+ // there are no imports following, just remove it
719
+ return createRemoveChange (
720
+ sourceFile ,
721
+ specifier ,
722
+ specifier . getStart ( sourceFile ) ,
723
+ specifier . getEnd ( )
724
+ ) ;
725
+ } ) ;
726
+
727
+ return importChanges . filter ( Boolean ) as ( ReplaceChange | RemoveChange ) [ ] ;
728
+ } ) ;
692
729
693
- return changes ;
730
+ return changes . reduce ( ( imports , curr ) => imports . concat ( curr ) , [ ] ) ;
694
731
}
0 commit comments