Skip to content

Commit 0ed24c0

Browse files
committed
feat(require-returns-check): add exemptAsync option
1 parent 445b020 commit 0ed24c0

File tree

5 files changed

+201
-15
lines changed

5 files changed

+201
-15
lines changed

.README/rules/require-returns-check.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,25 @@ in jsdoc comment.
55

66
Will also report if multiple `@returns` tags are present.
77

8+
#### Options
9+
10+
- `exemptAsync` - By default, functions which return a `Promise` that are not
11+
detected as resolving with a non-`undefined` value and `async` functions
12+
(even ones that do not explicitly return a value, as these are returning a
13+
`Promise` implicitly) will be exempted from reporting by this rule.
14+
If you wish to insist that only `Promise`'s which resolve to
15+
non-`undefined` values or `async` functions with explicit `return`'s will
16+
be exempted from reporting (i.e., that `async` functions can be reported
17+
if they lack an explicit (non-`undefined`) `return` when a `@returns` is
18+
present), you can set `exemptAsync` to `false` on the options object.
19+
Defaults to `true`.
20+
821
|||
922
|---|---|
1023
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
1124
|Tags|`returns`|
1225
|Aliases|`return`|
26+
|Options|`exemptAsync`|
1327
|Recommended|true|
1428

1529
<!-- assertions requireReturnsCheck -->

README.md

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13737,11 +13737,26 @@ in jsdoc comment.
1373713737

1373813738
Will also report if multiple `@returns` tags are present.
1373913739

13740+
<a name="eslint-plugin-jsdoc-rules-require-returns-check-options-27"></a>
13741+
#### Options
13742+
13743+
- `exemptAsync` - By default, functions which return a `Promise` that are not
13744+
detected as resolving with a non-`undefined` value and `async` functions
13745+
(even ones that do not explicitly return a value, as these are returning a
13746+
`Promise` implicitly) will be exempted from reporting by this rule.
13747+
If you wish to insist that only `Promise`'s which resolve to
13748+
non-`undefined` values or `async` functions with explicit `return`'s will
13749+
be exempted from reporting (i.e., that `async` functions can be reported
13750+
if they lack an explicit (non-`undefined`) `return` when a `@returns` is
13751+
present), you can set `exemptAsync` to `false` on the options object.
13752+
Defaults to `true`.
13753+
1374013754
|||
1374113755
|---|---|
1374213756
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
1374313757
|Tags|`returns`|
1374413758
|Aliases|`return`|
13759+
|Options|`exemptAsync`|
1374513760
|Recommended|true|
1374613761

1374713762
The following patterns are considered problems:
@@ -13822,6 +13837,35 @@ function f () {
1382213837
}
1382313838
}
1382413839
// Message: JSDoc @returns declaration present but return expression not available in function.
13840+
13841+
/**
13842+
* @returns {Promise<void>}
13843+
*/
13844+
async function quux() {}
13845+
// Options: [{"exemptAsync":false}]
13846+
// Message: JSDoc @returns declaration present but return expression not available in function.
13847+
13848+
/**
13849+
* @returns {Promise<void>}
13850+
*/
13851+
function quux() {
13852+
return new Promise((resolve, reject) => {})
13853+
}
13854+
// Options: [{"exemptAsync":false}]
13855+
// Message: JSDoc @returns declaration present but return expression not available in function.
13856+
13857+
/**
13858+
* @returns {Promise<void>}
13859+
*/
13860+
function quux() {
13861+
return new Promise((resolve, reject) => {
13862+
setTimeout(() => {
13863+
resolve();
13864+
});
13865+
})
13866+
}
13867+
// Options: [{"exemptAsync":false}]
13868+
// Message: JSDoc @returns declaration present but return expression not available in function.
1382513869
````
1382613870

1382713871
The following patterns are not considered problems:
@@ -14127,6 +14171,26 @@ function quux () {
1412714171
}
1412814172
return;
1412914173
}
14174+
14175+
/**
14176+
* @returns {Promise<void>}
14177+
*/
14178+
async function quux() {
14179+
return 5;
14180+
}
14181+
// Options: [{"exemptAsync":false}]
14182+
14183+
/**
14184+
* @returns {Promise<void>}
14185+
*/
14186+
function quux() {
14187+
return new Promise((resolve, reject) => {
14188+
setTimeout(() => {
14189+
resolve(true);
14190+
});
14191+
})
14192+
}
14193+
// Options: [{"exemptAsync":false}]
1413014194
````
1413114195

