Skip to content

Commit b41eb1b

Browse files
authored
feat(36249): add quick-fix action to declare a property as private which starts from underscore (microsoft#36632)
1 parent f1cc8e4 commit b41eb1b

File tree

5 files changed

+53
-12
lines changed

5 files changed

+53
-12
lines changed

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5113,6 +5113,10 @@
51135113
"category": "Message",
51145114
"code": 90034
51155115
},
5116+
"Declare private property '{0}'": {
5117+
"category": "Message",
5118+
"code": 90035
5119+
},
51165120
"Declare a private field named '{0}'.": {
51175121
"category": "Message",
51185122
"code": 90053

src/services/codefixes/fixAddMissingMember.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ namespace ts.codefix {
7474
}
7575
else {
7676
const typeNode = getTypeNode(program.getTypeChecker(), parentDeclaration, token);
77-
addPropertyDeclaration(changes, declSourceFile, parentDeclaration, token.text, typeNode, makeStatic);
77+
addPropertyDeclaration(changes, declSourceFile, parentDeclaration, token.text, typeNode, makeStatic ? ModifierFlags.Static : 0);
7878
}
7979
}
8080
}
@@ -211,8 +211,17 @@ namespace ts.codefix {
211211

212212
function getActionsForAddMissingMemberInTypeScriptFile(context: CodeFixContext, declSourceFile: SourceFile, classDeclaration: ClassOrInterface, token: Identifier | PrivateIdentifier, makeStatic: boolean): CodeFixAction[] | undefined {
213213
const typeNode = getTypeNode(context.program.getTypeChecker(), classDeclaration, token);
214-
const addProp = createAddPropertyDeclarationAction(context, declSourceFile, classDeclaration, makeStatic, token.text, typeNode);
215-
return makeStatic || isPrivateIdentifier(token) ? [addProp] : [addProp, createAddIndexSignatureAction(context, declSourceFile, classDeclaration, token.text, typeNode)];
214+
const actions: CodeFixAction[] = [createAddPropertyDeclarationAction(context, declSourceFile, classDeclaration, token.text, typeNode, makeStatic ? ModifierFlags.Static : 0)];
215+
if (makeStatic || isPrivateIdentifier(token)) {
216+
return actions;
217+
}
218+
219+
if (startsWithUnderscore(token.text)) {
220+
actions.unshift(createAddPropertyDeclarationAction(context, declSourceFile, classDeclaration, token.text, typeNode, ModifierFlags.Private));
221+
}
222+
223+
actions.push(createAddIndexSignatureAction(context, declSourceFile, classDeclaration, token.text, typeNode));
224+
return actions;
216225
}
217226

218227
function getTypeNode(checker: TypeChecker, classDeclaration: ClassOrInterface, token: Node) {
@@ -230,15 +239,18 @@ namespace ts.codefix {
230239
return typeNode || createKeywordTypeNode(SyntaxKind.AnyKeyword);
231240
}
232241

233-
function createAddPropertyDeclarationAction(context: CodeFixContext, declSourceFile: SourceFile, classDeclaration: ClassOrInterface, makeStatic: boolean, tokenName: string, typeNode: TypeNode): CodeFixAction {
234-
const changes = textChanges.ChangeTracker.with(context, t => addPropertyDeclaration(t, declSourceFile, classDeclaration, tokenName, typeNode, makeStatic));
235-
return createCodeFixAction(fixName, changes, [makeStatic ? Diagnostics.Declare_static_property_0 : Diagnostics.Declare_property_0, tokenName], fixId, Diagnostics.Add_all_missing_members);
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);
236248
}
237249

238-
function addPropertyDeclaration(changeTracker: textChanges.ChangeTracker, declSourceFile: SourceFile, classDeclaration: ClassOrInterface, tokenName: string, typeNode: TypeNode, makeStatic: boolean): void {
250+
function addPropertyDeclaration(changeTracker: textChanges.ChangeTracker, declSourceFile: SourceFile, classDeclaration: ClassOrInterface, tokenName: string, typeNode: TypeNode, modifierFlags: ModifierFlags): void {
239251
const property = createProperty(
240252
/*decorators*/ undefined,
241-
/*modifiers*/ makeStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined,
253+
/*modifiers*/ modifierFlags ? createNodeArray(createModifiersFromModifierFlags(modifierFlags)) : undefined,
242254
tokenName,
243255
/*questionToken*/ undefined,
244256
typeNode,

src/services/refactors/generateGetAccessorAndSetAccessor.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,6 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
112112
return modifiers && createNodeArray(modifiers);
113113
}
114114

115-
function startsWithUnderscore(name: string): boolean {
116-
return name.charCodeAt(0) === CharacterCodes._;
117-
}
118-
119115
function getConvertibleFieldAtPosition(context: RefactorContext): Info | undefined {
120116
const { file, startPosition, endPosition } = context;
121117

src/services/utilities.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2760,5 +2760,9 @@ namespace ts {
27602760
return symbol.name;
27612761
}
27622762

2763+
export function startsWithUnderscore(name: string): boolean {
2764+
return name.charCodeAt(0) === CharacterCodes._;
2765+
}
2766+
27632767
// #endregion
27642768
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////class A {
4+
//// constructor() {
5+
//// this._x = 10;
6+
//// }
7+
////}
8+
9+
verify.codeFixAvailable([
10+
{ description: "Declare private property '_x'" },
11+
{ description: "Declare property '_x'" },
12+
{ description: "Add index signature for property '_x'" }
13+
])
14+
15+
verify.codeFix({
16+
description: [ts.Diagnostics.Declare_private_property_0.message, "_x"],
17+
index: 0,
18+
newFileContent:
19+
`class A {
20+
private _x: number;
21+
constructor() {
22+
this._x = 10;
23+
}
24+
}`
25+
});

0 commit comments

Comments
 (0)