llm-tool-macros 0.4.2

Procedural macros for llm-tool (#[llm_tool] attribute)
Documentation
//! Helper logic for `response_file` response struct prediction.
//!
//! When `#[llm_tool(response_file = "path.tmpl.md")]` is used, the macro delegates
//! to `include_template!` from `md-tmpl-macros`. This module predicts
//! what type names `include_template!` will generate so `llm-tool-macros` can
//! generate appropriate `pub use` statements to bring them into scope.

use convert_case::{Case, Casing};
use quote::format_ident;

/// Collect all type names that `include_template!` will generate for the given
/// struct name and frontmatter declarations.
///
/// Returns identifiers for the top-level struct and all nested sub-structs
/// (list item structs, struct field structs, etc.).
pub(crate) fn collect_generated_type_names(
    struct_name: &str,
    declarations: &[md_tmpl::VarDecl],
) -> Vec<syn::Ident> {
    let mut names = vec![format_ident!("{}", struct_name)];
    for decl in declarations {
        collect_nested_names(struct_name, &decl.name, &decl.var_type, &mut names);
    }
    names
}

/// Recursively collect nested type names from compound `VarType` fields.
fn collect_nested_names(
    parent: &str,
    field: &str,
    ty: &md_tmpl::VarType,
    names: &mut Vec<syn::Ident>,
) {
    use md_tmpl::VarType;
    match ty {
        VarType::List(fields)
            if !fields.is_empty() && (fields.len() != 1 || !fields[0].name.is_empty()) =>
        {
            let pascal = field.to_case(Case::Pascal);
            let item_name = format!("{parent}{pascal}Item");
            names.push(format_ident!("{}", item_name));
            for f in fields {
                collect_nested_names(&item_name, &f.name, &f.var_type, names);
            }
        }
        VarType::Struct(fields) if !fields.is_empty() => {
            let pascal = field.to_case(Case::Pascal);
            let nested_name = format!("{parent}{pascal}");
            names.push(format_ident!("{}", nested_name));
            for f in fields {
                collect_nested_names(&nested_name, &f.name, &f.var_type, names);
            }
        }
        VarType::Option(inner) => {
            collect_nested_names(parent, field, inner, names);
        }
        _ => {}
    }
}