@@ -13,23 +13,19 @@ namespace ts.codefix {
13
13
errorCodes,
14
14
getCodeActions ( context ) {
15
15
const info = getInfo ( context . sourceFile , context . span . start , context . program . getTypeChecker ( ) , context . program ) ;
16
- if ( ! info ) return undefined ;
17
-
16
+ if ( ! info ) {
17
+ return undefined ;
18
+ }
18
19
if ( info . kind === InfoKind . Enum ) {
19
20
const { token, parentDeclaration } = info ;
20
21
const changes = textChanges . ChangeTracker . with ( context , t => addEnumMemberDeclaration ( t , context . program . getTypeChecker ( ) , token , parentDeclaration ) ) ;
21
22
return [ createCodeFixAction ( fixName , changes , [ Diagnostics . Add_missing_enum_member_0 , token . text ] , fixId , Diagnostics . Add_all_missing_members ) ] ;
22
23
}
23
- const { parentDeclaration, declSourceFile, inJs, makeStatic, token, call } = info ;
24
- const methodCodeAction = call && getActionForMethodDeclaration ( context , declSourceFile , parentDeclaration , token , call , makeStatic , inJs , context . preferences ) ;
25
- const addMember = inJs && ! isInterfaceDeclaration ( parentDeclaration ) ?
26
- singleElementArray ( getActionsForAddMissingMemberInJavascriptFile ( context , declSourceFile , parentDeclaration , token , makeStatic ) ) :
27
- getActionsForAddMissingMemberInTypeScriptFile ( context , declSourceFile , parentDeclaration , token , makeStatic ) ;
28
- return concatenate ( singleElementArray ( methodCodeAction ) , addMember ) ;
24
+ return concatenate ( getActionsForMissingMethodDeclaration ( context , info ) , getActionsForMissingMemberDeclaration ( context , info ) ) ;
29
25
} ,
30
26
fixIds : [ fixId ] ,
31
27
getAllCodeActions : context => {
32
- const { program, preferences } = context ;
28
+ const { program } = context ;
33
29
const checker = program . getTypeChecker ( ) ;
34
30
const seen = createMap < true > ( ) ;
35
31
@@ -62,19 +58,18 @@ namespace ts.codefix {
62
58
return ! ! superInfos && superInfos . some ( ( { token } ) => token . text === info . token . text ) ;
63
59
} ) ) continue ;
64
60
65
- const { parentDeclaration, declSourceFile, inJs, makeStatic, token, call } = info ;
66
-
61
+ const { parentDeclaration, declSourceFile, modifierFlags, token, call, isJSFile } = info ;
67
62
// Always prefer to add a method declaration if possible.
68
63
if ( call && ! isPrivateIdentifier ( token ) ) {
69
- addMethodDeclaration ( context , changes , declSourceFile , parentDeclaration , token , call , makeStatic , inJs , preferences ) ;
64
+ addMethodDeclaration ( context , changes , call , token . text , modifierFlags & ModifierFlags . Static , parentDeclaration , declSourceFile , isJSFile ) ;
70
65
}
71
66
else {
72
- if ( inJs && ! isInterfaceDeclaration ( parentDeclaration ) ) {
73
- addMissingMemberInJs ( changes , declSourceFile , parentDeclaration , token , makeStatic ) ;
67
+ if ( isJSFile && ! isInterfaceDeclaration ( parentDeclaration ) ) {
68
+ addMissingMemberInJs ( changes , declSourceFile , parentDeclaration , token , ! ! ( modifierFlags & ModifierFlags . Static ) ) ;
74
69
}
75
70
else {
76
71
const typeNode = getTypeNode ( program . getTypeChecker ( ) , parentDeclaration , token ) ;
77
- addPropertyDeclaration ( changes , declSourceFile , parentDeclaration , token . text , typeNode , makeStatic ? ModifierFlags . Static : 0 ) ;
72
+ addPropertyDeclaration ( changes , declSourceFile , parentDeclaration , token . text , typeNode , modifierFlags & ModifierFlags . Static ) ;
78
73
}
79
74
}
80
75
}
@@ -104,12 +99,12 @@ namespace ts.codefix {
104
99
}
105
100
interface ClassOrInterfaceInfo {
106
101
readonly kind : InfoKind . ClassOrInterface ;
102
+ readonly call : CallExpression | undefined ;
107
103
readonly token : Identifier | PrivateIdentifier ;
104
+ readonly modifierFlags : ModifierFlags ;
108
105
readonly parentDeclaration : ClassOrInterface ;
109
- readonly makeStatic : boolean ;
110
106
readonly declSourceFile : SourceFile ;
111
- readonly inJs : boolean ;
112
- readonly call : CallExpression | undefined ;
107
+ readonly isJSFile : boolean ;
113
108
}
114
109
type Info = EnumInfo | ClassOrInterfaceInfo ;
115
110
@@ -144,9 +139,10 @@ namespace ts.codefix {
144
139
}
145
140
146
141
const declSourceFile = classOrInterface . getSourceFile ( ) ;
147
- const inJs = isSourceFileJS ( declSourceFile ) ;
142
+ const modifierFlags = ( makeStatic ? ModifierFlags . Static : 0 ) | ( startsWithUnderscore ( token . text ) ? ModifierFlags . Private : 0 ) ;
143
+ const isJSFile = isSourceFileJS ( declSourceFile ) ;
148
144
const call = tryCast ( parent . parent , isCallExpression ) ;
149
- return { kind : InfoKind . ClassOrInterface , token, parentDeclaration : classOrInterface , makeStatic , declSourceFile, inJs , call } ;
145
+ return { kind : InfoKind . ClassOrInterface , token, call , modifierFlags , parentDeclaration : classOrInterface , declSourceFile, isJSFile } ;
150
146
}
151
147
152
148
const enumDeclaration = find ( symbol . declarations , isEnumDeclaration ) ;
@@ -156,13 +152,22 @@ namespace ts.codefix {
156
152
return undefined ;
157
153
}
158
154
159
- function getActionsForAddMissingMemberInJavascriptFile ( context : CodeFixContext , declSourceFile : SourceFile , classDeclaration : ClassLikeDeclaration , token : Identifier | PrivateIdentifier , makeStatic : boolean ) : CodeFixAction | undefined {
160
- const changes = textChanges . ChangeTracker . with ( context , t => addMissingMemberInJs ( t , declSourceFile , classDeclaration , token , makeStatic ) ) ;
155
+ function getActionsForMissingMemberDeclaration ( context : CodeFixContext , info : ClassOrInterfaceInfo ) : CodeFixAction [ ] | undefined {
156
+ return info . isJSFile ? singleElementArray ( createActionForAddMissingMemberInJavascriptFile ( context , info ) ) :
157
+ createActionsForAddMissingMemberInTypeScriptFile ( context , info ) ;
158
+ }
159
+
160
+ function createActionForAddMissingMemberInJavascriptFile ( context : CodeFixContext , { parentDeclaration, declSourceFile, modifierFlags, token } : ClassOrInterfaceInfo ) : CodeFixAction | undefined {
161
+ if ( isInterfaceDeclaration ( parentDeclaration ) ) {
162
+ return undefined ;
163
+ }
164
+
165
+ const changes = textChanges . ChangeTracker . with ( context , t => addMissingMemberInJs ( t , declSourceFile , parentDeclaration , token , ! ! ( modifierFlags & ModifierFlags . Static ) ) ) ;
161
166
if ( changes . length === 0 ) {
162
167
return undefined ;
163
168
}
164
169
165
- const diagnostic = makeStatic ? Diagnostics . Initialize_static_property_0 :
170
+ const diagnostic = modifierFlags & ModifierFlags . Static ? Diagnostics . Initialize_static_property_0 :
166
171
isPrivateIdentifier ( token ) ? Diagnostics . Declare_a_private_field_named_0 : Diagnostics . Initialize_property_0_in_the_constructor ;
167
172
168
173
return createCodeFixAction ( fixName , changes , [ diagnostic , token . text ] , fixId , Diagnostics . Add_all_missing_members ) ;
@@ -209,18 +214,22 @@ namespace ts.codefix {
209
214
return createStatement ( createAssignment ( createPropertyAccess ( obj , propertyName ) , createIdentifier ( "undefined" ) ) ) ;
210
215
}
211
216
212
- function getActionsForAddMissingMemberInTypeScriptFile ( context : CodeFixContext , declSourceFile : SourceFile , classDeclaration : ClassOrInterface , token : Identifier | PrivateIdentifier , makeStatic : boolean ) : CodeFixAction [ ] | undefined {
213
- const typeNode = getTypeNode ( context . program . getTypeChecker ( ) , classDeclaration , token ) ;
214
- const actions : CodeFixAction [ ] = [ createAddPropertyDeclarationAction ( context , declSourceFile , classDeclaration , token . text , typeNode , makeStatic ? ModifierFlags . Static : 0 ) ] ;
215
- if ( makeStatic || isPrivateIdentifier ( token ) ) {
217
+ function createActionsForAddMissingMemberInTypeScriptFile ( context : CodeFixContext , { parentDeclaration, declSourceFile, modifierFlags, token } : ClassOrInterfaceInfo ) : CodeFixAction [ ] | undefined {
218
+ const memberName = token . text ;
219
+ const isStatic = modifierFlags & ModifierFlags . Static ;
220
+ const typeNode = getTypeNode ( context . program . getTypeChecker ( ) , parentDeclaration , token ) ;
221
+ const addPropertyDeclarationChanges = ( modifierFlags : ModifierFlags ) => textChanges . ChangeTracker . with ( context , t => addPropertyDeclaration ( t , declSourceFile , parentDeclaration , memberName , typeNode , modifierFlags ) ) ;
222
+
223
+ const actions = [ createCodeFixAction ( fixName , addPropertyDeclarationChanges ( modifierFlags & ModifierFlags . Static ) , [ isStatic ? Diagnostics . Declare_static_property_0 : Diagnostics . Declare_property_0 , memberName ] , fixId , Diagnostics . Add_all_missing_members ) ] ;
224
+ if ( isStatic || isPrivateIdentifier ( token ) ) {
216
225
return actions ;
217
226
}
218
227
219
- if ( startsWithUnderscore ( token . text ) ) {
220
- actions . unshift ( createAddPropertyDeclarationAction ( context , declSourceFile , classDeclaration , token . text , typeNode , ModifierFlags . Private ) ) ;
228
+ if ( modifierFlags & ModifierFlags . Private ) {
229
+ actions . unshift ( createCodeFixActionWithoutFixAll ( fixName , addPropertyDeclarationChanges ( ModifierFlags . Private ) , [ Diagnostics . Declare_private_property_0 , memberName ] ) ) ;
221
230
}
222
231
223
- actions . push ( createAddIndexSignatureAction ( context , declSourceFile , classDeclaration , token . text , typeNode ) ) ;
232
+ actions . push ( createAddIndexSignatureAction ( context , declSourceFile , parentDeclaration , token . text , typeNode ) ) ;
224
233
return actions ;
225
234
}
226
235
@@ -239,14 +248,6 @@ namespace ts.codefix {
239
248
return typeNode || createKeywordTypeNode ( SyntaxKind . AnyKeyword ) ;
240
249
}
241
250
242
- function createAddPropertyDeclarationAction ( context : CodeFixContext , declSourceFile : SourceFile , classDeclaration : ClassOrInterface , tokenName : string , typeNode : TypeNode , modifierFlags : ModifierFlags ) : CodeFixAction {
243
- const changes = textChanges . ChangeTracker . with ( context , t => addPropertyDeclaration ( t , declSourceFile , classDeclaration , tokenName , typeNode , modifierFlags ) ) ;
244
- if ( modifierFlags & ModifierFlags . Private ) {
245
- return createCodeFixActionWithoutFixAll ( fixName , changes , [ Diagnostics . Declare_private_property_0 , tokenName ] ) ;
246
- }
247
- return createCodeFixAction ( fixName , changes , [ modifierFlags & ModifierFlags . Static ? Diagnostics . Declare_static_property_0 : Diagnostics . Declare_property_0 , tokenName ] , fixId , Diagnostics . Add_all_missing_members ) ;
248
- }
249
-
250
251
function addPropertyDeclaration ( changeTracker : textChanges . ChangeTracker , declSourceFile : SourceFile , classDeclaration : ClassOrInterface , tokenName : string , typeNode : TypeNode , modifierFlags : ModifierFlags ) : void {
251
252
const property = createProperty (
252
253
/*decorators*/ undefined ,
@@ -297,41 +298,43 @@ namespace ts.codefix {
297
298
return createCodeFixActionWithoutFixAll ( fixName , changes , [ Diagnostics . Add_index_signature_for_property_0 , tokenName ] ) ;
298
299
}
299
300
300
- function getActionForMethodDeclaration (
301
- context : CodeFixContext ,
302
- declSourceFile : SourceFile ,
303
- classDeclaration : ClassOrInterface ,
304
- token : Identifier | PrivateIdentifier ,
305
- callExpression : CallExpression ,
306
- makeStatic : boolean ,
307
- inJs : boolean ,
308
- preferences : UserPreferences ,
309
- ) : CodeFixAction | undefined {
301
+ function getActionsForMissingMethodDeclaration ( context : CodeFixContext , info : ClassOrInterfaceInfo ) : CodeFixAction [ ] | undefined {
302
+ const { parentDeclaration, declSourceFile, modifierFlags, token, call, isJSFile } = info ;
303
+ if ( call === undefined ) {
304
+ return undefined ;
305
+ }
306
+
310
307
// Private methods are not implemented yet.
311
- if ( isPrivateIdentifier ( token ) ) { return undefined ; }
312
- const changes = textChanges . ChangeTracker . with ( context , t => addMethodDeclaration ( context , t , declSourceFile , classDeclaration , token , callExpression , makeStatic , inJs , preferences ) ) ;
313
- return createCodeFixAction ( fixName , changes , [ makeStatic ? Diagnostics . Declare_static_method_0 : Diagnostics . Declare_method_0 , token . text ] , fixId , Diagnostics . Add_all_missing_members ) ;
308
+ if ( isPrivateIdentifier ( token ) ) {
309
+ return undefined ;
310
+ }
311
+
312
+ const methodName = token . text ;
313
+ const addMethodDeclarationChanges = ( modifierFlags : ModifierFlags ) => textChanges . ChangeTracker . with ( context , t => addMethodDeclaration ( context , t , call , methodName , modifierFlags , parentDeclaration , declSourceFile , isJSFile ) ) ;
314
+ const actions = [ createCodeFixAction ( fixName , addMethodDeclarationChanges ( modifierFlags & ModifierFlags . Static ) , [ modifierFlags & ModifierFlags . Static ? Diagnostics . Declare_static_method_0 : Diagnostics . Declare_method_0 , methodName ] , fixId , Diagnostics . Add_all_missing_members ) ] ;
315
+ if ( modifierFlags & ModifierFlags . Private ) {
316
+ actions . unshift ( createCodeFixActionWithoutFixAll ( fixName , addMethodDeclarationChanges ( ModifierFlags . Private ) , [ Diagnostics . Declare_private_method_0 , methodName ] ) ) ;
317
+ }
318
+ return actions ;
314
319
}
315
320
316
321
function addMethodDeclaration (
317
322
context : CodeFixContextBase ,
318
- changeTracker : textChanges . ChangeTracker ,
319
- declSourceFile : SourceFile ,
320
- typeDecl : ClassOrInterface ,
321
- token : Identifier ,
323
+ changes : textChanges . ChangeTracker ,
322
324
callExpression : CallExpression ,
323
- makeStatic : boolean ,
324
- inJs : boolean ,
325
- preferences : UserPreferences ,
325
+ methodName : string ,
326
+ modifierFlags : ModifierFlags ,
327
+ parentDeclaration : ClassOrInterface ,
328
+ sourceFile : SourceFile ,
329
+ isJSFile : boolean
326
330
) : void {
327
- const methodDeclaration = createMethodFromCallExpression ( context , callExpression , token . text , inJs , makeStatic , preferences , typeDecl ) ;
328
- const containingMethodDeclaration = getAncestor ( callExpression , SyntaxKind . MethodDeclaration ) ;
329
-
330
- if ( containingMethodDeclaration && containingMethodDeclaration . parent === typeDecl ) {
331
- changeTracker . insertNodeAfter ( declSourceFile , containingMethodDeclaration , methodDeclaration ) ;
331
+ const methodDeclaration = createMethodFromCallExpression ( context , callExpression , methodName , modifierFlags , parentDeclaration , isJSFile ) ;
332
+ const containingMethodDeclaration = findAncestor ( callExpression , n => isMethodDeclaration ( n ) || isConstructorDeclaration ( n ) ) ;
333
+ if ( containingMethodDeclaration && containingMethodDeclaration . parent === parentDeclaration ) {
334
+ changes . insertNodeAfter ( sourceFile , containingMethodDeclaration , methodDeclaration ) ;
332
335
}
333
336
else {
334
- changeTracker . insertNodeAtClassStart ( declSourceFile , typeDecl , methodDeclaration ) ;
337
+ changes . insertNodeAtClassStart ( sourceFile , parentDeclaration , methodDeclaration ) ;
335
338
}
336
339
}
337
340
0 commit comments