diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 751177c4ef8..1eab3582cb9 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2631,12 +2631,16 @@ namespace ts { useCaseSensitiveFileNames: boolean; } - export interface CachedHost extends PartialSystem { - addOrDeleteFileOrFolder(fileOrFolder: string): void; + export interface CachedHost { + addOrDeleteFileOrFolder(fileOrFolder: string, fileOrFolderPath: Path): void; + addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind): void; clearCache(): void; } - export function createCachedHost(host: HostForCaching): CachedHost { + export interface CachedPartialSystem extends PartialSystem, CachedHost { + } + + export function createCachedPartialSystem(host: HostForCaching): CachedPartialSystem { const cachedReadDirectoryResult = createMap(); const getCurrentDirectory = memoize(() => host.getCurrentDirectory()); const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames); @@ -2649,6 +2653,7 @@ namespace ts { getDirectories, readDirectory, addOrDeleteFileOrFolder, + addOrDeleteFile, clearCache }; @@ -2656,33 +2661,46 @@ namespace ts { return ts.toPath(fileName, getCurrentDirectory(), getCanonicalFileName); } - function getFileSystemEntries(rootDir: string) { - const path = toPath(rootDir); - const cachedResult = cachedReadDirectoryResult.get(path); - if (cachedResult) { - return cachedResult; - } + function getCachedFileSystemEntries(rootDirPath: Path): FileSystemEntries | undefined { + return cachedReadDirectoryResult.get(rootDirPath); + } + function getCachedFileSystemEntriesForBaseDir(path: Path): FileSystemEntries | undefined { + return getCachedFileSystemEntries(getDirectoryPath(path)); + } + + function getBaseNameOfFileName(fileName: string) { + return getBaseFileName(normalizePath(fileName)); + } + + function createCachedFileSystemEntries(rootDir: string, rootDirPath: Path) { const resultFromHost: FileSystemEntries = { files: host.readDirectory(rootDir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/["*.*"]) || [], directories: host.getDirectories(rootDir) || [] }; - cachedReadDirectoryResult.set(path, resultFromHost); + cachedReadDirectoryResult.set(rootDirPath, resultFromHost); return resultFromHost; } - function canWorkWithCacheForDir(rootDir: string) { - // Some of the hosts might not be able to handle read directory or getDirectories - const path = toPath(rootDir); - if (cachedReadDirectoryResult.get(path)) { - return true; + /** + * If the readDirectory result was already cached, it returns that + * Otherwise gets result from host and caches it. + * The host request is done under try catch block to avoid caching incorrect result + */ + function tryReadDirectory(rootDir: string, rootDirPath: Path): FileSystemEntries | undefined { + const cachedResult = getCachedFileSystemEntries(rootDirPath); + if (cachedResult) { + return cachedResult; } + try { - return getFileSystemEntries(rootDir); + return createCachedFileSystemEntries(rootDir, rootDirPath); } catch (_e) { - return false; + // If there is exception to read directories, dont cache the result and direct the calls to host + Debug.assert(!cachedReadDirectoryResult.has(rootDirPath)); + return undefined; } } @@ -2708,19 +2726,18 @@ namespace ts { function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void { const path = toPath(fileName); - const result = cachedReadDirectoryResult.get(getDirectoryPath(path)); - const baseFileName = getBaseFileName(normalizePath(fileName)); + const result = getCachedFileSystemEntriesForBaseDir(path); if (result) { - result.files = updateFileSystemEntry(result.files, baseFileName, /*isValid*/ true); + updateFilesOfFileSystemEntry(result, getBaseNameOfFileName(fileName), /*fileExists*/ true); } return host.writeFile(fileName, data, writeByteOrderMark); } function fileExists(fileName: string): boolean { const path = toPath(fileName); - const result = cachedReadDirectoryResult.get(getDirectoryPath(path)); - const baseName = getBaseFileName(normalizePath(fileName)); - return (result && hasEntry(result.files, baseName)) || host.fileExists(fileName); + const result = getCachedFileSystemEntriesForBaseDir(path); + return (result && hasEntry(result.files, getBaseNameOfFileName(fileName))) || + host.fileExists(fileName); } function directoryExists(dirPath: string): boolean { @@ -2730,8 +2747,8 @@ namespace ts { function createDirectory(dirPath: string) { const path = toPath(dirPath); - const result = cachedReadDirectoryResult.get(getDirectoryPath(path)); - const baseFileName = getBaseFileName(path); + const result = getCachedFileSystemEntriesForBaseDir(path); + const baseFileName = getBaseNameOfFileName(dirPath); if (result) { result.directories = updateFileSystemEntry(result.directories, baseFileName, /*isValid*/ true); } @@ -2739,41 +2756,68 @@ namespace ts { } function getDirectories(rootDir: string): string[] { - if (canWorkWithCacheForDir(rootDir)) { - return getFileSystemEntries(rootDir).directories.slice(); + const rootDirPath = toPath(rootDir); + const result = tryReadDirectory(rootDir, rootDirPath); + if (result) { + return result.directories.slice(); } return host.getDirectories(rootDir); } + function readDirectory(rootDir: string, extensions?: ReadonlyArray, excludes?: ReadonlyArray, includes?: ReadonlyArray, depth?: number): string[] { - if (canWorkWithCacheForDir(rootDir)) { - return matchFiles(rootDir, extensions, excludes, includes, host.useCaseSensitiveFileNames, getCurrentDirectory(), depth, path => getFileSystemEntries(path)); + const rootDirPath = toPath(rootDir); + const result = tryReadDirectory(rootDir, rootDirPath); + if (result) { + return matchFiles(rootDir, extensions, excludes, includes, host.useCaseSensitiveFileNames, getCurrentDirectory(), depth, getFileSystemEntries); } return host.readDirectory(rootDir, extensions, excludes, includes, depth); + + function getFileSystemEntries(dir: string) { + const path = toPath(dir); + if (path === rootDirPath) { + return result; + } + return getCachedFileSystemEntries(path) || createCachedFileSystemEntries(dir, path); + } } - function addOrDeleteFileOrFolder(fileOrFolder: string) { - const path = toPath(fileOrFolder); - const existingResult = cachedReadDirectoryResult.get(path); + function addOrDeleteFileOrFolder(fileOrFolder: string, fileOrFolderPath: Path) { + const existingResult = getCachedFileSystemEntries(fileOrFolderPath); if (existingResult) { // This was a folder already present, remove it if this doesnt exist any more if (!host.directoryExists(fileOrFolder)) { - cachedReadDirectoryResult.delete(path); + cachedReadDirectoryResult.delete(fileOrFolderPath); } } else { // This was earlier a file (hence not in cached directory contents) // or we never cached the directory containing it - const parentResult = cachedReadDirectoryResult.get(getDirectoryPath(path)); + const parentResult = getCachedFileSystemEntriesForBaseDir(fileOrFolderPath); if (parentResult) { - const baseName = getBaseFileName(fileOrFolder); + const baseName = getBaseNameOfFileName(fileOrFolder); if (parentResult) { - parentResult.files = updateFileSystemEntry(parentResult.files, baseName, host.fileExists(path)); - parentResult.directories = updateFileSystemEntry(parentResult.directories, baseName, host.directoryExists(path)); + updateFilesOfFileSystemEntry(parentResult, baseName, host.fileExists(fileOrFolderPath)); + parentResult.directories = updateFileSystemEntry(parentResult.directories, baseName, host.directoryExists(fileOrFolderPath)); } } } } + function addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind) { + if (eventKind === FileWatcherEventKind.Changed) { + return; + } + + const parentResult = getCachedFileSystemEntriesForBaseDir(filePath); + if (parentResult) { + updateFilesOfFileSystemEntry(parentResult, getBaseNameOfFileName(fileName), eventKind === FileWatcherEventKind.Created); + } + } + + function updateFilesOfFileSystemEntry(parentResult: FileSystemEntries, baseName: string, fileExists: boolean) { + parentResult.files = updateFileSystemEntry(parentResult.files, baseName, fileExists); + } + function clearCache() { cachedReadDirectoryResult.clear(); } diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 615340e4872..0379289cc8e 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -40,7 +40,7 @@ namespace ts { export function createResolutionCache( toPath: (fileName: string) => Path, getCompilerOptions: () => CompilerOptions, - watchForFailedLookupLocation: (failedLookupLocation: string, containingFile: string, name: string) => FileWatcher, + watchForFailedLookupLocation: (failedLookupLocation: string, failedLookupLocationPath: Path, containingFile: string, name: string) => FileWatcher, log: (s: string) => void, resolveWithGlobalCache?: ResolverWithGlobalCache): ResolutionCache { @@ -201,7 +201,7 @@ namespace ts { } else { log(`Watcher: FailedLookupLocations: Status: new watch: Location: ${failedLookupLocation}, containingFile: ${containingFile}, name: ${name}`); - const fileWatcher = watchForFailedLookupLocation(failedLookupLocation, containingFile, name); + const fileWatcher = watchForFailedLookupLocation(failedLookupLocation, failedLookupLocationPath, containingFile, name); failedLookupLocationsWatches.set(failedLookupLocationPath, { fileWatcher, refCount: 1 }); } } diff --git a/src/compiler/watchedProgram.ts b/src/compiler/watchedProgram.ts index 5229e11ea97..e79049b983c 100644 --- a/src/compiler/watchedProgram.ts +++ b/src/compiler/watchedProgram.ts @@ -520,7 +520,7 @@ namespace ts { function onSourceFileChange(fileName: string, path: Path, eventKind: FileWatcherEventKind) { writeLog(`Source file path : ${path} changed: ${FileWatcherEventKind[eventKind]}, fileName: ${fileName}`); - updateCachedSystem(fileName, path); + updateCachedSystemWithFile(fileName, path, eventKind); const hostSourceFile = sourceFilesCache.get(path); if (hostSourceFile) { // Update the cache @@ -547,21 +547,19 @@ namespace ts { scheduleProgramUpdate(); } - function updateCachedSystem(fileName: string, path: Path) { + function updateCachedSystemWithFile(fileName: string, path: Path, eventKind: FileWatcherEventKind) { if (configFileName) { - const absoluteNormalizedPath = getNormalizedAbsolutePath(fileName, getDirectoryPath(path)); - (host as CachedSystem).addOrDeleteFileOrFolder(normalizePath(absoluteNormalizedPath)); + (host as CachedSystem).addOrDeleteFile(fileName, path, eventKind); } } - function watchFailedLookupLocation(failedLookupLocation: string, containingFile: string, name: string) { - return host.watchFile(failedLookupLocation, (fileName, eventKind) => onFailedLookupLocationChange(fileName, eventKind, failedLookupLocation, containingFile, name)); + function watchFailedLookupLocation(failedLookupLocation: string, failedLookupLocationPath: Path, containingFile: string, name: string) { + return host.watchFile(failedLookupLocation, (fileName, eventKind) => onFailedLookupLocationChange(fileName, eventKind, failedLookupLocation, failedLookupLocationPath, containingFile, name)); } - function onFailedLookupLocationChange(fileName: string, eventKind: FileWatcherEventKind, failedLookupLocation: string, containingFile: string, name: string) { + function onFailedLookupLocationChange(fileName: string, eventKind: FileWatcherEventKind, failedLookupLocation: string, failedLookupLocationPath: Path, containingFile: string, name: string) { writeLog(`Failed lookup location : ${failedLookupLocation} changed: ${FileWatcherEventKind[eventKind]}, fileName: ${fileName} containingFile: ${containingFile}, name: ${name}`); - const path = toPath(failedLookupLocation); - updateCachedSystem(failedLookupLocation, path); + updateCachedSystemWithFile(fileName, failedLookupLocationPath, eventKind); resolutionCache.invalidateResolutionOfChangedFailedLookupLocation(failedLookupLocation); scheduleProgramUpdate(); } @@ -574,14 +572,14 @@ namespace ts { fileWatcher.close(); } - function onMissingFileChange(filename: string, missingFilePath: Path, eventKind: FileWatcherEventKind) { - writeLog(`Missing file path : ${missingFilePath} changed: ${FileWatcherEventKind[eventKind]}, fileName: ${filename}`); + function onMissingFileChange(fileName: string, missingFilePath: Path, eventKind: FileWatcherEventKind) { + writeLog(`Missing file path : ${missingFilePath} changed: ${FileWatcherEventKind[eventKind]}, fileName: ${fileName}`); + updateCachedSystemWithFile(fileName, missingFilePath, eventKind); + if (eventKind === FileWatcherEventKind.Created && missingFilesMap.has(missingFilePath)) { closeMissingFilePathWatcher(missingFilePath, missingFilesMap.get(missingFilePath)); missingFilesMap.delete(missingFilePath); - updateCachedSystem(filename, missingFilePath); - // Delete the entry in the source files cache so that new source file is created removeSourceFile(missingFilePath); @@ -600,8 +598,8 @@ namespace ts { } function watchWildCardDirectory(directory: string, flags: WatchDirectoryFlags) { - return host.watchDirectory(directory, fileName => - onFileAddOrRemoveInWatchedDirectory(getNormalizedAbsolutePath(fileName, directory)), + return host.watchDirectory(directory, fileOrFolder => + onFileAddOrRemoveInWatchedDirectory(getNormalizedAbsolutePath(fileOrFolder, directory)), (flags & WatchDirectoryFlags.Recursive) !== 0); } @@ -609,24 +607,24 @@ namespace ts { watcher.close(); } - function onFileAddOrRemoveInWatchedDirectory(fileName: string) { + function onFileAddOrRemoveInWatchedDirectory(fileOrFolder: string) { Debug.assert(!!configFileName); - const path = toPath(fileName); + const fileOrFolderPath = toPath(fileOrFolder); // Since the file existance changed, update the sourceFiles cache - updateCachedSystem(fileName, path); - removeSourceFile(path); + (host as CachedSystem).addOrDeleteFileOrFolder(fileOrFolder, fileOrFolderPath); + removeSourceFile(fileOrFolderPath); // 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. - if (fileName && !isSupportedSourceFileName(fileName, compilerOptions)) { - writeLog(`Project: ${configFileName} Detected file add/remove of non supported extension: ${fileName}`); + if (fileOrFolder && !isSupportedSourceFileName(fileOrFolder, compilerOptions)) { + writeLog(`Project: ${configFileName} Detected file add/remove of non supported extension: ${fileOrFolder}`); return; } - writeLog(`Project: ${configFileName} Detected file add/remove of supported extension: ${fileName}`); + writeLog(`Project: ${configFileName} Detected file add/remove of supported extension: ${fileOrFolder}`); // Reload is pending, do the reload if (!needsReload) { @@ -658,9 +656,7 @@ namespace ts { } } - interface CachedSystem extends System { - addOrDeleteFileOrFolder(fileOrFolder: string): void; - clearCache(): void; + interface CachedSystem extends System, CachedHost { } function createCachedSystem(host: System): CachedSystem { @@ -675,7 +671,7 @@ namespace ts { const setTimeout = host.setTimeout ? (callback: (...args: any[]) => void, ms: number, ...args: any[]) => host.setTimeout(callback, ms, ...args) : undefined; const clearTimeout = host.clearTimeout ? (timeoutId: any) => host.clearTimeout(timeoutId) : undefined; - const cachedHost = createCachedHost(host); + const cachedPartialSystem = createCachedPartialSystem(host); return { args: host.args, newLine: host.newLine, @@ -683,17 +679,17 @@ namespace ts { write: s => host.write(s), readFile: (path, encoding?) => host.readFile(path, encoding), getFileSize, - writeFile: (fileName, data, writeByteOrderMark?) => cachedHost.writeFile(fileName, data, writeByteOrderMark), + writeFile: (fileName, data, writeByteOrderMark?) => cachedPartialSystem.writeFile(fileName, data, writeByteOrderMark), watchFile, watchDirectory, resolvePath: path => host.resolvePath(path), - fileExists: fileName => cachedHost.fileExists(fileName), - directoryExists: dir => cachedHost.directoryExists(dir), - createDirectory: dir => cachedHost.createDirectory(dir), + fileExists: fileName => cachedPartialSystem.fileExists(fileName), + directoryExists: dir => cachedPartialSystem.directoryExists(dir), + createDirectory: dir => cachedPartialSystem.createDirectory(dir), getExecutingFilePath: () => host.getExecutingFilePath(), - getCurrentDirectory: () => cachedHost.getCurrentDirectory(), - getDirectories: dir => cachedHost.getDirectories(dir), - readDirectory: (path, extensions, excludes, includes, depth) => cachedHost.readDirectory(path, extensions, excludes, includes, depth), + getCurrentDirectory: () => cachedPartialSystem.getCurrentDirectory(), + getDirectories: dir => cachedPartialSystem.getDirectories(dir), + readDirectory: (path, extensions, excludes, includes, depth) => cachedPartialSystem.readDirectory(path, extensions, excludes, includes, depth), getModifiedTime, createHash, getMemoryUsage, @@ -704,8 +700,9 @@ namespace ts { debugMode: host.debugMode, setTimeout, clearTimeout, - addOrDeleteFileOrFolder: fileOrFolder => cachedHost.addOrDeleteFileOrFolder(fileOrFolder), - clearCache: () => cachedHost.clearCache() + addOrDeleteFileOrFolder: (fileOrFolder, fileOrFolderPath) => cachedPartialSystem.addOrDeleteFileOrFolder(fileOrFolder, fileOrFolderPath), + addOrDeleteFile: (file, filePath, eventKind) => cachedPartialSystem.addOrDeleteFile(file, filePath, eventKind), + clearCache: () => cachedPartialSystem.clearCache() }; } } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 8507b6f5cd2..0b7ba9e7441 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -695,8 +695,8 @@ namespace ts.server { } /* @internal */ - onTypeRootFileChanged(project: ConfiguredProject, fileName: NormalizedPath) { - project.getCachedServerHost().addOrDeleteFileOrFolder(fileName); + onTypeRootFileChanged(project: ConfiguredProject, fileOrFolder: NormalizedPath) { + project.getCachedServerHost().addOrDeleteFileOrFolder(fileOrFolder, this.toPath(fileOrFolder)); project.updateTypes(); this.delayUpdateProjectGraphAndInferredProjectsRefresh(project); } @@ -707,15 +707,15 @@ namespace ts.server { * @param fileName the absolute file name that changed in watched directory */ /* @internal */ - onFileAddOrRemoveInWatchedDirectoryOfProject(project: ConfiguredProject, fileName: NormalizedPath) { - project.getCachedServerHost().addOrDeleteFileOrFolder(fileName); + onFileAddOrRemoveInWatchedDirectoryOfProject(project: ConfiguredProject, fileOrFolder: NormalizedPath) { + project.getCachedServerHost().addOrDeleteFileOrFolder(fileOrFolder, this.toPath(fileOrFolder)); const configFilename = project.getConfigFilePath(); // 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. - if (fileName && !isSupportedSourceFileName(fileName, project.getCompilerOptions(), this.hostConfiguration.extraFileExtensions)) { - this.logger.info(`Project: ${configFilename} Detected file add/remove of non supported extension: ${fileName}`); + if (fileOrFolder && !isSupportedSourceFileName(fileOrFolder, project.getCompilerOptions(), this.hostConfiguration.extraFileExtensions)) { + this.logger.info(`Project: ${configFilename} Detected file add/remove of non supported extension: ${fileOrFolder}`); return; } diff --git a/src/server/lsHost.ts b/src/server/lsHost.ts index f4cbd402604..44b9893bc3d 100644 --- a/src/server/lsHost.ts +++ b/src/server/lsHost.ts @@ -4,12 +4,13 @@ /// namespace ts.server { + /*@internal*/ export class CachedServerHost implements ServerHost { args: string[]; newLine: string; useCaseSensitiveFileNames: boolean; - private readonly cachedHost: CachedHost; + private readonly cachedPartialSystem: CachedPartialSystem; readonly trace: (s: string) => void; readonly realpath?: (path: string) => string; @@ -24,7 +25,7 @@ namespace ts.server { if (this.host.realpath) { this.realpath = path => this.host.realpath(path); } - this.cachedHost = createCachedHost(host); + this.cachedPartialSystem = createCachedPartialSystem(host); } write(s: string) { @@ -32,7 +33,7 @@ namespace ts.server { } writeFile(fileName: string, data: string, writeByteOrderMark?: boolean) { - this.cachedHost.writeFile(fileName, data, writeByteOrderMark); + this.cachedPartialSystem.writeFile(fileName, data, writeByteOrderMark); } resolvePath(path: string) { @@ -48,7 +49,7 @@ namespace ts.server { } getCurrentDirectory() { - return this.cachedHost.getCurrentDirectory(); + return this.cachedPartialSystem.getCurrentDirectory(); } exit(exitCode?: number) { @@ -61,32 +62,35 @@ namespace ts.server { } getDirectories(rootDir: string) { - return this.cachedHost.getDirectories(rootDir); + return this.cachedPartialSystem.getDirectories(rootDir); } readDirectory(rootDir: string, extensions: string[], excludes: string[], includes: string[], depth: number): string[] { - return this.cachedHost.readDirectory(rootDir, extensions, excludes, includes, depth); + return this.cachedPartialSystem.readDirectory(rootDir, extensions, excludes, includes, depth); } fileExists(fileName: string): boolean { - return this.cachedHost.fileExists(fileName); + return this.cachedPartialSystem.fileExists(fileName); } directoryExists(dirPath: string) { - return this.cachedHost.directoryExists(dirPath); + return this.cachedPartialSystem.directoryExists(dirPath); } readFile(path: string, encoding?: string): string { return this.host.readFile(path, encoding); } + addOrDeleteFileOrFolder(fileOrFolder: NormalizedPath, fileOrFolderPath: Path) { + return this.cachedPartialSystem.addOrDeleteFileOrFolder(fileOrFolder, fileOrFolderPath); + } - addOrDeleteFileOrFolder(fileOrFolder: NormalizedPath) { - return this.cachedHost.addOrDeleteFileOrFolder(fileOrFolder); + addOrDeleteFile(file: string, path: Path, eventKind: FileWatcherEventKind) { + return this.cachedPartialSystem.addOrDeleteFile(file, path, eventKind); } clearCache() { - return this.cachedHost.clearCache(); + return this.cachedPartialSystem.clearCache(); } setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]) { diff --git a/src/server/project.ts b/src/server/project.ts index 2233ef1e941..552778e86c0 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -218,7 +218,7 @@ namespace ts.server { this.resolutionCache = createResolutionCache( fileName => this.projectService.toPath(fileName), () => this.compilerOptions, - (failedLookupLocation, containingFile, name) => this.watchFailedLookupLocation(failedLookupLocation, containingFile, name), + (failedLookupLocation, failedLookupLocationPath, containingFile, name) => this.watchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath, containingFile, name), s => this.projectService.logger.info(s), (primaryResult, moduleName, compilerOptions, host) => resolveWithGlobalCache(primaryResult, moduleName, compilerOptions, host, this.getTypeAcquisition().enable ? this.projectService.typingsInstaller.globalTypingsCacheLocation : undefined, this.getProjectName()) @@ -235,12 +235,12 @@ namespace ts.server { this.markAsDirty(); } - private watchFailedLookupLocation(failedLookupLocation: string, containingFile: string, name: string) { + private watchFailedLookupLocation(failedLookupLocation: string, failedLookupLocationPath: Path, containingFile: string, name: string) { // There is some kind of change in the failed lookup location, update the program - return this.projectService.addFileWatcher(WatchType.FailedLookupLocation, this, failedLookupLocation, (__fileName, eventKind) => { + return this.projectService.addFileWatcher(WatchType.FailedLookupLocation, this, failedLookupLocation, (fileName, eventKind) => { this.projectService.logger.info(`Watcher: FailedLookupLocations: Status: ${FileWatcherEventKind[eventKind]}: Location: ${failedLookupLocation}, containingFile: ${containingFile}, name: ${name}`); if (this.projectKind === ProjectKind.Configured) { - (this.lsHost.host as CachedServerHost).addOrDeleteFileOrFolder(toNormalizedPath(failedLookupLocation)); + (this.lsHost.host as CachedServerHost).addOrDeleteFile(fileName, failedLookupLocationPath, eventKind); } this.resolutionCache.invalidateResolutionOfChangedFailedLookupLocation(failedLookupLocation); this.markAsDirty(); @@ -719,16 +719,15 @@ namespace ts.server { private addMissingFileWatcher(missingFilePath: Path) { const fileWatcher = this.projectService.addFileWatcher( WatchType.MissingFilePath, this, missingFilePath, - (filename, eventKind) => { + (fileName, eventKind) => { + if (this.projectKind === ProjectKind.Configured) { + (this.lsHost.host as CachedServerHost).addOrDeleteFile(fileName, missingFilePath, eventKind); + } + if (eventKind === FileWatcherEventKind.Created && this.missingFilesMap.has(missingFilePath)) { this.missingFilesMap.delete(missingFilePath); this.closeMissingFileWatcher(missingFilePath, fileWatcher, WatcherCloseReason.FileCreated); - if (this.projectKind === ProjectKind.Configured) { - const absoluteNormalizedPath = getNormalizedAbsolutePath(filename, getDirectoryPath(missingFilePath)); - (this.lsHost.host as CachedServerHost).addOrDeleteFileOrFolder(toNormalizedPath(absoluteNormalizedPath)); - } - // When a missing file is created, we should update the graph. this.markAsDirty(); this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this); @@ -1076,6 +1075,7 @@ namespace ts.server { return super.updateGraph(); } + /*@internal*/ getCachedServerHost() { return this.lsHost.host as CachedServerHost; } diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index 6d439e92385..2dcbc52d87d 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -237,7 +237,7 @@ namespace ts.server { detachAllProjects() { for (const p of this.containingProjects) { if (p.projectKind === ProjectKind.Configured) { - (p.lsHost.host as CachedServerHost).addOrDeleteFileOrFolder(this.fileName); + (p.lsHost.host as CachedServerHost).addOrDeleteFile(this.fileName, this.path, FileWatcherEventKind.Deleted); } const isInfoRoot = p.isRoot(this); // detach is unnecessary since we'll clean the list of containing projects anyways