Skip to content

Commit

Permalink
feat(require-returns): add forceReturnsWithAsync
Browse files Browse the repository at this point in the history
Async functions implicitly returning Promise<void> is now behind the forceReturnsWithAsync (or forceRequireReturn) setting.
  • Loading branch information
AndrewLeedham committed Jun 12, 2019
1 parent a949094 commit bc184a4
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 65 deletions.
4 changes: 4 additions & 0 deletions .README/README.md
Expand Up @@ -296,6 +296,10 @@ only (e.g., to match `Array` if the type is `Array` vs. `Array.<string>`).
`@returns` documentation regardless of implicit or explicit `return`'s
in the function. May be desired to flag that a project is aware of an
`undefined`/`void` return.
* `settings.jsdoc.forceReturnsWithAsync` - Set to `true` to always insist on
`@returns` documentation regardless of implicit or explicit `return`'s
in an async function. May be desired to flag that a project is aware of an
`Promise<void>` return.

### Settings to Configure `require-example`

Expand Down
2 changes: 1 addition & 1 deletion .README/rules/require-returns.md
Expand Up @@ -7,6 +7,6 @@ Requires returns are documented.
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
|Tags|`returns`|
|Aliases|`return`|
|Settings|`forceRequireReturn`|
|Settings|`forceRequireReturn`, `forceReturnsWithAsync`|

<!-- assertions requireReturns -->
55 changes: 39 additions & 16 deletions README.md
Expand Up @@ -351,6 +351,10 @@ only (e.g., to match `Array` if the type is `Array` vs. `Array.<string>`).
`@returns` documentation regardless of implicit or explicit `return`'s
in the function. May be desired to flag that a project is aware of an
`undefined`/`void` return.
* `settings.jsdoc.forceReturnsWithAsync` - Set to `true` to always insist on
`@returns` documentation regardless of implicit or explicit `return`'s
in an async function. May be desired to flag that a project is aware of an
`Promise<void>` return.

<a name="eslint-plugin-jsdoc-settings-settings-to-configure-require-example"></a>
### Settings to Configure <code>require-example</code>
Expand Down Expand Up @@ -4569,7 +4573,7 @@ Requires returns are documented.
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
|Tags|`returns`|
|Aliases|`return`|
|Settings|`forceRequireReturn`|
|Settings|`forceRequireReturn`, `forceReturnsWithAsync`|

The following patterns are considered problems:

