Consistently use ScriptInfo for converting positions to Locations (#25623) (#25777)

* Consistently use ScriptInfo for converting positions to Locations

* Code review
This commit is contained in:
Andy
2018-07-18 14:49:06 -07:00
committed by GitHub
parent 53d240015c
commit 33df18de0c
3 changed files with 65 additions and 48 deletions

View File

@@ -1433,7 +1433,7 @@ namespace ts.server {
return project.getLanguageService().getCompletionEntryDetails(file, position, name, formattingOptions, source, this.getPreferences(file));
});
return simplifiedResult
? result.map(details => ({ ...details, codeActions: map(details.codeActions, action => this.mapCodeAction(project, action)) }))
? result.map(details => ({ ...details, codeActions: map(details.codeActions, action => this.mapCodeAction(action)) }))
: result;
}
@@ -1735,7 +1735,7 @@ namespace ts.server {
const renameScriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(renameFilename))!;
mappedRenameLocation = getLocationInNewDocument(getSnapshotText(renameScriptInfo.getSnapshot()), renameFilename, renameLocation, edits);
}
return { renameLocation: mappedRenameLocation, renameFilename, edits: this.mapTextChangesToCodeEdits(project, edits) };
return { renameLocation: mappedRenameLocation, renameFilename, edits: this.mapTextChangesToCodeEdits(edits) };
}
else {
return result;
@@ -1747,7 +1747,7 @@ namespace ts.server {
const { file, project } = this.getFileAndProject(scope.args);
const changes = project.getLanguageService().organizeImports({ type: "file", fileName: file }, this.getFormatOptions(file), this.getPreferences(file));
if (simplifiedResult) {
return this.mapTextChangesToCodeEdits(project, changes);
return this.mapTextChangesToCodeEdits(changes);
}
else {
return changes;
@@ -1763,7 +1763,7 @@ namespace ts.server {
this.projectService,
project => project.getLanguageService().getEditsForFileRename(oldPath, newPath, formatOptions, preferences),
(a, b) => a.fileName === b.fileName);
return simplifiedResult ? changes.map(c => this.mapTextChangeToCodeEditUsingScriptInfoOrConfigFile(c)) : changes;
return simplifiedResult ? changes.map(c => this.mapTextChangeToCodeEdit(c)) : changes;
}
private getCodeFixes(args: protocol.CodeFixRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.CodeFixAction> | ReadonlyArray<CodeFixAction> | undefined {
@@ -1776,7 +1776,7 @@ namespace ts.server {
const { startPosition, endPosition } = this.getStartAndEndPosition(args, scriptInfo);
const codeActions = project.getLanguageService().getCodeFixesAtPosition(file, startPosition, endPosition, args.errorCodes!, this.getFormatOptions(file), this.getPreferences(file));
return simplifiedResult ? codeActions.map(codeAction => this.mapCodeFixAction(project, codeAction)) : codeActions;
return simplifiedResult ? codeActions.map(codeAction => this.mapCodeFixAction(codeAction)) : codeActions;
}
private getCombinedCodeFix({ scope, fixId }: protocol.GetCombinedCodeFixRequestArgs, simplifiedResult: boolean): protocol.CombinedCodeActions | CombinedCodeActions {
@@ -1784,7 +1784,7 @@ namespace ts.server {
const { file, project } = this.getFileAndProject(scope.args);
const res = project.getLanguageService().getCombinedCodeFix({ type: "file", fileName: file }, fixId, this.getFormatOptions(file), this.getPreferences(file));
if (simplifiedResult) {
return { changes: this.mapTextChangesToCodeEdits(project, res.changes), commands: res.commands };
return { changes: this.mapTextChangesToCodeEdits(res.changes), commands: res.commands };
}
else {
return res;
@@ -1824,28 +1824,20 @@ namespace ts.server {
return { startPosition, endPosition };
}
private mapCodeAction(project: Project, { description, changes, commands }: CodeAction): protocol.CodeAction {
return { description, changes: this.mapTextChangesToCodeEdits(project, changes), commands };
private mapCodeAction({ description, changes, commands }: CodeAction): protocol.CodeAction {
return { description, changes: this.mapTextChangesToCodeEdits(changes), commands };
}
private mapCodeFixAction(project: Project, { fixName, description, changes, commands, fixId, fixAllDescription }: CodeFixAction): protocol.CodeFixAction {
return { fixName, description, changes: this.mapTextChangesToCodeEdits(project, changes), commands, fixId, fixAllDescription };
private mapCodeFixAction({ fixName, description, changes, commands, fixId, fixAllDescription }: CodeFixAction): protocol.CodeFixAction {
return { fixName, description, changes: this.mapTextChangesToCodeEdits(changes), commands, fixId, fixAllDescription };
}
private mapTextChangesToCodeEdits(project: Project, textChanges: ReadonlyArray<FileTextChanges>): protocol.FileCodeEdits[] {
return textChanges.map(change => this.mapTextChangeToCodeEdit(project, change));
private mapTextChangesToCodeEdits(textChanges: ReadonlyArray<FileTextChanges>): protocol.FileCodeEdits[] {
return textChanges.map(change => this.mapTextChangeToCodeEdit(change));
}
private mapTextChangeToCodeEdit(project: Project, change: FileTextChanges): protocol.FileCodeEdits {
return mapTextChangesToCodeEditsForFile(change, project.getSourceFileOrConfigFile(this.normalizePath(change.fileName)));
}
private mapTextChangeToCodeEditUsingScriptInfoOrConfigFile(change: FileTextChanges): protocol.FileCodeEdits {
return mapTextChangesToCodeEditsUsingScriptInfoOrConfig(change, this.projectService.getScriptInfoOrConfig(this.normalizePath(change.fileName)));
}
private normalizePath(fileName: string) {
return normalizedPathToPath(toNormalizedPath(fileName), this.host.getCurrentDirectory(), fileName => this.getCanonicalFileName(fileName));
private mapTextChangeToCodeEdit(change: FileTextChanges): protocol.FileCodeEdits {
return mapTextChangesToCodeEdits(change, this.projectService.getScriptInfoOrConfig(change.fileName));
}
private convertTextChangeToCodeEdit(change: TextChange, scriptInfo: ScriptInfo): protocol.CodeEdit {
@@ -2357,35 +2349,14 @@ namespace ts.server {
return { file: fileName, start: scriptInfo.positionToLineOffset(textSpan.start), end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)) };
}
function mapTextChangesToCodeEditsForFile(textChanges: FileTextChanges, sourceFile: SourceFile | undefined): protocol.FileCodeEdits {
Debug.assert(!!textChanges.isNewFile === !sourceFile, "Expected isNewFile for (only) new files", () => JSON.stringify({ isNewFile: !!textChanges.isNewFile, hasSourceFile: !!sourceFile }));
if (sourceFile) {
return {
fileName: textChanges.fileName,
textChanges: textChanges.textChanges.map(textChange => convertTextChangeToCodeEdit(textChange, sourceFile)),
};
}
else {
return convertNewFileTextChangeToCodeEdit(textChanges);
}
}
function mapTextChangesToCodeEditsUsingScriptInfoOrConfig(textChanges: FileTextChanges, scriptInfo: ScriptInfoOrConfig | undefined): protocol.FileCodeEdits {
function mapTextChangesToCodeEdits(textChanges: FileTextChanges, scriptInfo: ScriptInfoOrConfig | undefined): protocol.FileCodeEdits {
Debug.assert(!!textChanges.isNewFile === !scriptInfo, "Expected isNewFile for (only) new files", () => JSON.stringify({ isNewFile: !!textChanges.isNewFile, hasScriptInfo: !!scriptInfo }));
return scriptInfo
? { fileName: textChanges.fileName, textChanges: textChanges.textChanges.map(textChange => convertTextChangeToCodeEditUsingScriptInfoOrConfig(textChange, scriptInfo)) }
? { fileName: textChanges.fileName, textChanges: textChanges.textChanges.map(textChange => convertTextChangeToCodeEdit(textChange, scriptInfo)) }
: convertNewFileTextChangeToCodeEdit(textChanges);
}
function convertTextChangeToCodeEdit(change: TextChange, sourceFile: SourceFile): protocol.CodeEdit {
return {
start: convertToLocation(sourceFile.getLineAndCharacterOfPosition(change.span.start)),
end: convertToLocation(sourceFile.getLineAndCharacterOfPosition(change.span.start + change.span.length)),
newText: change.newText ? change.newText : "",
};
}
function convertTextChangeToCodeEditUsingScriptInfoOrConfig(change: TextChange, scriptInfo: ScriptInfoOrConfig): protocol.CodeEdit {
function convertTextChangeToCodeEdit(change: TextChange, scriptInfo: ScriptInfoOrConfig): protocol.CodeEdit {
return { start: positionToLineOffset(scriptInfo, change.span.start), end: positionToLineOffset(scriptInfo, textSpanEnd(change.span)), newText: change.newText };
}

View File

@@ -515,6 +515,10 @@ namespace ts.projectSystem {
return session.executeCommand(makeSessionRequest(command, args)).response as TResponse["body"];
}
export function executeSessionRequestNoResponse<TRequest extends protocol.Request>(session: server.Session, command: TRequest["command"], args: TRequest["arguments"]): void {
session.executeCommand(makeSessionRequest(command, args));
}
export function openFilesForSession(files: ReadonlyArray<File | { readonly file: File | string, readonly projectRootPath: string }>, session: server.Session): void {
for (const file of files) {
session.executeCommand(makeSessionRequest<protocol.OpenRequestArgs>(CommandNames.Open,
@@ -9256,6 +9260,50 @@ export function Test2() {
});
});
describe("Untitled files", () => {
it("Can convert positions to locations", () => {
const aTs: File = { path: "/proj/a.ts", content: "" };
const tsconfig: File = { path: "/proj/tsconfig.json", content: "{}" };
const session = createSession(createServerHost([aTs, tsconfig]));
openFilesForSession([aTs], session);
const untitledFile = "untitled:^Untitled-1";
executeSessionRequestNoResponse<protocol.OpenRequest>(session, protocol.CommandTypes.Open, {
file: untitledFile,
fileContent: "let foo = 1;\nfooo/**/",
scriptKindName: "TS",
projectRootPath: "/proj",
});
const response = executeSessionRequest<protocol.CodeFixRequest, protocol.CodeFixResponse>(session, protocol.CommandTypes.GetCodeFixes, {
file: untitledFile,
startLine: 2,
startOffset: 1,
endLine: 2,
endOffset: 5,
errorCodes: [Diagnostics.Cannot_find_name_0_Did_you_mean_1.code],
});
assert.deepEqual<ReadonlyArray<protocol.CodeFixAction> | undefined>(response, [
{
description: "Change spelling to 'foo'",
fixAllDescription: "Fix all detected spelling errors",
fixId: "fixSpelling",
fixName: "spelling",
changes: [{
fileName: untitledFile,
textChanges: [{
start: { line: 2, offset: 1 },
end: { line: 2, offset: 5 },
newText: "foo",
}],
}],
commands: undefined,
},
]);
});
});
function makeReferenceItem(file: File, isDefinition: boolean, text: string, lineText: string, options?: SpanFromSubstringOptions): protocol.ReferencesResponseItem {
return {
...protocolFileSpanFromSubstring(file, text, options),

View File

@@ -8893,8 +8893,6 @@ declare namespace ts.server {
private mapCodeFixAction;
private mapTextChangesToCodeEdits;
private mapTextChangeToCodeEdit;
private mapTextChangeToCodeEditUsingScriptInfoOrConfigFile;
private normalizePath;
private convertTextChangeToCodeEdit;
private getBraceMatching;
private getDiagnosticsForProject;