#![allow(unused_must_use)]
use convert_case::{Case, Casing};
use serde_json::Value;
use std::collections::HashSet;
use std::fs::File;
use std::io::{BufReader, Write};
use std::path::Path;
pub fn main() {
println!(
"cargo:rerun-if-changed=build.rs
cargo:rerun-if-changed=v5.json",
);
let file = File::open("v5.json").expect("Failed to find schema.");
let reader = BufReader::new(file);
let out_dir = std::env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("gen.rs");
let mut f = std::fs::File::create(dest_path).expect("Failed to create destination file.");
let vdata: Value = serde_json::from_reader(reader).expect("Failed to parse schema.");
let data = vdata.as_object().unwrap();
let defs = data["definitions"].as_object().unwrap();
let marks = defs["Mark"].as_object().unwrap();
let marks = marks["enum"].as_array().unwrap();
let config = defs["Config"].as_object().unwrap();
let config = config["properties"].as_object().unwrap();
let mut enumstr = String::from("#[derive(Subcommand, Debug)] pub enum Marks {");
let mut configs: HashSet<&str> = HashSet::new();
for mark in marks {
if let Value::String(mark) = mark {
let cf = config[mark.as_str()].as_object().unwrap();
let config_ref = cf["$ref"].as_str().unwrap();
let config_name = config_ref.split('/').last().unwrap();
if !configs.contains(config_name) {
let conf = vdata.pointer(&config_ref[1..]).unwrap();
let conf = conf.as_object().unwrap();
let conf = conf["properties"].as_object().unwrap();
writeln!(f, "#[derive(Args, Debug)] pub struct {config_name} {{");
let mut impl_str = format!("impl {config_name} {{ pub fn encode(&self) -> String {{ let mut encodings: Vec<String> = Vec::new();");
for (prop, _desc) in conf {
let snake_prop = prop.to_case(Case::Snake);
let kebab_prop = prop.to_case(Case::Kebab);
writeln!(
f,
"#[clap(long=\"{kebab_prop}\")] pub {snake_prop}: Option<String>,"
);
let prop_test = format!(
"if let Some(encoding) = &self.{snake_prop} {{ encodings.push(format!(\"\\\"{prop}\\\": {{{{{{}}}}}}\", parse_encodings(encoding))); }}\n\n"
);
impl_str.push_str(&prop_test);
}
writeln!(f, "}}");
impl_str.push_str("format!(\"{{{}}}\", encodings.join(\", \")) }}");
writeln!(f, "{impl_str}");
configs.insert(config_name);
};
let camel_mark = mark.to_case(Case::UpperCamel);
writeln!(
f,
"#[derive(Args, Debug)] pub struct {camel_mark} {{ #[clap(flatten)] config: {config_name} }}"
);
writeln!(
f,
"impl {camel_mark} {{pub fn encode(&self) -> String{{ self.config.encode() }}}}"
);
let s = format!("{camel_mark}({camel_mark}),\n");
enumstr.push_str(&s);
}
}
enumstr.push('}');
writeln!(f, "{enumstr}");
}