mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-19 01:33:15 -05:00
fix(54283): Provide better UX when an invalid file is selected for 'move to file' refactoring (#54300)
This commit is contained in:
@@ -7612,6 +7612,10 @@
|
||||
"category": "Message",
|
||||
"code": 95178
|
||||
},
|
||||
"Cannot move to file, selected file is invalid": {
|
||||
"category": "Message",
|
||||
"code": 95179
|
||||
},
|
||||
|
||||
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -818,7 +818,7 @@ export class SessionClient implements LanguageService {
|
||||
const response = this.processResponse<protocol.GetEditsForRefactorResponse>(request);
|
||||
|
||||
if (!response.body) {
|
||||
return { edits: [], renameFilename: undefined, renameLocation: undefined };
|
||||
return { edits: [], renameFilename: undefined, renameLocation: undefined, notApplicableReason: undefined };
|
||||
}
|
||||
|
||||
const edits: FileTextChanges[] = this.convertCodeEditsToTextChanges(response.body.edits);
|
||||
@@ -832,7 +832,8 @@ export class SessionClient implements LanguageService {
|
||||
return {
|
||||
edits,
|
||||
renameFilename,
|
||||
renameLocation
|
||||
renameLocation,
|
||||
notApplicableReason: response.body.notApplicableReason,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -721,6 +721,7 @@ export interface RefactorEditInfo {
|
||||
*/
|
||||
renameLocation?: Location;
|
||||
renameFilename?: string;
|
||||
notApplicableReason?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2709,7 +2709,8 @@ export class Session<TMessage = string> implements EventSender {
|
||||
return {
|
||||
renameLocation: mappedRenameLocation,
|
||||
renameFilename,
|
||||
edits: this.mapTextChangesToCodeEdits(edits)
|
||||
edits: this.mapTextChangesToCodeEdits(edits),
|
||||
notApplicableReason: result.notApplicableReason,
|
||||
};
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -53,7 +53,9 @@ import {
|
||||
getRelativePathFromFile,
|
||||
getSynthesizedDeepClone,
|
||||
getUniqueName,
|
||||
hasJSFileExtension,
|
||||
hasSyntacticModifier,
|
||||
hasTSFileExtension,
|
||||
hostGetCanonicalFileName,
|
||||
Identifier,
|
||||
ImportDeclaration,
|
||||
@@ -162,8 +164,12 @@ registerRefactor(refactorNameForMoveToFile, {
|
||||
Debug.assert(actionName === refactorNameForMoveToFile, "Wrong refactor invoked");
|
||||
const statements = Debug.checkDefined(getStatementsToMove(context));
|
||||
Debug.assert(interactiveRefactorArguments, "No interactive refactor arguments available");
|
||||
const edits = textChanges.ChangeTracker.with(context, t => doChange(context, context.file, interactiveRefactorArguments.targetFile, context.program, statements, t, context.host, context.preferences));
|
||||
return { edits, renameFilename: undefined, renameLocation: undefined };
|
||||
const targetFile = interactiveRefactorArguments.targetFile;
|
||||
if (hasJSFileExtension(targetFile) || hasTSFileExtension(targetFile)) {
|
||||
const edits = textChanges.ChangeTracker.with(context, t => doChange(context, context.file, interactiveRefactorArguments.targetFile, context.program, statements, t, context.host, context.preferences));
|
||||
return { edits, renameFilename: undefined, renameLocation: undefined };
|
||||
}
|
||||
return { edits: [], renameFilename: undefined, renameLocation: undefined, notApplicableReason: getLocaleSpecificMessage(Diagnostics.Cannot_move_to_file_selected_file_is_invalid) };
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1002,6 +1002,7 @@ export interface RefactorEditInfo {
|
||||
renameFilename?: string;
|
||||
renameLocation?: number;
|
||||
commands?: CodeActionCommand[];
|
||||
notApplicableReason?: string;
|
||||
}
|
||||
|
||||
export type RefactorTriggerReason = "implicit" | "invoked";
|
||||
|
||||
@@ -96,28 +96,61 @@ describe("unittests:: tsserver:: refactors", () => {
|
||||
});
|
||||
|
||||
it("handles moving statement to an existing file", () => {
|
||||
const aTs: File = { path: "/Foo/a.ts", content: "const x = 0;" };
|
||||
const bTs: File = {
|
||||
path: "/Foo/b.ts", content: `import {} from "./bar";
|
||||
const a = 1;`};
|
||||
const tsconfig: File = { path: "/Foo/tsconfig.json", content: `{ "files": ["./a.ts", "./b.ts"] }` };
|
||||
const host = createServerHost([aTs, bTs, tsconfig]);
|
||||
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([aTs], session);
|
||||
const aTs: File = { path: "/Foo/a.ts", content: "const x = 0;" };
|
||||
const bTs: File = {
|
||||
path: "/Foo/b.ts", content: `import {} from "./bar";
|
||||
const a = 1;`};
|
||||
const tsconfig: File = { path: "/Foo/tsconfig.json", content: `{ "files": ["./a.ts", "./b.ts"] }` };
|
||||
const host = createServerHost([aTs, bTs, tsconfig]);
|
||||
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([aTs], session);
|
||||
|
||||
session.executeCommandSeq<ts.server.protocol.GetEditsForRefactorRequest>({
|
||||
command: ts.server.protocol.CommandTypes.GetEditsForRefactor,
|
||||
arguments: {
|
||||
file: aTs.path,
|
||||
startLine: 1,
|
||||
startOffset: 1,
|
||||
endLine: 2,
|
||||
endOffset: aTs.content.length,
|
||||
refactor: "Move to file",
|
||||
action: "Move to file",
|
||||
interactiveRefactorArguments: { targetFile: "/Foo/b.ts" },
|
||||
}
|
||||
session.executeCommandSeq<ts.server.protocol.GetEditsForRefactorRequest>({
|
||||
command: ts.server.protocol.CommandTypes.GetEditsForRefactor,
|
||||
arguments: {
|
||||
file: aTs.path,
|
||||
startLine: 1,
|
||||
startOffset: 1,
|
||||
endLine: 2,
|
||||
endOffset: aTs.content.length,
|
||||
refactor: "Move to file",
|
||||
action: "Move to file",
|
||||
interactiveRefactorArguments: { targetFile: "/Foo/b.ts" },
|
||||
}
|
||||
});
|
||||
baselineTsserverLogs("refactors", "handles moving statement to an existing file", session);
|
||||
});
|
||||
baselineTsserverLogs("refactors", "handles moving statement to an existing file", session);
|
||||
|
||||
it("handles moving statements to a non-TS file", () => {
|
||||
const aTs: File = {
|
||||
path: "/Foo/a.ts",
|
||||
content: "const x = 0;"
|
||||
};
|
||||
const bTxt: File = {
|
||||
path: "/Foo/b.txt",
|
||||
content: ""
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: "/Foo/tsconfig.json",
|
||||
content: `{ "files": ["./a.ts"] }`
|
||||
};
|
||||
const host = createServerHost([aTs, bTxt, tsconfig]);
|
||||
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([aTs], session);
|
||||
|
||||
session.executeCommandSeq<ts.server.protocol.GetEditsForRefactorRequest>({
|
||||
command: ts.server.protocol.CommandTypes.GetEditsForRefactor,
|
||||
arguments: {
|
||||
file: aTs.path,
|
||||
startLine: 1,
|
||||
startOffset: 1,
|
||||
endLine: 2,
|
||||
endOffset: aTs.content.length,
|
||||
refactor: "Move to file",
|
||||
action: "Move to file",
|
||||
interactiveRefactorArguments: { targetFile: "/Foo/b.txt" },
|
||||
}
|
||||
});
|
||||
baselineTsserverLogs("refactors", "handles moving statements to a non-TS file", session);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user