Skip to content

TypeScript/JavaScript: a function bound through a wrapper call gets no node unless the wrapper is a React hook #1747

Description

@Dshuishui

CodeGraph already names an anonymous function after the variable_declarator it
is bound through — react_hook_bound_name does exactly this. The mechanism reads
as a general one, but it only runs when the callee is useCallback,
useEffectEvent or useEvent, so the same shape with any other wrapper yields
no function node at all.

Repro

declare const Effect: { fn: (n: string) => (b: unknown) => unknown };
declare function useCallback<T>(f: T, d: unknown[]): T;

function helper() { return 1; }

const viaHook   = useCallback(() => { return helper(); }, []);
const viaEffect = Effect.fn("Session.run")(function* () { return helper(); });

After codegraph index:

nodes:  helper · viaHook (function) · viaHook (constant) · viaEffect (constant)
edges:  viaHook -> helper
        b.ts    -> helper          <- the file, not a function

viaEffect gets a constant node but no function node. Its body is not simply
missing, either: the helper() call inside it is attributed to the file, so
the file picks up an outgoing call edge that belongs to a function, and
helper's caller list names the file rather than the function that actually
calls it.

What the two lines have in common

Both are an anonymous function passed as an argument to the call a
variable_declarator binds, and the declarator name is available in both. The
only difference is the callee's identity, checked against a literal list:

// codegraph-kernel/src/tsjs/mod.rs:769 — react_hook_bound_name
if !matches!(hook, "useCallback" | "useEffectEvent" | "useEvent") {
// src/extraction/tree-sitter.ts:396
const REACT_HANDLER_HOOKS = /^(?:React\.)?use(?:Callback|EffectEvent|Event)$/;

Other wrappers that land in the same position:

Shape Ecosystem
const run = Effect.fn("Session.run")(function* () {}) Effect-TS
const C = connect(mapState)(function () {}) Redux
const x = wrap("name")(function () {}) project-local helpers

Scope

The shape is not rare. sst/opencode carries 1,056 distinct string-named
Effect.fn* wrappers across its packages. Indexing it, 48 of them end up with a
function node — the other 1,008 are functions missing from the graph, each one
also sending its body's calls to a file instead of to a function.

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

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions