@@ -7,31 +7,38 @@ export default (entries: ts.CompletionEntry[]) => {
7
7
const { node, program, c } = sharedCompletionContext
8
8
if ( ! c ( 'fixSuggestionsSorting' ) ) return
9
9
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
19
18
else if ( ts . isObjectBindingPattern ( node ) ) {
20
19
if ( ts . isVariableDeclaration ( node . parent ) ) {
21
20
const { initializer } = node . parent
22
21
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
25
24
}
26
25
}
27
- if ( ts . isParameter ( node . parent ) ) rightNode = node . parent . type
26
+ if ( ts . isParameter ( node . parent ) ) targetNode = node . parent . type
28
27
} 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
30
29
}
31
- if ( ! rightNode ) return
30
+ if ( ! targetNode ) return
32
31
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
+ }
35
42
// languageService.getSignatureHelpItems(fileName, position, {}))
36
43
if ( ! sourceProps ) return
37
44
// const entriesBySortText = groupBy(({ sortText }) => sortText, entries)
@@ -42,11 +49,17 @@ export default (entries: ts.CompletionEntry[]) => {
42
49
// if sortText first symbol is not a number, than most probably it was highlighted by IntelliCode, keep them high
43
50
const [ sortableEntries , notSortableEntries ] = partition ( entry => ! isNaN ( parseInt ( entry . sortText ) ) , interestedEntries )
44
51
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
+ }
45
58
// make sorted
46
59
const sortedEntries = sortableEntries
47
60
. sort ( ( a , b ) => {
48
- return sourceProps . indexOf ( a . name ) - sourceProps . indexOf ( b . name )
61
+ return getScore ( a ) - getScore ( b )
49
62
} )
50
- . map ( ( entry , i ) => ( { ...entry , sortText : String ( lowestSortText + i ) } ) )
63
+ . map ( ( entry , i ) => ( { ...entry /* sortText: String(lowestSortText + i) */ } ) )
51
64
return [ ...notSortableEntries , ...sortedEntries , ...notInterestedEntries ]
52
65
}
0 commit comments