use std::path::PathBuf;
use std::process::ExitCode;
use clap::{arg, command, Parser};
use colored::Colorize;
use rasn_compiler::{OutputMode, RasnCompiler, TsCompiler};
use walkdir::WalkDir;
#[derive(clap::Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct CompilerArgs {
#[clap(flatten, next_help_heading = "Input")]
source: SourceArgsGroup,
#[clap(flatten, next_help_heading = "Output")]
output: OutputArgGroup,
#[arg(short, long, default_value = "rasn")]
backend: BackendArg,
}
#[derive(clap::Args, Debug)]
#[group(required = true, multiple = true)]
pub struct SourceArgsGroup {
#[arg(short, long, value_name = "DIR")]
directory: Option<PathBuf>,
#[arg(short, long = "module", value_name="FILE", num_args(0..))]
module_files: Vec<PathBuf>,
}
#[derive(clap::Args, Debug)]
#[group(required = false, multiple = false)]
pub struct OutputArgGroup {
#[arg(short, long, value_name = "PATH")]
output_path: Option<PathBuf>,
#[arg(long)]
stdout: bool,
#[arg(long)]
no_output: bool,
}
#[derive(clap::ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
enum BackendArg {
Rasn,
Typescript,
}
fn main() -> ExitCode {
let args = CompilerArgs::parse();
let mut modules = args.source.module_files;
if let Some(dir) = &args.source.directory {
let mut module_found = false;
for entry in WalkDir::new(dir).follow_links(true) {
let entry = match entry {
Ok(entry) => entry,
Err(err) => {
println!("{}: {err}", "warning".yellow());
continue;
}
};
let file_name = entry.file_name().to_string_lossy();
if file_name.ends_with(".asn") || file_name.ends_with(".asn1") {
println!("{}: Found ASN1 module {}", "info".blue(), file_name);
modules.push(entry.into_path());
module_found = true;
}
}
if !module_found {
println!(
"{}: No modules where found in '{}'",
"warning".yellow(),
dir.display(),
);
}
}
if modules.is_empty() {
println!("{}: No modules", "error".red());
return ExitCode::FAILURE;
}
let output = make_output_mode(args.output);
let results = match args.backend {
BackendArg::Rasn => RasnCompiler::new()
.add_asn_sources_by_path(modules.into_iter())
.set_output_mode(output)
.compile(),
BackendArg::Typescript => TsCompiler::new()
.add_asn_sources_by_path(modules.into_iter())
.set_output_mode(output)
.compile(),
};
match results {
Ok(warnings) => {
for warning in warnings {
println!("{}: {warning}", "warning".yellow())
}
ExitCode::SUCCESS
}
Err(error) => {
println!("{}: {error}", "error".red());
ExitCode::FAILURE
}
}
}
fn make_output_mode(args: OutputArgGroup) -> OutputMode {
if let Some(v) = args.output_path {
OutputMode::SingleFile(v)
} else if args.stdout {
OutputMode::Stdout
} else if args.no_output {
OutputMode::NoOutput
} else {
OutputMode::SingleFile(".".into())
}
}