From 8ef41a1e1d4d2627a65f70545de9c6c22e3ef162 Mon Sep 17 00:00:00 2001 From: Brett Zamir Date: Sun, 18 Jul 2021 14:17:47 +0800 Subject: [PATCH] feat(`require-returns-check`): add `exemptGenerators` option (default on for typescript mode) to allow `@returns` to be present even without `return` --- .README/rules/require-returns-check.md | 7 ++ README.md | 35 +++++++++ src/rules/requireReturnsCheck.js | 9 ++- test/rules/assertions/requireReturnsCheck.js | 82 ++++++++++++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) diff --git a/.README/rules/require-returns-check.md b/.README/rules/require-returns-check.md index df3ab3cd8..286fe546c 100644 --- a/.README/rules/require-returns-check.md +++ b/.README/rules/require-returns-check.md @@ -11,6 +11,13 @@ Will also report if multiple `@returns` tags are present. #### Options +- `exemptGenerators`- Because a generator might be labeled as having a + `IterableIterator` `@returns` value (along with an iterator type + corresponding to the type of any `yield` statements), projects might wish to + leverage `@returns` in generators even without a` return` statement. This + option is therefore `true` by default in `typescript` mode (in "jsdoc" mode, + one might be more likely to take advantage of `@yields`). Set it to `false` + if you wish for a missing `return` to be flagged regardless. - `exemptAsync` - By default, functions which return a `Promise` that are not detected as resolving with a non-`undefined` value and `async` functions (even ones that do not explicitly return a value, as these are returning a diff --git a/README.md b/README.md index a4f6c984a..860109549 100644 --- a/README.md +++ b/README.md @@ -16120,6 +16120,13 @@ Will also report if multiple `@returns` tags are present. #### Options +- `exemptGenerators`- Because a generator might be labeled as having a + `IterableIterator` `@returns` value (along with an iterator type + corresponding to the type of any `yield` statements), projects might wish to + leverage `@returns` in generators even without a` return` statement. This + option is therefore `true` by default in `typescript` mode (in "jsdoc" mode, + one might be more likely to take advantage of `@yields`). Set it to `false` + if you wish for a missing `return` to be flagged regardless. - `exemptAsync` - By default, functions which return a `Promise` that are not detected as resolving with a non-`undefined` value and `async` functions (even ones that do not explicitly return a value, as these are returning a @@ -16229,6 +16236,21 @@ async function quux() {} // "jsdoc/require-returns-check": ["error"|"warn", {"exemptAsync":false}] // Message: JSDoc @returns declaration present but return expression not available in function. +/** + * @returns {IterableIterator} + */ +function * quux() {} +// Settings: {"jsdoc":{"mode":"jsdoc"}} +// Message: JSDoc @returns declaration present but return expression not available in function. + +/** + * @returns {IterableIterator} + */ +function * quux() {} +// Settings: {"jsdoc":{"mode":"typescript"}} +// "jsdoc/require-returns-check": ["error"|"warn", {"exemptGenerators":false}] +// Message: JSDoc @returns declaration present but return expression not available in function. + /** * @returns {Promise} */ @@ -16634,6 +16656,19 @@ function quux () { return 'abc'; } // "jsdoc/require-returns-check": ["error"|"warn", {"reportMissingReturnForUndefinedTypes":true}] + +/** + * @returns {IterableIterator} + */ +function * quux() {} +// Settings: {"jsdoc":{"mode":"typescript"}} + +/** + * @returns {IterableIterator} + */ +function * quux() {} +// Settings: {"jsdoc":{"mode":"jsdoc"}} +// "jsdoc/require-returns-check": ["error"|"warn", {"exemptGenerators":true}] ```` diff --git a/src/rules/requireReturnsCheck.js b/src/rules/requireReturnsCheck.js index c745a91d4..12b30a481 100755 --- a/src/rules/requireReturnsCheck.js +++ b/src/rules/requireReturnsCheck.js @@ -30,12 +30,14 @@ const canSkip = (utils, settings) => { export default iterateJsdoc(({ context, + node, report, settings, utils, }) => { const { exemptAsync = true, + exemptGenerators = settings.mode === 'typescript', reportMissingReturnForUndefinedTypes = false, } = context.options[0] || {}; @@ -64,7 +66,9 @@ export default iterateJsdoc(({ } // In case a return value is declared in JSDoc, we also expect one in the code. - if ((reportMissingReturnForUndefinedTypes || utils.hasDefinedTypeTag(tags[0])) && !utils.hasValueOrExecutorHasNonEmptyResolveValue(exemptAsync)) { + if ((reportMissingReturnForUndefinedTypes || utils.hasDefinedTypeTag(tags[0])) && !utils.hasValueOrExecutorHasNonEmptyResolveValue( + exemptAsync, + ) && (!exemptGenerators || !node.generator)) { report(`JSDoc @${tagName} declaration present but return expression not available in function.`); } }, { @@ -81,6 +85,9 @@ export default iterateJsdoc(({ default: true, type: 'boolean', }, + exemptGenerators: { + type: 'boolean', + }, reportMissingReturnForUndefinedTypes: { default: false, type: 'boolean', diff --git a/test/rules/assertions/requireReturnsCheck.js b/test/rules/assertions/requireReturnsCheck.js index 9f8a648a9..77dbd7ec6 100755 --- a/test/rules/assertions/requireReturnsCheck.js +++ b/test/rules/assertions/requireReturnsCheck.js @@ -172,6 +172,53 @@ export default { ecmaVersion: 8, }, }, + { + code: ` + /** + * @returns {IterableIterator} + */ + function * quux() {} + `, + errors: [ + { + line: 2, + message: 'JSDoc @returns declaration present but return expression not available in function.', + }, + ], + parserOptions: { + ecmaVersion: 8, + }, + settings: { + jsdoc: { + mode: 'jsdoc', + }, + }, + }, + { + code: ` + /** + * @returns {IterableIterator} + */ + function * quux() {} + `, + errors: [ + { + line: 2, + message: 'JSDoc @returns declaration present but return expression not available in function.', + }, + ], + options: [{ + exemptGenerators: false, + }], + parserOptions: { + ecmaVersion: 8, + }, + settings: { + jsdoc: { + mode: 'typescript', + }, + }, + }, { code: ` /** @@ -791,5 +838,40 @@ export default { reportMissingReturnForUndefinedTypes: true, }], }, + { + code: ` + /** + * @returns {IterableIterator} + */ + function * quux() {} + `, + parserOptions: { + ecmaVersion: 8, + }, + settings: { + jsdoc: { + mode: 'typescript', + }, + }, + }, + { + code: ` + /** + * @returns {IterableIterator} + */ + function * quux() {} + `, + options: [{ + exemptGenerators: true, + }], + parserOptions: { + ecmaVersion: 8, + }, + settings: { + jsdoc: { + mode: 'jsdoc', + }, + }, + }, ], };