From b8082caa8eb5c16020f805ff70ef61454e07175c Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 11 Nov 2016 15:58:52 -0800 Subject: [PATCH 1/9] Clean up jsdoc in utilities Fix functions that were unused (getJsDocComments), redundant (append) or badly named (getJSDocCommentsFromText) --- src/compiler/declarationEmitter.ts | 2 +- src/compiler/parser.ts | 2 +- src/compiler/utilities.ts | 46 +++++++++--------------------- 3 files changed, 15 insertions(+), 35 deletions(-) diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 0bba375a2cb2e..3b48f45347800 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -371,7 +371,7 @@ namespace ts { function writeJsDocComments(declaration: Node) { if (declaration) { - const jsDocComments = getJsDocCommentsFromText(declaration, currentText); + const jsDocComments = getJSDocCommentRanges(declaration, currentText); emitNewLineBeforeLeadingComments(currentLineMap, writer, declaration, jsDocComments); // jsDoc comments are emitted at /*leading comment1 */space/*leading comment*/space emitComments(currentText, currentLineMap, writer, jsDocComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeCommentRange); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 943a677ef5d99..682c22b4fba63 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -676,7 +676,7 @@ namespace ts { function addJSDocComment(node: T): T { - const comments = getJsDocCommentsFromText(node, sourceFile.text); + const comments = getJSDocCommentRanges(node, sourceFile.text); if (comments) { for (const comment of comments) { const jsDoc = JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a9f2429d37645..9aa0e4267cf89 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -638,25 +638,18 @@ namespace ts { return getLeadingCommentRanges(text, node.pos); } - export function getJsDocComments(node: Node, sourceFileOfNode: SourceFile) { - return getJsDocCommentsFromText(node, sourceFileOfNode.text); - } - - export function getJsDocCommentsFromText(node: Node, text: string) { + export function getJSDocCommentRanges(node: Node, text: string) { const commentRanges = (node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.TypeParameter || node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.ArrowFunction) ? concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) : getLeadingCommentRangesOfNodeFromText(node, text); - return filter(commentRanges, isJsDocComment); - - function isJsDocComment(comment: CommentRange) { - // True if the comment starts with '/**' but not if it is '/**/' - return text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk && - text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk && - text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash; - } + // True if the comment starts with '/**' but not if it is '/**/' + return filter(commentRanges, comment => + text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk && + text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk && + text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash); } export let fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*/; @@ -1453,18 +1446,6 @@ namespace ts { } } - function append(previous: T[] | undefined, additional: T[] | undefined): T[] | undefined { - if (additional) { - if (!previous) { - previous = []; - } - for (const x of additional) { - previous.push(x); - } - } - return previous; - } - export function getJSDocComments(node: Node, checkParentVariableStatement: boolean): string[] { return getJSDocs(node, checkParentVariableStatement, docs => map(docs, doc => doc.comment), tags => map(tags, tag => tag.comment)); } @@ -1482,7 +1463,6 @@ namespace ts { } function getJSDocs(node: Node, checkParentVariableStatement: boolean, getDocs: (docs: JSDoc[]) => T[], getTags: (tags: JSDocTag[]) => T[]): T[] { - // TODO: Get rid of getJsDocComments and friends (note the lowercase 's' in Js) // TODO: A lot of this work should be cached, maybe. I guess it's only used in services right now... let result: T[] = undefined; // prepend documentation from parent sources @@ -1505,11 +1485,11 @@ namespace ts { isVariableOfVariableDeclarationStatement ? node.parent.parent : undefined; if (variableStatementNode) { - result = append(result, getJSDocs(variableStatementNode, checkParentVariableStatement, getDocs, getTags)); + result = concatenate(result, getJSDocs(variableStatementNode, checkParentVariableStatement, getDocs, getTags)); } if (node.kind === SyntaxKind.ModuleDeclaration && node.parent && node.parent.kind === SyntaxKind.ModuleDeclaration) { - result = append(result, getJSDocs(node.parent, checkParentVariableStatement, getDocs, getTags)); + result = concatenate(result, getJSDocs(node.parent, checkParentVariableStatement, getDocs, getTags)); } // Also recognize when the node is the RHS of an assignment expression @@ -1520,30 +1500,30 @@ namespace ts { (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && parent.parent.kind === SyntaxKind.ExpressionStatement; if (isSourceOfAssignmentExpressionStatement) { - result = append(result, getJSDocs(parent.parent, checkParentVariableStatement, getDocs, getTags)); + result = concatenate(result, getJSDocs(parent.parent, checkParentVariableStatement, getDocs, getTags)); } const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment; if (isPropertyAssignmentExpression) { - result = append(result, getJSDocs(parent, checkParentVariableStatement, getDocs, getTags)); + result = concatenate(result, getJSDocs(parent, checkParentVariableStatement, getDocs, getTags)); } // Pull parameter comments from declaring function as well if (node.kind === SyntaxKind.Parameter) { const paramTags = getJSDocParameterTag(node as ParameterDeclaration, checkParentVariableStatement); if (paramTags) { - result = append(result, getTags(paramTags)); + result = concatenate(result, getTags(paramTags)); } } } if (isVariableLike(node) && node.initializer) { - result = append(result, getJSDocs(node.initializer, /*checkParentVariableStatement*/ false, getDocs, getTags)); + result = concatenate(result, getJSDocs(node.initializer, /*checkParentVariableStatement*/ false, getDocs, getTags)); } if (node.jsDocComments) { if (result) { - result = append(result, getDocs(node.jsDocComments)); + result = concatenate(result, getDocs(node.jsDocComments)); } else { return getDocs(node.jsDocComments); From ad9ad8f948bf2cb7c03fc152e81cb8c911990a8d Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 17 Nov 2016 11:08:11 -0800 Subject: [PATCH 2/9] 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 b466bf7afb66b..26dd39d6b92f8 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 158da8e8f0b98..16255dfdde74c 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 { From 5a05b94fb5e03eed15f6b687f6ec490c5d685aa5 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 17 Nov 2016 13:27:57 -0800 Subject: [PATCH 3/9] Clean up getJSDocs 1. Get rid of parent check. 2. Use a couple of nested functions, one of them a recursive worker. --- src/compiler/checker.ts | 27 +++------ src/compiler/utilities.ts | 116 ++++++++++++++++++-------------------- src/services/jsDoc.ts | 2 +- 3 files changed, 66 insertions(+), 79 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 26dd39d6b92f8..53571e265eac3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3148,19 +3148,10 @@ namespace ts { } function getTypeForVariableLikeDeclarationFromJSDocComment(declaration: VariableLikeDeclaration) { - const jsDocType = getJSDocTypeForVariableLikeDeclarationFromJSDocComment(declaration); - if (jsDocType) { - return getTypeFromTypeNode(jsDocType); + const jsdocType = getJSDocType(declaration); + if (jsdocType) { + return getTypeFromTypeNode(jsdocType); } - } - - function getJSDocTypeForVariableLikeDeclarationFromJSDocComment(declaration: VariableLikeDeclaration): JSDocType { - // First, see if this node has an @type annotation on it directly. - const typeTag = getJSDocTypeTag(declaration, true); - if (typeTag && typeTag.typeExpression) { - return typeTag.typeExpression.type; - } - return undefined; } @@ -3426,9 +3417,9 @@ namespace ts { declaration.kind === SyntaxKind.PropertyAccessExpression && declaration.parent.kind === SyntaxKind.BinaryExpression) { // Use JS Doc type if present on parent expression statement if (declaration.flags & NodeFlags.JavaScriptFile) { - const typeTag = getJSDocTypeTag(declaration.parent); - if (typeTag && typeTag.typeExpression) { - return links.type = getTypeFromTypeNode(typeTag.typeExpression.type); + const jsdocType = getJSDocType(declaration.parent); + if (jsdocType) { + return links.type = getTypeFromTypeNode(jsdocType); } } const declaredTypes = map(symbol.declarations, @@ -10296,9 +10287,9 @@ namespace ts { } function getTypeForThisExpressionFromJSDoc(node: Node) { - const typeTag = getJSDocTypeTag(node); - if (typeTag && typeTag.typeExpression && typeTag.typeExpression.type && typeTag.typeExpression.type.kind === SyntaxKind.JSDocFunctionType) { - const jsDocFunctionType = typeTag.typeExpression.type; + const jsdocType = getJSDocType(node); + if (jsdocType && jsdocType.kind === SyntaxKind.JSDocFunctionType) { + const jsDocFunctionType = jsdocType; if (jsDocFunctionType.parameters.length > 0 && jsDocFunctionType.parameters[0].type.kind === SyntaxKind.JSDocThisType) { return getTypeFromTypeNode(jsDocFunctionType.parameters[0].type); } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 16255dfdde74c..a0ac380711c27 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1416,12 +1416,12 @@ namespace ts { (node).parameters[0].type.kind === SyntaxKind.JSDocConstructorType; } - function getJSDocTag(node: Node, kind: SyntaxKind, checkParentVariableStatement: boolean): JSDocTag { + function getJSDocTag(node: Node, kind: SyntaxKind): JSDocTag { if (!node) { return undefined; } - const jsDocTags = getJSDocTags(node, checkParentVariableStatement); + const jsDocTags = getJSDocTags(node); if (!jsDocTags) { return undefined; } @@ -1433,12 +1433,12 @@ namespace ts { } } - export function getJSDocComments(node: Node, checkParentVariableStatement: boolean): string[] { - return getJSDocs(node, checkParentVariableStatement, docs => map(docs, doc => doc.comment), tags => map(tags, tag => tag.comment)); + export function getJSDocComments(node: Node): string[] { + return getJSDocs(node, docs => map(docs, doc => doc.comment), tags => map(tags, tag => tag.comment)); } - function getJSDocTags(node: Node, checkParentVariableStatement: boolean): JSDocTag[] { - return getJSDocs(node, checkParentVariableStatement, docs => { + function getJSDocTags(node: Node): JSDocTag[] { + return getJSDocs(node, docs => { const result: JSDocTag[] = []; for (const doc of docs) { if (doc.tags) { @@ -1449,17 +1449,16 @@ namespace ts { }, tags => tags); } - 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) { + function getJSDocs(node: Node, getContent: (docs: JSDoc[]) => T[], getContentFromParam: (tags: JSDocTag[]) => T[]): T[] { + return getJSDocsWorker(node); + + function getJSDocsWorker(node: Node) { + // 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 ... + const parent = node.parent; + let result: T[] = undefined; + // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. // /** // * @param {number} name @@ -1467,70 +1466,61 @@ namespace ts { // */ // var x = function(name) { return name.length; } const isInitializerOfVariableDeclarationInStatement = - isVariableLike(node.parent) && - (node.parent).initializer === node && - node.parent.parent.parent.kind === SyntaxKind.VariableStatement; + isVariableLike(parent) && + parent.initializer === node && + parent.parent.parent.kind === SyntaxKind.VariableStatement; const isVariableOfVariableDeclarationStatement = isVariableLike(node) && - node.parent.parent.kind === SyntaxKind.VariableStatement; - + parent.parent.kind === SyntaxKind.VariableStatement; const variableStatementNode = - isInitializerOfVariableDeclarationInStatement ? node.parent.parent.parent : - isVariableOfVariableDeclarationStatement ? node.parent.parent : - undefined; + isInitializerOfVariableDeclarationInStatement ? parent.parent.parent : + isVariableOfVariableDeclarationStatement ? parent.parent : + undefined; if (variableStatementNode) { - 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, getDocContent, getTagContent)); + result = concatenate(result, getJSDocsWorker(variableStatementNode)); } // Also recognize when the node is the RHS of an assignment expression - const parent = node.parent; const isSourceOfAssignmentExpressionStatement = parent && parent.parent && parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && parent.parent.kind === SyntaxKind.ExpressionStatement; if (isSourceOfAssignmentExpressionStatement) { - result = concatenate(result, getJSDocs(parent.parent, checkParentVariableStatement, getDocContent, getTagContent)); + result = concatenate(result, getJSDocsWorker(parent.parent)); } + const isModuleDeclaration = node.kind === SyntaxKind.ModuleDeclaration && + parent && parent.kind === SyntaxKind.ModuleDeclaration; const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment; - if (isPropertyAssignmentExpression) { - result = concatenate(result, getJSDocs(parent, checkParentVariableStatement, getDocContent, getTagContent)); + if (isModuleDeclaration || isPropertyAssignmentExpression) { + result = concatenate(result, getJSDocsWorker(parent)); } // 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, getTagContent(paramTags)); - } + result = concatenate(result, getContentFromParam(getJSDocParameterTag(node as ParameterDeclaration))); + } + + if (isVariableLike(node) && node.initializer) { + result = concatenate(result, getOwnJSDocs(node.initializer)); } - } - if (isVariableLike(node) && node.initializer) { - // TODO: Does this really need to be called for everything? - result = concatenate(result, getJSDocs(node.initializer, /*checkParentVariableStatement*/ false, getDocContent, getTagContent)); + result = concatenate(result, getOwnJSDocs(node)); + + return result; } - if (node.jsDocComments) { - if (result) { - result = concatenate(result, getDocContent(node.jsDocComments)); - } - else { - return getDocContent(node.jsDocComments); + function getOwnJSDocs(node: Node) { + if (node.jsDocComments) { + return getContent(node.jsDocComments); } } - - return result; } - function getJSDocParameterTag(param: ParameterDeclaration, checkParentVariableStatement: boolean): JSDocTag[] { + function getJSDocParameterTag(param: ParameterDeclaration): 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); + const tags = getJSDocTags(func); if (!param.name) { // this is an anonymous jsdoc param from a `function(type1, type2): type3` specification const i = func.parameters.indexOf(param); @@ -1553,19 +1543,25 @@ namespace ts { } } - 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 getJSDocType(node: Node): JSDocType { + // TODO: If you have to call getparamtag, you really want the first with a typeExpression, not the first one. + let tag: JSDocTypeTag | JSDocParameterTag = getJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag; + if (!tag && node.kind === SyntaxKind.Parameter) { + const paramTags = getJSDocParameterTag(node as ParameterDeclaration); + if (paramTags) { + tag = find(paramTags, tag => !!(tag as JSDocParameterTag).typeExpression) as JSDocParameterTag; + } + } + + return tag && tag.typeExpression && tag.typeExpression.type; } export function getJSDocReturnTag(node: Node): JSDocReturnTag { - return getJSDocTag(node, SyntaxKind.JSDocReturnTag, /*checkParentVariableStatement*/ true) as JSDocReturnTag; + return getJSDocTag(node, SyntaxKind.JSDocReturnTag) as JSDocReturnTag; } export function getJSDocTemplateTag(node: Node): JSDocTemplateTag { - return getJSDocTag(node, SyntaxKind.JSDocTemplateTag, /*checkParentVariableStatement*/ false) as JSDocTemplateTag; + return getJSDocTag(node, SyntaxKind.JSDocTemplateTag) as JSDocTemplateTag; } export function getCorrespondingJSDocParameterTag(parameter: ParameterDeclaration): JSDocParameterTag { @@ -1574,7 +1570,7 @@ namespace ts { // annotation. const parameterName = (parameter.name).text; - const jsDocTags = getJSDocTags(parameter.parent, /*checkParentVariableStatement*/ true); + const jsDocTags = getJSDocTags(parameter.parent); if (!jsDocTags) { return undefined; } diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 5e2f5e7b4c906..24e99cf5c7754 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -52,7 +52,7 @@ namespace ts.JsDoc { // from Array - Array and Array const documentationComment = []; forEachUnique(declarations, declaration => { - const comments = getJSDocComments(declaration, /*checkParentVariableStatement*/ true); + const comments = getJSDocComments(declaration); if (!comments) { return; } From ddffe209f9ab8ee31cae9088688e34cadf255da3 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 17 Nov 2016 14:26:38 -0800 Subject: [PATCH 4/9] Clean up getJSDocParameterTag And delete its near-duplicate which was much less correct. The callers that had to switch are slightly more complex and more correct now. --- src/compiler/checker.ts | 17 ++++++------ src/compiler/utilities.ts | 56 +++++++++------------------------------ 2 files changed, 22 insertions(+), 51 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 53571e265eac3..0803814bc14a2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4854,15 +4854,16 @@ namespace ts { if (node.type && node.type.kind === SyntaxKind.JSDocOptionalType) { return true; } + const paramTags = getJSDocParameterTag(node); + if (paramTags) { + for (const paramTag of paramTags) { + if (paramTag.isBracketed) { + return true; + } - const paramTag = getCorrespondingJSDocParameterTag(node); - if (paramTag) { - if (paramTag.isBracketed) { - return true; - } - - if (paramTag.typeExpression) { - return paramTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType; + if (paramTag.typeExpression) { + return paramTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType; + } } } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a0ac380711c27..243d4f4c519ff 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1498,16 +1498,14 @@ namespace ts { // Pull parameter comments from declaring function as well if (node.kind === SyntaxKind.Parameter) { - result = concatenate(result, getContentFromParam(getJSDocParameterTag(node as ParameterDeclaration))); + result = concatenate(result, getContentFromParam(getJSDocParameterTag(node))); } if (isVariableLike(node) && node.initializer) { result = concatenate(result, getOwnJSDocs(node.initializer)); } - result = concatenate(result, getOwnJSDocs(node)); - - return result; + return concatenate(result, getOwnJSDocs(node)); } function getOwnJSDocs(node: Node) { @@ -1517,24 +1515,23 @@ namespace ts { } } - function getJSDocParameterTag(param: ParameterDeclaration): JSDocTag[] { - // TODO: getCorrespondingJSDocParameterTag is basically the same as this, except worse. (and typed, singleton return) + export function getJSDocParameterTag(param: Node): JSDocParameterTag[] { + if (!isParameter(param)) { + return undefined; + } const func = param.parent as FunctionLikeDeclaration; const tags = getJSDocTags(func); if (!param.name) { // this is an anonymous jsdoc param from a `function(type1, type2): type3` specification const i = func.parameters.indexOf(param); - const paramTags = filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag); + const paramTags = filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag) as JSDocParameterTag[]; if (paramTags && 0 <= i && i < paramTags.length) { return [paramTags[i]]; } } else if (param.name.kind === SyntaxKind.Identifier) { const name = (param.name as Identifier).text; - const paramTags = filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag && (tag as JSDocParameterTag).parameterName.text === name); - if (paramTags) { - return paramTags; - } + return filter(tags as JSDocParameterTag[], tag => tag.kind === SyntaxKind.JSDocParameterTag && tag.parameterName.text === name); } else { // TODO: it's a destructured parameter, so it should look up an "object type" series of multiple lines @@ -1544,12 +1541,11 @@ namespace ts { } export function getJSDocType(node: Node): JSDocType { - // TODO: If you have to call getparamtag, you really want the first with a typeExpression, not the first one. let tag: JSDocTypeTag | JSDocParameterTag = getJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag; if (!tag && node.kind === SyntaxKind.Parameter) { - const paramTags = getJSDocParameterTag(node as ParameterDeclaration); + const paramTags = getJSDocParameterTag(node); if (paramTags) { - tag = find(paramTags, tag => !!(tag as JSDocParameterTag).typeExpression) as JSDocParameterTag; + tag = find(paramTags, tag => !!tag.typeExpression); } } @@ -1564,29 +1560,6 @@ namespace ts { return getJSDocTag(node, SyntaxKind.JSDocTemplateTag) as JSDocTemplateTag; } - export function getCorrespondingJSDocParameterTag(parameter: ParameterDeclaration): JSDocParameterTag { - if (parameter.name && parameter.name.kind === SyntaxKind.Identifier) { - // If it's a parameter, see if the parent has a jsdoc comment with an @param - // annotation. - const parameterName = (parameter.name).text; - - const jsDocTags = getJSDocTags(parameter.parent); - if (!jsDocTags) { - return undefined; - } - for (const tag of jsDocTags) { - if (tag.kind === SyntaxKind.JSDocParameterTag) { - const parameterTag = tag; - if (parameterTag.parameterName.text === parameterName) { - return parameterTag; - } - } - } - } - - return undefined; - } - export function hasRestParameter(s: SignatureDeclaration): boolean { return isRestParameter(lastOrUndefined(s.parameters)); } @@ -1597,14 +1570,11 @@ namespace ts { export function isRestParameter(node: ParameterDeclaration) { if (node && (node.flags & NodeFlags.JavaScriptFile)) { - if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType) { + if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType || + forEach(getJSDocParameterTag(node), + t => t.typeExpression && t.typeExpression.type.kind === SyntaxKind.JSDocVariadicType)) { return true; } - - const paramTag = getCorrespondingJSDocParameterTag(node); - if (paramTag && paramTag.typeExpression) { - return paramTag.typeExpression.type.kind === SyntaxKind.JSDocVariadicType; - } } return isDeclaredRestParam(node); } From e81cfa10d6c670381ee0bb9823632df34bf57ab2 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 17 Nov 2016 15:32:16 -0800 Subject: [PATCH 5/9] Clean cache code and streamline other code Cache only uses one property now. getJSDocs isn't generic and doesn't take a function parameter any more. The code is overall easier to read. --- src/compiler/types.ts | 1 + src/compiler/utilities.ts | 83 +++++++++++++++++---------------------- 2 files changed, 36 insertions(+), 48 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index af46cb2173cb9..8b648000273df 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -498,6 +498,7 @@ namespace ts { /* @internal */ original?: Node; // The original node if this is an updated node. /* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms). /* @internal */ jsDocComments?: JSDoc[]; // JSDoc for the node, if it has any. + /* @internal */ jsDocCache?: (JSDoc | JSDocParameterTag)[]; // JSDoc for the node, plus JSDoc retrieved from its parents /* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding) /* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding) /* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 243d4f4c519ff..e5fd8b067b0e4 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1416,49 +1416,42 @@ namespace ts { (node).parameters[0].type.kind === SyntaxKind.JSDocConstructorType; } - function getJSDocTag(node: Node, kind: SyntaxKind): JSDocTag { - if (!node) { - return undefined; - } - - const jsDocTags = getJSDocTags(node); - if (!jsDocTags) { - return undefined; - } - - for (const tag of jsDocTags) { - if (tag.kind === kind) { - return tag; - } - } - } - export function getJSDocComments(node: Node): string[] { - return getJSDocs(node, docs => map(docs, doc => doc.comment), tags => map(tags, tag => tag.comment)); + return map(getJSDocs(node), doc => doc.comment); } - function getJSDocTags(node: Node): JSDocTag[] { - return getJSDocs(node, docs => { + function getJSDocTags(node: Node, kind: SyntaxKind): JSDocTag[] { + const docs = getJSDocs(node); + if (docs) { const result: JSDocTag[] = []; for (const doc of docs) { - if (doc.tags) { - result.push(...doc.tags); + if (doc.kind === SyntaxKind.JSDocParameterTag) { + if (doc.kind === kind) { + result.push(doc as JSDocParameterTag); + } + } + else { + result.push(...filter((doc as JSDoc).tags, tag => tag.kind === kind)); } } return result; - }, tags => tags); + } + } + + function getFirstJSDocTag(node: Node, kind: SyntaxKind): JSDocTag { + return node && firstOrUndefined(getJSDocTags(node, kind)); } - function getJSDocs(node: Node, getContent: (docs: JSDoc[]) => T[], getContentFromParam: (tags: JSDocTag[]) => T[]): T[] { - return getJSDocsWorker(node); + function getJSDocs(node: Node): (JSDoc | JSDocParameterTag)[] { + let cache: (JSDoc | JSDocParameterTag)[] = node.jsDocCache; + if (!cache) { + getJSDocsWorker(node); + node.jsDocCache = cache; + } + return cache; function getJSDocsWorker(node: Node) { - // 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 ... const parent = node.parent; - let result: T[] = undefined; - // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. // /** // * @param {number} name @@ -1476,7 +1469,7 @@ namespace ts { isVariableOfVariableDeclarationStatement ? parent.parent : undefined; if (variableStatementNode) { - result = concatenate(result, getJSDocsWorker(variableStatementNode)); + getJSDocsWorker(variableStatementNode); } // Also recognize when the node is the RHS of an assignment expression @@ -1486,32 +1479,26 @@ namespace ts { (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && parent.parent.kind === SyntaxKind.ExpressionStatement; if (isSourceOfAssignmentExpressionStatement) { - result = concatenate(result, getJSDocsWorker(parent.parent)); + getJSDocsWorker(parent.parent); } const isModuleDeclaration = node.kind === SyntaxKind.ModuleDeclaration && parent && parent.kind === SyntaxKind.ModuleDeclaration; const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment; if (isModuleDeclaration || isPropertyAssignmentExpression) { - result = concatenate(result, getJSDocsWorker(parent)); + getJSDocsWorker(parent); } // Pull parameter comments from declaring function as well if (node.kind === SyntaxKind.Parameter) { - result = concatenate(result, getContentFromParam(getJSDocParameterTag(node))); + cache = concatenate(cache, getJSDocParameterTag(node)); } if (isVariableLike(node) && node.initializer) { - result = concatenate(result, getOwnJSDocs(node.initializer)); + cache = concatenate(cache, node.initializer.jsDocComments); } - return concatenate(result, getOwnJSDocs(node)); - } - - function getOwnJSDocs(node: Node) { - if (node.jsDocComments) { - return getContent(node.jsDocComments); - } + cache = concatenate(cache, node.jsDocComments); } } @@ -1520,18 +1507,18 @@ namespace ts { return undefined; } const func = param.parent as FunctionLikeDeclaration; - const tags = getJSDocTags(func); + const tags = getJSDocTags(func, SyntaxKind.JSDocParameterTag) as JSDocParameterTag[]; if (!param.name) { // this is an anonymous jsdoc param from a `function(type1, type2): type3` specification const i = func.parameters.indexOf(param); - const paramTags = filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag) as JSDocParameterTag[]; + const paramTags = filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag); if (paramTags && 0 <= i && i < paramTags.length) { return [paramTags[i]]; } } else if (param.name.kind === SyntaxKind.Identifier) { const name = (param.name as Identifier).text; - return filter(tags as JSDocParameterTag[], tag => tag.kind === SyntaxKind.JSDocParameterTag && tag.parameterName.text === name); + return filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag && tag.parameterName.text === name); } else { // TODO: it's a destructured parameter, so it should look up an "object type" series of multiple lines @@ -1541,7 +1528,7 @@ namespace ts { } export function getJSDocType(node: Node): JSDocType { - let tag: JSDocTypeTag | JSDocParameterTag = getJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag; + let tag: JSDocTypeTag | JSDocParameterTag = getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag; if (!tag && node.kind === SyntaxKind.Parameter) { const paramTags = getJSDocParameterTag(node); if (paramTags) { @@ -1553,11 +1540,11 @@ namespace ts { } export function getJSDocReturnTag(node: Node): JSDocReturnTag { - return getJSDocTag(node, SyntaxKind.JSDocReturnTag) as JSDocReturnTag; + return getFirstJSDocTag(node, SyntaxKind.JSDocReturnTag) as JSDocReturnTag; } export function getJSDocTemplateTag(node: Node): JSDocTemplateTag { - return getJSDocTag(node, SyntaxKind.JSDocTemplateTag) as JSDocTemplateTag; + return getFirstJSDocTag(node, SyntaxKind.JSDocTemplateTag) as JSDocTemplateTag; } export function hasRestParameter(s: SignatureDeclaration): boolean { From ab84cd0647719a468e4bd6f7b911a094fe7c685d Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 18 Nov 2016 15:03:40 -0800 Subject: [PATCH 6/9] Improve readability of types and names --- src/compiler/checker.ts | 2 +- src/compiler/types.ts | 2 +- src/compiler/utilities.ts | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0803814bc14a2..94bbd8823e9f0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4854,7 +4854,7 @@ namespace ts { if (node.type && node.type.kind === SyntaxKind.JSDocOptionalType) { return true; } - const paramTags = getJSDocParameterTag(node); + const paramTags = getJSDocParameterTags(node); if (paramTags) { for (const paramTag of paramTags) { if (paramTag.isBracketed) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8b648000273df..51805228e4895 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -498,7 +498,7 @@ namespace ts { /* @internal */ original?: Node; // The original node if this is an updated node. /* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms). /* @internal */ jsDocComments?: JSDoc[]; // JSDoc for the node, if it has any. - /* @internal */ jsDocCache?: (JSDoc | JSDocParameterTag)[]; // JSDoc for the node, plus JSDoc retrieved from its parents + /* @internal */ jsDocCache?: (JSDoc | JSDocTag)[]; // JSDoc for the node, plus JSDoc and tags retrieved from its parents /* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding) /* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding) /* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index e5fd8b067b0e4..08eaa8033aedf 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1427,7 +1427,7 @@ namespace ts { for (const doc of docs) { if (doc.kind === SyntaxKind.JSDocParameterTag) { if (doc.kind === kind) { - result.push(doc as JSDocParameterTag); + result.push(doc as JSDocTag); } } else { @@ -1442,8 +1442,8 @@ namespace ts { return node && firstOrUndefined(getJSDocTags(node, kind)); } - function getJSDocs(node: Node): (JSDoc | JSDocParameterTag)[] { - let cache: (JSDoc | JSDocParameterTag)[] = node.jsDocCache; + function getJSDocs(node: Node): (JSDoc | JSDocTag)[] { + let cache: (JSDoc | JSDocTag)[] = node.jsDocCache; if (!cache) { getJSDocsWorker(node); node.jsDocCache = cache; @@ -1491,7 +1491,7 @@ namespace ts { // Pull parameter comments from declaring function as well if (node.kind === SyntaxKind.Parameter) { - cache = concatenate(cache, getJSDocParameterTag(node)); + cache = concatenate(cache, getJSDocParameterTags(node)); } if (isVariableLike(node) && node.initializer) { @@ -1502,7 +1502,7 @@ namespace ts { } } - export function getJSDocParameterTag(param: Node): JSDocParameterTag[] { + export function getJSDocParameterTags(param: Node): JSDocParameterTag[] { if (!isParameter(param)) { return undefined; } @@ -1530,7 +1530,7 @@ namespace ts { export function getJSDocType(node: Node): JSDocType { let tag: JSDocTypeTag | JSDocParameterTag = getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag; if (!tag && node.kind === SyntaxKind.Parameter) { - const paramTags = getJSDocParameterTag(node); + const paramTags = getJSDocParameterTags(node); if (paramTags) { tag = find(paramTags, tag => !!tag.typeExpression); } @@ -1558,7 +1558,7 @@ namespace ts { export function isRestParameter(node: ParameterDeclaration) { if (node && (node.flags & NodeFlags.JavaScriptFile)) { if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType || - forEach(getJSDocParameterTag(node), + forEach(getJSDocParameterTags(node), t => t.typeExpression && t.typeExpression.type.kind === SyntaxKind.JSDocVariadicType)) { return true; } From 7caee79ce7aa698a84f98f7a88796d56c5e90624 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 18 Nov 2016 15:10:19 -0800 Subject: [PATCH 7/9] Rename getJSDocComments -> getCommentsFromJSDoc --- src/compiler/utilities.ts | 2 +- src/services/jsDoc.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 08eaa8033aedf..5669ac9be8d3e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1416,7 +1416,7 @@ namespace ts { (node).parameters[0].type.kind === SyntaxKind.JSDocConstructorType; } - export function getJSDocComments(node: Node): string[] { + export function getCommentsFromJSDoc(node: Node): string[] { return map(getJSDocs(node), doc => doc.comment); } diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 24e99cf5c7754..3369ac23223c2 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -52,7 +52,7 @@ namespace ts.JsDoc { // from Array - Array and Array const documentationComment = []; forEachUnique(declarations, declaration => { - const comments = getJSDocComments(declaration); + const comments = getCommentsFromJSDoc(declaration); if (!comments) { return; } From 91e6bce34c3a2d771b815cd73c176018186b31b5 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 18 Nov 2016 15:44:15 -0800 Subject: [PATCH 8/9] Address PR comments --- src/compiler/binder.ts | 4 ++-- src/compiler/parser.ts | 20 ++++++++++---------- src/compiler/types.ts | 4 ++-- src/compiler/utilities.ts | 12 ++++++------ src/services/navigationBar.ts | 4 ++-- src/services/services.ts | 6 +++--- src/services/utilities.ts | 8 ++++---- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 1afe51db0218b..c2bfce10e57d6 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -599,8 +599,8 @@ namespace ts { // Binding of JsDocComment should be done before the current block scope container changes. // because the scope of JsDocComment should not be affected by whether the current node is a // container or not. - if (isInJavaScriptFile(node) && node.jsDocComments) { - forEach(node.jsDocComments, bind); + if (isInJavaScriptFile(node) && node.jsDoc) { + forEach(node.jsDoc, bind); } if (checkUnreachable(node)) { bindEachChild(node); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a3c21eaf8dca2..d286a9d9dac10 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -689,10 +689,10 @@ namespace ts { continue; } - if (!node.jsDocComments) { - node.jsDocComments = []; + if (!node.jsDoc) { + node.jsDoc = []; } - node.jsDocComments.push(jsDoc); + node.jsDoc.push(jsDoc); } } @@ -719,11 +719,11 @@ namespace ts { const saveParent = parent; parent = n; forEachChild(n, visitNode); - if (n.jsDocComments) { - for (const jsDocComment of n.jsDocComments) { - jsDocComment.parent = n; - parent = jsDocComment; - forEachChild(jsDocComment, visitNode); + if (n.jsDoc) { + for (const jsDoc of n.jsDoc) { + jsDoc.parent = n; + parent = jsDoc; + forEachChild(jsDoc, visitNode); } } parent = saveParent; @@ -6954,8 +6954,8 @@ namespace ts { } forEachChild(node, visitNode, visitArray); - if (node.jsDocComments) { - for (const jsDocComment of node.jsDocComments) { + if (node.jsDoc) { + for (const jsDocComment of node.jsDoc) { forEachChild(jsDocComment, visitNode, visitArray); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 51805228e4895..2a4b9e66d82e9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -497,8 +497,8 @@ namespace ts { parent?: Node; // Parent node (initialized by binding) /* @internal */ original?: Node; // The original node if this is an updated node. /* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms). - /* @internal */ jsDocComments?: JSDoc[]; // JSDoc for the node, if it has any. - /* @internal */ jsDocCache?: (JSDoc | JSDocTag)[]; // JSDoc for the node, plus JSDoc and tags retrieved from its parents + /* @internal */ jsDoc?: JSDoc[]; // JSDoc that directly precedes this node + /* @internal */ jsDocCache?: (JSDoc | JSDocTag)[]; // All JSDoc that applies to the node, including parent docs and @param tags /* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding) /* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding) /* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 5669ac9be8d3e..1d14854cd1f05 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -239,7 +239,7 @@ namespace ts { return !nodeIsMissing(node); } - export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile, includeJsDocComment?: boolean): number { + export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile, includeJsDoc?: boolean): number { // With nodes that have no width (i.e. 'Missing' nodes), we actually *don't* // want to skip trivia because this will launch us forward to the next token. if (nodeIsMissing(node)) { @@ -250,8 +250,8 @@ namespace ts { return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true); } - if (includeJsDocComment && node.jsDocComments && node.jsDocComments.length > 0) { - return getTokenPosOfNode(node.jsDocComments[0]); + if (includeJsDoc && node.jsDoc && node.jsDoc.length > 0) { + return getTokenPosOfNode(node.jsDoc[0]); } // For a syntax list, it is possible that one of its children has JSDocComment nodes, while @@ -259,7 +259,7 @@ namespace ts { // trivia for the list, we may have skipped the JSDocComment as well. So we should process its // first child to determine the actual position of its first token. if (node.kind === SyntaxKind.SyntaxList && (node)._children.length > 0) { - return getTokenPosOfNode((node)._children[0], sourceFile, includeJsDocComment); + return getTokenPosOfNode((node)._children[0], sourceFile, includeJsDoc); } return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos); @@ -1495,10 +1495,10 @@ namespace ts { } if (isVariableLike(node) && node.initializer) { - cache = concatenate(cache, node.initializer.jsDocComments); + cache = concatenate(cache, node.initializer.jsDoc); } - cache = concatenate(cache, node.jsDocComments); + cache = concatenate(cache, node.jsDoc); } } diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 51ce9b6001d53..1cbaa3d640faf 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -225,8 +225,8 @@ namespace ts.NavigationBar { break; default: - forEach(node.jsDocComments, jsDocComment => { - forEach(jsDocComment.tags, tag => { + forEach(node.jsDoc, jsDoc => { + forEach(jsDoc.tags, tag => { if (tag.kind === SyntaxKind.JSDocTypedefTag) { addLeafNode(tag); } diff --git a/src/services/services.ts b/src/services/services.ts index 3c0b78383141d..f826a8850fe2d 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1956,9 +1956,9 @@ namespace ts { break; default: forEachChild(node, walk); - if (node.jsDocComments) { - for (const jsDocComment of node.jsDocComments) { - forEachChild(jsDocComment, walk); + if (node.jsDoc) { + for (const jsDoc of node.jsDoc) { + forEachChild(jsDoc, walk); } } } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 82b13f8232769..e19fdc0a84a49 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -951,10 +951,10 @@ namespace ts { } if (node) { - if (node.jsDocComments) { - for (const jsDocComment of node.jsDocComments) { - if (jsDocComment.tags) { - for (const tag of jsDocComment.tags) { + if (node.jsDoc) { + for (const jsDoc of node.jsDoc) { + if (jsDoc.tags) { + for (const tag of jsDoc.tags) { if (tag.pos <= position && position <= tag.end) { return tag; } From 0c5429d3b704e557c5be8573a6faba4da30f10a2 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 18 Nov 2016 15:48:31 -0800 Subject: [PATCH 9/9] Add missed jsDoc rename in services' Node implementation Why would you implement an interface using a *class*? --- src/services/services.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index f826a8850fe2d..847967b2be986 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -45,7 +45,7 @@ namespace ts { public end: number; public flags: NodeFlags; public parent: Node; - public jsDocComments: JSDoc[]; + public jsDoc: JSDoc[]; public original: Node; public transformFlags: TransformFlags; private _children: Node[]; @@ -154,8 +154,8 @@ namespace ts { pos = nodes.end; }; // jsDocComments need to be the first children - if (this.jsDocComments) { - for (const jsDocComment of this.jsDocComments) { + if (this.jsDoc) { + for (const jsDocComment of this.jsDoc) { processNode(jsDocComment); } }