Skip to content

Barrel re-export with rename (export { X as Y } from ...) is not tracked, breaking barrel resolution #1823

Description

@carlos-alm

Summary

While fixing #1730 (renamed import specifiers not resolving to the correct call edge), I found a distinct-but-related gap in barrel/re-export handling: a barrel file that re-exports a symbol under a new name (export { X as Y } from './foo') does not track the rename at all, so resolution through that barrel silently breaks for consumers of the renamed name.

Root cause

extractImportNames in src/extractors/javascript.ts (and the mirrored scan_import_names_depth in crates/codegraph-core/src/extractors/javascript.rs) handles export_specifier nodes by always reading the tree-sitter name field (the local declaration being re-exported, i.e. X), and never the alias field (the external name it's re-exported as, i.e. Y). This part of the code is intentionally unchanged by #1730's fix — see the comment left in place in both files.

Given that, resolveBarrelExport in src/domain/graph/builder/stages/resolve-imports.ts (and resolve_barrel_export in crates/codegraph-core/src/domain/graph/builder/barrel_resolution.rs) look up a barrel's re-export list by the name a consumer of the barrel would import (Y), then call sourceDefinesSymbol(ctx, re.source, symbolName) to check whether the underlying module actually defines that name. Since re.names only ever contains X (never Y) for a renamed re-export, both the initial re.names.includes(symbolName) check and the sourceDefinesSymbol check fail whenever a consumer imports the barrel's renamed external name.

Repro

// underlying.js
export function realName() {}

// barrel.js
export { realName as friendlyName } from './underlying.js';

// consumer.js
import { friendlyName } from './barrel.js';
friendlyName();

friendlyName() in consumer.js does not resolve to realName in underlying.js — the call edge is dropped, and codegraph exports underlying.js reports zero consumers for realName even though it's genuinely used through the barrel.

Expected

resolveBarrelExport/resolve_barrel_export should be able to map the barrel's external name (Y) back to the original name (X) it re-exports, the same way #1730 taught direct-import resolution to do via Import.renamedImports/RenamedImport. The export_specifier branch of the extractor needs a parallel rename-pair mechanism (or reuse of the same renamedImports field, extended to export_specifier) plus barrel-resolution changes to consult it.

Scope note

Deliberately not fixed as part of #1730 — different code path (barrel/re-export resolution, not direct-import call-edge resolution), would have expanded that PR's scope significantly.

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