@@ -3011,6 +3011,7 @@ namespace ts {
3011
3011
3012
3012
function tryGetGlobalSymbols ( ) : boolean {
3013
3013
let objectLikeContainer = tryGetObjectLikeCompletionContainer ( contextToken ) ;
3014
+ let jsxContainer = tryGetContainingJsxElement ( contextToken ) ;
3014
3015
if ( objectLikeContainer ) {
3015
3016
// Object literal expression, look up possible property names from contextual type
3016
3017
isMemberCompletion = true ;
@@ -3061,30 +3062,19 @@ namespace ts {
3061
3062
}
3062
3063
return true ;
3063
3064
}
3064
- else if ( getAncestor ( contextToken , SyntaxKind . JsxElement ) || getAncestor ( contextToken , SyntaxKind . JsxSelfClosingElement ) ) {
3065
- // Go up until we hit either the element or expression
3066
- let jsxNode = contextToken ;
3065
+ else if ( jsxContainer ) {
3066
+ let attrsType : Type ;
3067
+ if ( ( jsxContainer . kind === SyntaxKind . JsxSelfClosingElement ) || ( jsxContainer . kind === SyntaxKind . JsxOpeningElement ) ) {
3068
+ // Cursor is inside a JSX self-closing element or opening element
3069
+ attrsType = typeChecker . getJsxElementAttributesType ( < JsxOpeningLikeElement > jsxContainer ) ;
3067
3070
3068
- while ( jsxNode ) {
3069
- if ( jsxNode . kind === SyntaxKind . JsxExpression ) {
3070
- // Defer to global completion if we're inside an {expression}
3071
- break ;
3072
- } else if ( jsxNode . kind === SyntaxKind . JsxSelfClosingElement || jsxNode . kind === SyntaxKind . JsxElement ) {
3073
- let attrsType : Type ;
3074
- if ( jsxNode . kind === SyntaxKind . JsxSelfClosingElement ) {
3075
- // Cursor is inside a JSX self-closing element
3076
- attrsType = typeChecker . getJsxElementAttributesType ( < JsxSelfClosingElement > jsxNode ) ;
3077
- }
3078
- else {
3079
- Debug . assert ( jsxNode . kind === SyntaxKind . JsxElement ) ;
3080
- // Cursor is inside a JSX element
3081
- attrsType = typeChecker . getJsxElementAttributesType ( ( < JsxElement > jsxNode ) . openingElement ) ;
3082
- }
3083
- symbols = typeChecker . getPropertiesOfType ( attrsType ) ;
3071
+ if ( attrsType ) {
3072
+ symbols = filterJsxAttributes ( ( < JsxOpeningLikeElement > jsxContainer ) . attributes , typeChecker . getPropertiesOfType ( attrsType ) ) ;
3084
3073
isMemberCompletion = true ;
3074
+ isNewIdentifierLocation = false ;
3085
3075
return true ;
3086
3076
}
3087
- jsxNode = jsxNode . parent ;
3077
+
3088
3078
}
3089
3079
}
3090
3080
@@ -3270,6 +3260,36 @@ namespace ts {
3270
3260
return undefined ;
3271
3261
}
3272
3262
3263
+ function tryGetContainingJsxElement ( contextToken : Node ) : JsxOpeningLikeElement {
3264
+ if ( contextToken ) {
3265
+ let parent = contextToken . parent ;
3266
+ switch ( contextToken . kind ) {
3267
+ case SyntaxKind . LessThanSlashToken :
3268
+ case SyntaxKind . SlashToken :
3269
+ case SyntaxKind . Identifier :
3270
+ if ( parent && ( parent . kind === SyntaxKind . JsxSelfClosingElement || parent . kind === SyntaxKind . JsxOpeningElement ) ) {
3271
+ return < JsxOpeningLikeElement > parent ;
3272
+ }
3273
+ break ;
3274
+
3275
+ case SyntaxKind . CloseBraceToken :
3276
+ // The context token is the closing } of an attribute, which means
3277
+ // its parent is a JsxExpression, whose parent is a JsxAttribute,
3278
+ // whose parent is a JsxOpeningLikeElement
3279
+ if ( parent &&
3280
+ parent . kind === SyntaxKind . JsxExpression &&
3281
+ parent . parent &&
3282
+ parent . parent . kind === SyntaxKind . JsxAttribute ) {
3283
+
3284
+ return < JsxOpeningLikeElement > parent . parent . parent ;
3285
+ }
3286
+
3287
+ break ;
3288
+ }
3289
+ }
3290
+ return undefined ;
3291
+ }
3292
+
3273
3293
function isFunction ( kind : SyntaxKind ) : boolean {
3274
3294
switch ( kind ) {
3275
3295
case SyntaxKind . FunctionExpression :
@@ -3455,6 +3475,22 @@ namespace ts {
3455
3475
}
3456
3476
}
3457
3477
3478
+ function filterJsxAttributes ( attributes : NodeArray < JsxAttribute | JsxSpreadAttribute > , symbols : Symbol [ ] ) : Symbol [ ] {
3479
+ let seenNames : Map < boolean > = { } ;
3480
+ for ( let attr of attributes ) {
3481
+ if ( attr . kind === SyntaxKind . JsxAttribute ) {
3482
+ seenNames [ ( < JsxAttribute > attr ) . name . text ] = true ;
3483
+ }
3484
+ }
3485
+ let result : Symbol [ ] = [ ] ;
3486
+ for ( let sym of symbols ) {
3487
+ if ( ! seenNames [ sym . name ] ) {
3488
+ result . push ( sym ) ;
3489
+ }
3490
+ }
3491
+ return result ;
3492
+ }
3493
+
3458
3494
function getCompletionsAtPosition ( fileName : string , position : number ) : CompletionInfo {
3459
3495
synchronizeHostData ( ) ;
3460
3496
0 commit comments