Skip to content

fix: mark destructured const export bindings as exported (#2070) - #2294

Merged
carlos-alm merged 2 commits into
mainfrom
fix/issue-2070
Aug 6, 2026
Merged

fix: mark destructured const export bindings as exported (#2070)#2294
carlos-alm merged 2 commits into
mainfrom
fix/issue-2070

Conversation

@carlos-alm

Copy link
Copy Markdown
Contributor

Summary

export const { a, b } = value and export const [a, b] = value never marked a/b as exported on either engine — collectExportedDeclarations (TS) and collect_exported_var_declarations (Rust) both skipped any declarator whose name field wasn't a plain identifier, so an object_pattern/array_pattern name field caused the declarator to be dropped entirely before pushing any Export. The matching Definition rows for a/b were created correctly by the sibling destructuring logic (extractDestructuredBindings/extract_destructured_bindings), so codegraph exports/dead-export analysis showed them as definitions but never as exports.

Both engines now walk the object_pattern/array_pattern name field the exact same way the Definition-building side already does, and push one 'constant' Export per bound name:

  • TS: extracted collectObjectPatternNames/collectArrayPatternNames name-only helpers out of extractDestructuredBindings/extractArrayPatternBindings (used by both, so they can never drift), and call them from collectExportedDeclarations.
  • Rust: reused the existing collect_object_pattern_names/collect_array_pattern_names helpers (already shared elsewhere) from collect_exported_var_declarations.

Restricted to const, matching the Definition side's own let/var restriction — export let { a } = ... still does not produce a Definition, so it must not produce an Export either.

Verification

  • lint: pass (npm run lint)
  • tests: pass (npm test — 275 files / 4470 tests; cargo test -p codegraph-core --lib — 780 tests)
  • added regression tests on both engines for object-pattern exports, array-pattern exports, and the let/var non-export case
  • codegraph diff-impact --staged -T confirms the change is contained to the destructuring/export helper family (5 functions, 14 callers, 1 file)

Closes #2070

collectExportedDeclarations (TS) / collect_exported_var_declarations (Rust)
skipped any declarator whose name field wasn't a plain identifier, so
`export const { a, b } = value` and `export const [a, b] = value` produced
Definition rows for a/b but no matching Export entries — the exported=1
UPDATE never fired even though the bindings are genuinely exported.

Both engines now walk the object_pattern/array_pattern name field the same
way the Definition-building side already does (via shared
collectObjectPatternNames/collectArrayPatternNames helpers extracted from
extractDestructuredBindings/extractArrayPatternBindings on the TS side, and
the existing collect_object_pattern_names/collect_array_pattern_names on the
Rust side), pushing one 'constant' Export per bound name. Restricted to
const, matching the Definition side's own let/var restriction.

docs check acknowledged: internal extractor bug fix, no README/CLAUDE.md/
ROADMAP surface (language list, feature list, architecture) changes needed.

Impact: 5 functions changed, 14 affected
@greptile-apps

greptile-apps Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR aligns destructured const export collection with Definition extraction in both JavaScript engines.

  • Collects object- and array-pattern binding names as constant exports.
  • Recursively handles nested array patterns used as rest targets in Rust, completing the previous review fix.
  • Adds native and TypeScript regression coverage for destructured exports and excluded let/var declarations.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the previously reported nested array-rest export omission is fixed in the current code.

Important Files Changed

Filename Overview
crates/codegraph-core/src/extractors/javascript.rs Adds destructured export collection and correctly recurses into nested array-pattern rest targets, resolving the previous Rust-engine omission.
src/extractors/javascript.ts Shares destructuring name collectors between Definition and Export extraction so the TypeScript engine produces matching bindings.
tests/parsers/javascript.test.ts Adds focused coverage for object, array, nested-rest, and non-const destructured export behavior.

Reviews (2): Last reviewed commit: "fix: recurse into nested array-pattern r..." | Re-trigger Greptile

}
}
"array_pattern" if is_const => {
for name in collect_array_pattern_names(&name_n, source) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Nested rest exports remain unmarked

When an exported const uses a nested array pattern as a rest target, such as export const [x, ...[a, b]] = value, collect_array_pattern_names omits a and b even though the Definition path creates both bindings, causing the Rust engine to leave these exports unmarked and diverge from the TypeScript engine.

Knowledge Base Used:

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cf97b73collect_array_pattern_names's rest_pattern branch now recurses into a nested array_pattern the same way extract_array_pattern_bindings's Definition-side rest handling already did, instead of delegating to the plain-identifier-only extract_rest_identifier. Added regression tests on both engines (marks_exported_nested_array_pattern_rest_bindings_as_exports in Rust, "marks exported nested array-pattern rest bindings as exports" in TS) covering export const [x, ...[a, b]] = value.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Codegraph Impact Analysis

5 functions changed14 callers affected across 1 files

  • collectExportedDeclarations in src/extractors/javascript.ts:227 (6 transitive callers)
  • extractDestructuredBindings in src/extractors/javascript.ts:1605 (6 transitive callers)
  • collectObjectPatternNames in src/extractors/javascript.ts:1627 (10 transitive callers)
  • extractArrayPatternBindings in src/extractors/javascript.ts:1684 (6 transitive callers)
  • collectArrayPatternNames in src/extractors/javascript.ts:1702 (10 transitive callers)

#2070)

Greptile review on PR #2294: collect_array_pattern_names's rest_pattern
branch called the plain-identifier-only extract_rest_identifier, so a rest
element nesting another array pattern (`...[a, b]`) got Definitions via
extract_array_pattern_bindings's own recursive rest handling but no matching
Export at all for `export const [x, ...[a, b]] = value` — diverging from
both the Definition side and the TS engine, which already recursed here.

Mirrors extract_array_pattern_bindings's rest_pattern handling directly in
collect_array_pattern_names instead of delegating to extract_rest_identifier
(left unchanged for its other two call sites — both object-pattern rest,
which can only ever bind a plain identifier per the grammar).

docs check acknowledged: internal extractor bug fix, no README/CLAUDE.md/
ROADMAP surface changes needed.
@carlos-alm

Copy link
Copy Markdown
Contributor Author

@greptileai

@carlos-alm
carlos-alm merged commit e60956b into main Aug 6, 2026
36 checks passed
@carlos-alm
carlos-alm deleted the fix/issue-2070 branch August 6, 2026 09:38
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 6, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant