@@ -335,10 +335,11 @@ namespace ts.Completions {
335335 const baseDirectory = getDirectoryPath ( absolutePath ) ;
336336 const ignoreCase = ! ( host . useCaseSensitiveFileNames && host . useCaseSensitiveFileNames ( ) ) ;
337337
338- if ( directoryProbablyExists ( baseDirectory , host ) ) {
339- if ( host . readDirectory ) {
340- // Enumerate the available files if possible
341- const files = host . readDirectory ( baseDirectory , extensions , /*exclude*/ undefined , /*include*/ [ "./*" ] ) ;
338+ if ( tryDirectoryExists ( host , baseDirectory ) ) {
339+ // Enumerate the available files if possible
340+ const files = tryReadDirectory ( host , baseDirectory , extensions , /*exclude*/ undefined , /*include*/ [ "./*" ] ) ;
341+
342+ if ( files ) {
342343 const foundFiles = createMap < boolean > ( ) ;
343344 for ( let filePath of files ) {
344345 filePath = normalizePath ( filePath ) ;
@@ -359,8 +360,9 @@ namespace ts.Completions {
359360 }
360361
361362 // If possible, get folder completion as well
362- if ( host . getDirectories ) {
363- const directories = host . getDirectories ( baseDirectory ) ;
363+ const directories = tryGetDirectories ( host , baseDirectory ) ;
364+
365+ if ( directories ) {
364366 for ( const directory of directories ) {
365367 const directoryName = getBaseFileName ( normalizePath ( directory ) ) ;
366368
@@ -449,22 +451,24 @@ namespace ts.Completions {
449451 // doesn't support. For now, this is safer but slower
450452 const includeGlob = normalizedSuffix ? "**/*" : "./*" ;
451453
452- const matches = host . readDirectory ( baseDirectory , fileExtensions , undefined , [ includeGlob ] ) ;
453- const result : string [ ] = [ ] ;
454+ const matches = tryReadDirectory ( host , baseDirectory , fileExtensions , undefined , [ includeGlob ] ) ;
455+ if ( matches ) {
456+ const result : string [ ] = [ ] ;
454457
455- // Trim away prefix and suffix
456- for ( const match of matches ) {
457- const normalizedMatch = normalizePath ( match ) ;
458- if ( ! endsWith ( normalizedMatch , normalizedSuffix ) || ! startsWith ( normalizedMatch , completePrefix ) ) {
459- continue ;
460- }
458+ // Trim away prefix and suffix
459+ for ( const match of matches ) {
460+ const normalizedMatch = normalizePath ( match ) ;
461+ if ( ! endsWith ( normalizedMatch , normalizedSuffix ) || ! startsWith ( normalizedMatch , completePrefix ) ) {
462+ continue ;
463+ }
461464
462- const start = completePrefix . length ;
463- const length = normalizedMatch . length - start - normalizedSuffix . length ;
465+ const start = completePrefix . length ;
466+ const length = normalizedMatch . length - start - normalizedSuffix . length ;
464467
465- result . push ( removeFileExtension ( normalizedMatch . substr ( start , length ) ) ) ;
468+ result . push ( removeFileExtension ( normalizedMatch . substr ( start , length ) ) ) ;
469+ }
470+ return result ;
466471 }
467- return result ;
468472 }
469473 }
470474
@@ -499,13 +503,14 @@ namespace ts.Completions {
499503 if ( ! isNestedModule ) {
500504 nonRelativeModules . push ( visibleModule . moduleName ) ;
501505 }
502- else if ( host . readDirectory && startsWith ( visibleModule . moduleName , moduleNameFragment ) ) {
503- const nestedFiles = host . readDirectory ( visibleModule . moduleDir , supportedTypeScriptExtensions , /*exclude*/ undefined , /*include*/ [ "./*" ] ) ;
504-
505- for ( let f of nestedFiles ) {
506- f = normalizePath ( f ) ;
507- const nestedModule = removeFileExtension ( getBaseFileName ( f ) ) ;
508- nonRelativeModules . push ( nestedModule ) ;
506+ else if ( startsWith ( visibleModule . moduleName , moduleNameFragment ) ) {
507+ const nestedFiles = tryReadDirectory ( host , visibleModule . moduleDir , supportedTypeScriptExtensions , /*exclude*/ undefined , /*include*/ [ "./*" ] ) ;
508+ if ( nestedFiles ) {
509+ for ( let f of nestedFiles ) {
510+ f = normalizePath ( f ) ;
511+ const nestedModule = removeFileExtension ( getBaseFileName ( f ) ) ;
512+ nonRelativeModules . push ( nestedModule ) ;
513+ }
509514 }
510515 }
511516 }
@@ -570,9 +575,17 @@ namespace ts.Completions {
570575 }
571576 }
572577 else if ( host . getDirectories ) {
573- const typeRoots = getEffectiveTypeRoots ( options , host ) ;
574- for ( const root of typeRoots ) {
575- getCompletionEntriesFromDirectories ( host , options , root , span , result ) ;
578+ let typeRoots : string [ ] ;
579+ try {
580+ // Wrap in try catch because getEffectiveTypeRoots touches the filesystem
581+ typeRoots = getEffectiveTypeRoots ( options , host ) ;
582+ }
583+ catch ( e ) { }
584+
585+ if ( typeRoots ) {
586+ for ( const root of typeRoots ) {
587+ getCompletionEntriesFromDirectories ( host , options , root , span , result ) ;
588+ }
576589 }
577590 }
578591
@@ -588,10 +601,13 @@ namespace ts.Completions {
588601 }
589602
590603 function getCompletionEntriesFromDirectories ( host : LanguageServiceHost , options : CompilerOptions , directory : string , span : TextSpan , result : CompletionEntry [ ] ) {
591- if ( host . getDirectories && directoryProbablyExists ( directory , host ) ) {
592- for ( let typeDirectory of host . getDirectories ( directory ) ) {
593- typeDirectory = normalizePath ( typeDirectory ) ;
594- result . push ( createCompletionEntryForModule ( getBaseFileName ( typeDirectory ) , ScriptElementKind . externalModuleName , span ) ) ;
604+ if ( host . getDirectories && tryDirectoryExists ( host , directory ) ) {
605+ const directories = tryGetDirectories ( host , directory ) ;
606+ if ( directories ) {
607+ for ( let typeDirectory of directories ) {
608+ typeDirectory = normalizePath ( typeDirectory ) ;
609+ result . push ( createCompletionEntryForModule ( getBaseFileName ( typeDirectory ) , ScriptElementKind . externalModuleName , span ) ) ;
610+ }
595611 }
596612 }
597613 }
@@ -600,7 +616,7 @@ namespace ts.Completions {
600616 const paths : string [ ] = [ ] ;
601617 let currentConfigPath : string ;
602618 while ( true ) {
603- currentConfigPath = findConfigFile ( currentDir , ( f ) => host . fileExists ( f ) , "package.json" ) ;
619+ currentConfigPath = findConfigFile ( currentDir , ( f ) => tryFileExists ( host , f ) , "package.json" ) ;
604620 if ( currentConfigPath ) {
605621 paths . push ( currentConfigPath ) ;
606622
@@ -652,8 +668,8 @@ namespace ts.Completions {
652668
653669 function tryReadingPackageJson ( filePath : string ) {
654670 try {
655- const fileText = host . readFile ( filePath ) ;
656- return JSON . parse ( fileText ) ;
671+ const fileText = tryReadFile ( host , filePath ) ;
672+ return fileText ? JSON . parse ( fileText ) : undefined ;
657673 }
658674 catch ( e ) {
659675 return undefined ;
@@ -1660,4 +1676,36 @@ namespace ts.Completions {
16601676 }
16611677
16621678 const nodeModulesDependencyKeys = [ "dependencies" , "devDependencies" , "peerDependencies" , "optionalDependencies" ] ;
1679+
1680+ function tryGetDirectories ( host : LanguageServiceHost , directoryName : string ) : string [ ] {
1681+ return tryIOAndConsumeErrors ( host , host . getDirectories , directoryName ) ;
1682+ }
1683+
1684+ function tryReadDirectory ( host : LanguageServiceHost , path : string , extensions ?: string [ ] , exclude ?: string [ ] , include ?: string [ ] ) : string [ ] {
1685+ return tryIOAndConsumeErrors ( host , host . readDirectory , path , extensions , exclude , include ) ;
1686+ }
1687+
1688+ function tryReadFile ( host : LanguageServiceHost , path : string ) : string {
1689+ return tryIOAndConsumeErrors ( host , host . readFile , path ) ;
1690+ }
1691+
1692+ function tryFileExists ( host : LanguageServiceHost , path : string ) : boolean {
1693+ return tryIOAndConsumeErrors ( host , host . fileExists , path ) ;
1694+ }
1695+
1696+ function tryDirectoryExists ( host : LanguageServiceHost , path : string ) : boolean {
1697+ try {
1698+ return directoryProbablyExists ( path , host ) ;
1699+ }
1700+ catch ( e ) { }
1701+ return undefined ;
1702+ }
1703+
1704+ function tryIOAndConsumeErrors < T > ( host : LanguageServiceHost , toApply : ( ...a : any [ ] ) => T , ...args : any [ ] ) {
1705+ try {
1706+ return toApply && toApply . apply ( host , args ) ;
1707+ }
1708+ catch ( e ) { }
1709+ return undefined ;
1710+ }
16631711}
0 commit comments