Merge pull request #16684 from amcasey/Vsts434619

Watch for the creation of missing files
This commit is contained in:
Andrew Casey
2017-06-29 13:41:18 -07:00
committed by GitHub
18 changed files with 287 additions and 47 deletions

View File

@@ -210,8 +210,11 @@ namespace ts.server {
return this.host.resolvePath(path);
}
fileExists(path: string): boolean {
return this.host.fileExists(path);
fileExists(file: string): boolean {
// As an optimization, don't hit the disks for files we already know don't exist
// (because we're watching for their creation).
const path = toPath(file, this.host.getCurrentDirectory(), this.getCanonicalFileName);
return !this.project.isWatchedMissingFile(path) && this.host.fileExists(file);
}
readFile(fileName: string): string {

View File

@@ -107,6 +107,7 @@ namespace ts.server {
private rootFilesMap: Map<ScriptInfo> = createMap<ScriptInfo>();
private program: ts.Program;
private externalFiles: SortedReadonlyArray<string>;
private missingFilesMap: Map<FileWatcher> = createMap<FileWatcher>();
private cachedUnresolvedImportsPerFile = new UnresolvedImportsMap();
private lastCachedUnresolvedImportsList: SortedReadonlyArray<string>;
@@ -310,6 +311,10 @@ namespace ts.server {
this.lsHost.dispose();
this.lsHost = undefined;
// Clean up file watchers waiting for missing files
this.missingFilesMap.forEach(fileWatcher => fileWatcher.close());
this.missingFilesMap = undefined;
// signal language service to release source files acquired from document registry
this.languageService.dispose();
this.languageService = undefined;
@@ -586,12 +591,12 @@ namespace ts.server {
const oldProgram = this.program;
this.program = this.languageService.getProgram();
let hasChanges = false;
// bump up the version if
// - oldProgram is not set - this is a first time updateGraph is called
// - newProgram is different from the old program and structure of the old program was not reused.
if (!oldProgram || (this.program !== oldProgram && !(oldProgram.structureIsReused & StructureIsReused.Completely))) {
hasChanges = true;
const hasChanges = !oldProgram || (this.program !== oldProgram && !(oldProgram.structureIsReused & StructureIsReused.Completely));
if (hasChanges) {
if (oldProgram) {
for (const f of oldProgram.getSourceFiles()) {
if (this.program.getSourceFileByPath(f.path)) {
@@ -604,6 +609,35 @@ namespace ts.server {
}
}
}
const missingFilePaths = this.program.getMissingFilePaths();
const missingFilePathsSet = arrayToSet(missingFilePaths, p => p);
// Files that are no longer missing (e.g. because they are no longer required)
// should no longer be watched.
this.missingFilesMap.forEach((fileWatcher, missingFilePath) => {
if (!missingFilePathsSet.has(missingFilePath)) {
this.missingFilesMap.delete(missingFilePath);
fileWatcher.close();
}
});
// Missing files that are not yet watched should be added to the map.
for (const missingFilePath of missingFilePaths) {
if (!this.missingFilesMap.has(missingFilePath)) {
const fileWatcher = this.projectService.host.watchFile(missingFilePath, (_filename: string, eventKind: FileWatcherEventKind) => {
if (eventKind === FileWatcherEventKind.Created && this.missingFilesMap.has(missingFilePath)) {
fileWatcher.close();
this.missingFilesMap.delete(missingFilePath);
// When a missing file is created, we should update the graph.
this.markAsDirty();
this.updateGraph();
}
});
this.missingFilesMap.set(missingFilePath, fileWatcher);
}
}
}
const oldExternalFiles = this.externalFiles || emptyArray as SortedReadonlyArray<string>;
@@ -626,6 +660,10 @@ namespace ts.server {
return hasChanges;
}
isWatchedMissingFile(path: Path) {
return this.missingFilesMap.has(path);
}
getScriptInfoLSHost(fileName: string) {
const scriptInfo = this.projectService.getOrCreateScriptInfo(fileName, /*openedByClient*/ false);
if (scriptInfo) {

View File

@@ -523,11 +523,14 @@ namespace ts.server {
fs.stat(watchedFile.fileName, (err: any, stats: any) => {
if (err) {
watchedFile.callback(watchedFile.fileName);
watchedFile.callback(watchedFile.fileName, FileWatcherEventKind.Changed);
}
else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) {
watchedFile.mtime = stats.mtime;
watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0);
const eventKind = watchedFile.mtime.getTime() === 0
? FileWatcherEventKind.Deleted
: FileWatcherEventKind.Changed;
watchedFile.callback(watchedFile.fileName, eventKind);
}
});
}
@@ -559,7 +562,9 @@ namespace ts.server {
const file: WatchedFile = {
fileName,
callback,
mtime: getModifiedTime(fileName)
mtime: sys.fileExists(fileName)
? getModifiedTime(fileName)
: new Date(0) // Any subsequent modification will occur after this time
};
watchedFiles.push(file);