greentic-flow-builder 0.1.0

AI-powered Adaptive Card flow builder with visual graph editor and demo runner
Documentation
//! Render pipeline: request → context → handlebars → post-process → Adaptive Card.

pub mod compose;
pub mod context;
pub mod helpers;
pub mod post_process;

use crate::registry::TemplateRegistry;
use crate::template::{ComposeSection, RenderResponse};
use anyhow::{Context, bail};
use serde_json::Value;

pub fn render_preset(
    registry: &TemplateRegistry,
    preset_name: &str,
    theme_name: Option<&str>,
    data: &Value,
) -> anyhow::Result<RenderResponse> {
    let _preset = registry
        .get_preset(preset_name)
        .with_context(|| format!("preset '{}' not found", preset_name))?;
    // Note: _preset prefix avoids unused_variables warning. Kept for future use
    // (e.g. passing preset metadata to post-processing).

    let theme = registry.get_theme(theme_name)?;
    let context = context::build_context(data, &theme);

    let rendered = registry
        .handlebars
        .render(preset_name, &context)
        .with_context(|| format!("handlebars render failed for '{}'", preset_name))?;

    let card = post_process::finalize(&rendered)?;

    Ok(RenderResponse {
        card,
        host_config: theme.host_config.clone(),
        preset: preset_name.to_string(),
        theme: theme.name.clone(),
    })
}

pub fn render_compose(
    registry: &TemplateRegistry,
    sections: &[ComposeSection],
    theme_name: Option<&str>,
) -> anyhow::Result<RenderResponse> {
    if sections.is_empty() {
        bail!("compose mode requires at least one section");
    }
    let theme = registry.get_theme(theme_name)?;
    let card = compose::render_sections(&registry.handlebars, sections, &theme)?;
    Ok(RenderResponse {
        card,
        host_config: theme.host_config.clone(),
        preset: "compose".to_string(),
        theme: theme.name.clone(),
    })
}

pub fn validate_theme_exists(registry: &TemplateRegistry, theme_name: &str) -> anyhow::Result<()> {
    registry.themes.get(theme_name).map(|_| ()).ok_or_else(|| {
        let available = registry.themes.names().join(", ");
        anyhow::anyhow!("theme '{}' not found. Available: {}", theme_name, available)
    })
}