Skip to content

Commit

Permalink
Share extended config watchers across projects in server
Browse files Browse the repository at this point in the history
New shared watcher map in ProjectService that stores callbacks per
project to be invoked when the file watcher is triggered. The
FileWatcher is created with the watch options of the first Project to
watch the extended config.
  • Loading branch information
molisani committed Nov 14, 2020
1 parent 60aa8b1 commit 588bee3
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/compiler/watchPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,7 @@ namespace ts {
}

function watchExtendedConfigFiles() {
const configFile = builderProgram.getCompilerOptions().configFile;
const { configFile } = builderProgram.getCompilerOptions();
if (configFile) {
updateExtendedConfigFilesWatch(
configFile,
Expand Down
58 changes: 58 additions & 0 deletions src/compiler/watchUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,64 @@ namespace ts {
);
}

export interface SharedExtendedConfigFileWatcher<P> {
watcher: FileWatcher;
callbacks: ESMap<P, FileWatcherCallback>;
}

export function updateSharedExtendedConfigFilesWatch<P>(
project: P,
configFile: TsConfigSourceFile,
sharedExtendedConfigFilesMap: ESMap<string, SharedExtendedConfigFileWatcher<P>>,
watchExtendedConfigFile: (extendedConfigPath: string, callback: FileWatcherCallback) => FileWatcher,
projectCallback: FileWatcherCallback
) {
const extendedSourceFiles = configFile.extendedSourceFiles || emptyArray;
const newSharedExtendedConfigFilesMap = arrayToMap(extendedSourceFiles, identity, returnTrue);

sharedExtendedConfigFilesMap.forEach((existingWatcher, key) => {
if (newSharedExtendedConfigFilesMap.has(key)) {
existingWatcher.callbacks.set(project, projectCallback);
}
else {
existingWatcher.callbacks.delete(project);
if (existingWatcher.callbacks.size === 0) {
sharedExtendedConfigFilesMap.delete(key);
closeFileWatcherOf(existingWatcher);
}
}
});

newSharedExtendedConfigFilesMap.forEach((_true, extendedConfigPath) => {
if (!sharedExtendedConfigFilesMap.has(extendedConfigPath)) {
const newWatcher = createSharedExtendedConfigFileWatcher(extendedConfigPath);
sharedExtendedConfigFilesMap.set(extendedConfigPath, newWatcher);
}
});

function createSharedExtendedConfigFileWatcher(extendedConfigPath: string) {
const callbacks = new Map<P, FileWatcherCallback>();
callbacks.set(project, projectCallback);
const watcher = watchExtendedConfigFile(extendedConfigPath, (...args) => {
callbacks.forEach((callback) => callback(...args));
});
return { watcher, callbacks };
}
}

export function removeProjectFromSharedExtendedConfigFilesWatch<P>(
project: P,
sharedExtendedConfigFilesMap: ESMap<string, SharedExtendedConfigFileWatcher<P>>
) {
sharedExtendedConfigFilesMap.forEach((existingWatcher, key) => {
existingWatcher.callbacks.delete(project);
if (existingWatcher.callbacks.size === 0) {
sharedExtendedConfigFilesMap.delete(key);
closeFileWatcherOf(existingWatcher);
}
});
}

/**
* Updates the existing missing file watches with the new set of missing files after new program is created
*/
Expand Down
8 changes: 6 additions & 2 deletions src/server/editorServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,9 @@ namespace ts.server {
/*@internal*/
readonly watchFactory: WatchFactory<WatchType, Project>;

/*@internal*/
private sharedExtendedConfigFilesMap = new Map<string, SharedExtendedConfigFileWatcher<Project>>();

/*@internal*/
readonly packageJsonCache: PackageJsonCache;
/*@internal*/
Expand Down Expand Up @@ -1384,6 +1387,7 @@ namespace ts.server {
project.print(/*writeProjectFileNames*/ true);

project.close();
removeProjectFromSharedExtendedConfigFilesWatch(project, this.sharedExtendedConfigFilesMap);
if (Debug.shouldAssert(AssertionLevel.Normal)) {
this.filenameToScriptInfo.forEach(info => Debug.assert(
!info.isAttached(project),
Expand Down Expand Up @@ -2156,14 +2160,14 @@ namespace ts.server {
const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(project.canonicalConfigFilePath, compilerOptions, parsedCommandLine.fileNames, fileNamePropertyReader);
if (lastFileExceededProgramSize) {
project.disableLanguageService(lastFileExceededProgramSize);
project.stopWatchingExtendedConfigFiles();
removeProjectFromSharedExtendedConfigFilesWatch(project, this.sharedExtendedConfigFilesMap);
project.stopWatchingWildCards();
}
else {
project.setCompilerOptions(compilerOptions);
project.setWatchOptions(parsedCommandLine.watchOptions);
project.enableLanguageService();
project.watchExtendedConfigFiles();
project.watchExtendedConfigFiles(this.sharedExtendedConfigFilesMap);
project.watchWildcards(new Map(getEntries(parsedCommandLine.wildcardDirectories!))); // TODO: GH#18217
}
project.enablePluginsWithOptions(compilerOptions, this.currentPluginConfigOverrides);
Expand Down
27 changes: 9 additions & 18 deletions src/server/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2046,8 +2046,6 @@ namespace ts.server {
export class ConfiguredProject extends Project {
/* @internal */
configFileWatcher: FileWatcher | undefined;
/* @internal */
private extendedConfigFileWatchers: ESMap<string, FileWatcher> | undefined;
private directoriesWatchedForWildcards: ESMap<string, WildcardDirectoryWatcher> | undefined;
readonly canonicalConfigFilePath: NormalizedPath;

Expand Down Expand Up @@ -2262,10 +2260,10 @@ namespace ts.server {
}

/* @internal */
createExtendedConfigFileWatcher(extendedConfigFile: string): FileWatcher {
createExtendedConfigFileWatcher(extendedConfigFile: string, callback: FileWatcherCallback): FileWatcher {
return this.projectService.watchFactory.watchFile(
extendedConfigFile,
(fileName) => this.projectService.onExtendedConfigChangedForConfiguredProject(this, fileName),
callback,
PollingInterval.High,
this.projectService.getWatchOptions(this),
WatchType.ExtendedConfigFile,
Expand All @@ -2274,25 +2272,19 @@ namespace ts.server {
}

/* @internal */
watchExtendedConfigFiles() {
const configFile = this.getCompilerOptions().configFile;
watchExtendedConfigFiles(sharedExtendedConfigFilesMap: ESMap<string, SharedExtendedConfigFileWatcher<Project>>) {
const { configFile } = this.getCompilerOptions();
if (configFile) {
updateExtendedConfigFilesWatch(
updateSharedExtendedConfigFilesWatch(
this,
configFile,
this.extendedConfigFileWatchers || (this.extendedConfigFileWatchers = new Map()),
(extendedConfigFile) => this.createExtendedConfigFileWatcher(extendedConfigFile),
sharedExtendedConfigFilesMap,
(extendedConfigFile, callback) => this.createExtendedConfigFileWatcher(extendedConfigFile, callback),
(fileName) => this.projectService.onExtendedConfigChangedForConfiguredProject(this, fileName),
);
}
}

/* @internal */
stopWatchingExtendedConfigFiles() {
if (this.extendedConfigFileWatchers) {
clearMap(this.extendedConfigFileWatchers, closeFileWatcher);
this.extendedConfigFileWatchers = undefined;
}
}

/*@internal*/
watchWildcards(wildcardDirectories: ESMap<string, WatchDirectoryFlags>) {
updateWatchingWildcardDirectories(
Expand All @@ -2317,7 +2309,6 @@ namespace ts.server {
this.configFileWatcher = undefined;
}

this.stopWatchingExtendedConfigFiles();
this.stopWatchingWildCards();
this.configFileSpecs = undefined;
this.openFileWatchTriggered.clear();
Expand Down

0 comments on commit 588bee3

Please sign in to comment.