Skip to content

export const { a, b } = ... never marks destructured bindings as exported #2070

Description

@carlos-alm

Both engines' `collectExportedDeclarations`/`collect_exported_var_declarations` skip any declarator whose name isn't a plain identifier (`if (nameN?.type !== 'identifier' ...) continue;` in `src/extractors/javascript.ts`, `if name_n.kind() != "identifier" { continue; }` in `crates/codegraph-core/src/extractors/javascript.rs`). For `export const { a, b } = callExpr();`, the name field is an `object_pattern`, so this declarator is skipped entirely — no export entry is pushed for it at all.

Meanwhile `handleVariableDeclarator`/`handle_var_decl`'s separate `object_pattern` branch (via `extractDestructuredBindings`/`extract_destructured_bindings`) does correctly create `Definition` rows for `a` and `b`. Since no matching `ExportInfo` is ever produced for them, the exported=1 UPDATE (keyed on name/kind/file/line, see #1728) never fires — `a` and `b` are real definitions that are genuinely exported at the JS/TS level, but `codegraph exports`/dead-export analysis will never show them as exported.

Repro (either engine):
```js
export const { a, b } = callExpr();
```
`codegraph exports ` (or a direct `extractSymbols` call) shows `a`/`b` as definitions but never as exports.

Confirmed unchanged/pre-existing on both engines as of PR #1964 (fix/issue-1819) — not introduced by that PR, just verified still present while resolving its merge conflicts. A Greptile review comment on #1964 initially described this as a "phantom export entry" (`{a, b}` pushed as a literal export name), but that specific scenario does not reproduce — the `name.kind() !== 'identifier'` guard prevents any entry from being pushed at all, phantom or otherwise. The actual gap is the omission described above.

Fix sketch: when `name_n.kind() == "object_pattern"` (or `array_pattern`) and the declaration is exported, walk the pattern the same way `extractDestructuredBindings`/`extract_destructured_bindings` does and push one `ExportInfo` per bound name, instead of skipping the declarator outright.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    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