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>
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.

1 participant