1+ /* @internal */
2+ namespace ts . codefix {
3+ registerCodeFix ( {
4+ errorCodes : [
5+ Diagnostics . _0_is_declared_but_never_used . code ,
6+ Diagnostics . Property_0_is_declared_but_never_used . code
7+ ] ,
8+ getCodeActions : ( context : CodeFixContext ) => {
9+ const sourceFile = context . sourceFile ;
10+ const start = context . span . start ;
11+
12+ let token = getTokenAtPosition ( sourceFile , start ) ;
13+
14+ // this handles var ["computed"] = 12;
15+ if ( token . kind === SyntaxKind . OpenBracketToken ) {
16+ token = getTokenAtPosition ( sourceFile , start + 1 ) ;
17+ }
18+
19+ switch ( token . kind ) {
20+ case ts . SyntaxKind . Identifier :
21+ switch ( token . parent . kind ) {
22+ case ts . SyntaxKind . VariableDeclaration :
23+ switch ( token . parent . parent . parent . kind ) {
24+ case SyntaxKind . ForStatement :
25+ const forStatement = < ForStatement > token . parent . parent . parent ;
26+ const forInitializer = < VariableDeclarationList > forStatement . initializer ;
27+ if ( forInitializer . declarations . length === 1 ) {
28+ return createCodeFix ( "" , forInitializer . pos , forInitializer . end - forInitializer . pos ) ;
29+ }
30+ else {
31+ return removeSingleItem ( forInitializer . declarations , token ) ;
32+ }
33+
34+ case SyntaxKind . ForOfStatement :
35+ const forOfStatement = < ForOfStatement > token . parent . parent . parent ;
36+ if ( forOfStatement . initializer . kind === SyntaxKind . VariableDeclarationList ) {
37+ const forOfInitializer = < VariableDeclarationList > forOfStatement . initializer ;
38+ return createCodeFix ( "{}" , forOfInitializer . declarations [ 0 ] . pos , forOfInitializer . declarations [ 0 ] . end - forOfInitializer . declarations [ 0 ] . pos ) ;
39+ }
40+ break ;
41+
42+ case SyntaxKind . ForInStatement :
43+ // There is no valid fix in the case of:
44+ // for .. in
45+ return undefined ;
46+
47+ case SyntaxKind . CatchClause :
48+ const catchClause = < CatchClause > token . parent . parent ;
49+ const parameter = catchClause . variableDeclaration . getChildren ( ) [ 0 ] ;
50+ return createCodeFix ( "" , parameter . pos , parameter . end - parameter . pos ) ;
51+
52+ default :
53+ const variableStatement = < VariableStatement > token . parent . parent . parent ;
54+ if ( variableStatement . declarationList . declarations . length === 1 ) {
55+ return createCodeFix ( "" , variableStatement . pos , variableStatement . end - variableStatement . pos ) ;
56+ }
57+ else {
58+ const declarations = variableStatement . declarationList . declarations ;
59+ return removeSingleItem ( declarations , token ) ;
60+ }
61+ }
62+
63+ case SyntaxKind . TypeParameter :
64+ const typeParameters = ( < DeclarationWithTypeParameters > token . parent . parent ) . typeParameters ;
65+ if ( typeParameters . length === 1 ) {
66+ return createCodeFix ( "" , token . parent . pos - 1 , token . parent . end - token . parent . pos + 2 ) ;
67+ }
68+ else {
69+ return removeSingleItem ( typeParameters , token ) ;
70+ }
71+
72+ case ts . SyntaxKind . Parameter :
73+ const functionDeclaration = < FunctionDeclaration > token . parent . parent ;
74+ if ( functionDeclaration . parameters . length === 1 ) {
75+ return createCodeFix ( "" , token . parent . pos , token . parent . end - token . parent . pos ) ;
76+ }
77+ else {
78+ return removeSingleItem ( functionDeclaration . parameters , token ) ;
79+ }
80+
81+ // handle case where 'import a = A;'
82+ case SyntaxKind . ImportEqualsDeclaration :
83+ const importEquals = findImportDeclaration ( token ) ;
84+ return createCodeFix ( "" , importEquals . pos , importEquals . end - importEquals . pos ) ;
85+
86+ case SyntaxKind . ImportSpecifier :
87+ const namedImports = < NamedImports > token . parent . parent ;
88+ if ( namedImports . elements . length === 1 ) {
89+ // Only 1 import and it is unused. So the entire declaration should be removed.
90+ const importSpec = findImportDeclaration ( token ) ;
91+ return createCodeFix ( "" , importSpec . pos , importSpec . end - importSpec . pos ) ;
92+ }
93+ else {
94+ return removeSingleItem ( namedImports . elements , token ) ;
95+ }
96+
97+ // handle case where "import d, * as ns from './file'"
98+ // or "'import {a, b as ns} from './file'"
99+ case SyntaxKind . ImportClause : // this covers both 'import |d|' and 'import |d,| *'
100+ const importClause = < ImportClause > token . parent ;
101+ if ( ! importClause . namedBindings ) { // |import d from './file'| or |import * as ns from './file'|
102+ const importDecl = findImportDeclaration ( importClause ) ;
103+ return createCodeFix ( "" , importDecl . pos , importDecl . end - importDecl . pos ) ;
104+ }
105+ else { // import |d,| * as ns from './file'
106+ return createCodeFix ( "" , importClause . name . pos , importClause . namedBindings . pos - importClause . name . pos ) ;
107+ }
108+
109+ case SyntaxKind . NamespaceImport :
110+ const namespaceImport = < NamespaceImport > token . parent ;
111+ if ( namespaceImport . name == token && ! ( < ImportClause > namespaceImport . parent ) . name ) {
112+ const importDecl = findImportDeclaration ( namespaceImport ) ;
113+ return createCodeFix ( "" , importDecl . pos , importDecl . end - importDecl . pos ) ;
114+ }
115+ else {
116+ const start = ( < ImportClause > namespaceImport . parent ) . name . end ;
117+ return createCodeFix ( "" , start , ( < ImportClause > namespaceImport . parent ) . namedBindings . end - start ) ;
118+ }
119+ }
120+ break ;
121+
122+ case SyntaxKind . PropertyDeclaration :
123+ return createCodeFix ( "" , token . parent . pos , token . parent . end - token . parent . pos ) ;
124+
125+ case SyntaxKind . NamespaceImport :
126+ return createCodeFix ( "" , token . parent . pos , token . parent . end - token . parent . pos ) ;
127+ }
128+ if ( isDeclarationName ( token ) ) {
129+ return createCodeFix ( "" , token . parent . pos , token . parent . end - token . parent . pos ) ;
130+ }
131+ else if ( isLiteralComputedPropertyDeclarationName ( token ) ) {
132+ return createCodeFix ( "" , token . parent . parent . pos , token . parent . parent . end - token . parent . parent . pos ) ;
133+ }
134+ else {
135+ return undefined ;
136+ }
137+
138+ function findImportDeclaration ( token : Node ) : Node {
139+ let importDecl = token ;
140+ while ( importDecl . kind != SyntaxKind . ImportDeclaration && importDecl . parent ) {
141+ importDecl = importDecl . parent ;
142+ }
143+
144+ return importDecl ;
145+ }
146+
147+ function createCodeFix ( newText : string , start : number , length : number ) : CodeAction [ ] {
148+ return [ {
149+ description : getLocaleSpecificMessage ( Diagnostics . Remove_unused_identifiers ) ,
150+ changes : [ {
151+ fileName : sourceFile . fileName ,
152+ textChanges : [ { newText, span : { start, length } } ]
153+ } ]
154+ } ] ;
155+ }
156+
157+ function removeSingleItem < T extends Node > ( elements : NodeArray < T > , token : T ) : CodeAction [ ] {
158+ if ( elements [ 0 ] === token . parent ) {
159+ return createCodeFix ( "" , token . parent . pos , token . parent . end - token . parent . pos + 1 ) ;
160+ }
161+ else {
162+ return createCodeFix ( "" , token . parent . pos - 1 , token . parent . end - token . parent . pos + 1 ) ;
163+ }
164+ }
165+ }
166+ } ) ;
167+ }
0 commit comments