Merge pull request #11002 from RyanCavanaugh/watchForTypes
Watch for changes in types roots
This commit is contained in:
commit
53232b9680
6 changed files with 70 additions and 0 deletions
|
@ -218,6 +218,9 @@ namespace Harness.LanguageService {
|
||||||
const snapshot = this.getScriptSnapshot(path);
|
const snapshot = this.getScriptSnapshot(path);
|
||||||
return snapshot.getText(0, snapshot.getLength());
|
return snapshot.getText(0, snapshot.getLength());
|
||||||
}
|
}
|
||||||
|
getTypeRootsVersion() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
log(s: string): void { }
|
log(s: string): void { }
|
||||||
|
|
|
@ -363,6 +363,15 @@ namespace ts.server {
|
||||||
this.printProjects();
|
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.
|
* 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
|
* @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
|
// 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
|
// it is not likely to affect the project for other files opened by the client. We can
|
||||||
// just update the current project.
|
// just update the current project.
|
||||||
|
|
||||||
|
this.logger.info("Updating configured project");
|
||||||
this.updateConfiguredProject(project);
|
this.updateConfiguredProject(project);
|
||||||
|
|
||||||
// Call refreshInferredProjects to clean up inferred projects we may have
|
// Call refreshInferredProjects to clean up inferred projects we may have
|
||||||
|
@ -771,6 +782,7 @@ namespace ts.server {
|
||||||
this.watchConfigDirectoryForProject(project, projectOptions);
|
this.watchConfigDirectoryForProject(project, projectOptions);
|
||||||
}
|
}
|
||||||
project.watchWildcards((project, path) => this.onSourceFileInDirectoryChangedForConfiguredProject(project, path));
|
project.watchWildcards((project, path) => this.onSourceFileInDirectoryChangedForConfiguredProject(project, path));
|
||||||
|
project.watchTypeRoots((project, path) => this.onTypeRootFileChanged(project, path));
|
||||||
|
|
||||||
this.configuredProjects.push(project);
|
this.configuredProjects.push(project);
|
||||||
return project;
|
return project;
|
||||||
|
|
|
@ -145,6 +145,10 @@ namespace ts.server {
|
||||||
return this.project.getRootFilesLSHost();
|
return this.project.getRootFilesLSHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTypeRootsVersion() {
|
||||||
|
return this.project.typesVersion;
|
||||||
|
}
|
||||||
|
|
||||||
getScriptKind(fileName: string) {
|
getScriptKind(fileName: string) {
|
||||||
const info = this.project.getScriptInfoLSHost(fileName);
|
const info = this.project.getScriptInfoLSHost(fileName);
|
||||||
return info && info.scriptKind;
|
return info && info.scriptKind;
|
||||||
|
|
|
@ -69,6 +69,8 @@ namespace ts.server {
|
||||||
|
|
||||||
protected projectErrors: Diagnostic[];
|
protected projectErrors: Diagnostic[];
|
||||||
|
|
||||||
|
public typesVersion = 0;
|
||||||
|
|
||||||
public isJsOnlyProject() {
|
public isJsOnlyProject() {
|
||||||
this.updateGraph();
|
this.updateGraph();
|
||||||
return allFilesAreJsOrDts(this);
|
return allFilesAreJsOrDts(this);
|
||||||
|
@ -153,6 +155,12 @@ namespace ts.server {
|
||||||
return this.program.getSourceFileByPath(path);
|
return this.program.getSourceFileByPath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTypes() {
|
||||||
|
this.typesVersion++;
|
||||||
|
this.markAsDirty();
|
||||||
|
this.updateGraph();
|
||||||
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
if (this.program) {
|
if (this.program) {
|
||||||
// if we have a program - release all files that are enlisted in 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 projectFileWatcher: FileWatcher;
|
||||||
private directoryWatcher: FileWatcher;
|
private directoryWatcher: FileWatcher;
|
||||||
private directoriesWatchedForWildcards: Map<FileWatcher>;
|
private directoriesWatchedForWildcards: Map<FileWatcher>;
|
||||||
|
private typeRootsWatchers: FileWatcher[];
|
||||||
|
|
||||||
/** Used for configured projects which may have multiple open roots */
|
/** Used for configured projects which may have multiple open roots */
|
||||||
openRefCount = 0;
|
openRefCount = 0;
|
||||||
|
@ -608,6 +617,16 @@ namespace ts.server {
|
||||||
this.projectFileWatcher = this.projectService.host.watchFile(this.configFileName, _ => callback(this));
|
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) {
|
watchConfigDirectory(callback: (project: ConfiguredProject, path: string) => void) {
|
||||||
if (this.directoryWatcher) {
|
if (this.directoryWatcher) {
|
||||||
return;
|
return;
|
||||||
|
@ -651,6 +670,13 @@ namespace ts.server {
|
||||||
this.projectFileWatcher.close();
|
this.projectFileWatcher.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.typeRootsWatchers) {
|
||||||
|
for (const watcher of this.typeRootsWatchers) {
|
||||||
|
watcher.close();
|
||||||
|
}
|
||||||
|
this.typeRootsWatchers = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
for (const id in this.directoriesWatchedForWildcards) {
|
for (const id in this.directoriesWatchedForWildcards) {
|
||||||
this.directoriesWatchedForWildcards[id].close();
|
this.directoriesWatchedForWildcards[id].close();
|
||||||
}
|
}
|
||||||
|
@ -667,6 +693,10 @@ namespace ts.server {
|
||||||
this.openRefCount--;
|
this.openRefCount--;
|
||||||
return this.openRefCount;
|
return this.openRefCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getEffectiveTypeRoots() {
|
||||||
|
return ts.getEffectiveTypeRoots(this.getCompilerOptions(), this.projectService.host) || [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExternalProject extends Project {
|
export class ExternalProject extends Project {
|
||||||
|
|
|
@ -1185,6 +1185,11 @@ namespace ts {
|
||||||
readFile?(path: string, encoding?: string): string;
|
readFile?(path: string, encoding?: string): string;
|
||||||
fileExists?(path: string): boolean;
|
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.
|
* 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
|
* 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 ruleProvider: formatting.RulesProvider;
|
||||||
let program: Program;
|
let program: Program;
|
||||||
let lastProjectVersion: string;
|
let lastProjectVersion: string;
|
||||||
|
let lastTypesRootVersion = 0;
|
||||||
|
|
||||||
const useCaseSensitivefileNames = host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames();
|
const useCaseSensitivefileNames = host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames();
|
||||||
const cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken());
|
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 documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings);
|
||||||
const newProgram = createProgram(hostCache.getRootFileNames(), newSettings, compilerHost, program);
|
const newProgram = createProgram(hostCache.getRootFileNames(), newSettings, compilerHost, program);
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ namespace ts {
|
||||||
getProjectVersion?(): string;
|
getProjectVersion?(): string;
|
||||||
useCaseSensitiveFileNames?(): boolean;
|
useCaseSensitiveFileNames?(): boolean;
|
||||||
|
|
||||||
|
getTypeRootsVersion?(): number;
|
||||||
readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string;
|
readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string;
|
||||||
readFile(path: string, encoding?: string): string;
|
readFile(path: string, encoding?: string): string;
|
||||||
fileExists(path: string): boolean;
|
fileExists(path: string): boolean;
|
||||||
|
@ -358,6 +359,13 @@ namespace ts {
|
||||||
return this.shimHost.getProjectVersion();
|
return this.shimHost.getProjectVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getTypeRootsVersion(): number {
|
||||||
|
if (!this.shimHost.getTypeRootsVersion) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return this.shimHost.getTypeRootsVersion();
|
||||||
|
}
|
||||||
|
|
||||||
public useCaseSensitiveFileNames(): boolean {
|
public useCaseSensitiveFileNames(): boolean {
|
||||||
return this.shimHost.useCaseSensitiveFileNames ? this.shimHost.useCaseSensitiveFileNames() : false;
|
return this.shimHost.useCaseSensitiveFileNames ? this.shimHost.useCaseSensitiveFileNames() : false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue