mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
Optimize wildcard watchers and config directory watching as now we have missing file watching as well
We dont need to explicitly watch config file directory as it will be watched: - if there was no files specified, in wild card directories - if there were files specified as missing file (if the file wasnt present)
This commit is contained in:
parent
6bd42b81ee
commit
df6f75bc70
@ -611,7 +611,8 @@ namespace ts.server {
|
||||
* @param project the project that associates with this directory watcher
|
||||
* @param fileName the absolute file name that changed in watched directory
|
||||
*/
|
||||
private onSourceFileInDirectoryChangedForConfiguredProject(project: ConfiguredProject, fileName: string) {
|
||||
/* @internal */
|
||||
onFileAddOrRemoveInWatchedDirectoryOfProject(project: ConfiguredProject, fileName: string) {
|
||||
// If a change was made inside "folder/file", node will trigger the callback twice:
|
||||
// one with the fileName being "folder/file", and the other one with "folder".
|
||||
// We don't respond to the second one.
|
||||
@ -623,10 +624,13 @@ namespace ts.server {
|
||||
this.throttledOperations.schedule(
|
||||
project.getConfigFilePath(),
|
||||
/*delay*/250,
|
||||
() => this.handleChangeInSourceFileForConfiguredProject(project, fileName));
|
||||
() => this.handleFileAddOrRemoveInWatchedDirectoryOfProject(project, fileName));
|
||||
}
|
||||
|
||||
private handleChangeInSourceFileForConfiguredProject(project: ConfiguredProject, triggerFile: string) {
|
||||
private handleFileAddOrRemoveInWatchedDirectoryOfProject(project: ConfiguredProject, triggerFile: string) {
|
||||
// TODO: (sheetalkamat) this actually doesnt need to re-read the config file from the disk
|
||||
// it just needs to update the file list of file names
|
||||
// We might be able to do that by caching the info from first parse and add reusing this with the change in the file path
|
||||
const { projectOptions, configFileErrors } = this.convertConfigFileContentToProjectOptions(project.getConfigFilePath());
|
||||
this.reportConfigFileDiagnostics(project.getProjectName(), configFileErrors, triggerFile);
|
||||
|
||||
@ -676,6 +680,10 @@ namespace ts.server {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: (sheetalkamat)
|
||||
// 1. We should only watch tsconfig/jsconfig file here instead of watching directory
|
||||
// 2. We should try reloading projects with open files in Inferred project only
|
||||
// 3. We should use this watcher to answer questions to findConfigFile rather than calling host everytime
|
||||
this.logger.info(`Detected newly added tsconfig file: ${fileName}`);
|
||||
this.reloadProjects();
|
||||
}
|
||||
@ -1117,17 +1125,13 @@ namespace ts.server {
|
||||
this.documentRegistry,
|
||||
projectOptions.configHasFilesProperty,
|
||||
projectOptions.compilerOptions,
|
||||
projectOptions.wildcardDirectories,
|
||||
/*languageServiceEnabled*/ !sizeLimitExceeded,
|
||||
projectOptions.compileOnSave === undefined ? false : projectOptions.compileOnSave);
|
||||
|
||||
this.addFilesToProjectAndUpdateGraph(project, projectOptions.files, fileNamePropertyReader, clientFileName, projectOptions.typeAcquisition, configFileErrors);
|
||||
|
||||
project.watchConfigFile((project, eventKind) => this.onConfigChangedForConfiguredProject(project, eventKind));
|
||||
if (!sizeLimitExceeded) {
|
||||
this.watchConfigDirectoryForProject(project, projectOptions);
|
||||
}
|
||||
project.watchWildcards((project, path) => this.onSourceFileInDirectoryChangedForConfiguredProject(project, path));
|
||||
project.watchWildcards(projectOptions.wildcardDirectories);
|
||||
project.watchTypeRoots((project, path) => this.onTypeRootFileChanged(project, path));
|
||||
|
||||
this.configuredProjects.push(project);
|
||||
@ -1135,12 +1139,6 @@ namespace ts.server {
|
||||
return project;
|
||||
}
|
||||
|
||||
private watchConfigDirectoryForProject(project: ConfiguredProject, options: ProjectOptions): void {
|
||||
if (!options.configHasFilesProperty) {
|
||||
project.watchConfigDirectory((project, path) => this.onSourceFileInDirectoryChangedForConfiguredProject(project, path));
|
||||
}
|
||||
}
|
||||
|
||||
private addFilesToProjectAndUpdateGraph<T>(project: ConfiguredProject | ExternalProject, files: T[], propertyReader: FilePropertyReader<T>, clientFileName: string, typeAcquisition: TypeAcquisition, configFileErrors: Diagnostic[]): void {
|
||||
for (const f of files) {
|
||||
const rootFilename = propertyReader.getFileName(f);
|
||||
@ -1271,12 +1269,12 @@ namespace ts.server {
|
||||
project.setProjectErrors(configFileErrors);
|
||||
}
|
||||
project.disableLanguageService();
|
||||
project.stopWatchingDirectory();
|
||||
project.stopWatchingWildCards();
|
||||
project.setProjectErrors(configFileErrors);
|
||||
}
|
||||
else {
|
||||
project.enableLanguageService();
|
||||
this.watchConfigDirectoryForProject(project, projectOptions);
|
||||
project.watchWildcards(projectOptions.wildcardDirectories);
|
||||
this.updateNonInferredProject(project, projectOptions.files, fileNamePropertyReader, projectOptions.compilerOptions, projectOptions.typeAcquisition, projectOptions.compileOnSave, configFileErrors);
|
||||
}
|
||||
}
|
||||
|
||||
@ -957,6 +957,8 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
type WildCardDirectoryWatchers = { watcher: FileWatcher, recursive: boolean };
|
||||
|
||||
/**
|
||||
* If a file is opened, the server will look for a tsconfig (or jsconfig)
|
||||
* and if successfull create a ConfiguredProject for it.
|
||||
@ -964,9 +966,8 @@ namespace ts.server {
|
||||
*/
|
||||
export class ConfiguredProject extends Project {
|
||||
private typeAcquisition: TypeAcquisition;
|
||||
private projectFileWatcher: FileWatcher;
|
||||
private directoryWatcher: FileWatcher;
|
||||
private directoriesWatchedForWildcards: Map<FileWatcher>;
|
||||
private configFileWatcher: FileWatcher;
|
||||
private directoriesWatchedForWildcards: Map<WildCardDirectoryWatchers>;
|
||||
private typeRootsWatchers: FileWatcher[];
|
||||
readonly canonicalConfigFilePath: NormalizedPath;
|
||||
|
||||
@ -980,7 +981,6 @@ namespace ts.server {
|
||||
documentRegistry: ts.DocumentRegistry,
|
||||
hasExplicitListOfFiles: boolean,
|
||||
compilerOptions: CompilerOptions,
|
||||
private wildcardDirectories: Map<WatchDirectoryFlags>,
|
||||
languageServiceEnabled: boolean,
|
||||
public compileOnSaveEnabled: boolean) {
|
||||
super(configFileName, ProjectKind.Configured, projectService, documentRegistry, hasExplicitListOfFiles, languageServiceEnabled, compilerOptions, compileOnSaveEnabled);
|
||||
@ -1098,7 +1098,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
watchConfigFile(callback: (project: ConfiguredProject, eventKind: FileWatcherEventKind) => void) {
|
||||
this.projectFileWatcher = this.projectService.host.watchFile(this.getConfigFilePath(), (_fileName, eventKind) => callback(this, eventKind));
|
||||
this.configFileWatcher = this.projectService.host.watchFile(this.getConfigFilePath(), (_fileName, eventKind) => callback(this, eventKind));
|
||||
}
|
||||
|
||||
watchTypeRoots(callback: (project: ConfiguredProject, path: string) => void) {
|
||||
@ -1111,49 +1111,70 @@ namespace ts.server {
|
||||
this.typeRootsWatchers = watchers;
|
||||
}
|
||||
|
||||
watchConfigDirectory(callback: (project: ConfiguredProject, path: string) => void) {
|
||||
if (this.directoryWatcher) {
|
||||
return;
|
||||
}
|
||||
|
||||
const directoryToWatch = getDirectoryPath(this.getConfigFilePath());
|
||||
this.projectService.logger.info(`Add recursive watcher for: ${directoryToWatch}`);
|
||||
this.directoryWatcher = this.projectService.host.watchDirectory(directoryToWatch, path => callback(this, path), /*recursive*/ true);
|
||||
}
|
||||
|
||||
watchWildcards(callback: (project: ConfiguredProject, path: string) => void) {
|
||||
if (!this.wildcardDirectories) {
|
||||
return;
|
||||
}
|
||||
const configDirectoryPath = getDirectoryPath(this.getConfigFilePath());
|
||||
|
||||
this.directoriesWatchedForWildcards = createMap<FileWatcher>();
|
||||
this.wildcardDirectories.forEach((flag, directory) => {
|
||||
if (comparePaths(configDirectoryPath, directory, ".", !this.projectService.host.useCaseSensitiveFileNames) !== Comparison.EqualTo) {
|
||||
const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0;
|
||||
this.projectService.logger.info(`Add ${recursive ? "recursive " : ""}watcher for: ${directory}`);
|
||||
this.directoriesWatchedForWildcards.set(directory, this.projectService.host.watchDirectory(
|
||||
private addWatcherForDirectory(flag: WatchDirectoryFlags, directory: string, replaceExisting: boolean) {
|
||||
if (replaceExisting || !this.directoriesWatchedForWildcards.has(directory)) {
|
||||
const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0;
|
||||
this.projectService.logger.info(`Add ${recursive ? "recursive " : ""} watcher for: ${directory}`);
|
||||
this.directoriesWatchedForWildcards.set(directory, {
|
||||
watcher: this.projectService.host.watchDirectory(
|
||||
directory,
|
||||
path => callback(this, path),
|
||||
path => this.projectService.onFileAddOrRemoveInWatchedDirectoryOfProject(this, path),
|
||||
recursive
|
||||
));
|
||||
}
|
||||
});
|
||||
),
|
||||
recursive
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
stopWatchingDirectory() {
|
||||
if (this.directoryWatcher) {
|
||||
this.directoryWatcher.close();
|
||||
this.directoryWatcher = undefined;
|
||||
watchWildcards(wildcardDirectories: Map<WatchDirectoryFlags>) {
|
||||
if (wildcardDirectories) {
|
||||
if (this.directoriesWatchedForWildcards) {
|
||||
this.directoriesWatchedForWildcards.forEach(({ watcher, recursive }, directory) => {
|
||||
const currentFlag = wildcardDirectories.get(directory);
|
||||
// Remove already watching wild card if it isnt in updated map
|
||||
if (currentFlag === undefined) {
|
||||
this.projectService.logger.info(`Removing ${recursive ? "recursive " : ""} watcher for: ${directory}`);
|
||||
watcher.close();
|
||||
this.directoriesWatchedForWildcards.delete(directory);
|
||||
}
|
||||
// Or if the recursive doesnt match (add the updated one here)
|
||||
else {
|
||||
const currentRecursive = (currentFlag & WatchDirectoryFlags.Recursive) !== 0;
|
||||
if (currentRecursive !== recursive) {
|
||||
this.projectService.logger.info(`Removing ${recursive ? "recursive " : ""} watcher for: ${directory}`);
|
||||
watcher.close();
|
||||
this.addWatcherForDirectory(currentFlag, directory, /*replaceExisting*/ true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.directoriesWatchedForWildcards = createMap<WildCardDirectoryWatchers>();
|
||||
}
|
||||
wildcardDirectories.forEach((flag, directory) =>
|
||||
this.addWatcherForDirectory(flag, directory, /*replaceExisting*/ false));
|
||||
}
|
||||
else {
|
||||
this.stopWatchingWildCards();
|
||||
}
|
||||
}
|
||||
|
||||
stopWatchingWildCards() {
|
||||
if (this.directoriesWatchedForWildcards) {
|
||||
this.directoriesWatchedForWildcards.forEach(({ watcher, recursive }, directory) => {
|
||||
this.projectService.logger.info(`Removing ${recursive ? "recursive " : ""} watcher for: ${directory}`);
|
||||
watcher.close();
|
||||
});
|
||||
this.directoriesWatchedForWildcards = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
super.close();
|
||||
|
||||
if (this.projectFileWatcher) {
|
||||
this.projectFileWatcher.close();
|
||||
this.projectFileWatcher = undefined;
|
||||
if (this.configFileWatcher) {
|
||||
this.configFileWatcher.close();
|
||||
this.configFileWatcher = undefined;
|
||||
}
|
||||
|
||||
if (this.typeRootsWatchers) {
|
||||
@ -1163,12 +1184,7 @@ namespace ts.server {
|
||||
this.typeRootsWatchers = undefined;
|
||||
}
|
||||
|
||||
this.directoriesWatchedForWildcards.forEach(watcher => {
|
||||
watcher.close();
|
||||
});
|
||||
this.directoriesWatchedForWildcards = undefined;
|
||||
|
||||
this.stopWatchingDirectory();
|
||||
this.stopWatchingWildCards();
|
||||
}
|
||||
|
||||
addOpenRef() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user