From 2c04ddfe3c1e55879e524f5ce40e1dba2fd80fcb Mon Sep 17 00:00:00 2001 From: Brett Zamir Date: Mon, 26 Jun 2023 08:04:33 +0800 Subject: [PATCH] feat(`valid-types`): check `link` and `tutorial` for content; #233 --- docs/rules/valid-types.md | 27 +++++++++++++ src/jsdocUtils.js | 2 +- src/rules/validTypes.js | 17 ++++++++ test/rules/assertions/validTypes.js | 60 +++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 1 deletion(-) diff --git a/docs/rules/valid-types.md b/docs/rules/valid-types.md index 8c88d81d5..5b0f61cfa 100644 --- a/docs/rules/valid-types.md +++ b/docs/rules/valid-types.md @@ -487,6 +487,21 @@ function quux (items) { } // Settings: {"jsdoc":{"mode":"typescript"}} // Message: Syntax error in type: JsdocTypeNullable + +/** + * An inline {@link} tag without content. + */ +// Message: Inline tag "link" missing content + +/** + * An inline {@tutorial} tag without content. + */ +// Message: Inline tag "tutorial" missing content + +/** + * @param {SomeType} aName An inline {@link} tag without content. + */ +// Message: Inline tag "link" missing content ```` @@ -850,5 +865,17 @@ function quux() { /** * @returns {Promise<{publicKey, privateKey}>} - The public and private key */ + +/** + * Some other {@inline} tag. + */ + +/** + * @param {SomeType} aName An inline {@link text} tag with content. + */ + +/** + * An inline {@link text} tag with content. + */ ```` diff --git a/src/jsdocUtils.js b/src/jsdocUtils.js index 10a9f6a98..89d186ebb 100644 --- a/src/jsdocUtils.js +++ b/src/jsdocUtils.js @@ -483,7 +483,7 @@ const hasParams = (functionNode) => { /** * Gets all names of the target type, including those that refer to a path, e.g. - * "@param foo; @param foo.bar". + * `foo` or `foo.bar`. * @param {import('comment-parser').Block} jsdoc * @param {string} targetTagName * @returns {{ diff --git a/src/rules/validTypes.js b/src/rules/validTypes.js index 702ceccea..c3df2edcb 100644 --- a/src/rules/validTypes.js +++ b/src/rules/validTypes.js @@ -5,6 +5,11 @@ import { tryParse, } from '@es-joy/jsdoccomment'; +const inlineTags = new Set([ + 'link', 'linkcode', 'linkplain', + 'tutorial', +]); + const asExpression = /as\s+/u; const suppressTypes = new Set([ @@ -327,6 +332,18 @@ export default iterateJsdoc(({ validNamepathParsing(tag.name, tag.tag); } } + + for (const inlineTag of tag.inlineTags) { + if (inlineTags.has(inlineTag.tag) && !inlineTag.text && !inlineTag.namepathOrURL) { + report(`Inline tag "${inlineTag.tag}" missing content`, null, tag); + } + } + } + + for (const inlineTag of jsdoc.inlineTags) { + if (inlineTags.has(inlineTag.tag) && !inlineTag.text && !inlineTag.namepathOrURL) { + report(`Inline tag "${inlineTag.tag}" missing content`); + } } }, { iterateAllJsdocs: true, diff --git a/test/rules/assertions/validTypes.js b/test/rules/assertions/validTypes.js index d7b12db92..fe605976b 100644 --- a/test/rules/assertions/validTypes.js +++ b/test/rules/assertions/validTypes.js @@ -1102,6 +1102,45 @@ export default { }, }, }, + { + code: ` + /** + * An inline {@link} tag without content. + */ + `, + errors: [ + { + line: 2, + message: 'Inline tag "link" missing content', + }, + ], + }, + { + code: ` + /** + * An inline {@tutorial} tag without content. + */ + `, + errors: [ + { + line: 2, + message: 'Inline tag "tutorial" missing content', + }, + ], + }, + { + code: ` + /** + * @param {SomeType} aName An inline {@link} tag without content. + */ + `, + errors: [ + { + line: 3, + message: 'Inline tag "link" missing content', + }, + ], + }, ], valid: [ { @@ -1790,5 +1829,26 @@ export default { */ `, }, + { + code: ` + /** + * Some other {@inline} tag. + */ + `, + }, + { + code: ` + /** + * @param {SomeType} aName An inline {@link text} tag with content. + */ + `, + }, + { + code: ` + /** + * An inline {@link text} tag with content. + */ + `, + }, ], };