@@ -7,31 +7,38 @@ export default (entries: ts.CompletionEntry[]) => {
77 const { node, program, c } = sharedCompletionContext
88 if ( ! c ( 'fixSuggestionsSorting' ) ) return
99 if ( ! node ) return
10- // if (ts.isObjectLiteralExpression(node) && ts.isCallExpression(node.parent)) {
11- // const typeChecker = program.getTypeChecker()
12- // const type = typeChecker.getTypeAtLocation(node.parent)
13- // const callSignatures = type.getCallSignatures()
14- // }
15- let rightNode : ts . Node | undefined
16- const upperNode = ts . isIdentifier ( node ) ? node . parent : node
17- if ( ts . isObjectLiteralExpression ( node ) ) rightNode = node
18- if ( ts . isPropertyAccessExpression ( upperNode ) ) rightNode = upperNode . expression
10+ let targetNode : ts . Node | undefined
11+ let upperNode = ts . isIdentifier ( node ) ? node . parent : node
12+ if ( ts . isJsxAttributes ( upperNode ) ) upperNode = upperNode . parent
13+ if ( ts . isObjectLiteralExpression ( node ) ) targetNode = node
14+ const isJsxElem = ts . isJsxOpeningElement ( upperNode ) || ts . isJsxSelfClosingElement ( upperNode )
15+ if ( isJsxElem ) {
16+ targetNode = upperNode
17+ } else if ( ts . isPropertyAccessExpression ( upperNode ) ) targetNode = upperNode . expression
1918 else if ( ts . isObjectBindingPattern ( node ) ) {
2019 if ( ts . isVariableDeclaration ( node . parent ) ) {
2120 const { initializer } = node . parent
2221 if ( initializer ) {
23- if ( ts . isIdentifier ( initializer ) ) rightNode = initializer
24- if ( ts . isPropertyAccessExpression ( initializer ) ) rightNode = initializer . name
22+ if ( ts . isIdentifier ( initializer ) ) targetNode = initializer
23+ if ( ts . isPropertyAccessExpression ( initializer ) ) targetNode = initializer . name
2524 }
2625 }
27- if ( ts . isParameter ( node . parent ) ) rightNode = node . parent . type
26+ if ( ts . isParameter ( node . parent ) ) targetNode = node . parent . type
2827 } else if ( ts . isObjectLiteralExpression ( node ) && ts . isReturnStatement ( node . parent ) && ts . isArrowFunction ( node . parent . parent . parent ) ) {
29- rightNode = node . parent . parent . parent . type
28+ targetNode = node . parent . parent . parent . type
3029 }
31- if ( ! rightNode ) return
30+ if ( ! targetNode ) return
3231 const typeChecker = program . getTypeChecker ( )
33- const type = typeChecker . getContextualType ( rightNode as ts . Expression ) ?? typeChecker . getTypeAtLocation ( rightNode )
34- const sourceProps = getAllPropertiesOfType ( type , typeChecker ) ?. map ( ( { name } ) => name )
32+ let sourceProps : string [ ]
33+ if ( isJsxElem ) {
34+ const type = typeChecker . getContextualType ( ( node as ts . JsxOpeningElement ) . attributes )
35+ if ( ! type ) return
36+ // usually component own props defined first like interface Props extends ... {} or type A = Props & ..., but this is not a case with mui...
37+ sourceProps = ( type . isIntersection ( ) ? type . types . flatMap ( type => type . getProperties ( ) ) : type . getProperties ( ) ) . map ( symbol => symbol . name )
38+ } else {
39+ const type = typeChecker . getContextualType ( targetNode as ts . Expression ) ?? typeChecker . getTypeAtLocation ( targetNode )
40+ sourceProps = getAllPropertiesOfType ( type , typeChecker ) ?. map ( ( { name } ) => name )
41+ }
3542 // languageService.getSignatureHelpItems(fileName, position, {}))
3643 if ( ! sourceProps ) return
3744 // const entriesBySortText = groupBy(({ sortText }) => sortText, entries)
@@ -42,11 +49,17 @@ export default (entries: ts.CompletionEntry[]) => {
4249 // if sortText first symbol is not a number, than most probably it was highlighted by IntelliCode, keep them high
4350 const [ sortableEntries , notSortableEntries ] = partition ( entry => ! isNaN ( parseInt ( entry . sortText ) ) , interestedEntries )
4451 const lowestSortText = Math . min ( ...sortableEntries . map ( ( { sortText } ) => parseInt ( sortText ) ) )
52+ const getScore = ( completion : ts . CompletionEntry ) => {
53+ return (
54+ sourceProps . indexOf ( completion . name ) +
55+ ( isJsxElem && ( completion [ 'symbol' ] as ts . Symbol | undefined ) ?. declarations ?. [ 0 ] ?. getSourceFile ( ) . fileName . includes ( '@types/react' ) ? 10_000 : 0 )
56+ )
57+ }
4558 // make sorted
4659 const sortedEntries = sortableEntries
4760 . sort ( ( a , b ) => {
48- return sourceProps . indexOf ( a . name ) - sourceProps . indexOf ( b . name )
61+ return getScore ( a ) - getScore ( b )
4962 } )
50- . map ( ( entry , i ) => ( { ...entry , sortText : String ( lowestSortText + i ) } ) )
63+ . map ( ( entry , i ) => ( { ...entry /* sortText: String(lowestSortText + i) */ } ) )
5164 return [ ...notSortableEntries , ...sortedEntries , ...notInterestedEntries ]
5265}
0 commit comments