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.
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
extractImportNamesinsrc/extractors/javascript.ts(and the mirroredscan_import_names_depthincrates/codegraph-core/src/extractors/javascript.rs) handlesexport_specifiernodes by always reading the tree-sitternamefield (the local declaration being re-exported, i.e.X), and never thealiasfield (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,
resolveBarrelExportinsrc/domain/graph/builder/stages/resolve-imports.ts(andresolve_barrel_exportincrates/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 callsourceDefinesSymbol(ctx, re.source, symbolName)to check whether the underlying module actually defines that name. Sincere.namesonly ever containsX(neverY) for a renamed re-export, both the initialre.names.includes(symbolName)check and thesourceDefinesSymbolcheck fail whenever a consumer imports the barrel's renamed external name.Repro
friendlyName()in consumer.js does not resolve torealNamein underlying.js — the call edge is dropped, andcodegraph exports underlying.jsreports zero consumers forrealNameeven though it's genuinely used through the barrel.Expected
resolveBarrelExport/resolve_barrel_exportshould 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 viaImport.renamedImports/RenamedImport. The export_specifier branch of the extractor needs a parallel rename-pair mechanism (or reuse of the samerenamedImportsfield, extended toexport_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.