Skip to content

Comments

Add TypeScript import path resolver with tsconfig paths support#642

Open
alex4o wants to merge 4 commits intoCodeGraphContext:mainfrom
alex4o:ts-import-resolver
Open

Add TypeScript import path resolver with tsconfig paths support#642
alex4o wants to merge 4 commits intoCodeGraphContext:mainfrom
alex4o:ts-import-resolver

Conversation

@alex4o
Copy link

@alex4o alex4o commented Feb 15, 2026

What

Index <JSXComponent /> tags as call-sites so component usage shows up in the code graph.
Resolve TS/TSX import paths (aliases from tsconfig.json and relative imports) to absolute file paths so two files importing the same module share one Module node instead of creating duplicates.

Why

Without this:

  • <Layout> or <Button /> in .tsx files are invisible to the graph — no CALLS edge is created.
  • import { capitalize } from "@utils/string-helpers" and import { capitalize } from "./utils/string-helpers" produce two separate Module nodes for the same file, fragmenting the graph.

How

JSX call-site indexing

  • Added TypescriptJSXTreeSitterParser (extends the TS parser) with a _find_calls override that runs a tree-sitter query for jsx_opening_element / jsx_self_closing_element.
  • PascalCase names are treated as component references; lowercase (<div>) is ignored.
  • .tsx files now use the new typescriptjsx parser instead of reusing typescript.

TS import resolution

  • New ts_import_resolver.py module with:
    • parse_tsconfig_paths(project_root) — reads tsconfig.json (handles // comments, trailing commas, one level of extends), returns baseUrl + paths map.
    • resolve_ts_import(specifier, importing_file, ...) — resolves in order: relative → alias → baseUrl → bare (returns None for npm packages).
    • _try_resolve_file(base) — tries exact path → .ts/.tsx/.js/.jsxindex.{ts,tsx,js,jsx}.
  • graph_builder.py calls parse_tsconfig_paths once per indexing run, then passes the config to add_file_to_graph where each import is resolved before MERGE (m:Module {name: $resolved_path}).
  • Module nodes now also store raw_specifier (the original import string) for debugging.

Example

// tsconfig.json: { "paths": { "@utils/*": ["src/utils/*"] } }

// src/App.tsx
import { capitalize } from "@utils/string-helpers";  // → resolves to /abs/src/utils/string-helpers.ts
import Layout from "./Layout";                        // → resolves to /abs/src/Layout.tsx

const App = () => (
  <Layout>              // ← CALLS edge to Layout component
    <Button />          // ← CALLS edge to Button component
  </Layout>
);

Testing

  • Unit tests (test_ts_import_resolver.py, 25 tests): _try_resolve_file, relative imports, bare specifiers, alias imports, tsconfig.json parsing (comments, trailing commas, extends).
  • Integration tests (test_ts_import_resolver_integration.py, 14 tests): parse the real fixture app-service.ts with tree-sitter, then resolve every import against the fixture's tsconfig.json.
  • E2E tests (test_ts_indexing.py): index the full TS fixture into the DB and verify via Cypher that alias imports resolve to absolute paths, bare specifiers stay raw, JSX component calls are detected, and no duplicate Module nodes exist.
  • Fixture: expanded sample_project_typescript with tsconfig.json paths, .tsx components (App.tsx, Layout.tsx, Button.tsx), alias-imported modules (string-helpers, math-helpers, user-model, constants, logger), and app-service.ts exercising all import patterns.

alex4o and others added 3 commits February 15, 2026 01:07
Use the tsx tree-sitter grammar for .tsx files (the typescript grammar
misparses JSX as type assertions). Override _find_calls() in
TypescriptJSXTreeSitterParser to capture jsx_opening_element and
jsx_self_closing_element nodes, filtering to PascalCase names only.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Resolve TS/JS import specifiers to absolute file paths during indexing so
that Module nodes use resolved paths instead of raw specifiers. This makes
File->Module->File traversal work correctly for relative and alias imports.

- Create ts_import_resolver.py handling relative, alias (tsconfig paths),
  and bare specifier imports with extension/index file resolution
- Fix lang routing bug: include 'typescript' and 'typescriptjsx' alongside
  'javascript' in the import handling branch of graph_builder
- Parse tsconfig.json once per indexing run (supports baseUrl, paths,
  extends, comments, trailing commas)
- Store raw_specifier on Module nodes for debugging
- Add test fixture files with tsconfig paths aliases (@utils/*, @models/*,
  @shared/*, @app/*) and corresponding source files
- Add 50 unit + integration tests covering resolver, tsconfig parsing,
  and end-to-end resolution with real TS parser output

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add ts_import_resolver for resolving TypeScript path aliases from tsconfig.json
- Track JSX component usage as CALLS relationships in graph builder
- Add TSX test fixtures and e2e test for TypeScript indexing
- Update sample TypeScript project with TSX components

Amp-Thread-ID: https://ampcode.com/threads/T-019c6303-d1c9-763f-b9ab-08be8da73f8a
Co-authored-by: Amp <[email protected]>
@vercel
Copy link

vercel bot commented Feb 15, 2026

@alex4o is attempting to deploy a commit to the shashankss1205's projects Team on Vercel.

A member of the Team first needs to authorize it.

…icity

- Resolve baseUrl-only imports (e.g. "utils/foo") before dismissing as bare specifiers
- Replace naive regex comment stripping with state-aware parser to avoid corrupting strings containing "//"
- Sort tsconfig path patterns by specificity (longest first) to match TypeScript behavior
- Remove debug log from graph_builder.py
- Improve E2E test assertions to parse JSON values instead of fragile string checks
- Restore .cgcignore file

Co-Authored-By: Claude Opus 4.6 <[email protected]>
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