@@ -132,6 +132,46 @@ namespace ts {
132132 let scanner : Scanner = createScanner ( ScriptTarget . Latest , /*skipTrivia*/ true ) ;
133133
134134 let emptyArray : any [ ] = [ ] ;
135+
136+ const jsDocTagNames = [
137+ "augments" ,
138+ "author" ,
139+ "argument" ,
140+ "borrows" ,
141+ "class" ,
142+ "constant" ,
143+ "constructor" ,
144+ "constructs" ,
145+ "default" ,
146+ "deprecated" ,
147+ "description" ,
148+ "event" ,
149+ "example" ,
150+ "extends" ,
151+ "field" ,
152+ "fileOverview" ,
153+ "function" ,
154+ "ignore" ,
155+ "inner" ,
156+ "lends" ,
157+ "link" ,
158+ "memberOf" ,
159+ "name" ,
160+ "namespace" ,
161+ "param" ,
162+ "private" ,
163+ "property" ,
164+ "public" ,
165+ "requires" ,
166+ "returns" ,
167+ "see" ,
168+ "since" ,
169+ "static" ,
170+ "throws" ,
171+ "type" ,
172+ "version"
173+ ] ;
174+ let jsDocCompletionEntries : CompletionEntry [ ] ;
135175
136176 function createNode ( kind : SyntaxKind , pos : number , end : number , flags : NodeFlags , parent ?: Node ) : NodeObject {
137177 let node = < NodeObject > new ( getNodeConstructor ( kind ) ) ( ) ;
@@ -2971,6 +3011,8 @@ namespace ts {
29713011 let sourceFile = getValidSourceFile ( fileName ) ;
29723012 let isJavaScriptFile = isJavaScript ( fileName ) ;
29733013
3014+ let isJsDocTagName = false ;
3015+
29743016 let start = new Date ( ) . getTime ( ) ;
29753017 let currentToken = getTokenAtPosition ( sourceFile , position ) ;
29763018 log ( "getCompletionData: Get current token: " + ( new Date ( ) . getTime ( ) - start ) ) ;
@@ -2981,8 +3023,44 @@ namespace ts {
29813023 log ( "getCompletionData: Is inside comment: " + ( new Date ( ) . getTime ( ) - start ) ) ;
29823024
29833025 if ( insideComment ) {
2984- log ( "Returning an empty list because completion was inside a comment." ) ;
2985- return undefined ;
3026+ // The current position is next to the '@' sign, when no tag name being provided yet.
3027+ // Provide a full list of tag names
3028+ if ( hasDocComment ( sourceFile , position ) && sourceFile . text . charCodeAt ( position - 1 ) === CharacterCodes . at ) {
3029+ isJsDocTagName = true ;
3030+ }
3031+
3032+ // Completion should work inside certain JsDoc tags. For example:
3033+ // /** @type {number | string } */
3034+ // Completion should work in the brackets
3035+ let insideJsDocTagExpression = false ;
3036+ let tag = getJsDocTagAtPosition ( sourceFile , position ) ;
3037+ if ( tag ) {
3038+ if ( tag . tagName . pos <= position && position <= tag . tagName . end ) {
3039+ isJsDocTagName = true ;
3040+ }
3041+
3042+ switch ( tag . kind ) {
3043+ case SyntaxKind . JSDocTypeTag :
3044+ case SyntaxKind . JSDocParameterTag :
3045+ case SyntaxKind . JSDocReturnTag :
3046+ let tagWithExpression = < JSDocTypeTag | JSDocParameterTag | JSDocReturnTag > tag ;
3047+ if ( tagWithExpression . typeExpression ) {
3048+ insideJsDocTagExpression = tagWithExpression . typeExpression . pos < position && position < tagWithExpression . typeExpression . end ;
3049+ }
3050+ break ;
3051+ }
3052+ }
3053+
3054+ if ( isJsDocTagName ) {
3055+ return { symbols : undefined , isMemberCompletion : false , isNewIdentifierLocation : false , location : undefined , isRightOfDot : false , isJsDocTagName } ;
3056+ }
3057+
3058+ if ( ! insideJsDocTagExpression ) {
3059+ // Proceed if the current position is in jsDoc tag expression; otherwise it is a normal
3060+ // comment or the plain text part of a jsDoc comment, so no completion should be available
3061+ log ( "Returning an empty list because completion was inside a regular comment or plain text part of a JsDoc comment." ) ;
3062+ return undefined ;
3063+ }
29863064 }
29873065
29883066 start = new Date ( ) . getTime ( ) ;
@@ -3068,7 +3146,7 @@ namespace ts {
30683146
30693147 log ( "getCompletionData: Semantic work: " + ( new Date ( ) . getTime ( ) - semanticStart ) ) ;
30703148
3071- return { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot : ( isRightOfDot || isRightOfOpenTag ) } ;
3149+ return { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot : ( isRightOfDot || isRightOfOpenTag ) , isJsDocTagName } ;
30723150
30733151 function getTypeScriptMemberSymbols ( ) : void {
30743152 // Right of dot member completion list
@@ -3708,9 +3786,14 @@ namespace ts {
37083786 return undefined ;
37093787 }
37103788
3711- let { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot } = completionData ;
3789+ let { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot, isJsDocTagName } = completionData ;
37123790
37133791 let entries : CompletionEntry [ ] ;
3792+ if ( isJsDocTagName ) {
3793+ // If the current position is a jsDoc tag name, only tag names should be provided for completion
3794+ return { isMemberCompletion : false , isNewIdentifierLocation : false , entries : getAllJsDocCompletionEntries ( ) } ;
3795+ }
3796+
37143797 if ( isRightOfDot && isJavaScript ( fileName ) ) {
37153798 entries = getCompletionEntriesFromSymbols ( symbols ) ;
37163799 addRange ( entries , getJavaScriptCompletionEntries ( ) ) ;
@@ -3724,7 +3807,7 @@ namespace ts {
37243807 }
37253808
37263809 // Add keywords if this is not a member completion list
3727- if ( ! isMemberCompletion ) {
3810+ if ( ! isMemberCompletion && ! isJsDocTagName ) {
37283811 addRange ( entries , keywordCompletions ) ;
37293812 }
37303813
@@ -3757,6 +3840,17 @@ namespace ts {
37573840 return entries ;
37583841 }
37593842
3843+ function getAllJsDocCompletionEntries ( ) : CompletionEntry [ ] {
3844+ return jsDocCompletionEntries || ( jsDocCompletionEntries = ts . map ( jsDocTagNames , tagName => {
3845+ return {
3846+ name : tagName ,
3847+ kind : ScriptElementKind . keyword ,
3848+ kindModifiers : "" ,
3849+ sortText : "0" ,
3850+ }
3851+ } ) ) ;
3852+ }
3853+
37603854 function createCompletionEntry ( symbol : Symbol , location : Node ) : CompletionEntry {
37613855 // Try to get a valid display name for this symbol, if we could not find one, then ignore it.
37623856 // We would like to only show things that can be added after a dot, so for instance numeric properties can
0 commit comments