diff --git a/src/server/project.ts b/src/server/project.ts index db704b7dfa8..b067d454f2d 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1188,8 +1188,8 @@ namespace ts.server { // by the host for files in the program when the program is retrieved above but // the program doesn't contain external files so this must be done explicitly. inserted => { - const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(inserted, this.currentDirectory, this.directoryStructureHost)!; - scriptInfo.attachToProject(this); + const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(inserted, this.currentDirectory, this.directoryStructureHost); + scriptInfo?.attachToProject(this); }, removed => this.detachScriptInfoFromProject(removed) ); diff --git a/src/testRunner/unittests/tsserver/externalProjects.ts b/src/testRunner/unittests/tsserver/externalProjects.ts index 0e842d72971..4e8f4128bdc 100644 --- a/src/testRunner/unittests/tsserver/externalProjects.ts +++ b/src/testRunner/unittests/tsserver/externalProjects.ts @@ -898,5 +898,44 @@ namespace ts.projectSystem { const jsConfigProject = service.configuredProjects.get(jsConfig.path.toLowerCase())!; checkProjectActualFiles(jsConfigProject, [jsConfig.path, jsFilePath, libFile.path]); }); + + it("does not crash if external file does not exist", () => { + const f1 = { + path: "/a/file1.ts", + content: "let x = [1, 2];", + }; + const p1 = { + projectFileName: "/a/proj1.csproj", + rootFiles: [toExternalFile(f1.path)], + options: {}, + }; + + const host = createServerHost([f1]); + host.require = (_initialPath, moduleName) => { + assert.equal(moduleName, "myplugin"); + return { + module: () => ({ + create(info: server.PluginCreateInfo) { + return Harness.LanguageService.makeDefaultProxy(info); + }, + getExternalFiles() { + return ["/does/not/exist"]; + }, + }), + error: undefined, + }; + }; + const session = createSession(host, { + globalPlugins: ["myplugin"], + }); + const projectService = session.getProjectService(); + // When the external project is opened, the graph will be updated, + // and in the process getExternalFiles() above will be called. + // Since the external file does not exist, there will not be a script + // info for it. If tsserver does not handle this case, the following + // method call will crash. + projectService.openExternalProject(p1); + checkNumberOfProjects(projectService, { externalProjects: 1 }); + }); }); }