Skip to content

Commit 76462fd

Browse files
committed
fix: cross-platform CI -- tree-sitter API compat, pin >=0.24, Windows path separators in tests
1 parent 3363d6b commit 76462fd

6 files changed

Lines changed: 50 additions & 21 deletions

File tree

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ These files have the most dependents -- understand them before editing:
3636

3737
- `saar/models.py` (14 dependents)
3838
- `saar/formatters/_tribal.py` (4 dependents)
39-
- `saar/formatters/agents_md.py` (3 dependents)
4039
- `saar/formatters/claude_md.py` (3 dependents)
40+
- `saar/formatters/agents_md.py` (3 dependents)
4141
- `saar/cli.py` (3 dependents)
4242
- `saar/interview.py` (3 dependents)
4343
- `saar/dependency_analyzer.py` (2 dependents)

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ classifiers = [
2929
"Topic :: Software Development :: Code Generators",
3030
]
3131
dependencies = [
32-
"tree-sitter>=0.23.0",
33-
"tree-sitter-python>=0.23.0",
34-
"tree-sitter-javascript>=0.23.0",
32+
"tree-sitter>=0.24.0,<0.26.0",
33+
"tree-sitter-python>=0.23.0,<0.26.0",
34+
"tree-sitter-javascript>=0.23.0,<0.26.0",
3535
"typer>=0.12.0",
3636
"rich>=13.0.0",
3737
"questionary>=2.0.0",

saar/dependency_analyzer.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,20 @@ class DependencyAnalyzer:
4949
}
5050

5151
def __init__(self) -> None:
52-
self.parsers = {
53-
"python": Parser(Language(tspython.language())),
54-
"javascript": Parser(Language(tsjavascript.language())),
55-
"typescript": Parser(Language(tsjavascript.language())),
56-
}
52+
try:
53+
self.parsers = {
54+
"python": Parser(Language(tspython.language())),
55+
"javascript": Parser(Language(tsjavascript.language())),
56+
"typescript": Parser(Language(tsjavascript.language())),
57+
}
58+
except TypeError:
59+
py_lang = Language(tspython.language())
60+
js_lang = Language(tsjavascript.language())
61+
self.parsers = {}
62+
for name, lang in [("python", py_lang), ("javascript", js_lang), ("typescript", js_lang)]:
63+
p = Parser()
64+
p.language = lang
65+
self.parsers[name] = p
5766

5867
def _detect_language(self, file_path: str) -> str:
5968
ext = Path(file_path).suffix.lower()

saar/extractor.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,21 @@ class DNAExtractor:
9090
]
9191

9292
def __init__(self) -> None:
93-
self.parsers = {
94-
"python": Parser(Language(tspython.language())),
95-
"javascript": Parser(Language(tsjavascript.language())),
96-
"typescript": Parser(Language(tsjavascript.language())),
97-
}
93+
try:
94+
self.parsers = {
95+
"python": Parser(Language(tspython.language())),
96+
"javascript": Parser(Language(tsjavascript.language())),
97+
"typescript": Parser(Language(tsjavascript.language())),
98+
}
99+
except TypeError:
100+
# tree-sitter <0.24 uses Parser().set_language() API
101+
py_lang = Language(tspython.language())
102+
js_lang = Language(tsjavascript.language())
103+
self.parsers = {}
104+
for name, lang in [("python", py_lang), ("javascript", js_lang), ("typescript", js_lang)]:
105+
p = Parser()
106+
p.language = lang
107+
self.parsers[name] = p
98108
self._file_cache: Dict[Path, str] = {}
99109
self._stats = {"files_read": 0, "files_skipped": 0, "read_errors": 0}
100110
self._active_skip_dirs = set(self.SKIP_DIRS)

saar/style_analyzer.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,20 @@ class StyleAnalyzer:
4848
}
4949

5050
def __init__(self) -> None:
51-
self.parsers = {
52-
"python": Parser(Language(tspython.language())),
53-
"javascript": Parser(Language(tsjavascript.language())),
54-
"typescript": Parser(Language(tsjavascript.language())),
55-
}
51+
try:
52+
self.parsers = {
53+
"python": Parser(Language(tspython.language())),
54+
"javascript": Parser(Language(tsjavascript.language())),
55+
"typescript": Parser(Language(tsjavascript.language())),
56+
}
57+
except TypeError:
58+
py_lang = Language(tspython.language())
59+
js_lang = Language(tsjavascript.language())
60+
self.parsers = {}
61+
for name, lang in [("python", py_lang), ("javascript", js_lang), ("typescript", js_lang)]:
62+
p = Parser()
63+
p.language = lang
64+
self.parsers[name] = p
5665

5766
def _detect_language(self, file_path: str) -> str:
5867
ext = Path(file_path).suffix.lower()

tests/test_dependency_analyzer.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@ def test_build_graph_returns_dict(self, tmp_repo: Path):
1515
def test_finds_nodes(self, tmp_repo: Path):
1616
result = DependencyAnalyzer().build_graph(str(tmp_repo))
1717
file_ids = [n["id"] for n in result["nodes"]]
18-
assert any("main.py" in f for f in file_ids)
18+
assert any("main.py" in str(Path(f)) for f in file_ids)
1919

2020
def test_resolves_internal_imports(self, tmp_repo: Path):
2121
result = DependencyAnalyzer().build_graph(str(tmp_repo))
2222
# dependencies.py imports from services/user_service.py
2323
edges = result["edges"]
2424
sources = [e["source"] for e in edges]
25-
assert any("dependencies.py" in s for s in sources)
25+
# use Path for cross-platform comparison
26+
assert any(Path(s).name == "dependencies.py" for s in sources)
2627

2728
def test_detects_circular_deps(self, tmp_path: Path):
2829
"""Two files importing each other should be flagged."""

0 commit comments

Comments
 (0)