Skip to content

Commit

Permalink
Support 'tsconfig.json' when converting TextChanges to CodeEdits (#24667
Browse files Browse the repository at this point in the history
) (#24772)

* Support 'tsconfig.json' when converting TextChanges to CodeEdits

* Create Project#getSourceFileOrConfigFile to use instead
  • Loading branch information
Andy committed Jun 7, 2018
1 parent b2ad86d commit 59134dc
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 25 deletions.
65 changes: 64 additions & 1 deletion src/harness/unittests/tsserverProjectSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ namespace ts.projectSystem {
return newRequest;
}

export function openFilesForSession(files: File[], session: server.Session) {
export function openFilesForSession(files: ReadonlyArray<File>, session: server.Session) {
for (const file of files) {
const request = makeSessionRequest<protocol.OpenRequestArgs>(CommandNames.Open, { file: file.path });
session.executeCommand(request);
Expand Down Expand Up @@ -6194,6 +6194,69 @@ namespace ts.projectSystem {
renameLocation: { line: 2, offset: 3 },
});
});

it("handles text changes in tsconfig.json", () => {
const aTs = {
path: "/a.ts",
content: "export const a = 0;",
};
const tsconfig = {
path: "/tsconfig.json",
content: '{ "files": ["./a.ts"] }',
};

const session = createSession(createServerHost([aTs, tsconfig]));
openFilesForSession([aTs], session);

const response1 = session.executeCommandSeq<server.protocol.GetEditsForRefactorRequest>({
command: server.protocol.CommandTypes.GetEditsForRefactor,
arguments: {
refactor: "Move to a new file",
action: "Move to a new file",
file: "/a.ts",
startLine: 1,
startOffset: 1,
endLine: 1,
endOffset: 20,
},
}).response;
assert.deepEqual(response1, {
edits: [
{
fileName: "/a.ts",
textChanges: [
{
start: { line: 1, offset: 1 },
end: { line: 1, offset: 20 },
newText: "",
},
],
},
{
fileName: "/tsconfig.json",
textChanges: [
{
start: { line: 1, offset: 21 },
end: { line: 1, offset: 21 },
newText: ", \"./a.1.ts\"",
},
],
},
{
fileName: "/a.1.ts",
textChanges: [
{
start: { line: 0, offset: 0 },
end: { line: 0, offset: 0 },
newText: "export const a = 0;",
},
],
}
],
renameFilename: undefined,
renameLocation: undefined,
});
});
});

describe("tsserverProjectSystem CachingFileSystemInformation", () => {
Expand Down
6 changes: 6 additions & 0 deletions src/server/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,12 @@ namespace ts.server {
return this.program.getSourceFileByPath(path);
}

/* @internal */
getSourceFileOrConfigFile(path: Path): SourceFile | undefined {
const options = this.program.getCompilerOptions();
return path === options.configFilePath ? options.configFile : this.getSourceFile(path);
}

close() {
if (this.program) {
// if we have a program - release all files that are enlisted in program but arent root
Expand Down
55 changes: 33 additions & 22 deletions src/server/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1766,20 +1766,10 @@ namespace ts.server {
}

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 | undefined): protocol.FileCodeEdits {
Debug.assert(!!textChanges.isNewFile === !scriptInfo);
if (scriptInfo) {
return {
fileName: textChanges.fileName,
textChanges: textChanges.textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo))
};
}
else {
return this.convertNewFileTextChangeToCodeEdit(textChanges);
}
return textChanges.map(change => {
const path = normalizedPathToPath(toNormalizedPath(change.fileName), this.host.getCurrentDirectory(), fileName => this.getCanonicalFileName(fileName));
return mapTextChangesToCodeEdits(change, project.getSourceFileOrConfigFile(path));
});
}

private convertTextChangeToCodeEdit(change: TextChange, scriptInfo: ScriptInfo): protocol.CodeEdit {
Expand All @@ -1790,14 +1780,7 @@ namespace ts.server {
};
}

private convertNewFileTextChangeToCodeEdit(textChanges: FileTextChanges): protocol.FileCodeEdits {
Debug.assert(textChanges.textChanges.length === 1);
const change = first(textChanges.textChanges);
Debug.assert(change.span.start === 0 && change.span.length === 0);
return { fileName: textChanges.fileName, textChanges: [{ start: { line: 0, offset: 0 }, end: { line: 0, offset: 0 }, newText: change.newText }] };
}

private getBraceMatching(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.TextSpan[] | TextSpan[] {
private getBraceMatching(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.TextSpan[] | TextSpan[] | undefined {
const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file);
const position = this.getPosition(args, scriptInfo);
Expand Down Expand Up @@ -2272,6 +2255,34 @@ namespace ts.server {
}
}

function mapTextChangesToCodeEdits(textChanges: FileTextChanges, sourceFile: SourceFile | undefined): protocol.FileCodeEdits {
Debug.assert(!!textChanges.isNewFile === !sourceFile);
if (sourceFile) {
return {
fileName: textChanges.fileName,
textChanges: textChanges.textChanges.map(textChange => convertTextChangeToCodeEdit(textChange, sourceFile)),
};
}
else {
return 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 convertNewFileTextChangeToCodeEdit(textChanges: FileTextChanges): protocol.FileCodeEdits {
Debug.assert(textChanges.textChanges.length === 1);
const change = first(textChanges.textChanges);
Debug.assert(change.span.start === 0 && change.span.length === 0);
return { fileName: textChanges.fileName, textChanges: [{ start: { line: 0, offset: 0 }, end: { line: 0, offset: 0 }, newText: change.newText }] };
}

export interface HandlerResponse {
response?: {};
responseRequired?: boolean;
Expand Down
2 changes: 0 additions & 2 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8523,9 +8523,7 @@ declare namespace ts.server {
private mapCodeAction;
private mapCodeFixAction;
private mapTextChangesToCodeEdits;
private mapTextChangesToCodeEditsUsingScriptinfo;
private convertTextChangeToCodeEdit;
private convertNewFileTextChangeToCodeEdit;
private getBraceMatching;
private getDiagnosticsForProject;
getCanonicalFileName(fileName: string): string;
Expand Down

0 comments on commit 59134dc

Please sign in to comment.