use std::process::ExitCode;
use clap::Parser;
use clap::ValueEnum;
use schemars::schema_for;
use mago_reporting::baseline::Baseline;
use crate::config::Configuration;
use crate::config::analyzer::AnalyzerConfiguration;
use crate::config::formatter::FormatterConfiguration;
use crate::config::linter::LinterConfiguration;
use crate::config::parser::ParserConfiguration;
use crate::config::source::SourceConfiguration;
use crate::consts::CURRENT_DIR;
use crate::error::Error;
#[derive(ValueEnum, Debug, Clone, Copy)]
#[value(rename_all = "kebab-case")]
enum ConfigSection {
Source,
Linter,
Formatter,
Analyzer,
Parser,
Baseline,
}
#[derive(Parser, Debug)]
#[command(
name = "config",
about = "Display the current configuration that Mago is using.",
long_about = "Display the final, merged configuration that Mago is using for this project.\n\n\
This command is invaluable for debugging your setup. It shows you the\n\
complete configuration that results from combining:\n\
• Built-in default values\n\
• Global configuration from ~/.mago.toml or $XDG_CONFIG_HOME/mago.toml\n\
• Project configuration from ./mago.toml\n\
• Environment variables (MAGO_*)\n\
• Command-line overrides\n\n\
Use --show to focus on a specific section, or --default to see\n\
what the defaults would be without any configuration files."
)]
pub struct ConfigCommand {
#[arg(long, value_enum)]
show: Option<ConfigSection>,
#[arg(long, default_value_t = false)]
default: bool,
#[arg(long, default_value_t = false)]
schema: bool,
}
impl ConfigCommand {
pub fn execute(self, configuration: Configuration) -> Result<ExitCode, Error> {
let json = if self.schema {
if let Some(section) = self.show {
match section {
ConfigSection::Source => {
let schema = schema_for!(SourceConfiguration);
serde_json::to_string_pretty(&schema)?
}
ConfigSection::Linter => {
let schema = schema_for!(LinterConfiguration);
serde_json::to_string_pretty(&schema)?
}
ConfigSection::Formatter => {
let schema = schema_for!(FormatterConfiguration);
serde_json::to_string_pretty(&schema)?
}
ConfigSection::Analyzer => {
let schema = schema_for!(AnalyzerConfiguration);
serde_json::to_string_pretty(&schema)?
}
ConfigSection::Parser => {
let schema = schema_for!(ParserConfiguration);
serde_json::to_string_pretty(&schema)?
}
ConfigSection::Baseline => {
let schema = schema_for!(Baseline);
serde_json::to_string_pretty(&schema)?
}
}
} else {
let schema = schema_for!(Configuration);
serde_json::to_string_pretty(&schema)?
}
} else if let Some(section) = self.show {
match section {
ConfigSection::Source => {
if self.default {
serde_json::to_string_pretty(&SourceConfiguration::from_workspace(CURRENT_DIR.clone()))?
} else {
serde_json::to_string_pretty(&configuration.source)?
}
}
ConfigSection::Linter => {
if self.default {
serde_json::to_string_pretty(&LinterConfiguration::default())?
} else {
serde_json::to_string_pretty(
&configuration.linter.to_filtered_value(configuration.php_version),
)?
}
}
ConfigSection::Formatter => {
if self.default {
serde_json::to_string_pretty(&FormatterConfiguration::default().to_value())?
} else {
serde_json::to_string_pretty(&configuration.formatter.to_value())?
}
}
ConfigSection::Analyzer => {
if self.default {
serde_json::to_string_pretty(&AnalyzerConfiguration::default())?
} else {
serde_json::to_string_pretty(&configuration.analyzer)?
}
}
ConfigSection::Parser => {
if self.default {
serde_json::to_string_pretty(&ParserConfiguration::default())?
} else {
serde_json::to_string_pretty(&configuration.parser)?
}
}
ConfigSection::Baseline => {
tracing::error!("Baseline is not a configuration section.");
tracing::error!("Use `--schema --show baseline` to get the baseline file schema.");
return Ok(ExitCode::FAILURE);
}
}
} else if self.default {
serde_json::to_string_pretty(&Configuration::from_workspace(CURRENT_DIR.clone()))?
} else {
let filtered = configuration.to_filtered_value();
serde_json::to_string_pretty(&filtered)?
};
println!("{}", json);
Ok(ExitCode::SUCCESS)
}
}