From fc90b8f98b6dbf3a4fbae22a4c310382700fc099 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 28 Aug 2018 14:08:59 -0700 Subject: [PATCH] lazyConfiguredProjectsFromExternalProject as userpreference instead of command line option --- src/server/editorServices.ts | 17 ++++-- src/server/project.ts | 5 ++ src/server/protocol.ts | 1 + src/server/session.ts | 2 - src/services/types.ts | 1 + .../unittests/tsserverProjectSystem.ts | 61 +++++++++++++++++-- src/tsserver/server.ts | 2 - 7 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index c506c656de7..d941ce2f3f4 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -323,7 +323,6 @@ namespace ts.server { cancellationToken: HostCancellationToken; useSingleInferredProject: boolean; useInferredProjectPerProjectRoot: boolean; - lazyConfiguredProjectsFromExternalProject?: boolean; typingsInstaller: ITypingsInstaller; eventHandler?: ProjectServiceEventHandler; suppressDiagnosticEvents?: boolean; @@ -441,7 +440,6 @@ namespace ts.server { public readonly cancellationToken: HostCancellationToken; public readonly useSingleInferredProject: boolean; public readonly useInferredProjectPerProjectRoot: boolean; - private readonly lazyConfiguredProjectsFromExternalProject?: boolean; public readonly typingsInstaller: ITypingsInstaller; private readonly globalCacheLocationDirectoryPath: Path | undefined; public readonly throttleWaitMilliseconds?: number; @@ -467,7 +465,6 @@ namespace ts.server { this.cancellationToken = opts.cancellationToken; this.useSingleInferredProject = opts.useSingleInferredProject; this.useInferredProjectPerProjectRoot = opts.useInferredProjectPerProjectRoot; - this.lazyConfiguredProjectsFromExternalProject = opts.lazyConfiguredProjectsFromExternalProject; this.typingsInstaller = opts.typingsInstaller || nullTypingsInstaller; this.throttleWaitMilliseconds = opts.throttleWaitMilliseconds; this.eventHandler = opts.eventHandler; @@ -1989,7 +1986,19 @@ namespace ts.server { this.logger.info("Format host information updated"); } if (args.preferences) { + const { lazyConfiguredProjectsFromExternalProject } = this.hostConfiguration.preferences; this.hostConfiguration.preferences = { ...this.hostConfiguration.preferences, ...args.preferences }; + if (lazyConfiguredProjectsFromExternalProject && !this.hostConfiguration.preferences.lazyConfiguredProjectsFromExternalProject) { + // Load configured projects for external projects that are pending reload + this.configuredProjects.forEach(project => { + if (project.hasExternalProjectRef() && + project.pendingReload === ConfigFileProgramReloadLevel.Full && + !this.pendingProjectUpdates.has(project.getProjectName())) { + this.loadConfiguredProject(project); + project.updateGraph(); + } + }); + } } if (args.extraFileExtensions) { this.hostConfiguration.extraFileExtensions = args.extraFileExtensions; @@ -2642,7 +2651,7 @@ namespace ts.server { let project = this.findConfiguredProjectByProjectName(tsconfigFile); if (!project) { // errors are stored in the project, do not need to update the graph - project = this.lazyConfiguredProjectsFromExternalProject ? + project = this.getHostPreferences().lazyConfiguredProjectsFromExternalProject ? this.createConfiguredProjectWithDelayLoad(tsconfigFile) : this.createLoadAndUpdateConfiguredProject(tsconfigFile); } diff --git a/src/server/project.ts b/src/server/project.ts index ff2c504a54a..9589108c93d 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1520,6 +1520,11 @@ namespace ts.server { ) || false; } + /*@internal*/ + hasExternalProjectRef() { + return !!this.externalProjectRefCount; + } + getEffectiveTypeRoots() { return getEffectiveTypeRoots(this.getCompilationSettings(), this.directoryStructureHost) || []; } diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 39a0045d97e..441c1316c99 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -2823,6 +2823,7 @@ namespace ts.server.protocol { readonly includeCompletionsWithInsertText?: boolean; readonly importModuleSpecifierPreference?: "relative" | "non-relative"; readonly allowTextChangesInNewFiles?: boolean; + readonly lazyConfiguredProjectsFromExternalProject?: boolean; } export interface CompilerOptions { diff --git a/src/server/session.ts b/src/server/session.ts index 69328b4c73b..8d2fbe9e190 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -465,7 +465,6 @@ namespace ts.server { cancellationToken: ServerCancellationToken; useSingleInferredProject: boolean; useInferredProjectPerProjectRoot: boolean; - lazyConfiguredProjectsFromExternalProject?: boolean; typingsInstaller: ITypingsInstaller; byteLength: (buf: string, encoding?: string) => number; hrtime: (start?: number[]) => number[]; @@ -537,7 +536,6 @@ namespace ts.server { cancellationToken: this.cancellationToken, useSingleInferredProject: opts.useSingleInferredProject, useInferredProjectPerProjectRoot: opts.useInferredProjectPerProjectRoot, - lazyConfiguredProjectsFromExternalProject: opts.lazyConfiguredProjectsFromExternalProject, typingsInstaller: this.typingsInstaller, throttleWaitMilliseconds, eventHandler: this.eventHandler, diff --git a/src/services/types.ts b/src/services/types.ts index 51c98724c09..73a70c786b7 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -240,6 +240,7 @@ namespace ts { readonly includeCompletionsWithInsertText?: boolean; readonly importModuleSpecifierPreference?: "relative" | "non-relative"; readonly allowTextChangesInNewFiles?: boolean; + readonly lazyConfiguredProjectsFromExternalProject?: boolean; } /* @internal */ export const emptyOptions = {}; diff --git a/src/testRunner/unittests/tsserverProjectSystem.ts b/src/testRunner/unittests/tsserverProjectSystem.ts index 7ef838fd6ff..cb608d26dc6 100644 --- a/src/testRunner/unittests/tsserverProjectSystem.ts +++ b/src/testRunner/unittests/tsserverProjectSystem.ts @@ -656,7 +656,8 @@ namespace ts.projectSystem { }; const host = createServerHost([f1, config], { useCaseSensitiveFileNames: false }); - const service = createProjectService(host, /*parameters*/ undefined, { lazyConfiguredProjectsFromExternalProject }); + const service = createProjectService(host); + service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } }); const upperCaseConfigFilePath = combinePaths(getDirectoryPath(config.path).toUpperCase(), getBaseFileName(config.path)); service.openExternalProject({ projectFileName: "/a/b/project.csproj", @@ -670,7 +671,7 @@ namespace ts.projectSystem { checkProjectActualFiles(project, emptyArray); } else { - assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project pending to be reloaded + assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded checkProjectActualFiles(project, [upperCaseConfigFilePath]); } @@ -2978,7 +2979,8 @@ namespace ts.projectSystem { }; const projectFileName = "/user/someuser/project/WebApplication6.csproj"; const host = createServerHost([libFile, site, configFile]); - const projectService = createProjectService(host, /*parameters*/ undefined, { lazyConfiguredProjectsFromExternalProject }); + const projectService = createProjectService(host); + projectService.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } }); const externalProject: protocol.ExternalProject = { projectFileName, @@ -3341,8 +3343,12 @@ namespace ts.projectSystem { }; const host = createServerHost([file1, file2, tsconfig]); - const session = createSession(host, { lazyConfiguredProjectsFromExternalProject }); + const session = createSession(host); const projectService = session.getProjectService(); + session.executeCommandSeq({ + command: protocol.CommandTypes.Configure, + arguments: { preferences: { lazyConfiguredProjectsFromExternalProject } } + }); // Configure the deferred extension. const extraFileExtensions = [{ extension: ".deferred", scriptKind: ScriptKind.Deferred, isMixedContent: true }]; @@ -3995,7 +4001,8 @@ namespace ts.projectSystem { content: "" }; const host = createServerHost([f1, f2]); - const projectService = createProjectService(host, /*parameters*/ undefined, { lazyConfiguredProjectsFromExternalProject }); + const projectService = createProjectService(host); + projectService.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } }); // open external project const projectName = "/a/b/proj1"; @@ -4064,7 +4071,8 @@ namespace ts.projectSystem { content: "{}" }; const host = createServerHost([f1, cLib, cTsconfig, dLib, dTsconfig]); - const projectService = createProjectService(host, /*parameters*/ undefined, { lazyConfiguredProjectsFromExternalProject }); + const projectService = createProjectService(host); + projectService.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } }); // open external project const projectName = "/a/b/proj1"; @@ -4233,6 +4241,47 @@ namespace ts.projectSystem { assert.isTrue(project.hasOpenRef()); // f assert.isFalse(project.isClosed()); }); + + it("handles loads existing configured projects of external projects when lazyConfiguredProjectsFromExternalProject is disabled", () => { + const f1 = { + path: "/a/b/app.ts", + content: "let x = 1" + }; + const config = { + path: "/a/b/tsconfig.json", + content: JSON.stringify({}) + }; + const projectFileName = "/a/b/project.csproj"; + const host = createServerHost([f1, config]); + const service = createProjectService(host); + service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject: true } }); + service.openExternalProject({ + projectFileName, + rootFiles: toExternalFiles([f1.path, config.path]), + options: {} + }); + service.checkNumberOfProjects({ configuredProjects: 1 }); + const project = service.configuredProjects.get(config.path)!; + assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.Full); // External project referenced configured project pending to be reloaded + checkProjectActualFiles(project, emptyArray); + + service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject: false } }); + assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded + checkProjectActualFiles(project, [config.path, f1.path]); + + service.closeExternalProject(projectFileName); + service.checkNumberOfProjects({}); + + service.openExternalProject({ + projectFileName, + rootFiles: toExternalFiles([f1.path, config.path]), + options: {} + }); + service.checkNumberOfProjects({ configuredProjects: 1 }); + const project2 = service.configuredProjects.get(config.path)!; + assert.equal(project2.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded + checkProjectActualFiles(project2, [config.path, f1.path]); + }); }); describe("tsserverProjectSystem prefer typings to js", () => { diff --git a/src/tsserver/server.ts b/src/tsserver/server.ts index 6b8a146d8f3..3e5986e9408 100644 --- a/src/tsserver/server.ts +++ b/src/tsserver/server.ts @@ -499,7 +499,6 @@ namespace ts.server { cancellationToken, useSingleInferredProject, useInferredProjectPerProjectRoot, - lazyConfiguredProjectsFromExternalProject, typingsInstaller: typingsInstaller || nullTypingsInstaller, byteLength: Buffer.byteLength, hrtime: process.hrtime, @@ -938,7 +937,6 @@ namespace ts.server { const useSingleInferredProject = hasArgument("--useSingleInferredProject"); const useInferredProjectPerProjectRoot = hasArgument("--useInferredProjectPerProjectRoot"); - const lazyConfiguredProjectsFromExternalProject = hasArgument("--lazyConfiguredProjectsFromExternalProject"); const disableAutomaticTypingAcquisition = hasArgument("--disableAutomaticTypingAcquisition"); const suppressDiagnosticEvents = hasArgument("--suppressDiagnosticEvents"); const syntaxOnly = hasArgument("--syntaxOnly");