From ad9ad8f948bf2cb7c03fc152e81cb8c911990a8d Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 17 Nov 2016 11:08:11 -0800 Subject: [PATCH] Clean up getJSDocTypeForVariableLikeDeclarationFromJSDocComment Yeah, that name is way too long. --- src/compiler/checker.ts | 23 ++--------------------- src/compiler/utilities.ts | 37 ++++++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b466bf7afb6..26dd39d6b92 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3156,30 +3156,11 @@ namespace ts { function getJSDocTypeForVariableLikeDeclarationFromJSDocComment(declaration: VariableLikeDeclaration): JSDocType { // First, see if this node has an @type annotation on it directly. - const typeTag = getJSDocTypeTag(declaration); + const typeTag = getJSDocTypeTag(declaration, true); if (typeTag && typeTag.typeExpression) { return typeTag.typeExpression.type; } - if (declaration.kind === SyntaxKind.VariableDeclaration && - declaration.parent.kind === SyntaxKind.VariableDeclarationList && - declaration.parent.parent.kind === SyntaxKind.VariableStatement) { - - // @type annotation might have been on the variable statement, try that instead. - const annotation = getJSDocTypeTag(declaration.parent.parent); - if (annotation && annotation.typeExpression) { - return annotation.typeExpression.type; - } - } - else if (declaration.kind === SyntaxKind.Parameter) { - // If it's a parameter, see if the parent has a jsdoc comment with an @param - // annotation. - const paramTag = getCorrespondingJSDocParameterTag(declaration); - if (paramTag && paramTag.typeExpression) { - return paramTag.typeExpression.type; - } - } - return undefined; } @@ -13551,7 +13532,7 @@ namespace ts { // the destructured type into the contained binding elements. function assignBindingElementTypes(node: VariableLikeDeclaration) { if (isBindingPattern(node.name)) { - for (const element of (node.name).elements) { + for (const element of node.name.elements) { if (!isOmittedExpression(element)) { if (element.name.kind === SyntaxKind.Identifier) { getSymbolLinks(getSymbolOfNode(element)).type = getTypeForBindingElement(element); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 158da8e8f0b..16255dfdde7 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1449,10 +1449,16 @@ namespace ts { }, tags => tags); } - function getJSDocs(node: Node, checkParentVariableStatement: boolean, getDocs: (docs: JSDoc[]) => T[], getTags: (tags: JSDocTag[]) => T[]): T[] { + function getJSDocs(node: Node, + checkParentVariableStatement: boolean, + getDocContent: (docs: JSDoc[]) => T[], + getTagContent: (tags: JSDocTag[]) => T[]): T[] { // TODO: A lot of this work should be cached, maybe. I guess it's only used in services right now... + // This will be hard because it may need to cache parentvariable versions and nonparent versions + // maybe I should eliminate checkParent first ... let result: T[] = undefined; // prepend documentation from parent sources + // TODO: Probably always want checkParent=true, right? if (checkParentVariableStatement) { // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. // /** @@ -1472,11 +1478,11 @@ namespace ts { isVariableOfVariableDeclarationStatement ? node.parent.parent : undefined; if (variableStatementNode) { - result = concatenate(result, getJSDocs(variableStatementNode, checkParentVariableStatement, getDocs, getTags)); + result = concatenate(result, getJSDocs(variableStatementNode, checkParentVariableStatement, getDocContent, getTagContent)); } if (node.kind === SyntaxKind.ModuleDeclaration && node.parent && node.parent.kind === SyntaxKind.ModuleDeclaration) { - result = concatenate(result, getJSDocs(node.parent, checkParentVariableStatement, getDocs, getTags)); + result = concatenate(result, getJSDocs(node.parent, checkParentVariableStatement, getDocContent, getTagContent)); } // Also recognize when the node is the RHS of an assignment expression @@ -1487,33 +1493,34 @@ namespace ts { (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && parent.parent.kind === SyntaxKind.ExpressionStatement; if (isSourceOfAssignmentExpressionStatement) { - result = concatenate(result, getJSDocs(parent.parent, checkParentVariableStatement, getDocs, getTags)); + result = concatenate(result, getJSDocs(parent.parent, checkParentVariableStatement, getDocContent, getTagContent)); } const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment; if (isPropertyAssignmentExpression) { - result = concatenate(result, getJSDocs(parent, checkParentVariableStatement, getDocs, getTags)); + result = concatenate(result, getJSDocs(parent, checkParentVariableStatement, getDocContent, getTagContent)); } // Pull parameter comments from declaring function as well if (node.kind === SyntaxKind.Parameter) { const paramTags = getJSDocParameterTag(node as ParameterDeclaration, checkParentVariableStatement); if (paramTags) { - result = concatenate(result, getTags(paramTags)); + result = concatenate(result, getTagContent(paramTags)); } } } if (isVariableLike(node) && node.initializer) { - result = concatenate(result, getJSDocs(node.initializer, /*checkParentVariableStatement*/ false, getDocs, getTags)); + // TODO: Does this really need to be called for everything? + result = concatenate(result, getJSDocs(node.initializer, /*checkParentVariableStatement*/ false, getDocContent, getTagContent)); } if (node.jsDocComments) { if (result) { - result = concatenate(result, getDocs(node.jsDocComments)); + result = concatenate(result, getDocContent(node.jsDocComments)); } else { - return getDocs(node.jsDocComments); + return getDocContent(node.jsDocComments); } } @@ -1521,6 +1528,7 @@ namespace ts { } function getJSDocParameterTag(param: ParameterDeclaration, checkParentVariableStatement: boolean): JSDocTag[] { + // TODO: getCorrespondingJSDocParameterTag is basically the same as this, except worse. (and typed, singleton return) const func = param.parent as FunctionLikeDeclaration; const tags = getJSDocTags(func, checkParentVariableStatement); if (!param.name) { @@ -1545,16 +1553,19 @@ namespace ts { } } - export function getJSDocTypeTag(node: Node): JSDocTypeTag { - return getJSDocTag(node, SyntaxKind.JSDocTypeTag, /*checkParentVariableStatement*/ false); + export function getJSDocTypeTag(node: Node, checkParentVariableStatement?: boolean): JSDocTypeTag | JSDocParameterTag { + // TODO: Get rid of the second parameter again + // TODO: Don't call getJSDocTag twice. Call a version that allows you to retrieve either kind. + return getJSDocTag(node, SyntaxKind.JSDocTypeTag, checkParentVariableStatement) as JSDocTypeTag || + node.kind === SyntaxKind.Parameter && firstOrUndefined(getJSDocParameterTag(node as ParameterDeclaration, checkParentVariableStatement)) as JSDocParameterTag; } export function getJSDocReturnTag(node: Node): JSDocReturnTag { - return getJSDocTag(node, SyntaxKind.JSDocReturnTag, /*checkParentVariableStatement*/ true); + return getJSDocTag(node, SyntaxKind.JSDocReturnTag, /*checkParentVariableStatement*/ true) as JSDocReturnTag; } export function getJSDocTemplateTag(node: Node): JSDocTemplateTag { - return getJSDocTag(node, SyntaxKind.JSDocTemplateTag, /*checkParentVariableStatement*/ false); + return getJSDocTag(node, SyntaxKind.JSDocTemplateTag, /*checkParentVariableStatement*/ false) as JSDocTemplateTag; } export function getCorrespondingJSDocParameterTag(parameter: ParameterDeclaration): JSDocParameterTag {