Skip to content

Commit

Permalink
feat(require-returns-check): add exemptGenerators option (default…
Browse files Browse the repository at this point in the history
… on for typescript mode) to allow `@returns` to be present even without `return`
  • Loading branch information
brettz9 committed Jul 20, 2021
1 parent fdca227 commit 8ef41a1
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 1 deletion.
7 changes: 7 additions & 0 deletions .README/rules/require-returns-check.md
Expand Up @@ -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
Expand Down
35 changes: 35 additions & 0 deletions README.md
Expand Up @@ -16120,6 +16120,13 @@ Will also report if multiple `@returns` tags are present.
<a name="eslint-plugin-jsdoc-rules-require-returns-check-options-33"></a>
#### 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
Expand Down Expand Up @@ -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<any>}
*/
function * quux() {}
// Settings: {"jsdoc":{"mode":"jsdoc"}}
// Message: JSDoc @returns declaration present but return expression not available in function.

/**
* @returns {IterableIterator<any>}
*/
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<void>}
*/
Expand Down Expand Up @@ -16634,6 +16656,19 @@ function quux () {
return 'abc';
}
// "jsdoc/require-returns-check": ["error"|"warn", {"reportMissingReturnForUndefinedTypes":true}]

/**
* @returns {IterableIterator<any>}
*/
function * quux() {}
// Settings: {"jsdoc":{"mode":"typescript"}}

/**
* @returns {IterableIterator<any>}
*/
function * quux() {}
// Settings: {"jsdoc":{"mode":"jsdoc"}}
// "jsdoc/require-returns-check": ["error"|"warn", {"exemptGenerators":true}]
````


Expand Down
9 changes: 8 additions & 1 deletion src/rules/requireReturnsCheck.js
Expand Up @@ -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] || {};

Expand Down Expand Up @@ -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.`);
}
}, {
Expand All @@ -81,6 +85,9 @@ export default iterateJsdoc(({
default: true,
type: 'boolean',
},
exemptGenerators: {
type: 'boolean',
},
reportMissingReturnForUndefinedTypes: {
default: false,
type: 'boolean',
Expand Down
82 changes: 82 additions & 0 deletions test/rules/assertions/requireReturnsCheck.js
Expand Up @@ -172,6 +172,53 @@ export default {
ecmaVersion: 8,
},
},
{
code: `
/**
* @returns {IterableIterator<any>}
*/
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<any>}
*/
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: `
/**
Expand Down Expand Up @@ -791,5 +838,40 @@ export default {
reportMissingReturnForUndefinedTypes: true,
}],
},
{
code: `
/**
* @returns {IterableIterator<any>}
*/
function * quux() {}
`,
parserOptions: {
ecmaVersion: 8,
},
settings: {
jsdoc: {
mode: 'typescript',
},
},
},
{
code: `
/**
* @returns {IterableIterator<any>}
*/
function * quux() {}
`,
options: [{
exemptGenerators: true,
}],
parserOptions: {
ecmaVersion: 8,
},
settings: {
jsdoc: {
mode: 'jsdoc',
},
},
},
],
};

0 comments on commit 8ef41a1

Please sign in to comment.