Skip to content

Commit d832021

Browse files
committed
fix: TypeScript dependency analysis -- proper parser, .js->ts resolution, include_paths (OPE-120)
Three stacked bugs causing 0 dependencies for TypeScript repos: 1. Wrong parser: used JS grammar for TS files. JS parser has errors on import type, generics, mapped types. Now uses tree-sitter-typescript (language_typescript for .ts, language_tsx for .tsx). 2. Import resolution: TS imports use .js extension but actual files are .ts on disk (standard with moduleResolution: nodenext). Resolver now strips .js/.jsx before trying .ts/.tsx extensions. Also added .d.ts. 3. No include_paths: build_dependency_graph scanned entire clone dir. Effect-TS subset repos got Python files mixed in. Now accepts include_paths parameter to filter file discovery. Closes OPE-120
1 parent c3288da commit d832021

1 file changed

Lines changed: 18 additions & 7 deletions

File tree

backend/services/dependency_analyzer.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
# Tree-sitter
1010
import tree_sitter_python as tspython
1111
import tree_sitter_javascript as tsjavascript
12+
import tree_sitter_typescript as tstypescript
1213
from tree_sitter import Language, Parser
1314

1415
from services.observability import logger, metrics
@@ -22,7 +23,8 @@ def __init__(self):
2223
self.parsers = {
2324
'python': Parser(Language(tspython.language())),
2425
'javascript': Parser(Language(tsjavascript.language())),
25-
'typescript': Parser(Language(tsjavascript.language())),
26+
'typescript': Parser(Language(tstypescript.language_typescript())),
27+
'tsx': Parser(Language(tstypescript.language_tsx())),
2628
}
2729
logger.info("DependencyAnalyzer initialized")
2830

@@ -34,7 +36,7 @@ def _detect_language(self, file_path: str) -> str:
3436
'.js': 'javascript',
3537
'.jsx': 'javascript',
3638
'.ts': 'typescript',
37-
'.tsx': 'typescript',
39+
'.tsx': 'tsx',
3840
}
3941
return lang_map.get(ext, 'unknown')
4042

@@ -122,8 +124,8 @@ def analyze_file_dependencies(self, file_path: str) -> Dict:
122124
logger.error("Error analyzing file", file_path=file_path, error=str(e))
123125
return {"file": str(file_path), "imports": [], "language": language, "error": str(e)}
124126

125-
def build_dependency_graph(self, repo_path: str) -> Dict:
126-
"""Build complete dependency graph for repository"""
127+
def build_dependency_graph(self, repo_path: str, include_paths: List[str] = None) -> Dict:
128+
"""Build dependency graph. If include_paths set, only analyze those dirs."""
127129
repo_path = Path(repo_path)
128130

129131
# Discover code files
@@ -136,8 +138,13 @@ def build_dependency_graph(self, repo_path: str) -> Dict:
136138
continue
137139
if any(skip in file_path.parts for skip in skip_dirs):
138140
continue
139-
if file_path.suffix in extensions:
140-
code_files.append(file_path)
141+
if file_path.suffix not in extensions:
142+
continue
143+
if include_paths:
144+
relative = str(file_path.relative_to(repo_path))
145+
if not any(relative.startswith(p) for p in include_paths):
146+
continue
147+
code_files.append(file_path)
141148

142149
logger.info("Building dependency graph", file_count=len(code_files))
143150

@@ -236,6 +243,10 @@ def _resolve_import_to_file(
236243
source_path = Path(source_file)
237244
source_dir = source_path.parent
238245

246+
# TS imports use .js extension but actual file is .ts on disk
247+
if import_path.endswith('.js') or import_path.endswith('.jsx'):
248+
import_path = re.sub(r'\.(jsx?)$', '', import_path)
249+
239250
# Relative imports
240251
if import_path.startswith('.'):
241252
clean_import = import_path.lstrip('./')
@@ -250,7 +261,7 @@ def _resolve_import_to_file(
250261
else:
251262
potential_base = source_dir / clean_import
252263

253-
extensions = ['', '.ts', '.tsx', '.js', '.jsx', '.py']
264+
extensions = ['', '.ts', '.tsx', '.d.ts', '.js', '.jsx', '.py']
254265

255266
for ext in extensions:
256267
# Build the potential path

0 commit comments

Comments
 (0)