mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Add 'fileToRename' property to RenameInfo (#24702)
* Add 'fileToRename' property to RenameInfo * Update tests * Support directory rename
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
+22
-2
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -5101,6 +5101,11 @@ declare namespace ts {
|
||||
}
|
||||
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;
|
||||
@@ -6422,6 +6427,11 @@ declare namespace ts.server.protocol {
|
||||
* True if item can be renamed.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -5101,6 +5101,11 @@ declare namespace ts {
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -27,5 +27,5 @@ verify.renameLocations(r1, [r1, r2]);
|
||||
verify.renameLocations(r2, [r0, r1, r2]);
|
||||
for (const range of [r3, r4]) {
|
||||
goTo.rangeStart(range);
|
||||
verify.renameInfoFailed();
|
||||
verify.renameInfoSucceeded(/*displayName*/ "/a.ts", /*fullDisplayName*/ "/a.ts", /*kind*/ "module", /*kindModifiers*/ "", /*fileToRename*/ "/a.ts", range);
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ declare namespace FourSlashInterface {
|
||||
eachMarker(markers: ReadonlyArray<string>, action: (marker: Marker, index: number) => void): void;
|
||||
eachMarker(action: (marker: Marker, index: number) => void): void;
|
||||
rangeStart(range: Range): void;
|
||||
eachRange(action: () => void): void;
|
||||
eachRange(action: (range: Range) => void): void;
|
||||
bof(): void;
|
||||
eof(): void;
|
||||
implementation(): void;
|
||||
@@ -315,7 +315,7 @@ declare namespace FourSlashInterface {
|
||||
text: string;
|
||||
textSpan?: TextSpan;
|
||||
}[]): void;
|
||||
renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string): void;
|
||||
renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, range?: Range): void;
|
||||
renameInfoFailed(message?: string): void;
|
||||
renameLocations(startRanges: ArrayOrSingle<Range>, options: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges: Range[] }): void;
|
||||
|
||||
|
||||
@@ -5,12 +5,22 @@
|
||||
// @Filename: /a.ts
|
||||
////export const x = 0;
|
||||
|
||||
// @Filename: /dir/index.ts
|
||||
////export const x = 0;
|
||||
|
||||
// @Filename: /b.ts
|
||||
////import * as a from "[|./a|]";
|
||||
////import a2 = require("[|./a"|]);
|
||||
////import a2 = require("[|./a|]");
|
||||
////import * as dir from "[|{| "target": "dir" |}./dir|]";
|
||||
////import * as dir2 from "[|{| "target": "dir/index" |}./dir/index|]";
|
||||
|
||||
// @Filename: /c.js
|
||||
////const a = require("[|./a|]");
|
||||
|
||||
verify.noErrors();
|
||||
goTo.eachRange(() => { verify.renameInfoFailed(); });
|
||||
goTo.eachRange(range => {
|
||||
const target = range.marker && range.marker.data && range.marker.data.target;
|
||||
const name = target === "dir" ? "/dir" : target === "dir/index" ? "/dir/index.ts" : "/a.ts";
|
||||
const kind = target === "dir" ? "directory" : "module";
|
||||
verify.renameInfoSucceeded(/*displayName*/ name, /*fullDisplayName*/ name, /*kind*/ kind, /*kindModifiers*/ "", /*fileToRename*/ name, range);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user