Skip to content

Commit 02b8a7d

Browse files
committed
More work on PR feedback
1 parent 27988bf commit 02b8a7d

5 files changed

Lines changed: 144 additions & 145 deletions

File tree

src/compiler/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3688,7 +3688,13 @@ namespace ts {
36883688

36893689
export interface ConfigFileSpecs {
36903690
filesSpecs: ReadonlyArray<string>;
3691+
/**
3692+
* Present to report errors (user specified specs), validatedIncludeSpecs are used for file name matching
3693+
*/
36913694
includeSpecs: ReadonlyArray<string>;
3695+
/**
3696+
* Present to report errors (user specified specs), validatedExcludeSpecs are used for file name matching
3697+
*/
36923698
excludeSpecs: ReadonlyArray<string>;
36933699
validatedIncludeSpecs: ReadonlyArray<string>;
36943700
validatedExcludeSpecs: ReadonlyArray<string>;

src/compiler/utilities.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3607,6 +3607,10 @@ namespace ts {
36073607
export function getCombinedLocalAndExportSymbolFlags(symbol: Symbol): SymbolFlags {
36083608
return symbol.exportSymbol ? symbol.exportSymbol.flags | symbol.flags : symbol.flags;
36093609
}
3610+
3611+
export function isRecursiveDirectoryWatch(flags: WatchDirectoryFlags) {
3612+
return (flags & WatchDirectoryFlags.Recursive) !== 0;
3613+
}
36103614
}
36113615

36123616
namespace ts {

src/server/editorServices.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ namespace ts.server {
280280
/* @internal */
281281
export type ServerDirectoryWatcherCallback = (path: NormalizedPath) => void;
282282

283-
type ConfigFileExistence = {
283+
interface ConfigFileExistence {
284284
/**
285285
* Cached value of existence of config file
286286
* It is true if there is configured project open for this file.
@@ -302,7 +302,7 @@ namespace ts.server {
302302
* The watcher is present only when there is no open configured project for this config file
303303
*/
304304
configFileWatcher?: FileWatcher;
305-
};
305+
}
306306

307307
export interface ProjectServiceOptions {
308308
host: ServerHost;
@@ -1606,13 +1606,15 @@ namespace ts.server {
16061606
}
16071607

16081608
/* @internal */
1609-
closeDirectoryWatcher(watchType: WatchType, project: Project, directory: string, watcher: FileWatcher, recursive: boolean, reason: WatcherCloseReason) {
1609+
closeDirectoryWatcher(watchType: WatchType, project: Project, directory: string, watcher: FileWatcher, flags: WatchDirectoryFlags, reason: WatcherCloseReason) {
1610+
const recursive = isRecursiveDirectoryWatch(flags);
16101611
this.logger.info(`DirectoryWatcher ${recursive ? "recursive" : ""}:: Close: ${directory} Project: ${project.getProjectName()} WatchType: ${watchType} Reason: ${reason}`);
16111612
watcher.close();
16121613
}
16131614

16141615
/* @internal */
1615-
addDirectoryWatcher(watchType: WatchType, project: Project, directory: string, cb: ServerDirectoryWatcherCallback, recursive: boolean) {
1616+
addDirectoryWatcher(watchType: WatchType, project: Project, directory: string, cb: ServerDirectoryWatcherCallback, flags: WatchDirectoryFlags) {
1617+
const recursive = isRecursiveDirectoryWatch(flags);
16161618
this.logger.info(`DirectoryWatcher ${recursive ? "recursive" : ""}:: Added: ${directory} Project: ${project.getProjectName()} WatchType: ${watchType}`);
16171619
return this.host.watchDirectory(directory, fileName => {
16181620
const path = toNormalizedPath(getNormalizedAbsolutePath(fileName, directory));

src/server/project.ts

Lines changed: 94 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -327,10 +327,12 @@ namespace ts.server {
327327
this.lsHost = undefined;
328328

329329
// Clean up file watchers waiting for missing files
330-
cleanExistingMap(this.missingFilesMap, (missingFilePath, fileWatcher) => {
331-
this.projectService.closeFileWatcher(WatchType.MissingFilePath, this, missingFilePath, fileWatcher, WatcherCloseReason.ProjectClose);
332-
});
333-
this.missingFilesMap = undefined;
330+
if (this.missingFilesMap) {
331+
clearMap(this.missingFilesMap, (missingFilePath, fileWatcher) => {
332+
this.projectService.closeFileWatcher(WatchType.MissingFilePath, this, missingFilePath, fileWatcher, WatcherCloseReason.ProjectClose);
333+
});
334+
this.missingFilesMap = undefined;
335+
}
334336

335337
// signal language service to release source files acquired from document registry
336338
this.languageService.dispose();
@@ -642,34 +644,37 @@ namespace ts.server {
642644
const missingFilePaths = this.program.getMissingFilePaths();
643645
const newMissingFilePathMap = arrayToSet(missingFilePaths);
644646
// Update the missing file paths watcher
645-
this.missingFilesMap = mutateExistingMapWithNewSet(
646-
this.missingFilesMap, newMissingFilePathMap,
647-
// Watch the missing files
648-
missingFilePath => {
649-
const fileWatcher = this.projectService.addFileWatcher(
650-
WatchType.MissingFilePath, this, missingFilePath,
651-
(filename, eventKind) => {
652-
if (eventKind === FileWatcherEventKind.Created && this.missingFilesMap.has(missingFilePath)) {
653-
this.missingFilesMap.delete(missingFilePath);
654-
this.projectService.closeFileWatcher(WatchType.MissingFilePath, this, missingFilePath, fileWatcher, WatcherCloseReason.FileCreated);
655-
656-
if (this.projectKind === ProjectKind.Configured) {
657-
const absoluteNormalizedPath = getNormalizedAbsolutePath(filename, getDirectoryPath(missingFilePath));
658-
(this.lsHost.host as CachedServerHost).addOrDeleteFileOrFolder(toNormalizedPath(absoluteNormalizedPath));
647+
mutateMap(
648+
this.missingFilesMap || (this.missingFilesMap = createMap()),
649+
newMissingFilePathMap,
650+
{
651+
// Watch the missing files
652+
createNewValue: missingFilePath => {
653+
const fileWatcher = this.projectService.addFileWatcher(
654+
WatchType.MissingFilePath, this, missingFilePath,
655+
(filename, eventKind) => {
656+
if (eventKind === FileWatcherEventKind.Created && this.missingFilesMap.has(missingFilePath)) {
657+
this.missingFilesMap.delete(missingFilePath);
658+
this.projectService.closeFileWatcher(WatchType.MissingFilePath, this, missingFilePath, fileWatcher, WatcherCloseReason.FileCreated);
659+
660+
if (this.projectKind === ProjectKind.Configured) {
661+
const absoluteNormalizedPath = getNormalizedAbsolutePath(filename, getDirectoryPath(missingFilePath));
662+
(this.lsHost.host as CachedServerHost).addOrDeleteFileOrFolder(toNormalizedPath(absoluteNormalizedPath));
663+
}
664+
665+
// When a missing file is created, we should update the graph.
666+
this.markAsDirty();
667+
this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this);
659668
}
660-
661-
// When a missing file is created, we should update the graph.
662-
this.markAsDirty();
663-
this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this);
664669
}
665-
}
666-
);
667-
return fileWatcher;
668-
},
669-
// Files that are no longer missing (e.g. because they are no longer required)
670-
// should no longer be watched.
671-
(missingFilePath, fileWatcher) => {
672-
this.projectService.closeFileWatcher(WatchType.MissingFilePath, this, missingFilePath, fileWatcher, WatcherCloseReason.NotNeeded);
670+
);
671+
return fileWatcher;
672+
},
673+
// Files that are no longer missing (e.g. because they are no longer required)
674+
// should no longer be watched.
675+
onDeleteExistingValue: (missingFilePath, fileWatcher) => {
676+
this.projectService.closeFileWatcher(WatchType.MissingFilePath, this, missingFilePath, fileWatcher, WatcherCloseReason.NotNeeded);
677+
}
673678
}
674679
);
675680
}
@@ -970,7 +975,10 @@ namespace ts.server {
970975
}
971976
}
972977

973-
type WildCardDirectoryWatchers = { watcher: FileWatcher, recursive: boolean };
978+
interface WildcardDirectoryWatcher {
979+
watcher: FileWatcher;
980+
flags: WatchDirectoryFlags;
981+
}
974982

975983
/**
976984
* If a file is opened, the server will look for a tsconfig (or jsconfig)
@@ -981,7 +989,7 @@ namespace ts.server {
981989
private typeAcquisition: TypeAcquisition;
982990
/* @internal */
983991
configFileWatcher: FileWatcher;
984-
private directoriesWatchedForWildcards: Map<WildCardDirectoryWatchers> | undefined;
992+
private directoriesWatchedForWildcards: Map<WildcardDirectoryWatcher> | undefined;
985993
private typeRootsWatchers: Map<FileWatcher> | undefined;
986994
readonly canonicalConfigFilePath: NormalizedPath;
987995

@@ -1136,70 +1144,72 @@ namespace ts.server {
11361144
}
11371145

11381146
watchWildcards(wildcardDirectories: Map<WatchDirectoryFlags>) {
1139-
this.directoriesWatchedForWildcards = mutateExistingMap(
1140-
this.directoriesWatchedForWildcards, wildcardDirectories,
1141-
// Watcher is same if the recursive flags match
1142-
({ recursive: existingRecursive }, flag) => {
1143-
// If the recursive dont match, it needs update
1144-
const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0;
1145-
return existingRecursive !== recursive;
1146-
},
1147-
// Create new watch and recursive info
1148-
(directory, flag) => {
1149-
const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0;
1150-
return {
1151-
watcher: this.projectService.addDirectoryWatcher(
1152-
WatchType.WildCardDirectories, this, directory,
1153-
path => this.projectService.onFileAddOrRemoveInWatchedDirectoryOfProject(this, path),
1154-
recursive
1155-
),
1156-
recursive
1157-
};
1158-
},
1159-
// Close existing watch thats not needed any more
1160-
(directory, { watcher, recursive }) => this.projectService.closeDirectoryWatcher(
1161-
WatchType.WildCardDirectories, this, directory, watcher, recursive, WatcherCloseReason.NotNeeded
1162-
),
1163-
// Close existing watch that doesnt match in recursive flag
1164-
(directory, { watcher, recursive }) => this.projectService.closeDirectoryWatcher(
1165-
WatchType.WildCardDirectories, this, directory, watcher, recursive, WatcherCloseReason.RecursiveChanged
1166-
)
1147+
mutateMap(
1148+
this.directoriesWatchedForWildcards || (this.directoriesWatchedForWildcards = createMap()),
1149+
wildcardDirectories,
1150+
{
1151+
// Watcher is same if the recursive flags match
1152+
isSameValue: ({ flags: existingFlags }, flags) => existingFlags !== flags,
1153+
// Create new watch and recursive info
1154+
createNewValue: (directory, flags) => {
1155+
return {
1156+
watcher: this.projectService.addDirectoryWatcher(
1157+
WatchType.WildCardDirectories, this, directory,
1158+
path => this.projectService.onFileAddOrRemoveInWatchedDirectoryOfProject(this, path),
1159+
flags
1160+
),
1161+
flags
1162+
};
1163+
},
1164+
// Close existing watch thats not needed any more or doesnt match recursive flags
1165+
onDeleteExistingValue: (directory, wildcardDirectoryWatcher, isNotSame) =>
1166+
this.closeWildcardDirectoryWatcher(directory, wildcardDirectoryWatcher, isNotSame ? WatcherCloseReason.RecursiveChanged : WatcherCloseReason.NotNeeded),
1167+
}
11671168
);
11681169
}
11691170

1171+
private closeWildcardDirectoryWatcher(directory: string, { watcher, flags }: WildcardDirectoryWatcher, closeReason: WatcherCloseReason) {
1172+
this.projectService.closeDirectoryWatcher(WatchType.WildCardDirectories, this, directory, watcher, flags, closeReason);
1173+
}
1174+
11701175
stopWatchingWildCards(reason: WatcherCloseReason) {
1171-
cleanExistingMap(
1172-
this.directoriesWatchedForWildcards,
1173-
(directory, { watcher, recursive }) =>
1174-
this.projectService.closeDirectoryWatcher(WatchType.WildCardDirectories, this,
1175-
directory, watcher, recursive, reason)
1176-
);
1177-
this.directoriesWatchedForWildcards = undefined;
1176+
if (this.directoriesWatchedForWildcards) {
1177+
clearMap(
1178+
this.directoriesWatchedForWildcards,
1179+
(directory, wildcardDirectoryWatcher) => this.closeWildcardDirectoryWatcher(directory, wildcardDirectoryWatcher, reason)
1180+
);
1181+
this.directoriesWatchedForWildcards = undefined;
1182+
}
11781183
}
11791184

11801185
watchTypeRoots() {
11811186
const newTypeRoots = arrayToSet(this.getEffectiveTypeRoots(), dir => this.projectService.toCanonicalFileName(dir));
1182-
this.typeRootsWatchers = mutateExistingMapWithNewSet(
1183-
this.typeRootsWatchers, newTypeRoots,
1184-
// Create new watch
1185-
root => this.projectService.addDirectoryWatcher(WatchType.TypeRoot, this, root,
1186-
path => this.projectService.onTypeRootFileChanged(this, path), /*recursive*/ false
1187-
),
1188-
// Close existing watch thats not needed any more
1189-
(directory, watcher) => this.projectService.closeDirectoryWatcher(
1190-
WatchType.TypeRoot, this, directory, watcher, /*recursive*/ false, WatcherCloseReason.NotNeeded
1191-
)
1187+
mutateMap(
1188+
this.typeRootsWatchers || (this.typeRootsWatchers = createMap()),
1189+
newTypeRoots,
1190+
{
1191+
// Create new watch
1192+
createNewValue: root => this.projectService.addDirectoryWatcher(WatchType.TypeRoot, this, root,
1193+
path => this.projectService.onTypeRootFileChanged(this, path), WatchDirectoryFlags.None
1194+
),
1195+
// Close existing watch thats not needed any more
1196+
onDeleteExistingValue: (directory, watcher) => this.projectService.closeDirectoryWatcher(
1197+
WatchType.TypeRoot, this, directory, watcher, WatchDirectoryFlags.None, WatcherCloseReason.NotNeeded
1198+
)
1199+
}
11921200
);
11931201
}
11941202

11951203
stopWatchingTypeRoots(reason: WatcherCloseReason) {
1196-
cleanExistingMap(
1197-
this.typeRootsWatchers,
1198-
(directory, watcher) =>
1199-
this.projectService.closeDirectoryWatcher(WatchType.TypeRoot, this,
1200-
directory, watcher, /*recursive*/ false, reason)
1201-
);
1202-
this.typeRootsWatchers = undefined;
1204+
if (this.typeRootsWatchers) {
1205+
clearMap(
1206+
this.typeRootsWatchers,
1207+
(directory, watcher) =>
1208+
this.projectService.closeDirectoryWatcher(WatchType.TypeRoot, this,
1209+
directory, watcher, WatchDirectoryFlags.None, reason)
1210+
);
1211+
this.typeRootsWatchers = undefined;
1212+
}
12031213
}
12041214

12051215
close() {

0 commit comments

Comments
 (0)