fallow-cli 3.4.2

CLI for fallow, codebase intelligence for TypeScript and JavaScript
Documentation
use std::path::PathBuf;
use std::process::ExitCode;

use fallow_config::{OutputFormat, ProductionAnalysis, ProductionConfig};

use super::Cli;
use crate::cli_format::bool_from_env;
use crate::error::emit_error;

#[derive(Clone, Copy)]
pub struct ProductionModes {
    pub dead_code: bool,
    pub health: bool,
    pub dupes: bool,
}

impl ProductionModes {
    pub const fn for_analysis(self, analysis: ProductionAnalysis) -> bool {
        match analysis {
            ProductionAnalysis::DeadCode => self.dead_code,
            ProductionAnalysis::Health => self.health,
            ProductionAnalysis::Dupes => self.dupes,
        }
    }
}

fn load_config_production(
    root: &std::path::Path,
    config_path: Option<&PathBuf>,
    output: OutputFormat,
    allow_remote_extends: bool,
) -> Result<ProductionConfig, ExitCode> {
    let load_options = fallow_config::ConfigLoadOptions {
        allow_remote_extends,
    };
    let loaded = if let Some(path) = config_path {
        fallow_config::FallowConfig::load_with_options(path, load_options)
            .map(Some)
            .map_err(|e| {
                emit_error(
                    &format!("failed to load config '{}': {e}", path.display()),
                    2,
                    output,
                )
            })?
    } else {
        fallow_config::FallowConfig::find_and_load_with_options(root, load_options)
            .map(|found| found.map(|(config, _)| config))
            .map_err(|e| emit_error(&e, 2, output))?
    };

    Ok(match loaded {
        Some(config) => config.production,
        None => ProductionConfig::default(),
    })
}

pub fn resolve_production_modes(
    cli: &Cli,
    root: &std::path::Path,
    output: OutputFormat,
    production_dead_code: bool,
    production_health: bool,
    production_dupes: bool,
) -> Result<ProductionModes, ExitCode> {
    let config =
        load_config_production(root, cli.config.as_ref(), output, cli.allow_remote_extends)?;
    let env_global = bool_from_env("FALLOW_PRODUCTION");

    let resolve_one = |analysis: ProductionAnalysis, cli_specific: bool, env_name: &str| {
        if cli.production || cli_specific {
            true
        } else if cli.no_production {
            false
        } else if let Some(value) = bool_from_env(env_name) {
            value
        } else if let Some(value) = env_global {
            value
        } else {
            config.for_analysis(analysis)
        }
    };

    Ok(ProductionModes {
        dead_code: resolve_one(
            ProductionAnalysis::DeadCode,
            production_dead_code,
            "FALLOW_PRODUCTION_DEAD_CODE",
        ),
        health: resolve_one(
            ProductionAnalysis::Health,
            production_health,
            "FALLOW_PRODUCTION_HEALTH",
        ),
        dupes: resolve_one(
            ProductionAnalysis::Dupes,
            production_dupes,
            "FALLOW_PRODUCTION_DUPES",
        ),
    })
}