Merge pull request #11002 from RyanCavanaugh/watchForTypes

Watch for changes in types roots
This commit is contained in:
Ryan Cavanaugh 2016-09-20 17:12:18 -07:00 committed by GitHub
commit 53232b9680
6 changed files with 70 additions and 0 deletions

View file

@ -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 { }

View file

@ -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;

View file

@ -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;

View file

@ -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 {

View file

@ -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);

View file

@ -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;
}