@@ -13,19 +13,15 @@ namespace ts.codefix {
1313 errorCodes,
1414 getCodeActions ( context ) {
1515 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+ }
1819 if ( info . kind === InfoKind . Enum ) {
1920 const { token, parentDeclaration } = info ;
2021 const changes = textChanges . ChangeTracker . with ( context , t => addEnumMemberDeclaration ( t , context . program . getTypeChecker ( ) , token , parentDeclaration ) ) ;
2122 return [ createCodeFixAction ( fixName , changes , [ Diagnostics . Add_missing_enum_member_0 , token . text ] , fixId , Diagnostics . Add_all_missing_members ) ] ;
2223 }
23- const { parentDeclaration, declSourceFile, inJs, makeStatic, token, call } = info ;
24- const methodCodeAction = call && getActionForMethodDeclaration ( context , declSourceFile , parentDeclaration , token , call , makeStatic , inJs ) ;
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 ) ) ;
2925 } ,
3026 fixIds : [ fixId ] ,
3127 getAllCodeActions : context => {
@@ -62,19 +58,18 @@ namespace ts.codefix {
6258 return ! ! superInfos && superInfos . some ( ( { token } ) => token . text === info . token . text ) ;
6359 } ) ) continue ;
6460
65- const { parentDeclaration, declSourceFile, inJs, makeStatic, token, call } = info ;
66-
61+ const { parentDeclaration, declSourceFile, modifierFlags, token, call, isJSFile } = info ;
6762 // Always prefer to add a method declaration if possible.
6863 if ( call && ! isPrivateIdentifier ( token ) ) {
69- addMethodDeclaration ( context , changes , declSourceFile , parentDeclaration , token , call , makeStatic , inJs ) ;
64+ addMethodDeclaration ( context , changes , call , token . text , modifierFlags & ModifierFlags . Static , parentDeclaration , declSourceFile , isJSFile ) ;
7065 }
7166 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 ) ) ;
7469 }
7570 else {
7671 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 ) ;
7873 }
7974 }
8075 }
@@ -104,12 +99,12 @@ namespace ts.codefix {
10499 }
105100 interface ClassOrInterfaceInfo {
106101 readonly kind : InfoKind . ClassOrInterface ;
102+ readonly call : CallExpression | undefined ;
107103 readonly token : Identifier | PrivateIdentifier ;
104+ readonly modifierFlags : ModifierFlags ;
108105 readonly parentDeclaration : ClassOrInterface ;
109- readonly makeStatic : boolean ;
110106 readonly declSourceFile : SourceFile ;
111- readonly inJs : boolean ;
112- readonly call : CallExpression | undefined ;
107+ readonly isJSFile : boolean ;
113108 }
114109 type Info = EnumInfo | ClassOrInterfaceInfo ;
115110
@@ -144,9 +139,10 @@ namespace ts.codefix {
144139 }
145140
146141 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 ) ;
148144 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 } ;
150146 }
151147
152148 const enumDeclaration = find ( symbol . declarations , isEnumDeclaration ) ;
@@ -156,13 +152,22 @@ namespace ts.codefix {
156152 return undefined ;
157153 }
158154
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 ) ) ) ;
161166 if ( changes . length === 0 ) {
162167 return undefined ;
163168 }
164169
165- const diagnostic = makeStatic ? Diagnostics . Initialize_static_property_0 :
170+ const diagnostic = modifierFlags & ModifierFlags . Static ? Diagnostics . Initialize_static_property_0 :
166171 isPrivateIdentifier ( token ) ? Diagnostics . Declare_a_private_field_named_0 : Diagnostics . Initialize_property_0_in_the_constructor ;
167172
168173 return createCodeFixAction ( fixName , changes , [ diagnostic , token . text ] , fixId , Diagnostics . Add_all_missing_members ) ;
@@ -209,18 +214,22 @@ namespace ts.codefix {
209214 return createStatement ( createAssignment ( createPropertyAccess ( obj , propertyName ) , createIdentifier ( "undefined" ) ) ) ;
210215 }
211216
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 ) ) {
216225 return actions ;
217226 }
218227
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 ] ) ) ;
221230 }
222231
223- actions . push ( createAddIndexSignatureAction ( context , declSourceFile , classDeclaration , token . text , typeNode ) ) ;
232+ actions . push ( createAddIndexSignatureAction ( context , declSourceFile , parentDeclaration , token . text , typeNode ) ) ;
224233 return actions ;
225234 }
226235
@@ -239,14 +248,6 @@ namespace ts.codefix {
239248 return typeNode || createKeywordTypeNode ( SyntaxKind . AnyKeyword ) ;
240249 }
241250
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-
250251 function addPropertyDeclaration ( changeTracker : textChanges . ChangeTracker , declSourceFile : SourceFile , classDeclaration : ClassOrInterface , tokenName : string , typeNode : TypeNode , modifierFlags : ModifierFlags ) : void {
251252 const property = createProperty (
252253 /*decorators*/ undefined ,
@@ -297,41 +298,46 @@ namespace ts.codefix {
297298 return createCodeFixActionWithoutFixAll ( fixName , changes , [ Diagnostics . Add_index_signature_for_property_0 , tokenName ] ) ;
298299 }
299300
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- ) : 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+
309307 // Private methods are not implemented yet.
310- if ( isPrivateIdentifier ( token ) ) { return undefined ; }
311- const changes = textChanges . ChangeTracker . with ( context , t => addMethodDeclaration ( context , t , declSourceFile , classDeclaration , token , callExpression , makeStatic , inJs ) ) ;
312- 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 ;
313319 }
314320
315321 function addMethodDeclaration (
316322 context : CodeFixContextBase ,
317- changeTracker : textChanges . ChangeTracker ,
318- declSourceFile : SourceFile ,
319- typeDecl : ClassOrInterface ,
320- token : Identifier ,
323+ changes : textChanges . ChangeTracker ,
321324 callExpression : CallExpression ,
322- makeStatic : boolean ,
323- inJs : boolean
325+ methodName : string ,
326+ modifierFlags : ModifierFlags ,
327+ parentDeclaration : ClassOrInterface ,
328+ sourceFile : SourceFile ,
329+ isJSFile : boolean
324330 ) : void {
325- const importAdder = createImportAdder ( declSourceFile , context . program , context . preferences , context . host ) ;
326- const methodDeclaration = createMethodFromCallExpression ( context , callExpression , token . text , inJs , makeStatic , typeDecl , importAdder ) ;
327- const containingMethodDeclaration = getAncestor ( callExpression , SyntaxKind . MethodDeclaration ) ;
328- if ( containingMethodDeclaration && containingMethodDeclaration . parent === typeDecl ) {
329- changeTracker . insertNodeAfter ( declSourceFile , containingMethodDeclaration , methodDeclaration ) ;
331+ const importAdder = createImportAdder ( sourceFile , context . program , context . preferences , context . host ) ;
332+ const methodDeclaration = createMethodFromCallExpression ( context , importAdder , callExpression , methodName , modifierFlags , parentDeclaration , isJSFile ) ;
333+ const containingMethodDeclaration = findAncestor ( callExpression , n => isMethodDeclaration ( n ) || isConstructorDeclaration ( n ) ) ;
334+ if ( containingMethodDeclaration && containingMethodDeclaration . parent === parentDeclaration ) {
335+ changes . insertNodeAfter ( sourceFile , containingMethodDeclaration , methodDeclaration ) ;
330336 }
331337 else {
332- changeTracker . insertNodeAtClassStart ( declSourceFile , typeDecl , methodDeclaration ) ;
338+ changes . insertNodeAtClassStart ( sourceFile , parentDeclaration , methodDeclaration ) ;
333339 }
334- importAdder . writeFixes ( changeTracker ) ;
340+ importAdder . writeFixes ( changes ) ;
335341 }
336342
337343 function addEnumMemberDeclaration ( changes : textChanges . ChangeTracker , checker : TypeChecker , token : Identifier , enumDeclaration : EnumDeclaration ) {
0 commit comments