Skip to content

Fix/import map call resolution#243

Open
petercoxphoto wants to merge 4 commits intoDeusData:mainfrom
petercoxphoto:fix/import-map-call-resolution
Open

Fix/import map call resolution#243
petercoxphoto wants to merge 4 commits intoDeusData:mainfrom
petercoxphoto:fix/import-map-call-resolution

Conversation

@petercoxphoto
Copy link
Copy Markdown

@petercoxphoto petercoxphoto commented Apr 11, 2026

Fix CALLS edge mis-resolution for TypeScript path aliases

Summary

  • Layer 1a: Add tsconfig.json path alias resolution. TypeScript projects using path aliases (e.g. @/*src/*) had zero IMPORTS edges because resolve_relative_import only handled ./relative paths. New cbm_load_tsconfig_paths() parses compilerOptions.paths and baseUrl from tsconfig.json/jsconfig.json. Aliases sorted by specificity (longest prefix first) per TypeScript semantics. JSONC-aware (comments + trailing commas).
  • Layer 1b: Walk monorepo for nested tsconfigs. The initial fix only read {repo_root}/tsconfig.json. Monorepos have path aliases in subdirectory tsconfigs (e.g. apps/manager/tsconfig.json). New cbm_load_all_tsconfig_paths() walks the repo for all tsconfig.json/jsconfig.json files and builds a per-directory alias collection. cbm_find_path_aliases() finds the nearest ancestor tsconfig for each source file. Target paths (e.g. ./src/*) are resolved relative to the tsconfig's directory.
  • Layer 2: Fix bare function call resolution via import_map. When callee has no dot (e.g. requireAdmin), the candidate QN was built as just module_qn instead of module_qn.requireAdmin. One-line fix in registry.c.
  • 20 new tests covering alias resolution (wildcards, exact match, baseUrl, overlapping prefixes, extension stripping, NULL safety), monorepo collection (nearest ancestor lookup, no-match fallback, root-only), and the registry bare function call fix. All 2740 tests pass (ASan + UBSan).

Problem

CALLS edges for cross-file function calls are mis-wired or missing when functions share names across files in TypeScript projects that use path aliases.

Resolution cascade failure:

  1. Strategy 1 (import_map) — fails because IMPORTS edges are missing (no alias resolution)
  2. Strategy 2 (same_module) — fails because the function is in a different file
  3. Strategy 3/4 (name_lookup) — finds both candidates, picks the wrong one

Verified impact

Tested against a real monorepo (Next.js, 2,769 nodes, @/* aliases in apps/manager/tsconfig.json):

Metric Before fix After Layer 1a After Layer 1b
IMPORTS edges 102 123 682
Total edges 4,383 5,238 6,186

The 6.7x increase in IMPORTS edges directly improves trace_path accuracy for cross-file call resolution.

Files changed

File Change
src/pipeline/fqn.c New: cbm_load_tsconfig_paths, cbm_resolve_path_alias, cbm_load_all_tsconfig_paths, cbm_find_path_aliases, cbm_tsconfig_collection_free
src/pipeline/pipeline_internal.h New: cbm_path_alias_t, cbm_path_alias_map_t, cbm_tsconfig_entry_t, cbm_tsconfig_collection_t structs
src/pipeline/pipeline.c Load tsconfig collection at pipeline start, free on cleanup
src/pipeline/pipeline_incremental.c Same for incremental pipeline path
src/pipeline/pass_definitions.c Resolve imports via nearest ancestor tsconfig aliases
src/pipeline/pass_parallel.c Same for parallel pipeline path
src/pipeline/registry.c Fix bare function call candidate: module_qn.prefix not module_qn
tests/test_fqn.c 19 new tests (alias resolution + monorepo collection)
tests/test_registry.c 1 new bare function call import_map test

Test plan

  • All 2740 tests pass (ASan + UBSan enabled)
  • Path alias wildcard resolution (@/lib/authsrc/lib/auth)
  • Multiple alias prefixes (@/, ~/, @components/)
  • Overlapping prefixes resolved by specificity (longest prefix wins)
  • baseUrl resolution with bare package name exclusion
  • Exact match aliases (no wildcard)
  • Extension stripping (.ts, .tsx, .js, .jsx)
  • NULL safety (NULL map, NULL path, missing tsconfig)
  • Relative imports unaffected by alias resolution
  • Bare function call via import_map resolves correctly
  • Monorepo: nearest ancestor tsconfig selected per source file
  • Monorepo: root-only tsconfig matches all files
  • Monorepo: files with no ancestor tsconfig fall through gracefully
  • Monorepo: non-existent repo returns NULL
  • No memory leaks (ASan clean)
  • Real-world verification: On an in-house project, IMPORTS 102 → 682

petercoxphoto and others added 4 commits April 11, 2026 19:24
When a callee has no dot (e.g. `requireAdmin()` vs `pkg.Func()`), the
import_map strategy built the candidate QN as just the module QN instead
of module_qn.functionName. This caused lookups to fail, falling through
to name-based resolution which picks the wrong target when multiple
functions share the same name across files.

Example: `settings.ts` imports `requireAdmin` from `@/lib/authorization`,
but the CALLS edge was wired to a same-named local function in `users.ts`
because Strategy 1 failed and Strategy 3/4 picked by name alone.

Fix: append prefix (the callee name) to the resolved module QN when
suffix is NULL, matching the actual function node QN format.

Note: This fix is necessary but not sufficient — the import map must
also be populated with correct IMPORTS edges. TypeScript path aliases
(e.g. @/lib/foo) are not currently resolved, which is tracked separately.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Layer 1 fix: TypeScript projects using path aliases (e.g. @/* → src/*) had
zero IMPORTS edges because resolve_relative_import only handled ./relative
paths. Added tsconfig.json parser that reads compilerOptions.paths and
baseUrl, resolves aliases during IMPORTS edge creation in both sequential
and parallel pipelines.

Layer 2 was already fixed (069c895): bare function calls via import_map
now correctly build candidate as module_qn.functionName instead of just
module_qn.

14 new tests covering alias resolution, baseUrl, edge cases, and the
registry bare function call fix. All 2734 tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Audit fix: TypeScript resolves to the most specific matching alias.
Sort entries by alias_prefix length descending during loading so
"@/lib/star" matches before "@/star". Added test verifying this.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous fix only read {repo_root}/tsconfig.json. Monorepos like
Skyline have path aliases in apps/manager/tsconfig.json, not the root.
IMPORTS went from 102->123 instead of the expected hundreds.

New cbm_load_all_tsconfig_paths() walks the repo for all tsconfig.json
and jsconfig.json files, parses each, and builds a per-directory alias
collection. Target paths (e.g. "./src/star") are resolved relative to
the tsconfig's directory. cbm_find_path_aliases() finds the nearest
ancestor tsconfig for each source file being processed.

5 new collection tests. All 2740 tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@DeusData DeusData added bug Something isn't working parsing/quality Graph extraction bugs, false positives, missing edges labels Apr 15, 2026
Dialectician added a commit to Dialectician/codebase-memory-mcp that referenced this pull request Apr 18, 2026
Plans extending cbm_pkgmap_try_parse with a pre-scan phase for
workspace-root detection (npm package.json#workspaces, pnpm-
workspace.yaml, Cargo.toml [workspace]). Three-phase PR rollout.

Ships as a parallel-coordination strategy: file an upstream issue
AND open a draft PR for Phase 1 simultaneously, to give maintainers
something concrete to react to rather than a design-doc thread.

Explicitly acknowledges PR DeusData#243 (936 LoC, touches pipeline init/
cleanup + incremental paths) and proposes waiting for its merge or
rebasing on it.

Not for upstream merge — this is a planning branch on our fork.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working parsing/quality Graph extraction bugs, false positives, missing edges

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants