-
Notifications
You must be signed in to change notification settings - Fork 12.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add refactor of convert private field to getter and setter
- Loading branch information
Showing
14 changed files
with
391 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/* @internal */ | ||
namespace ts.refactor.ConvertGetterAndSetter { | ||
const actionName = "Generate 'get' and 'set' accessors"; | ||
const actionDescription = Diagnostics.Generate_get_and_set_accessors.message; | ||
|
||
registerRefactor(actionName, { getEditsForAction, getAvailableActions }); | ||
|
||
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined { | ||
const { file, startPosition } = context; | ||
|
||
const fieldInfo = getConvertibleFieldAtPosition(file, startPosition); | ||
if (!fieldInfo) return undefined; | ||
|
||
return [ | ||
{ | ||
name: actionName, | ||
description: actionDescription, | ||
actions: [ | ||
{ | ||
name: actionName, | ||
description: actionDescription | ||
} | ||
] | ||
} | ||
]; | ||
} | ||
|
||
function getEditsForAction(context: RefactorContext, _actionName: string): RefactorEditInfo | undefined { | ||
const { file, startPosition } = context; | ||
|
||
const fieldInfo = getConvertibleFieldAtPosition(file, startPosition); | ||
if (!fieldInfo) return undefined; | ||
|
||
const changeTracker = textChanges.ChangeTracker.fromContext(context); | ||
const newLineCharacter = getNewLineOrDefaultFromHost(context.host, context.formatContext.options); | ||
|
||
const { fieldName, accessorName, propertyDeclaration, needUpdateName, hasModifiers, needUpdateModifiers } = fieldInfo; | ||
const accessorModifiers = hasModifiers ? createNodeArray([createToken(SyntaxKind.PublicKeyword)]) : undefined; | ||
|
||
const getAccessor = generateGetAccessor(propertyDeclaration, fieldName, accessorName, accessorModifiers); | ||
const setAccessor = generateSetAccessor(propertyDeclaration, fieldName, accessorName, accessorModifiers); | ||
|
||
const modifiers = needUpdateModifiers ? createNodeArray([createToken(SyntaxKind.PrivateKeyword)]) : propertyDeclaration.modifiers; | ||
if (needUpdateName || needUpdateModifiers) { | ||
changeTracker.replaceNode(file, propertyDeclaration, updateOriginPropertyDeclaration(propertyDeclaration, fieldName, modifiers), { | ||
suffix: newLineCharacter | ||
}); | ||
} | ||
|
||
changeTracker.insertNodeAfter(file, propertyDeclaration, getAccessor); | ||
changeTracker.insertNodeAfter(file, propertyDeclaration, setAccessor); | ||
|
||
return { | ||
edits: changeTracker.getChanges(), | ||
renameFilename: undefined, | ||
renameLocation: undefined, | ||
}; | ||
} | ||
|
||
interface Info { originName: string; fieldName: string; accessorName: string; propertyDeclaration: PropertyDeclaration; needUpdateName: boolean; hasModifiers: boolean; needUpdateModifiers: boolean; } | ||
function getConvertibleFieldAtPosition(file: SourceFile, startPosition: number): Info | undefined { | ||
const node = getTokenAtPosition(file, startPosition, /*includeJsDocComment*/ false); | ||
const propertyDeclaration = findAncestor(node.parent, isPropertyDeclaration); | ||
|
||
if (!(propertyDeclaration && propertyDeclaration.name.kind === SyntaxKind.Identifier && | ||
(getModifierFlags(propertyDeclaration) | ModifierFlags.AccessibilityModifier) === ModifierFlags.AccessibilityModifier)) return undefined; | ||
|
||
const containerClass = getContainingClass(propertyDeclaration); | ||
if (!containerClass) return undefined; | ||
|
||
const members = getMembersOfDeclaration(containerClass); | ||
if (!members) return undefined; | ||
|
||
const needUpdateName = propertyDeclaration.name.text.charCodeAt(0) !== CharacterCodes._; | ||
|
||
const accessorName = needUpdateName ? propertyDeclaration.name.text : propertyDeclaration.name.text.substring(1); | ||
const fieldName = `_${accessorName}`; | ||
|
||
if (find(members, member => needUpdateName ? member.name.getText() === fieldName : member.name.getText() === accessorName)) return undefined; | ||
|
||
const hasModifiers = !!find(members, member => !!member.modifiers); | ||
const needUpdateModifiers = hasModifiers && (!propertyDeclaration.modifiers || hasModifier(propertyDeclaration, ModifierFlags.Public)); | ||
|
||
return { | ||
originName: propertyDeclaration.name.text, | ||
fieldName, | ||
accessorName, | ||
propertyDeclaration, | ||
needUpdateName, | ||
hasModifiers, | ||
needUpdateModifiers | ||
}; | ||
} | ||
|
||
function generateGetAccessor (propertyDeclaration: PropertyDeclaration, fieldName: string, name: string, modifiers: ModifiersArray) { | ||
return createGetAccessor( | ||
/*decorators*/ undefined, | ||
modifiers, | ||
name, | ||
/*parameters*/ undefined, | ||
propertyDeclaration.type, | ||
createBlock([ | ||
createReturn( | ||
createPropertyAccess( | ||
createThis(), | ||
fieldName | ||
) | ||
) | ||
], /*multiLine*/ true) | ||
); | ||
} | ||
|
||
function generateSetAccessor (propertyDeclaration: PropertyDeclaration, fieldName: string, name: string, modifiers: ModifiersArray) { | ||
return createSetAccessor( | ||
/*decorators*/ undefined, | ||
modifiers, | ||
name, | ||
[createParameter( | ||
/*decorators*/ undefined, | ||
/*modifies*/ undefined, | ||
/*dotDotDotToken*/ undefined, | ||
createIdentifier("value"), | ||
/*questionToken*/ undefined, | ||
propertyDeclaration.type | ||
)], | ||
createBlock([ | ||
createStatement( | ||
createAssignment( | ||
createPropertyAccess( | ||
createThis(), | ||
fieldName | ||
), | ||
createIdentifier("value") | ||
) | ||
) | ||
], /*multiLine*/ true) | ||
); | ||
} | ||
|
||
function updateOriginPropertyDeclaration (propertyDeclaration: PropertyDeclaration, fieldName: string, modifiers: ModifiersArray) { | ||
return updateProperty( | ||
propertyDeclaration, | ||
/*decorators*/ undefined, | ||
modifiers, | ||
fieldName, | ||
/*questionOrExclamationToken*/ undefined, | ||
propertyDeclaration.type, | ||
propertyDeclaration.initializer, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess1.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// class A { | ||
//// /*a*/public a: string;/*b*/ | ||
//// } | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Generate 'get' and 'set' accessors", | ||
actionName: "Generate 'get' and 'set' accessors", | ||
actionDescription: "Generate 'get' and 'set' accessors", | ||
newContent: `class A { | ||
private _a: string; | ||
public get a(): string { | ||
return this._a; | ||
} | ||
public set a(value: string) { | ||
this._a = value; | ||
} | ||
}`, | ||
}); |
23 changes: 23 additions & 0 deletions
23
tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess10.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// class A { | ||
//// public a: string; | ||
//// /*a*/b: number;/*b*/ | ||
//// } | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Generate 'get' and 'set' accessors", | ||
actionName: "Generate 'get' and 'set' accessors", | ||
actionDescription: "Generate 'get' and 'set' accessors", | ||
newContent: `class A { | ||
public a: string; | ||
private _b: number; | ||
public get b(): number { | ||
return this._b; | ||
} | ||
public set b(value: number) { | ||
this._b = value; | ||
} | ||
}`, | ||
}); |
21 changes: 21 additions & 0 deletions
21
tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess11.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// class A { | ||
//// /*a*/public a: string = "foo";/*b*/ | ||
//// } | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Generate 'get' and 'set' accessors", | ||
actionName: "Generate 'get' and 'set' accessors", | ||
actionDescription: "Generate 'get' and 'set' accessors", | ||
newContent: `class A { | ||
private _a: string = "foo"; | ||
public get a(): string { | ||
return this._a; | ||
} | ||
public set a(value: string) { | ||
this._a = value; | ||
} | ||
}`, | ||
}); |
21 changes: 21 additions & 0 deletions
21
tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess2.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// class A { | ||
//// /*a*/protected a: string;/*b*/ | ||
//// } | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Generate 'get' and 'set' accessors", | ||
actionName: "Generate 'get' and 'set' accessors", | ||
actionDescription: "Generate 'get' and 'set' accessors", | ||
newContent: `class A { | ||
protected _a: string; | ||
public get a(): string { | ||
return this._a; | ||
} | ||
public set a(value: string) { | ||
this._a = value; | ||
} | ||
}`, | ||
}); |
21 changes: 21 additions & 0 deletions
21
tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess3.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// class A { | ||
//// /*a*/private a: string;/*b*/ | ||
//// } | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Generate 'get' and 'set' accessors", | ||
actionName: "Generate 'get' and 'set' accessors", | ||
actionDescription: "Generate 'get' and 'set' accessors", | ||
newContent: `class A { | ||
private _a: string; | ||
public get a(): string { | ||
return this._a; | ||
} | ||
public set a(value: string) { | ||
this._a = value; | ||
} | ||
}`, | ||
}); |
21 changes: 21 additions & 0 deletions
21
tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess4.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// class A { | ||
//// /*a*/private _a: string;/*b*/ | ||
//// } | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Generate 'get' and 'set' accessors", | ||
actionName: "Generate 'get' and 'set' accessors", | ||
actionDescription: "Generate 'get' and 'set' accessors", | ||
newContent: `class A { | ||
private _a: string; | ||
public get a(): string { | ||
return this._a; | ||
} | ||
public set a(value: string) { | ||
this._a = value; | ||
} | ||
}`, | ||
}); |
21 changes: 21 additions & 0 deletions
21
tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess5.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// class A { | ||
//// /*a*/protected _a: string;/*b*/ | ||
//// } | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Generate 'get' and 'set' accessors", | ||
actionName: "Generate 'get' and 'set' accessors", | ||
actionDescription: "Generate 'get' and 'set' accessors", | ||
newContent: `class A { | ||
protected _a: string; | ||
public get a(): string { | ||
return this._a; | ||
} | ||
public set a(value: string) { | ||
this._a = value; | ||
} | ||
}`, | ||
}); |
21 changes: 21 additions & 0 deletions
21
tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess6.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// class A { | ||
//// /*a*/public _a: string;/*b*/ | ||
//// } | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Generate 'get' and 'set' accessors", | ||
actionName: "Generate 'get' and 'set' accessors", | ||
actionDescription: "Generate 'get' and 'set' accessors", | ||
newContent: `class A { | ||
private _a: string; | ||
public get a(): string { | ||
return this._a; | ||
} | ||
public set a(value: string) { | ||
this._a = value; | ||
} | ||
}`, | ||
}); |
21 changes: 21 additions & 0 deletions
21
tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess7.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// class A { | ||
//// /*a*/_a: string;/*b*/ | ||
//// } | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Generate 'get' and 'set' accessors", | ||
actionName: "Generate 'get' and 'set' accessors", | ||
actionDescription: "Generate 'get' and 'set' accessors", | ||
newContent: `class A { | ||
_a: string; | ||
get a(): string { | ||
return this._a; | ||
} | ||
set a(value: string) { | ||
this._a = value; | ||
} | ||
}`, | ||
}); |
21 changes: 21 additions & 0 deletions
21
tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess8.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// class A { | ||
//// /*a*/a: string;/*b*/ | ||
//// } | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Generate 'get' and 'set' accessors", | ||
actionName: "Generate 'get' and 'set' accessors", | ||
actionDescription: "Generate 'get' and 'set' accessors", | ||
newContent: `class A { | ||
_a: string; | ||
get a(): string { | ||
return this._a; | ||
} | ||
set a(value: string) { | ||
this._a = value; | ||
} | ||
}`, | ||
}); |
Oops, something went wrong.