22namespace ts . Completions {
33 export enum SortText {
44 LocationPriority = "0" ,
5- LocationPriorityOptional = "1" ,
6- LocationPriorityFulfilled = "2" ,
5+ OptionalMember = "1" ,
6+ MemberDeclaredBySpreadAssignment = "2" ,
77 SuggestedClassMembers = "3" ,
88 GlobalsOrKeywords = "4" ,
99 AutoImportSuggestions = "5" ,
@@ -105,7 +105,6 @@ namespace ts.Completions {
105105 isJsxInitializer,
106106 insideJsDocTagTypeExpression,
107107 symbolToSortTextMap,
108- fulfilledSymbols,
109108 } = completionData ;
110109
111110 if ( location && location . parent && isJsxClosingElement ( location . parent ) ) {
@@ -167,7 +166,6 @@ namespace ts.Completions {
167166 recommendedCompletion ,
168167 symbolToOriginInfoMap ,
169168 symbolToSortTextMap ,
170- fulfilledSymbols
171169 ) ;
172170 }
173171
@@ -321,7 +319,6 @@ namespace ts.Completions {
321319 recommendedCompletion ?: Symbol ,
322320 symbolToOriginInfoMap ?: SymbolOriginInfoMap ,
323321 symbolToSortTextMap ?: SymbolSortTextMap ,
324- fulfilledSymbols ?: ReadonlyArray < Symbol > ,
325322 ) : Map < true > {
326323 const start = timestamp ( ) ;
327324 // Tracks unique names.
@@ -340,23 +337,9 @@ namespace ts.Completions {
340337 continue ;
341338 }
342339
343- let sortText = symbolToSortTextMap && symbolToSortTextMap [ getSymbolId ( symbol ) ] ;
344- if ( ! sortText ) {
345- if ( fulfilledSymbols && fulfilledSymbols . length > 0 ) {
346- fulfilledSymbols . forEach ( fulfilledSymbol => {
347- if ( fulfilledSymbol . name === symbol . name ) {
348- sortText = SortText . LocationPriorityFulfilled ;
349- }
350- } ) ;
351- }
352- }
353- if ( ! sortText ) {
354- sortText = SymbolDisplay . getSymbolModifiers ( symbol ) === "optional" ? SortText . LocationPriorityOptional : SortText . LocationPriority ;
355- }
356-
357340 const entry = createCompletionEntry (
358341 symbol ,
359- sortText ,
342+ symbolToSortTextMap && symbolToSortTextMap [ getSymbolId ( symbol ) ] || SortText . LocationPriority ,
360343 location ,
361344 sourceFile ,
362345 typeChecker ,
@@ -366,7 +349,7 @@ namespace ts.Completions {
366349 recommendedCompletion ,
367350 propertyAccessToConvert ,
368351 isJsxInitializer ,
369- preferences ,
352+ preferences
370353 ) ;
371354 if ( ! entry ) {
372355 continue ;
@@ -600,7 +583,6 @@ namespace ts.Completions {
600583 readonly isJsxInitializer : IsJsxInitializer ;
601584 readonly insideJsDocTagTypeExpression : boolean ;
602585 readonly symbolToSortTextMap : SymbolSortTextMap ;
603- readonly fulfilledSymbols ?: ReadonlyArray < Symbol > ;
604586 }
605587 type Request = { readonly kind : CompletionDataKind . JsDocTagName | CompletionDataKind . JsDocTag } | { readonly kind : CompletionDataKind . JsDocParameterName , tag : JSDocParameterTag } ;
606588
@@ -892,7 +874,6 @@ namespace ts.Completions {
892874 let isNewIdentifierLocation = false ;
893875 let keywordFilters = KeywordCompletionFilters . None ;
894876 let symbols : Symbol [ ] = [ ] ;
895- let fulfilledSymbols : Symbol [ ] | undefined = [ ] ;
896877 const symbolToOriginInfoMap : SymbolOriginInfoMap = [ ] ;
897878 const symbolToSortTextMap : SymbolSortTextMap = [ ] ;
898879
@@ -946,7 +927,6 @@ namespace ts.Completions {
946927 isJsxInitializer,
947928 insideJsDocTagTypeExpression,
948929 symbolToSortTextMap,
949- fulfilledSymbols
950930 } ;
951931
952932 type JSDocTagWithTypeExpression = JSDocParameterTag | JSDocPropertyTag | JSDocReturnTag | JSDocTypeTag | JSDocTypedefTag ;
@@ -1516,20 +1496,21 @@ namespace ts.Completions {
15161496 if ( typeMembers && typeMembers . length > 0 ) {
15171497 // Add filtered items to the completion list
15181498 symbols = filterObjectMembersList ( typeMembers , Debug . assertDefined ( existingMembers ) ) ;
1519- if ( existingMembers && existingMembers . length > 0 ) {
1520- existingMembers . forEach ( member => {
1521- if ( member . kind === SyntaxKind . SpreadAssignment ) {
1522- const expression = ( < SpreadAssignment > member ) . expression ;
1523- const symbol = typeChecker . getSymbolAtLocation ( expression ) ;
1524- const type = symbol && typeChecker . getTypeOfSymbolAtLocation ( symbol , expression ) ;
1525- fulfilledSymbols = type && ( < ObjectType > type ) . properties ;
1526- }
1527- } ) ;
1528- }
15291499 }
1500+ setSortTextToOptionalMember ( ) ;
1501+
15301502 return GlobalsSearch . Success ;
15311503 }
15321504
1505+ // Set SortText to OptionalMember if it is an optinoal member
1506+ function setSortTextToOptionalMember ( ) {
1507+ symbols . forEach ( m => {
1508+ if ( SymbolDisplay . getSymbolModifiers ( m ) === "optional" ) {
1509+ symbolToSortTextMap [ getSymbolId ( m ) ] = symbolToSortTextMap [ getSymbolId ( m ) ] || SortText . OptionalMember ;
1510+ }
1511+ } ) ;
1512+ }
1513+
15331514 /**
15341515 * Aggregates relevant symbols for completion in import clauses and export clauses
15351516 * whose declarations have a module specifier; for instance, symbols will be aggregated for
@@ -1898,6 +1879,7 @@ namespace ts.Completions {
18981879 return contextualMemberSymbols ;
18991880 }
19001881
1882+ const fulfilledSymbols : Symbol [ ] = [ ] ;
19011883 const existingMemberNames = createUnderscoreEscapedMap < boolean > ( ) ;
19021884 for ( const m of existingMembers ) {
19031885 // Ignore omitted expressions for missing members
@@ -1906,7 +1888,8 @@ namespace ts.Completions {
19061888 m . kind !== SyntaxKind . BindingElement &&
19071889 m . kind !== SyntaxKind . MethodDeclaration &&
19081890 m . kind !== SyntaxKind . GetAccessor &&
1909- m . kind !== SyntaxKind . SetAccessor ) {
1891+ m . kind !== SyntaxKind . SetAccessor &&
1892+ m . kind !== SyntaxKind . SpreadAssignment ) {
19101893 continue ;
19111894 }
19121895
@@ -1917,7 +1900,16 @@ namespace ts.Completions {
19171900
19181901 let existingName : __String | undefined ;
19191902
1920- if ( isBindingElement ( m ) && m . propertyName ) {
1903+ if ( isSpreadAssignment ( m ) ) {
1904+ const expression = m . expression ;
1905+ const symbol = typeChecker . getSymbolAtLocation ( expression ) ;
1906+ const type = symbol && typeChecker . getTypeOfSymbolAtLocation ( symbol , expression ) ;
1907+ const properties = type && ( < ObjectType > type ) . properties ;
1908+ if ( properties ) {
1909+ fulfilledSymbols . push ( ...properties ) ;
1910+ }
1911+ }
1912+ else if ( isBindingElement ( m ) && m . propertyName ) {
19211913 // include only identifiers in completion list
19221914 if ( m . propertyName . kind === SyntaxKind . Identifier ) {
19231915 existingName = m . propertyName . escapedText ;
@@ -1934,7 +1926,18 @@ namespace ts.Completions {
19341926 existingMemberNames . set ( existingName ! , true ) ; // TODO: GH#18217
19351927 }
19361928
1937- return contextualMemberSymbols . filter ( m => ! existingMemberNames . get ( m . escapedName ) ) ;
1929+ const filteredSymbols = contextualMemberSymbols . filter ( m => ! existingMemberNames . get ( m . escapedName ) ) ;
1930+
1931+ // Set SortText to MemberDeclaredBySpreadAssignment if it is fulfilled by spread assignment
1932+ for ( const fulfilledSymbol of fulfilledSymbols ) {
1933+ for ( const contextualMemberSymbol of filteredSymbols ) {
1934+ if ( contextualMemberSymbol . name === fulfilledSymbol . name ) {
1935+ symbolToSortTextMap [ getSymbolId ( contextualMemberSymbol ) ] = SortText . MemberDeclaredBySpreadAssignment ;
1936+ }
1937+ }
1938+ }
1939+
1940+ return filteredSymbols ;
19381941 }
19391942
19401943 /**
0 commit comments