use clap::Parser;
use std::fs::write as write_file;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{exit, Command, Stdio};
use std::str::from_utf8;
use ts_bindgen_gen::{generate_rust_for_typescript_with_file_processor, StdFs};
use which::which;
#[derive(Parser, Debug)]
#[clap(about, version, author)]
struct Args {
#[clap(name = "input-path")]
ts_input_file_path: String,
#[clap(short = 'o', long = "output", name = "rust-output-path")]
rust_output_path: Option<String>,
#[clap(long = "skip-rustfmt", name = "skip-rustfmt")]
skip_rustfmt: bool,
#[clap(long)]
rerun_if_changed: bool,
}
fn main() {
let args = Args::parse();
if args.rust_output_path.is_none() && args.rerun_if_changed {
eprintln!("--rust-output-path must be specified if --rerun-if-changed is set");
exit(1);
}
let process_file = if args.rerun_if_changed {
|f: &Path| {
println!("cargo:rerun-if-changed={:?}", f.to_string_lossy());
}
} else {
|_: &Path| {}
};
let rust_result = generate_rust_for_typescript_with_file_processor(
StdFs,
args.ts_input_file_path,
process_file,
);
let rust = match rust_result {
Ok(rust) => rust.to_string(),
Err(err) => {
eprintln!("aborting due to errors in typescript rust binding generation");
eprintln!("Errors:");
eprintln!("{}", err);
exit(101);
}
};
let rust = if args.skip_rustfmt {
rust
} else {
rustfmt_code(rust)
};
if let Some(out_path) = args.rust_output_path {
if let Err(err) = write_file(&out_path, rust) {
eprintln!("Failed to write file {}: {}", out_path, err);
exit(2);
}
} else {
println!("{}", rust);
}
}
fn rustfmt_code(code: String) -> String {
match get_rustfmt_path() {
None => code,
Some(rustfmt) => {
let mut proc = Command::new(rustfmt)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap();
let mut stdin = proc.stdin.take().expect("Failed to open rustfmt stdin");
let stdin_code = code.clone();
std::thread::spawn(move || {
if let Err(err) = stdin.write_all(stdin_code.as_bytes()) {
eprintln!("Failed to write to rustfmt: {}", err);
}
});
let result = proc
.wait_with_output()
.expect("Failed to read rustfmt stdout");
if result.status.success() {
from_utf8(&result.stdout).unwrap().to_owned()
} else {
eprintln!("Failed to run rustfmt: {:?}", result.status.code());
code
}
}
}
}
fn get_rustfmt_path() -> Option<PathBuf> {
which("rustfmt").ok()
}