From 8c95c2b474e37ee440a15405dfc9cc717f300cc6 Mon Sep 17 00:00:00 2001 From: Richard Knoll Date: Tue, 13 Sep 2016 11:44:23 -0700 Subject: [PATCH] Wrap IO for import completions in try catch --- src/services/services.ts | 106 +++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 33 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index b581836d9c4..b26dea5efb1 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -4599,10 +4599,11 @@ namespace ts { const baseDirectory = getDirectoryPath(absolutePath); const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames()); - if (directoryProbablyExists(baseDirectory, host)) { - if (host.readDirectory) { - // Enumerate the available files if possible - const files = host.readDirectory(baseDirectory, extensions, /*exclude*/undefined, /*include*/["./*"]); + if (tryDirectoryExists(host, baseDirectory)) { + // Enumerate the available files if possible + const files = tryReadDirectory(host, baseDirectory, extensions, /*exclude*/undefined, /*include*/["./*"]); + + if (files) { const foundFiles = createMap(); for (let filePath of files) { filePath = normalizePath(filePath); @@ -4623,8 +4624,9 @@ namespace ts { } // If possible, get folder completion as well - if (host.getDirectories) { - const directories = host.getDirectories(baseDirectory); + const directories = tryGetDirectories(host, baseDirectory); + + if (directories) { for (const directory of directories) { const directoryName = getBaseFileName(normalizePath(directory)); @@ -4714,22 +4716,24 @@ namespace ts { // doesn't support. For now, this is safer but slower const includeGlob = normalizedSuffix ? "**/*" : "./*"; - const matches = host.readDirectory(baseDirectory, fileExtensions, undefined, [includeGlob]); - const result: string[] = []; + const matches = tryReadDirectory(host, baseDirectory, fileExtensions, undefined, [includeGlob]); + if (matches) { + const result: string[] = []; - // Trim away prefix and suffix - for (const match of matches) { - const normalizedMatch = normalizePath(match); - if (!endsWith(normalizedMatch, normalizedSuffix) || !startsWith(normalizedMatch, completePrefix)) { - continue; + // Trim away prefix and suffix + for (const match of matches) { + const normalizedMatch = normalizePath(match); + if (!endsWith(normalizedMatch, normalizedSuffix) || !startsWith(normalizedMatch, completePrefix)) { + continue; + } + + const start = completePrefix.length; + const length = normalizedMatch.length - start - normalizedSuffix.length; + + result.push(removeFileExtension(normalizedMatch.substr(start, length))); } - - const start = completePrefix.length; - const length = normalizedMatch.length - start - normalizedSuffix.length; - - result.push(removeFileExtension(normalizedMatch.substr(start, length))); + return result; } - return result; } } @@ -4764,13 +4768,14 @@ namespace ts { if (!isNestedModule) { nonRelativeModules.push(visibleModule.moduleName); } - else if (host.readDirectory && startsWith(visibleModule.moduleName, moduleNameFragment)) { - const nestedFiles = host.readDirectory(visibleModule.moduleDir, supportedTypeScriptExtensions, /*exclude*/undefined, /*include*/["./*"]); - - for (let f of nestedFiles) { - f = normalizePath(f); - const nestedModule = removeFileExtension(getBaseFileName(f)); - nonRelativeModules.push(nestedModule); + else if (startsWith(visibleModule.moduleName, moduleNameFragment)) { + const nestedFiles = tryReadDirectory(host, visibleModule.moduleDir, supportedTypeScriptExtensions, /*exclude*/undefined, /*include*/["./*"]); + if (nestedFiles) { + for (let f of nestedFiles) { + f = normalizePath(f); + const nestedModule = removeFileExtension(getBaseFileName(f)); + nonRelativeModules.push(nestedModule); + } } } } @@ -4853,10 +4858,13 @@ namespace ts { } function getCompletionEntriesFromDirectories(host: LanguageServiceHost, options: CompilerOptions, directory: string, span: TextSpan, result: CompletionEntry[]) { - if (host.getDirectories && directoryProbablyExists(directory, host)) { - for (let typeDirectory of host.getDirectories(directory)) { - typeDirectory = normalizePath(typeDirectory); - result.push(createCompletionEntryForModule(getBaseFileName(typeDirectory), ScriptElementKind.externalModuleName, span)); + if (host.getDirectories && tryDirectoryExists(host, directory)) { + const directories = tryGetDirectories(host, directory); + if (directories) { + for (let typeDirectory of directories) { + typeDirectory = normalizePath(typeDirectory); + result.push(createCompletionEntryForModule(getBaseFileName(typeDirectory), ScriptElementKind.externalModuleName, span)); + } } } } @@ -4865,7 +4873,7 @@ namespace ts { const paths: string[] = []; let currentConfigPath: string; while (true) { - currentConfigPath = findConfigFile(currentDir, (f) => host.fileExists(f), "package.json"); + currentConfigPath = findConfigFile(currentDir, (f) => tryFileExists(host, f), "package.json"); if (currentConfigPath) { paths.push(currentConfigPath); @@ -4917,8 +4925,8 @@ namespace ts { function tryReadingPackageJson(filePath: string) { try { - const fileText = host.readFile(filePath); - return JSON.parse(fileText); + const fileText = tryReadFile(host, filePath); + return fileText ? JSON.parse(fileText) : undefined; } catch (e) { return undefined; @@ -4960,6 +4968,38 @@ namespace ts { function normalizeAndPreserveTrailingSlash(path: string) { return hasTrailingDirectorySeparator(path) ? ensureTrailingDirectorySeparator(normalizePath(path)) : normalizePath(path); } + + function tryGetDirectories(host: LanguageServiceHost, directoryName: string): string[] { + return tryIOAndConsumeErrors(host, host.getDirectories, directoryName); + } + + function tryReadDirectory(host: LanguageServiceHost, path: string, extensions?: string[], exclude?: string[], include?: string[]): string[] { + return tryIOAndConsumeErrors(host, host.readDirectory, path, extensions, exclude, include); + } + + function tryReadFile(host: LanguageServiceHost, path: string): string { + return tryIOAndConsumeErrors(host, host.readFile, path); + } + + function tryFileExists(host: LanguageServiceHost, path: string): boolean { + return tryIOAndConsumeErrors(host, host.fileExists, path); + } + + function tryDirectoryExists(host: LanguageServiceHost, path: string): boolean { + try { + return directoryProbablyExists(path, host); + } + catch (e) {} + return undefined; + } + + function tryIOAndConsumeErrors(host: LanguageServiceHost, toApply: (...a: any[]) => T, ...args: any[]) { + try { + return toApply && toApply.apply(host, args); + } + catch (e) {} + return undefined; + } } function getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails {