Skip to content

Commit

Permalink
Handle PropertyAssignment in getCommentOwnerInfo (#25911)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy committed Jul 25, 2018
1 parent fd2eb49 commit e4d4b0a
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 40 deletions.
10 changes: 10 additions & 0 deletions src/compiler/utilities.ts
Expand Up @@ -142,6 +142,16 @@ namespace ts {
return undefined;
}

export function forEachAncestor<T>(node: Node, callback: (n: Node) => T | undefined | "quit"): T | undefined {
while (true) {
const res = callback(node);
if (res === "quit") return undefined;
if (res !== undefined) return res;
if (isSourceFile(node)) return undefined;
node = node.parent;
}
}

/**
* Calls `callback` for each entry in the map, returning the first truthy result.
* Use `map.forEach` instead for normal iteration.
Expand Down
84 changes: 44 additions & 40 deletions src/services/jsDoc.ts
Expand Up @@ -338,50 +338,54 @@ namespace ts.JsDoc {
readonly parameters?: ReadonlyArray<ParameterDeclaration>;
}
function getCommentOwnerInfo(tokenAtPos: Node): CommentOwnerInfo | undefined {
for (let commentOwner = tokenAtPos; commentOwner; commentOwner = commentOwner.parent) {
switch (commentOwner.kind) {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.Constructor:
case SyntaxKind.MethodSignature:
const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature;
return { commentOwner, parameters };

case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.EnumMember:
case SyntaxKind.TypeAliasDeclaration:
return { commentOwner };

case SyntaxKind.VariableStatement: {
const varStatement = <VariableStatement>commentOwner;
const varDeclarations = varStatement.declarationList.declarations;
const parameters = varDeclarations.length === 1 && varDeclarations[0].initializer
? getParametersFromRightHandSideOfAssignment(varDeclarations[0].initializer!)
: undefined;
return { commentOwner, parameters };
}
return forEachAncestor(tokenAtPos, getCommentOwnerInfoWorker);
}
function getCommentOwnerInfoWorker(commentOwner: Node): CommentOwnerInfo | undefined | "quit" {
switch (commentOwner.kind) {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.Constructor:
case SyntaxKind.MethodSignature:
const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature;
return { commentOwner, parameters };

case SyntaxKind.PropertyAssignment:
return getCommentOwnerInfoWorker((commentOwner as PropertyAssignment).initializer);

case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.EnumMember:
case SyntaxKind.TypeAliasDeclaration:
return { commentOwner };

case SyntaxKind.VariableStatement: {
const varStatement = <VariableStatement>commentOwner;
const varDeclarations = varStatement.declarationList.declarations;
const parameters = varDeclarations.length === 1 && varDeclarations[0].initializer
? getParametersFromRightHandSideOfAssignment(varDeclarations[0].initializer!)
: undefined;
return { commentOwner, parameters };
}

case SyntaxKind.SourceFile:
return undefined;
case SyntaxKind.SourceFile:
return "quit";

case SyntaxKind.ModuleDeclaration:
// If in walking up the tree, we hit a a nested namespace declaration,
// then we must be somewhere within a dotted namespace name; however we don't
// want to give back a JSDoc template for the 'b' or 'c' in 'namespace a.b.c { }'.
return commentOwner.parent.kind === SyntaxKind.ModuleDeclaration ? undefined : { commentOwner };
case SyntaxKind.ModuleDeclaration:
// If in walking up the tree, we hit a a nested namespace declaration,
// then we must be somewhere within a dotted namespace name; however we don't
// want to give back a JSDoc template for the 'b' or 'c' in 'namespace a.b.c { }'.
return commentOwner.parent.kind === SyntaxKind.ModuleDeclaration ? undefined : { commentOwner };

case SyntaxKind.BinaryExpression: {
const be = commentOwner as BinaryExpression;
if (getSpecialPropertyAssignmentKind(be) === SpecialPropertyAssignmentKind.None) {
return undefined;
}
const parameters = isFunctionLike(be.right) ? be.right.parameters : emptyArray;
return { commentOwner, parameters };
case SyntaxKind.BinaryExpression: {
const be = commentOwner as BinaryExpression;
if (getSpecialPropertyAssignmentKind(be) === SpecialPropertyAssignmentKind.None) {
return "quit";
}
const parameters = isFunctionLike(be.right) ? be.right.parameters : emptyArray;
return { commentOwner, parameters };
}
}
}
Expand Down
Expand Up @@ -10,6 +10,8 @@ const multiLineOffset = 12;
//// }
//// /*1*/
//// [1 + 2 + 3 + Math.rand()](x: number, y: string, z = true) { }
//// /*2*/
//// m: function(a) {}
////}

verify.docCommentTemplateAt("0", singleLineOffset, "/** */");
Expand All @@ -21,3 +23,9 @@ verify.docCommentTemplateAt("1", multiLineOffset,
* @param y
* @param z
*/`);

verify.docCommentTemplateAt("2", multiLineOffset,
`/**
*
* @param a
*/`);

0 comments on commit e4d4b0a

Please sign in to comment.