1
1
/* @internal */
2
2
namespace ts . Completions . StringCompletions {
3
+ interface NameAndKindSet {
4
+ add ( value : NameAndKind ) : void ;
5
+ has ( name : string ) : boolean ;
6
+ values ( ) : Iterator < NameAndKind > ;
7
+ }
8
+ const kindPrecedence = {
9
+ [ ScriptElementKind . directory ] : 0 ,
10
+ [ ScriptElementKind . scriptElement ] : 1 ,
11
+ [ ScriptElementKind . externalModuleName ] : 2 ,
12
+ } ;
13
+ function createNameAndKindSet ( ) : NameAndKindSet {
14
+ const map = new Map < string , NameAndKind > ( ) ;
15
+ function add ( value : NameAndKind ) {
16
+ const existing = map . get ( value . name ) ;
17
+ if ( ! existing || kindPrecedence [ existing . kind ] < kindPrecedence [ value . kind ] ) {
18
+ map . set ( value . name , value ) ;
19
+ }
20
+ }
21
+ return {
22
+ add,
23
+ has : map . has . bind ( map ) ,
24
+ values : map . values . bind ( map ) ,
25
+ } ;
26
+ }
27
+
3
28
export function getStringLiteralCompletions (
4
29
sourceFile : SourceFile ,
5
30
position : number ,
@@ -435,7 +460,7 @@ namespace ts.Completions.StringCompletions {
435
460
host : LanguageServiceHost ,
436
461
exclude ?: string ,
437
462
result = createNameAndKindSet ( )
438
- ) : Set < NameAndKind > {
463
+ ) : NameAndKindSet {
439
464
if ( fragment === undefined ) {
440
465
fragment = "" ;
441
466
}
@@ -526,7 +551,7 @@ namespace ts.Completions.StringCompletions {
526
551
527
552
/** @returns whether `fragment` was a match for any `paths` (which should indicate whether any other path completions should be offered) */
528
553
function addCompletionEntriesFromPaths (
529
- result : Set < NameAndKind > ,
554
+ result : NameAndKindSet ,
530
555
fragment : string ,
531
556
baseDirectory : string ,
532
557
extensionOptions : ExtensionOptions ,
@@ -546,7 +571,7 @@ namespace ts.Completions.StringCompletions {
546
571
547
572
/** @returns whether `fragment` was a match for any `paths` (which should indicate whether any other path completions should be offered) */
548
573
function addCompletionEntriesFromPathsOrExports (
549
- result : Set < NameAndKind > ,
574
+ result : NameAndKindSet ,
550
575
fragment : string ,
551
576
baseDirectory : string ,
552
577
extensionOptions : ExtensionOptions ,
@@ -595,10 +620,6 @@ namespace ts.Completions.StringCompletions {
595
620
return matchedPath !== undefined ;
596
621
}
597
622
598
- function createNameAndKindSet ( ) {
599
- return createSet < NameAndKind > ( element => + generateDjb2Hash ( element . name ) , ( a , b ) => a . name === b . name ) ;
600
- }
601
-
602
623
/**
603
624
* Check all of the declared modules and those in node modules. Possible sources of modules:
604
625
* Modules that are found by the type checker
@@ -642,7 +663,7 @@ namespace ts.Completions.StringCompletions {
642
663
if ( fragmentDirectory === undefined ) {
643
664
for ( const moduleName of enumerateNodeModulesVisibleToScript ( host , scriptPath ) ) {
644
665
const moduleResult = nameAndKind ( moduleName , ScriptElementKind . externalModuleName , /*extension*/ undefined ) ;
645
- if ( ! result . has ( moduleResult ) ) {
666
+ if ( ! result . has ( moduleResult . name ) ) {
646
667
foundGlobal = true ;
647
668
result . add ( moduleResult ) ;
648
669
}
@@ -733,20 +754,20 @@ namespace ts.Completions.StringCompletions {
733
754
) : readonly NameAndKind [ ] {
734
755
if ( ! endsWith ( path , "*" ) ) {
735
756
// For a path mapping "foo": ["/x/y/z.ts"], add "foo" itself as a completion.
736
- return ! stringContains ( path , "*" ) ? justPathMappingName ( path ) : emptyArray ;
757
+ return ! stringContains ( path , "*" ) ? justPathMappingName ( path , ScriptElementKind . scriptElement ) : emptyArray ;
737
758
}
738
759
739
760
const pathPrefix = path . slice ( 0 , path . length - 1 ) ;
740
761
const remainingFragment = tryRemovePrefix ( fragment , pathPrefix ) ;
741
762
if ( remainingFragment === undefined ) {
742
763
const starIsFullPathComponent = path [ path . length - 2 ] === "/" ;
743
- return starIsFullPathComponent ? justPathMappingName ( pathPrefix ) : flatMap ( patterns , pattern =>
764
+ return starIsFullPathComponent ? justPathMappingName ( pathPrefix , ScriptElementKind . directory ) : flatMap ( patterns , pattern =>
744
765
getModulesForPathsPattern ( "" , packageDirectory , pattern , extensionOptions , host ) ?. map ( ( { name, ...rest } ) => ( { name : pathPrefix + name , ...rest } ) ) ) ;
745
766
}
746
767
return flatMap ( patterns , pattern => getModulesForPathsPattern ( remainingFragment , packageDirectory , pattern , extensionOptions , host ) ) ;
747
768
748
- function justPathMappingName ( name : string ) : readonly NameAndKind [ ] {
749
- return startsWith ( name , fragment ) ? [ directoryResult ( removeTrailingDirectorySeparator ( name ) ) ] : emptyArray ;
769
+ function justPathMappingName ( name : string , kind : ScriptElementKind . directory | ScriptElementKind . scriptElement ) : readonly NameAndKind [ ] {
770
+ return startsWith ( name , fragment ) ? [ { name : removeTrailingDirectorySeparator ( name ) , kind , extension : undefined } ] : emptyArray ;
750
771
}
751
772
}
752
773
@@ -789,12 +810,12 @@ namespace ts.Completions.StringCompletions {
789
810
const includeGlob = suffixHasFilename ? "**/*" : "./*" ;
790
811
791
812
const matches = mapDefined ( tryReadDirectory ( host , baseDirectory , extensionOptions . extensions , /*exclude*/ undefined , [ includeGlob ] ) , match => {
792
- const basename = trimPrefixAndSuffix ( match ) ;
793
- if ( basename ) {
794
- if ( containsSlash ( basename ) ) {
795
- return directoryResult ( getPathComponents ( basename ) [ 0 ] ) ;
813
+ const trimmedWithPattern = trimPrefixAndSuffix ( match ) ;
814
+ if ( trimmedWithPattern ) {
815
+ if ( containsSlash ( trimmedWithPattern ) ) {
816
+ return directoryResult ( getPathComponents ( trimmedWithPattern ) [ 0 ] ) ;
796
817
}
797
- const { name, extension } = getFilenameWithExtensionOption ( basename , host . getCompilationSettings ( ) , extensionOptions . includeExtensionsOption ) ;
818
+ const { name, extension } = getFilenameWithExtensionOption ( trimmedWithPattern , host . getCompilationSettings ( ) , extensionOptions . includeExtensionsOption ) ;
798
819
return nameAndKind ( name , ScriptElementKind . scriptElement , extension ) ;
799
820
}
800
821
} ) ;
@@ -858,7 +879,7 @@ namespace ts.Completions.StringCompletions {
858
879
return addReplacementSpans ( toComplete , range . pos + prefix . length , arrayFrom ( names . values ( ) ) ) ;
859
880
}
860
881
861
- function getCompletionEntriesFromTypings ( host : LanguageServiceHost , options : CompilerOptions , scriptPath : string , fragmentDirectory : string | undefined , extensionOptions : ExtensionOptions , result = createNameAndKindSet ( ) ) : Set < NameAndKind > {
882
+ function getCompletionEntriesFromTypings ( host : LanguageServiceHost , options : CompilerOptions , scriptPath : string , fragmentDirectory : string | undefined , extensionOptions : ExtensionOptions , result = createNameAndKindSet ( ) ) : NameAndKindSet {
862
883
// Check for typings specified in compiler options
863
884
const seen = new Map < string , true > ( ) ;
864
885
0 commit comments