@@ -165,7 +165,7 @@ namespace ts.Completions {
165165 isJsxInitializer ,
166166 recommendedCompletion ,
167167 symbolToOriginInfoMap ,
168- symbolToSortTextMap ,
168+ symbolToSortTextMap
169169 ) ;
170170 }
171171
@@ -926,7 +926,7 @@ namespace ts.Completions {
926926 previousToken,
927927 isJsxInitializer,
928928 insideJsDocTagTypeExpression,
929- symbolToSortTextMap,
929+ symbolToSortTextMap
930930 } ;
931931
932932 type JSDocTagWithTypeExpression = JSDocParameterTag | JSDocPropertyTag | JSDocReturnTag | JSDocTypeTag | JSDocTypedefTag ;
@@ -985,6 +985,7 @@ namespace ts.Completions {
985985 symbol . declarations . some ( d => d . kind !== SyntaxKind . SourceFile && d . kind !== SyntaxKind . ModuleDeclaration && d . kind !== SyntaxKind . EnumDeclaration ) ) {
986986 addTypeProperties ( typeChecker . getTypeOfSymbolAtLocation ( symbol , node ) ) ;
987987 }
988+ setSortTextToOptionalMember ( ) ;
988989
989990 return ;
990991 }
@@ -994,11 +995,13 @@ namespace ts.Completions {
994995 if ( isMetaProperty ( node ) && ( node . keywordToken === SyntaxKind . NewKeyword || node . keywordToken === SyntaxKind . ImportKeyword ) ) {
995996 const completion = ( node . keywordToken === SyntaxKind . NewKeyword ) ? "target" : "meta" ;
996997 symbols . push ( typeChecker . createSymbol ( SymbolFlags . Property , escapeLeadingUnderscores ( completion ) ) ) ;
998+ setSortTextToOptionalMember ( ) ;
997999 return ;
9981000 }
9991001
10001002 if ( ! isTypeLocation ) {
10011003 addTypeProperties ( typeChecker . getTypeAtLocation ( node ) ) ;
1004+ setSortTextToOptionalMember ( ) ;
10021005 }
10031006 }
10041007
@@ -1079,6 +1082,7 @@ namespace ts.Completions {
10791082 const attrsType = jsxContainer && typeChecker . getContextualType ( jsxContainer . attributes ) ;
10801083 if ( ! attrsType ) return GlobalsSearch . Continue ;
10811084 symbols = filterJsxAttributes ( getPropertiesForObjectExpression ( attrsType , jsxContainer ! . attributes , typeChecker ) , jsxContainer ! . attributes . properties ) ;
1085+ setSortTextToOptionalMember ( ) ;
10821086 completionKind = CompletionKind . MemberLike ;
10831087 isNewIdentifierLocation = false ;
10841088 return GlobalsSearch . Success ;
@@ -1586,6 +1590,7 @@ namespace ts.Completions {
15861590 return type && typeChecker . getPropertiesOfType ( classElementModifierFlags & ModifierFlags . Static ? typeChecker . getTypeOfSymbolAtLocation ( type . symbol , decl ) : type ) ;
15871591 } ) ;
15881592 symbols = filterClassMembersList ( baseSymbols , decl . members , classElementModifierFlags ) ;
1593+ setSortTextToOptionalMember ( ) ;
15891594 }
15901595
15911596 return GlobalsSearch . Success ;
@@ -1879,7 +1884,7 @@ namespace ts.Completions {
18791884 return contextualMemberSymbols ;
18801885 }
18811886
1882- const fulfilledSymbols : Symbol [ ] = [ ] ;
1887+ const membersDeclaredBySpreadAssignment : Symbol [ ] = [ ] ;
18831888 const existingMemberNames = createUnderscoreEscapedMap < boolean > ( ) ;
18841889 for ( const m of existingMembers ) {
18851890 // Ignore omitted expressions for missing members
@@ -1906,7 +1911,7 @@ namespace ts.Completions {
19061911 const type = symbol && typeChecker . getTypeOfSymbolAtLocation ( symbol , expression ) ;
19071912 const properties = type && ( < ObjectType > type ) . properties ;
19081913 if ( properties ) {
1909- fulfilledSymbols . push ( ...properties ) ;
1914+ membersDeclaredBySpreadAssignment . push ( ...properties ) ;
19101915 }
19111916 }
19121917 else if ( isBindingElement ( m ) && m . propertyName ) {
@@ -1927,17 +1932,20 @@ namespace ts.Completions {
19271932 }
19281933
19291934 const filteredSymbols = contextualMemberSymbols . filter ( m => ! existingMemberNames . get ( m . escapedName ) ) ;
1935+ setSortTextToMemberDeclaredBySpreadAssignment ( membersDeclaredBySpreadAssignment , contextualMemberSymbols ) ;
1936+
1937+ return filteredSymbols ;
1938+ }
19301939
1931- // Set SortText to MemberDeclaredBySpreadAssignment if it is fulfilled by spread assignment
1932- for ( const fulfilledSymbol of fulfilledSymbols ) {
1933- for ( const contextualMemberSymbol of filteredSymbols ) {
1940+ // Set SortText to MemberDeclaredBySpreadAssignment if it is fulfilled by spread assignment
1941+ function setSortTextToMemberDeclaredBySpreadAssignment ( membersDeclaredBySpreadAssignment : Symbol [ ] , contextualMemberSymbols : Symbol [ ] ) : void {
1942+ for ( const fulfilledSymbol of membersDeclaredBySpreadAssignment ) {
1943+ for ( const contextualMemberSymbol of contextualMemberSymbols ) {
19341944 if ( contextualMemberSymbol . name === fulfilledSymbol . name ) {
19351945 symbolToSortTextMap [ getSymbolId ( contextualMemberSymbol ) ] = SortText . MemberDeclaredBySpreadAssignment ;
19361946 }
19371947 }
19381948 }
1939-
1940- return filteredSymbols ;
19411949 }
19421950
19431951 /**
@@ -1991,6 +1999,7 @@ namespace ts.Completions {
19911999 */
19922000 function filterJsxAttributes ( symbols : Symbol [ ] , attributes : NodeArray < JsxAttribute | JsxSpreadAttribute > ) : Symbol [ ] {
19932001 const seenNames = createUnderscoreEscapedMap < boolean > ( ) ;
2002+ const membersDeclaredBySpreadAssignment : Symbol [ ] = [ ] ;
19942003 for ( const attr of attributes ) {
19952004 // If this is the current item we are editing right now, do not filter it out
19962005 if ( isCurrentlyEditingNode ( attr ) ) {
@@ -2000,9 +2009,21 @@ namespace ts.Completions {
20002009 if ( attr . kind === SyntaxKind . JsxAttribute ) {
20012010 seenNames . set ( attr . name . escapedText , true ) ;
20022011 }
2012+ else if ( isJsxSpreadAttribute ( attr ) ) {
2013+ const expression = attr . expression ;
2014+ const symbol = typeChecker . getSymbolAtLocation ( expression ) ;
2015+ const type = symbol && typeChecker . getTypeOfSymbolAtLocation ( symbol , expression ) ;
2016+ const properties = type && ( < ObjectType > type ) . properties ;
2017+ if ( properties ) {
2018+ membersDeclaredBySpreadAssignment . push ( ...properties ) ;
2019+ }
2020+ }
20032021 }
2022+ const filteredSymbols = symbols . filter ( a => ! seenNames . get ( a . escapedName ) ) ;
20042023
2005- return symbols . filter ( a => ! seenNames . get ( a . escapedName ) ) ;
2024+ setSortTextToMemberDeclaredBySpreadAssignment ( membersDeclaredBySpreadAssignment , symbols ) ;
2025+
2026+ return filteredSymbols ;
20062027 }
20072028
20082029 function isCurrentlyEditingNode ( node : Node ) : boolean {
0 commit comments