diff --git a/.README/rules/match-description.md b/.README/rules/match-description.md index 9dca7d442..0abd943e3 100644 --- a/.README/rules/match-description.md +++ b/.README/rules/match-description.md @@ -50,6 +50,14 @@ tag should be linted with the `matchDescription` value (or the default). } ``` +The tags `@param`/`@arg`/`@argument` will be properly parsed to ensure that +the matched "description" text includes only the text after the name. +All other tags will treat the text following the tag name, a space, and +an optional curly-bracketed type expression (and another space) as part of +its "description" (e.g., for `@returns {someType} some description`, the +description is `some description` while for `@some-tag xyz`, the description +is `xyz`). + ##### `mainDescription` If you wish to override the main function description without changing the @@ -82,6 +90,6 @@ Overrides the default contexts (see below). |Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`; others when `contexts` option enabled| |Tags|N/A by default but see `tags` options| |Settings|| -|Options|`contexts`, `tags` (allows for 'param', 'arg', 'argument', 'returns', 'return', 'description', 'desc'), `mainDescription`, `matchDescription`| +|Options|`contexts`, `tags` (allows for 'param', 'arg', 'argument', 'description', 'desc', and any added to `tags` option, e.g., 'returns', 'return'), `mainDescription`, `matchDescription`| diff --git a/README.md b/README.md index 82231a183..92fdb1570 100644 --- a/README.md +++ b/README.md @@ -2428,6 +2428,14 @@ tag should be linted with the `matchDescription` value (or the default). } ``` +The tags `@param`/`@arg`/`@argument` will be properly parsed to ensure that +the matched "description" text includes only the text after the name. +All other tags will treat the text following the tag name, a space, and +an optional curly-bracketed type expression (and another space) as part of +its "description" (e.g., for `@returns {someType} some description`, the +description is `some description` while for `@some-tag xyz`, the description +is `xyz`). + ##### mainDescription @@ -2462,7 +2470,7 @@ Overrides the default contexts (see below). |Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`; others when `contexts` option enabled| |Tags|N/A by default but see `tags` options| |Settings|| -|Options|`contexts`, `tags` (allows for 'param', 'arg', 'argument', 'returns', 'return', 'description', 'desc'), `mainDescription`, `matchDescription`| +|Options|`contexts`, `tags` (allows for 'param', 'arg', 'argument', 'description', 'desc', and any added to `tags` option, e.g., 'returns', 'return'), `mainDescription`, `matchDescription`| The following patterns are considered problems: @@ -2538,6 +2546,39 @@ function quux (foo) { // Options: [{"tags":{"param":true}}] // Message: JSDoc description does not satisfy the regex pattern. +/** + * Foo. + * + * @summary foo. + */ +function quux () { + +} +// Options: [{"tags":{"summary":true}}] +// Message: JSDoc description does not satisfy the regex pattern. + +/** + * Foo. + * + * @author + */ +function quux () { + +} +// Options: [{"tags":{"author":".+"}}] +// Message: JSDoc description does not satisfy the regex pattern. + +/** + * Foo. + * + * @x-tag + */ +function quux () { + +} +// Options: [{"tags":{"x-tag":".+"}}] +// Message: JSDoc description does not satisfy the regex pattern. + /** * Foo. * @@ -2797,6 +2838,14 @@ function quux () { } // Options: [{"tags":{"returns":true}}] +/** + * @returns {type1} Foo bar. + */ +function quux () { + +} +// Options: [{"tags":{"returns":true}}] + /** * @description Foo bar. */ @@ -2934,6 +2983,36 @@ function quux () { } // Options: [{"tags":{"param":true}}] + +/** + * Foo. + * + * @summary Foo. + */ +function quux () { + +} +// Options: [{"tags":{"summary":true}}] + +/** + * Foo. + * + * @author Somebody + */ +function quux () { + +} +// Options: [{"tags":{"author":".+"}}] + +/** + * Foo. + * + * @x-tag something + */ +function quux () { + +} +// Options: [{"tags":{"x-tag":".+"}}] ```` diff --git a/src/rules/matchDescription.js b/src/rules/matchDescription.js index 1bf4c7a47..d1ef93260 100644 --- a/src/rules/matchDescription.js +++ b/src/rules/matchDescription.js @@ -1,7 +1,7 @@ import _ from 'lodash'; import iterateJsdoc from '../iterateJsdoc'; -const tagsWithDescriptions = ['param', 'arg', 'argument', 'returns', 'return']; +const tagsWithNamesAndDescriptions = ['param', 'arg', 'argument']; // If supporting Node >= 10, we could loosen the default to this for the // initial letter: \\p{Upper} @@ -57,22 +57,40 @@ export default iterateJsdoc(({ return Boolean(options.tags[tagName]); }; + let descName; utils.forEachPreferredTag('description', (matchingJsdocTag, targetTagName) => { + descName = targetTagName; const description = (matchingJsdocTag.name + ' ' + matchingJsdocTag.description).trim(); if (hasOptionTag(targetTagName)) { validateDescription(description, matchingJsdocTag); } }); - const tags = utils.filterTags(({tag}) => { - return tagsWithDescriptions.includes(tag) && hasOptionTag(tag); + const tagsWithoutNames = []; + const tagsWithNames = utils.filterTags((tag) => { + const {tag: tagName} = tag; + if (!hasOptionTag(tagName)) { + return false; + } + const tagWithName = tagsWithNamesAndDescriptions.includes(tagName); + if (!tagWithName && tagName !== descName) { + tagsWithoutNames.push(tag); + } + + return tagWithName; }); - tags.some((tag) => { + tagsWithNames.some((tag) => { const description = _.trimStart(tag.description, '- '); return validateDescription(description, tag); }); + + tagsWithoutNames.some((tag) => { + const description = (tag.name + ' ' + tag.description).trim(); + + return validateDescription(description, tag); + }); }, { contextDefaults: true, meta: { diff --git a/test/rules/assertions/matchDescription.js b/test/rules/assertions/matchDescription.js index 0f7d4f7b1..fc2bc3fed 100644 --- a/test/rules/assertions/matchDescription.js +++ b/test/rules/assertions/matchDescription.js @@ -160,6 +160,81 @@ export default { } ] }, + { + code: ` + /** + * Foo. + * + * @summary foo. + */ + function quux () { + + } + `, + errors: [ + { + line: 5, + message: 'JSDoc description does not satisfy the regex pattern.' + } + ], + options: [ + { + tags: { + summary: true + } + } + ] + }, + { + code: ` + /** + * Foo. + * + * @author + */ + function quux () { + + } + `, + errors: [ + { + line: 5, + message: 'JSDoc description does not satisfy the regex pattern.' + } + ], + options: [ + { + tags: { + author: '.+' + } + } + ] + }, + { + code: ` + /** + * Foo. + * + * @x-tag + */ + function quux () { + + } + `, + errors: [ + { + line: 5, + message: 'JSDoc description does not satisfy the regex pattern.' + } + ], + options: [ + { + tags: { + 'x-tag': '.+' + } + } + ] + }, { code: ` /** @@ -706,6 +781,23 @@ export default { } ] }, + { + code: ` + /** + * @returns {type1} Foo bar. + */ + function quux () { + + } + `, + options: [ + { + tags: { + returns: true + } + } + ] + }, { code: ` /** @@ -937,6 +1029,63 @@ export default { param: true }} ] + }, + { + code: ` + /** + * Foo. + * + * @summary Foo. + */ + function quux () { + + } + `, + options: [ + { + tags: { + summary: true + } + } + ] + }, + { + code: ` + /** + * Foo. + * + * @author Somebody + */ + function quux () { + + } + `, + options: [ + { + tags: { + author: '.+' + } + } + ] + }, + { + code: ` + /** + * Foo. + * + * @x-tag something + */ + function quux () { + + } + `, + options: [ + { + tags: { + 'x-tag': '.+' + } + } + ] } ] };