@@ -1968,7 +1968,7 @@ namespace ts {
1968
1968
* for completions.
1969
1969
* For example, this matches /// <reference path="fragment
1970
1970
*/
1971
- const tripleSlashDirectiveFragmentRegex = / ^ \/ \/ \/ \s * < r e f e r e n c e \s + p a t h \s * = \s * (?: ' | " ) ( [ ^ ' " ] + ) $ / ;
1971
+ const tripleSlashDirectiveFragmentRegex = / ^ \/ \/ \/ \s * < r e f e r e n c e \s + ( p a t h | t y p e s ) \s * = \s * (?: ' | " ) ( [ ^ ' " ] + ) $ / ;
1972
1972
1973
1973
let commandLineOptionsStringToEnum : CommandLineOptionOfCustomType [ ] ;
1974
1974
@@ -4501,7 +4501,7 @@ namespace ts {
4501
4501
result = getCompletionEntriesForDirectoryFragment ( fragment , normalizePath ( absolute ) , fileExtensions , /*includeExtensions*/ false ) ;
4502
4502
4503
4503
if ( paths ) {
4504
- for ( var path in paths ) {
4504
+ for ( const path in paths ) {
4505
4505
if ( paths . hasOwnProperty ( path ) ) {
4506
4506
if ( path === "*" ) {
4507
4507
if ( paths [ path ] ) {
@@ -4526,7 +4526,7 @@ namespace ts {
4526
4526
result = [ ] ;
4527
4527
}
4528
4528
4529
-
4529
+ getCompletionEntriesFromTypings ( host , options , scriptPath , result ) ;
4530
4530
4531
4531
forEach ( enumeratePotentialNonRelativeModules ( fragment , scriptPath ) , moduleName => {
4532
4532
result . push ( createCompletionEntryForModule ( moduleName , ScriptElementKind . externalModuleName ) ) ;
@@ -4558,7 +4558,7 @@ namespace ts {
4558
4558
// If we have a suffix, then we need to read the directory all the way down. We could create a glob
4559
4559
// that encodes the suffix, but we would have to escape the character "?" which readDirectory
4560
4560
// doesn't support. For now, this is safer but slower
4561
- const includeGlob = normalizedSuffix ? "**/*" : "./*"
4561
+ const includeGlob = normalizedSuffix ? "**/*" : "./*" ;
4562
4562
4563
4563
const matches = host . readDirectory ( baseDirectory , fileExtensions , undefined , [ includeGlob ] ) ;
4564
4564
const result : string [ ] = [ ] ;
@@ -4629,19 +4629,97 @@ namespace ts {
4629
4629
const text = sourceFile . text . substr ( node . pos , position ) ;
4630
4630
const match = tripleSlashDirectiveFragmentRegex . exec ( text ) ;
4631
4631
if ( match ) {
4632
- const fragment = match [ 1 ] ;
4633
- const scriptPath = getDirectoryPath ( sourceFile . path ) ;
4634
- return {
4635
- isMemberCompletion : false ,
4636
- isNewIdentifierLocation : false ,
4637
- entries : getCompletionEntriesForDirectoryFragment ( fragment , scriptPath , getSupportedExtensions ( program . getCompilerOptions ( ) ) , /*includeExtensions*/ true )
4638
- } ;
4632
+ const kind = match [ 1 ] ;
4633
+ const fragment = match [ 2 ] ;
4634
+ if ( kind === "path" ) {
4635
+ // Give completions for a relative path
4636
+ const scriptPath = getDirectoryPath ( sourceFile . path ) ;
4637
+ return {
4638
+ isMemberCompletion : false ,
4639
+ isNewIdentifierLocation : false ,
4640
+ entries : getCompletionEntriesForDirectoryFragment ( fragment , scriptPath , getSupportedExtensions ( program . getCompilerOptions ( ) ) , /*includeExtensions*/ true )
4641
+ } ;
4642
+ }
4643
+ else {
4644
+ // Give completions based on what is available in the types directory
4645
+ }
4639
4646
}
4640
4647
4641
4648
return undefined ;
4642
4649
}
4643
4650
}
4644
4651
4652
+ function getCompletionEntriesFromTypings ( host : LanguageServiceHost , options : CompilerOptions , scriptPath : string , result : CompletionEntry [ ] ) : CompletionEntry [ ] {
4653
+ // Check for typings specified in compiler options
4654
+ if ( options . types ) {
4655
+ forEach ( options . types , moduleName => {
4656
+ result . push ( createCompletionEntryForModule ( moduleName , ScriptElementKind . externalModuleName ) ) ;
4657
+ } ) ;
4658
+ }
4659
+ else if ( options . typeRoots ) {
4660
+ const absoluteRoots = map ( options . typeRoots , rootDirectory => getAbsoluteProjectPath ( rootDirectory , host , options . project ) ) ;
4661
+ forEach ( absoluteRoots , absoluteRoot => getCompletionEntriesFromDirectory ( host , options , absoluteRoot , result ) ) ;
4662
+ }
4663
+
4664
+ // Also get all @types typings installed in visible node_modules directories
4665
+ forEach ( findPackageJsons ( scriptPath ) , package => {
4666
+ const typesDir = combinePaths ( getDirectoryPath ( package ) , "node_modules/@types" ) ;
4667
+ getCompletionEntriesFromDirectory ( host , options , typesDir , result ) ;
4668
+ } ) ;
4669
+
4670
+ return result ;
4671
+ }
4672
+
4673
+ function getAbsoluteProjectPath ( path : string , host : LanguageServiceHost , projectDir ?: string ) {
4674
+ if ( isRootedDiskPath ( path ) ) {
4675
+ return normalizePath ( path ) ;
4676
+ }
4677
+
4678
+ if ( projectDir ) {
4679
+ return normalizePath ( combinePaths ( projectDir , path ) ) ;
4680
+ }
4681
+
4682
+ return normalizePath ( host . resolvePath ( path ) ) ;
4683
+ }
4684
+
4685
+ function getCompletionEntriesFromDirectory ( host : LanguageServiceHost , options : CompilerOptions , directory : string , result : CompletionEntry [ ] ) {
4686
+ if ( directoryProbablyExists ( directory , host ) ) {
4687
+ const typeDirectories = host . readDirectory ( directory , getSupportedExtensions ( options ) , /*exclude*/ undefined , /*include*/ [ "./*/*" ] ) ;
4688
+ const seen : { [ index : string ] : boolean } = { } ;
4689
+ forEach ( typeDirectories , typeFile => {
4690
+ const typeDirectory = getDirectoryPath ( typeFile ) ;
4691
+ if ( ! hasProperty ( seen , typeDirectory ) ) {
4692
+ seen [ typeDirectory ] = true ;
4693
+ result . push ( createCompletionEntryForModule ( getBaseFileName ( typeDirectory ) , ScriptElementKind . externalModuleName ) ) ;
4694
+ }
4695
+ } ) ;
4696
+ }
4697
+ }
4698
+
4699
+ function findPackageJsons ( currentDir : string ) : string [ ] {
4700
+ const paths : string [ ] = [ ] ;
4701
+ let currentConfigPath : string ;
4702
+ while ( true ) {
4703
+ currentConfigPath = findConfigFile ( currentDir , ( f ) => host . fileExists ( f ) , "package.json" ) ;
4704
+ if ( currentConfigPath ) {
4705
+ paths . push ( currentConfigPath ) ;
4706
+
4707
+ currentDir = getDirectoryPath ( currentConfigPath ) ;
4708
+ const parent = getDirectoryPath ( currentDir ) ;
4709
+ if ( currentDir === parent ) {
4710
+ break ;
4711
+ }
4712
+ currentDir = parent ;
4713
+ }
4714
+ else {
4715
+ break ;
4716
+ }
4717
+ }
4718
+
4719
+ return paths ;
4720
+ }
4721
+
4722
+
4645
4723
function enumerateNodeModulesVisibleToScript ( host : LanguageServiceHost , scriptPath : string , modulePrefix ?: string ) {
4646
4724
const result : VisibleModuleInfo [ ] = [ ] ;
4647
4725
findPackageJsons ( scriptPath ) . forEach ( ( packageJson ) => {
@@ -4672,29 +4750,6 @@ namespace ts {
4672
4750
4673
4751
return result ;
4674
4752
4675
- function findPackageJsons ( currentDir : string ) : string [ ] {
4676
- const paths : string [ ] = [ ] ;
4677
- let currentConfigPath : string ;
4678
- while ( true ) {
4679
- currentConfigPath = findConfigFile ( currentDir , ( f ) => host . fileExists ( f ) , "package.json" ) ;
4680
- if ( currentConfigPath ) {
4681
- paths . push ( currentConfigPath ) ;
4682
-
4683
- currentDir = getDirectoryPath ( currentConfigPath ) ;
4684
- const parent = getDirectoryPath ( currentDir ) ;
4685
- if ( currentDir === parent ) {
4686
- break ;
4687
- }
4688
- currentDir = parent ;
4689
- }
4690
- else {
4691
- break ;
4692
- }
4693
- }
4694
-
4695
- return paths ;
4696
- }
4697
-
4698
4753
function tryReadingPackageJson ( filePath : string ) {
4699
4754
try {
4700
4755
const fileText = host . readFile ( filePath ) ;
@@ -4745,7 +4800,7 @@ namespace ts {
4745
4800
kind,
4746
4801
kindModifiers : ScriptElementKindModifier . none ,
4747
4802
sortText : name
4748
- }
4803
+ } ;
4749
4804
}
4750
4805
4751
4806
function getCompletionEntryDetails ( fileName : string , position : number , entryName : string ) : CompletionEntryDetails {
0 commit comments