Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -7628,6 +7628,10 @@
"category": "Message",
"code": 95182
},
"Cannot move statements to the selected file": {
"category": "Message",
"code": 95183
},

"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
"category": "Error",
Expand Down
14 changes: 11 additions & 3 deletions src/services/refactors/moveToFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,20 +167,28 @@ registerRefactor(refactorNameForMoveToFile, {
getEditsForAction: function getRefactorEditsToMoveToFile(context, actionName, interactiveRefactorArguments): RefactorEditInfo | undefined {
Debug.assert(actionName === refactorNameForMoveToFile, "Wrong refactor invoked");
const statements = Debug.checkDefined(getStatementsToMove(context));
const { host, program } = context;
Debug.assert(interactiveRefactorArguments, "No interactive refactor arguments available");
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));
if (host.fileExists(targetFile) && program.getSourceFile(targetFile) === undefined) {
return error(getLocaleSpecificMessage(Diagnostics.Cannot_move_statements_to_the_selected_file));
}
const edits = textChanges.ChangeTracker.with(context, t => doChange(context, context.file, interactiveRefactorArguments.targetFile, 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) };
return error(getLocaleSpecificMessage(Diagnostics.Cannot_move_to_file_selected_file_is_invalid));
}
});

function error(notApplicableReason: string) {
return { edits: [], renameFilename: undefined, renameLocation: undefined, notApplicableReason };
}

function doChange(context: RefactorContext, oldFile: SourceFile, targetFile: string, program: Program, toMove: ToMove, changes: textChanges.ChangeTracker, host: LanguageServiceHost, preferences: UserPreferences): void {
const checker = program.getTypeChecker();
const usage = getUsageInfo(oldFile, toMove.all, checker);
//For a new file
// For a new file
if (!host.fileExists(targetFile)) {
changes.createNewFile(oldFile, targetFile, getNewStatementsAndRemoveFromOldFile(oldFile, targetFile, usage, changes, toMove, program, host, preferences));
addNewFileToTsconfig(program, changes, oldFile.fileName, targetFile, hostGetCanonicalFileName(host));
Expand Down
42 changes: 42 additions & 0 deletions src/testRunner/unittests/tsserver/refactors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,46 @@ describe("unittests:: tsserver:: refactors", () => {
});
baselineTsserverLogs("refactors", "handles moving statements to a non-TS file", session);
});

it("handles moving statements to a TS file that is not included in the TS project", () => {
const fooATs: File = {
path: "/Foo/a.ts",
content: ""
};
const fooTsconfig: File = {
path: "/Foo/tsconfig.json",
content: `{ "files": ["./a.ts"] }`
};

const barATs: File = {
path: "/Bar/a.ts",
content: [
"const a = 1;",
"const b = 2;",
"console.log(a, b);",
].join("\n")
};
const barTsconfig: File = {
path: "/Bar/tsconfig.json",
content: `{ "files": ["./a.ts"] }`
};
const host = createServerHost([fooATs, fooTsconfig, barATs, barTsconfig]);
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
openFilesForSession([barATs], session);

session.executeCommandSeq<ts.server.protocol.GetEditsForRefactorRequest>({
command: ts.server.protocol.CommandTypes.GetEditsForRefactor,
arguments: {
file: barATs.path,
startLine: 1,
startOffset: 1,
endLine: 1,
endOffset: 13,
refactor: "Move to file",
action: "Move to file",
interactiveRefactorArguments: { targetFile: "/Foo/a.ts" },
}
});
baselineTsserverLogs("refactors", "handles moving statements to a TS file that is not included in the TS project", session);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
currentDirectory:: / useCaseSensitiveFileNames: false
Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist
Before request
//// [/Foo/a.ts]


//// [/Foo/tsconfig.json]
{ "files": ["./a.ts"] }

//// [/Bar/a.ts]
const a = 1;
const b = 2;
console.log(a, b);

//// [/Bar/tsconfig.json]
{ "files": ["./a.ts"] }


Info seq [hh:mm:ss:mss] request:
{
"command": "open",
"arguments": {
"file": "/Bar/a.ts"
},
"seq": 1,
"type": "request"
}
Info seq [hh:mm:ss:mss] Search path: /Bar
Info seq [hh:mm:ss:mss] For info: /Bar/a.ts :: Config file name: /Bar/tsconfig.json
Info seq [hh:mm:ss:mss] Creating configuration project /Bar/tsconfig.json
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /Bar/tsconfig.json 2000 undefined Project: /Bar/tsconfig.json WatchType: Config file
Info seq [hh:mm:ss:mss] Config: /Bar/tsconfig.json : {
"rootNames": [
"/Bar/a.ts"
],
"options": {
"configFilePath": "/Bar/tsconfig.json"
}
}
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /Bar/tsconfig.json
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /Bar/tsconfig.json WatchType: Missing file
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /Bar/tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
Info seq [hh:mm:ss:mss] Project '/Bar/tsconfig.json' (Configured)
Info seq [hh:mm:ss:mss] Files (1)
/Bar/a.ts SVC-1-0 "const a = 1;\nconst b = 2;\nconsole.log(a, b);"


a.ts
Part of 'files' list in tsconfig.json

Info seq [hh:mm:ss:mss] -----------------------------------------------
Info seq [hh:mm:ss:mss] Project '/Bar/tsconfig.json' (Configured)
Info seq [hh:mm:ss:mss] Files (1)

Info seq [hh:mm:ss:mss] -----------------------------------------------
Info seq [hh:mm:ss:mss] Open files:
Info seq [hh:mm:ss:mss] FileName: /Bar/a.ts ProjectRootPath: undefined
Info seq [hh:mm:ss:mss] Projects: /Bar/tsconfig.json
Info seq [hh:mm:ss:mss] response:
{
"responseRequired": false
}
After request

PolledWatches::
/a/lib/lib.d.ts: *new*
{"pollingInterval":500}

FsWatches::
/bar/tsconfig.json: *new*
{}

Before request

Info seq [hh:mm:ss:mss] request:
{
"command": "getEditsForRefactor",
"arguments": {
"file": "/Bar/a.ts",
"startLine": 1,
"startOffset": 1,
"endLine": 1,
"endOffset": 13,
"refactor": "Move to file",
"action": "Move to file",
"interactiveRefactorArguments": {
"targetFile": "/Foo/a.ts"
}
},
"seq": 2,
"type": "request"
}
Info seq [hh:mm:ss:mss] response:
{
"response": {
"edits": [],
"notApplicableReason": "Cannot move statements to the selected file"
},
"responseRequired": true
}
After request