Skip to content

Commit 0b86ed6

Browse files
committed
Merge branch 'forceReturnsWithAsync'
feat(require-returns): add forceReturnsWithAsync option
2 parents 5f296a0 + 71ba9f2 commit 0b86ed6

File tree

6 files changed

+228
-13
lines changed

6 files changed

+228
-13
lines changed

.README/rules/require-returns.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,18 @@
22

33
Requires returns are documented.
44

5+
By default `async` functions that do not explicitly return a value pass this rule. You can force all `async` functions to require return statements by setting `forceReturnsWithAsync` as true on the options object. This may be useful as an `async` function will always return a Promise, even if the Promise returns void.
6+
7+
```js
8+
'jsdoc/require-jsdoc': ['error', {forceReturnsWithAsync: true}]
9+
```
10+
511
|||
612
|---|---|
713
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
814
|Tags|`returns`|
915
|Aliases|`return`|
1016
|Settings|`forceRequireReturn`|
17+
|Options|`forceReturnsWithAsync`|
1118

1219
<!-- assertions requireReturns -->

README.md

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4567,12 +4567,19 @@ function quux () {
45674567

45684568
Requires returns are documented.
45694569

4570+
By default `async` functions that do not explicitly return a value pass this rule. You can force all `async` functions to require return statements by setting `forceReturnsWithAsync` as true on the options object. This may be useful as an `async` function will always return a Promise, even if the Promise returns void.
4571+
4572+
```js
4573+
'jsdoc/require-jsdoc': ['error', {forceReturnsWithAsync: true}]
4574+
```
4575+
45704576
|||
45714577
|---|---|
45724578
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
45734579
|Tags|`returns`|
45744580
|Aliases|`return`|
45754581
|Settings|`forceRequireReturn`|
4582+
|Options|`forceReturnsWithAsync`|
45764583

45774584
The following patterns are considered problems:
45784585

@@ -4619,19 +4626,30 @@ function quux (foo) {
46194626
/**
46204627
*
46214628
*/
4622-
async function quux() {}
4629+
async function quux() {
4630+
}
4631+
// Settings: {"jsdoc":{"forceRequireReturn":true}}
46234632
// Message: Missing JSDoc @returns declaration.
46244633

46254634
/**
46264635
*
46274636
*/
46284637
const quux = async function () {}
4638+
// Settings: {"jsdoc":{"forceRequireReturn":true}}
46294639
// Message: Missing JSDoc @returns declaration.
46304640

46314641
/**
46324642
*
46334643
*/
46344644
const quux = async () => {}
4645+
// Settings: {"jsdoc":{"forceRequireReturn":true}}
4646+
// Message: Missing JSDoc @returns declaration.
4647+
4648+
/**
4649+
*
4650+
*/
4651+
async function quux () {}
4652+
// Settings: {"jsdoc":{"forceRequireReturn":true}}
46354653
// Message: Missing JSDoc @returns declaration.
46364654

46374655
/**
@@ -4651,6 +4669,14 @@ const language = {
46514669
}
46524670
}
46534671
// Message: Missing JSDoc @returns declaration.
4672+
4673+
/**
4674+
*
4675+
*/
4676+
async function quux () {
4677+
}
4678+
// Options: [{"forceReturnsWithAsync":true}]
4679+
// Message: Missing JSDoc @returns declaration.
46544680
````
46554681

46564682
The following patterns are not considered problems:
@@ -4865,6 +4891,35 @@ function quux (req, res , next) {
48654891
return;
48664892
}
48674893

4894+
/**
4895+
* @returns {Promise}
4896+
*/
4897+
async function quux () {
4898+
}
4899+
// Settings: {"jsdoc":{"forceRequireReturn":true}}
4900+
4901+
/**
4902+
* @returns {Promise}
4903+
*/
4904+
async function quux () {
4905+
}
4906+
// Options: [{"forceReturnsWithAsync":true}]
4907+
4908+
/**
4909+
*
4910+
*/
4911+
async function quux () {}
4912+
4913+
/**
4914+
*
4915+
*/
4916+
const quux = async function () {}
4917+
4918+
/**
4919+
*
4920+
*/
4921+
const quux = async () => {}
4922+
48684923
/** foo class */
48694924
class foo {
48704925
/** foo constructor */
@@ -4875,6 +4930,13 @@ class foo {
48754930
}
48764931

48774932
export default foo;
4933+
4934+
/**
4935+
*
4936+
*/
4937+
function quux () {
4938+
}
4939+
// Options: [{"forceReturnsWithAsync":true}]
48784940
````
48794941

48804942

src/iterateJsdoc.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,12 @@ const curryUtils = (
145145
return jsdocUtils.hasDefinedTypeReturnTag(tag);
146146
};
147147

148-
utils.hasReturnValue = () => {
149-
return jsdocUtils.hasReturnValue(node, context);
148+
utils.hasReturnValue = (ignoreAsync = false) => {
149+
return jsdocUtils.hasReturnValue(node, context, ignoreAsync);
150+
};
151+
152+
utils.isAsync = () => {
153+
return node.async;
150154
};
151155

152156
utils.getTags = (tagName) => {

src/jsdocUtils.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -372,27 +372,27 @@ const lookupTable = {
372372
is (node) {
373373
return node.type === 'FunctionExpression';
374374
},
375-
check (node, context) {
376-
return node.async || lookupTable.BlockStatement.check(node.body, context);
375+
check (node, context, ignoreAsync) {
376+
return !ignoreAsync && node.async || lookupTable.BlockStatement.check(node.body, context);
377377
}
378378
},
379379
ArrowFunctionExpression: {
380380
is (node) {
381381
return node.type === 'ArrowFunctionExpression';
382382
},
383-
check (node, context) {
383+
check (node, context, ignoreAsync) {
384384
// An expression always has a return value.
385385
return node.expression ||
386-
node.async ||
386+
!ignoreAsync && node.async ||
387387
lookupTable.BlockStatement.check(node.body, context);
388388
}
389389
},
390390
FunctionDeclaration: {
391391
is (node) {
392392
return node.type === 'FunctionDeclaration';
393393
},
394-
check (node, context) {
395-
return node.async || lookupTable.BlockStatement.check(node.body, context);
394+
check (node, context, ignoreAsync) {
395+
return !ignoreAsync && node.async || lookupTable.BlockStatement.check(node.body, context);
396396
}
397397
},
398398
'@default': {
@@ -431,14 +431,17 @@ const lookupTable = {
431431
*
432432
* @param {Object} node
433433
* the node which should be checked.
434+
* @param {Object} context
435+
* @param {boolean} ignoreAsync
436+
* ignore implicit async return.
434437
* @returns {boolean}
435438
* true in case the code returns a return value
436439
*/
437-
const hasReturnValue = (node, context) => {
440+
const hasReturnValue = (node, context, ignoreAsync) => {
438441
// Loop through all of our entry points
439442
for (const item of ENTRY_POINTS) {
440443
if (lookupTable[item].is(node)) {
441-
return lookupTable[item].check(node, context);
444+
return lookupTable[item].check(node, context, ignoreAsync);
442445
}
443446
}
444447

src/rules/requireReturns.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const canSkip = (utils) => {
4343
export default iterateJsdoc(({
4444
report,
4545
utils,
46+
context,
4647
settings
4748
}) => {
4849
// A preflight check. We do not need to run a deep check
@@ -51,6 +52,8 @@ export default iterateJsdoc(({
5152
return;
5253
}
5354

55+
const options = context.options[0] || {};
56+
5457
const tagName = utils.getPreferredTagName('returns');
5558
const tags = utils.getTags(tagName);
5659

@@ -62,7 +65,7 @@ export default iterateJsdoc(({
6265
const [tag] = tags;
6366
const missingReturnTag = typeof tag === 'undefined' || tag === null;
6467
if (missingReturnTag &&
65-
(utils.hasReturnValue() || settings.forceRequireReturn)
68+
((utils.isAsync() && !utils.hasReturnValue(true) ? Boolean(options.forceReturnsWithAsync) : utils.hasReturnValue()) || settings.forceRequireReturn)
6669
) {
6770
report('Missing JSDoc @' + tagName + ' declaration.');
6871
}

0 commit comments

Comments
 (0)