Skip to content

Add a Rust frontend

StubHelp wanted

This page is a stub. A Rust frontend does not exist yet; this describes the form it would take and where to begin. To contribute one, open an issue first to coordinate with the maintainers.

A frontend is an SDK that consumes the canonical analysis JSON the codeanalyzer backends emit and exposes an analysis API over it. The Python SDK is the reference implementation. Because the backends perform all language analysis, a second frontend supports every existing backend without additional work: a Rust SDK would analyze Python, Java, and (once available) Go from the outset.

Rust is well suited to this role: strong types for the schema, serde for efficient deserialization, and petgraph for call-graph queries that map onto the SDK’s networkx graphs.

flowchart LR
    CA["codeanalyzer-* backends"] -->|canonical JSON| RS["Rust SDK (cldk-rs)"]
    RS --> M["serde models"]
    RS --> F["Analysis API"]
    RS --> G["petgraph call graph"]

Mirror the Python SDK’s structure, module by module. None of this is built yet; treat each step as a tracking item.

  1. Model the canonical schema with serde. Translate the backend JSON entities (JApplication/JType/JCallable, PyModule/PyClass/PyCallable, …) into Rust structs with #[derive(Deserialize)]. This is the Rust analogue of cldk/models/*. Start with one language (Java) to prove the round-trip.

  2. Define the analysis trait. A LanguageAnalysis trait with the core methods (get_symbol_table, get_classes, get_method, get_call_graph, get_callers, get_callees) so every language implementation shares one surface, matching the Python analysis APIs.

  3. Build the call graph with petgraph. Deserialize the backend’s call-graph edges into a petgraph::DiGraph. Reachability is then petgraph::algo::has_path_connecting, the Rust counterpart of networkx.has_path.

  4. Invoke the backends. Reuse the same CLI contract the Python SDK uses to invoke codeanalyzer-* (input project directory, output JSON, analysis level). See the backend’s CLI interface; the wire format is shared, so this step is primarily process management and JSON parsing.

  5. Register languages with per-language factories. Mirror the current cldk/core.py, which no longer dispatches on a language enum inside one analysis() method. Instead it exposes a per-language factory — CLDK.java(...), CLDK.python(...), CLDK.typescript(...) — and each facade then selects its backend by the type of a backend= config object (CodeAnalyzerConfig for the in-process codeanalyzer vs Neo4jConnectionConfig for the read-only graph). The Rust port should mirror this: per-language constructors like CLDK::java(project_path) (rather than CLDK::new(Language::Java).analysis(...)), with the backend chosen by config type — e.g. an enum or trait object Backend::CodeAnalyzer { cache_dir } vs Backend::Neo4j { uri, .. } that each LanguageAnalysis impl matches on. (Python keeps a deprecated CLDK(language).analysis(...) shim that forwards to the factories; a Rust port need not replicate the shim.)

  6. Validate against the same fixtures. Run it against Apache Commons CLI and assert the same facts the Python test suite asserts: same project, same results, different host language.