Add source files: main, lib, cli, error, convert, highlight, validate, typescript
This commit is contained in:
203
src/main.rs
Normal file
203
src/main.rs
Normal file
@@ -0,0 +1,203 @@
|
||||
use std::process;
|
||||
|
||||
use config_forge::{
|
||||
cli::{parse_args, Command, OutputFormat, SchemaSource},
|
||||
convert::{convert, detect_format, parse_content, read_file, write_file, ConfigFormat, infer_schema},
|
||||
highlight::{highlight_env, highlight_ini, highlight_value, highlight_yaml},
|
||||
validate::validate_config,
|
||||
typescript::{generate_ts_interface},
|
||||
ConfigForgeError,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let args = parse_args();
|
||||
|
||||
if args.no_color {
|
||||
colored::control::set_override(false);
|
||||
}
|
||||
|
||||
if let Err(e) = run(args) {
|
||||
eprintln!("Error: {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn run(args: config_forge::cli::Args) -> std::result::Result<(), ConfigForgeError> {
|
||||
match args.command {
|
||||
Command::Convert(convert_args) => {
|
||||
let content = read_file(&convert_args.input)?;
|
||||
let format = convert_args.from.unwrap_or_else(|| detect_format(&convert_args.input.to_string_lossy()));
|
||||
let value = parse_content(&content, format)?;
|
||||
|
||||
let converted = convert(value, convert_args.to.into())?;
|
||||
|
||||
if let Some(output) = convert_args.output {
|
||||
write_file(&output, &converted)?;
|
||||
if args.verbose {
|
||||
println!("Converted {} to {}", convert_args.input.display(), output.display());
|
||||
}
|
||||
} else {
|
||||
if !convert_args.no_highlight {
|
||||
let highlighted = match convert_args.to {
|
||||
OutputFormat::Json => {
|
||||
let json_val: serde_json::Value = serde_json::from_str(&converted)
|
||||
.unwrap_or_else(|_| serde_json::Value::String(converted.clone()));
|
||||
highlight_value(&json_val, 0)
|
||||
}
|
||||
OutputFormat::Yaml => highlight_yaml(&converted),
|
||||
OutputFormat::Ini => highlight_ini(&converted),
|
||||
OutputFormat::Env => highlight_env(&converted),
|
||||
OutputFormat::Toml => highlight_yaml(&converted),
|
||||
};
|
||||
println!("{}", highlighted);
|
||||
} else {
|
||||
println!("{}", converted);
|
||||
}
|
||||
}
|
||||
}
|
||||
Command::Validate(validate_args) => {
|
||||
let config_content = read_file(&validate_args.config)?;
|
||||
let format = detect_format(&validate_args.config.to_string_lossy());
|
||||
|
||||
let (schema_path, schema_format) = if let Some(schema_file) = validate_args.schema_file {
|
||||
(schema_file.to_string_lossy().to_string(), "file")
|
||||
} else if let Some(schema) = validate_args.schema {
|
||||
(schema, "inline")
|
||||
} else {
|
||||
return Err(ConfigForgeError::ValidationError {
|
||||
path: String::new(),
|
||||
reason: "No schema provided. Use --schema or --schema-file".to_string(),
|
||||
});
|
||||
};
|
||||
|
||||
let result = validate_config(&config_content, &format.to_string(), &schema_path, schema_format)?;
|
||||
|
||||
if result.valid {
|
||||
println!("{}", "Validation passed".green().bold());
|
||||
} else {
|
||||
println!("{}", "Validation failed".red().bold());
|
||||
for error in result.errors {
|
||||
eprintln!(" {}: {}", error.path, error.message);
|
||||
}
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
Command::GenerateTs(generate_args) => {
|
||||
let content = read_file(&generate_args.input)?;
|
||||
let format = generate_args.from.unwrap_or_else(|| detect_format(&generate_args.input.to_string_lossy()));
|
||||
let value = parse_content(&content, format)?;
|
||||
|
||||
let interface_name = generate_args.interface_name.unwrap_or_else(|| {
|
||||
generate_args.input.file_stem()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap_or("Config")
|
||||
.to_string()
|
||||
});
|
||||
|
||||
let ts = generate_ts_interface(&value, &interface_name)?;
|
||||
|
||||
if let Some(output) = generate_args.output {
|
||||
write_file(&output, &ts)?;
|
||||
if args.verbose {
|
||||
println!("Generated TypeScript interface {} to {}", interface_name, output.display());
|
||||
}
|
||||
} else {
|
||||
println!("{}", ts);
|
||||
}
|
||||
}
|
||||
Command::Batch(batch_args) => {
|
||||
use rayon::prelude::*;
|
||||
|
||||
let pattern = batch_args.pattern;
|
||||
let output_dir = batch_args.output_dir.unwrap_or_else(|| std::path::PathBuf::from("."));
|
||||
|
||||
let files: Vec<_> = glob::glob(&pattern)
|
||||
.unwrap_or_else(|_| vec![])
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|p| p.is_file())
|
||||
.collect();
|
||||
|
||||
if files.is_empty() {
|
||||
println!("No files found matching pattern: {}", pattern);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if args.verbose {
|
||||
println!("Found {} files to convert", files.len());
|
||||
}
|
||||
|
||||
let convert_file = |input_path: std::path::PathBuf| -> std::result::Result<(), ConfigForgeError> {
|
||||
let content = read_file(&input_path)?;
|
||||
let format = detect_format(&input_path.to_string_lossy());
|
||||
let value = parse_content(&content, format)?;
|
||||
|
||||
let converted = convert(value, batch_args.to.into())?;
|
||||
|
||||
let file_name = input_path.file_stem()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap_or("output");
|
||||
let output_path = output_dir.join(format!("{}.{}", file_name, batch_args.to));
|
||||
|
||||
write_file(&output_path, &converted)?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
if batch_args.parallel {
|
||||
files.par_iter()
|
||||
.try_for_each(|entry| convert_file(entry.clone()))?;
|
||||
} else {
|
||||
for entry in &files {
|
||||
convert_file(entry.clone())?;
|
||||
}
|
||||
}
|
||||
|
||||
if args.verbose {
|
||||
println!("Converted {} files to {}", files.len(), output_dir.display());
|
||||
}
|
||||
}
|
||||
Command::Infer(infer_args) => {
|
||||
let content = read_file(&infer_args.input)?;
|
||||
let format = infer_args.from.unwrap_or_else(|| detect_format(&infer_args.input.to_string_lossy()));
|
||||
let value = parse_content(&content, format)?;
|
||||
|
||||
let schema = infer_schema(&value);
|
||||
let schema_str = serde_json::to_string_pretty(&schema)?;
|
||||
|
||||
if let Some(output) = infer_args.output {
|
||||
write_file(&output, &schema_str)?;
|
||||
if args.verbose {
|
||||
println!("Inferred schema from {} to {}", infer_args.input.display(), output.display());
|
||||
}
|
||||
} else {
|
||||
println!("{}", schema_str);
|
||||
}
|
||||
}
|
||||
Command::Init(init_args) => {
|
||||
let output = init_args.output.unwrap_or_else(|| std::path::PathBuf::from("configforge.toml"));
|
||||
let default_config = r#"# ConfigForge default configuration
|
||||
output_dir = "./"
|
||||
default_format = "json"
|
||||
color_output = true
|
||||
parallel_processing = false
|
||||
"#;
|
||||
write_file(&output, default_config)?;
|
||||
if args.verbose {
|
||||
println!("Created default configuration at {}", output.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl From<OutputFormat> for ConfigFormat {
|
||||
fn from(format: OutputFormat) -> Self {
|
||||
match format {
|
||||
OutputFormat::Json => ConfigFormat::Json,
|
||||
OutputFormat::Yaml => ConfigFormat::Yaml,
|
||||
OutputFormat::Toml => ConfigFormat::Toml,
|
||||
OutputFormat::Env => ConfigFormat::Env,
|
||||
OutputFormat::Ini => ConfigFormat::Ini,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user