Why
A listener that hands delivery to a helper declared outside it is reported as undelivered:
async function deliverToFollowers(ctx, activity) {
await ctx.sendActivity({ identifier: ctx.identifier }, "followers", activity);
}
federation
.setOutboxListeners("/users/{identifier}/outbox")
.on(Activity, async (ctx, activity) => {
await deliverToFollowers(ctx, activity);
});
Pulling a delivery helper out to module scope is ordinary, so this is a false positive with no useful fix for the listener.
The behavior predates #1050. The original rule scanned only the listener's own source text, so a helper anywhere else was always invisible. The #1050 rewrite added machinery that can cover this case: collectNamedHelpers() and collectResolvedCallTargets() in packages/lint/src/rules/outbox-listener-delivery-required.ts already resolve calls through variable bindings, object literals, and sibling helpers. They are never given declarations above the listener body.
Scope
Seed the helper map from the enclosing module scope before walking the listener, so that a call to a module-level function resolves the way a local one does. A helper in the same file is the natural boundary.
Add a mutual-recursion test. The visited set already carried by computeUsedFunctions() should cover a cycle between the listener and a module-level helper.
Non-goals
No cross-file analysis and no type information, following #900. A helper imported from another module should keep reporting, and that limitation belongs in docs/manual/lint.md rather than in the analysis.
Suggested checks
Add cases to packages/lint/src/tests/outbox-listener-delivery-required.test.ts for a module-level function declaration, a module-level const arrow binding, a module-level helper that is declared but never called, and a helper imported from another module. The last two should still report.
Why
A listener that hands delivery to a helper declared outside it is reported as undelivered:
Pulling a delivery helper out to module scope is ordinary, so this is a false positive with no useful fix for the listener.
The behavior predates #1050. The original rule scanned only the listener's own source text, so a helper anywhere else was always invisible. The #1050 rewrite added machinery that can cover this case:
collectNamedHelpers()andcollectResolvedCallTargets()in packages/lint/src/rules/outbox-listener-delivery-required.ts already resolve calls through variable bindings, object literals, and sibling helpers. They are never given declarations above the listener body.Scope
Seed the helper map from the enclosing module scope before walking the listener, so that a call to a module-level function resolves the way a local one does. A helper in the same file is the natural boundary.
Add a mutual-recursion test. The
visitedset already carried bycomputeUsedFunctions()should cover a cycle between the listener and a module-level helper.Non-goals
No cross-file analysis and no type information, following #900. A helper imported from another module should keep reporting, and that limitation belongs in docs/manual/lint.md rather than in the analysis.
Suggested checks
Add cases to packages/lint/src/tests/outbox-listener-delivery-required.test.ts for a module-level
functiondeclaration, a module-levelconstarrow binding, a module-level helper that is declared but never called, and a helper imported from another module. The last two should still report.