Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1b796ed

Browse files
authored
Merge pull requestmicrosoft#23954 from Kingwl/readonly-getter-support
add support for readonly modifier
2 parents3e08c41 +44d10dc commit1b796ed

File tree

3 files changed

+104
-11
lines changed

3 files changed

+104
-11
lines changed

‎src/services/refactors/generateGetAccessorAndSetAccessor.ts

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
1111
interfaceInfo{
1212
container:ContainerDeclaration;
1313
isStatic:boolean;
14+
isReadonly:boolean;
1415
type:TypeNode|undefined;
1516
declaration:AcceptedDeclaration;
1617
fieldName:AcceptedNameType;
1718
accessorName:AcceptedNameType;
19+
originalName:AcceptedNameType;
1820
}
1921

2022
functiongetAvailableActions(context:RefactorContext):ApplicableRefactorInfo[]|undefined{
@@ -41,21 +43,40 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
4143

4244
constisJS=isSourceFileJavaScript(file);
4345
constchangeTracker=textChanges.ChangeTracker.fromContext(context);
44-
const{ isStatic, fieldName, accessorName, type, container, declaration}=fieldInfo;
46+
const{ isStatic, isReadonly, fieldName, accessorName, originalName, type, container, declaration}=fieldInfo;
47+
48+
suppressLeadingAndTrailingTrivia(fieldName);
49+
suppressLeadingAndTrailingTrivia(declaration);
50+
suppressLeadingAndTrailingTrivia(container);
4551

4652
constisInClassLike=isClassLike(container);
53+
// avoid Readonly modifier because it will convert to get accessor
54+
constmodifierFlags=getModifierFlags(declaration)&~ModifierFlags.Readonly;
4755
constaccessorModifiers=isInClassLike
48-
?!declaration.modifiers||getModifierFlags(declaration)&ModifierFlags.Private ?getModifiers(isJS,isStatic,SyntaxKind.PublicKeyword) :declaration.modifiers
56+
?!modifierFlags||modifierFlags&ModifierFlags.Private
57+
?getModifiers(isJS,isStatic,SyntaxKind.PublicKeyword)
58+
:createNodeArray(createModifiersFromModifierFlags(modifierFlags))
4959
:undefined;
5060
constfieldModifiers=isInClassLike ?getModifiers(isJS,isStatic,SyntaxKind.PrivateKeyword) :undefined;
5161

5262
updateFieldDeclaration(changeTracker,file,declaration,fieldName,fieldModifiers);
5363

5464
constgetAccessor=generateGetAccessor(fieldName,accessorName,type,accessorModifiers,isStatic,container);
55-
constsetAccessor=generateSetAccessor(fieldName,accessorName,type,accessorModifiers,isStatic,container);
56-
65+
suppressLeadingAndTrailingTrivia(getAccessor);
5766
insertAccessor(changeTracker,file,getAccessor,declaration,container);
58-
insertAccessor(changeTracker,file,setAccessor,declaration,container);
67+
68+
if(isReadonly){
69+
// readonly modifier only existed in classLikeDeclaration
70+
constconstructor=getFirstConstructorWithBody(<ClassLikeDeclaration>container);
71+
if(constructor){
72+
updateReadonlyPropertyInitializerStatementConstructor(changeTracker,context,constructor,fieldName,originalName);
73+
}
74+
}
75+
else{
76+
constsetAccessor=generateSetAccessor(fieldName,accessorName,type,accessorModifiers,isStatic,container);
77+
suppressLeadingAndTrailingTrivia(setAccessor);
78+
insertAccessor(changeTracker,file,setAccessor,declaration,container);
79+
}
5980

6081
constedits=changeTracker.getChanges();
6182
constrenameFilename=file.fileName;
@@ -92,18 +113,18 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
92113
functiongetConvertibleFieldAtPosition(file:SourceFile,startPosition:number):Info|undefined{
93114
constnode=getTokenAtPosition(file,startPosition,/*includeJsDocComment*/false);
94115
constdeclaration=findAncestor(node.parent,isAcceptedDeclaration);
95-
// make surepropertyDeclaration have AccessibilityModifier or Static Modifier
96-
constmeaning=ModifierFlags.AccessibilityModifier|ModifierFlags.Static;
116+
// make suredeclaration have AccessibilityModifier or Static Modifier or Readonly Modifier
117+
constmeaning=ModifierFlags.AccessibilityModifier|ModifierFlags.Static|ModifierFlags.Readonly;
97118
if(!declaration||!isConvertableName(declaration.name)||(getModifierFlags(declaration)|meaning)!==meaning)returnundefined;
98119

99120
constfieldName=createPropertyName(getUniqueName(`_${declaration.name.text}`,file.text),declaration.name);
100121
constaccessorName=createPropertyName(declaration.name.text,declaration.name);
101-
suppressLeadingAndTrailingTrivia(fieldName);
102-
suppressLeadingAndTrailingTrivia(declaration);
103122
return{
104123
isStatic:hasStaticModifier(declaration),
124+
isReadonly:hasReadonlyModifier(declaration),
105125
type:getTypeAnnotationNode(declaration),
106126
container:declaration.kind===SyntaxKind.Parameter ?declaration.parent.parent :declaration.parent,
127+
originalName:<AcceptedNameType>declaration.name,
107128
declaration,
108129
fieldName,
109130
accessorName,
@@ -159,7 +180,6 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
159180
declaration.type,
160181
declaration.initializer
161182
);
162-
163183
changeTracker.replaceNode(file,declaration,property);
164184
}
165185

@@ -186,4 +206,24 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
186206
?changeTracker.insertNodeAtClassStart(file,<ClassLikeDeclaration>container,accessor)
187207
:changeTracker.insertNodeAfter(file,declaration,accessor);
188208
}
209+
210+
functionupdateReadonlyPropertyInitializerStatementConstructor(changeTracker:textChanges.ChangeTracker,context:RefactorContext,constructor:ConstructorDeclaration,fieldName:AcceptedNameType,originalName:AcceptedNameType){
211+
if(!constructor.body)return;
212+
const{ file, program, cancellationToken}=context;
213+
214+
constreferenceEntries=mapDefined(FindAllReferences.getReferenceEntriesForNode(originalName.parent.pos,originalName,program,[file],cancellationToken),entry=>(
215+
(entry.type==="node"&&rangeContainsRange(constructor,entry.node)&&isIdentifier(entry.node)&&isWriteAccess(entry.node)) ?entry.node :undefined
216+
));
217+
218+
forEach(referenceEntries,entry=>{
219+
constparent=entry.parent;
220+
constaccessorName=createIdentifier(fieldName.text);
221+
constnode=isBinaryExpression(parent)
222+
?updateBinary(parent,accessorName,parent.right,parent.operatorToken)
223+
:isPropertyAccessExpression(parent)
224+
?updatePropertyAccess(parent,parent.expression,accessorName)
225+
:Debug.fail("Unexpected write access token");
226+
changeTracker.replaceNode(file,parent,node);
227+
});
228+
}
189229
}

