Skip to content

Commit b9058e4

Browse files
committed
fix(require-yields): avoid checking nested generators (as with functions)
1 parent a8d09eb commit b9058e4

File tree

3 files changed

+57
-28
lines changed

3 files changed

+57
-28
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16621,6 +16621,15 @@ function * quux () {
1662116621
yield;
1662216622
}
1662316623
// Options: [{"next":true}]
16624+
16625+
/**
16626+
*
16627+
*/
16628+
function * quux (foo) {
16629+
const a = function * bar () {
16630+
yield foo;
16631+
}
16632+
}
1662416633
````
1662516634

1662616635

src/jsdocUtils.js

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -794,33 +794,25 @@ const hasValueOrExecutorHasNonEmptyResolveValue = (node, anyPromiseAsReturn) =>
794794
});
795795
};
796796
797-
/**
798-
* Checks if a node has a return statement. Void return does not count.
799-
*
800-
* @param {object} node
801-
* @returns {boolean}
802-
*/
803797
// eslint-disable-next-line complexity
804-
const hasYieldValue = (node, checkYieldReturnValue) => {
798+
const hasNonFunctionYield = (node, checkYieldReturnValue) => {
805799
if (!node) {
806800
return false;
807801
}
808802
switch (node.type) {
809-
case 'FunctionExpression':
810-
case 'FunctionDeclaration': {
811-
return node.generator && (
812-
node.expression || hasYieldValue(node.body, checkYieldReturnValue)
813-
);
814-
}
815803
case 'BlockStatement': {
816804
return node.body.some((bodyNode) => {
817-
return bodyNode.type !== 'FunctionDeclaration' && hasYieldValue(
805+
return ![
806+
'ArrowFunctionExpression',
807+
'FunctionDeclaration',
808+
'FunctionExpression',
809+
].includes(bodyNode.type) && hasNonFunctionYield(
818810
bodyNode, checkYieldReturnValue,
819811
);
820812
});
821813
}
822814
case 'ExpressionStatement': {
823-
return hasYieldValue(node.expression, checkYieldReturnValue);
815+
return hasNonFunctionYield(node.expression, checkYieldReturnValue);
824816
}
825817
case 'LabeledStatement':
826818
case 'WhileStatement':
@@ -829,44 +821,44 @@ const hasYieldValue = (node, checkYieldReturnValue) => {
829821
case 'ForInStatement':
830822
case 'ForOfStatement':
831823
case 'WithStatement': {
832-
return hasYieldValue(node.body, checkYieldReturnValue);
824+
return hasNonFunctionYield(node.body, checkYieldReturnValue);
833825
}
834826
case 'ConditionalExpression':
835827
case 'IfStatement': {
836-
return hasYieldValue(node.test, checkYieldReturnValue) ||
837-
hasYieldValue(node.consequent, checkYieldReturnValue) ||
838-
hasYieldValue(node.alternate, checkYieldReturnValue);
828+
return hasNonFunctionYield(node.test, checkYieldReturnValue) ||
829+
hasNonFunctionYield(node.consequent, checkYieldReturnValue) ||
830+
hasNonFunctionYield(node.alternate, checkYieldReturnValue);
839831
}
840832
case 'TryStatement': {
841-
return hasYieldValue(node.block, checkYieldReturnValue) ||
842-
hasYieldValue(node.handler && node.handler.body, checkYieldReturnValue) ||
843-
hasYieldValue(node.finalizer, checkYieldReturnValue);
833+
return hasNonFunctionYield(node.block, checkYieldReturnValue) ||
834+
hasNonFunctionYield(node.handler && node.handler.body, checkYieldReturnValue) ||
835+
hasNonFunctionYield(node.finalizer, checkYieldReturnValue);
844836
}
845837
case 'SwitchStatement': {
846838
return node.cases.some(
847839
(someCase) => {
848840
return someCase.consequent.some((nde) => {
849-
return hasYieldValue(nde, checkYieldReturnValue);
841+
return hasNonFunctionYield(nde, checkYieldReturnValue);
850842
});
851843
},
852844
);
853845
}
854846
case 'ArrayPattern':
855847
case 'ArrayExpression':
856848
return node.elements.some((element) => {
857-
return hasYieldValue(element, checkYieldReturnValue);
849+
return hasNonFunctionYield(element, checkYieldReturnValue);
858850
});
859851
case 'AssignmentPattern':
860-
return hasYieldValue(node.right, checkYieldReturnValue);
852+
return hasNonFunctionYield(node.right, checkYieldReturnValue);
861853
862854
case 'VariableDeclaration': {
863855
return node.declarations.some((nde) => {
864-
return hasYieldValue(nde, checkYieldReturnValue);
856+
return hasNonFunctionYield(nde, checkYieldReturnValue);
865857
});
866858
}
867859
case 'VariableDeclarator': {
868-
return hasYieldValue(node.id, checkYieldReturnValue) ||
869-
hasYieldValue(node.init, checkYieldReturnValue);
860+
return hasNonFunctionYield(node.id, checkYieldReturnValue) ||
861+
hasNonFunctionYield(node.init, checkYieldReturnValue);
870862
}
871863
case 'YieldExpression': {
872864
if (checkYieldReturnValue) {
@@ -890,6 +882,18 @@ const hasYieldValue = (node, checkYieldReturnValue) => {
890882
}
891883
};
892884
885+
/**
886+
* Checks if a node has a return statement. Void return does not count.
887+
*
888+
* @param {object} node
889+
* @returns {boolean}
890+
*/
891+
const hasYieldValue = (node, checkYieldReturnValue) => {
892+
return node.generator && (
893+
node.expression || hasNonFunctionYield(node.body, checkYieldReturnValue)
894+
);
895+
};
896+
893897
/**
894898
* Checks if a node has a throws statement.
895899
*
@@ -902,6 +906,10 @@ const hasThrowValue = (node, innerFunction) => {
902906
if (!node) {
903907
return false;
904908
}
909+
910+
// There are cases where a function may execute its inner function which
911+
// throws, but we're treating functions atomically rather than trying to
912+
// follow them
905913
switch (node.type) {
906914
case 'FunctionExpression':
907915
case 'FunctionDeclaration':

test/rules/assertions/requireYields.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,5 +1446,17 @@ export default {
14461446
next: true,
14471447
}],
14481448
},
1449+
{
1450+
code: `
1451+
/**
1452+
*
1453+
*/
1454+
function * quux (foo) {
1455+
const a = function * bar () {
1456+
yield foo;
1457+
}
1458+
}
1459+
`,
1460+
},
14491461
],
14501462
};

0 commit comments

Comments
 (0)