Skip to content

Commit 57200df

Browse files
feat: resolve tsconfig/jsconfig path aliases in dependency graph (#40) (#71)
Add TsconfigResolver that discovers tsconfig.json/jsconfig.json files, resolves extends chains, and maps path aliases (e.g. @/* -> src/*) to real files during graph construction. Non-relative TS/JS imports that match a path alias now create proper internal edges instead of phantom external: nodes. Fixes broken dependency graph, PageRank, dead code detection, and change propagation for any TS/JS project using path aliases.
1 parent c92cb80 commit 57200df

6 files changed

Lines changed: 1060 additions & 5 deletions

File tree

packages/core/src/repowise/core/ingestion/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
)
2626
from .parser import LANGUAGE_CONFIGS, ASTParser, LanguageConfig, parse_file
2727
from .traverser import FileTraverser, TraversalStats
28+
from .tsconfig_resolver import TsconfigResolver
2829

2930
__all__ = [
3031
# Models
@@ -42,6 +43,7 @@
4243
"TraversalStats",
4344
# Graph
4445
"GraphBuilder",
46+
"TsconfigResolver",
4547
"Import",
4648
"LanguageConfig",
4749
"PackageInfo",

packages/core/src/repowise/core/ingestion/graph.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ def __init__(self, repo_path: Path | str | None = None) -> None:
120120
self._built = False
121121
self._repo_path: Path | None = Path(repo_path) if repo_path else None
122122
self._compile_commands_cache: dict[str, dict] | None = None
123+
self._tsconfig_resolver: Any | None = None # TsconfigResolver (lazy import)
124+
125+
def set_tsconfig_resolver(self, resolver: Any) -> None:
126+
"""Attach a :class:`TsconfigResolver` for TS/JS path-alias resolution."""
127+
self._tsconfig_resolver = resolver
123128

124129
# ------------------------------------------------------------------
125130
# Building
@@ -350,7 +355,9 @@ def _load_compile_commands(self) -> dict[str, dict] | None:
350355
)
351356
return self._compile_commands_cache
352357
# No valid entries — try next candidate
353-
log.debug("compile_commands.json had no resolvable entries", path=str(candidate))
358+
log.debug(
359+
"compile_commands.json had no resolvable entries", path=str(candidate)
360+
)
354361
except Exception as exc:
355362
log.debug("Failed to load compile_commands.json", error=str(exc))
356363
return None
@@ -510,7 +517,18 @@ def _resolve_import(
510517
)
511518
if candidate in path_set:
512519
return candidate
513-
# External npm package
520+
return None
521+
522+
# Non-relative: try tsconfig path-alias resolution first.
523+
if self._tsconfig_resolver is not None:
524+
importer_abs = (
525+
str(self._repo_path / importer_path) if self._repo_path else importer_path
526+
)
527+
alias_resolved = self._tsconfig_resolver.resolve(module_path, importer_abs)
528+
if alias_resolved is not None:
529+
return alias_resolved
530+
531+
# Fallback: external npm package.
514532
external_key = f"external:{module_path}"
515533
if external_key not in self._graph.nodes:
516534
self._graph.add_node(

0 commit comments

Comments
 (0)