Add 'fileToRename' property to RenameInfo (#24702)

* Add 'fileToRename' property to RenameInfo

* Update tests

* Support directory rename
This commit is contained in:
Andy
2018-09-10 11:25:03 -07:00
committed by GitHub
parent af8e44ac85
commit 24a5bdd1b1
11 changed files with 77 additions and 17 deletions

View File

@@ -397,6 +397,7 @@ 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,

View File

@@ -420,12 +420,12 @@ namespace FourSlash {
}
}
public goToEachRange(action: () => void) {
public goToEachRange(action: (range: Range) => void) {
const ranges = this.getRanges();
assert(ranges.length);
for (const range of ranges) {
this.selectRange(range);
action();
action(range);
}
}
@@ -1525,7 +1525,7 @@ Actual: ${stringify(fullActual)}`);
}
}
public verifyRenameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string) {
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");
@@ -1535,12 +1535,15 @@ Actual: ${stringify(fullActual)}`);
this.validate("fullDisplayName", fullDisplayName, renameInfo.fullDisplayName);
this.validate("kind", kind, renameInfo.kind);
this.validate("kindModifiers", kindModifiers, renameInfo.kindModifiers);
this.validate("fileToRename", fileToRename, renameInfo.fileToRename);
if (this.getRanges().length !== 1) {
this.raiseError("Expected a single range to be selected in the test file.");
if (!expectedRange) {
if (this.getRanges().length !== 1) {
this.raiseError("Expected a single range to be selected in the test file.");
}
expectedRange = this.getRanges()[0];
}
const expectedRange = this.getRanges()[0];
if (renameInfo.triggerSpan.start !== expectedRange.pos ||
ts.textSpanEnd(renameInfo.triggerSpan) !== expectedRange.end) {
this.raiseError("Expected triggerSpan [" + expectedRange.pos + "," + expectedRange.end + "). Got [" +
@@ -3977,7 +3980,7 @@ namespace FourSlashInterface {
this.state.goToRangeStart(range);
}
public eachRange(action: () => void) {
public eachRange(action: (range: FourSlash.Range) => void) {
this.state.goToEachRange(action);
}
@@ -4456,8 +4459,8 @@ namespace FourSlashInterface {
this.state.verifySemanticClassifications(classifications);
}
public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string) {
this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers);
public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, expectedRange?: FourSlash.Range) {
this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers, fileToRename, expectedRange);
}
public renameInfoFailed(message?: string) {

View File

@@ -1093,6 +1093,12 @@ namespace ts.server.protocol {
*/
canRename: boolean;
/**
* File or directory to rename.
* If set, `getEditsForFileRename` should be called instead of `findRenameLocations`.
*/
fileToRename?: string;
/**
* Error message if item can not be renamed.
*/

View File

@@ -1096,7 +1096,7 @@ namespace ts.server {
return projectInfo;
}
private getRenameInfo(args: protocol.FileLocationRequestArgs) {
private getRenameInfo(args: protocol.FileLocationRequestArgs): RenameInfo {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
return project.getLanguageService().getRenameInfo(file, position);

View File

@@ -25,8 +25,9 @@ namespace ts.Rename {
return undefined;
}
// Can't rename a module name.
if (isStringLiteralLike(node) && tryGetImportFromModuleSpecifier(node)) return undefined;
if (isStringLiteralLike(node) && tryGetImportFromModuleSpecifier(node)) {
return getRenameInfoForModule(node, sourceFile, symbol);
}
const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node);
const specifierName = (isImportOrExportSpecifierName(node) || isStringOrNumericLiteralLike(node) && node.parent.kind === SyntaxKind.ComputedPropertyName)
@@ -37,9 +38,28 @@ namespace ts.Rename {
return getRenameInfoSuccess(displayName, fullDisplayName, kind, SymbolDisplay.getSymbolModifiers(symbol), node, sourceFile);
}
function getRenameInfoForModule(node: StringLiteralLike, sourceFile: SourceFile, moduleSymbol: Symbol): RenameInfo | undefined {
const moduleSourceFile = find(moduleSymbol.declarations, isSourceFile);
if (!moduleSourceFile) return undefined;
const withoutIndex = node.text.endsWith("/index") || node.text.endsWith("/index.js") ? undefined : tryRemoveSuffix(removeFileExtension(moduleSourceFile.fileName), "/index");
const name = withoutIndex === undefined ? moduleSourceFile.fileName : withoutIndex;
const kind = withoutIndex === undefined ? ScriptElementKind.moduleElement : ScriptElementKind.directory;
return {
canRename: true,
fileToRename: name,
kind,
displayName: name,
localizedErrorMessage: undefined,
fullDisplayName: name,
kindModifiers: ScriptElementKindModifier.none,
triggerSpan: createTriggerSpanForNode(node, sourceFile),
};
}
function getRenameInfoSuccess(displayName: string, fullDisplayName: string, kind: ScriptElementKind, kindModifiers: string, node: Node, sourceFile: SourceFile): RenameInfo {
return {
canRename: true,
fileToRename: undefined,
kind,
displayName,
localizedErrorMessage: undefined,

View File

@@ -784,6 +784,11 @@ namespace ts {
export interface RenameInfo {
canRename: boolean;
/**
* File or directory to rename.
* If set, `getEditsForFileRename` should be called instead of `findRenameLocations`.
*/
fileToRename?: string;
localizedErrorMessage?: string;
displayName: string;
fullDisplayName: string;