diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 5bc8e78f749..b29bea18e41 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1538,6 +1538,34 @@ namespace ts { return getJSDocCommentsAndTags(node); } + export function getSourceOfAssignment(node: Node): Node { + return isExpressionStatement(node) && + node.expression && isBinaryExpression(node.expression) && + node.expression.operatorToken.kind === SyntaxKind.EqualsToken && + node.expression.right; + } + + export function getSingleInitializerOfVariableStatement(node: Node, child?: Node): Node { + return isVariableStatement(node) && + node.declarationList.declarations.length > 0 && + (!child || node.declarationList.declarations[0].initializer === child) && + node.declarationList.declarations[0].initializer; + } + + export function getSingleVariableOfVariableStatement(node: Node, child?: Node): Node { + return isVariableStatement(node) && + node.declarationList.declarations.length > 0 && + (!child || node.declarationList.declarations[0] === child) && + node.declarationList.declarations[0]; + } + + export function getNestedModuleDeclaration(node: Node): Node { + return node.kind === SyntaxKind.ModuleDeclaration && + (node as ModuleDeclaration).body && + (node as ModuleDeclaration).body.kind === SyntaxKind.ModuleDeclaration && + (node as ModuleDeclaration).body; + } + export function getJSDocCommentsAndTags(node: Node): (JSDoc | JSDocTag)[] { let result: (JSDoc | JSDocTag)[] | undefined; getJSDocCommentsAndTagsWorker(node); @@ -1551,35 +1579,15 @@ namespace ts { // * @returns {number} // */ // var x = function(name) { return name.length; } - const isInitializerOfVariableDeclarationInStatement = - isVariableLike(parent) && - parent.initializer === node && - parent.parent.parent.kind === SyntaxKind.VariableStatement; - const isVariableOfVariableDeclarationStatement = isVariableLike(node) && - parent.parent.kind === SyntaxKind.VariableStatement; - const variableStatementNode = - isInitializerOfVariableDeclarationInStatement ? parent.parent.parent : - isVariableOfVariableDeclarationStatement ? parent.parent : - undefined; - if (variableStatementNode) { - getJSDocCommentsAndTagsWorker(variableStatementNode); + if (parent && (parent.kind === SyntaxKind.PropertyAssignment || getNestedModuleDeclaration(parent))) { + getJSDocCommentsAndTagsWorker(parent); } - - // Also recognize when the node is the RHS of an assignment expression - const isSourceOfAssignmentExpressionStatement = - parent && parent.parent && - parent.kind === SyntaxKind.BinaryExpression && - (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && - parent.parent.kind === SyntaxKind.ExpressionStatement; - if (isSourceOfAssignmentExpressionStatement) { + if (parent && parent.parent && + (getSingleVariableOfVariableStatement(parent.parent, node) || getSourceOfAssignment(parent.parent))) { getJSDocCommentsAndTagsWorker(parent.parent); } - - const isModuleDeclaration = node.kind === SyntaxKind.ModuleDeclaration && - parent && parent.kind === SyntaxKind.ModuleDeclaration; - const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment; - if (isModuleDeclaration || isPropertyAssignmentExpression) { - getJSDocCommentsAndTagsWorker(parent); + if (parent && parent.parent && parent.parent.parent && getSingleInitializerOfVariableStatement(parent.parent.parent, node)) { + getJSDocCommentsAndTagsWorker(parent.parent.parent); } // Pull parameter comments from declaring function as well @@ -1606,24 +1614,16 @@ namespace ts { return undefined; } const name = node.name.escapedText; - const decl = getJSDocHost(node); - let func: FunctionLike; - if (isExpressionStatement(decl) && isBinaryExpression(decl.expression) && isFunctionLike(decl.expression.right)) { - func = decl.expression.right; + const host = getJSDocHost(node); + const decl = getSourceOfAssignment(host) || + getSingleInitializerOfVariableStatement(host) || + getSingleVariableOfVariableStatement(host) || + getNestedModuleDeclaration(host) || + host; + if (decl && isFunctionLike(decl)) { + const parameter = find(decl.parameters, p => p.name.kind === SyntaxKind.Identifier && p.name.escapedText === name); + return parameter && parameter.symbol; } - else if (isVariableStatement(decl) && decl.declarationList.declarations.length === 1 && isVariableDeclaration(decl.declarationList.declarations[0]) - && isFunctionLike(decl.declarationList.declarations[0].initializer)) { - func = decl.declarationList.declarations[0].initializer as FunctionLike; - } - else if (isFunctionLike(decl)) { - func = decl; - } - else { - return undefined; - } - const parameter = find(func.parameters, p => - p.name.kind === SyntaxKind.Identifier && p.name.escapedText === name); - return parameter && parameter.symbol; } export function getJSDocHost(node: JSDocTag): HasJSDoc {