Skip to content

Commit ae04ec4

Browse files
committed
fix(41736): tsserver should not crash if external file does not exist
If a file does not exist, `projectService.getOrCreateScriptInfoNotOpenedByClient()` will return `undefined`, but tsserver does not handle this case. Fix #41736
1 parent 1bd8e38 commit ae04ec4

2 files changed

Lines changed: 41 additions & 2 deletions

File tree

‎src/server/project.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,8 +1188,8 @@ namespace ts.server {
11881188
// by the host for files in the program when the program is retrieved above but
11891189
// the program doesn't contain external files so this must be done explicitly.
11901190
inserted => {
1191-
const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(inserted, this.currentDirectory, this.directoryStructureHost)!;
1192-
scriptInfo.attachToProject(this);
1191+
const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(inserted, this.currentDirectory, this.directoryStructureHost);
1192+
scriptInfo?.attachToProject(this);
11931193
},
11941194
removed => this.detachScriptInfoFromProject(removed)
11951195
);

‎src/testRunner/unittests/tsserver/externalProjects.ts‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,5 +898,44 @@ namespace ts.projectSystem {
898898
const jsConfigProject = service.configuredProjects.get(jsConfig.path.toLowerCase())!;
899899
checkProjectActualFiles(jsConfigProject, [jsConfig.path, jsFilePath, libFile.path]);
900900
});
901+
902+
it("does not crash if external file does not exist", () => {
903+
const f1 = {
904+
path: "/a/file1.ts",
905+
content: "let x = [1, 2];",
906+
};
907+
const p1 = {
908+
projectFileName: "/a/proj1.csproj",
909+
rootFiles: [toExternalFile(f1.path)],
910+
options: {},
911+
};
912+
913+
const host = createServerHost([f1]);
914+
host.require = (_initialPath, moduleName) => {
915+
assert.equal(moduleName, "myplugin");
916+
return {
917+
module: () => ({
918+
create(info: server.PluginCreateInfo) {
919+
return Harness.LanguageService.makeDefaultProxy(info);
920+
},
921+
getExternalFiles() {
922+
return ["/does/not/exist"];
923+
},
924+
}),
925+
error: undefined,
926+
};
927+
};
928+
const session = createSession(host, {
929+
globalPlugins: ["myplugin"],
930+
});
931+
const projectService = session.getProjectService();
932+
// When the external project is opened, the graph will be updated,
933+
// and in the process getExternalFiles() above will be called.
934+
// Since the external file does not exist, there will not be a script
935+
// info for it. If tsserver does not handle this case, the following
936+
// method call will crash.
937+
projectService.openExternalProject(p1);
938+
checkNumberOfProjects(projectService, { externalProjects: 1 });
939+
});
901940
});
902941
}

0 commit comments

Comments
 (0)