slave 0.2.0

Laravel-inspired CLI for Rust web apps: scaffold Axum projects with built-in auth, users, roles and Turso migrations
//! Command-line interface definition.

use std::path::PathBuf;

use clap::{Args, Parser, Subcommand};

/// A Laravel-inspired web framework for Rust.
#[derive(Debug, Parser)]
#[command(name = "slave", version, about, long_about = None)]
#[command(propagate_version = true, arg_required_else_help = true)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Command,
}

#[derive(Debug, Subcommand)]
pub enum Command {
    /// Create a new slave application
    New(NewArgs),

    /// Create a new model in a domain module
    ///
    /// Writes src/modules/<module>/model.rs. The module defaults to the model
    /// name in snake_case (`BlogPost` → `blog_post`) and is created if missing.
    #[command(name = "make:model")]
    MakeModel(MakeArgs),

    /// Create a new controller in a domain module
    ///
    /// Writes src/modules/<module>/controller.rs. The module defaults to the
    /// controller name without its `Controller` suffix, in snake_case
    /// (`BlogPostController` → `blog_post`). New modules also get a routes.rs
    /// that is registered in src/modules/mod.rs.
    #[command(name = "make:controller")]
    MakeController(MakeArgs),

    /// Create a new database migration
    ///
    /// Writes database/migrations/<timestamp>_<name>.rs and registers it in
    /// database/migrations/mod.rs. Names like `create_posts_table` start from
    /// a CREATE TABLE template; others start empty and irreversible.
    #[command(name = "make:migration")]
    MakeMigration {
        /// Migration name in snake_case, e.g. `create_users_table`
        name: String,
    },

    /// Run all pending database migrations as a new batch
    Migrate,

    /// Show which migrations have run and which are pending
    #[command(name = "migrate:status")]
    MigrateStatus,

    /// Roll back the most recent batch of migrations
    ///
    /// Refuses, changing nothing, if any migration in the batch is
    /// irreversible (its `down()` returns `None`).
    #[command(name = "migrate:rollback")]
    MigrateRollback,

    /// Serve the application on the development server
    Serve(ServeArgs),
}

#[derive(Debug, Args)]
pub struct NewArgs {
    /// Name of the application (also used as the directory and package name)
    pub name: String,

    /// Depend on a local checkout of slave-framework instead of crates.io
    #[arg(long, value_name = "PATH")]
    pub framework_path: Option<PathBuf>,
}

#[derive(Debug, Args)]
pub struct MakeArgs {
    /// Type name in PascalCase, e.g. `User` or `UserController`
    pub name: String,

    /// Domain module to generate into, in snake_case (default: derived from the name)
    #[arg(short, long, visible_alias = "domain", value_name = "MODULE")]
    pub module: Option<String>,

    /// Overwrite the file with a fresh template if it already exists
    #[arg(short, long)]
    pub force: bool,
}

#[derive(Debug, Args)]
pub struct ServeArgs {
    /// Host address to bind to [default: APP_HOST from the environment or .env, else 127.0.0.1]
    #[arg(long)]
    pub host: Option<String>,

    /// Port to listen on [default: APP_PORT from the environment or .env, else 3000]
    #[arg(short, long)]
    pub port: Option<u16>,

    /// Build and run the application in release mode
    #[arg(long)]
    pub release: bool,
}