diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 756be48ed9..3d3a86f20f 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -267,6 +267,18 @@ namespace ts { let functionType = node.parent; let index = indexOf(functionType.parameters, node); return "p" + index; + case SyntaxKind.JSDocTypedefTag: + const parentNode = node.parent && node.parent.parent; + let nameFromParentNode: string; + if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) { + if ((parentNode).declarationList.declarations.length > 0) { + const nameIdentifier = (parentNode).declarationList.declarations[0].name; + if (nameIdentifier.kind === SyntaxKind.Identifier) { + nameFromParentNode = (nameIdentifier).text; + } + } + } + return nameFromParentNode; } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 42af34c065..e8b2382259 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3586,11 +3586,21 @@ namespace ts { return unknownType; } + let type: Type; let declaration: JSDocTypedefTag | TypeAliasDeclaration = getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag); - if (!declaration) { - declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); + if (declaration) { + if (declaration.jsDocTypeLiteral) { + type = getTypeFromTypeNode(declaration.jsDocTypeLiteral); + } + else { + type = getTypeFromTypeNode(declaration.typeExpression.type); + } } - let type = getTypeFromTypeNode(declaration.type); + else { + declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); + type = getTypeFromTypeNode(declaration.type); + } + if (popTypeResolution()) { links.typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); if (links.typeParameters) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 07509d0afc..c61b4b836e 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -404,7 +404,7 @@ namespace ts { case SyntaxKind.JSDocTypedefTag: return visitNode(cbNode, (node).typeExpression) || visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).type); + visitNode(cbNode, (node).jsDocTypeLiteral); case SyntaxKind.JSDocTypeLiteral: return visitNodes(cbNodes, (node).jsDocPropertyTags); case SyntaxKind.JSDocPropertyTag: @@ -6301,28 +6301,11 @@ namespace ts { function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag { const typeExpression = tryParseTypeExpression(); skipWhitespace(); - let name = parseJSDocIdentifierName(); - if (!name) { - let foundNameFromParentNode = false; - if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) { - if ((parentNode).declarationList.declarations.length > 0) { - const nameFromParentNode = (parentNode).declarationList.declarations[0].name; - if (nameFromParentNode.kind === SyntaxKind.Identifier) { - foundNameFromParentNode = true; - name = nameFromParentNode; - } - } - } - if (!foundNameFromParentNode) { - parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected); - return undefined; - } - } const typedefTag = createNode(SyntaxKind.JSDocTypedefTag, atToken.pos); typedefTag.atToken = atToken; typedefTag.tagName = tagName; - typedefTag.name = name; + typedefTag.name = parseJSDocIdentifierName(); typedefTag.typeExpression = typeExpression; if (typeExpression) { @@ -6331,16 +6314,16 @@ namespace ts { if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) { const name = jsDocTypeReference.name; if (name.text === "Object") { - typedefTag.type = scanChildTags(); + typedefTag.jsDocTypeLiteral = scanChildTags(); } } } - if (!typedefTag.type) { - typedefTag.type = typeExpression.type; + if (!typedefTag.jsDocTypeLiteral) { + typedefTag.jsDocTypeLiteral = typeExpression.type; } } else { - typedefTag.type = scanChildTags(); + typedefTag.jsDocTypeLiteral = scanChildTags(); } return finishNode(typedefTag); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1b9af02a8d..f23b52b35d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -376,7 +376,9 @@ namespace ts { LastBinaryOperator = CaretEqualsToken, FirstNode = QualifiedName, FirstJSDocNode = JSDocTypeExpression, - LastJSDocNode = JSDocTypeLiteral + LastJSDocNode = JSDocTypeLiteral, + FirstJSDocTagNode = JSDocComment, + LastJSDocTagNode = JSDocTypeLiteral } export const enum NodeFlags { @@ -1518,9 +1520,9 @@ namespace ts { // @kind(SyntaxKind.JSDocTypedefTag) export interface JSDocTypedefTag extends JSDocTag, Declaration { - name: Identifier; + name?: Identifier; typeExpression?: JSDocTypeExpression; - type: JSDocType; + jsDocTypeLiteral?: JSDocTypeLiteral; } // @kind(SyntaxKind.JSDocPropertyTag) diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 0cb431de66..5515356a25 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -653,6 +653,12 @@ namespace ts.NavigationBar { topItem.childItems.push(newItem); } + if (node.jsDocComments && node.jsDocComments.length > 0) { + for (const jsDocComment of node.jsDocComments) { + visitNode(jsDocComment); + } + } + // Add a level if traversing into a container if (newItem && (isFunctionLike(node) || isClassLike(node))) { const lastTop = topItem; diff --git a/src/services/services.ts b/src/services/services.ts index 8fef753f2e..90740b257c 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -276,16 +276,7 @@ namespace ts { scanner.setText((sourceFile || this.getSourceFile()).text); children = []; let pos = this.pos; - const useJSDocScanner = - this.kind === SyntaxKind.JSDocComment || - this.kind === SyntaxKind.JSDocParameterTag || - this.kind === SyntaxKind.JSDocTag || - this.kind === SyntaxKind.JSDocParameterTag || - this.kind === SyntaxKind.JSDocReturnTag || - this.kind === SyntaxKind.JSDocTypeTag || - this.kind === SyntaxKind.JSDocTemplateTag || - this.kind === SyntaxKind.JSDocTypedefTag || - this.kind === SyntaxKind.JSDocPropertyTag; + const useJSDocScanner = this.kind >= SyntaxKind.FirstJSDocTagNode && this.kind <= SyntaxKind.LastJSDocTagNode; const processNode = (node: Node) => { if (pos < node.pos) { pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner);