From 445b020804eecdc4d26b2200dd2da8756c61d11f Mon Sep 17 00:00:00 2001 From: Brett Zamir Date: Sun, 31 Jan 2021 16:19:49 +0800 Subject: [PATCH] Check further AST --- src/jsdocUtils.js | 34 +++++++++---- test/rules/assertions/requireReturns.js | 66 ++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 10 deletions(-) diff --git a/src/jsdocUtils.js b/src/jsdocUtils.js index 5f75e3f1f..6e34d619e 100644 --- a/src/jsdocUtils.js +++ b/src/jsdocUtils.js @@ -620,6 +620,7 @@ const hasNonEmptyResolverCall = (node, resolverName) => { return hasNonEmptyResolverCall(node.body, resolverName); } + case 'LabeledStatement': case 'WhileStatement': case 'DoWhileStatement': case 'ForStatement': @@ -664,32 +665,46 @@ const hasNonEmptyResolverCall = (node, resolverName) => { } case 'ArrayExpression': - return node.elements.some((bodyNode) => { - return hasNonEmptyResolverCall(bodyNode, resolverName); + return node.elements.some((element) => { + return hasNonEmptyResolverCall(element, resolverName); }); + case 'ObjectExpression': + return node.properties.some((property) => { + return hasNonEmptyResolverCall(property, resolverName); + }); + case 'Property': + return node.computed && hasNonEmptyResolverCall(node.key, resolverName) || + hasNonEmptyResolverCall(node.value, resolverName); + case 'AwaitExpression': case 'SpreadElement': case 'UnaryExpression': case 'YieldExpression': return hasNonEmptyResolverCall(node.argument, resolverName); + case 'VariableDeclaration': { + return node.declarations.some((nde) => { + return hasNonEmptyResolverCall(nde, resolverName); + }); + } + case 'VariableDeclarator': { + // Todo: Check `id` too once `ArrayPattern` is implemented (destructuring default) + return hasNonEmptyResolverCall(node.init, resolverName); + } + /* - case 'LabeledStatement': - case 'VariableDeclaration': + // Todo: As relevant, also check these in return/throw and yield checks case 'MemberExpression': case 'OptionalMemberExpression': // ?. - case 'OptionalCallExpression': ?.x() + case 'OptionalCallExpression': ?.x(resolve) case 'TaggedTemplateExpression': case 'TemplateElement': case 'TemplateLiteral': - case 'AssignmentPattern': + case 'AssignmentPattern': // Default destructuring value case 'ArrayPattern': case 'ObjectPattern': - case 'ObjectExpression': - case 'Property': - case 'ClassProperty': case 'ClassDeclaration': case 'ClassExpression': case 'MethodDefinition': case 'Super': @@ -803,6 +818,7 @@ const hasYieldValue = (node, checkYieldReturnValue) => { }); } case 'VariableDeclarator': { + // Todo: Check `id` too once `ArrayPattern` is implemented (destructuring default) return hasYieldValue(node.init, checkYieldReturnValue); } case 'YieldExpression': { diff --git a/test/rules/assertions/requireReturns.js b/test/rules/assertions/requireReturns.js index d6aa168fb..ec2fe6f69 100644 --- a/test/rules/assertions/requireReturns.js +++ b/test/rules/assertions/requireReturns.js @@ -1068,7 +1068,7 @@ export default { return new Promise((resolve, reject) => { +resolve(); [...resolve()]; - [resolve(true)]; + [...+resolve(true)]; }); } `, @@ -1121,6 +1121,70 @@ export default { ecmaVersion: 8, }, }, + { + code: ` + /** + * + */ + function quux () { + return new Promise((resolve, reject) => { + someLabel: { + resolve(true); + } + }); + } + `, + errors: [ + { + line: 2, + message: 'Missing JSDoc @returns declaration.', + }, + ], + ignoreReadme: true, + }, + { + code: ` + /** + * + */ + function quux () { + return new Promise((resolve, reject) => { + var obj = { + [someKey]: 'val', + anotherKey: resolve(true) + } + }); + } + `, + errors: [ + { + line: 2, + message: 'Missing JSDoc @returns declaration.', + }, + ], + ignoreReadme: true, + }, + { + code: ` + /** + * + */ + function quux () { + return new Promise((resolve, reject) => { + var obj = { + [resolve(true)]: 'val', + } + }); + } + `, + errors: [ + { + line: 2, + message: 'Missing JSDoc @returns declaration.', + }, + ], + ignoreReadme: true, + }, { code: ` /**