morph-cli 0.1.0

AST-based codebase migration and codemod tool for JavaScript and TypeScript projects.
Documentation
use std::fs;
use std::path::{Path, PathBuf};
use anyhow::{Result, Context};
use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct MigrationManifest {
    pub profile_name: Option<String>,
    pub recipes: Vec<String>,
    pub target_path: PathBuf,
    pub write: bool,
    pub dry_run: bool,
    pub allow_risky: bool,
    pub strict: bool,
    pub autofix: bool,
    pub review: bool,
    pub verbose: bool,
    pub summary_only: bool,
}

impl MigrationManifest {
    pub fn load_from_file(path: &Path) -> Result<Self> {
        let content = fs::read_to_string(path)
            .with_context(|| format!("Failed to read manifest file: {}", path.display()))?;
        
        let ext = path.extension().and_then(|s| s.to_str()).unwrap_or("");
        if ext == "json" {
            serde_json::from_str(&content)
                .with_context(|| "Failed to parse JSON manifest")
        } else {
            toml::from_str(&content)
                .with_context(|| "Failed to parse TOML manifest")
        }
    }

    pub fn save_to_file(&self, path: &Path) -> Result<()> {
        let ext = path.extension().and_then(|s| s.to_str()).unwrap_or("");
        let content = if ext == "json" {
            serde_json::to_string_pretty(self)
                .with_context(|| "Failed to serialize JSON manifest")?
        } else {
            toml::to_string_pretty(self)
                .with_context(|| "Failed to serialize TOML manifest")?
        };

        if let Some(parent) = path.parent() {
            fs::create_dir_all(parent)?;
        }
        fs::write(path, content)
            .with_context(|| format!("Failed to write manifest file: {}", path.display()))?;
        Ok(())
    }
}