@@ -173,38 +173,15 @@ namespace ts.JsDoc {
173173 return undefined ;
174174 }
175175
176- // TODO: add support for:
177- // - enums/enum members
178- // - interfaces
179- // - property declarations
180- // - potentially property assignments
181- let commentOwner : Node ;
182- findOwner: for ( commentOwner = tokenAtPos ; commentOwner ; commentOwner = commentOwner . parent ) {
183- switch ( commentOwner . kind ) {
184- case SyntaxKind . FunctionDeclaration :
185- case SyntaxKind . MethodDeclaration :
186- case SyntaxKind . Constructor :
187- case SyntaxKind . ClassDeclaration :
188- case SyntaxKind . VariableStatement :
189- break findOwner;
190- case SyntaxKind . SourceFile :
191- return undefined ;
192- case SyntaxKind . ModuleDeclaration :
193- // If in walking up the tree, we hit a a nested namespace declaration,
194- // then we must be somewhere within a dotted namespace name; however we don't
195- // want to give back a JSDoc template for the 'b' or 'c' in 'namespace a.b.c { }'.
196- if ( commentOwner . parent . kind === SyntaxKind . ModuleDeclaration ) {
197- return undefined ;
198- }
199- break findOwner;
200- }
176+ const commentOwnerInfo = getCommentOwnerInfo ( tokenAtPos ) ;
177+ if ( ! commentOwnerInfo ) {
178+ return undefined ;
201179 }
202-
203- if ( ! commentOwner || commentOwner . getStart ( ) < position ) {
180+ const { commentOwner , parameters } = commentOwnerInfo ;
181+ if ( commentOwner . getStart ( ) < position ) {
204182 return undefined ;
205183 }
206184
207- const parameters = getParametersForJsDocOwningNode ( commentOwner ) ;
208185 const posLineAndChar = sourceFile . getLineAndCharacterOfPosition ( position ) ;
209186 const lineStart = sourceFile . getLineStarts ( ) [ posLineAndChar . line ] ;
210187
@@ -213,16 +190,18 @@ namespace ts.JsDoc {
213190 const isJavaScriptFile = hasJavaScriptFileExtension ( sourceFile . fileName ) ;
214191
215192 let docParams = "" ;
216- for ( let i = 0 ; i < parameters . length ; i ++ ) {
217- const currentName = parameters [ i ] . name ;
218- const paramName = currentName . kind === SyntaxKind . Identifier ?
219- ( < Identifier > currentName ) . escapedText :
220- "param" + i ;
221- if ( isJavaScriptFile ) {
222- docParams += `${ indentationStr } * @param {any} ${ paramName } ${ newLine } ` ;
223- }
224- else {
225- docParams += `${ indentationStr } * @param ${ paramName } ${ newLine } ` ;
193+ if ( parameters ) {
194+ for ( let i = 0 ; i < parameters . length ; i ++ ) {
195+ const currentName = parameters [ i ] . name ;
196+ const paramName = currentName . kind === SyntaxKind . Identifier ?
197+ ( < Identifier > currentName ) . escapedText :
198+ "param" + i ;
199+ if ( isJavaScriptFile ) {
200+ docParams += `${ indentationStr } * @param {any} ${ paramName } ${ newLine } ` ;
201+ }
202+ else {
203+ docParams += `${ indentationStr } * @param ${ paramName } ${ newLine } ` ;
204+ }
226205 }
227206 }
228207
@@ -244,21 +223,55 @@ namespace ts.JsDoc {
244223 return { newText : result , caretOffset : preamble . length } ;
245224 }
246225
247- function getParametersForJsDocOwningNode ( commentOwner : Node ) : ReadonlyArray < ParameterDeclaration > {
248- if ( isFunctionLike ( commentOwner ) ) {
249- return commentOwner . parameters ;
250- }
226+ interface CommentOwnerInfo {
227+ readonly commentOwner : Node ;
228+ readonly parameters ?: ReadonlyArray < ParameterDeclaration > ;
229+ }
230+ function getCommentOwnerInfo ( tokenAtPos : Node ) : CommentOwnerInfo | undefined {
231+ // TODO: add support for:
232+ // - enums/enum members
233+ // - interfaces
234+ // - property declarations
235+ // - potentially property assignments
236+ for ( let commentOwner = tokenAtPos ; commentOwner ; commentOwner = commentOwner . parent ) {
237+ switch ( commentOwner . kind ) {
238+ case SyntaxKind . FunctionDeclaration :
239+ case SyntaxKind . MethodDeclaration :
240+ case SyntaxKind . Constructor :
241+ const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration ;
242+ return { commentOwner, parameters } ;
243+
244+ case SyntaxKind . ClassDeclaration :
245+ return { commentOwner } ;
251246
252- if ( commentOwner . kind === SyntaxKind . VariableStatement ) {
253- const varStatement = < VariableStatement > commentOwner ;
254- const varDeclarations = varStatement . declarationList . declarations ;
247+ case SyntaxKind . VariableStatement : {
248+ const varStatement = < VariableStatement > commentOwner ;
249+ const varDeclarations = varStatement . declarationList . declarations ;
250+ const parameters = varDeclarations . length === 1 && varDeclarations [ 0 ] . initializer
251+ ? getParametersFromRightHandSideOfAssignment ( varDeclarations [ 0 ] . initializer )
252+ : undefined ;
253+ return { commentOwner, parameters } ;
254+ }
255255
256- if ( varDeclarations . length === 1 && varDeclarations [ 0 ] . initializer ) {
257- return getParametersFromRightHandSideOfAssignment ( varDeclarations [ 0 ] . initializer ) ;
256+ case SyntaxKind . SourceFile :
257+ return undefined ;
258+
259+ case SyntaxKind . ModuleDeclaration :
260+ // If in walking up the tree, we hit a a nested namespace declaration,
261+ // then we must be somewhere within a dotted namespace name; however we don't
262+ // want to give back a JSDoc template for the 'b' or 'c' in 'namespace a.b.c { }'.
263+ return commentOwner . parent . kind === SyntaxKind . ModuleDeclaration ? undefined : { commentOwner } ;
264+
265+ case SyntaxKind . BinaryExpression : {
266+ const be = commentOwner as BinaryExpression ;
267+ if ( getSpecialPropertyAssignmentKind ( be ) === ts . SpecialPropertyAssignmentKind . None ) {
268+ return undefined ;
269+ }
270+ const parameters = isFunctionLike ( be . right ) ? be . right . parameters : emptyArray ;
271+ return { commentOwner, parameters } ;
272+ }
258273 }
259274 }
260-
261- return emptyArray ;
262275 }
263276
264277 /**
0 commit comments