cyclos-codegen.rs (2822B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2025, 2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 use std::io::{Write, stdout}; 18 19 use clap::Parser; 20 use http_client::builder::Req; 21 use hyper::Method; 22 use taler_build::long_version; 23 use url::Url; 24 25 /// Cyclos API schema codegen 26 #[derive(clap::Parser, Debug)] 27 #[command(long_version = long_version(), about, long_about = None)] 28 struct Args { 29 kind: Kind, 30 ty: String, 31 } 32 33 #[derive(Debug, Clone, Copy, clap::ValueEnum)] 34 enum Kind { 35 Error, 36 Enum, 37 } 38 39 #[tokio::main] 40 async fn main() -> anyhow::Result<()> { 41 let args = Args::parse(); 42 let client = http_client::client()?; 43 let api: serde_json::Value = Req::new( 44 &client, 45 Method::GET, 46 &Url::parse("https://demo.cyclos.org/api/").unwrap(), 47 "openapi.json", 48 ) 49 .send() 50 .await 51 .unwrap() 52 .1 53 .json() 54 .await?; 55 let schemas = &api["components"]["schemas"]; 56 57 let out = &mut stdout().lock(); 58 let ty = &schemas[&args.ty]; 59 let lines: Vec<_> = ty["description"].as_str().unwrap().lines().collect(); 60 61 match args.kind { 62 Kind::Error => writeln!( 63 out, 64 "#[derive(Debug, serde::Deserialize, thiserror::Error)]" 65 )?, 66 Kind::Enum => writeln!(out, "#[derive(Debug, serde::Deserialize)]")?, 67 } 68 writeln!(out, "#[serde(rename_all = \"camelCase\")]")?; 69 writeln!(out, "/// {}", lines[0])?; 70 writeln!(out, "pub enum {} {{", args.ty)?; 71 for (i, l) in lines[2..].iter().enumerate() { 72 let name = ty["enum"][i].as_str().unwrap(); 73 let mut split = l.split("`").skip(1); 74 let code = split.next().unwrap(); 75 let msg = split 76 .next() 77 .unwrap() 78 .strip_prefix(": ") 79 .unwrap() 80 .trim_end_matches('.'); 81 assert_eq!(name, code); 82 match args.kind { 83 Kind::Error => writeln!(out, " #[error(\"{name} - {msg}\")]")?, 84 Kind::Enum => writeln!(out, " /// {msg}")?, 85 } 86 writeln!( 87 out, 88 " {}{},", 89 name.chars().next().unwrap().to_uppercase(), 90 &name[1..] 91 )?; 92 } 93 writeln!(out, "}}")?; 94 95 Ok(()) 96 }