motto 0.3.2

Compiler-as-a-Service: Turn Rust schema.rs into multi-platform SDK toolkits
Documentation
//! Backend Emitters Module
//!
//! Generates platform-specific SDK code from the IR manifest.
//! Implements Single-Version Policy with 1-byte version header.

#[cfg(feature = "emitter-kotlin")]
pub mod kotlin;
pub mod rust;
#[cfg(feature = "emitter-swift")]
pub mod swift;
#[cfg(feature = "emitter-typescript")]
pub mod typescript;
#[cfg(feature = "emitter-unity")]
pub mod unity;

use crate::ir::manifest::SchemaManifest;
use std::path::PathBuf;

/// Configuration for emitters
#[derive(Debug, Clone)]
pub struct EmitterConfig {
    /// Output directory
    pub output_dir: PathBuf,
    /// Generate WASM bindings
    pub wasm_bindings: bool,
    /// Generate native addon bindings (napi-rs)
    pub native_bindings: bool,
    /// The schema manifest to emit
    pub manifest: SchemaManifest,
}

/// Trait for all backend emitters
pub trait Emitter {
    /// Target platform name
    fn platform(&self) -> &'static str;

    /// File extension for generated files
    fn extension(&self) -> &'static str;

    /// Generate SDK code
    fn emit(&self, config: &EmitterConfig) -> anyhow::Result<Vec<GeneratedFile>>;
}

/// A generated file
#[derive(Debug, Clone)]
pub struct GeneratedFile {
    /// Relative path from output directory
    pub path: PathBuf,
    /// File content
    pub content: String,
}

/// Protocol version byte constant for generated code
pub const VERSION_BYTE_COMMENT: &str = r#"
// ============================================================================
// MOTTO GENERATED CODE - DO NOT EDIT
// 
// This file was generated by motto from a Rust schema definition.
// Any changes will be overwritten on next generation.
//
// Protocol Version Byte: {VERSION_BYTE}
// Schema Fingerprint: {FINGERPRINT}
// Generated At: {TIMESTAMP}
// ============================================================================
"#;

/// Common utility functions for emitters
pub mod utils {
    use heck::{ToLowerCamelCase, ToPascalCase, ToSnakeCase, ToUpperCamelCase};

    /// Convert a Rust type name to the target language's convention
    pub fn to_pascal_case(s: &str) -> String {
        s.to_pascal_case()
    }

    pub fn to_camel_case(s: &str) -> String {
        s.to_lower_camel_case()
    }

    pub fn to_snake_case(s: &str) -> String {
        s.to_snake_case()
    }

    pub fn to_upper_camel_case(s: &str) -> String {
        s.to_upper_camel_case()
    }

    /// Escape reserved words in various languages
    pub fn escape_reserved(name: &str, reserved: &[&str]) -> String {
        if reserved.contains(&name) {
            format!("{}_", name)
        } else {
            name.to_string()
        }
    }

    /// Generate file header with version info
    pub fn generate_header(version_byte: u8, fingerprint: &str, timestamp: &str) -> String {
        super::VERSION_BYTE_COMMENT
            .replace("{VERSION_BYTE}", &format!("0x{:02X}", version_byte))
            .replace("{FINGERPRINT}", fingerprint)
            .replace("{TIMESTAMP}", timestamp)
    }
}