11/* @internal */
22namespace ts . JsDoc {
3- const singleLineTemplate = { newText : "/** */" , caretOffset : 3 } ;
43 const jsDocTagNames = [
54 "augments" ,
65 "author" ,
@@ -197,9 +196,15 @@ namespace ts.JsDoc {
197196 /**
198197 * Checks if position points to a valid position to add JSDoc comments, and if so,
199198 * returns the appropriate template. Otherwise returns an empty string.
200- * Invalid positions are
201- * - within comments, strings (including template literals and regex), and JSXText
202- * - within a token
199+ * Valid positions are
200+ * - outside of comments, statements, and expressions, and
201+ * - preceding a:
202+ * - function/constructor/method declaration
203+ * - class declarations
204+ * - variable statements
205+ * - namespace declarations
206+ * - interface declarations
207+ * - method signatures
203208 *
204209 * Hosts should ideally check that:
205210 * - The line is all whitespace up to 'position' before performing the insertion.
@@ -225,19 +230,17 @@ namespace ts.JsDoc {
225230
226231 const commentOwnerInfo = getCommentOwnerInfo ( tokenAtPos ) ;
227232 if ( ! commentOwnerInfo ) {
228- // if climbing the tree did not find a declaration with parameters, complete to a single line comment
229- return singleLineTemplate ;
233+ return undefined ;
230234 }
231235 const { commentOwner, parameters } = commentOwnerInfo ;
232-
233- if ( commentOwner . kind === SyntaxKind . JsxText ) {
236+ if ( commentOwner . getStart ( ) < position ) {
234237 return undefined ;
235238 }
236239
237- if ( commentOwner . getStart ( ) < position || parameters . length === 0 ) {
238- // if climbing the tree found a declaration with parameters but the request was made inside it
239- // or if there are no parameters, complete to a single line comment
240- return singleLineTemplate ;
240+ if ( ! parameters || parameters . length === 0 ) {
241+ // if there are no parameters, just complete to a single line JSDoc comment
242+ const singleLineResult = "/** */" ;
243+ return { newText : singleLineResult , caretOffset : 3 } ;
241244 }
242245
243246 const posLineAndChar = sourceFile . getLineAndCharacterOfPosition ( position ) ;
@@ -247,11 +250,19 @@ namespace ts.JsDoc {
247250 const indentationStr = sourceFile . text . substr ( lineStart , posLineAndChar . character ) . replace ( / \S / i, ( ) => " " ) ;
248251 const isJavaScriptFile = hasJavaScriptFileExtension ( sourceFile . fileName ) ;
249252
250- const docParams = parameters . map ( ( { name} , i ) => {
251- const nameText = isIdentifier ( name ) ? name . text : `param${ i } ` ;
252- const type = isJavaScriptFile ? "{any} " : "" ;
253- return `${ indentationStr } * @param ${ type } ${ nameText } ${ newLine } ` ;
254- } ) . join ( "" ) ;
253+ let docParams = "" ;
254+ for ( let i = 0 ; i < parameters . length ; i ++ ) {
255+ const currentName = parameters [ i ] . name ;
256+ const paramName = currentName . kind === SyntaxKind . Identifier ?
257+ ( < Identifier > currentName ) . escapedText :
258+ "param" + i ;
259+ if ( isJavaScriptFile ) {
260+ docParams += `${ indentationStr } * @param {any} ${ paramName } ${ newLine } ` ;
261+ }
262+ else {
263+ docParams += `${ indentationStr } * @param ${ paramName } ${ newLine } ` ;
264+ }
265+ }
255266
256267 // A doc comment consists of the following
257268 // * The opening comment line
@@ -273,7 +284,7 @@ namespace ts.JsDoc {
273284
274285 interface CommentOwnerInfo {
275286 readonly commentOwner : Node ;
276- readonly parameters : ReadonlyArray < ParameterDeclaration > ;
287+ readonly parameters ? : ReadonlyArray < ParameterDeclaration > ;
277288 }
278289 function getCommentOwnerInfo ( tokenAtPos : Node ) : CommentOwnerInfo | undefined {
279290 for ( let commentOwner = tokenAtPos ; commentOwner ; commentOwner = commentOwner . parent ) {
@@ -285,18 +296,32 @@ namespace ts.JsDoc {
285296 const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature ;
286297 return { commentOwner, parameters } ;
287298
299+ case SyntaxKind . ClassDeclaration :
300+ case SyntaxKind . InterfaceDeclaration :
301+ case SyntaxKind . PropertySignature :
302+ case SyntaxKind . EnumDeclaration :
303+ case SyntaxKind . EnumMember :
304+ case SyntaxKind . TypeAliasDeclaration :
305+ return { commentOwner } ;
306+
288307 case SyntaxKind . VariableStatement : {
289308 const varStatement = < VariableStatement > commentOwner ;
290309 const varDeclarations = varStatement . declarationList . declarations ;
291310 const parameters = varDeclarations . length === 1 && varDeclarations [ 0 ] . initializer
292311 ? getParametersFromRightHandSideOfAssignment ( varDeclarations [ 0 ] . initializer )
293312 : undefined ;
294- return parameters ? { commentOwner, parameters } : undefined ;
313+ return { commentOwner, parameters } ;
295314 }
296315
297316 case SyntaxKind . SourceFile :
298317 return undefined ;
299318
319+ case SyntaxKind . ModuleDeclaration :
320+ // If in walking up the tree, we hit a a nested namespace declaration,
321+ // then we must be somewhere within a dotted namespace name; however we don't
322+ // want to give back a JSDoc template for the 'b' or 'c' in 'namespace a.b.c { }'.
323+ return commentOwner . parent . kind === SyntaxKind . ModuleDeclaration ? undefined : { commentOwner } ;
324+
300325 case SyntaxKind . BinaryExpression : {
301326 const be = commentOwner as BinaryExpression ;
302327 if ( getSpecialPropertyAssignmentKind ( be ) === ts . SpecialPropertyAssignmentKind . None ) {
@@ -305,11 +330,6 @@ namespace ts.JsDoc {
305330 const parameters = isFunctionLike ( be . right ) ? be . right . parameters : emptyArray ;
306331 return { commentOwner, parameters } ;
307332 }
308-
309- case SyntaxKind . JsxText : {
310- const parameters : ReadonlyArray < ParameterDeclaration > = emptyArray ;
311- return { commentOwner, parameters } ;
312- }
313333 }
314334 }
315335 }
0 commit comments