m2s2-cli 0.1.28

CLI for scaffolding M²S² design system projects
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::fs;

#[derive(Serialize, Deserialize, Default, Debug)]
pub struct M2S2Config {
    pub framework: Option<String>,
    pub api_framework: Option<String>,
    pub project_type: Option<String>,
    pub runtime: Option<String>,
}

impl M2S2Config {
    pub fn load() -> Option<Self> {
        let raw = fs::read_to_string(".m2s2.json").ok()?;
        serde_json::from_str(&raw).ok()
    }

    pub fn save(&self) -> Result<()> {
        let json = serde_json::to_string_pretty(self)?;
        fs::write(".m2s2.json", json + "\n")?;
        Ok(())
    }
}

/// Resolve frontend framework from CLI flag → `.m2s2.json` → `package.json`.
pub fn resolve_framework(explicit: Option<String>) -> Result<String> {
    if let Some(f) = explicit {
        return Ok(f);
    }
    detect_framework()
        .context("could not detect framework — run from your project root or pass --framework")
}

/// Project type defaults to "frontend" for backward compatibility.
pub fn resolve_project_type() -> String {
    M2S2Config::load()
        .and_then(|c| c.project_type)
        .unwrap_or_else(|| "frontend".into())
}

pub fn resolve_api_framework() -> Option<String> {
    M2S2Config::load().and_then(|c| c.api_framework)
}

pub fn resolve_runtime() -> Option<String> {
    M2S2Config::load().and_then(|c| c.runtime)
}

pub fn detect_framework() -> Option<String> {
    if let Some(cfg) = M2S2Config::load().filter(|c| c.framework.is_some()) {
        return cfg.framework;
    }
    let raw = fs::read_to_string("package.json").ok()?;
    let pkg: serde_json::Value = serde_json::from_str(&raw).ok()?;
    let deps = pkg.get("dependencies")?;
    if deps.get("@m2s2/react-lib").is_some() {
        Some("react".into())
    } else if deps.get("@m2s2/ng-lib").is_some() {
        Some("angular".into())
    } else if deps.get("@m2s2/vue-lib").is_some() {
        Some("vue".into())
    } else {
        None
    }
}