From 6d543eac0000bf28fd959d476d34ea5061bb09a7 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 20 Jan 2021 16:06:18 -0800 Subject: [PATCH] Schedule update graph only if typings change Fixes #39326 --- src/server/editorServices.ts | 1 - src/server/project.ts | 13 ++++++---- .../unittests/tsserver/projectErrors.ts | 2 +- src/testRunner/unittests/tsserver/projects.ts | 2 +- .../unittests/tsserver/resolutionCache.ts | 10 ++----- .../unittests/tsserver/typingsInstaller.ts | 26 +++++++++---------- 6 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 889c76bf0d58a..864cc0268e2ce 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -922,7 +922,6 @@ namespace ts.server { case ActionSet: // Update the typing files and update the project project.updateTypingFiles(this.typingsCache.updateTypingsForProject(response.projectName, response.compilerOptions, response.typeAcquisition, response.unresolvedImports, response.typings)); - this.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project); return; case ActionInvalidate: // Do not clear resolution cache, there was changes detected in typings, so enque typing request and let it get us correct results diff --git a/src/server/project.ts b/src/server/project.ts index 21f3f55eb2696..7c95a633dae79 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1057,13 +1057,16 @@ namespace ts.server { /*@internal*/ updateTypingFiles(typingFiles: SortedReadonlyArray) { - enumerateInsertsAndDeletes(typingFiles, this.typingFiles, getStringComparer(!this.useCaseSensitiveFileNames()), + if (enumerateInsertsAndDeletes(typingFiles, this.typingFiles, getStringComparer(!this.useCaseSensitiveFileNames()), /*inserted*/ noop, removed => this.detachScriptInfoFromProject(removed) - ); - this.typingFiles = typingFiles; - // Invalidate files with unresolved imports - this.resolutionCache.setFilesWithInvalidatedNonRelativeUnresolvedImports(this.cachedUnresolvedImportsPerFile); + )) { + // If typing files changed, then only schedule project update + this.typingFiles = typingFiles; + // Invalidate files with unresolved imports + this.resolutionCache.setFilesWithInvalidatedNonRelativeUnresolvedImports(this.cachedUnresolvedImportsPerFile); + this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this); + } } /* @internal */ diff --git a/src/testRunner/unittests/tsserver/projectErrors.ts b/src/testRunner/unittests/tsserver/projectErrors.ts index 40312f9303ab0..4a5926afaca8e 100644 --- a/src/testRunner/unittests/tsserver/projectErrors.ts +++ b/src/testRunner/unittests/tsserver/projectErrors.ts @@ -409,7 +409,7 @@ namespace ts.projectSystem { checkErrors([serverUtilities.path, app.path]); function checkErrors(openFiles: [string, string]) { - verifyGetErrRequestNoErrors({ session, host, files: openFiles, existingTimeouts: 2 }); + verifyGetErrRequestNoErrors({ session, host, files: openFiles }); } }); diff --git a/src/testRunner/unittests/tsserver/projects.ts b/src/testRunner/unittests/tsserver/projects.ts index 65938314f115a..566d098416311 100644 --- a/src/testRunner/unittests/tsserver/projects.ts +++ b/src/testRunner/unittests/tsserver/projects.ts @@ -419,7 +419,7 @@ namespace ts.projectSystem { unresolvedImports: response.unresolvedImports, }); - host.checkTimeoutQueueLengthAndRun(1); + host.checkTimeoutQueueLength(0); assert.isUndefined(request); }); diff --git a/src/testRunner/unittests/tsserver/resolutionCache.ts b/src/testRunner/unittests/tsserver/resolutionCache.ts index 7a88d42da050e..d3d4ff1361774 100644 --- a/src/testRunner/unittests/tsserver/resolutionCache.ts +++ b/src/testRunner/unittests/tsserver/resolutionCache.ts @@ -198,10 +198,7 @@ namespace ts.projectSystem { checkNumberOfProjects(service, { inferredProjects: 1 }); session.clearMessages(); - host.checkTimeoutQueueLengthAndRun(2); - - checkProjectUpdatedInBackgroundEvent(session, [file.path]); - + host.checkTimeoutQueueLength(0); verifyGetErrRequest({ session, host, @@ -240,10 +237,7 @@ namespace ts.projectSystem { checkNumberOfProjects(service, { inferredProjects: 1 }); session.clearMessages(); - host.checkTimeoutQueueLengthAndRun(2); - - checkProjectUpdatedInBackgroundEvent(session, [file.path]); - + host.checkTimeoutQueueLength(0); verifyGetErrRequest({ session, host, diff --git a/src/testRunner/unittests/tsserver/typingsInstaller.ts b/src/testRunner/unittests/tsserver/typingsInstaller.ts index 52e30daf45947..5bb0fc9792a83 100644 --- a/src/testRunner/unittests/tsserver/typingsInstaller.ts +++ b/src/testRunner/unittests/tsserver/typingsInstaller.ts @@ -244,7 +244,7 @@ namespace ts.projectSystem { checkProjectActualFiles(p, [jqueryJs.path]); installer.installAll(/*expectedCount*/ 0); - host.checkTimeoutQueueLengthAndRun(2); + host.checkTimeoutQueueLength(0); checkNumberOfProjects(projectService, { inferredProjects: 1 }); // files should not be removed from project if ATA is skipped checkProjectActualFiles(p, [jqueryJs.path]); @@ -1024,9 +1024,8 @@ namespace ts.projectSystem { service.openClientFile(f.path); installer.checkPendingCommands(/*expectedCount*/ 0); - host.writeFile(fixedPackageJson.path, fixedPackageJson.content); - host.checkTimeoutQueueLengthAndRun(2); // To refresh the project and refresh inferred projects + host.checkTimeoutQueueLength(0); // expected install request installer.installAll(/*expectedCount*/ 1); host.checkTimeoutQueueLengthAndRun(2); @@ -1212,7 +1211,8 @@ namespace ts.projectSystem { } }; session.executeCommand(changeRequest); - host.checkTimeoutQueueLengthAndRun(2); // This enqueues the updategraph and refresh inferred projects + host.checkTimeoutQueueLength(0); + proj.updateGraph(); const version2 = proj.lastCachedUnresolvedImportsList; assert.strictEqual(version1, version2, "set of unresolved imports should change"); }); @@ -1884,8 +1884,8 @@ namespace ts.projectSystem { }])); host.runQueuedTimeoutCallbacks(); // Update the graph // Update the typing - host.checkTimeoutQueueLength(2); - assert.isTrue(proj.resolutionCache.isFileWithInvalidatedNonRelativeUnresolvedImports(app.path as Path)); + host.checkTimeoutQueueLength(0); + assert.isFalse(proj.resolutionCache.isFileWithInvalidatedNonRelativeUnresolvedImports(app.path as Path)); } it("correctly invalidate the resolutions with typing names", () => { @@ -1947,7 +1947,7 @@ declare module "stream" { executeCommand(this, host, ["node"], [nodeTyping], cb); } })(); - const projectService = createProjectService(host, { typingsInstaller: installer, logger: createLoggerWritingToConsole() }); + const projectService = createProjectService(host, { typingsInstaller: installer }); projectService.openClientFile(file.path); projectService.checkNumberOfProjects({ inferredProjects: 1 }); @@ -1975,11 +1975,8 @@ declare module "stream" { host.checkTimeoutQueueLengthAndRun(2); checkProjectActualFiles(proj, [file.path, libFile.path, nodeTyping.path]); - // Here, since typings doesnt contain node typings and resolution fails and - // node typings go out of project, - // but because we handle core node modules when resolving from typings cache - // node typings are included in the project - host.checkTimeoutQueueLengthAndRun(2); + // Here, since typings dont change, there is no timeout scheduled + host.checkTimeoutQueueLength(0); checkProjectActualFiles(proj, [file.path, libFile.path, nodeTyping.path]); projectService.applyChangesInOpenFiles(/*openFiles*/ undefined, arrayIterator([{ fileName: file.path, @@ -1989,9 +1986,10 @@ declare module "stream" { }]) }])); proj.updateGraph(); // Update the graph + checkProjectActualFiles(proj, [file.path, libFile.path, nodeTyping.path]); // Update the typing - host.checkTimeoutQueueLength(2); - assert.isTrue(proj.resolutionCache.isFileWithInvalidatedNonRelativeUnresolvedImports(file.path as Path)); + host.checkTimeoutQueueLength(0); + assert.isFalse(proj.resolutionCache.isFileWithInvalidatedNonRelativeUnresolvedImports(file.path as Path)); }); });