diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 8ca6a6c7cae..6f387271048 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -8,6 +8,7 @@ import { CompletionEntry, CompletionEntryDetails, Completions, + concatenate, ConstructorDeclaration, contains, Declaration, @@ -258,17 +259,21 @@ export function getJsDocTagsFromDeclarations(declarations?: Declaration[], check } for (const tag of tags) { infos.push({ name: tag.tagName.text, text: getCommentDisplayParts(tag, checker) }); - - if (isJSDocPropertyLikeTag(tag) && tag.isNameFirst && tag.typeExpression && isJSDocTypeLiteral(tag.typeExpression.type)) { - forEach(tag.typeExpression.type.jsDocPropertyTags, propTag => { - infos.push({ name: propTag.tagName.text, text: getCommentDisplayParts(propTag, checker) }); - }); - } + infos.push(...getJSDocPropertyTagsInfo(tryGetJSDocPropertyTags(tag), checker)); } }); return infos; } +function getJSDocPropertyTagsInfo(nodes: readonly JSDocTag[] | undefined, checker: TypeChecker | undefined): readonly JSDocTagInfo[] { + return flatMap(nodes, propTag => concatenate([{ name: propTag.tagName.text, text: getCommentDisplayParts(propTag, checker) }], getJSDocPropertyTagsInfo(tryGetJSDocPropertyTags(propTag), checker))); +} + +function tryGetJSDocPropertyTags(node: JSDocTag) { + return isJSDocPropertyLikeTag(node) && node.isNameFirst && node.typeExpression && + isJSDocTypeLiteral(node.typeExpression.type) ? node.typeExpression.type.jsDocPropertyTags : undefined; +} + function getDisplayPartsFromComment(comment: string | readonly JSDocComment[], checker: TypeChecker | undefined): SymbolDisplayPart[] { if (typeof comment === "string") { return [textPart(comment)]; diff --git a/tests/baselines/reference/quickInfoJsDocTags14.baseline b/tests/baselines/reference/quickInfoJsDocTags14.baseline new file mode 100644 index 00000000000..ec3e3738e89 --- /dev/null +++ b/tests/baselines/reference/quickInfoJsDocTags14.baseline @@ -0,0 +1,227 @@ +// === QuickInfo === +=== /tests/cases/fourslash/quickInfoJsDocTags14.ts === +// /** +// * @param {Object} options the args object +// * @param {number} options.a first number +// * @param {number} options.b second number +// * @param {Object} options.c sub-object +// * @param {number} options.c.d third number +// * @param {Function} callback the callback function +// * @returns {number} +// */ +// function fn(options, callback = null) { } +// ^^ +// | ---------------------------------------------------------------------- +// | function fn(options: any, callback?: any): void +// | @param options the args object +// | @param options.a first number +// | @param options.b second number +// | @param options.c sub-object +// | @param options.c.d third number +// | @param callback the callback function +// | @returns +// | ---------------------------------------------------------------------- + +[ + { + "marker": { + "fileName": "/tests/cases/fourslash/quickInfoJsDocTags14.ts", + "position": 302, + "name": "" + }, + "item": { + "kind": "function", + "kindModifiers": "", + "textSpan": { + "start": 302, + "length": 2 + }, + "displayParts": [ + { + "text": "function", + "kind": "keyword" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "fn", + "kind": "functionName" + }, + { + "text": "(", + "kind": "punctuation" + }, + { + "text": "options", + "kind": "parameterName" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "any", + "kind": "keyword" + }, + { + "text": ",", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "callback", + "kind": "parameterName" + }, + { + "text": "?", + "kind": "punctuation" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "any", + "kind": "keyword" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "void", + "kind": "keyword" + } + ], + "documentation": [], + "tags": [ + { + "name": "param", + "text": [ + { + "text": "options", + "kind": "parameterName" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "the args object", + "kind": "text" + } + ] + }, + { + "name": "param", + "text": [ + { + "text": "options.a", + "kind": "parameterName" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "first number", + "kind": "text" + } + ] + }, + { + "name": "param", + "text": [ + { + "text": "options.b", + "kind": "parameterName" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "second number", + "kind": "text" + } + ] + }, + { + "name": "param", + "text": [ + { + "text": "options.c", + "kind": "parameterName" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "sub-object", + "kind": "text" + } + ] + }, + { + "name": "param", + "text": [ + { + "text": "options.c.d", + "kind": "parameterName" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "third number", + "kind": "text" + } + ] + }, + { + "name": "param", + "text": [ + { + "text": "callback", + "kind": "parameterName" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "the callback function", + "kind": "text" + } + ] + }, + { + "name": "returns" + } + ] + } + } +] \ No newline at end of file diff --git a/tests/cases/fourslash/quickInfoJsDocTags14.ts b/tests/cases/fourslash/quickInfoJsDocTags14.ts new file mode 100644 index 00000000000..ee6781e2751 --- /dev/null +++ b/tests/cases/fourslash/quickInfoJsDocTags14.ts @@ -0,0 +1,14 @@ +/// + +/////** +//// * @param {Object} options the args object +//// * @param {number} options.a first number +//// * @param {number} options.b second number +//// * @param {Object} options.c sub-object +//// * @param {number} options.c.d third number +//// * @param {Function} callback the callback function +//// * @returns {number} +//// */ +////function /**/fn(options, callback = null) { } + +verify.baselineQuickInfo();