Skip to main content

treesitter_types_macros/
lib.rs

1//! Proc-macro companion for [`treesitter-types`](https://docs.rs/treesitter-types).
2//!
3//! Provides the [`generate_types!`] macro, which reads a
4//! [Tree-sitter](https://tree-sitter.github.io/tree-sitter/) `node-types.json` file at compile
5//! time and expands it into strongly-typed Rust AST structs and enums.
6//!
7//! If you don't need compile-time generation, consider using one of the pre-generated language
8//! crates (e.g. [`treesitter-types-go`](https://docs.rs/treesitter-types-go)) instead.
9
10use proc_macro::TokenStream;
11
12/// Generates typed AST structs and enums from a tree-sitter `node-types.json` file.
13///
14/// The path is resolved relative to the crate root (same semantics as `include_str!`).
15///
16/// # Example
17///
18/// ```ignore
19/// treesitter_types_macros::generate_types!("src/node-types.json");
20/// ```
21#[proc_macro]
22pub fn generate_types(input: TokenStream) -> TokenStream {
23    let input: proc_macro2::TokenStream = input.into();
24    match generate_types_impl(input) {
25        Ok(tokens) => tokens.into(),
26        Err(err) => err.into_compile_error().into(),
27    }
28}
29
30fn generate_types_impl(
31    input: proc_macro2::TokenStream,
32) -> Result<proc_macro2::TokenStream, syn::Error> {
33    let lit: syn::LitStr = syn::parse2(input)?;
34    let rel_path = lit.value();
35
36    // Resolve relative to CARGO_MANIFEST_DIR (the calling crate's root)
37    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
38        .map_err(|_| syn::Error::new(lit.span(), "CARGO_MANIFEST_DIR not set"))?;
39    let full_path = std::path::Path::new(&manifest_dir).join(&rel_path);
40
41    let json = std::fs::read_to_string(&full_path).map_err(|e| {
42        syn::Error::new(
43            lit.span(),
44            format!("failed to read {}: {e}", full_path.display()),
45        )
46    })?;
47
48    treesitter_types::codegen::generate(&json)
49        .map_err(|e| syn::Error::new(lit.span(), format!("codegen failed: {e}")))
50}