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.
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 anIfStatement'sconsequentandalternatebut not itstest.SwitchStatementwalks each case'sconsequentand skips thediscriminantalong with the individualcasetests. The loop branches walkbodyand skipinit,test,update, andright.Reproduction
Both of these pass on the rule as it stood before #1050 and are reported after it:
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()andcollectDeliveryScanCode()already handle the nodes returned bycollectReachableStatements(), so the change can stay within that walk and its consumers. Make the expressions visible tocollectConsumedCallbacks()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
iftest, a helper call in a switch discriminant, and a delivery call in a loop'sinitorright. Scanning a test expression must not resurrect the branch behind it:if (false)should still hide its consequent.