Skip to content

Commit 53232b9

Browse files
Merge pull request #11002 from RyanCavanaugh/watchForTypes
Watch for changes in types roots
2 parents 6275da2 + 52fddfa commit 53232b9

File tree

6 files changed

+70
-0
lines changed

6 files changed

+70
-0
lines changed

src/harness/harnessLanguageService.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ namespace Harness.LanguageService {
218218
const snapshot = this.getScriptSnapshot(path);
219219
return snapshot.getText(0, snapshot.getLength());
220220
}
221+
getTypeRootsVersion() {
222+
return 0;
223+
}
221224

222225

223226
log(s: string): void { }

src/server/editorServices.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,15 @@ namespace ts.server {
363363
this.printProjects();
364364
}
365365

366+
private onTypeRootFileChanged(project: ConfiguredProject, fileName: string) {
367+
this.logger.info(`Type root file ${fileName} changed`);
368+
this.throttledOperations.schedule(project.configFileName + " * type root", /*delay*/ 250, () => {
369+
project.updateTypes();
370+
this.updateConfiguredProject(project); // TODO: Figure out why this is needed (should be redundant?)
371+
this.refreshInferredProjects();
372+
});
373+
}
374+
366375
/**
367376
* This is the callback function when a watched directory has added or removed source code files.
368377
* @param project the project that associates with this directory watcher
@@ -395,6 +404,8 @@ namespace ts.server {
395404
// For configured projects, the change is made outside the tsconfig file, and
396405
// it is not likely to affect the project for other files opened by the client. We can
397406
// just update the current project.
407+
408+
this.logger.info("Updating configured project");
398409
this.updateConfiguredProject(project);
399410

400411
// Call refreshInferredProjects to clean up inferred projects we may have
@@ -771,6 +782,7 @@ namespace ts.server {
771782
this.watchConfigDirectoryForProject(project, projectOptions);
772783
}
773784
project.watchWildcards((project, path) => this.onSourceFileInDirectoryChangedForConfiguredProject(project, path));
785+
project.watchTypeRoots((project, path) => this.onTypeRootFileChanged(project, path));
774786

775787
this.configuredProjects.push(project);
776788
return project;

src/server/lsHost.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ namespace ts.server {
145145
return this.project.getRootFilesLSHost();
146146
}
147147

148+
getTypeRootsVersion() {
149+
return this.project.typesVersion;
150+
}
151+
148152
getScriptKind(fileName: string) {
149153
const info = this.project.getScriptInfoLSHost(fileName);
150154
return info && info.scriptKind;

src/server/project.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ namespace ts.server {
6969

7070
protected projectErrors: Diagnostic[];
7171

72+
public typesVersion = 0;
73+
7274
public isJsOnlyProject() {
7375
this.updateGraph();
7476
return allFilesAreJsOrDts(this);
@@ -153,6 +155,12 @@ namespace ts.server {
153155
return this.program.getSourceFileByPath(path);
154156
}
155157

158+
updateTypes() {
159+
this.typesVersion++;
160+
this.markAsDirty();
161+
this.updateGraph();
162+
}
163+
156164
close() {
157165
if (this.program) {
158166
// if we have a program - release all files that are enlisted in program
@@ -569,6 +577,7 @@ namespace ts.server {
569577
private projectFileWatcher: FileWatcher;
570578
private directoryWatcher: FileWatcher;
571579
private directoriesWatchedForWildcards: Map<FileWatcher>;
580+
private typeRootsWatchers: FileWatcher[];
572581

573582
/** Used for configured projects which may have multiple open roots */
574583
openRefCount = 0;
@@ -608,6 +617,16 @@ namespace ts.server {
608617
this.projectFileWatcher = this.projectService.host.watchFile(this.configFileName, _ => callback(this));
609618
}
610619

620+
watchTypeRoots(callback: (project: ConfiguredProject, path: string) => void) {
621+
const roots = this.getEffectiveTypeRoots();
622+
const watchers: FileWatcher[] = [];
623+
for (const root of roots) {
624+
this.projectService.logger.info(`Add type root watcher for: ${root}`);
625+
watchers.push(this.projectService.host.watchDirectory(root, path => callback(this, path), /*recursive*/ false));
626+
}
627+
this.typeRootsWatchers = watchers;
628+
}
629+
611630
watchConfigDirectory(callback: (project: ConfiguredProject, path: string) => void) {
612631
if (this.directoryWatcher) {
613632
return;
@@ -651,6 +670,13 @@ namespace ts.server {
651670
this.projectFileWatcher.close();
652671
}
653672

673+
if (this.typeRootsWatchers) {
674+
for (const watcher of this.typeRootsWatchers) {
675+
watcher.close();
676+
}
677+
this.typeRootsWatchers = undefined;
678+
}
679+
654680
for (const id in this.directoriesWatchedForWildcards) {
655681
this.directoriesWatchedForWildcards[id].close();
656682
}
@@ -667,6 +693,10 @@ namespace ts.server {
667693
this.openRefCount--;
668694
return this.openRefCount;
669695
}
696+
697+
getEffectiveTypeRoots() {
698+
return ts.getEffectiveTypeRoots(this.getCompilerOptions(), this.projectService.host) || [];
699+
}
670700
}
671701

672702
export class ExternalProject extends Project {

src/services/services.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,11 @@ namespace ts {
11851185
readFile?(path: string, encoding?: string): string;
11861186
fileExists?(path: string): boolean;
11871187

1188+
/*
1189+
* LS host can optionally implement these methods to support automatic updating when new type libraries are installed
1190+
*/
1191+
getTypeRootsVersion?(): number;
1192+
11881193
/*
11891194
* LS host can optionally implement this method if it wants to be completely in charge of module name resolution.
11901195
* if implementation is omitted then language service will use built-in module resolution logic and get answers to
@@ -3099,6 +3104,7 @@ namespace ts {
30993104
let ruleProvider: formatting.RulesProvider;
31003105
let program: Program;
31013106
let lastProjectVersion: string;
3107+
let lastTypesRootVersion = 0;
31023108

31033109
const useCaseSensitivefileNames = host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames();
31043110
const cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken());
@@ -3215,6 +3221,13 @@ namespace ts {
32153221
};
32163222
}
32173223

3224+
const typeRootsVersion = host.getTypeRootsVersion ? host.getTypeRootsVersion() : 0;
3225+
if (lastTypesRootVersion !== typeRootsVersion) {
3226+
log("TypeRoots version has changed; provide new program");
3227+
program = undefined;
3228+
lastTypesRootVersion = typeRootsVersion;
3229+
}
3230+
32183231
const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings);
32193232
const newProgram = createProgram(hostCache.getRootFileNames(), newSettings, compilerHost, program);
32203233

src/services/shims.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ namespace ts {
6767
getProjectVersion?(): string;
6868
useCaseSensitiveFileNames?(): boolean;
6969

70+
getTypeRootsVersion?(): number;
7071
readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string;
7172
readFile(path: string, encoding?: string): string;
7273
fileExists(path: string): boolean;
@@ -358,6 +359,13 @@ namespace ts {
358359
return this.shimHost.getProjectVersion();
359360
}
360361

362+
public getTypeRootsVersion(): number {
363+
if (!this.shimHost.getTypeRootsVersion) {
364+
return 0;
365+
}
366+
return this.shimHost.getTypeRootsVersion();
367+
}
368+
361369
public useCaseSensitiveFileNames(): boolean {
362370
return this.shimHost.useCaseSensitiveFileNames ? this.shimHost.useCaseSensitiveFileNames() : false;
363371
}

0 commit comments

Comments
 (0)