Skip typedef in services getJSDocTags (#43677)

* Symbols in services skip @typedef/@callback in jsdoc

Fixes #43534

* comment text skips jsdocs that are typedef-only

* Skip comment text from typedef-only jsdocs

* Skip whole comments instead of individual tags

* add semicolons

* retain comments from @callback + better comments
This commit is contained in:
Nathan Shively-Sanders 2021-06-23 16:19:14 -07:00 committed by GitHub
parent ece76e8a63
commit aee779ac7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 263 additions and 7 deletions

View File

@ -92,9 +92,20 @@ namespace ts.JsDoc {
// from Array<T> - Array<string> and Array<number>
const parts: SymbolDisplayPart[][] = [];
forEachUnique(declarations, declaration => {
for (const { comment } of getCommentHavingNodes(declaration)) {
if (comment === undefined) continue;
const newparts = getDisplayPartsFromComment(comment, checker);
for (const jsdoc of getCommentHavingNodes(declaration)) {
// skip comments containing @typedefs since they're not associated with particular declarations
// Exceptions:
// - @typedefs are themselves declarations with associated comments
// - @param or @return indicate that the author thinks of it as a 'local' @typedef that's part of the function documentation
if (jsdoc.comment === undefined
|| isJSDoc(jsdoc)
&& declaration.kind !== SyntaxKind.JSDocTypedefTag && declaration.kind !== SyntaxKind.JSDocCallbackTag
&& jsdoc.tags
&& jsdoc.tags.some(t => t.kind === SyntaxKind.JSDocTypedefTag || t.kind === SyntaxKind.JSDocCallbackTag)
&& !jsdoc.tags.some(t => t.kind === SyntaxKind.JSDocParameterTag || t.kind === SyntaxKind.JSDocReturnTag)) {
continue;
}
const newparts = getDisplayPartsFromComment(jsdoc.comment, checker);
if (!contains(parts, newparts, isIdenticalListOfDisplayParts)) {
parts.push(newparts);
}
@ -122,13 +133,21 @@ namespace ts.JsDoc {
export function getJsDocTagsFromDeclarations(declarations?: Declaration[], checker?: TypeChecker): JSDocTagInfo[] {
// Only collect doc comments from duplicate declarations once.
const tags: JSDocTagInfo[] = [];
const infos: JSDocTagInfo[] = [];
forEachUnique(declarations, declaration => {
for (const tag of getJSDocTags(declaration)) {
tags.push({ name: tag.tagName.text, text: getCommentDisplayParts(tag, checker) });
const tags = getJSDocTags(declaration);
// skip comments containing @typedefs since they're not associated with particular declarations
// Exceptions:
// - @param or @return indicate that the author thinks of it as a 'local' @typedef that's part of the function documentation
if (tags.some(t => t.kind === SyntaxKind.JSDocTypedefTag || t.kind === SyntaxKind.JSDocCallbackTag)
&& !tags.some(t => t.kind === SyntaxKind.JSDocParameterTag || t.kind === SyntaxKind.JSDocReturnTag)) {
return;
}
for (const tag of tags) {
infos.push({ name: tag.tagName.text, text: getCommentDisplayParts(tag, checker) });
}
});
return tags;
return infos;
}
function getDisplayPartsFromComment(comment: string | readonly JSDocComment[], checker: TypeChecker | undefined): SymbolDisplayPart[] {

View File

@ -0,0 +1,210 @@
[
{
"marker": {
"fileName": "/tests/cases/fourslash/a.js",
"position": 114,
"name": "1"
},
"quickInfo": {
"kind": "function",
"kindModifiers": "",
"textSpan": {
"start": 113,
"length": 1
},
"displayParts": [
{
"text": "function",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "f",
"kind": "functionName"
},
{
"text": "(",
"kind": "punctuation"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "void",
"kind": "keyword"
}
],
"documentation": []
}
},
{
"marker": {
"fileName": "/tests/cases/fourslash/a.js",
"position": 316,
"name": "2"
},
"quickInfo": {
"kind": "function",
"kindModifiers": "",
"textSpan": {
"start": 315,
"length": 1
},
"displayParts": [
{
"text": "function",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "g",
"kind": "functionName"
},
{
"text": "(",
"kind": "punctuation"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "void",
"kind": "keyword"
}
],
"documentation": []
}
},
{
"marker": {
"fileName": "/tests/cases/fourslash/a.js",
"position": 472,
"name": "3"
},
"quickInfo": {
"kind": "function",
"kindModifiers": "",
"textSpan": {
"start": 471,
"length": 1
},
"displayParts": [
{
"text": "function",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "h",
"kind": "functionName"
},
{
"text": "(",
"kind": "punctuation"
},
{
"text": "keep",
"kind": "parameterName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "Local",
"kind": "aliasName"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "void",
"kind": "keyword"
}
],
"documentation": [
{
"text": "The whole thing is kept",
"kind": "text"
}
],
"tags": [
{
"name": "param",
"text": [
{
"text": "keep",
"kind": "text"
}
]
},
{
"name": "typedef",
"text": [
{
"text": "Local",
"kind": "aliasName"
},
{
"text": " ",
"kind": "space"
},
{
"text": "kept too",
"kind": "text"
}
]
},
{
"name": "returns",
"text": [
{
"text": "also kept",
"kind": "text"
}
]
}
]
}
}
]

View File

@ -0,0 +1,27 @@
/// <reference path='fourslash.ts' />
// @allowJs: true
// @Filename: a.js
//// /**
//// * The typedef tag should not appear in the quickinfo.
//// * @typedef {{ foo: 'foo' }} Foo
//// */
//// function f() { }
//// f/*1*/()
//// /**
//// * A removed comment
//// * @tag Usage shows that non-param tags in comments explain the typedef instead of using it
//// * @typedef {{ nope: any }} Nope not here
//// * @tag comment 2
//// */
//// function g() { }
//// g/*2*/()
//// /**
//// * The whole thing is kept
//// * @param {Local} keep
//// * @typedef {{ local: any }} Local kept too
//// * @returns {void} also kept
//// */
//// function h(keep) { }
//// h/*3*/({ nope: 1 })
verify.baselineQuickInfo()