ggen-cli-lib 26.7.3

CLI interface for ggen
Documentation
{#- Domain layer template -- pure business logic scaffolding ONLY
    This generates stubs that the developer fills in.
    It is intentionally minimal: no business logic is ever generated.

    Expected variables:
    - interface_name: string (e.g., "ggen")
    - commands: array of { name, summary, description, subcommands[], special, options[] }
      - subcommands[]: { name, summary, about, options[], positional_arguments[] }
        - options[]: { name, long_name, type, summary, required, global }
        - positional_arguments[]: { name, summary, required }
      - options[]: { name, long_name, type, summary, required, global } (for special/root commands)
    - global_options: array of { name, long_name, type, summary, global }
-#}
//! Domain Layer -- Pure Business Logic
//!
//! Implement your domain logic here. Each function is a stub.
//! The CLI layer delegates here after argument validation.
//!
//! Rules:
//! - No CLI types (no clap imports)
//! - No I/O in this file (use separate infrastructure modules)
//! - Pure functions that return Result<impl Serialize, DomainError>
//! - Test with real collaborators (Chicago TDD)

use crate::error::DomainError;
use serde::Serialize;

{%- for command in commands %}
{%- if command.subcommands and command.subcommands | length > 0 %}

pub mod {{ command.name | snake }} {
    use super::*;

    {%- for subcmd in command.subcommands %}
    /// {{ subcmd.summary }}
    {%- if subcmd.about %}
    ///
    /// {{ subcmd.about }}
    {%- endif %}
    pub fn {{ subcmd.name | snake }}(
        {%- for arg in subcmd.positional_arguments %}
        {%- if arg.required %}
        _{{ arg.name | snake }}: String,
        {%- else %}
        _{{ arg.name | snake }}: Option<String>,
        {%- endif %}
        {%- endfor %}
        {%- for opt in subcmd.options %}
        {%- if opt.global %}{% continue %}{% endif %}
        {%- if opt.type == "flag" %}
        _{{ opt.name | replace(from="-", to="_") }}: bool,
        {%- elif opt.required %}
        _{{ opt.name | replace(from="-", to="_") }}: String,
        {%- else %}
        _{{ opt.name | replace(from="-", to="_") }}: Option<String>,
        {%- endif %}
        {%- endfor %}
    ) -> Result<impl Serialize, DomainError> {
        Err(DomainError::not_implemented("{{ command.name | snake }}::{{ subcmd.name | snake }}"))
    }

    {%- endfor %}
}

{%- elif command.special %}

pub mod {{ command.name | snake }} {
    use super::*;

    /// {{ command.summary }}
    pub fn run(
        {%- for opt in command.options %}
        {%- if opt.type == "flag" %}
        _{{ opt.name | replace(from="-", to="_") }}: Option<bool>,
        {%- else %}
        _{{ opt.name | replace(from="-", to="_") }}: Option<String>,
        {%- endif %}
        {%- if not loop.last %}, {% endif %}
        {%- endfor %}
    ) -> Result<impl Serialize, DomainError> {
        Err(DomainError::not_implemented("{{ command.name | snake }}::run"))
    }
}

{%- endif %}
{%- endfor %}