diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index a766a9c4230..1844b0743ca 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -1620,7 +1620,7 @@ namespace ts.projectSystem { const configureHostRequest = makeSessionRequest(CommandNames.Configure, { extraFileExtensions }); session.executeCommand(configureHostRequest).response; - // HTML file still not included in the project as it is closed + // HTML file still not included in the project as it is closed checkNumberOfProjects(projectService, { configuredProjects: 1 }); checkProjectActualFiles(projectService.configuredProjects[0], [file1.path]); @@ -3053,7 +3053,7 @@ namespace ts.projectSystem { }); describe("maxNodeModuleJsDepth for inferred projects", () => { - it("should be set by default", () => { + it("should be set to 2 if the project has js root files", () => { const file1: FileOrFolder = { path: "/a/b/file1.js", content: `var t = require("test"); t.` @@ -3077,6 +3077,33 @@ namespace ts.projectSystem { options = project.getCompilerOptions(); assert.isTrue(options.maxNodeModuleJsDepth === 2); }); + + it("should return to normal state when all js root files are removed from project", () => { + const file1 = { + path: "/a/file1.ts", + content: "let x =1;" + }; + const file2 = { + path: "/a/file2.js", + content: "let x =1;" + }; + + const host = createServerHost([file1, file2, libFile]); + const projectService = createProjectService(host, { useSingleInferredProject: true }); + + projectService.openClientFile(file1.path); + checkNumberOfInferredProjects(projectService, 1); + let project = projectService.inferredProjects[0]; + assert.isUndefined(project.getCompilerOptions().maxNodeModuleJsDepth); + + projectService.openClientFile(file2.path); + project = projectService.inferredProjects[0]; + assert.isTrue(project.getCompilerOptions().maxNodeModuleJsDepth === 2); + + projectService.closeClientFile(file2.path); + project = projectService.inferredProjects[0]; + assert.isUndefined(project.getCompilerOptions().maxNodeModuleJsDepth); + }); }); } \ No newline at end of file diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 2b87fdf1cc7..00df53e1e35 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1072,10 +1072,6 @@ namespace ts.server { ? this.inferredProjects[0] : new InferredProject(this, this.documentRegistry, this.compilerOptionsForInferredProjects); - if (root.scriptKind === ScriptKind.JS || root.scriptKind === ScriptKind.JSX) { - project.setAsJsInferredProject(); - } - project.addRoot(root); this.directoryWatchers.startWatchingContainingDirectoriesForFile( diff --git a/src/server/project.ts b/src/server/project.ts index 5178820b3c4..89312610a54 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -395,7 +395,9 @@ namespace ts.server { } removeFile(info: ScriptInfo, detachFromProject = true) { - this.removeRootFileIfNecessary(info); + if (this.isRoot(info)) { + this.removeRoot(info); + } this.lsHost.notifyFileRemoved(info); this.cachedUnresolvedImportsPerFile.remove(info.path); @@ -693,11 +695,9 @@ namespace ts.server { } // remove a root file from project - private removeRootFileIfNecessary(info: ScriptInfo): void { - if (this.isRoot(info)) { - remove(this.rootFiles, info); - this.rootFilesMap.remove(info.path); - } + protected removeRoot(info: ScriptInfo): void { + remove(this.rootFiles, info); + this.rootFilesMap.remove(info.path); } } @@ -714,13 +714,16 @@ namespace ts.server { private _isJsInferredProject = false; - setAsJsInferredProject() { - this._isJsInferredProject = true; - this.setCompilerOptions(); + toggleJsInferredProject(isJsInferredProject: boolean) { + if (isJsInferredProject !== this._isJsInferredProject) { + this._isJsInferredProject = isJsInferredProject; + this.setCompilerOptions(); + } } - setCompilerOptions(newOptions?: CompilerOptions) { - newOptions = newOptions ? newOptions : this.getCompilerOptions(); + setCompilerOptions(options?: CompilerOptions) { + // Avoid manipulating the given options directly + const newOptions = options ? clone(options) : this.getCompilerOptions(); if (!newOptions) { return; } @@ -728,6 +731,9 @@ namespace ts.server { if (this._isJsInferredProject && typeof newOptions.maxNodeModuleJsDepth !== "number") { newOptions.maxNodeModuleJsDepth = 2; } + else if (!this._isJsInferredProject) { + newOptions.maxNodeModuleJsDepth = undefined; + } newOptions.allowJs = true; super.setCompilerOptions(newOptions); } @@ -746,6 +752,22 @@ namespace ts.server { /*compileOnSaveEnabled*/ false); } + addRoot(info: ScriptInfo) { + if (!this._isJsInferredProject && info.isJavaScript()) { + this.toggleJsInferredProject(/*isJsInferredProject*/ true); + } + super.addRoot(info); + } + + removeRoot(info: ScriptInfo) { + if (this._isJsInferredProject && info.isJavaScript()) { + if (filter(this.getRootScriptInfos(), info => info.isJavaScript()).length === 0) { + this.toggleJsInferredProject(/*isJsInferredProject*/ false); + } + } + super.removeRoot(info); + } + getProjectRootPath() { // Single inferred project does not have a project root. if (this.projectService.useSingleInferredProject) { diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index 0acd45d0287..a93600de1a8 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -355,5 +355,9 @@ namespace ts.server { positionToLineOffset(position: number): ILineInfo { return this.textStorage.positionToLineOffset(position); } + + public isJavaScript() { + return this.scriptKind === ScriptKind.JS || this.scriptKind === ScriptKind.JSX; + } } } \ No newline at end of file