1
1
/* @internal */
2
2
namespace ts . JsDoc {
3
- const singleLineTemplate = { newText : "/** */" , caretOffset : 3 } ;
4
3
const jsDocTagNames = [
5
4
"augments" ,
6
5
"author" ,
@@ -197,9 +196,16 @@ namespace ts.JsDoc {
197
196
/**
198
197
* Checks if position points to a valid position to add JSDoc comments, and if so,
199
198
* 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
203
209
*
204
210
* Hosts should ideally check that:
205
211
* - The line is all whitespace up to 'position' before performing the insertion.
@@ -225,19 +231,17 @@ namespace ts.JsDoc {
225
231
226
232
const commentOwnerInfo = getCommentOwnerInfo ( tokenAtPos ) ;
227
233
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 ;
230
235
}
231
236
const { commentOwner, parameters } = commentOwnerInfo ;
232
-
233
- if ( commentOwner . kind === SyntaxKind . JsxText ) {
237
+ if ( commentOwner . getStart ( ) < position ) {
234
238
return undefined ;
235
239
}
236
240
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 } ;
241
245
}
242
246
243
247
const posLineAndChar = sourceFile . getLineAndCharacterOfPosition ( position ) ;
@@ -247,11 +251,19 @@ namespace ts.JsDoc {
247
251
const indentationStr = sourceFile . text . substr ( lineStart , posLineAndChar . character ) . replace ( / \S / i, ( ) => " " ) ;
248
252
const isJavaScriptFile = hasJavaScriptFileExtension ( sourceFile . fileName ) ;
249
253
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
+ }
255
267
256
268
// A doc comment consists of the following
257
269
// * The opening comment line
@@ -273,7 +285,7 @@ namespace ts.JsDoc {
273
285
274
286
interface CommentOwnerInfo {
275
287
readonly commentOwner : Node ;
276
- readonly parameters : ReadonlyArray < ParameterDeclaration > ;
288
+ readonly parameters ? : ReadonlyArray < ParameterDeclaration > ;
277
289
}
278
290
function getCommentOwnerInfo ( tokenAtPos : Node ) : CommentOwnerInfo | undefined {
279
291
for ( let commentOwner = tokenAtPos ; commentOwner ; commentOwner = commentOwner . parent ) {
@@ -285,18 +297,32 @@ namespace ts.JsDoc {
285
297
const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature ;
286
298
return { commentOwner, parameters } ;
287
299
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
+
288
308
case SyntaxKind . VariableStatement : {
289
309
const varStatement = < VariableStatement > commentOwner ;
290
310
const varDeclarations = varStatement . declarationList . declarations ;
291
311
const parameters = varDeclarations . length === 1 && varDeclarations [ 0 ] . initializer
292
312
? getParametersFromRightHandSideOfAssignment ( varDeclarations [ 0 ] . initializer )
293
313
: undefined ;
294
- return parameters ? { commentOwner, parameters } : undefined ;
314
+ return { commentOwner, parameters } ;
295
315
}
296
316
297
317
case SyntaxKind . SourceFile :
298
318
return undefined ;
299
319
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
+
300
326
case SyntaxKind . BinaryExpression : {
301
327
const be = commentOwner as BinaryExpression ;
302
328
if ( getSpecialPropertyAssignmentKind ( be ) === ts . SpecialPropertyAssignmentKind . None ) {
@@ -305,11 +331,6 @@ namespace ts.JsDoc {
305
331
const parameters = isFunctionLike ( be . right ) ? be . right . parameters : emptyArray ;
306
332
return { commentOwner, parameters } ;
307
333
}
308
-
309
- case SyntaxKind . JsxText : {
310
- const parameters : ReadonlyArray < ParameterDeclaration > = emptyArray ;
311
- return { commentOwner, parameters } ;
312
- }
313
334
}
314
335
}
315
336
}
0 commit comments