Parser System
Synapses ships with 49+ language parsers built on tree-sitter grammars. Each parser extracts structural nodes and edges from source files.
Parser Interface
All parsers implement a common interface that accepts a file path and source bytes, and returns:
- Nodes — each with a type (function, struct, interface, class, method, etc.), name, file path, line number, and exported flag
- Edges — relationships between nodes (calls, contains, imports, implements, etc.)
This uniform interface means the graph engine is language-agnostic — it only works with nodes and edges.
Parser Registry
The registry maps file extensions to parser implementations:
.go→ Go parser.ts,.tsx→ TypeScript parser.py→ Python parser.rs→ Rust parser- …and so on for all supported languages
When the watcher detects a changed file, it looks up the extension in the registry to find the right parser. Unknown extensions are skipped.
Tree-Sitter Grammars
Each parser uses a tree-sitter grammar to produce a concrete syntax tree (CST). The parser then walks the CST to extract nodes and edges. Tree-sitter provides:
- Accurate parsing even for incomplete or syntactically broken files
- Fast incremental parsing
- Consistent API across all languages
Call Site Resolution
Call resolution happens in two passes:
- During parse — When a parser encounters a function call, it records an unresolved call site in the
call_sitestable with the callee name and context (file, line, receiver type if known). - Post-parse pass — After all files are parsed, a resolution pass matches unresolved call sites to known function nodes by name, package, and receiver type. Resolved calls become edges in the graph.
This two-pass approach handles cross-file calls where the callee might not have been parsed yet when the caller was processed.
Route Heuristic
For web frameworks, parsers detect HTTP route registration patterns (e.g., router.GET("/api/users", handler)) and create route nodes. Framework-specific pattern detection covers:
- Go: net/http, chi, gin, echo, fiber
- Node.js: Express, Fastify
- Python: Flask, FastAPI, Django
Route nodes connect to their handler functions, making it possible to trace from an API endpoint to the code that serves it.
Adding a New Language
To add parser support for a new language:
- Implement the parser interface — Create a new file in
internal/parser/that walks the tree-sitter CST and extracts nodes and edges. - Add the tree-sitter grammar — Include the grammar dependency so tree-sitter can parse the language.
- Register in the registry — Map the file extension(s) to your new parser.
- Add tests — Write test cases with sample source files and verify the extracted nodes and edges are correct.
- Handle call sites — Implement call site extraction so function calls can be resolved to edges in the post-parse pass.