@@ -11,7 +11,6 @@ import {
11
11
confirmAsSerializable ,
12
12
ProgramInfo ,
13
13
projectFile ,
14
- ProjectFileID ,
15
14
Replacement ,
16
15
Serializable ,
17
16
TextUpdate ,
@@ -27,8 +26,8 @@ export interface CompilationUnitData {
27
26
/** Text changes that should be performed. */
28
27
replacements : Replacement [ ] ;
29
28
30
- /** Identifiers that have been removed from each file . */
31
- removedIdentifiers : NodeID [ ] ;
29
+ /** Total number of imports that were removed . */
30
+ removedImports : number ;
32
31
33
32
/** Total number of files that were changed. */
34
33
changedFiles : number ;
@@ -43,7 +42,7 @@ interface RemovalLocations {
43
42
partialRemovals : Map < ts . ArrayLiteralExpression , Set < ts . Expression > > ;
44
43
45
44
/** Text of all identifiers that have been removed. */
46
- allRemovedIdentifiers : Set < ts . Identifier > ;
45
+ allRemovedIdentifiers : Set < string > ;
47
46
}
48
47
49
48
/** Tracks how identifiers are used across a single file. */
@@ -59,9 +58,6 @@ interface UsageAnalysis {
59
58
identifierCounts : Map < string , number > ;
60
59
}
61
60
62
- /** ID of a node based on its location. */
63
- type NodeID = string & { __nodeID : true } ;
64
-
65
61
/** Migration that cleans up unused imports from a project. */
66
62
export class UnusedImportsMigration extends TsurgeFunnelMigration <
67
63
CompilationUnitData ,
@@ -83,7 +79,7 @@ export class UnusedImportsMigration extends TsurgeFunnelMigration<
83
79
override async analyze ( info : ProgramInfo ) : Promise < Serializable < CompilationUnitData > > {
84
80
const nodePositions = new Map < ts . SourceFile , Set < string > > ( ) ;
85
81
const replacements : Replacement [ ] = [ ] ;
86
- const removedIdentifiers : NodeID [ ] = [ ] ;
82
+ let removedImports = 0 ;
87
83
let changedFiles = 0 ;
88
84
89
85
info . ngCompiler ?. getDiagnostics ( ) . forEach ( ( diag ) => {
@@ -101,7 +97,7 @@ export class UnusedImportsMigration extends TsurgeFunnelMigration<
101
97
if ( ! nodePositions . has ( diag . file ) ) {
102
98
nodePositions . set ( diag . file , new Set ( ) ) ;
103
99
}
104
- nodePositions . get ( diag . file ) ! . add ( this . getNodeID ( diag . start , diag . length ) ) ;
100
+ nodePositions . get ( diag . file ) ! . add ( this . getNodeKey ( diag . start , diag . length ) ) ;
105
101
}
106
102
} ) ;
107
103
@@ -110,15 +106,14 @@ export class UnusedImportsMigration extends TsurgeFunnelMigration<
110
106
const usageAnalysis = this . analyzeUsages ( sourceFile , resolvedLocations ) ;
111
107
112
108
if ( resolvedLocations . allRemovedIdentifiers . size > 0 ) {
109
+ removedImports += resolvedLocations . allRemovedIdentifiers . size ;
113
110
changedFiles ++ ;
114
- resolvedLocations . allRemovedIdentifiers . forEach ( ( identifier ) => {
115
- removedIdentifiers . push ( this . getNodeID ( identifier . getStart ( ) , identifier . getWidth ( ) ) ) ;
116
- } ) ;
117
111
}
112
+
118
113
this . generateReplacements ( sourceFile , resolvedLocations , usageAnalysis , info , replacements ) ;
119
114
} ) ;
120
115
121
- return confirmAsSerializable ( { replacements, removedIdentifiers , changedFiles} ) ;
116
+ return confirmAsSerializable ( { replacements, removedImports , changedFiles} ) ;
122
117
}
123
118
124
119
override async migrate ( globalData : CompilationUnitData ) {
@@ -129,34 +124,10 @@ export class UnusedImportsMigration extends TsurgeFunnelMigration<
129
124
unitA : CompilationUnitData ,
130
125
unitB : CompilationUnitData ,
131
126
) : Promise < Serializable < CompilationUnitData > > {
132
- const combinedReplacements : Replacement [ ] = [ ] ;
133
- const combinedRemovedIdentifiers : NodeID [ ] = [ ] ;
134
- const seenReplacements = new Set < string > ( ) ;
135
- const seenIdentifiers = new Set < NodeID > ( ) ;
136
- const changedFileIds = new Set < ProjectFileID > ( ) ;
137
-
138
- [ unitA , unitB ] . forEach ( ( unit ) => {
139
- for ( const replacement of unit . replacements ) {
140
- const key = this . getReplacementID ( replacement ) ;
141
- changedFileIds . add ( replacement . projectFile . id ) ;
142
- if ( ! seenReplacements . has ( key ) ) {
143
- seenReplacements . add ( key ) ;
144
- combinedReplacements . push ( replacement ) ;
145
- }
146
- }
147
-
148
- for ( const identifier of unit . removedIdentifiers ) {
149
- if ( ! seenIdentifiers . has ( identifier ) ) {
150
- seenIdentifiers . add ( identifier ) ;
151
- combinedRemovedIdentifiers . push ( identifier ) ;
152
- }
153
- }
154
- } ) ;
155
-
156
127
return confirmAsSerializable ( {
157
- replacements : combinedReplacements ,
158
- removedIdentifiers : combinedRemovedIdentifiers ,
159
- changedFiles : changedFileIds . size ,
128
+ replacements : [ ... unitA . replacements , ... unitB . replacements ] ,
129
+ removedImports : unitA . removedImports + unitB . removedImports ,
130
+ changedFiles : unitA . changedFiles + unitB . changedFiles ,
160
131
} ) ;
161
132
}
162
133
@@ -168,20 +139,14 @@ export class UnusedImportsMigration extends TsurgeFunnelMigration<
168
139
169
140
override async stats ( globalMetadata : CompilationUnitData ) {
170
141
return confirmAsSerializable ( {
171
- removedImports : globalMetadata . removedIdentifiers . length ,
142
+ removedImports : globalMetadata . removedImports ,
172
143
changedFiles : globalMetadata . changedFiles ,
173
144
} ) ;
174
145
}
175
146
176
- /** Gets an ID that can be used to look up a node based on its location. */
177
- private getNodeID ( start : number , length : number ) : NodeID {
178
- return `${ start } /${ length } ` as NodeID ;
179
- }
180
-
181
- /** Gets a unique ID for a replacement. */
182
- private getReplacementID ( replacement : Replacement ) : string {
183
- const { position, end, toInsert} = replacement . update . data ;
184
- return replacement . projectFile . id + '/' + position + '/' + end + '/' + toInsert ;
147
+ /** Gets a key that can be used to look up a node based on its location. */
148
+ private getNodeKey ( start : number , length : number ) : string {
149
+ return `${ start } /${ length } ` ;
185
150
}
186
151
187
152
/**
@@ -212,7 +177,7 @@ export class UnusedImportsMigration extends TsurgeFunnelMigration<
212
177
return ;
213
178
}
214
179
215
- if ( locations . has ( this . getNodeID ( node . getStart ( ) , node . getWidth ( ) ) ) ) {
180
+ if ( locations . has ( this . getNodeKey ( node . getStart ( ) , node . getWidth ( ) ) ) ) {
216
181
// When the entire array needs to be cleared, the diagnostic is
217
182
// reported on the property assignment, rather than an array element.
218
183
if (
@@ -223,15 +188,15 @@ export class UnusedImportsMigration extends TsurgeFunnelMigration<
223
188
result . fullRemovals . add ( parent . initializer ) ;
224
189
parent . initializer . elements . forEach ( ( element ) => {
225
190
if ( ts . isIdentifier ( element ) ) {
226
- result . allRemovedIdentifiers . add ( element ) ;
191
+ result . allRemovedIdentifiers . add ( element . text ) ;
227
192
}
228
193
} ) ;
229
194
} else if ( ts . isArrayLiteralExpression ( parent ) ) {
230
195
if ( ! result . partialRemovals . has ( parent ) ) {
231
196
result . partialRemovals . set ( parent , new Set ( ) ) ;
232
197
}
233
198
result . partialRemovals . get ( parent ) ! . add ( node ) ;
234
- result . allRemovedIdentifiers . add ( node ) ;
199
+ result . allRemovedIdentifiers . add ( node . text ) ;
235
200
}
236
201
}
237
202
} ;
@@ -362,13 +327,8 @@ export class UnusedImportsMigration extends TsurgeFunnelMigration<
362
327
names . forEach ( ( symbolName , localName ) => {
363
328
// Note that in the `identifierCounts` lookup both zero and undefined
364
329
// are valid and mean that the identifiers isn't being used anymore.
365
- if ( ! identifierCounts . get ( localName ) ) {
366
- for ( const identifier of allRemovedIdentifiers ) {
367
- if ( identifier . text === localName ) {
368
- importManager . removeImport ( sourceFile , symbolName , moduleName ) ;
369
- break ;
370
- }
371
- }
330
+ if ( allRemovedIdentifiers . has ( localName ) && ! identifierCounts . get ( localName ) ) {
331
+ importManager . removeImport ( sourceFile , symbolName , moduleName ) ;
372
332
}
373
333
} ) ;
374
334
} ) ;
0 commit comments