Skip to content

Commit bc184a4

Browse files
committed
feat(require-returns): add forceReturnsWithAsync
Async functions implicitly returning Promise<void> is now behind the forceReturnsWithAsync (or forceRequireReturn) setting.
1 parent a949094 commit bc184a4

File tree

7 files changed

+145
-65
lines changed

7 files changed

+145
-65
lines changed

.README/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,10 @@ only (e.g., to match `Array` if the type is `Array` vs. `Array.<string>`).
296296
`@returns` documentation regardless of implicit or explicit `return`'s
297297
in the function. May be desired to flag that a project is aware of an
298298
`undefined`/`void` return.
299+
* `settings.jsdoc.forceReturnsWithAsync` - Set to `true` to always insist on
300+
`@returns` documentation regardless of implicit or explicit `return`'s
301+
in an async function. May be desired to flag that a project is aware of an
302+
`Promise<void>` return.
299303

300304
### Settings to Configure `require-example`
301305

.README/rules/require-returns.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ Requires returns are documented.
77
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
88
|Tags|`returns`|
99
|Aliases|`return`|
10-
|Settings|`forceRequireReturn`|
10+
|Settings|`forceRequireReturn`, `forceReturnsWithAsync`|
1111

1212
<!-- assertions requireReturns -->

README.md

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,10 @@ only (e.g., to match `Array` if the type is `Array` vs. `Array.<string>`).
351351
`@returns` documentation regardless of implicit or explicit `return`'s
352352
in the function. May be desired to flag that a project is aware of an
353353
`undefined`/`void` return.
354+
* `settings.jsdoc.forceReturnsWithAsync` - Set to `true` to always insist on
355+
`@returns` documentation regardless of implicit or explicit `return`'s
356+
in an async function. May be desired to flag that a project is aware of an
357+
`Promise<void>` return.
354358

355359
<a name="eslint-plugin-jsdoc-settings-settings-to-configure-require-example"></a>
356360
### Settings to Configure <code>require-example</code>
@@ -4569,7 +4573,7 @@ Requires returns are documented.
45694573
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
45704574
|Tags|`returns`|
45714575
|Aliases|`return`|
4572-
|Settings|`forceRequireReturn`|
4576+
|Settings|`forceRequireReturn`, `forceReturnsWithAsync`|
45734577

45744578
The following patterns are considered problems:
45754579

