2
2
namespace ts . Completions {
3
3
export enum SortText {
4
4
LocationPriority = "0" ,
5
- SuggestedClassMembers = "1" ,
6
- GlobalsOrKeywords = "2" ,
7
- AutoImportSuggestions = "3" ,
8
- JavascriptIdentifiers = "4"
5
+ OptionalMember = "1" ,
6
+ MemberDeclaredBySpreadAssignment = "2" ,
7
+ SuggestedClassMembers = "3" ,
8
+ GlobalsOrKeywords = "4" ,
9
+ AutoImportSuggestions = "5" ,
10
+ JavascriptIdentifiers = "6"
9
11
}
10
12
export type Log = ( message : string ) => void ;
11
13
@@ -1109,6 +1111,7 @@ namespace ts.Completions {
1109
1111
const attrsType = jsxContainer && typeChecker . getContextualType ( jsxContainer . attributes ) ;
1110
1112
if ( ! attrsType ) return GlobalsSearch . Continue ;
1111
1113
symbols = filterJsxAttributes ( getPropertiesForObjectExpression ( attrsType , jsxContainer ! . attributes , typeChecker ) , jsxContainer ! . attributes . properties ) ;
1114
+ setSortTextToOptionalMember ( ) ;
1112
1115
completionKind = CompletionKind . MemberLike ;
1113
1116
isNewIdentifierLocation = false ;
1114
1117
return GlobalsSearch . Success ;
@@ -1539,6 +1542,8 @@ namespace ts.Completions {
1539
1542
// Add filtered items to the completion list
1540
1543
symbols = filterObjectMembersList ( typeMembers , Debug . assertDefined ( existingMembers ) ) ;
1541
1544
}
1545
+ setSortTextToOptionalMember ( ) ;
1546
+
1542
1547
return GlobalsSearch . Success ;
1543
1548
}
1544
1549
@@ -1910,6 +1915,7 @@ namespace ts.Completions {
1910
1915
return contextualMemberSymbols ;
1911
1916
}
1912
1917
1918
+ const membersDeclaredBySpreadAssignment = createMap < true > ( ) ;
1913
1919
const existingMemberNames = createUnderscoreEscapedMap < boolean > ( ) ;
1914
1920
for ( const m of existingMembers ) {
1915
1921
// Ignore omitted expressions for missing members
@@ -1918,7 +1924,8 @@ namespace ts.Completions {
1918
1924
m . kind !== SyntaxKind . BindingElement &&
1919
1925
m . kind !== SyntaxKind . MethodDeclaration &&
1920
1926
m . kind !== SyntaxKind . GetAccessor &&
1921
- m . kind !== SyntaxKind . SetAccessor ) {
1927
+ m . kind !== SyntaxKind . SetAccessor &&
1928
+ m . kind !== SyntaxKind . SpreadAssignment ) {
1922
1929
continue ;
1923
1930
}
1924
1931
@@ -1929,7 +1936,10 @@ namespace ts.Completions {
1929
1936
1930
1937
let existingName : __String | undefined ;
1931
1938
1932
- if ( isBindingElement ( m ) && m . propertyName ) {
1939
+ if ( isSpreadAssignment ( m ) ) {
1940
+ setMembersDeclaredBySpreadAssignment ( m , membersDeclaredBySpreadAssignment ) ;
1941
+ }
1942
+ else if ( isBindingElement ( m ) && m . propertyName ) {
1933
1943
// include only identifiers in completion list
1934
1944
if ( m . propertyName . kind === SyntaxKind . Identifier ) {
1935
1945
existingName = m . propertyName . escapedText ;
@@ -1946,7 +1956,43 @@ namespace ts.Completions {
1946
1956
existingMemberNames . set ( existingName ! , true ) ; // TODO: GH#18217
1947
1957
}
1948
1958
1949
- return contextualMemberSymbols . filter ( m => ! existingMemberNames . get ( m . escapedName ) ) ;
1959
+ const filteredSymbols = contextualMemberSymbols . filter ( m => ! existingMemberNames . get ( m . escapedName ) ) ;
1960
+ setSortTextToMemberDeclaredBySpreadAssignment ( membersDeclaredBySpreadAssignment , filteredSymbols ) ;
1961
+
1962
+ return filteredSymbols ;
1963
+ }
1964
+
1965
+ function setMembersDeclaredBySpreadAssignment ( declaration : SpreadAssignment | JsxSpreadAttribute , membersDeclaredBySpreadAssignment : Map < true > ) {
1966
+ const expression = declaration . expression ;
1967
+ const symbol = typeChecker . getSymbolAtLocation ( expression ) ;
1968
+ const type = symbol && typeChecker . getTypeOfSymbolAtLocation ( symbol , expression ) ;
1969
+ const properties = type && ( < ObjectType > type ) . properties ;
1970
+ if ( properties ) {
1971
+ properties . forEach ( property => {
1972
+ membersDeclaredBySpreadAssignment . set ( property . name , true ) ;
1973
+ } ) ;
1974
+ }
1975
+ }
1976
+
1977
+ // Set SortText to OptionalMember if it is an optinoal member
1978
+ function setSortTextToOptionalMember ( ) {
1979
+ symbols . forEach ( m => {
1980
+ if ( m . flags & SymbolFlags . Optional ) {
1981
+ symbolToSortTextMap [ getSymbolId ( m ) ] = symbolToSortTextMap [ getSymbolId ( m ) ] || SortText . OptionalMember ;
1982
+ }
1983
+ } ) ;
1984
+ }
1985
+
1986
+ // Set SortText to MemberDeclaredBySpreadAssignment if it is fulfilled by spread assignment
1987
+ function setSortTextToMemberDeclaredBySpreadAssignment ( membersDeclaredBySpreadAssignment : Map < true > , contextualMemberSymbols : Symbol [ ] ) : void {
1988
+ if ( membersDeclaredBySpreadAssignment . size === 0 ) {
1989
+ return ;
1990
+ }
1991
+ for ( const contextualMemberSymbol of contextualMemberSymbols ) {
1992
+ if ( membersDeclaredBySpreadAssignment . has ( contextualMemberSymbol . name ) ) {
1993
+ symbolToSortTextMap [ getSymbolId ( contextualMemberSymbol ) ] = SortText . MemberDeclaredBySpreadAssignment ;
1994
+ }
1995
+ }
1950
1996
}
1951
1997
1952
1998
/**
@@ -2000,6 +2046,7 @@ namespace ts.Completions {
2000
2046
*/
2001
2047
function filterJsxAttributes ( symbols : Symbol [ ] , attributes : NodeArray < JsxAttribute | JsxSpreadAttribute > ) : Symbol [ ] {
2002
2048
const seenNames = createUnderscoreEscapedMap < boolean > ( ) ;
2049
+ const membersDeclaredBySpreadAssignment = createMap < true > ( ) ;
2003
2050
for ( const attr of attributes ) {
2004
2051
// If this is the current item we are editing right now, do not filter it out
2005
2052
if ( isCurrentlyEditingNode ( attr ) ) {
@@ -2009,9 +2056,15 @@ namespace ts.Completions {
2009
2056
if ( attr . kind === SyntaxKind . JsxAttribute ) {
2010
2057
seenNames . set ( attr . name . escapedText , true ) ;
2011
2058
}
2059
+ else if ( isJsxSpreadAttribute ( attr ) ) {
2060
+ setMembersDeclaredBySpreadAssignment ( attr , membersDeclaredBySpreadAssignment ) ;
2061
+ }
2012
2062
}
2063
+ const filteredSymbols = symbols . filter ( a => ! seenNames . get ( a . escapedName ) ) ;
2064
+
2065
+ setSortTextToMemberDeclaredBySpreadAssignment ( membersDeclaredBySpreadAssignment , filteredSymbols ) ;
2013
2066
2014
- return symbols . filter ( a => ! seenNames . get ( a . escapedName ) ) ;
2067
+ return filteredSymbols ;
2015
2068
}
2016
2069
2017
2070
function isCurrentlyEditingNode ( node : Node ) : boolean {
0 commit comments