11/* @internal */
22namespace ts . JsDoc {
3- const singleLineTemplate = { newText : "/** */" , caretOffset : 3 } ;
43 const jsDocTagNames = [
54 "augments" ,
65 "author" ,
@@ -197,9 +196,16 @@ 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
208+ * - type alias declarations
203209 *
204210 * Hosts should ideally check that:
205211 * - The line is all whitespace up to 'position' before performing the insertion.
@@ -225,19 +231,17 @@ namespace ts.JsDoc {
225231
226232 const commentOwnerInfo = getCommentOwnerInfo ( tokenAtPos ) ;
227233 if ( ! commentOwnerInfo ) {
228- // if climbing the tree did not find a declaration with parameters, complete to a single line comment
229- return singleLineTemplate ;
234+ return undefined ;
230235 }
231236 const { commentOwner, parameters } = commentOwnerInfo ;
232-
233- if ( commentOwner . kind === SyntaxKind . JsxText ) {
237+ if ( commentOwner . getStart ( ) < position ) {
234238 return undefined ;
235239 }
236240
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 ;
241+ if ( ! parameters || parameters . length === 0 ) {
242+ // if there are no parameters, just complete to a single line JSDoc comment
243+ const singleLineResult = "/** */" ;
244+ return { newText : singleLineResult , caretOffset : 3 } ;
241245 }
242246
243247 const posLineAndChar = sourceFile . getLineAndCharacterOfPosition ( position ) ;
@@ -247,11 +251,19 @@ namespace ts.JsDoc {
247251 const indentationStr = sourceFile . text . substr ( lineStart , posLineAndChar . character ) . replace ( / \S / i, ( ) => " " ) ;
248252 const isJavaScriptFile = hasJavaScriptFileExtension ( sourceFile . fileName ) ;
249253
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 ( "" ) ;
254+ let docParams = "" ;
255+ for ( let i = 0 ; i < parameters . length ; i ++ ) {
256+ const currentName = parameters [ i ] . name ;
257+ const paramName = currentName . kind === SyntaxKind . Identifier ?
258+ ( < Identifier > currentName ) . escapedText :
259+ "param" + i ;
260+ if ( isJavaScriptFile ) {
261+ docParams += `${ indentationStr } * @param {any} ${ paramName } ${ newLine } ` ;
262+ }
263+ else {
264+ docParams += `${ indentationStr } * @param ${ paramName } ${ newLine } ` ;
265+ }
266+ }
255267
256268 // A doc comment consists of the following
257269 // * The opening comment line
@@ -273,7 +285,7 @@ namespace ts.JsDoc {
273285
274286 interface CommentOwnerInfo {
275287 readonly commentOwner : Node ;
276- readonly parameters : ReadonlyArray < ParameterDeclaration > ;
288+ readonly parameters ? : ReadonlyArray < ParameterDeclaration > ;
277289 }
278290 function getCommentOwnerInfo ( tokenAtPos : Node ) : CommentOwnerInfo | undefined {
279291 for ( let commentOwner = tokenAtPos ; commentOwner ; commentOwner = commentOwner . parent ) {
@@ -285,18 +297,32 @@ namespace ts.JsDoc {
285297 const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature ;
286298 return { commentOwner, parameters } ;
287299
300+ case SyntaxKind . ClassDeclaration :
301+ case SyntaxKind . InterfaceDeclaration :
302+ case SyntaxKind . PropertySignature :
303+ case SyntaxKind . EnumDeclaration :
304+ case SyntaxKind . EnumMember :
305+ case SyntaxKind . TypeAliasDeclaration :
306+ return { commentOwner } ;
307+
288308 case SyntaxKind . VariableStatement : {
289309 const varStatement = < VariableStatement > commentOwner ;
290310 const varDeclarations = varStatement . declarationList . declarations ;
291311 const parameters = varDeclarations . length === 1 && varDeclarations [ 0 ] . initializer
292312 ? getParametersFromRightHandSideOfAssignment ( varDeclarations [ 0 ] . initializer )
293313 : undefined ;
294- return parameters ? { commentOwner, parameters } : undefined ;
314+ return { commentOwner, parameters } ;
295315 }
296316
297317 case SyntaxKind . SourceFile :
298318 return undefined ;
299319
320+ case SyntaxKind . ModuleDeclaration :
321+ // If in walking up the tree, we hit a a nested namespace declaration,
322+ // then we must be somewhere within a dotted namespace name; however we don't
323+ // want to give back a JSDoc template for the 'b' or 'c' in 'namespace a.b.c { }'.
324+ return commentOwner . parent . kind === SyntaxKind . ModuleDeclaration ? undefined : { commentOwner } ;
325+
300326 case SyntaxKind . BinaryExpression : {
301327 const be = commentOwner as BinaryExpression ;
302328 if ( getSpecialPropertyAssignmentKind ( be ) === ts . SpecialPropertyAssignmentKind . None ) {
@@ -305,11 +331,6 @@ namespace ts.JsDoc {
305331 const parameters = isFunctionLike ( be . right ) ? be . right . parameters : emptyArray ;
306332 return { commentOwner, parameters } ;
307333 }
308-
309- case SyntaxKind . JsxText : {
310- const parameters : ReadonlyArray < ParameterDeclaration > = emptyArray ;
311- return { commentOwner, parameters } ;
312- }
313334 }
314335 }
315336 }
0 commit comments