Skip to content

fix(ts): follow re-export chains through index.ts barrels - #2900

Open
chidev wants to merge 6 commits into
DeusData:mainfrom
lev-os:fix/ts-reexport-chains-pr
Open

chidev wants to merge 6 commits into
DeusData:mainfrom
lev-os:fix/ts-reexport-chains-pr

Conversation

@chidev

@chidev chidev commented Nov 2, 2026

Copy link
Copy Markdown

Calls through index.ts re-exports now reach the function's defining file. This covers renamed named re-exports (export { a as b } from './m') and export * chains, the cases in #2718 and #1557.

Credit

The first two commits are @antespi's from #2402 (index.ts barrels, dotted file names). I kept his authorship and sign-off unchanged. On October 4 you asked for #2402 to be split into focused PRs. This PR is only the barrel part, plus one commit of mine for renames and export *. @antespi, if you would rather land these yourself, I will close this PR. It only builds on your work.

One claim

This PR changes only TS/JS re-export resolution. It does not include the bare-specifier binding reported in #2869, and it does not change MCP output.

Reproduction

repro.sh (below) writes 6 files: a renamed re-export, an export * chain, and a decoy file with the same names. It uses its own cache and runtime folders.

main (812d075):

a statePath src/other/decoy.ts unique_name "0.38"
b loadThing src/star/thing.impl.ts suffix_match "0.55"

this branch:

a getStatePath src/lib/xdg-paths.ts import_map "0.95"
b loadThing src/star/thing.impl.ts lsp_ts_import "0.95"
repro.sh
#!/usr/bin/env bash
# Calls through index.ts re-exports: a renamed named re-export and an export * chain.
# Usage: bash repro.sh [path/to/codebase-memory-mcp]
# Uses its own cache and runtime folders, so an installed daemon or index is not touched.
set -euo pipefail
BIN="${1:-codebase-memory-mcp}"
W="$(mktemp -d /tmp/cbmreexport.XXXX)"
export CBM_CACHE_DIR="$W/cache" CBM_RUNTIME_DIR="$W/run"
mkdir -p "$CBM_CACHE_DIR" "$CBM_RUNTIME_DIR"; chmod 700 "$CBM_RUNTIME_DIR"
R="$W/repo"; mkdir -p "$R/src/lib" "$R/src/star" "$R/src/other"
echo '{"name":"rel","private":true}' > "$R/package.json"
cat > "$R/src/app.ts" <<'TS'
import { statePath } from './lib';
import { loadThing } from './star';
export function a(): string { return statePath(); }
export function b(): number { return loadThing(); }
TS
echo "export { getStatePath as statePath } from './xdg-paths';" > "$R/src/lib/index.ts"
echo 'export function getStatePath(): string { return "/s"; }' > "$R/src/lib/xdg-paths.ts"
echo "export * from './thing.impl';" > "$R/src/star/index.ts"
echo 'export function loadThing(): number { return 1; }' > "$R/src/star/thing.impl.ts"
# Same names in an unrelated file, so a name guess is visible.
echo 'export function statePath(): string { return "decoy"; } export function loadThing(): number { return 2; }' > "$R/src/other/decoy.ts"
(cd "$R" && git init -q . && git add . && git -c user.email=r@example.invalid -c user.name=repro commit -qm init)
"$BIN" --version
"$BIN" cli --quiet index_repository "{\"repo_path\":\"$R\"}" > "$W/index.json"
P="$(grep -o '"project":"[^"]*"' "$W/index.json" | head -1 | cut -d'"' -f4)"
"$BIN" cli --quiet query_graph "{\"project\":\"$P\",\"query\":\"MATCH (a)-[r:CALLS]->(b) WHERE a.file_path = 'src/app.ts' RETURN a.name, b.name, b.file_path, r.strategy, r.confidence\"}"

Tests

New cases in tests/test_extraction_imports.c and tests/test_lsp_resolution_probe.c. On macOS arm64: scripts/test.sh --suites extraction_imports,edge_imports,path_alias,mcp,lsp_resolution_probe gives 625 passed, 4 skipped. The only failure in a wider run is regex_compile_refuses_overlong_pattern, which fails on main too (#2899).

Every commit is signed off. I have not seen CI on Linux or Windows yet.

antespi and others added 3 commits November 2, 2026 15:36
Signed-off-by: Antonio Espinosa <antespi@gmail.com>
Signed-off-by: Antonio Espinosa <antespi@gmail.com>
Named re-exports (export { a as b } from './m') and star re-exports
(export * from './m') are now recorded as re-export imports instead of
one module-level import. JS and TS call resolution uses the cross-file
import map, so a call through a barrel file reaches the function's
defining file, renames included.

Builds on the index.ts barrel commit from DeusData#2402. Covers the rename and
export * cases in DeusData#2718 and DeusData#1557.

Signed-off-by: chidev <chicagowebdev@gmail.com>
@chidev
chidev requested a review from DeusData as a code owner November 2, 2026 22:40
@chidev chidev mentioned this pull request Nov 2, 2026
3 of 4 tasks
@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

The barrel walker kept a visited set of file QNs. A barrel with both
`export * from './m'` and `export { a as b } from './m'` searched m for
`b` through the star edge first, marked m visited, and then skipped m
when the renamed edge asked for `a`. The call to `b` got no edge.

The visited set is now keyed on (file QN, name). Each key is an owned
string stored as its own value and freed with the table.

Tested: new lrp_ts_barrel_star_and_renamed_same_module fails before
(renamed=0) and passes after.

Suites extraction_imports, edge_imports, path_alias, mcp,
lsp_resolution_probe: 626 passed, 4 skipped. The issue repro binds both
calls at 0.95.

Signed-off-by: chidev <chicagowebdev@gmail.com>
Formats the changed lines with clang-format 20.1.8, drops a condition that
is always true (pass_calls.c), and narrows the scope of public_name
(pass_lsp_cross.c), as the lint job reported.

Signed-off-by: chidev <chicagowebdev@gmail.com>
The memory-core lint gate counted new raw allocator sites in the
re-export commits (pass_calls.c 22 -> 28, pass_lsp_cross.c 49 -> 61).

- The barrel walker now returns the graph node it reaches, borrowed for
  the life of the graph buffer, instead of a strdup'd QN. The import map
  stores that node's QN through the existing pxc_import_value_qn copy.
- File and symbol lookups use cbm_pipeline_file_node and a stack-built
  symbol QN (cbm_pipeline_fqn_symbol_prefix_len), so they allocate nothing.
- The visited-set keys are allocated and freed with cbm_alloc/cbm_free
  (CBM_MEM_CLASS_OTHER).
- pass_calls keeps the JS/TS cross-file map as built and frees it with
  cbm_pxc_free_import_map, instead of copying it into a borrowed array.

Both files are back at their baseline counts.

Signed-off-by: chidev <chicagowebdev@gmail.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants