@@ -1158,9 +1158,13 @@ namespace ts {
1158
1158
error ?( s : string ) : void ;
1159
1159
useCaseSensitiveFileNames ?( ) : boolean ;
1160
1160
1161
- readDirectory ( path : string , extensions ?: string [ ] , exclude ?: string [ ] , include ?: string [ ] ) : string [ ] ;
1162
- readFile ( path : string , encoding ?: string ) : string ;
1163
- fileExists ( path : string ) : boolean ;
1161
+ /*
1162
+ * LS host can optionally implement these methods to support getImportModuleCompletionsAtPosition.
1163
+ * Without these methods, only completions for ambient modules will be provided.
1164
+ */
1165
+ readDirectory ?( path : string , extensions ?: string [ ] , exclude ?: string [ ] , include ?: string [ ] ) : string [ ] ;
1166
+ readFile ?( path : string , encoding ?: string ) : string ;
1167
+ fileExists ?( path : string ) : boolean ;
1164
1168
1165
1169
/*
1166
1170
* LS host can optionally implement this method if it wants to be completely in charge of module name resolution.
@@ -3155,7 +3159,8 @@ namespace ts {
3155
3159
writeFile : ( fileName , data , writeByteOrderMark ) => { } ,
3156
3160
getCurrentDirectory : ( ) => currentDirectory ,
3157
3161
fileExists : ( fileName ) : boolean => {
3158
- return host . fileExists ( fileName ) ;
3162
+ // stub missing host functionality
3163
+ return hostCache . getOrCreateEntry ( fileName ) !== undefined ;
3159
3164
} ,
3160
3165
readFile : ( fileName ) : string => {
3161
3166
// stub missing host functionality
@@ -4598,23 +4603,25 @@ namespace ts {
4598
4603
const ignoreCase = ! ( host . useCaseSensitiveFileNames && host . useCaseSensitiveFileNames ( ) ) ;
4599
4604
4600
4605
if ( directoryProbablyExists ( baseDirectory , host ) ) {
4601
- // Enumerate the available files
4602
- const files = host . readDirectory ( baseDirectory , extensions , /*exclude*/ undefined , /*include*/ [ "./*" ] ) ;
4603
- for ( let filePath of files ) {
4604
- filePath = normalizePath ( filePath ) ;
4605
- if ( exclude && comparePaths ( filePath , exclude , scriptPath , ignoreCase ) === Comparison . EqualTo ) {
4606
- continue ;
4607
- }
4606
+ if ( host . readDirectory ) {
4607
+ // Enumerate the available files if possible
4608
+ const files = host . readDirectory ( baseDirectory , extensions , /*exclude*/ undefined , /*include*/ [ "./*" ] ) ;
4609
+ for ( let filePath of files ) {
4610
+ filePath = normalizePath ( filePath ) ;
4611
+ if ( exclude && comparePaths ( filePath , exclude , scriptPath , ignoreCase ) === Comparison . EqualTo ) {
4612
+ continue ;
4613
+ }
4608
4614
4609
- const fileName = includeExtensions ? getBaseFileName ( filePath ) : removeFileExtension ( getBaseFileName ( filePath ) ) ;
4610
- const duplicate = ! includeExtensions && forEach ( result , entry => entry . name === fileName ) ;
4615
+ const fileName = includeExtensions ? getBaseFileName ( filePath ) : removeFileExtension ( getBaseFileName ( filePath ) ) ;
4616
+ const duplicate = ! includeExtensions && forEach ( result , entry => entry . name === fileName ) ;
4611
4617
4612
- if ( ! duplicate ) {
4613
- result . push ( {
4614
- name : fileName ,
4615
- kind : ScriptElementKind . scriptElement ,
4616
- sortText : fileName
4617
- } ) ;
4618
+ if ( ! duplicate ) {
4619
+ result . push ( {
4620
+ name : fileName ,
4621
+ kind : ScriptElementKind . scriptElement ,
4622
+ sortText : fileName
4623
+ } ) ;
4624
+ }
4618
4625
}
4619
4626
}
4620
4627
@@ -4691,44 +4698,46 @@ namespace ts {
4691
4698
}
4692
4699
4693
4700
function getModulesForPathsPattern ( fragment : string , baseUrl : string , pattern : string , fileExtensions : string [ ] ) : string [ ] {
4694
- const parsed = hasZeroOrOneAsteriskCharacter ( pattern ) ? tryParsePattern ( pattern ) : undefined ;
4695
- if ( parsed ) {
4696
- // The prefix has two effective parts: the directory path and the base component after the filepath that is not a
4697
- // full directory component. For example: directory/path/of/prefix/base*
4698
- const normalizedPrefix = normalizeAndPreserveTrailingSlash ( parsed . prefix ) ;
4699
- const normalizedPrefixDirectory = getDirectoryPath ( normalizedPrefix ) ;
4700
- const normalizedPrefixBase = getBaseFileName ( normalizedPrefix ) ;
4701
-
4702
- const fragmentHasPath = fragment . indexOf ( directorySeparator ) !== - 1 ;
4703
-
4704
- // Try and expand the prefix to include any path from the fragment so that we can limit the readDirectory call
4705
- const expandedPrefixDirectory = fragmentHasPath ? combinePaths ( normalizedPrefixDirectory , normalizedPrefixBase + getDirectoryPath ( fragment ) ) : normalizedPrefixDirectory ;
4706
-
4707
- const normalizedSuffix = normalizePath ( parsed . suffix ) ;
4708
- const baseDirectory = combinePaths ( baseUrl , expandedPrefixDirectory ) ;
4709
- const completePrefix = fragmentHasPath ? baseDirectory : ensureTrailingDirectorySeparator ( baseDirectory ) + normalizedPrefixBase ;
4710
-
4711
- // If we have a suffix, then we need to read the directory all the way down. We could create a glob
4712
- // that encodes the suffix, but we would have to escape the character "?" which readDirectory
4713
- // doesn't support. For now, this is safer but slower
4714
- const includeGlob = normalizedSuffix ? "**/*" : "./*" ;
4715
-
4716
- const matches = host . readDirectory ( baseDirectory , fileExtensions , undefined , [ includeGlob ] ) ;
4717
- const result : string [ ] = [ ] ;
4718
-
4719
- // Trim away prefix and suffix
4720
- for ( const match of matches ) {
4721
- const normalizedMatch = normalizePath ( match ) ;
4722
- if ( ! endsWith ( normalizedMatch , normalizedSuffix ) || ! startsWith ( normalizedMatch , completePrefix ) ) {
4723
- continue ;
4724
- }
4701
+ if ( host . readDirectory ) {
4702
+ const parsed = hasZeroOrOneAsteriskCharacter ( pattern ) ? tryParsePattern ( pattern ) : undefined ;
4703
+ if ( parsed ) {
4704
+ // The prefix has two effective parts: the directory path and the base component after the filepath that is not a
4705
+ // full directory component. For example: directory/path/of/prefix/base*
4706
+ const normalizedPrefix = normalizeAndPreserveTrailingSlash ( parsed . prefix ) ;
4707
+ const normalizedPrefixDirectory = getDirectoryPath ( normalizedPrefix ) ;
4708
+ const normalizedPrefixBase = getBaseFileName ( normalizedPrefix ) ;
4709
+
4710
+ const fragmentHasPath = fragment . indexOf ( directorySeparator ) !== - 1 ;
4711
+
4712
+ // Try and expand the prefix to include any path from the fragment so that we can limit the readDirectory call
4713
+ const expandedPrefixDirectory = fragmentHasPath ? combinePaths ( normalizedPrefixDirectory , normalizedPrefixBase + getDirectoryPath ( fragment ) ) : normalizedPrefixDirectory ;
4714
+
4715
+ const normalizedSuffix = normalizePath ( parsed . suffix ) ;
4716
+ const baseDirectory = combinePaths ( baseUrl , expandedPrefixDirectory ) ;
4717
+ const completePrefix = fragmentHasPath ? baseDirectory : ensureTrailingDirectorySeparator ( baseDirectory ) + normalizedPrefixBase ;
4718
+
4719
+ // If we have a suffix, then we need to read the directory all the way down. We could create a glob
4720
+ // that encodes the suffix, but we would have to escape the character "?" which readDirectory
4721
+ // doesn't support. For now, this is safer but slower
4722
+ const includeGlob = normalizedSuffix ? "**/*" : "./*" ;
4723
+
4724
+ const matches = host . readDirectory ( baseDirectory , fileExtensions , undefined , [ includeGlob ] ) ;
4725
+ const result : string [ ] = [ ] ;
4726
+
4727
+ // Trim away prefix and suffix
4728
+ for ( const match of matches ) {
4729
+ const normalizedMatch = normalizePath ( match ) ;
4730
+ if ( ! endsWith ( normalizedMatch , normalizedSuffix ) || ! startsWith ( normalizedMatch , completePrefix ) ) {
4731
+ continue ;
4732
+ }
4725
4733
4726
- const start = completePrefix . length ;
4727
- const length = normalizedMatch . length - start - normalizedSuffix . length ;
4734
+ const start = completePrefix . length ;
4735
+ const length = normalizedMatch . length - start - normalizedSuffix . length ;
4728
4736
4729
- result . push ( removeFileExtension ( normalizedMatch . substr ( start , length ) ) ) ;
4737
+ result . push ( removeFileExtension ( normalizedMatch . substr ( start , length ) ) ) ;
4738
+ }
4739
+ return result ;
4730
4740
}
4731
- return result ;
4732
4741
}
4733
4742
4734
4743
return undefined ;
@@ -4762,7 +4771,7 @@ namespace ts {
4762
4771
if ( ! isNestedModule ) {
4763
4772
nonRelativeModules . push ( visibleModule . moduleName ) ;
4764
4773
}
4765
- else if ( startsWith ( visibleModule . moduleName , moduleNameFragment ) ) {
4774
+ else if ( host . readDirectory && startsWith ( visibleModule . moduleName , moduleNameFragment ) ) {
4766
4775
const nestedFiles = host . readDirectory ( visibleModule . moduleDir , supportedTypeScriptExtensions , /*exclude*/ undefined , /*include*/ [ "./*" ] ) ;
4767
4776
4768
4777
for ( let f of nestedFiles ) {
@@ -4891,28 +4900,31 @@ namespace ts {
4891
4900
4892
4901
function enumerateNodeModulesVisibleToScript ( host : LanguageServiceHost , scriptPath : string ) {
4893
4902
const result : VisibleModuleInfo [ ] = [ ] ;
4894
- for ( const packageJson of findPackageJsons ( scriptPath ) ) {
4895
- const package = tryReadingPackageJson ( packageJson ) ;
4896
- if ( ! package ) {
4897
- return ;
4898
- }
4899
4903
4900
- const nodeModulesDir = combinePaths ( getDirectoryPath ( packageJson ) , "node_modules" ) ;
4901
- const foundModuleNames : string [ ] = [ ] ;
4904
+ if ( host . readFile && host . fileExists ) {
4905
+ for ( const packageJson of findPackageJsons ( scriptPath ) ) {
4906
+ const package = tryReadingPackageJson ( packageJson ) ;
4907
+ if ( ! package ) {
4908
+ return ;
4909
+ }
4902
4910
4903
- if ( package . dependencies ) {
4904
- addPotentialPackageNames ( package . dependencies , foundModuleNames ) ;
4905
- }
4906
- if ( package . devDependencies ) {
4907
- addPotentialPackageNames ( package . devDependencies , foundModuleNames ) ;
4908
- }
4911
+ const nodeModulesDir = combinePaths ( getDirectoryPath ( packageJson ) , "node_modules" ) ;
4912
+ const foundModuleNames : string [ ] = [ ] ;
4909
4913
4910
- for ( const moduleName of foundModuleNames ) {
4911
- const moduleDir = combinePaths ( nodeModulesDir , moduleName ) ;
4912
- result . push ( {
4913
- moduleName,
4914
- moduleDir
4915
- } ) ;
4914
+ if ( package . dependencies ) {
4915
+ addPotentialPackageNames ( package . dependencies , foundModuleNames ) ;
4916
+ }
4917
+ if ( package . devDependencies ) {
4918
+ addPotentialPackageNames ( package . devDependencies , foundModuleNames ) ;
4919
+ }
4920
+
4921
+ for ( const moduleName of foundModuleNames ) {
4922
+ const moduleDir = combinePaths ( nodeModulesDir , moduleName ) ;
4923
+ result . push ( {
4924
+ moduleName,
4925
+ moduleDir
4926
+ } ) ;
4927
+ }
4916
4928
}
4917
4929
}
4918
4930
0 commit comments