use std::{fs, path::Path};
use typify::{TypeSpace, TypeSpaceSettings};
const SCHEMA_URL: &'static str = "https://raw.githubusercontent.com/versa-protocol/schema";
const SCHEMA_PATH: &'static str = "data";
const SCHEMA_VERSION: &'static str = "1.11.0"; const SCHEMAS: [&'static str; 2] = ["receipt", "itinerary"];
const LTS_SCHEMA_VERSIONS: [&'static str; 5] = ["1.7.0", "1.8.0", "1.9.0", "1.10.0", "1.11.0"];
fn get_schema_definition_json(schema_name: &str, version: &str) -> Result<String, ()> {
let schema_url = format!("{}/{}/{}/{}.schema.json", SCHEMA_URL, version, SCHEMA_PATH, schema_name);
match ureq::get(&schema_url).call() {
Ok(mut res) => {
let response_status = res.status();
if response_status != ureq::http::StatusCode::OK {
println!("Error fetching schema version {}: {}", version, response_status);
return Err(())
}
return match res.body_mut().read_to_string() {
Ok(text) => Ok(text),
Err(e) => {
println!("Error fetching schema version {}: {:?}", version, e);
Err(())
}
}
}
Err(e) => {
println!("Error fetching schema version {}: {:?}", version, e);
return Err(())
}
}
}
fn generate_schema_bindings(schema_name: &str) {
let Ok(content) = get_schema_definition_json(schema_name, SCHEMA_VERSION) else {
return;
};
let schema = serde_json::from_str::<schemars::schema::RootSchema>(&content).unwrap();
let mut type_space = TypeSpace::new(TypeSpaceSettings::default().with_struct_builder(true));
type_space.add_root_schema(schema).unwrap();
let contents = prettyplease::unparse(&syn::parse2::<syn::File>(type_space.to_stream()).unwrap())
.replace("chrono::naive::NaiveDate", "String");
let mut out_file = Path::new("src/schema").to_path_buf();
out_file.push(format!("{}.rs", schema_name));
fs::write(out_file, contents).unwrap();
}
fn bundle_schema_definition(schema: &str, version: &str) {
let Ok(content) = get_schema_definition_json(schema, version) else {
return;
};
let safe_version = format!("{}", version.replace('.', "_"));
let safe_version_name = format!("v{}", safe_version);
let mut out_file = Path::new("src/schema/json").to_path_buf();
out_file.push(format!("{}_{}.json", schema, safe_version_name));
fs::write(out_file, content).unwrap();
println!("Bundled schema definition for {} version {}", schema, version);
}
fn bundle_schema_definitions(schema: &str,) {
for version in LTS_SCHEMA_VERSIONS {
bundle_schema_definition(schema, version);
}
}
fn output_current_schema_version() {
let mut out_file = Path::new("src/schema").to_path_buf();
out_file.push("current.rs");
fs::write(out_file, format!("pub const SCHEMA_VERSION: &str = \"{}\";
", SCHEMA_VERSION)).unwrap();
}
fn main() {
let json_dir = Path::new("src/schema/json");
if json_dir.exists() {
for entry in fs::read_dir(json_dir).unwrap() {
let entry = entry.unwrap();
if entry.path().extension().map(|s| s == "json").unwrap_or(false) {
fs::remove_file(entry.path()).unwrap();
}
}
} else {
fs::create_dir_all(json_dir).unwrap();
}
output_current_schema_version();
for schema in SCHEMAS.iter() {
generate_schema_bindings(schema);
bundle_schema_definitions(schema);
}
}