Skip to content

Commit 80dfc6a

Browse files
authored
Only when typings file change for the project, schedule the update for the project (microsoft#42428)
* Update and add test when typings dont change because of import name * Update project scheduling only when typings are set * Schedule update graph only if typings change Fixes microsoft#39326
1 parent 4c62f6e commit 80dfc6a

File tree

7 files changed

+52
-27
lines changed

7 files changed

+52
-27
lines changed

src/compiler/resolutionCache.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ namespace ts {
1616
setFilesWithInvalidatedNonRelativeUnresolvedImports(filesWithUnresolvedImports: ESMap<Path, readonly string[]>): void;
1717
createHasInvalidatedResolution(forceAllFilesAsInvalidated?: boolean): HasInvalidatedResolution;
1818
hasChangedAutomaticTypeDirectiveNames(): boolean;
19+
isFileWithInvalidatedNonRelativeUnresolvedImports(path: Path): boolean;
20+
1921

2022
startCachingPerDirectoryResolution(): void;
2123
finishCachingPerDirectoryResolution(): void;
@@ -208,6 +210,7 @@ namespace ts {
208210
invalidateResolutionsOfFailedLookupLocations,
209211
setFilesWithInvalidatedNonRelativeUnresolvedImports,
210212
createHasInvalidatedResolution,
213+
isFileWithInvalidatedNonRelativeUnresolvedImports,
211214
updateTypeRootsWatch,
212215
closeTypeRootsWatch,
213216
clear

src/server/editorServices.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -922,13 +922,12 @@ namespace ts.server {
922922
case ActionSet:
923923
// Update the typing files and update the project
924924
project.updateTypingFiles(this.typingsCache.updateTypingsForProject(response.projectName, response.compilerOptions, response.typeAcquisition, response.unresolvedImports, response.typings));
925-
break;
925+
return;
926926
case ActionInvalidate:
927927
// Do not clear resolution cache, there was changes detected in typings, so enque typing request and let it get us correct results
928928
this.typingsCache.enqueueInstallTypingsForProject(project, project.lastCachedUnresolvedImportsList, /*forceRefresh*/ true);
929929
return;
930930
}
931-
this.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project);
932931
}
933932

934933
/*@internal*/

src/server/project.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,13 +1057,16 @@ namespace ts.server {
10571057

10581058
/*@internal*/
10591059
updateTypingFiles(typingFiles: SortedReadonlyArray<string>) {
1060-
enumerateInsertsAndDeletes<string, string>(typingFiles, this.typingFiles, getStringComparer(!this.useCaseSensitiveFileNames()),
1060+
if (enumerateInsertsAndDeletes<string, string>(typingFiles, this.typingFiles, getStringComparer(!this.useCaseSensitiveFileNames()),
10611061
/*inserted*/ noop,
10621062
removed => this.detachScriptInfoFromProject(removed)
1063-
);
1064-
this.typingFiles = typingFiles;
1065-
// Invalidate files with unresolved imports
1066-
this.resolutionCache.setFilesWithInvalidatedNonRelativeUnresolvedImports(this.cachedUnresolvedImportsPerFile);
1063+
)) {
1064+
// If typing files changed, then only schedule project update
1065+
this.typingFiles = typingFiles;
1066+
// Invalidate files with unresolved imports
1067+
this.resolutionCache.setFilesWithInvalidatedNonRelativeUnresolvedImports(this.cachedUnresolvedImportsPerFile);
1068+
this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this);
1069+
}
10671070
}
10681071

10691072
/* @internal */

src/testRunner/unittests/tsserver/projectErrors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ namespace ts.projectSystem {
409409
checkErrors([serverUtilities.path, app.path]);
410410

411411
function checkErrors(openFiles: [string, string]) {
412-
verifyGetErrRequestNoErrors({ session, host, files: openFiles, existingTimeouts: 2 });
412+
verifyGetErrRequestNoErrors({ session, host, files: openFiles });
413413
}
414414
});
415415

src/testRunner/unittests/tsserver/projects.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ namespace ts.projectSystem {
419419
unresolvedImports: response.unresolvedImports,
420420
});
421421

422-
host.checkTimeoutQueueLengthAndRun(1);
422+
host.checkTimeoutQueueLength(0);
423423
assert.isUndefined(request);
424424
});
425425

