From 8fb8bd07d4fa211235d14968e70b784459c3509f Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 16 Jan 2020 12:50:56 -0800 Subject: [PATCH 1/2] Test for #36200 --- .../unittests/tsserver/untitledFiles.ts | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/testRunner/unittests/tsserver/untitledFiles.ts b/src/testRunner/unittests/tsserver/untitledFiles.ts index 7f5c36ac6e2f5..a73134b942c08 100644 --- a/src/testRunner/unittests/tsserver/untitledFiles.ts +++ b/src/testRunner/unittests/tsserver/untitledFiles.ts @@ -1,5 +1,6 @@ namespace ts.projectSystem { 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: "{}" }; @@ -7,7 +8,6 @@ namespace ts.projectSystem { openFilesForSession([aTs], session); - const untitledFile = "untitled:^Untitled-1"; executeSessionRequestNoResponse(session, protocol.CommandTypes.Open, { file: untitledFile, fileContent: `/// \nlet foo = 1;\nfooo/**/`, @@ -41,5 +41,35 @@ 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, { logger: createLoggerWritingToConsole() }); + service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, tscWatch.projectRoot); + checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 }); + checkProjectActualFiles(service.configuredProjects.get("tsconfig.json")!, ["tsconfig.json"]); + checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]); + + 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); + }); }); } From 776b179881906ff409bd4ae8a793ca77f78eae04 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 16 Jan 2020 13:21:34 -0800 Subject: [PATCH 2/2] 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 | 18 +++++++++++++----- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 2e3e0ae67e5cd..c5bc372e179cd 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 02d3bff1a0f8c..f630b9329aaa7 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 172d264242b77..54a488c0c94c2 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 369b0d8905ed8..7c4c5ef522cc0 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 a73134b942c08..1aac75230075e 100644 --- a/src/testRunner/unittests/tsserver/untitledFiles.ts +++ b/src/testRunner/unittests/tsserver/untitledFiles.ts @@ -1,10 +1,15 @@ 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); @@ -14,7 +19,7 @@ namespace ts.projectSystem { scriptKindName: "TS", projectRootPath: "/proj", }); - + verifyDynamic(session.getProjectService(), `/proj/untitled:^untitled-1`); const response = executeSessionRequest(session, protocol.CommandTypes.GetCodeFixes, { file: untitledFile, startLine: 3, @@ -48,11 +53,11 @@ namespace ts.projectSystem { content: "{}" }; const host = createServerHost([config, libFile], { useCaseSensitiveFileNames: true, currentDirectory: tscWatch.projectRoot }); - const service = createProjectService(host, { logger: createLoggerWritingToConsole() }); + const service = createProjectService(host); service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, tscWatch.projectRoot); - checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 }); - checkProjectActualFiles(service.configuredProjects.get("tsconfig.json")!, ["tsconfig.json"]); + 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`, @@ -70,6 +75,9 @@ namespace ts.projectSystem { 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]); }); }); }