From 9b865ed797b78df3cbca65ed1a713013c3cfbbe5 Mon Sep 17 00:00:00 2001 From: Daniel Martens Date: Sat, 4 Jun 2022 12:21:22 +0200 Subject: [PATCH] feat: Require description only for public functions --- .README/rules/require-description.md | 1 + .README/rules/require-param-description.md | 8 + .README/rules/require-returns-description.md | 8 + README.md | 237 ++++++++++++++++++ src/exportParser.js | 17 ++ src/iterateJsdoc.js | 9 + src/rules/requireDescription.js | 27 ++ src/rules/requireParamDescription.js | 27 ++ src/rules/requireReturnsDescription.js | 27 ++ test/rules/assertions/requireDescription.js | 162 ++++++++++++ .../assertions/requireParamDescription.js | 162 ++++++++++++ .../assertions/requireReturnsDescription.js | 165 ++++++++++++ 12 files changed, 850 insertions(+) diff --git a/.README/rules/require-description.md b/.README/rules/require-description.md index 39ec7d507..a2ff5488f 100644 --- a/.README/rules/require-description.md +++ b/.README/rules/require-description.md @@ -31,6 +31,7 @@ An options object may have any of the following properties: Defaults to `true`. - `checkSetters` - A value indicating whether setters should be checked. Defaults to `true`. +- `publicOnly`: - A value indicating whether only exported constructs should be checked | | | | -------- | ------------------------------------------------------------------------------------------------------------- | diff --git a/.README/rules/require-param-description.md b/.README/rules/require-param-description.md index 32e71486e..d7113b89f 100644 --- a/.README/rules/require-param-description.md +++ b/.README/rules/require-param-description.md @@ -4,6 +4,14 @@ Requires that each `@param` tag has a `description` value. #### Options +Accepts one optional options object with the following optional keys. + +##### `publicOnly` + +This option will insist that missing jsdoc blocks are only reported for +function bodies / class declarations that are exported from the module. +For more information see the documentation of `require-jsdoc`. + ##### `contexts` Set this to an array of strings representing the AST context (or an object with diff --git a/.README/rules/require-returns-description.md b/.README/rules/require-returns-description.md index 70663dbff..9b38a08ae 100644 --- a/.README/rules/require-returns-description.md +++ b/.README/rules/require-returns-description.md @@ -6,6 +6,14 @@ or if it is `Promise` or `Promise`. #### Options +Accepts one optional options object with the following optional keys. + +##### `publicOnly` + +This option will insist that missing jsdoc blocks are only reported for +function bodies / class declarations that are exported from the module. +For more information see the documentation of `require-jsdoc`. + ##### `contexts` Set this to an array of strings representing the AST context (or an object with diff --git a/README.md b/README.md index 3f1a16114..ca06b3f9e 100644 --- a/README.md +++ b/README.md @@ -11411,6 +11411,7 @@ An options object may have any of the following properties: Defaults to `true`. - `checkSetters` - A value indicating whether setters should be checked. Defaults to `true`. +- `publicOnly`: - A value indicating whether only exported constructs should be checked | | | | -------- | ------------------------------------------------------------------------------------------------------------- | @@ -11696,6 +11697,44 @@ class quux { // Settings: {"jsdoc":{"implementsReplacesDocs":false}} // "jsdoc/require-description": ["error"|"warn", {"contexts":[{"comment":"JsdocBlock[postDelimiter=\"\"]:has(JsdocTag[tag=\"implements\"])","context":"any"}],"descriptionStyle":"tag"}] // Message: Missing JSDoc @description declaration. + +/** + * + */ +export function quux (foo) { + +} +// "jsdoc/require-description": ["error"|"warn", {"publicOnly":true}] +// Message: Missing JSDoc block description. + +/** + * + */ +module.exports = function quux (foo) { + +} +// "jsdoc/require-description": ["error"|"warn", {"publicOnly":{"cjs":true,"esm":false}}] +// Message: Missing JSDoc block description. + +/** + * + */ +function quux (foo) { + +} +// "jsdoc/require-description": ["error"|"warn", {"publicOnly":false}] +// Message: Missing JSDoc block description. + +export default class Class { + /** + * + */ + quux(foo) { + + } +} +// "jsdoc/require-description": ["error"|"warn", {"publicOnly":true}] +// Message: Missing JSDoc block description. ```` The following patterns are not considered problems: @@ -11926,6 +11965,40 @@ class quux { * description already. */ // "jsdoc/require-description": ["error"|"warn", {"contexts":[{"comment":"JsdocBlock[postDelimiter=\"\"]:has(JsdocTag[rawType=\"{Bar}\"])","context":"any"}],"descriptionStyle":"tag"}] + +/** + * + */ +function quux (foo) { + +} +// "jsdoc/require-description": ["error"|"warn", {"publicOnly":true}] + +/** + * description + */ +export function quux (foo) { + +} +// "jsdoc/require-description": ["error"|"warn", {"publicOnly":true}] + +/** + * + */ +module.exports = function quux (foo) { + +} +// "jsdoc/require-description": ["error"|"warn", {"publicOnly":{"cjs":false}}] + +class Class { + /** + * + */ + quux(foo) { + + } +} +// "jsdoc/require-description": ["error"|"warn", {"publicOnly":true}] ```` @@ -14625,6 +14698,16 @@ Requires that each `@param` tag has a `description` value. #### Options +Accepts one optional options object with the following optional keys. + + + +##### publicOnly + +This option will insist that missing jsdoc blocks are only reported for +function bodies / class declarations that are exported from the module. +For more information see the documentation of `require-jsdoc`. + ##### contexts @@ -14699,6 +14782,44 @@ function quux (foo) { } // Settings: {"jsdoc":{"tagNamePreference":{"param":false}}} // Message: Unexpected tag `@param` + +/** + * @param foo + */ +export function quux (foo) { + +} +// "jsdoc/require-param-description": ["error"|"warn", {"publicOnly":true}] +// Message: Missing JSDoc @param "foo" description. + +/** + * @param foo + */ +module.exports = function quux (foo) { + +} +// "jsdoc/require-param-description": ["error"|"warn", {"publicOnly":{"cjs":true,"esm":false}}] +// Message: Missing JSDoc @param "foo" description. + +/** + * @param foo + */ +function quux (foo) { + +} +// "jsdoc/require-param-description": ["error"|"warn", {"publicOnly":false}] +// Message: Missing JSDoc @param "foo" description. + +export default class Class { + /** + * @param foo + */ + quux(foo) { + + } +} +// "jsdoc/require-param-description": ["error"|"warn", {"publicOnly":true}] +// Message: Missing JSDoc @param "foo" description. ```` The following patterns are not considered problems: @@ -14735,6 +14856,40 @@ function quux (foo) { * @callback * @param foo */ + +/** + * @param foo + */ +function quux (foo) { + +} +// "jsdoc/require-param-description": ["error"|"warn", {"publicOnly":true}] + +/** + * @param foo - description + */ +export function quux (foo) { + +} +// "jsdoc/require-param-description": ["error"|"warn", {"publicOnly":true}] + +/** + * @param + */ +module.exports = function quux (foo) { + +} +// "jsdoc/require-param-description": ["error"|"warn", {"publicOnly":{"cjs":false}}] + +class Class { + /** + * @param foo + */ + quux(foo) { + + } +} +// "jsdoc/require-param-description": ["error"|"warn", {"publicOnly":true}] ```` @@ -17665,6 +17820,16 @@ or if it is `Promise` or `Promise`. #### Options +Accepts one optional options object with the following optional keys. + + + +##### publicOnly + +This option will insist that missing jsdoc blocks are only reported for +function bodies / class declarations that are exported from the module. +For more information see the documentation of `require-jsdoc`. + ##### contexts @@ -17747,6 +17912,44 @@ function quux () { } // Settings: {"jsdoc":{"tagNamePreference":{"returns":false}}} // Message: Unexpected tag `@returns` + +/** + * @returns + */ +export function quux (foo) { + +} +// "jsdoc/require-returns-description": ["error"|"warn", {"publicOnly":true}] +// Message: Missing JSDoc @returns description. + +/** + * @returns + */ +module.exports = function quux (foo) { + +} +// "jsdoc/require-returns-description": ["error"|"warn", {"publicOnly":{"cjs":true,"esm":false}}] +// Message: Missing JSDoc @returns description. + +/** + * @returns + */ +function quux (foo) { + +} +// "jsdoc/require-returns-description": ["error"|"warn", {"publicOnly":false}] +// Message: Missing JSDoc @returns description. + +export default class Class { + /** + * @returns + */ + quux(foo) { + + } +} +// "jsdoc/require-returns-description": ["error"|"warn", {"publicOnly":true}] +// Message: Missing JSDoc @returns description. ```` The following patterns are not considered problems: @@ -17811,6 +18014,40 @@ function quux () { * @callback * @returns */ + +/** + * @returns + */ +function quux (foo) { + +} +// "jsdoc/require-returns-description": ["error"|"warn", {"publicOnly":true}] + +/** + * @returns - description + */ +export function quux (foo) { + +} +// "jsdoc/require-returns-description": ["error"|"warn", {"publicOnly":true}] + +/** + * @returns + */ +module.exports = function quux (foo) { + +} +// "jsdoc/require-returns-description": ["error"|"warn", {"publicOnly":{"cjs":false}}] + +class Class { + /** + * @returns + */ + quux(foo) { + + } +} +// "jsdoc/require-returns-description": ["error"|"warn", {"publicOnly":true}] ```` diff --git a/src/exportParser.js b/src/exportParser.js index eb258fc05..40d05f591 100644 --- a/src/exportParser.js +++ b/src/exportParser.js @@ -601,7 +601,24 @@ const isUncommentedExport = function (node, sourceCode, opt, settings) { return isNodeExported(node, parseResult.globalVars, opt); }; +const isPublic = function (node, sourceCode, opt) { + const normalizedOpts = { + ancestorsOnly: Boolean(opt?.ancestorsOnly ?? false), + esm: Boolean(opt?.esm ?? true), + initModuleExports: Boolean(opt?.cjs ?? true), + initWindow: Boolean(opt?.window ?? false), + }; + if (normalizedOpts.esm && (getExportAncestor(node) || isExportByAncestor(node))) { + return true; + } + + const parseResult = parse(sourceCode.ast, node, normalizedOpts); + + return isNodeExported(node, parseResult.globalVars, normalizedOpts); +}; + export default { + isPublic, isUncommentedExport, parse, }; diff --git a/src/iterateJsdoc.js b/src/iterateJsdoc.js index ef00d5d41..bdd7d215d 100644 --- a/src/iterateJsdoc.js +++ b/src/iterateJsdoc.js @@ -8,6 +8,7 @@ import { stringify as commentStringify, util, } from 'comment-parser'; +import exportParser from './exportParser.js'; import jsdocUtils from './jsdocUtils'; const { @@ -962,6 +963,14 @@ const iterate = ( return; } + if ( + context.options[0] && + context.options[0].publicOnly && + !exportParser.isPublic(node, sourceCode, context.options[0].publicOnly) + ) { + return; + } + iterator({ context, globalState, diff --git a/src/rules/requireDescription.js b/src/rules/requireDescription.js index d54ade9c7..d571885c4 100644 --- a/src/rules/requireDescription.js +++ b/src/rules/requireDescription.js @@ -146,6 +146,33 @@ export default iterateJsdoc(({ }, type: 'array', }, + publicOnly: { + oneOf: [ + { + default: false, + type: 'boolean', + }, + { + additionalProperties: false, + default: {}, + properties: { + ancestorsOnly: { + type: 'boolean', + }, + cjs: { + type: 'boolean', + }, + esm: { + type: 'boolean', + }, + window: { + type: 'boolean', + }, + }, + type: 'object', + }, + ], + }, }, type: 'object', }, diff --git a/src/rules/requireParamDescription.js b/src/rules/requireParamDescription.js index 37319f8f5..831ed41d0 100644 --- a/src/rules/requireParamDescription.js +++ b/src/rules/requireParamDescription.js @@ -46,6 +46,33 @@ export default iterateJsdoc(({ }, type: 'array', }, + publicOnly: { + oneOf: [ + { + default: false, + type: 'boolean', + }, + { + additionalProperties: false, + default: {}, + properties: { + ancestorsOnly: { + type: 'boolean', + }, + cjs: { + type: 'boolean', + }, + esm: { + type: 'boolean', + }, + window: { + type: 'boolean', + }, + }, + type: 'object', + }, + ], + }, }, type: 'object', }, diff --git a/src/rules/requireReturnsDescription.js b/src/rules/requireReturnsDescription.js index d3de206dd..c58b7355c 100644 --- a/src/rules/requireReturnsDescription.js +++ b/src/rules/requireReturnsDescription.js @@ -50,6 +50,33 @@ export default iterateJsdoc(({ }, type: 'array', }, + publicOnly: { + oneOf: [ + { + default: false, + type: 'boolean', + }, + { + additionalProperties: false, + default: {}, + properties: { + ancestorsOnly: { + type: 'boolean', + }, + cjs: { + type: 'boolean', + }, + esm: { + type: 'boolean', + }, + window: { + type: 'boolean', + }, + }, + type: 'object', + }, + ], + }, }, type: 'object', }, diff --git a/test/rules/assertions/requireDescription.js b/test/rules/assertions/requireDescription.js index f25fd45bb..4fbf6d222 100644 --- a/test/rules/assertions/requireDescription.js +++ b/test/rules/assertions/requireDescription.js @@ -707,6 +707,101 @@ export default { }, }, }, + { + code: ` + /** + * + */ + export function quux (foo) { + + } + `, + errors: [ + { + line: 2, + message: 'Missing JSDoc block description.', + }, + ], + options: [ + { + publicOnly: true, + }, + ], + parserOptions: { + sourceType: 'module', + }, + }, + { + code: ` + /** + * + */ + module.exports = function quux (foo) { + + } + `, + errors: [ + { + line: 2, + message: 'Missing JSDoc block description.', + }, + ], + options: [ + { + publicOnly: { + cjs: true, + esm: false, + }, + }, + ], + }, + { + code: ` + /** + * + */ + function quux (foo) { + + } + `, + errors: [ + { + line: 2, + message: 'Missing JSDoc block description.', + }, + ], + options: [ + { + publicOnly: false, + }, + ], + }, + { + code: ` + export default class Class { + /** + * + */ + quux(foo) { + + } + } + `, + errors: [ + { + line: 3, + message: 'Missing JSDoc block description.', + }, + ], + options: [ + { + publicOnly: true, + }, + ], + parserOptions: { + sourceType: 'module', + }, + }, ], valid: [ { @@ -1148,5 +1243,72 @@ export default { }, ], }, + { + code: ` + /** + * + */ + function quux (foo) { + + } + `, + options: [ + { + publicOnly: true, + }, + ], + }, + { + code: ` + /** + * description + */ + export function quux (foo) { + + } + `, + options: [ + { + publicOnly: true, + }, + ], + parserOptions: { + sourceType: 'module', + }, + }, + { + code: ` + /** + * + */ + module.exports = function quux (foo) { + + } + `, + options: [ + { + publicOnly: { + cjs: false, + }, + }, + ], + }, + { + code: ` + class Class { + /** + * + */ + quux(foo) { + + } + } + `, + options: [ + { + publicOnly: true, + }, + ], + }, ], }; diff --git a/test/rules/assertions/requireParamDescription.js b/test/rules/assertions/requireParamDescription.js index 01c7e8806..deecfa770 100644 --- a/test/rules/assertions/requireParamDescription.js +++ b/test/rules/assertions/requireParamDescription.js @@ -127,6 +127,101 @@ export default { }, }, }, + { + code: ` + /** + * @param foo + */ + export function quux (foo) { + + } + `, + errors: [ + { + line: 3, + message: 'Missing JSDoc @param "foo" description.', + }, + ], + options: [ + { + publicOnly: true, + }, + ], + parserOptions: { + sourceType: 'module', + }, + }, + { + code: ` + /** + * @param foo + */ + module.exports = function quux (foo) { + + } + `, + errors: [ + { + line: 3, + message: 'Missing JSDoc @param "foo" description.', + }, + ], + options: [ + { + publicOnly: { + cjs: true, + esm: false, + }, + }, + ], + }, + { + code: ` + /** + * @param foo + */ + function quux (foo) { + + } + `, + errors: [ + { + line: 3, + message: 'Missing JSDoc @param "foo" description.', + }, + ], + options: [ + { + publicOnly: false, + }, + ], + }, + { + code: ` + export default class Class { + /** + * @param foo + */ + quux(foo) { + + } + } + `, + errors: [ + { + line: 4, + message: 'Missing JSDoc @param "foo" description.', + }, + ], + options: [ + { + publicOnly: true, + }, + ], + parserOptions: { + sourceType: 'module', + }, + }, ], valid: [ { @@ -196,5 +291,72 @@ export default { `, ignoreReadme: true, }, + { + code: ` + /** + * @param foo + */ + function quux (foo) { + + } + `, + options: [ + { + publicOnly: true, + }, + ], + }, + { + code: ` + /** + * @param foo - description + */ + export function quux (foo) { + + } + `, + options: [ + { + publicOnly: true, + }, + ], + parserOptions: { + sourceType: 'module', + }, + }, + { + code: ` + /** + * @param + */ + module.exports = function quux (foo) { + + } + `, + options: [ + { + publicOnly: { + cjs: false, + }, + }, + ], + }, + { + code: ` + class Class { + /** + * @param foo + */ + quux(foo) { + + } + } + `, + options: [ + { + publicOnly: true, + }, + ], + }, ], }; diff --git a/test/rules/assertions/requireReturnsDescription.js b/test/rules/assertions/requireReturnsDescription.js index 441cc578f..3553360c5 100644 --- a/test/rules/assertions/requireReturnsDescription.js +++ b/test/rules/assertions/requireReturnsDescription.js @@ -143,6 +143,104 @@ export default { }, }, }, + { + code: ` + /** + * @returns + */ + export function quux (foo) { + + } + `, + errors: [ + { + line: 3, + message: 'Missing JSDoc @returns description.', + }, + ], + options: [ + { + publicOnly: true, + }, + ], + parserOptions: { + sourceType: 'module', + }, + }, + { + code: ` + /** + * @returns + */ + module.exports = function quux (foo) { + + } + `, + errors: [ + { + line: 3, + message: 'Missing JSDoc @returns description.', + }, + ], + options: [ + { + publicOnly: { + cjs: true, + esm: false, + }, + }, + ], + }, + { + code: ` + /** + * @returns + */ + function quux (foo) { + + } + `, + errors: [ + { + line: 3, + message: 'Missing JSDoc @returns description.', + }, + ], + options: [ + { + publicOnly: false, + }, + ], + parserOptions: { + sourceType: 'module', + }, + }, + { + code: ` + export default class Class { + /** + * @returns + */ + quux(foo) { + + } + } + `, + errors: [ + { + line: 4, + message: 'Missing JSDoc @returns description.', + }, + ], + options: [ + { + publicOnly: true, + }, + ], + parserOptions: { + sourceType: 'module', + }, + }, ], valid: [ { @@ -238,5 +336,72 @@ export default { */ `, }, + { + code: ` + /** + * @returns + */ + function quux (foo) { + + } + `, + options: [ + { + publicOnly: true, + }, + ], + }, + { + code: ` + /** + * @returns - description + */ + export function quux (foo) { + + } + `, + options: [ + { + publicOnly: true, + }, + ], + parserOptions: { + sourceType: 'module', + }, + }, + { + code: ` + /** + * @returns + */ + module.exports = function quux (foo) { + + } + `, + options: [ + { + publicOnly: { + cjs: false, + }, + }, + ], + }, + { + code: ` + class Class { + /** + * @returns + */ + quux(foo) { + + } + } + `, + options: [ + { + publicOnly: true, + }, + ], + }, ], };