This repository has been archived on 2025-03-28. You can view files and clone it, but cannot push or open issues or pull requests.
2023-02-03 15:06:29 +01:00

152 lines
4.2 KiB
Rust

use clap::{Parser, Subcommand};
use openapi_parser::{build_tree, parse_schema, NodeType, ObjectChild, TreeNode};
use std::fmt::Write;
/// Dump the tree structure of a schema element as dot file
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// The name of the file to dump
///
/// If this value is unspecified, the default petstore schema
/// is used instead
#[arg(short, long)]
file_name: Option<String>,
/// The name of the structure to dump
#[arg(short, long, default_value = "Pet")]
struct_name: String,
/// The action to perform
#[clap(subcommand)]
action: Action,
}
#[derive(Subcommand, Debug)]
enum Action {
/// Dump as JSON
Json,
/// Dump as Graphviz graph
Graph,
/// Dump as Tex list
Tex,
}
fn main() {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
let args = Args::parse();
let file_content = match args.file_name {
None => include_str!("../examples/petstore.yaml").to_string(),
Some(path) => std::fs::read_to_string(path).expect("Unable to load schema file!"),
};
let schema = parse_schema(&file_content);
let tree = build_tree(&args.struct_name, schema.components.as_ref().unwrap());
match args.action {
Action::Json => println!("{}", serde_json::to_string(&tree).unwrap()),
Action::Graph => println!("{}", graphviz_export(&tree)),
Action::Tex => println!("{}", tex_export(&tree)),
}
}
fn recurse_export(node: &TreeNode, parent_name: &str, out: &mut String) {
if !parent_name.is_empty() && matches!(node.r#type, NodeType::Object { .. }) {
writeln!(out, "\"{}\" -> \"{}\";", parent_name, node.name).unwrap();
}
match &node.r#type {
NodeType::Array { item } => {
let mut item = item.clone();
item.name.push_str(" []");
recurse_export(&item, parent_name, out);
}
NodeType::Object { children, .. } => {
for child in children {
recurse_export(&child.node, &node.name, out);
}
}
_ => {}
}
}
fn graphviz_export(tree: &TreeNode) -> String {
let mut out = "digraph G {\n".to_string();
recurse_export(tree, "", &mut out);
out.push_str("}\n");
out
}
fn tex_export_inner(tree: &ObjectChild, out: &mut String, required: bool) {
let type_str = match &tree.node.r#type {
NodeType::Null => "NULL".to_string(),
NodeType::Boolean => "bool".to_string(),
NodeType::Array { item } => format!("{}[]", item.name),
NodeType::Object { .. } => tree.node.name.to_string(),
NodeType::String => "string".to_string(),
NodeType::Number => "number".to_string(),
NodeType::Integer => "integer".to_string(),
};
write!(out, "\\textbf{{{}}}", tree.name).unwrap();
if required {
out.push_str("\\textcolor{red}{*}");
}
out.push_str("\n\\newline");
write!(out, "\\textit{{\\textcolor{{gray}}{{{type_str}}}}}").unwrap();
if let Some(description) = &tree.node.description {
write!(out, "\\newline\n\textcolor{{gray}}{{{}}}", description).unwrap();
}
if let Some(example) = &tree.node.examples.get(0) {
write!(
out,
"\\newline\n\textcolor{{gray}}{{Exemple : {}}}",
example
)
.unwrap();
}
}
fn tex_export(tree: &TreeNode) -> String {
let mut out = String::new();
writeln!(out, "% START OF EXPORT OF STRUCTURE {}", tree.name).unwrap();
match &tree.r#type {
NodeType::Object { children, required } => {
for child in children {
tex_export_inner(
child,
&mut out,
required
.as_ref()
.map(|r| r.contains(&child.name))
.unwrap_or(false),
);
out.push_str("\n\n");
}
}
_ => tex_export_inner(
&ObjectChild {
name: tree.name.to_string(),
node: tree.clone(),
},
&mut out,
false,
),
}
writeln!(out, "% END OF EXPORT OF STRUCTURE {}", tree.name).unwrap();
out
}