Skip to content

outbox-listener-delivery-required ignores control-flow head expressions #1052

Description

@dahlia

Why

outbox-listener-delivery-required (@fedify/lint) decides whether a listener delivers by walking the statements it can prove are reachable. The walk covers statement bodies but never the expressions in a control-flow header, so a delivery call or a helper call sitting in one of those positions is invisible and the listener gets reported as undelivered.

In packages/lint/src/rules/outbox-listener-delivery-required.ts, collectReachableStatements() recurses into an IfStatement's consequent and alternate but not its test. SwitchStatement walks each case's consequent and skips the discriminant along with the individual case tests. The loop branches walk body and skip init, test, update, and right.

Reproduction

Both of these pass on the rule as it stood before #1050 and are reported after it:

federation
  .setOutboxListeners("/users/{identifier}/outbox")
  .on(Activity, async (ctx, activity) => {
    if (await ctx.sendActivity({ identifier: ctx.identifier }, inbox, activity)) {
      console.log("sent");
    }
  });
federation
  .setOutboxListeners("/users/{identifier}/outbox")
  .on(Activity, async (ctx, activity) => {
    async function deliver() {
      await ctx.sendActivity({ identifier: ctx.identifier }, inbox, activity);
      return 1;
    }
    switch (await deliver()) {
      case 1:
        break;
    }
  });

Given what sendActivity() returns, a delivery call is unlikely to appear in a head expression. A helper call is more plausible, so the rule should scan these expressions rather than document them as a limitation.

Scope

Collect the head expressions alongside the bodies. computeUsedFunctions() and collectDeliveryScanCode() already handle the nodes returned by collectReachableStatements(), so the change can stay within that walk and its consumers. Make the expressions visible to collectConsumedCallbacks() as well, so an awaited callback in a head expression counts.

Suggested checks

Add cases to packages/lint/src/tests/outbox-listener-delivery-required.test.ts for a delivery call in an if test, a helper call in a switch discriminant, and a delivery call in a loop's init or right. Scanning a test expression must not resurrect the branch behind it: if (false) should still hide its consequent.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Fields

    Priority

    None yet

    Effort

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions