From b2a7d420322e2f16bcae6e74bdf6023b3ea3d53a Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 16 Jan 2020 15:38:55 -0800 Subject: [PATCH] Handle untitled files from vscode which are of format: untitled:^Untitled-1 (#36240) * Test for #36200 * Handle dynamic files by vscode Fixes #36200 --- src/server/editorServices.ts | 2 +- src/server/scriptInfo.ts | 3 +- .../unittests/tsserver/externalProjects.ts | 1 + src/testRunner/unittests/tsserver/projects.ts | 3 ++ .../unittests/tsserver/untitledFiles.ts | 44 +++++++++++++++++-- 5 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 2e3e0ae67e5..c5bc372e179 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1304,7 +1304,7 @@ namespace ts.server { // Closing file should trigger re-reading the file content from disk. This is // because the user may chose to discard the buffer content before saving // to the disk, and the server's version of the file can be out of sync. - const fileExists = this.host.fileExists(info.fileName); + const fileExists = info.isDynamic ? false : this.host.fileExists(info.fileName); info.close(fileExists); this.stopWatchingConfigFilesForClosedScriptInfo(info); diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index 02d3bff1a0f..f630b9329aa 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -272,7 +272,8 @@ namespace ts.server { /*@internal*/ export function isDynamicFileName(fileName: NormalizedPath) { - return fileName[0] === "^"; + return fileName[0] === "^" || + (stringContains(fileName, ":^") && !stringContains(fileName, directorySeparator)); } /*@internal*/ diff --git a/src/testRunner/unittests/tsserver/externalProjects.ts b/src/testRunner/unittests/tsserver/externalProjects.ts index 172d264242b..54a488c0c94 100644 --- a/src/testRunner/unittests/tsserver/externalProjects.ts +++ b/src/testRunner/unittests/tsserver/externalProjects.ts @@ -221,6 +221,7 @@ namespace ts.projectSystem { checkNumberOfExternalProjects(projectService, 1); checkNumberOfInferredProjects(projectService, 0); + verifyDynamic(projectService, "/^scriptdocument1 file1.ts"); externalFiles[0].content = "let x =1;"; projectService.applyChangesInOpenFiles(arrayIterator(externalFiles)); diff --git a/src/testRunner/unittests/tsserver/projects.ts b/src/testRunner/unittests/tsserver/projects.ts index 369b0d8905e..7c4c5ef522c 100644 --- a/src/testRunner/unittests/tsserver/projects.ts +++ b/src/testRunner/unittests/tsserver/projects.ts @@ -1094,6 +1094,7 @@ namespace ts.projectSystem { const project = projectService.inferredProjects[0]; checkProjectRootFiles(project, [file.path]); checkProjectActualFiles(project, [file.path, libFile.path]); + verifyDynamic(projectService, `/${file.path}`); assert.strictEqual(projectService.ensureDefaultProjectForFile(server.toNormalizedPath(file.path)), project); const indexOfX = file.content.indexOf("x"); @@ -1124,6 +1125,7 @@ var x = 10;` const host = createServerHost([libFile]); const projectService = createProjectService(host); projectService.openClientFile(file.path, file.content); + verifyDynamic(projectService, projectService.toPath(file.path)); projectService.checkNumberOfProjects({ inferredProjects: 1 }); const project = projectService.inferredProjects[0]; @@ -1152,6 +1154,7 @@ var x = 10;` const projectService = session.getProjectService(); checkNumberOfProjects(projectService, { inferredProjects: 1 }); checkProjectActualFiles(projectService.inferredProjects[0], [file.path, libFile.path]); + verifyDynamic(projectService, `${tscWatch.projectRoot}/${file.path}`); session.executeCommandSeq({ command: protocol.CommandTypes.GetOutliningSpans, diff --git a/src/testRunner/unittests/tsserver/untitledFiles.ts b/src/testRunner/unittests/tsserver/untitledFiles.ts index 31612d49a14..6ba8da3cf39 100644 --- a/src/testRunner/unittests/tsserver/untitledFiles.ts +++ b/src/testRunner/unittests/tsserver/untitledFiles.ts @@ -1,20 +1,25 @@ namespace ts.projectSystem { + export function verifyDynamic(service: server.ProjectService, path: string) { + const info = Debug.assertDefined(service.filenameToScriptInfo.get(path), `Expected ${path} in :: ${JSON.stringify(arrayFrom(service.filenameToScriptInfo.entries(), ([key, f]) => ({ key, fileName: f.fileName, path: f.path })))}`); + assert.isTrue(info.isDynamic); + } + describe("unittests:: tsserver:: Untitled files", () => { + const untitledFile = "untitled:^Untitled-1"; it("Can convert positions to locations", () => { const aTs: File = { path: "/proj/a.ts", content: "" }; const tsconfig: File = { path: "/proj/tsconfig.json", content: "{}" }; - const session = createSession(createServerHost([aTs, tsconfig])); + const session = createSession(createServerHost([aTs, tsconfig]), { useInferredProjectPerProjectRoot: true }); openFilesForSession([aTs], session); - const untitledFile = "untitled:^Untitled-1"; executeSessionRequestNoResponse(session, protocol.CommandTypes.Open, { file: untitledFile, fileContent: `/// \nlet foo = 1;\nfooo/**/`, scriptKindName: "TS", projectRootPath: "/proj", }); - + verifyDynamic(session.getProjectService(), `/proj/untitled:^untitled-1`); const response = executeSessionRequest(session, protocol.CommandTypes.GetCodeFixes, { file: untitledFile, startLine: 3, @@ -41,5 +46,38 @@ namespace ts.projectSystem { }, ]); }); + + it("opening untitled files", () => { + const config: File = { + path: `${tscWatch.projectRoot}/tsconfig.json`, + content: "{}" + }; + const host = createServerHost([config, libFile], { useCaseSensitiveFileNames: true, currentDirectory: tscWatch.projectRoot }); + const service = createProjectService(host); + service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, tscWatch.projectRoot); + checkNumberOfProjects(service, { inferredProjects: 1 }); + checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]); + verifyDynamic(service, `${tscWatch.projectRoot}/${untitledFile}`); + + const untitled: File = { + path: `${tscWatch.projectRoot}/Untitled-1.ts`, + content: "const x = 10;" + }; + host.writeFile(untitled.path, untitled.content); + host.checkTimeoutQueueLength(0); + service.openClientFile(untitled.path, untitled.content, /*scriptKind*/ undefined, tscWatch.projectRoot); + checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 }); + checkProjectActualFiles(service.configuredProjects.get(config.path)!, [untitled.path, libFile.path, config.path]); + checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]); + + service.closeClientFile(untitledFile); + checkProjectActualFiles(service.configuredProjects.get(config.path)!, [untitled.path, libFile.path, config.path]); + checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]); + + service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, tscWatch.projectRoot); + verifyDynamic(service, `${tscWatch.projectRoot}/${untitledFile}`); + checkProjectActualFiles(service.configuredProjects.get(config.path)!, [untitled.path, libFile.path, config.path]); + checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]); + }); }); }