Skip to content

fix(tsconfig): resolve non-relative imports against baseUrl - #1098

Merged
1 commit merged into
tirth8205:stagingfrom
Balghisa12:fix/tsconfig-baseurl-resolution
Nov 6, 2026
Merged

1 commit merged into
tirth8205:stagingfrom
Balghisa12:fix/tsconfig-baseurl-resolution

Conversation

@Balghisa12

Copy link
Copy Markdown
Contributor

Pull Request

Linked issue

No existing issue. Found while evaluating the graph on a NestJS monorepo. Related to #1030 (workspace packages), which is a separate gap.

What & why

TsconfigResolver.resolve_alias returned None whenever compilerOptions.paths was empty, so a tsconfig that sets only baseUrl resolved no non-relative import. tsc resolves such specifiers against baseUrl, both without paths and when no paths pattern matches. The resolver now does the same, after trying paths. docs/FEATURES.md already lists paths/baseUrl resolution, so no docs change.

On a NestJS service of 1,181 TypeScript files that imports src/... with "baseUrl": "./" and no paths:

  • unresolved src/... import edges: 1,849 → 44 (the 44 point at generated clients absent from the checkout);
  • the import edges are identical to declaring "paths": { "src/*": ["src/*"] }, which takes importers_of for one service from 14 to 35 of its 35 importers and the real callers callers_of finds for its method from 4 to all 6.

How it was tested

uv run pytest tests/test_tsconfig_resolver.py -q   # on staging: 2 failed (the two baseUrl cases); with the fix: 15 passed
uv run pytest tests/ --tb=short -q                 # 4272 passed, 850 skipped, 2 xfailed, 2 xpassed
uv run --extra dev ruff check code_review_graph/   # All checks passed
uv run --extra dev mypy code_review_graph/ --ignore-missing-imports --no-strict-optional  # no issues in 77 files
uvx bandit -q -r code_review_graph/tsconfig_resolver.py -c pyproject.toml                # clean

tsc 5.8.3 with --traceResolution on two fixtures, baseUrl alone and baseUrl with a non-matching paths entry, resolves src/lib/util through baseUrl in both.

Checklist

  • Tests added for new functionality
  • All tests pass: uv run pytest tests/ --tb=short -q
  • Linting passes: uv run ruff check code_review_graph/
  • Type checking passes: uv run mypy code_review_graph/ --ignore-missing-imports --no-strict-optional
  • Lines are at most 100 characters
  • Docs updated where behavior changed (README, docs/, docstrings)

🤖 Generated with Claude Code

resolve_alias returned None whenever compilerOptions.paths was empty, so a
tsconfig that sets only baseUrl resolved no non-relative import. tsc resolves
such specifiers against baseUrl, both without paths and when no paths pattern
matches; the resolver now does the same, after trying paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tirth8205

Copy link
Copy Markdown
Owner

Thank you for this PR. I ran the tsconfig tests and compared the results with tsc 5.9.3. The baseUrl-only case works well now.

Before I can merge it, please fix these:

  1. The baseUrl fallback also runs after a paths pattern has matched. tsc stops at a matched pattern and never tries baseUrl. See code_review_graph/tsconfig_resolver.py:67. Example: baseUrl "." and paths {"": ["types/"]}, with a local config/index.ts. Then import "config" links to config/index.ts. tsc picks node_modules/config instead. A small fix: return None when any paths pattern matched the import.

Note: PR #1111 changes the same function. After one is merged, the other will need an update.

After you push the fix, I will test it again.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The baseUrl fallback mishandles empty values and inherited configurations and incorrectly retries matched paths whose targets are missing, leaving valid imports unresolved or creating incorrect import edges.

3 open issues
What changed in this PR

This PR adds baseUrl fallback resolution for TypeScript and JavaScript imports, helping the graph link non-relative imports to files rather than retain bare specifiers. Workspace-package resolution from #1030 remains separate.

Changes:

  • Probe imports against baseUrl after attempting paths resolution.
  • Add tests for baseUrl-only configurations, unmatched aliases, and unresolved imports.
  • Document the fix and observed graph improvements in the changelog.
File Description
tests/​test_tsconfig_resolver.py Adds four baseUrl resolution regression tests.
code_review_graph/​tsconfig_resolver.py Implements the baseUrl fallback and updates its documentation.
CHANGELOG.md Records the resolution fix and its impact.

Review effort: Balanced

if resolved:
return resolved

# Like tsc, resolve a specifier no paths entry resolved against baseUrl.
return resolved

# Like tsc, resolve a specifier no paths entry resolved against baseUrl.
if base_url:

# Like tsc, resolve a specifier no paths entry resolved against baseUrl.
if base_url:
found = _probe_path((base_dir / import_str).resolve())
@tirth8205 tirth8205 closed this pull request by merging all changes into tirth8205:staging in 0160eb0 Nov 6, 2026
gowrishacv pushed a commit to gowrishacv/code-review-graph that referenced this pull request Nov 6, 2026
… and in bounds (review of tirth8205#1098)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gowrishacv pushed a commit to gowrishacv/code-review-graph that referenced this pull request Nov 6, 2026
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.

3 participants