Expand Down Expand Up @@ -4616,27 +4620,17 @@ function quux (foo) {
/**
*
*/
async function quux() {}
// Message: Missing JSDoc @returns declaration.

/**
*
*/
const quux = async function () {}
// Message: Missing JSDoc @returns declaration.

/**
*
*/
const quux = async () => {}
function quux () {
}
// Settings: {"jsdoc":{"forceRequireReturn":true}}
// Message: Missing JSDoc @returns declaration.

/**
*
*/
function quux () {
async function quux () {
}
// Settings: {"jsdoc":{"forceRequireReturn":true}}
// Settings: {"jsdoc":{"forceReturnsWithAsync":true}}
// Message: Missing JSDoc @returns declaration.

const language = {
Expand Down Expand Up @@ -4857,6 +4851,35 @@ function quux () {
}
// Settings: {"jsdoc":{"forceRequireReturn":true}}

/**
* @returns {Promise}
*/
async function quux () {
}
// Settings: {"jsdoc":{"forceRequireReturn":true}}

/**
* @returns {Promise}
*/
async function quux () {
}
// Settings: {"jsdoc":{"forceReturnsWithAsync":true}}

/**
*
*/
async function quux () {}

/**
*
*/
const quux = async function () {}

/**
*
*/
const quux = async () => {}

/** foo class */
class foo {
/** foo constructor */
Expand Down
15 changes: 13 additions & 2 deletions src/iterateJsdoc.js
Expand Up @@ -46,6 +46,7 @@ const curryUtils = (
allowAugmentsExtendsWithoutParam,
checkSeesForNamepaths,
forceRequireReturn,
forceReturnsWithAsync,
avoidExampleOnConstructors,
ancestors,
sourceCode,
Expand Down Expand Up @@ -199,8 +200,12 @@ const curryUtils = (
return jsdocUtils.hasDefinedTypeReturnTag(tag);
};

utils.hasReturnValue = () => {
return jsdocUtils.hasReturnValue(node, context);
utils.hasReturnValue = (ignoreAsync = false) => {
return jsdocUtils.hasReturnValue(node, context, ignoreAsync);
};

utils.isAsync = () => {
return node.async;
};

utils.getTags = (tagName) => {
Expand All @@ -213,6 +218,10 @@ const curryUtils = (
return forceRequireReturn;
};

utils.isForceReturnsWithAsync = () => {
return forceReturnsWithAsync;
};

utils.filterTags = (filter) => {
return (jsdoc.tags || []).filter(filter);
};
Expand Down Expand Up @@ -312,6 +321,7 @@ export default (iterator, opts = {}) => {

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

// `require-example` only
const avoidExampleOnConstructors = Boolean(_.get(context, 'settings.jsdoc.avoidExampleOnConstructors'));
Expand Down Expand Up @@ -388,6 +398,7 @@ export default (iterator, opts = {}) => {
allowAugmentsExtendsWithoutParam,
checkSeesForNamepaths,
forceRequireReturn,
forceReturnsWithAsync,
avoidExampleOnConstructors,
ancestors,
sourceCode
Expand Down
19 changes: 11 additions & 8 deletions src/jsdocUtils.js
Expand Up @@ -372,27 +372,27 @@ const lookupTable = {
is (node) {
return node.type === 'FunctionExpression';
},
check (node, context) {
return node.async || lookupTable.BlockStatement.check(node.body, context);
check (node, context, ignoreAsync) {
return !ignoreAsync && node.async || lookupTable.BlockStatement.check(node.body, context);
}
},
ArrowFunctionExpression: {
is (node) {
return node.type === 'ArrowFunctionExpression';
},
check (node, context) {
check (node, context, ignoreAsync) {
// An expression always has a return value.
return node.expression ||
node.async ||
!ignoreAsync && node.async ||
lookupTable.BlockStatement.check(node.body, context);
}
},
FunctionDeclaration: {
is (node) {
return node.type === 'FunctionDeclaration';
},
check (node, context) {
return node.async || lookupTable.BlockStatement.check(node.body, context);
check (node, context, ignoreAsync) {
return !ignoreAsync && node.async || lookupTable.BlockStatement.check(node.body, context);
}
},
'@default': {
Expand Down Expand Up @@ -431,14 +431,17 @@ const lookupTable = {
*
* @param {Object} node
* the node which should be checked.
* @param {Object} context
* @param {boolean} ignoreAsync
* ignore implicit async return.
* @returns {boolean}
* true in case the code returns a return value
*/
const hasReturnValue = (node, context) => {
const hasReturnValue = (node, context, ignoreAsync) => {
// Loop through all of our entry points
for (const item of ENTRY_POINTS) {
if (lookupTable[item].is(node)) {
return lookupTable[item].check(node, context);
return lookupTable[item].check(node, context, ignoreAsync);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/rules/requireReturns.js
Expand Up @@ -58,7 +58,7 @@ export default iterateJsdoc(({
const [tag] = tags;
const missingReturnTag = typeof tag === 'undefined' || tag === null;
if (missingReturnTag &&
(utils.hasReturnValue() || utils.isForceRequireReturn())
((utils.isAsync() && !utils.hasReturnValue(true) ? utils.isForceReturnsWithAsync() : utils.hasReturnValue()) || utils.isForceRequireReturn())
) {
report('Missing JSDoc @' + tagName + ' declaration.');
}
Expand Down
113 changes: 76 additions & 37 deletions test/rules/assertions/requireReturns.js
Expand Up @@ -90,41 +90,28 @@ export default {
/**
*
*/
async function quux() {}
function quux () {
}
`,
errors: [
{
line: 2,
message: 'Missing JSDoc @returns declaration.'
}
],
parserOptions: {
ecmaVersion: 8
}
},
{
code: `
/**
*
*/
const quux = async function () {}
`,
errors: [
{
line: 2,
message: 'Missing JSDoc @returns declaration.'
settings: {
jsdoc: {
forceRequireReturn: true
}
],
parserOptions: {
ecmaVersion: 8
}
},
{
code: `
/**
*
*/
const quux = async () => {}
async function quux () {
}
`,
errors: [
{
Expand All @@ -134,25 +121,10 @@ export default {
],
parserOptions: {
ecmaVersion: 8
}
},
{
code: `
/**
*
*/
function quux () {
}
`,
errors: [
{
line: 2,
message: 'Missing JSDoc @returns declaration.'
}
],
},
settings: {
jsdoc: {
forceRequireReturn: true
forceReturnsWithAsync: true
}
}
},
Expand Down Expand Up @@ -487,6 +459,73 @@ export default {
}
}
},
{
code: `
/**
* @returns {Promise}
*/
async function quux () {
}
`,
parserOptions: {
ecmaVersion: 8
},
settings: {
jsdoc: {
forceRequireReturn: true
}
}
},
{
code: `
/**
* @returns {Promise}
*/
async function quux () {
}
`,
parserOptions: {
ecmaVersion: 8
},
settings: {
jsdoc: {
forceReturnsWithAsync: true
}
}
},
{
code: `
/**
*
*/
async function quux () {}
`,
parserOptions: {
ecmaVersion: 8
}
},
{
code: `
/**
*
*/
const quux = async function () {}
`,
parserOptions: {
ecmaVersion: 8
}
},
{
code: `
/**
*
*/
const quux = async () => {}
`,
parserOptions: {
ecmaVersion: 8
}
},
{
code: `
/** foo class */
Expand Down

0 comments on commit bc184a4

Please sign in to comment.