‎tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess14.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,15 @@
55
////}
66

77
goTo.select("a","b");
8-
verify.not.refactorAvailable("Generate 'get' and 'set' accessors");
8+
goTo.select("a","b");
9+
edit.applyRefactor({
10+
refactorName:"Generate 'get' and 'set' accessors",
11+
actionName:"Generate 'get' and 'set' accessors",
12+
actionDescription:"Generate 'get' and 'set' accessors",
13+
newContent:`class A {
14+
private /*RENAME*/_a: string = "foo";
15+
public get a(): string {
16+
return this._a;
17+
}
18+
}`,
19+
});
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// class A {
4+
//// public readonly /*a*/a/*b*/: number;
5+
//// public b: number;
6+
//// constructor () {
7+
//// this.a = 1; // convert
8+
//// this.a++; // convert
9+
//// ++this.a; // convert
10+
//// if (Math.random()) {
11+
//// this.a = 2; // convert
12+
////}
13+
//// console.log(this.a); // preserve
14+
//// this.b = this.a; // preserve
15+
////}
16+
//// foo () { this.a = 2; }
17+
////}
18+
19+
goTo.select("a","b");
20+
edit.applyRefactor({
21+
refactorName:"Generate 'get' and 'set' accessors",
22+
actionName:"Generate 'get' and 'set' accessors",
23+
actionDescription:"Generate 'get' and 'set' accessors",
24+
newContent:`class A {
25+
private /*RENAME*/_a: number;
26+
public get a(): number {
27+
return this._a;
28+
}
29+
public b: number;
30+
constructor () {
31+
this._a = 1; // convert
32+
this._a++; // convert
33+
++this._a; // convert
34+
if (Math.random()) {
35+
this._a = 2; // convert
36+
}
37+
console.log(this.a); // preserve
38+
this.b = this.a; // preserve
39+
}
40+
foo () { this.a = 2; }
41+
}`,
42+
});

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp