mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-24 20:44:53 -05:00
Support a "getCombinedCodeFix" service (#20338)
* Support a "getCombinedCodeFix" service * Rename things * Code review * Rename things * Update API baselines * CodeActionAll -> CombinedCodeActions * Take a `scope` parameter instead of `fileName` for flexibility * Renames and bugfixes * Make API changes internal * Code review * Update comment
This commit is contained in:
@@ -200,7 +200,7 @@ namespace ts.server {
|
||||
const response = this.processResponse<protocol.CompletionDetailsResponse>(request);
|
||||
Debug.assert(response.body.length === 1, "Unexpected length of completion details response body.");
|
||||
|
||||
const convertedCodeActions = map(response.body[0].codeActions, codeAction => this.convertCodeActions(codeAction, fileName));
|
||||
const convertedCodeActions = map(response.body[0].codeActions, ({ description, changes }) => ({ description, changes: this.convertChanges(changes, fileName) }));
|
||||
return { ...response.body[0], codeActions: convertedCodeActions };
|
||||
}
|
||||
|
||||
@@ -553,15 +553,18 @@ namespace ts.server {
|
||||
return notImplemented();
|
||||
}
|
||||
|
||||
getCodeFixesAtPosition(file: string, start: number, end: number, errorCodes: number[]): CodeAction[] {
|
||||
getCodeFixesAtPosition(file: string, start: number, end: number, errorCodes: ReadonlyArray<number>): ReadonlyArray<CodeFixAction> {
|
||||
const args: protocol.CodeFixRequestArgs = { ...this.createFileRangeRequestArgs(file, start, end), errorCodes };
|
||||
|
||||
const request = this.processRequest<protocol.CodeFixRequest>(CommandNames.GetCodeFixes, args);
|
||||
const response = this.processResponse<protocol.CodeFixResponse>(request);
|
||||
|
||||
return response.body.map(entry => this.convertCodeActions(entry, file));
|
||||
// TODO: GH#20538 shouldn't need cast
|
||||
return (response.body as ReadonlyArray<protocol.CodeFixAction>).map(({ description, changes, fixId }) => ({ description, changes: this.convertChanges(changes, file), fixId }));
|
||||
}
|
||||
|
||||
getCombinedCodeFix = notImplemented;
|
||||
|
||||
applyCodeActionCommand = notImplemented;
|
||||
|
||||
private createFileLocationOrRangeRequestArgs(positionOrRange: number | TextRange, fileName: string): protocol.FileLocationOrRangeRequestArgs {
|
||||
@@ -638,14 +641,11 @@ namespace ts.server {
|
||||
});
|
||||
}
|
||||
|
||||
convertCodeActions(entry: protocol.CodeAction, fileName: string): CodeAction {
|
||||
return {
|
||||
description: entry.description,
|
||||
changes: entry.changes.map(change => ({
|
||||
fileName: change.fileName,
|
||||
textChanges: change.textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, fileName))
|
||||
}))
|
||||
};
|
||||
private convertChanges(changes: protocol.FileCodeEdits[], fileName: string): FileTextChanges[] {
|
||||
return changes.map(change => ({
|
||||
fileName: change.fileName,
|
||||
textChanges: change.textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, fileName))
|
||||
}));
|
||||
}
|
||||
|
||||
convertTextChangeToCodeEdit(change: protocol.CodeEdit, fileName: string): ts.TextChange {
|
||||
|
||||
@@ -100,9 +100,14 @@ namespace ts.server.protocol {
|
||||
BreakpointStatement = "breakpointStatement",
|
||||
CompilerOptionsForInferredProjects = "compilerOptionsForInferredProjects",
|
||||
GetCodeFixes = "getCodeFixes",
|
||||
ApplyCodeActionCommand = "applyCodeActionCommand",
|
||||
/* @internal */
|
||||
GetCodeFixesFull = "getCodeFixes-full",
|
||||
// TODO: GH#20538
|
||||
/* @internal */
|
||||
GetCombinedCodeFix = "getCombinedCodeFix",
|
||||
/* @internal */
|
||||
GetCombinedCodeFixFull = "getCombinedCodeFix-full",
|
||||
ApplyCodeActionCommand = "applyCodeActionCommand",
|
||||
GetSupportedCodeFixes = "getSupportedCodeFixes",
|
||||
|
||||
GetApplicableRefactors = "getApplicableRefactors",
|
||||
@@ -552,6 +557,19 @@ namespace ts.server.protocol {
|
||||
arguments: CodeFixRequestArgs;
|
||||
}
|
||||
|
||||
// TODO: GH#20538
|
||||
/* @internal */
|
||||
export interface GetCombinedCodeFixRequest extends Request {
|
||||
command: CommandTypes.GetCombinedCodeFix;
|
||||
arguments: GetCombinedCodeFixRequestArgs;
|
||||
}
|
||||
|
||||
// TODO: GH#20538
|
||||
/* @internal */
|
||||
export interface GetCombinedCodeFixResponse extends Response {
|
||||
body: CombinedCodeActions;
|
||||
}
|
||||
|
||||
export interface ApplyCodeActionCommandRequest extends Request {
|
||||
command: CommandTypes.ApplyCodeActionCommand;
|
||||
arguments: ApplyCodeActionCommandRequestArgs;
|
||||
@@ -601,7 +619,21 @@ namespace ts.server.protocol {
|
||||
/**
|
||||
* Errorcodes we want to get the fixes for.
|
||||
*/
|
||||
errorCodes?: number[];
|
||||
errorCodes?: ReadonlyArray<number>;
|
||||
}
|
||||
|
||||
// TODO: GH#20538
|
||||
/* @internal */
|
||||
export interface GetCombinedCodeFixRequestArgs {
|
||||
scope: GetCombinedCodeFixScope;
|
||||
fixId: {};
|
||||
}
|
||||
|
||||
// TODO: GH#20538
|
||||
/* @internal */
|
||||
export interface GetCombinedCodeFixScope {
|
||||
type: "file";
|
||||
args: FileRequestArgs;
|
||||
}
|
||||
|
||||
export interface ApplyCodeActionCommandRequestArgs {
|
||||
@@ -1587,7 +1619,7 @@ namespace ts.server.protocol {
|
||||
|
||||
export interface CodeFixResponse extends Response {
|
||||
/** The code actions that are available */
|
||||
body?: CodeAction[];
|
||||
body?: CodeAction[]; // TODO: GH#20538 CodeFixAction[]
|
||||
}
|
||||
|
||||
export interface CodeAction {
|
||||
@@ -1599,6 +1631,23 @@ namespace ts.server.protocol {
|
||||
commands?: {}[];
|
||||
}
|
||||
|
||||
// TODO: GH#20538
|
||||
/* @internal */
|
||||
export interface CombinedCodeActions {
|
||||
changes: ReadonlyArray<FileCodeEdits>;
|
||||
commands?: ReadonlyArray<{}>;
|
||||
}
|
||||
|
||||
// TODO: GH#20538
|
||||
/* @internal */
|
||||
export interface CodeFixAction extends CodeAction {
|
||||
/**
|
||||
* If present, one may call 'getCombinedCodeFix' with this fixId.
|
||||
* This may be omitted to indicate that the code fix can't be applied in a group.
|
||||
*/
|
||||
fixId?: {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Format and format on key response message.
|
||||
*/
|
||||
|
||||
@@ -1538,18 +1538,14 @@ namespace ts.server {
|
||||
const oldText = snapshot.getText(0, snapshot.getLength());
|
||||
mappedRenameLocation = getLocationInNewDocument(oldText, renameFilename, renameLocation, edits);
|
||||
}
|
||||
return {
|
||||
renameLocation: mappedRenameLocation,
|
||||
renameFilename,
|
||||
edits: edits.map(change => this.mapTextChangesToCodeEdits(project, change))
|
||||
};
|
||||
return { renameLocation: mappedRenameLocation, renameFilename, edits: this.mapTextChangesToCodeEdits(project, edits) };
|
||||
}
|
||||
else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private getCodeFixes(args: protocol.CodeFixRequestArgs, simplifiedResult: boolean): protocol.CodeAction[] | CodeAction[] {
|
||||
private getCodeFixes(args: protocol.CodeFixRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.CodeAction> | ReadonlyArray<CodeAction> {
|
||||
if (args.errorCodes.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -1571,6 +1567,19 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
private getCombinedCodeFix({ scope, fixId }: protocol.GetCombinedCodeFixRequestArgs, simplifiedResult: boolean): protocol.CombinedCodeActions | CombinedCodeActions {
|
||||
Debug.assert(scope.type === "file");
|
||||
const { file, project } = this.getFileAndProject(scope.args);
|
||||
const formatOptions = this.projectService.getFormatCodeOptions(file);
|
||||
const res = project.getLanguageService().getCombinedCodeFix({ type: "file", fileName: file }, fixId, formatOptions);
|
||||
if (simplifiedResult) {
|
||||
return { changes: this.mapTextChangesToCodeEdits(project, res.changes), commands: res.commands };
|
||||
}
|
||||
else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
private applyCodeActionCommand(args: protocol.ApplyCodeActionCommandRequestArgs): {} {
|
||||
const commands = args.command as CodeActionCommand | CodeActionCommand[]; // They should be sending back the command we sent them.
|
||||
for (const command of toArray(commands)) {
|
||||
@@ -1605,15 +1614,15 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private mapCodeAction({ description, changes: unmappedChanges, commands }: CodeAction, scriptInfo: ScriptInfo): protocol.CodeAction {
|
||||
const changes = unmappedChanges.map(change => ({
|
||||
fileName: change.fileName,
|
||||
textChanges: change.textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo))
|
||||
}));
|
||||
const changes = unmappedChanges.map(change => this.mapTextChangesToCodeEditsUsingScriptinfo(change, scriptInfo));
|
||||
return { description, changes, commands };
|
||||
}
|
||||
|
||||
private mapTextChangesToCodeEdits(project: Project, textChanges: FileTextChanges): protocol.FileCodeEdits {
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(textChanges.fileName));
|
||||
private mapTextChangesToCodeEdits(project: Project, textChanges: ReadonlyArray<FileTextChanges>): protocol.FileCodeEdits[] {
|
||||
return textChanges.map(change => this.mapTextChangesToCodeEditsUsingScriptinfo(change, project.getScriptInfoForNormalizedPath(toNormalizedPath(change.fileName))));
|
||||
}
|
||||
|
||||
private mapTextChangesToCodeEditsUsingScriptinfo(textChanges: FileTextChanges, scriptInfo: ScriptInfo): protocol.FileCodeEdits {
|
||||
return {
|
||||
fileName: textChanges.fileName,
|
||||
textChanges: textChanges.textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo))
|
||||
@@ -1960,6 +1969,12 @@ namespace ts.server {
|
||||
[CommandNames.GetCodeFixesFull]: (request: protocol.CodeFixRequest) => {
|
||||
return this.requiredResponse(this.getCodeFixes(request.arguments, /*simplifiedResult*/ false));
|
||||
},
|
||||
[CommandNames.GetCombinedCodeFix]: (request: protocol.GetCombinedCodeFixRequest) => {
|
||||
return this.requiredResponse(this.getCombinedCodeFix(request.arguments, /*simplifiedResult*/ true));
|
||||
},
|
||||
[CommandNames.GetCombinedCodeFixFull]: (request: protocol.GetCombinedCodeFixRequest) => {
|
||||
return this.requiredResponse(this.getCombinedCodeFix(request.arguments, /*simplifiedResult*/ false));
|
||||
},
|
||||
[CommandNames.ApplyCodeActionCommand]: (request: protocol.ApplyCodeActionCommandRequest) => {
|
||||
return this.requiredResponse(this.applyCodeActionCommand(request.arguments));
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user