diff --git a/src/harness/client.ts b/src/harness/client.ts index f8841eaa6b027..f59a9ca318884 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -3,12 +3,15 @@ namespace ts.server { writeMessage(message: string): void; } - interface RenameEntry extends RenameInfo { - fileName: string; - position: number; - locations: RenameLocation[]; - findInStrings: boolean; - findInComments: boolean; + interface RenameEntry { + readonly renameInfo: RenameInfo; + readonly inputs: { + readonly fileName: string; + readonly position: number; + readonly findInStrings: boolean; + readonly findInComments: boolean; + }; + readonly locations: RenameLocation[]; } /* @internal */ @@ -395,29 +398,36 @@ namespace ts.server { } } - return this.lastRenameEntry = { - canRename: body.info.canRename, - fileToRename: body.info.fileToRename, - displayName: body.info.displayName, - fullDisplayName: body.info.fullDisplayName, - kind: body.info.kind, - kindModifiers: body.info.kindModifiers, - localizedErrorMessage: body.info.localizedErrorMessage, - triggerSpan: createTextSpanFromBounds(position, position), - fileName, - position, - findInStrings: !!findInStrings, - findInComments: !!findInComments, + const renameInfo = body.info.canRename + ? identity({ + canRename: body.info.canRename, + fileToRename: body.info.fileToRename, + displayName: body.info.displayName, + fullDisplayName: body.info.fullDisplayName, + kind: body.info.kind, + kindModifiers: body.info.kindModifiers, + triggerSpan: createTextSpanFromBounds(position, position), + }) + : identity({ canRename: false, localizedErrorMessage: body.info.localizedErrorMessage }); + this.lastRenameEntry = { + renameInfo, + inputs: { + fileName, + position, + findInStrings: !!findInStrings, + findInComments: !!findInComments, + }, locations, }; + return renameInfo; } findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] { if (!this.lastRenameEntry || - this.lastRenameEntry.fileName !== fileName || - this.lastRenameEntry.position !== position || - this.lastRenameEntry.findInStrings !== findInStrings || - this.lastRenameEntry.findInComments !== findInComments) { + this.lastRenameEntry.inputs.fileName !== fileName || + this.lastRenameEntry.inputs.position !== position || + this.lastRenameEntry.inputs.findInStrings !== findInStrings || + this.lastRenameEntry.inputs.findInComments !== findInComments) { this.getRenameInfo(fileName, position, findInStrings, findInComments); } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index b7ce7437f3c4b..ccd7aa1d067b8 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1537,7 +1537,7 @@ Actual: ${stringify(fullActual)}`); public verifyRenameInfoSucceeded(displayName: string | undefined, fullDisplayName: string | undefined, kind: string | undefined, kindModifiers: string | undefined, fileToRename: string | undefined, expectedRange: Range | undefined): void { const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition); if (!renameInfo.canRename) { - this.raiseError("Rename did not succeed"); + throw this.raiseError("Rename did not succeed"); } this.validate("displayName", displayName, renameInfo.displayName); @@ -1563,9 +1563,8 @@ Actual: ${stringify(fullActual)}`); public verifyRenameInfoFailed(message?: string) { const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition); if (renameInfo.canRename) { - this.raiseError("Rename was expected to fail"); + throw this.raiseError("Rename was expected to fail"); } - this.validate("error", message, renameInfo.localizedErrorMessage); } diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 52389c9e0d65d..4a2d35503cca8 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -1087,23 +1087,18 @@ namespace ts.server.protocol { /** * Information about the item to be renamed. */ - export interface RenameInfo { + export type RenameInfo = RenameInfoSuccess | RenameInfoFailure; + export interface RenameInfoSuccess { /** * True if item can be renamed. */ - canRename: boolean; - + canRename: true; /** * File or directory to rename. * If set, `getEditsForFileRename` should be called instead of `findRenameLocations`. */ fileToRename?: string; - /** - * Error message if item can not be renamed. - */ - localizedErrorMessage?: string; - /** * Display name of the item to be renamed. */ @@ -1127,6 +1122,13 @@ namespace ts.server.protocol { /** Span of text to rename. */ triggerSpan: TextSpan; } + export interface RenameInfoFailure { + canRename: false; + /** + * Error message if item can not be renamed. + */ + localizedErrorMessage: string; + } /** * A group of text spans, all in 'file'. diff --git a/src/server/session.ts b/src/server/session.ts index 744cfe0492732..f664251cff651 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1184,8 +1184,15 @@ namespace ts.server { return { info: renameInfo, locs: this.toSpanGroups(locations) }; } - private mapRenameInfo({ canRename, fileToRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers, triggerSpan }: RenameInfo, scriptInfo: ScriptInfo): protocol.RenameInfo { - return { canRename, fileToRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers, triggerSpan: this.toLocationTextSpan(triggerSpan, scriptInfo) }; + private mapRenameInfo(info: RenameInfo, scriptInfo: ScriptInfo): protocol.RenameInfo { + if (info.canRename) { + const { canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan } = info; + return identity( + { canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan: this.toLocationTextSpan(triggerSpan, scriptInfo) }); + } + else { + return info; + } } private toSpanGroups(locations: ReadonlyArray): ReadonlyArray { diff --git a/src/services/rename.ts b/src/services/rename.ts index d7f23347cb457..7ba32c913090c 100644 --- a/src/services/rename.ts +++ b/src/services/rename.ts @@ -56,37 +56,26 @@ namespace ts.Rename { fileToRename: name, kind, displayName: name, - localizedErrorMessage: undefined, fullDisplayName: name, kindModifiers: ScriptElementKindModifier.none, triggerSpan, }; } - function getRenameInfoSuccess(displayName: string, fullDisplayName: string, kind: ScriptElementKind, kindModifiers: string, node: Node, sourceFile: SourceFile): RenameInfo { + function getRenameInfoSuccess(displayName: string, fullDisplayName: string, kind: ScriptElementKind, kindModifiers: string, node: Node, sourceFile: SourceFile): RenameInfoSuccess { return { canRename: true, fileToRename: undefined, kind, displayName, - localizedErrorMessage: undefined, fullDisplayName, kindModifiers, triggerSpan: createTriggerSpanForNode(node, sourceFile) }; } - function getRenameInfoError(diagnostic: DiagnosticMessage): RenameInfo { - // TODO: GH#18217 - return { - canRename: false, - localizedErrorMessage: getLocaleSpecificMessage(diagnostic), - displayName: undefined!, - fullDisplayName: undefined!, - kind: undefined!, - kindModifiers: undefined!, - triggerSpan: undefined! - }; + function getRenameInfoError(diagnostic: DiagnosticMessage): RenameInfoFailure { + return { canRename: false, localizedErrorMessage: getLocaleSpecificMessage(diagnostic) }; } function createTriggerSpanForNode(node: Node, sourceFile: SourceFile) { diff --git a/src/services/types.ts b/src/services/types.ts index ff2081d3c2244..011c98f9da698 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -821,20 +821,24 @@ namespace ts { tags?: JSDocTagInfo[]; } - export interface RenameInfo { - canRename: boolean; + export type RenameInfo = RenameInfoSuccess | RenameInfoFailure; + export interface RenameInfoSuccess { + canRename: true; /** * File or directory to rename. * If set, `getEditsForFileRename` should be called instead of `findRenameLocations`. */ fileToRename?: string; - localizedErrorMessage?: string; displayName: string; fullDisplayName: string; kind: ScriptElementKind; kindModifiers: string; triggerSpan: TextSpan; } + export interface RenameInfoFailure { + canRename: false; + localizedErrorMessage: string; + } export interface SignatureHelpParameter { name: string; diff --git a/src/testRunner/unittests/tsserverProjectSystem.ts b/src/testRunner/unittests/tsserverProjectSystem.ts index ad23e4a832356..41a8d9f292ebc 100644 --- a/src/testRunner/unittests/tsserverProjectSystem.ts +++ b/src/testRunner/unittests/tsserverProjectSystem.ts @@ -8309,7 +8309,6 @@ namespace ts.projectSystem { fullDisplayName: '"/users/username/projects/a/c/fc".C', kind: ScriptElementKind.constElement, kindModifiers: ScriptElementKindModifier.exportedModifier, - localizedErrorMessage: undefined, triggerSpan: protocolTextSpanFromSubstring(cFile.content, "C"), }, locs: [ @@ -9597,7 +9596,6 @@ export function Test2() { fullDisplayName: aTs.path, kind: ScriptElementKind.moduleElement, kindModifiers: "", - localizedErrorMessage: undefined, triggerSpan: protocolTextSpanFromSubstring(bTs.content, "a", { index: 1 }), }, locs: [{ file: bTs.path, locs: [protocolRenameSpanFromSubstring(bTs.content, "./a")] }], @@ -9618,7 +9616,6 @@ export function Test2() { fullDisplayName: "x", kind: ScriptElementKind.constElement, kindModifiers: ScriptElementKindModifier.none, - localizedErrorMessage: undefined, triggerSpan: protocolTextSpanFromSubstring(aTs.content, "x"), }, locs: [ @@ -10131,7 +10128,6 @@ declare class TestLib { fullDisplayName: "fnA", kind: ScriptElementKind.alias, kindModifiers: ScriptElementKindModifier.none, - localizedErrorMessage: undefined, triggerSpan: protocolTextSpanFromSubstring(userTs.content, "fnA", { index: 1 }), }, locs: [renameUserTs(userTs), renameATs(aTs)], @@ -10151,7 +10147,6 @@ declare class TestLib { fullDisplayName: '"/a/a".fnA', kind: ScriptElementKind.functionElement, kindModifiers: ScriptElementKindModifier.exportedModifier, - localizedErrorMessage: undefined, triggerSpan: protocolTextSpanFromSubstring(aTs.content, "fnA"), }, locs: [renameATs(aTs), renameUserTs(userTs)], @@ -10181,7 +10176,6 @@ declare class TestLib { fullDisplayName: "fnB", kind: ScriptElementKind.alias, kindModifiers: ScriptElementKindModifier.none, - localizedErrorMessage: undefined, triggerSpan: protocolTextSpanFromSubstring(userTs.content, "fnB", { index: 1 }), }, locs: [ diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 61fc5dbac4621..a454ffe3be26f 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -5114,20 +5114,24 @@ declare namespace ts { documentation?: SymbolDisplayPart[]; tags?: JSDocTagInfo[]; } - interface RenameInfo { - canRename: boolean; + type RenameInfo = RenameInfoSuccess | RenameInfoFailure; + interface RenameInfoSuccess { + canRename: true; /** * File or directory to rename. * If set, `getEditsForFileRename` should be called instead of `findRenameLocations`. */ fileToRename?: string; - localizedErrorMessage?: string; displayName: string; fullDisplayName: string; kind: ScriptElementKind; kindModifiers: string; triggerSpan: TextSpan; } + interface RenameInfoFailure { + canRename: false; + localizedErrorMessage: string; + } interface SignatureHelpParameter { name: string; documentation: SymbolDisplayPart[]; @@ -6437,20 +6441,17 @@ declare namespace ts.server.protocol { /** * Information about the item to be renamed. */ - interface RenameInfo { + type RenameInfo = RenameInfoSuccess | RenameInfoFailure; + interface RenameInfoSuccess { /** * True if item can be renamed. */ - canRename: boolean; + canRename: true; /** * File or directory to rename. * If set, `getEditsForFileRename` should be called instead of `findRenameLocations`. */ fileToRename?: string; - /** - * Error message if item can not be renamed. - */ - localizedErrorMessage?: string; /** * Display name of the item to be renamed. */ @@ -6470,6 +6471,13 @@ declare namespace ts.server.protocol { /** Span of text to rename. */ triggerSpan: TextSpan; } + interface RenameInfoFailure { + canRename: false; + /** + * Error message if item can not be renamed. + */ + localizedErrorMessage: string; + } /** * A group of text spans, all in 'file'. */ diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 54a37336d35cd..3ee556a58ddd4 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -5114,20 +5114,24 @@ declare namespace ts { documentation?: SymbolDisplayPart[]; tags?: JSDocTagInfo[]; } - interface RenameInfo { - canRename: boolean; + type RenameInfo = RenameInfoSuccess | RenameInfoFailure; + interface RenameInfoSuccess { + canRename: true; /** * File or directory to rename. * If set, `getEditsForFileRename` should be called instead of `findRenameLocations`. */ fileToRename?: string; - localizedErrorMessage?: string; displayName: string; fullDisplayName: string; kind: ScriptElementKind; kindModifiers: string; triggerSpan: TextSpan; } + interface RenameInfoFailure { + canRename: false; + localizedErrorMessage: string; + } interface SignatureHelpParameter { name: string; documentation: SymbolDisplayPart[];