cyclos-codegen.rs (2618B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2025 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 taler_build::long_version; 22 23 /// Cyclos API schema codegen 24 #[derive(clap::Parser, Debug)] 25 #[command(long_version = long_version(), about, long_about = None)] 26 struct Args { 27 kind: Kind, 28 ty: String, 29 } 30 31 #[derive(Debug, Clone, Copy, clap::ValueEnum)] 32 enum Kind { 33 Error, 34 Enum, 35 } 36 37 #[tokio::main] 38 async fn main() -> anyhow::Result<()> { 39 let args = Args::parse(); 40 let api: serde_json::Value = reqwest::get("https://demo.cyclos.org/api/openapi.json") 41 .await? 42 .json() 43 .await?; 44 let schemas = &api["components"]["schemas"]; 45 46 let out = &mut stdout().lock(); 47 let ty = &schemas[&args.ty]; 48 let lines: Vec<_> = ty["description"].as_str().unwrap().lines().collect(); 49 50 match args.kind { 51 Kind::Error => writeln!( 52 out, 53 "#[derive(Debug, serde::Deserialize, thiserror::Error)]" 54 )?, 55 Kind::Enum => writeln!(out, "#[derive(Debug, serde::Deserialize)]")?, 56 } 57 writeln!(out, "#[serde(rename_all = \"camelCase\")]")?; 58 writeln!(out, "/// {}", lines[0])?; 59 writeln!(out, "pub enum {} {{", args.ty)?; 60 for (i, l) in lines[2..].iter().enumerate() { 61 let name = ty["enum"][i].as_str().unwrap(); 62 let mut split = l.split("`").skip(1); 63 let code = split.next().unwrap(); 64 let msg = split 65 .next() 66 .unwrap() 67 .strip_prefix(": ") 68 .unwrap() 69 .trim_end_matches('.'); 70 assert_eq!(name, code); 71 match args.kind { 72 Kind::Error => writeln!(out, " #[error(\"{name} - {msg}\")]")?, 73 Kind::Enum => writeln!(out, " /// {msg}")?, 74 } 75 writeln!( 76 out, 77 " {}{},", 78 name.chars().next().unwrap().to_uppercase(), 79 &name[1..] 80 )?; 81 } 82 writeln!(out, "}}")?; 83 Ok(()) 84 }