Skip to content

eslint-factory: require-return-after-core-setfailed misses aliased/destructured core.setFailed #45051

Description

@github-actions

Rule

require-return-after-core-setfailed (eslint-factory/src/rules/require-return-after-core-setfailed.ts) — first review since it shipped (15th rule; not yet in the README).

Summary

The control-flow analysis in this rule is strong and well-tested (same-block, cross-block continuation through if/else/else if, loop back-edges, switch fall-through). But detection of the core.setFailed(...) call itself is purely syntactic: isCoreSetFailedStatement only matches a MemberExpression whose object is the Identifier named exactly core and whose property is setFailed (non-computed). Any indirection escapes the rule entirely — the setFailed is not recognized, so a missing control-transfer after it is a false negative.

Escaping forms:

const c = core; c.setFailed(msg); doMore();            // aliased object
const { setFailed } = core; setFailed(msg); doMore();  // destructured
core["setFailed"](msg); doMore();                       // computed access
const core2 = require("`@actions/core`"); ...            // renamed import

Each of these silently passes even though execution continues after failure is declared.

Grounding

Ungrounded / latent — a grep of non-test actions/setup/js/**/*.cjs shows every production core.setFailed(...) uses the literal core.setFailed form and is already followed by return or is block/function-terminal (the corpus is disciplined; the rule currently produces zero live violations). The { setFailed } / = core matches in the tree are all test mocks. This is therefore a regression-guard / coverage refinement, not a live bug — but it mirrors the alias-blindspot false negatives previously filed and fixed for sibling rules (e.g. require-await-core-summary-write #43404, require-error-cause-in-rethrow #43948), so it is worth closing before an aliased usage lands.

Proposed refinement

Resolve core aliases and destructured setFailed bindings via scope analysis (as the sibling rules now do), covering at least:

  • const c = core; c.setFailed(...) — single-hop const alias of core.
  • const { setFailed } = core; setFailed(...) — destructured binding.
  • core["setFailed"](...) — computed member with a string-literal property.

Exclude locally-shadowed bindings (a local function setFailed() / parameter), consistent with the shadow handling in prefer-number-isnan.

Acceptance criteria

  • Aliased (const c = core; c.setFailed(...)) and destructured (const { setFailed } = core; setFailed(...)) calls not followed by a control transfer are reported, with the same cross-block/continuation semantics as the direct form.
  • Computed core["setFailed"](...) is recognized.
  • Locally-shadowed setFailed bindings are not flagged (tests).
  • The existing suggestion (addReturn) behaves identically for the alias/destructure forms.

Filed by the ESLint Refiner daily review (newest-rule coverage; ungrounded/latent).

Generated by 🤖 ESLint Refiner · 354.5 AIC · ⌖ 12.7 AIC · ⊞ 4.6K ·

  • expires on Jul 18, 2026, 10:27 PM UTC-08:00

Metadata

Metadata

Labels

cookieIssue Monster Loves Cookies!eslint

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions