diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 857d2c95dc5..5dd6865f568 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -167,7 +167,7 @@ namespace ts.server { return undefined; } if (isInferredProjectName(projectName)) { - return forEach(this.inferredProjects, p => p.getProjectName() === projectName && p); + return findProjectByName(projectName, this.inferredProjects); } return this.findExternalProjectByProjectName(projectName) || this.findConfiguredProjectByProjectName(toNormalizedPath(projectName)); } @@ -209,17 +209,19 @@ namespace ts.server { info.detachAllProjects(); + if (!this.eventHandler) { + return; + } + for (const openFile of this.openFileRoots) { - if (this.eventHandler) { - this.eventHandler("context", openFile.getDefaultProject(), openFile.fileName); - } + this.eventHandler("context", openFile.getDefaultProject(), openFile.fileName); } for (const openFile of this.openFilesReferenced) { - if (this.eventHandler) { - this.eventHandler("context", openFile.getDefaultProject(), openFile.fileName); - } + this.eventHandler("context", openFile.getDefaultProject(), openFile.fileName); } + + // TODO: project system view is inconsistent } this.printProjects(); diff --git a/src/server/lsHost.ts b/src/server/lsHost.ts index b65c71d5e28..36bdc7a9afe 100644 --- a/src/server/lsHost.ts +++ b/src/server/lsHost.ts @@ -89,8 +89,8 @@ namespace ts.server { } getDefaultLibFileName() { - const nodeModuleBinDir = ts.getDirectoryPath(ts.normalizePath(this.host.getExecutingFilePath())); - return ts.combinePaths(nodeModuleBinDir, ts.getDefaultLibFileName(this.compilationSettings)); + const nodeModuleBinDir = getDirectoryPath(normalizePath(this.host.getExecutingFilePath())); + return combinePaths(nodeModuleBinDir, getDefaultLibFileName(this.compilationSettings)); } getScriptSnapshot(filename: string): ts.IScriptSnapshot { diff --git a/src/server/project.ts b/src/server/project.ts index 00eeda9d8f0..40bd98c980b 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -19,8 +19,8 @@ namespace ts.server { } export abstract class Project { - private readonly rootFiles: ScriptInfo[] = []; - private readonly rootFilesMap: FileMap = createFileMap(); + private rootFiles: ScriptInfo[] = []; + private rootFilesMap: FileMap = createFileMap(); private lsHost: ServerLanguageServiceHost; private program: ts.Program; @@ -96,11 +96,24 @@ namespace ts.server { abstract getProjectName(): string; close() { - for (const fileName of this.getFileNames()) { - const info = this.projectService.getScriptInfoForNormalizedPath(fileName); - info.detachFromProject(this); + if (this.program) { + // if we have a program - release all files that are enlisted in program + for (const f of this.program.getSourceFiles()) { + const info = this.projectService.getScriptInfo(f.fileName); + info.detachFromProject(this); + } } - // signal language service to release files acquired from document registry + else { + // release all root files + for (const root of this.rootFiles) { + root.detachFromProject(this); + } + } + this.rootFiles = undefined; + this.rootFilesMap = undefined; + this.program = undefined; + + // signal language service to release source files acquired from document registry this.languageService.dispose(); } @@ -137,7 +150,7 @@ namespace ts.server { } containsScriptInfo(info: ScriptInfo): boolean { - return this.program && this.program.getSourceFileByPath(info.path) !== undefined; + return this.isRoot(info) || (this.program && this.program.getSourceFileByPath(info.path) !== undefined); } containsFile(filename: NormalizedPath, requireOpen?: boolean) { diff --git a/tests/cases/unittests/tsserverProjectSystem.ts b/tests/cases/unittests/tsserverProjectSystem.ts index 9e003bc8049..bcdcdc09106 100644 --- a/tests/cases/unittests/tsserverProjectSystem.ts +++ b/tests/cases/unittests/tsserverProjectSystem.ts @@ -698,5 +698,28 @@ namespace ts { checkNumberOfInferredProjects(projectService, 1); checkProjectActualFiles(projectService.inferredProjects[0], [file2.path, file3.path, libFile.path]); }); + + it ("should close configured project after closing last open file", () => { + const file1 = { + path: "/a/b/main.ts", + content: "let x =1;" + }; + const configFile: FileOrFolder = { + path: "/a/b/tsconfig.json", + content: `{ + "compilerOptions": { + "target": "es6" + }, + "files": [ "main.ts" ] + }` + }; + const host = createServerHost({ fileOrFolderList: [file1, configFile, libFile], libFile }); + const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ true); + projectService.openClientFile(file1.path); + checkNumberOfConfiguredProjects(projectService, 1); + + projectService.closeClientFile(file1.path); + checkNumberOfConfiguredProjects(projectService, 0); + }) }); } \ No newline at end of file