cyclos-codegen.rs (2833B)
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; 18 use std::io::stdout; 19 20 use clap::Parser; 21 use http_client::builder::Req; 22 use hyper::Method; 23 use taler_build::long_version; 24 use url::Url; 25 26 /// Cyclos API schema codegen 27 #[derive(clap::Parser, Debug)] 28 #[command(long_version = long_version(), about, long_about = None)] 29 struct Args { 30 kind: Kind, 31 ty: String, 32 } 33 34 #[derive(Debug, Clone, Copy, clap::ValueEnum)] 35 enum Kind { 36 Error, 37 Enum, 38 } 39 40 #[tokio::main] 41 async fn main() -> anyhow::Result<()> { 42 let args = Args::parse(); 43 let client = http_client::client()?; 44 let api: serde_json::Value = Req::new( 45 &client, 46 Method::GET, 47 &Url::parse("https://demo.cyclos.org/api/").unwrap(), 48 "openapi.json", 49 ) 50 .send() 51 .await 52 .unwrap() 53 .1 54 .json() 55 .await?; 56 let schemas = &api["components"]["schemas"]; 57 58 let out = &mut stdout().lock(); 59 let ty = &schemas[&args.ty]; 60 let lines: Vec<_> = ty["description"].as_str().unwrap().lines().collect(); 61 62 match args.kind { 63 Kind::Error => writeln!( 64 out, 65 "#[derive(Debug, serde::Deserialize, thiserror::Error)]" 66 )?, 67 Kind::Enum => writeln!(out, "#[derive(Debug, serde::Deserialize)]")?, 68 } 69 writeln!(out, "#[serde(rename_all = \"camelCase\")]")?; 70 writeln!(out, "/// {}", lines[0])?; 71 writeln!(out, "pub enum {} {{", args.ty)?; 72 for (i, l) in lines[2..].iter().enumerate() { 73 let name = ty["enum"][i].as_str().unwrap(); 74 let mut split = l.split("`").skip(1); 75 let code = split.next().unwrap(); 76 let msg = split 77 .next() 78 .unwrap() 79 .strip_prefix(": ") 80 .unwrap() 81 .trim_end_matches('.'); 82 assert_eq!(name, code); 83 match args.kind { 84 Kind::Error => writeln!(out, " #[error(\"{name} - {msg}\")]")?, 85 Kind::Enum => writeln!(out, " /// {msg}")?, 86 } 87 writeln!( 88 out, 89 " {}{},", 90 name.chars().next().unwrap().to_uppercase(), 91 &name[1..] 92 )?; 93 } 94 writeln!(out, "}}")?; 95 96 Ok(()) 97 }