@@ -4616,27 +4620,17 @@ function quux (foo) {
46164620
/**
46174621
*
46184622
*/
4619-
async function quux() {}
4620-
// Message: Missing JSDoc @returns declaration.
4621-
4622-
/**
4623-
*
4624-
*/
4625-
const quux = async function () {}
4626-
// Message: Missing JSDoc @returns declaration.
4627-
4628-
/**
4629-
*
4630-
*/
4631-
const quux = async () => {}
4623+
function quux () {
4624+
}
4625+
// Settings: {"jsdoc":{"forceRequireReturn":true}}
46324626
// Message: Missing JSDoc @returns declaration.
46334627

46344628
/**
46354629
*
46364630
*/
4637-
function quux () {
4631+
async function quux () {
46384632
}
4639-
// Settings: {"jsdoc":{"forceRequireReturn":true}}
4633+
// Settings: {"jsdoc":{"forceReturnsWithAsync":true}}
46404634
// Message: Missing JSDoc @returns declaration.
46414635

46424636
const language = {
@@ -4857,6 +4851,35 @@ function quux () {
48574851
}
48584852
// Settings: {"jsdoc":{"forceRequireReturn":true}}
48594853

4854+
/**
4855+
* @returns {Promise}
4856+
*/
4857+
async function quux () {
4858+
}
4859+
// Settings: {"jsdoc":{"forceRequireReturn":true}}
4860+
4861+
/**
4862+
* @returns {Promise}
4863+
*/
4864+
async function quux () {
4865+
}
4866+
// Settings: {"jsdoc":{"forceReturnsWithAsync":true}}
4867+
4868+
/**
4869+
*
4870+
*/
4871+
async function quux () {}
4872+
4873+
/**
4874+
*
4875+
*/
4876+
const quux = async function () {}
4877+
4878+
/**
4879+
*
4880+
*/
4881+
const quux = async () => {}
4882+
48604883
/** foo class */
48614884
class foo {
48624885
/** foo constructor */

src/iterateJsdoc.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ const curryUtils = (
4646
allowAugmentsExtendsWithoutParam,
4747
checkSeesForNamepaths,
4848
forceRequireReturn,
49+
forceReturnsWithAsync,
4950
avoidExampleOnConstructors,
5051
ancestors,
5152
sourceCode,
@@ -199,8 +200,12 @@ const curryUtils = (
199200
return jsdocUtils.hasDefinedTypeReturnTag(tag);
200201
};
201202

202-
utils.hasReturnValue = () => {
203-
return jsdocUtils.hasReturnValue(node, context);
203+
utils.hasReturnValue = (ignoreAsync = false) => {
204+
return jsdocUtils.hasReturnValue(node, context, ignoreAsync);
205+
};
206+
207+
utils.isAsync = () => {
208+
return node.async;
204209
};
205210

206211
utils.getTags = (tagName) => {
@@ -213,6 +218,10 @@ const curryUtils = (
213218
return forceRequireReturn;
214219
};
215220

221+
utils.isForceReturnsWithAsync = () => {
222+
return forceReturnsWithAsync;
223+
};
224+
216225
utils.filterTags = (filter) => {
217226
return (jsdoc.tags || []).filter(filter);
218227
};
@@ -312,6 +321,7 @@ export default (iterator, opts = {}) => {
312321

313322
// `require-returns` only
314323
const forceRequireReturn = Boolean(_.get(context, 'settings.jsdoc.forceRequireReturn'));
324+
const forceReturnsWithAsync = Boolean(_.get(context, 'settings.jsdoc.forceReturnsWithAsync'));
315325

316326
// `require-example` only
317327
const avoidExampleOnConstructors = Boolean(_.get(context, 'settings.jsdoc.avoidExampleOnConstructors'));
@@ -388,6 +398,7 @@ export default (iterator, opts = {}) => {
388398
allowAugmentsExtendsWithoutParam,
389399
checkSeesForNamepaths,
390400
forceRequireReturn,
401+
forceReturnsWithAsync,
391402
avoidExampleOnConstructors,
392403
ancestors,
393404
sourceCode

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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export default iterateJsdoc(({
5858
const [tag] = tags;
5959
const missingReturnTag = typeof tag === 'undefined' || tag === null;
6060
if (missingReturnTag &&
61-
(utils.hasReturnValue() || utils.isForceRequireReturn())
61+
((utils.isAsync() && !utils.hasReturnValue(true) ? utils.isForceReturnsWithAsync() : utils.hasReturnValue()) || utils.isForceRequireReturn())
6262
) {
6363
report('Missing JSDoc @' + tagName + ' declaration.');
6464
}

test/rules/assertions/requireReturns.js

Lines changed: 76 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -90,41 +90,28 @@ export default {
9090
/**
9191
*
9292
*/
93-
async function quux() {}
93+
function quux () {
94+
}
9495
`,
9596
errors: [
9697
{
9798
line: 2,
9899
message: 'Missing JSDoc @returns declaration.'
99100
}
100101
],
101-
parserOptions: {
102-
ecmaVersion: 8
103-
}
104-
},
105-
{
106-
code: `
107-
/**
108-
*
109-
*/
110-
const quux = async function () {}
111-
`,
112-
errors: [
113-
{
114-
line: 2,
115-
message: 'Missing JSDoc @returns declaration.'
102+
settings: {
103+
jsdoc: {
104+
forceRequireReturn: true
116105
}
117-
],
118-
parserOptions: {
119-
ecmaVersion: 8
120106
}
121107
},
122108
{
123109
code: `
124110
/**
125111
*
126112
*/
127-
const quux = async () => {}
113+
async function quux () {
114+
}
128115
`,
129116
errors: [
130117
{
@@ -134,25 +121,10 @@ export default {
134121
],
135122
parserOptions: {
136123
ecmaVersion: 8
137-
}
138-
},
139-
{
140-
code: `
141-
/**
142-
*
143-
*/
144-
function quux () {
145-
}
146-
`,
147-
errors: [
148-
{
149-
line: 2,
150-
message: 'Missing JSDoc @returns declaration.'
151-
}
152-
],
124+
},
153125
settings: {
154126
jsdoc: {
155-
forceRequireReturn: true
127+
forceReturnsWithAsync: true
156128
}
157129
}
158130
},
@@ -487,6 +459,73 @@ export default {
487459
}
488460
}
489461
},
462+
{
463+
code: `
464+
/**
465+
* @returns {Promise}
466+
*/
467+
async function quux () {
468+
}
469+
`,
470+
parserOptions: {
471+
ecmaVersion: 8
472+
},
473+
settings: {
474+
jsdoc: {
475+
forceRequireReturn: true
476+
}
477+
}
478+
},
479+
{
480+
code: `
481+
/**
482+
* @returns {Promise}
483+
*/
484+
async function quux () {
485+
}
486+
`,
487+
parserOptions: {
488+
ecmaVersion: 8
489+
},
490+
settings: {
491+
jsdoc: {
492+
forceReturnsWithAsync: true
493+
}
494+
}
495+
},
496+
{
497+
code: `
498+
/**
499+
*
500+
*/
501+
async function quux () {}
502+
`,
503+
parserOptions: {
504+
ecmaVersion: 8
505+
}
506+
},
507+
{
508+
code: `
509+
/**
510+
*
511+
*/
512+
const quux = async function () {}
513+
`,
514+
parserOptions: {
515+
ecmaVersion: 8
516+
}
517+
},
518+
{
519+
code: `
520+
/**
521+
*
522+
*/
523+
const quux = async () => {}
524+
`,
525+
parserOptions: {
526+
ecmaVersion: 8
527+
}
528+
},
490529
{
491530
code: `
492531
/** foo class */

0 commit comments

Comments
 (0)