Merge pull request #11002 from RyanCavanaugh/watchForTypes
Watch for changes in types roots
This commit is contained in:
commit
53232b9680
|
@ -218,6 +218,9 @@ namespace Harness.LanguageService {
|
|||
const snapshot = this.getScriptSnapshot(path);
|
||||
return snapshot.getText(0, snapshot.getLength());
|
||||
}
|
||||
getTypeRootsVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
log(s: string): void { }
|
||||
|
|
|
@ -363,6 +363,15 @@ namespace ts.server {
|
|||
this.printProjects();
|
||||
}
|
||||
|
||||
private onTypeRootFileChanged(project: ConfiguredProject, fileName: string) {
|
||||
this.logger.info(`Type root file ${fileName} changed`);
|
||||
this.throttledOperations.schedule(project.configFileName + " * type root", /*delay*/ 250, () => {
|
||||
project.updateTypes();
|
||||
this.updateConfiguredProject(project); // TODO: Figure out why this is needed (should be redundant?)
|
||||
this.refreshInferredProjects();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the callback function when a watched directory has added or removed source code files.
|
||||
* @param project the project that associates with this directory watcher
|
||||
|
@ -395,6 +404,8 @@ namespace ts.server {
|
|||
// For configured projects, the change is made outside the tsconfig file, and
|
||||
// it is not likely to affect the project for other files opened by the client. We can
|
||||
// just update the current project.
|
||||
|
||||
this.logger.info("Updating configured project");
|
||||
this.updateConfiguredProject(project);
|
||||
|
||||
// Call refreshInferredProjects to clean up inferred projects we may have
|
||||
|
@ -771,6 +782,7 @@ namespace ts.server {
|
|||
this.watchConfigDirectoryForProject(project, projectOptions);
|
||||
}
|
||||
project.watchWildcards((project, path) => this.onSourceFileInDirectoryChangedForConfiguredProject(project, path));
|
||||
project.watchTypeRoots((project, path) => this.onTypeRootFileChanged(project, path));
|
||||
|
||||
this.configuredProjects.push(project);
|
||||
return project;
|
||||
|
|
|
@ -145,6 +145,10 @@ namespace ts.server {
|
|||
return this.project.getRootFilesLSHost();
|
||||
}
|
||||
|
||||
getTypeRootsVersion() {
|
||||
return this.project.typesVersion;
|
||||
}
|
||||
|
||||
getScriptKind(fileName: string) {
|
||||
const info = this.project.getScriptInfoLSHost(fileName);
|
||||
return info && info.scriptKind;
|
||||
|
|
|
@ -69,6 +69,8 @@ namespace ts.server {
|
|||
|
||||
protected projectErrors: Diagnostic[];
|
||||
|
||||
public typesVersion = 0;
|
||||
|
||||
public isJsOnlyProject() {
|
||||
this.updateGraph();
|
||||
return allFilesAreJsOrDts(this);
|
||||
|
@ -153,6 +155,12 @@ namespace ts.server {
|
|||
return this.program.getSourceFileByPath(path);
|
||||
}
|
||||
|
||||
updateTypes() {
|
||||
this.typesVersion++;
|
||||
this.markAsDirty();
|
||||
this.updateGraph();
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.program) {
|
||||
// if we have a program - release all files that are enlisted in program
|
||||
|
@ -569,6 +577,7 @@ namespace ts.server {
|
|||
private projectFileWatcher: FileWatcher;
|
||||
private directoryWatcher: FileWatcher;
|
||||
private directoriesWatchedForWildcards: Map<FileWatcher>;
|
||||
private typeRootsWatchers: FileWatcher[];
|
||||
|
||||
/** Used for configured projects which may have multiple open roots */
|
||||
openRefCount = 0;
|
||||
|
@ -608,6 +617,16 @@ namespace ts.server {
|
|||
this.projectFileWatcher = this.projectService.host.watchFile(this.configFileName, _ => callback(this));
|
||||
}
|
||||
|
||||
watchTypeRoots(callback: (project: ConfiguredProject, path: string) => void) {
|
||||
const roots = this.getEffectiveTypeRoots();
|
||||
const watchers: FileWatcher[] = [];
|
||||
for (const root of roots) {
|
||||
this.projectService.logger.info(`Add type root watcher for: ${root}`);
|
||||
watchers.push(this.projectService.host.watchDirectory(root, path => callback(this, path), /*recursive*/ false));
|
||||
}
|
||||
this.typeRootsWatchers = watchers;
|
||||
}
|
||||
|
||||
watchConfigDirectory(callback: (project: ConfiguredProject, path: string) => void) {
|
||||
if (this.directoryWatcher) {
|
||||
return;
|
||||
|
@ -651,6 +670,13 @@ namespace ts.server {
|
|||
this.projectFileWatcher.close();
|
||||
}
|
||||
|
||||
if (this.typeRootsWatchers) {
|
||||
for (const watcher of this.typeRootsWatchers) {
|
||||
watcher.close();
|
||||
}
|
||||
this.typeRootsWatchers = undefined;
|
||||
}
|
||||
|
||||
for (const id in this.directoriesWatchedForWildcards) {
|
||||
this.directoriesWatchedForWildcards[id].close();
|
||||
}
|
||||
|
@ -667,6 +693,10 @@ namespace ts.server {
|
|||
this.openRefCount--;
|
||||
return this.openRefCount;
|
||||
}
|
||||
|
||||
getEffectiveTypeRoots() {
|
||||
return ts.getEffectiveTypeRoots(this.getCompilerOptions(), this.projectService.host) || [];
|
||||
}
|
||||
}
|
||||
|
||||
export class ExternalProject extends Project {
|
||||
|
|
|
@ -1185,6 +1185,11 @@ namespace ts {
|
|||
readFile?(path: string, encoding?: string): string;
|
||||
fileExists?(path: string): boolean;
|
||||
|
||||
/*
|
||||
* LS host can optionally implement these methods to support automatic updating when new type libraries are installed
|
||||
*/
|
||||
getTypeRootsVersion?(): number;
|
||||
|
||||
/*
|
||||
* LS host can optionally implement this method if it wants to be completely in charge of module name resolution.
|
||||
* if implementation is omitted then language service will use built-in module resolution logic and get answers to
|
||||
|
@ -3099,6 +3104,7 @@ namespace ts {
|
|||
let ruleProvider: formatting.RulesProvider;
|
||||
let program: Program;
|
||||
let lastProjectVersion: string;
|
||||
let lastTypesRootVersion = 0;
|
||||
|
||||
const useCaseSensitivefileNames = host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames();
|
||||
const cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken());
|
||||
|
@ -3215,6 +3221,13 @@ namespace ts {
|
|||
};
|
||||
}
|
||||
|
||||
const typeRootsVersion = host.getTypeRootsVersion ? host.getTypeRootsVersion() : 0;
|
||||
if (lastTypesRootVersion !== typeRootsVersion) {
|
||||
log("TypeRoots version has changed; provide new program");
|
||||
program = undefined;
|
||||
lastTypesRootVersion = typeRootsVersion;
|
||||
}
|
||||
|
||||
const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings);
|
||||
const newProgram = createProgram(hostCache.getRootFileNames(), newSettings, compilerHost, program);
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ namespace ts {
|
|||
getProjectVersion?(): string;
|
||||
useCaseSensitiveFileNames?(): boolean;
|
||||
|
||||
getTypeRootsVersion?(): number;
|
||||
readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string;
|
||||
readFile(path: string, encoding?: string): string;
|
||||
fileExists(path: string): boolean;
|
||||
|
@ -358,6 +359,13 @@ namespace ts {
|
|||
return this.shimHost.getProjectVersion();
|
||||
}
|
||||
|
||||
public getTypeRootsVersion(): number {
|
||||
if (!this.shimHost.getTypeRootsVersion) {
|
||||
return 0;
|
||||
}
|
||||
return this.shimHost.getTypeRootsVersion();
|
||||
}
|
||||
|
||||
public useCaseSensitiveFileNames(): boolean {
|
||||
return this.shimHost.useCaseSensitiveFileNames ? this.shimHost.useCaseSensitiveFileNames() : false;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue