@@ -232,22 +232,12 @@ namespace ts.Completions {
232
232
symbolToSortTextMap,
233
233
} = completionData ;
234
234
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
+ }
251
241
}
252
242
253
243
const entries : CompletionEntry [ ] = [ ] ;
@@ -335,6 +325,52 @@ namespace ts.Completions {
335
325
}
336
326
}
337
327
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
+
338
374
function getJSCompletionEntries (
339
375
sourceFile : SourceFile ,
340
376
position : number ,
0 commit comments