@@ -232,22 +232,12 @@ namespace ts.Completions {
232232 symbolToSortTextMap,
233233 } = completionData ;
234234
235- if ( location && location . parent && isJsxClosingElement ( location . parent ) ) {
236- // In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
237- // instead of simply giving unknown value, the completion will return the tag-name of an associated opening-element.
238- // For example:
239- // var x = <div> </ /*1*/
240- // The completion list at "1" will contain "div>" with type any
241- // And at `<div> </ /*1*/ >` (with a closing `>`), the completion list will contain "div".
242- const tagName = location . parent . parent . openingElement . tagName ;
243- const hasClosingAngleBracket = ! ! findChildOfKind ( location . parent , SyntaxKind . GreaterThanToken , sourceFile ) ;
244- const entry : CompletionEntry = {
245- name : tagName . getFullText ( sourceFile ) + ( hasClosingAngleBracket ? "" : ">" ) ,
246- kind : ScriptElementKind . classElement ,
247- kindModifiers : undefined ,
248- sortText : SortText . LocationPriority ,
249- } ;
250- return { isGlobalCompletion : false , isMemberCompletion : true , isNewIdentifierLocation : false , optionalReplacementSpan : getOptionalReplacementSpan ( location ) , entries : [ entry ] } ;
235+ // Verify if the file is JSX language variant
236+ if ( getLanguageVariant ( sourceFile . scriptKind ) === LanguageVariant . JSX ) {
237+ const completionInfo = getJsxClosingTagCompletion ( location , sourceFile ) ;
238+ if ( completionInfo ) {
239+ return completionInfo ;
240+ }
251241 }
252242
253243 const entries : CompletionEntry [ ] = [ ] ;
@@ -335,6 +325,52 @@ namespace ts.Completions {
335325 }
336326 }
337327
328+ function getJsxClosingTagCompletion ( location : Node | undefined , sourceFile : SourceFile ) : CompletionInfo | undefined {
329+ // We wanna walk up the tree till we find a JSX closing element
330+ const jsxClosingElement = findAncestor ( location , node => {
331+ switch ( node . kind ) {
332+ case SyntaxKind . JsxClosingElement :
333+ return true ;
334+ case SyntaxKind . SlashToken :
335+ case SyntaxKind . GreaterThanToken :
336+ case SyntaxKind . Identifier :
337+ case SyntaxKind . PropertyAccessExpression :
338+ return false ;
339+ default :
340+ return "quit" ;
341+ }
342+ } ) as JsxClosingElement | undefined ;
343+
344+ if ( jsxClosingElement ) {
345+ // In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
346+ // instead of simply giving unknown value, the completion will return the tag-name of an associated opening-element.
347+ // For example:
348+ // var x = <div> </ /*1*/
349+ // The completion list at "1" will contain "div>" with type any
350+ // And at `<div> </ /*1*/ >` (with a closing `>`), the completion list will contain "div".
351+ // And at property access expressions `<MainComponent.Child> </MainComponent. /*1*/ >` the completion will
352+ // return full closing tag with an optional replacement span
353+ // For example:
354+ // var x = <MainComponent.Child> </ MainComponent /*1*/ >
355+ // var y = <MainComponent.Child> </ /*2*/ MainComponent >
356+ // the completion list at "1" and "2" will contain "MainComponent.Child" with a replacement span of closing tag name
357+ const hasClosingAngleBracket = ! ! findChildOfKind ( jsxClosingElement , SyntaxKind . GreaterThanToken , sourceFile ) ;
358+ const tagName = jsxClosingElement . parent . openingElement . tagName ;
359+ const closingTag = tagName . getText ( sourceFile ) ;
360+ const fullClosingTag = closingTag + ( hasClosingAngleBracket ? "" : ">" ) ;
361+ const replacementSpan = createTextSpanFromNode ( jsxClosingElement . tagName ) ;
362+
363+ const entry : CompletionEntry = {
364+ name : fullClosingTag ,
365+ kind : ScriptElementKind . classElement ,
366+ kindModifiers : undefined ,
367+ sortText : SortText . LocationPriority ,
368+ } ;
369+ return { isGlobalCompletion : false , isMemberCompletion : true , isNewIdentifierLocation : false , optionalReplacementSpan : replacementSpan , entries : [ entry ] } ;
370+ }
371+ return ;
372+ }
373+
338374 function getJSCompletionEntries (
339375 sourceFile : SourceFile ,
340376 position : number ,
0 commit comments