Summary
require-return-after-core-setfailed only inspects statement lists — BlockStatement.body (rule L332), SwitchCase.consequent (L349), and the filtered Program.body (L352). A core.setFailed(...) that is the direct single-statement consequent/alternate of an unbraced if/else, or the unbraced body of a for/while/for-of, is never an element of any of those lists. So it is neither checked for an immediately-following statement (checkStatementList) nor for cross-block continuation (findContinuationOutsideBlock, which only runs from the BlockStatement visitor at L338-345). Such a setFailed escapes the rule entirely.
File: eslint-factory/src/rules/require-return-after-core-setfailed.ts
False negatives (not flagged today)
if (bad) core.setFailed("x"); doMore(); // doMore() runs in a failed state
if (bad) core.setFailed("a"); else core.setFailed("b"); doMore();
for (const f of files) if (!ok(f)) core.setFailed("bad " + f); // continues the loop, then falls through
Inconsistency that makes this a clear gap
The braced equivalent is correctly flagged via findContinuationOutsideBlock:
if (bad) { core.setFailed("x"); } doMore(); // correctly reported today
So identical control flow is diagnosed or not purely based on the presence of braces around the consequent.
Grounding
No live braceless-if core.setFailed exists in actions/setup/js/** today — every current site returns immediately after setFailed (e.g. check_permissions.cjs:38-39, check_skip_if_helpers.cjs:54-55, create_labels.cjs:65-66). This is therefore a latent soundness gap / regression guard for a control-flow-safety rule, filed before such code lands. Alias/destructured/computed callee detection is already handled (shipped via #45334); this is a distinct, positional gap.
Acceptance criteria
core.setFailed() — in every already-recognized callee form (core., single-assignment alias, destructured { setFailed }, computed core["setFailed"]) — as the single-statement consequent or alternate of a braceless if/else is analyzed for a following continuation and reported when one exists.
- Same for braceless
for/for-in/for-of/while/do-while bodies, consistent with the existing loop back-edge handling at L113-122.
if (bad) core.setFailed("x"); as the terminal statement of a function/program (no continuation) stays valid (no report).
- The
addReturn suggestion must emit a syntactically valid, correctly-associated fix (e.g. wrap as if (bad) { core.setFailed("x"); return; }), never if (bad) core.setFailed("x"); return; which would detach the return from the if. Keep the suggestion gated by the existing isInsideFunctionLike check.
- Unit tests: braceless-if + continuation (invalid), braceless-if/else + continuation (invalid), braceless loop body + continuation (invalid), terminal braceless-if (valid); confirm all existing braced cases remain unchanged.
Generated by 🤖 ESLint Refiner · 360.4 AIC · ⌖ 12.5 AIC · ⊞ 4.6K · ◷
Summary
require-return-after-core-setfailedonly inspects statement lists —BlockStatement.body(rule L332),SwitchCase.consequent(L349), and the filteredProgram.body(L352). Acore.setFailed(...)that is the direct single-statement consequent/alternate of an unbracedif/else, or the unbraced body of afor/while/for-of, is never an element of any of those lists. So it is neither checked for an immediately-following statement (checkStatementList) nor for cross-block continuation (findContinuationOutsideBlock, which only runs from theBlockStatementvisitor at L338-345). Such asetFailedescapes the rule entirely.File:
eslint-factory/src/rules/require-return-after-core-setfailed.tsFalse negatives (not flagged today)
Inconsistency that makes this a clear gap
The braced equivalent is correctly flagged via
findContinuationOutsideBlock:So identical control flow is diagnosed or not purely based on the presence of braces around the consequent.
Grounding
No live braceless-
ifcore.setFailedexists inactions/setup/js/**today — every current site returns immediately aftersetFailed(e.g.check_permissions.cjs:38-39,check_skip_if_helpers.cjs:54-55,create_labels.cjs:65-66). This is therefore a latent soundness gap / regression guard for a control-flow-safety rule, filed before such code lands. Alias/destructured/computed callee detection is already handled (shipped via #45334); this is a distinct, positional gap.Acceptance criteria
core.setFailed()— in every already-recognized callee form (core., single-assignment alias, destructured{ setFailed }, computedcore["setFailed"]) — as the single-statement consequent or alternate of a bracelessif/elseis analyzed for a following continuation and reported when one exists.for/for-in/for-of/while/do-whilebodies, consistent with the existing loop back-edge handling at L113-122.if (bad) core.setFailed("x");as the terminal statement of a function/program (no continuation) stays valid (no report).addReturnsuggestion must emit a syntactically valid, correctly-associated fix (e.g. wrap asif (bad) { core.setFailed("x"); return; }), neverif (bad) core.setFailed("x"); return;which would detach thereturnfrom theif. Keep the suggestion gated by the existingisInsideFunctionLikecheck.