@@ -18,142 +18,150 @@ namespace ts.codefix {
18
18
19
19
switch ( token . kind ) {
20
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 deleteNode ( forInitializer ) ;
29
- }
30
- else {
31
- return deleteNodeInList ( token . parent ) ;
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 replaceNode ( forOfInitializer . declarations [ 0 ] , createObjectLiteral ( ) ) ;
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 deleteNode ( parameter ) ;
51
-
52
- default :
53
- const variableStatement = < VariableStatement > token . parent . parent . parent ;
54
- if ( variableStatement . declarationList . declarations . length === 1 ) {
55
- return deleteNode ( variableStatement ) ;
56
- }
57
- else {
58
- return deleteNodeInList ( token . parent ) ;
59
- }
60
- }
61
- // TODO: #14885
62
- // falls through
63
-
64
- case SyntaxKind . TypeParameter :
65
- const typeParameters = ( < DeclarationWithTypeParameters > token . parent . parent ) . typeParameters ;
66
- if ( typeParameters . length === 1 ) {
67
- const previousToken = getTokenAtPosition ( sourceFile , typeParameters . pos - 1 ) ;
68
- if ( ! previousToken || previousToken . kind !== SyntaxKind . LessThanToken ) {
69
- return deleteRange ( typeParameters ) ;
70
- }
71
- const nextToken = getTokenAtPosition ( sourceFile , typeParameters . end ) ;
72
- if ( ! nextToken || nextToken . kind !== SyntaxKind . GreaterThanToken ) {
73
- return deleteRange ( typeParameters ) ;
74
- }
75
- return deleteNodeRange ( previousToken , nextToken ) ;
76
- }
77
- else {
78
- return deleteNodeInList ( token . parent ) ;
79
- }
21
+ return deleteIdentifier ( ) ;
80
22
81
- case ts . SyntaxKind . Parameter :
82
- const functionDeclaration = < FunctionDeclaration > token . parent . parent ;
83
- if ( functionDeclaration . parameters . length === 1 ) {
84
- return deleteNode ( token . parent ) ;
85
- }
86
- else {
87
- return deleteNodeInList ( token . parent ) ;
88
- }
23
+ case SyntaxKind . PropertyDeclaration :
24
+ case SyntaxKind . NamespaceImport :
25
+ return deleteNode ( token . parent ) ;
89
26
90
- // handle case where 'import a = A;'
91
- case SyntaxKind . ImportEqualsDeclaration :
92
- const importEquals = getAncestor ( token , SyntaxKind . ImportEqualsDeclaration ) ;
93
- return deleteNode ( importEquals ) ;
94
-
95
- case SyntaxKind . ImportSpecifier :
96
- const namedImports = < NamedImports > token . parent . parent ;
97
- if ( namedImports . elements . length === 1 ) {
98
- // Only 1 import and it is unused. So the entire declaration should be removed.
99
- const importSpec = getAncestor ( token , SyntaxKind . ImportDeclaration ) ;
100
- return deleteNode ( importSpec ) ;
101
- }
102
- else {
103
- // delete import specifier
104
- return deleteNodeInList ( token . parent ) ;
105
- }
27
+ default :
28
+ return deleteDefault ( ) ;
29
+ }
30
+
31
+ function deleteDefault ( ) {
32
+ if ( isDeclarationName ( token ) ) {
33
+ return deleteNode ( token . parent ) ;
34
+ }
35
+ else if ( isLiteralComputedPropertyDeclarationName ( token ) ) {
36
+ return deleteNode ( token . parent . parent ) ;
37
+ }
38
+ else {
39
+ return undefined ;
40
+ }
41
+ }
106
42
107
- // handle case where "import d, * as ns from './file'"
108
- // or "'import {a, b as ns} from './file'"
109
- case SyntaxKind . ImportClause : // this covers both 'import |d|' and 'import |d,| *'
110
- const importClause = < ImportClause > token . parent ;
111
- if ( ! importClause . namedBindings ) { // |import d from './file'| or |import * as ns from './file'|
112
- const importDecl = getAncestor ( importClause , SyntaxKind . ImportDeclaration ) ;
113
- return deleteNode ( importDecl ) ;
43
+ function deleteIdentifier ( ) : CodeAction [ ] | undefined {
44
+ switch ( token . parent . kind ) {
45
+ case ts . SyntaxKind . VariableDeclaration :
46
+ return deleteVariableDeclaration ( < ts . VariableDeclaration > token . parent ) ;
47
+
48
+ case SyntaxKind . TypeParameter :
49
+ const typeParameters = ( < DeclarationWithTypeParameters > token . parent . parent ) . typeParameters ;
50
+ if ( typeParameters . length === 1 ) {
51
+ const previousToken = getTokenAtPosition ( sourceFile , typeParameters . pos - 1 ) ;
52
+ if ( ! previousToken || previousToken . kind !== SyntaxKind . LessThanToken ) {
53
+ return deleteRange ( typeParameters ) ;
114
54
}
115
- else {
116
- // import |d,| * as ns from './file'
117
- const start = importClause . name . getStart ( sourceFile ) ;
118
- const nextToken = getTokenAtPosition ( sourceFile , importClause . name . end ) ;
119
- if ( nextToken && nextToken . kind === SyntaxKind . CommaToken ) {
120
- // shift first non-whitespace position after comma to the start position of the node
121
- return deleteRange ( { pos : start , end : skipTrivia ( sourceFile . text , nextToken . end , /*stopAfterLineBreaks*/ false , /*stopAtComments*/ true ) } ) ;
122
- }
123
- else {
124
- return deleteNode ( importClause . name ) ;
125
- }
55
+ const nextToken = getTokenAtPosition ( sourceFile , typeParameters . end ) ;
56
+ if ( ! nextToken || nextToken . kind !== SyntaxKind . GreaterThanToken ) {
57
+ return deleteRange ( typeParameters ) ;
126
58
}
127
-
128
- case SyntaxKind . NamespaceImport :
129
- const namespaceImport = < NamespaceImport > token . parent ;
130
- if ( namespaceImport . name === token && ! ( < ImportClause > namespaceImport . parent ) . name ) {
131
- const importDecl = getAncestor ( namespaceImport , SyntaxKind . ImportDeclaration ) ;
132
- return deleteNode ( importDecl ) ;
59
+ return deleteNodeRange ( previousToken , nextToken ) ;
60
+ }
61
+ else {
62
+ return deleteNodeInList ( token . parent ) ;
63
+ }
64
+
65
+ case ts . SyntaxKind . Parameter :
66
+ const functionDeclaration = < FunctionDeclaration > token . parent . parent ;
67
+ if ( functionDeclaration . parameters . length === 1 ) {
68
+ return deleteNode ( token . parent ) ;
69
+ }
70
+ else {
71
+ return deleteNodeInList ( token . parent ) ;
72
+ }
73
+
74
+ // handle case where 'import a = A;'
75
+ case SyntaxKind . ImportEqualsDeclaration :
76
+ const importEquals = getAncestor ( token , SyntaxKind . ImportEqualsDeclaration ) ;
77
+ return deleteNode ( importEquals ) ;
78
+
79
+ case SyntaxKind . ImportSpecifier :
80
+ const namedImports = < NamedImports > token . parent . parent ;
81
+ if ( namedImports . elements . length === 1 ) {
82
+ // Only 1 import and it is unused. So the entire declaration should be removed.
83
+ const importSpec = getAncestor ( token , SyntaxKind . ImportDeclaration ) ;
84
+ return deleteNode ( importSpec ) ;
85
+ }
86
+ else {
87
+ // delete import specifier
88
+ return deleteNodeInList ( token . parent ) ;
89
+ }
90
+
91
+ // handle case where "import d, * as ns from './file'"
92
+ // or "'import {a, b as ns} from './file'"
93
+ case SyntaxKind . ImportClause : // this covers both 'import |d|' and 'import |d,| *'
94
+ const importClause = < ImportClause > token . parent ;
95
+ if ( ! importClause . namedBindings ) { // |import d from './file'| or |import * as ns from './file'|
96
+ const importDecl = getAncestor ( importClause , SyntaxKind . ImportDeclaration ) ;
97
+ return deleteNode ( importDecl ) ;
98
+ }
99
+ else {
100
+ // import |d,| * as ns from './file'
101
+ const start = importClause . name . getStart ( sourceFile ) ;
102
+ const nextToken = getTokenAtPosition ( sourceFile , importClause . name . end ) ;
103
+ if ( nextToken && nextToken . kind === SyntaxKind . CommaToken ) {
104
+ // shift first non-whitespace position after comma to the start position of the node
105
+ return deleteRange ( { pos : start , end : skipTrivia ( sourceFile . text , nextToken . end , /*stopAfterLineBreaks*/ false , /*stopAtComments*/ true ) } ) ;
133
106
}
134
107
else {
135
- const previousToken = getTokenAtPosition ( sourceFile , namespaceImport . pos - 1 ) ;
136
- if ( previousToken && previousToken . kind === SyntaxKind . CommaToken ) {
137
- const startPosition = textChanges . getAdjustedStartPosition ( sourceFile , previousToken , { } , textChanges . Position . FullStart ) ;
138
- return deleteRange ( { pos : startPosition , end : namespaceImport . end } ) ;
139
- }
140
- return deleteRange ( namespaceImport ) ;
108
+ return deleteNode ( importClause . name ) ;
109
+ }
110
+ }
111
+
112
+ case SyntaxKind . NamespaceImport :
113
+ const namespaceImport = < NamespaceImport > token . parent ;
114
+ if ( namespaceImport . name === token && ! ( < ImportClause > namespaceImport . parent ) . name ) {
115
+ const importDecl = getAncestor ( namespaceImport , SyntaxKind . ImportDeclaration ) ;
116
+ return deleteNode ( importDecl ) ;
117
+ }
118
+ else {
119
+ const previousToken = getTokenAtPosition ( sourceFile , namespaceImport . pos - 1 ) ;
120
+ if ( previousToken && previousToken . kind === SyntaxKind . CommaToken ) {
121
+ const startPosition = textChanges . getAdjustedStartPosition ( sourceFile , previousToken , { } , textChanges . Position . FullStart ) ;
122
+ return deleteRange ( { pos : startPosition , end : namespaceImport . end } ) ;
141
123
}
142
- }
143
- break ;
124
+ return deleteRange ( namespaceImport ) ;
125
+ }
144
126
145
- case SyntaxKind . PropertyDeclaration :
146
- case SyntaxKind . NamespaceImport :
147
- return deleteNode ( token . parent ) ;
127
+ default :
128
+ return deleteDefault ( ) ;
129
+ }
148
130
}
149
- if ( isDeclarationName ( token ) ) {
150
- return deleteNode ( token . parent ) ;
151
- }
152
- else if ( isLiteralComputedPropertyDeclarationName ( token ) ) {
153
- return deleteNode ( token . parent . parent ) ;
154
- }
155
- else {
156
- return undefined ;
131
+
132
+ // token.parent is a variableDeclaration
133
+ function deleteVariableDeclaration ( varDecl : ts . VariableDeclaration ) : CodeAction [ ] | undefined {
134
+ switch ( varDecl . parent . parent . kind ) {
135
+ case SyntaxKind . ForStatement :
136
+ const forStatement = < ForStatement > varDecl . parent . parent ;
137
+ const forInitializer = < VariableDeclarationList > forStatement . initializer ;
138
+ if ( forInitializer . declarations . length === 1 ) {
139
+ return deleteNode ( forInitializer ) ;
140
+ }
141
+ else {
142
+ return deleteNodeInList ( varDecl ) ;
143
+ }
144
+
145
+ case SyntaxKind . ForOfStatement :
146
+ const forOfStatement = < ForOfStatement > varDecl . parent . parent ;
147
+ Debug . assert ( forOfStatement . initializer . kind === SyntaxKind . VariableDeclarationList ) ;
148
+ const forOfInitializer = < VariableDeclarationList > forOfStatement . initializer ;
149
+ return replaceNode ( forOfInitializer . declarations [ 0 ] , createObjectLiteral ( ) ) ;
150
+
151
+ case SyntaxKind . ForInStatement :
152
+ // There is no valid fix in the case of:
153
+ // for .. in
154
+ return undefined ;
155
+
156
+ default :
157
+ const variableStatement = < VariableStatement > varDecl . parent . parent ;
158
+ if ( variableStatement . declarationList . declarations . length === 1 ) {
159
+ return deleteNode ( variableStatement ) ;
160
+ }
161
+ else {
162
+ return deleteNodeInList ( varDecl ) ;
163
+ }
164
+ }
157
165
}
158
166
159
167
function deleteNode ( n : Node ) {
0 commit comments