src/testRunner/unittests/tsserver/resolutionCache.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,7 @@ namespace ts.projectSystem {
198198

199199
checkNumberOfProjects(service, { inferredProjects: 1 });
200200
session.clearMessages();
201-
host.checkTimeoutQueueLengthAndRun(2);
202-
203-
checkProjectUpdatedInBackgroundEvent(session, [file.path]);
204-
201+
host.checkTimeoutQueueLength(0);
205202
verifyGetErrRequest({
206203
session,
207204
host,
@@ -240,10 +237,7 @@ namespace ts.projectSystem {
240237

241238
checkNumberOfProjects(service, { inferredProjects: 1 });
242239
session.clearMessages();
243-
host.checkTimeoutQueueLengthAndRun(2);
244-
245-
checkProjectUpdatedInBackgroundEvent(session, [file.path]);
246-
240+
host.checkTimeoutQueueLength(0);
247241
verifyGetErrRequest({
248242
session,
249243
host,

src/testRunner/unittests/tsserver/typingsInstaller.ts

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ namespace ts.projectSystem {
244244
checkProjectActualFiles(p, [jqueryJs.path]);
245245

246246
installer.installAll(/*expectedCount*/ 0);
247-
host.checkTimeoutQueueLengthAndRun(2);
247+
host.checkTimeoutQueueLength(0);
248248
checkNumberOfProjects(projectService, { inferredProjects: 1 });
249249
// files should not be removed from project if ATA is skipped
250250
checkProjectActualFiles(p, [jqueryJs.path]);
@@ -1024,9 +1024,8 @@ namespace ts.projectSystem {
10241024
service.openClientFile(f.path);
10251025

10261026
installer.checkPendingCommands(/*expectedCount*/ 0);
1027-
10281027
host.writeFile(fixedPackageJson.path, fixedPackageJson.content);
1029-
host.checkTimeoutQueueLengthAndRun(2); // To refresh the project and refresh inferred projects
1028+
host.checkTimeoutQueueLength(0);
10301029
// expected install request
10311030
installer.installAll(/*expectedCount*/ 1);
10321031
host.checkTimeoutQueueLengthAndRun(2);
@@ -1212,7 +1211,8 @@ namespace ts.projectSystem {
12121211
}
12131212
};
12141213
session.executeCommand(changeRequest);
1215-
host.checkTimeoutQueueLengthAndRun(2); // This enqueues the updategraph and refresh inferred projects
1214+
host.checkTimeoutQueueLength(0);
1215+
proj.updateGraph();
12161216
const version2 = proj.lastCachedUnresolvedImportsList;
12171217
assert.strictEqual(version1, version2, "set of unresolved imports should change");
12181218
});
@@ -1837,6 +1837,7 @@ namespace ts.projectSystem {
18371837
const appPath = "/a/b/app.js" as Path;
18381838
const foooPath = "/a/b/node_modules/fooo/index.d.ts";
18391839
function verifyResolvedModuleOfFooo(project: server.Project) {
1840+
server.updateProjectIfDirty(project);
18401841
const foooResolution = project.getLanguageService().getProgram()!.getSourceFileByPath(appPath)!.resolvedModules!.get("fooo")!;
18411842
assert.equal(foooResolution.resolvedFileName, foooPath);
18421843
return foooResolution;
@@ -1851,6 +1852,7 @@ namespace ts.projectSystem {
18511852
path: foooPath,
18521853
content: `export var x: string;`
18531854
};
1855+
18541856
const host = createServerHost([app, fooo]);
18551857
const installer = new (class extends Installer {
18561858
constructor() {
@@ -1873,6 +1875,17 @@ namespace ts.projectSystem {
18731875
checkProjectActualFiles(proj, typingFiles.map(f => f.path).concat(app.path, fooo.path));
18741876
const foooResolution2 = verifyResolvedModuleOfFooo(proj);
18751877
assert.strictEqual(foooResolution1, foooResolution2);
1878+
projectService.applyChangesInOpenFiles(/*openFiles*/ undefined, arrayIterator([{
1879+
fileName: app.path,
1880+
changes: arrayIterator([{
1881+
span: { start: 0, length: 0 },
1882+
newText: `import * as bar from "bar";`
1883+
}])
1884+
}]));
1885+
host.runQueuedTimeoutCallbacks(); // Update the graph
1886+
// Update the typing
1887+
host.checkTimeoutQueueLength(0);
1888+
assert.isFalse(proj.resolutionCache.isFileWithInvalidatedNonRelativeUnresolvedImports(app.path as Path));
18761889
}
18771890

18781891
it("correctly invalidate the resolutions with typing names", () => {
@@ -1883,6 +1896,10 @@ namespace ts.projectSystem {
18831896
});
18841897

18851898
it("correctly invalidate the resolutions with typing names that are trimmed", () => {
1899+
const fooIndex: File = {
1900+
path: `${globalTypingsCacheLocation}/node_modules/foo/index.d.ts`,
1901+
content: "export function aa(): void;"
1902+
};
18861903
const fooAA: File = {
18871904
path: `${globalTypingsCacheLocation}/node_modules/foo/a/a.d.ts`,
18881905
content: "export function a (): void;"
@@ -1899,7 +1916,7 @@ namespace ts.projectSystem {
18991916
import * as a from "foo/a/a";
19001917
import * as b from "foo/a/b";
19011918
import * as c from "foo/a/c";
1902-
`, ["foo"], [fooAA, fooAB, fooAC]);
1919+
`, ["foo"], [fooIndex, fooAA, fooAB, fooAC]);
19031920
});
19041921

19051922
it("should handle node core modules", () => {
@@ -1958,12 +1975,21 @@ declare module "stream" {
19581975
host.checkTimeoutQueueLengthAndRun(2);
19591976
checkProjectActualFiles(proj, [file.path, libFile.path, nodeTyping.path]);
19601977

1961-
// Here, since typings doesnt contain node typings and resolution fails and
1962-
// node typings go out of project,
1963-
// but because we handle core node modules when resolving from typings cache
1964-
// node typings are included in the project
1965-
host.checkTimeoutQueueLengthAndRun(2);
1978+
// Here, since typings dont change, there is no timeout scheduled
1979+
host.checkTimeoutQueueLength(0);
1980+
checkProjectActualFiles(proj, [file.path, libFile.path, nodeTyping.path]);
1981+
projectService.applyChangesInOpenFiles(/*openFiles*/ undefined, arrayIterator([{
1982+
fileName: file.path,
1983+
changes: arrayIterator([{
1984+
span: { start: file.content.indexOf("const"), length: 0 },
1985+
newText: `const bar = require("bar");`
1986+
}])
1987+
}]));
1988+
proj.updateGraph(); // Update the graph
19661989
checkProjectActualFiles(proj, [file.path, libFile.path, nodeTyping.path]);
1990+
// Update the typing
1991+
host.checkTimeoutQueueLength(0);
1992+
assert.isFalse(proj.resolutionCache.isFileWithInvalidatedNonRelativeUnresolvedImports(file.path as Path));
19671993
});
19681994
});
19691995

0 commit comments

Comments
 (0)