Skip to content

Commit

Permalink
require-returns: more AST (ObjectPattern/ObjectProperty/`Object…
Browse files Browse the repository at this point in the history
…Method`/`Import`/`ImportExpression`/class related)
  • Loading branch information
brettz9 committed Jan 31, 2021
1 parent 6fd8a07 commit a8d09eb
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 18 deletions.
55 changes: 38 additions & 17 deletions src/jsdocUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ const hasReturnValue = (node, promFilter) => {
if (!node) {
return false;
}

switch (node.type) {
case 'FunctionExpression':
case 'FunctionDeclaration':
Expand Down Expand Up @@ -591,8 +592,6 @@ const hasNonEmptyResolverCall = (node, resolverName) => {

// Arrow function without block
switch (node.type) {
case 'ChainExpression':
return hasNonEmptyResolverCall(node.expression, resolverName);
// istanbul ignore next -- In Babel?
case 'OptionalCallExpression':
case 'CallExpression':
Expand All @@ -608,8 +607,11 @@ const hasNonEmptyResolverCall = (node, resolverName) => {
// Handle nested items
hasNonEmptyResolverCall(nde, resolverName);
});
case 'ChainExpression':
case 'Decorator':
case 'ExpressionStatement':
return hasNonEmptyResolverCall(node.expression, resolverName);
case 'ClassBody':
case 'BlockStatement':
return node.body.some((bodyNode) => {
return hasNonEmptyResolverCall(bodyNode, resolverName);
Expand All @@ -624,6 +626,7 @@ const hasNonEmptyResolverCall = (node, resolverName) => {

return hasNonEmptyResolverCall(node.body, resolverName);
}

case 'LabeledStatement':
case 'WhileStatement':
case 'DoWhileStatement':
Expand Down Expand Up @@ -663,7 +666,7 @@ const hasNonEmptyResolverCall = (node, resolverName) => {
case 'AssignmentPattern':
return hasNonEmptyResolverCall(node.right, resolverName);

// Todo: Review all of the statements below this for relevance to yields/throw/return checkers
// Todo: Review all of the types below this for adapting to yields checks
case 'AssignmentExpression':
case 'BinaryExpression':
case 'LogicalExpression': {
Expand All @@ -678,13 +681,40 @@ const hasNonEmptyResolverCall = (node, resolverName) => {
return hasNonEmptyResolverCall(subExpression, resolverName);
});

case 'ObjectPattern':
case 'ObjectExpression':
return node.properties.some((property) => {
return hasNonEmptyResolverCall(property, resolverName);
});
// istanbul ignore next -- In Babel?
case 'ClassMethod':
case 'MethodDefinition':
return node.decorators && node.decorators.some((decorator) => {
return hasNonEmptyResolverCall(decorator, resolverName);
}) ||
node.computed && hasNonEmptyResolverCall(node.key, resolverName) ||
hasNonEmptyResolverCall(node.value, resolverName);

// istanbul ignore next -- In Babel?
case 'ObjectProperty':
/* eslint-disable no-fallthrough */
// istanbul ignore next -- In Babel?
case 'ClassProperty':
/* eslint-enable no-fallthrough */
case 'Property':
return node.computed && hasNonEmptyResolverCall(node.key, resolverName) ||
hasNonEmptyResolverCall(node.value, resolverName);
// istanbul ignore next -- In Babel?
case 'ObjectMethod':
// istanbul ignore next -- In Babel?
return node.computed && hasNonEmptyResolverCall(node.key, resolverName) ||
node.arguments.some((nde) => {
return hasNonEmptyResolverCall(nde, resolverName);
});

case 'ClassExpression':
case 'ClassDeclaration':
return hasNonEmptyResolverCall(node.body, resolverName);

case 'AwaitExpression':
case 'SpreadElement':
Expand Down Expand Up @@ -712,22 +742,11 @@ const hasNonEmptyResolverCall = (node, resolverName) => {
return hasNonEmptyResolverCall(node.object, resolverName) ||
hasNonEmptyResolverCall(node.property, resolverName);

/*
// Todo: As relevant, also check these in return/throw and yield checks
case 'ObjectPattern':
case 'ClassProperty':
case 'ClassDeclaration': case 'ClassExpression': case 'MethodDefinition':
case 'Super':
case 'ExportDefaultDeclaration': case 'ExportNamedDeclaration':
// istanbul ignore next -- In Babel?
case 'Import':
case 'ImportExpression':
case 'Decorator':
return hasNonEmptyResolverCall(node.source, resolverName);

return false;
*/
case 'ReturnStatement': {
if (node.argument === null) {
return false;
Expand All @@ -737,10 +756,12 @@ const hasNonEmptyResolverCall = (node, resolverName) => {
}

/*
// Shouldn't need to parse literals/literal components
// Shouldn't need to parse literals/literal components, etc.
case 'Identifier':
case 'TemplateElement':
case 'Super':
// Exports not relevant in this context
*/
default:
return false;
Expand Down
173 changes: 172 additions & 1 deletion test/rules/assertions/requireReturns.js
Original file line number Diff line number Diff line change
Expand Up @@ -1290,7 +1290,7 @@ export default {
*/
function quux () {
return new Promise((resolve, reject) => {
const [a = resolve(true)] = [];
const [a = resolve(true)] = arr;
});
}
`,
Expand All @@ -1302,6 +1302,177 @@ export default {
],
ignoreReadme: true,
},
{
code: `
/**
*
*/
function quux () {
return new Promise((resolve, reject) => {
const {a = resolve(true)} = obj;
});
}
`,
errors: [
{
line: 2,
message: 'Missing JSDoc @returns declaration.',
},
],
ignoreReadme: true,
},
{
code: `
/**
*
*/
function quux () {
return new Promise((resolve, reject) => {
import(resolve(true));
});
}
`,
errors: [
{
line: 2,
message: 'Missing JSDoc @returns declaration.',
},
],
ignoreReadme: true,
parserOptions: {
ecmaVersion: 2_020,
},
},
{
code: `
/**
*
*/
function quux () {
return new Promise((resolve, reject) => {
class A {
method1 () {
resolve();
}
@dec(function () {
resolve()
})
method2 () {
resolve(true);
}
}
});
}
`,
errors: [
{
line: 2,
message: 'Missing JSDoc @returns declaration.',
},
],
ignoreReadme: true,
parser: require.resolve('@typescript-eslint/parser'),
},
{
code: `
/**
*
*/
function quux () {
return new Promise((resolve, reject) => {
class A {
method1 () {
resolve();
}
@dec(function () {
resolve(true)
})
method2 () {}
}
});
}
`,
errors: [
{
line: 2,
message: 'Missing JSDoc @returns declaration.',
},
],
ignoreReadme: true,
parser: require.resolve('@typescript-eslint/parser'),
},
{
code: `
/**
*
*/
function quux () {
return new Promise((resolve, reject) => {
const a = class {
[b] () {
resolve();
}
method1 () {
resolve(true);
}
method2 () {}
}
});
}
`,
errors: [
{
line: 2,
message: 'Missing JSDoc @returns declaration.',
},
],
ignoreReadme: true,
},
{
code: `
/**
*
*/
function quux () {
return new Promise((resolve, reject) => {
const a = class {
[b] () {
resolve(true);
}
}
});
}
`,
errors: [
{
line: 2,
message: 'Missing JSDoc @returns declaration.',
},
],
ignoreReadme: true,
},
{
code: `
/**
*
*/
export function quux () {
return new Promise((resolve, reject) => {
resolve(true);
});
}
`,
errors: [
{
line: 2,
message: 'Missing JSDoc @returns declaration.',
},
],
ignoreReadme: true,
parserOptions: {
sourceType: 'module',
},
},
{
code: `
/**
Expand Down

0 comments on commit a8d09eb

Please sign in to comment.