1413214196

@@ -14137,10 +14201,10 @@ Requires that the `@returns` tag has a `description` value. The error
1413714201
will not be reported if the return value is `void` or `undefined`
1413814202
or if it is `Promise<void>` or `Promise<undefined>`.
1413914203

14140-
<a name="eslint-plugin-jsdoc-rules-require-returns-description-options-27"></a>
14204+
<a name="eslint-plugin-jsdoc-rules-require-returns-description-options-28"></a>
1414114205
#### Options
1414214206

14143-
<a name="eslint-plugin-jsdoc-rules-require-returns-description-options-27-contexts-10"></a>
14207+
<a name="eslint-plugin-jsdoc-rules-require-returns-description-options-28-contexts-10"></a>
1414414208
##### <code>contexts</code>
1414514209

1414614210
Set this to an array of strings representing the AST context
@@ -14293,10 +14357,10 @@ function quux () {
1429314357

1429414358
Requires that `@returns` tag has `type` value.
1429514359

14296-
<a name="eslint-plugin-jsdoc-rules-require-returns-type-options-28"></a>
14360+
<a name="eslint-plugin-jsdoc-rules-require-returns-type-options-29"></a>
1429714361
#### Options
1429814362

14299-
<a name="eslint-plugin-jsdoc-rules-require-returns-type-options-28-contexts-11"></a>
14363+
<a name="eslint-plugin-jsdoc-rules-require-returns-type-options-29-contexts-11"></a>
1430014364
##### <code>contexts</code>
1430114365

1430214366
Set this to an array of strings representing the AST context
@@ -14416,7 +14480,7 @@ Requires that returns are documented.
1441614480

1441714481
Will also report if multiple `@returns` tags are present.
1441814482

14419-
<a name="eslint-plugin-jsdoc-rules-require-returns-options-29"></a>
14483+
<a name="eslint-plugin-jsdoc-rules-require-returns-options-30"></a>
1442014484
#### Options
1442114485

1442214486
- `checkConstructors` - A value indicating whether `constructor`s should
@@ -15436,7 +15500,7 @@ async function foo() {
1543615500

1543715501
Requires that throw statements are documented.
1543815502

15439-
<a name="eslint-plugin-jsdoc-rules-require-throws-options-30"></a>
15503+
<a name="eslint-plugin-jsdoc-rules-require-throws-options-31"></a>
1544015504
#### Options
1544115505

1544215506
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the
@@ -15711,7 +15775,7 @@ Will also report if multiple `@yields` tags are present.
1571115775
See the `next`, `forceRequireNext`, and `nextWithGeneratorTag` options for an
1571215776
option to expect a non-standard `@next` tag.
1571315777

15714-
<a name="eslint-plugin-jsdoc-rules-require-yields-options-31"></a>
15778+
<a name="eslint-plugin-jsdoc-rules-require-yields-options-32"></a>
1571515779
#### Options
1571615780

1571715781
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the
@@ -16511,7 +16575,7 @@ function bodies.
1651116575

1651216576
Will also report if multiple `@yields` tags are present.
1651316577

16514-
<a name="eslint-plugin-jsdoc-rules-require-yields-check-options-32"></a>
16578+
<a name="eslint-plugin-jsdoc-rules-require-yields-check-options-33"></a>
1651516579
#### Options
1651616580

1651716581
- `checkGeneratorsOnly` - Avoids checking the function body and merely insists
@@ -17064,7 +17128,7 @@ for valid types (based on the tag's `type` value), and either portion checked
1706417128
for presence (based on `false` `name` or `type` values or their `required`
1706517129
value). See the setting for more details.
1706617130

17067-
<a name="eslint-plugin-jsdoc-rules-valid-types-options-33"></a>
17131+
<a name="eslint-plugin-jsdoc-rules-valid-types-options-34"></a>
1706817132
#### Options
1706917133

1707017134
- `allowEmptyNamepaths` (default: true) - Set to `false` to bulk disallow

src/iterateJsdoc.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -457,10 +457,6 @@ const getUtils = (
457457
return jsdocUtils.hasDefinedTypeTag(tag);
458458
};
459459

460-
utils.hasReturnValue = () => {
461-
return jsdocUtils.hasReturnValue(node);
462-
};
463-
464460
utils.hasValueOrExecutorHasNonEmptyResolveValue = (anyPromiseAsReturn) => {
465461
return jsdocUtils.hasValueOrExecutorHasNonEmptyResolveValue(node, anyPromiseAsReturn);
466462
};

src/rules/requireReturnsCheck.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,20 @@ const canSkip = (utils, settings) => {
2929
};
3030

3131
export default iterateJsdoc(({
32+
context,
3233
report,
3334
settings,
3435
utils,
3536
}) => {
37+
const {
38+
exemptAsync = true,
39+
} = context.options[0] || {};
40+
3641
if (canSkip(utils, settings)) {
3742
return;
3843
}
3944

40-
if (utils.isAsync()) {
45+
if (exemptAsync && utils.isAsync()) {
4146
return;
4247
}
4348

@@ -58,7 +63,7 @@ export default iterateJsdoc(({
5863
}
5964

6065
// In case a return value is declared in JSDoc, we also expect one in the code.
61-
if (utils.hasDefinedTypeTag(tags[0]) && !utils.hasReturnValue()) {
66+
if (utils.hasDefinedTypeTag(tags[0]) && !utils.hasValueOrExecutorHasNonEmptyResolveValue(exemptAsync)) {
6267
report(`JSDoc @${tagName} declaration present but return expression not available in function.`);
6368
}
6469
}, {
@@ -67,6 +72,18 @@ export default iterateJsdoc(({
6772
description: 'Requires a return statement in function body if a `@returns` tag is specified in jsdoc comment.',
6873
url: 'https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-returns-check',
6974
},
75+
schema: [
76+
{
77+
additionalProperties: false,
78+
properties: {
79+
exemptAsync: {
80+
default: true,
81+
type: 'boolean',
82+
},
83+
},
84+
type: 'object',
85+
},
86+
],
7087
type: 'suggestion',
7188
},
7289
});

test/rules/assertions/requireReturnsCheck.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,68 @@ export default {
151151
},
152152
],
153153
},
154+
{
155+
code: `
156+
/**
157+
* @returns {Promise<void>}
158+
*/
159+
async function quux() {}
160+
`,
161+
errors: [
162+
{
163+
line: 2,
164+
message: 'JSDoc @returns declaration present but return expression not available in function.',
165+
},
166+
],
167+
options: [{
168+
exemptAsync: false,
169+
}],
170+
parserOptions: {
171+
ecmaVersion: 8,
172+
},
173+
},
174+
{
175+
code: `
176+
/**
177+
* @returns {Promise<void>}
178+
*/
179+
function quux() {
180+
return new Promise((resolve, reject) => {})
181+
}
182+
`,
183+
errors: [
184+
{
185+
line: 2,
186+
message: 'JSDoc @returns declaration present but return expression not available in function.',
187+
},
188+
],
189+
options: [{
190+
exemptAsync: false,
191+
}],
192+
},
193+
{
194+
code: `
195+
/**
196+
* @returns {Promise<void>}
197+
*/
198+
function quux() {
199+
return new Promise((resolve, reject) => {
200+
setTimeout(() => {
201+
resolve();
202+
});
203+
})
204+
}
205+
`,
206+
errors: [
207+
{
208+
line: 2,
209+
message: 'JSDoc @returns declaration present but return expression not available in function.',
210+
},
211+
],
212+
options: [{
213+
exemptAsync: false,
214+
}],
215+
},
154216
],
155217
valid: [
156218
{
@@ -575,5 +637,38 @@ export default {
575637
}
576638
`,
577639
},
640+
{
641+
code: `
642+
/**
643+
* @returns {Promise<void>}
644+
*/
645+
async function quux() {
646+
return 5;
647+
}
648+
`,
649+
options: [{
650+
exemptAsync: false,
651+
}],
652+
parserOptions: {
653+
ecmaVersion: 8,
654+
},
655+
},
656+
{
657+
code: `
658+
/**
659+
* @returns {Promise<void>}
660+
*/
661+
function quux() {
662+
return new Promise((resolve, reject) => {
663+
setTimeout(() => {
664+
resolve(true);
665+
});
666+
})
667+
}
668+
`,
669+
options: [{
670+
exemptAsync: false,
671+
}],
672+
},
578673
],
579674
};

0 commit comments

Comments
 (0)