From cbbe34b35e548fa282ff18b3d9111e5963ea4bca Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 15 May 2018 13:55:26 -0700 Subject: [PATCH] Fix conversion of TextChanges to FileCodeEdits for new file (#24126) --- src/server/project.ts | 2 +- src/server/session.ts | 23 +++++++++++++++---- src/services/textChanges.ts | 2 +- src/services/types.ts | 1 + .../reference/api/tsserverlibrary.d.ts | 4 +++- tests/baselines/reference/api/typescript.d.ts | 1 + 6 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/server/project.ts b/src/server/project.ts index 6073cd9caef..5b1dbddfc20 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -964,7 +964,7 @@ namespace ts.server { return this.missingFilesMap && this.missingFilesMap.has(path); } - getScriptInfoForNormalizedPath(fileName: NormalizedPath) { + getScriptInfoForNormalizedPath(fileName: NormalizedPath): ScriptInfo | undefined { const scriptInfo = this.projectService.getScriptInfoForPath(this.toPath(fileName)); if (scriptInfo && !scriptInfo.isAttached(this)) { return Errors.ThrowProjectDoesNotContainDocument(fileName, this); diff --git a/src/server/session.ts b/src/server/session.ts index d0c58b20922..40f26785113 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1766,11 +1766,17 @@ namespace ts.server { 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)) - }; + 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); + } } private convertTextChangeToCodeEdit(change: TextChange, scriptInfo: ScriptInfo): protocol.CodeEdit { @@ -1781,6 +1787,13 @@ 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[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file); diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index de588120db1..1ddfa2e6448 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -719,7 +719,7 @@ namespace ts.textChanges { export function newFileChanges(oldFile: SourceFile, fileName: string, statements: ReadonlyArray, newLineCharacter: string): FileTextChanges { const text = statements.map(s => getNonformattedText(s, oldFile, newLineCharacter).text).join(newLineCharacter); - return { fileName, textChanges: [createTextChange(createTextSpan(0, 0), text)] }; + return { fileName, textChanges: [createTextChange(createTextSpan(0, 0), text)], isNewFile: true }; } function computeNewText(change: Change, sourceFile: SourceFile, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText): string { diff --git a/src/services/types.ts b/src/services/types.ts index 0d15213cb12..0e9dbccbd1b 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -439,6 +439,7 @@ namespace ts { export interface FileTextChanges { fileName: string; textChanges: TextChange[]; + isNewFile?: boolean; } export interface CodeAction { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index d3c9bb8849f..67bd6cbe980 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -4618,6 +4618,7 @@ declare namespace ts { interface FileTextChanges { fileName: string; textChanges: TextChange[]; + isNewFile?: boolean; } interface CodeAction { /** Description of the code action to display in the UI of the editor */ @@ -7898,7 +7899,7 @@ declare namespace ts.server { private detachScriptInfoFromProject; private addMissingFileWatcher; private isWatchedMissingFile; - getScriptInfoForNormalizedPath(fileName: NormalizedPath): ScriptInfo; + getScriptInfoForNormalizedPath(fileName: NormalizedPath): ScriptInfo | undefined; getScriptInfo(uncheckedFileName: string): ScriptInfo; filesToString(writeProjectFileNames: boolean): string; setCompilerOptions(compilerOptions: CompilerOptions): void; @@ -8492,6 +8493,7 @@ declare namespace ts.server { private mapTextChangesToCodeEdits; private mapTextChangesToCodeEditsUsingScriptinfo; private convertTextChangeToCodeEdit; + private convertNewFileTextChangeToCodeEdit; private getBraceMatching; private getDiagnosticsForProject; getCanonicalFileName(fileName: string): string; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 4f1b38c2c8a..ef435632a36 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -4618,6 +4618,7 @@ declare namespace ts { interface FileTextChanges { fileName: string; textChanges: TextChange[]; + isNewFile?: boolean; } interface CodeAction { /** Description of the code action to display in the UI of the editor */