Skip to content

Commit 326ba1c

Browse files
committed
Address PR comments
1 parent d2b866f commit 326ba1c

File tree

6 files changed

+60
-110
lines changed

6 files changed

+60
-110
lines changed

src/compiler/diagnosticMessages.json

+9
Original file line numberDiff line numberDiff line change
@@ -3556,6 +3556,15 @@
35563556
"code": 90022
35573557
},
35583558

3559+
"Convert function to an ES2015 class": {
3560+
"category": "Message",
3561+
"code": 95001
3562+
},
3563+
"Convert function '{0}' to class": {
3564+
"category": "Message",
3565+
"code": 95002
3566+
},
3567+
35593568
"Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": {
35603569
"category": "Error",
35613570
"code": 8017

src/services/refactorProvider.ts

+19-17
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,20 @@ namespace ts {
88
description: string;
99

1010
/** Compute the associated code actions */
11-
getCodeActions(context: RefactorContext, positionOrRange: number | TextRange): CodeAction[];
11+
getCodeActions(context: RefactorContext): CodeAction[];
1212

1313
/** A fast syntactic check to see if the refactor is applicable at given position. */
14-
isApplicableForPositionOrRange(context: QueryRefactorContext, positionOrRange: number | TextRange): boolean;
14+
isApplicable(context: RefactorContext): boolean;
1515
}
1616

17-
export interface QueryRefactorContext {
17+
export interface RefactorContext {
1818
file: SourceFile;
19+
startPosition: number;
20+
endPosition?: number;
1921
program: Program;
20-
}
21-
22-
export interface RefactorContext extends QueryRefactorContext {
2322
newLineCharacter: string;
24-
rulesProvider: formatting.RulesProvider;
23+
rulesProvider?: formatting.RulesProvider;
24+
cancellationToken?: CancellationToken;
2525
}
2626

2727
export namespace refactor {
@@ -33,31 +33,33 @@ namespace ts {
3333
refactors.set(refactor.name, refactor);
3434
}
3535

36-
export function getApplicableRefactors(
37-
context: QueryRefactorContext,
38-
positionOrRange: number | TextRange): ApplicableRefactorInfo[] | undefined {
36+
export function getApplicableRefactors(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
3937

4038
let results: ApplicableRefactorInfo[];
39+
const refactorList: Refactor[] = [];
4140
refactors.forEach(refactor => {
42-
if (refactor.isApplicableForPositionOrRange(context, positionOrRange)) {
41+
refactorList.push(refactor);
42+
});
43+
for (const refactor of refactorList) {
44+
if (context.cancellationToken && context.cancellationToken.isCancellationRequested()) {
45+
return results;
46+
}
47+
if (refactor.isApplicable(context)) {
4348
(results || (results = [])).push({ name: refactor.name, description: refactor.description });
4449
}
45-
});
50+
}
4651
return results;
4752
}
4853

49-
export function getRefactorCodeActions(
50-
context: RefactorContext,
51-
positionOrRange: number | TextRange,
52-
refactorName: string): CodeAction[] | undefined {
54+
export function getRefactorCodeActions(context: RefactorContext, refactorName: string): CodeAction[] | undefined {
5355

5456
let result: CodeAction[];
5557
const refactor = refactors.get(refactorName);
5658
if (!refactor) {
5759
return undefined;
5860
}
5961

60-
const codeActions = refactor.getCodeActions(context, positionOrRange);
62+
const codeActions = refactor.getCodeActions(context);
6163
if (codeActions) {
6264
addRange((result || (result = [])), codeActions);
6365
}

src/services/refactors/addAsyncSuffix.ts

-52
This file was deleted.

src/services/refactors/convertFunctionToEs6Class.ts

+15-30
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,33 @@
33
namespace ts.refactor {
44
const convertFunctionToES6Class: Refactor = {
55
name: "Convert to ES2015 class",
6-
description: "Convert a pre-ES2015 function into an ES2015 class",
6+
description: Diagnostics.Convert_function_to_an_ES2015_class.message,
77
getCodeActions,
8-
isApplicableForPositionOrRange
8+
isApplicable
99
};
1010

1111
registerRefactor(convertFunctionToES6Class);
1212

13-
function isApplicableForPositionOrRange(context: QueryRefactorContext, positionOrRange: number | TextRange): boolean {
14-
const start = typeof positionOrRange === "number" ? positionOrRange : positionOrRange.pos;
13+
function isApplicable(context: RefactorContext): boolean {
14+
const start = context.startPosition;
1515
const node = getTokenAtPosition(context.file, start);
1616
const checker = context.program.getTypeChecker();
17-
const symbol = checker.getSymbolAtLocation(node);
18-
if (isClassLikeSymbol(symbol)) {
19-
return true;
20-
}
21-
22-
function isClassLikeSymbol(symbol: Symbol) {
23-
if (!symbol || !symbol.valueDeclaration) {
24-
return false;
25-
}
17+
let symbol = checker.getSymbolAtLocation(node);
2618

27-
let targetSymbol: Symbol;
28-
if (symbol.valueDeclaration.kind === SyntaxKind.FunctionDeclaration) {
29-
targetSymbol = symbol;
30-
}
31-
else if (isDeclarationOfFunctionOrClassExpression(symbol)) {
32-
targetSymbol = (symbol.valueDeclaration as VariableDeclaration).initializer.symbol;
33-
}
34-
35-
// if there is a prototype property assignment like:
36-
// foo.prototype.method = function () { }
37-
// then the symbol for "foo" will have a member
38-
return targetSymbol && targetSymbol.members && targetSymbol.members.size > 0;
19+
if (symbol && isDeclarationOfFunctionOrClassExpression(symbol)) {
20+
symbol = (symbol.valueDeclaration as VariableDeclaration).initializer.symbol;
3921
}
22+
23+
return symbol && symbol.flags & SymbolFlags.Function && symbol.members && symbol.members.size > 0;
4024
}
4125

42-
function getCodeActions(context: RefactorContext, positionOrRange: number | TextRange): CodeAction[] | undefined {
43-
const start = typeof positionOrRange === "number" ? positionOrRange : positionOrRange.pos;
26+
function getCodeActions(context: RefactorContext): CodeAction[] | undefined {
27+
const start = context.startPosition;
4428
const sourceFile = context.file;
4529
const checker = context.program.getTypeChecker();
4630
const token = getTokenAtPosition(sourceFile, start);
4731
const ctorSymbol = checker.getSymbolAtLocation(token);
32+
const newLine = context.rulesProvider.getFormatOptions().newLineCharacter;
4833

4934
const deletedNodes: Node[] = [];
5035
const deletes: (() => any)[] = [];
@@ -54,7 +39,7 @@ namespace ts.refactor {
5439
}
5540

5641
const ctorDeclaration = ctorSymbol.valueDeclaration;
57-
const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
42+
const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context as { newLineCharacter: string, rulesProvider: formatting.RulesProvider });
5843

5944
let precedingNode: Node;
6045
let newClassDeclaration: ClassDeclaration;
@@ -82,13 +67,13 @@ namespace ts.refactor {
8267
}
8368

8469
// Because the preceding node could be touched, we need to insert nodes before delete nodes.
85-
changeTracker.insertNodeAfter(sourceFile, precedingNode, newClassDeclaration, { suffix: "\n" });
70+
changeTracker.insertNodeAfter(sourceFile, precedingNode, newClassDeclaration, { suffix: newLine });
8671
for (const deleteCallback of deletes) {
8772
deleteCallback();
8873
}
8974

9075
return [{
91-
description: `Convert function ${ctorSymbol.name} to ES6 class`,
76+
description: formatStringFromArgs(Diagnostics.Convert_function_0_to_class.message, [ctorSymbol.name]),
9277
changes: changeTracker.getChanges()
9378
}];
9479

src/services/refactors/refactors.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
/// <reference path="addAsyncSuffix.ts" />
21
/// <reference path="convertFunctionToEs6Class.ts" />

src/services/services.ts

+17-10
Original file line numberDiff line numberDiff line change
@@ -1960,11 +1960,23 @@ namespace ts {
19601960
return Rename.getRenameInfo(program.getTypeChecker(), defaultLibFileName, getCanonicalFileName, getValidSourceFile(fileName), position);
19611961
}
19621962

1963+
function getRefactorContext(file: SourceFile, positionOrRange: number | TextRange, formatOptions?: FormatCodeSettings): RefactorContext {
1964+
const [startPosition, endPosition] = typeof positionOrRange === "number" ? [positionOrRange, undefined] : [positionOrRange.pos, positionOrRange.end];
1965+
return {
1966+
file,
1967+
startPosition,
1968+
endPosition,
1969+
program: getProgram(),
1970+
newLineCharacter: host.getNewLine(),
1971+
rulesProvider: getRuleProvider(formatOptions),
1972+
cancellationToken
1973+
};
1974+
}
1975+
19631976
function getApplicableRefactors(fileName: string, positionOrRange: number | TextRange): ApplicableRefactorInfo[] {
19641977
synchronizeHostData();
19651978
const file = getValidSourceFile(fileName);
1966-
const context: QueryRefactorContext = { file, program: getProgram() };
1967-
return refactor.getApplicableRefactors(context, positionOrRange);
1979+
return refactor.getApplicableRefactors(getRefactorContext(file, positionOrRange));
19681980
}
19691981

19701982
function getRefactorCodeActions(
@@ -1973,14 +1985,9 @@ namespace ts {
19731985
positionOrRange: number | TextRange,
19741986
refactorName: string): CodeAction[] | undefined {
19751987

1976-
const context: RefactorContext = {
1977-
file: getValidSourceFile(fileName),
1978-
newLineCharacter: host.getNewLine(),
1979-
program: getProgram(),
1980-
rulesProvider: getRuleProvider(formatOptions)
1981-
};
1982-
1983-
return refactor.getRefactorCodeActions(context, positionOrRange, refactorName);
1988+
synchronizeHostData();
1989+
const file = getValidSourceFile(fileName);
1990+
return refactor.getRefactorCodeActions(getRefactorContext(file, positionOrRange, formatOptions), refactorName);
19841991
}
19851992

19861993
return {

0 commit comments

Comments
 (0)