use crate::InputSpec;
use std::collections::BTreeMap;
#[derive(Debug, Default)]
pub struct Parsed {
pub description: String,
pub inputs: BTreeMap<String, InputSpec>,
pub outputs: BTreeMap<String, String>,
}
pub fn parse(src: &str) -> Parsed {
let mut out = Parsed::default();
let mut section: Option<&str> = None;
let mut current_key: Option<String> = None;
for raw in src.lines() {
let line = raw.trim_end();
if line.starts_with("description:") {
out.description = unquote(line.splitn(2, ':').nth(1).unwrap_or("").trim());
continue;
}
if line.starts_with("inputs:") {
section = Some("inputs");
current_key = None;
continue;
}
if line.starts_with("outputs:") {
section = Some("outputs");
current_key = None;
continue;
}
if line.starts_with("runs:") || line.starts_with("name:") || line.starts_with("branding:") {
section = None;
current_key = None;
continue;
}
if let Some(sec) = section {
if let Some(rest) = line.strip_prefix(" ") {
if !rest.starts_with(' ') && rest.ends_with(':') {
let key = rest.trim_end_matches(':').to_string();
current_key = Some(key.clone());
if sec == "inputs" {
out.inputs.insert(key, InputSpec::default());
} else {
out.outputs.insert(key, String::new());
}
continue;
}
if let Some(ck) = ¤t_key {
let attr = rest.trim();
if sec == "inputs" {
if let Some(spec) = out.inputs.get_mut(ck) {
if let Some(val) = attr.strip_prefix("required:") {
spec.required = val.trim().contains("true");
} else if let Some(val) = attr.strip_prefix("default:") {
spec.default = Some(unquote(val.trim()));
} else if let Some(val) = attr.strip_prefix("description:") {
spec.description = Some(unquote(val.trim()));
}
}
} else if sec == "outputs" {
if let Some(val) = attr.strip_prefix("description:") {
out.outputs.insert(ck.clone(), unquote(val.trim()));
}
}
}
}
}
}
out
}
fn unquote(s: &str) -> String {
let s = s.trim();
if (s.starts_with('"') && s.ends_with('"')) || (s.starts_with('\'') && s.ends_with('\'')) {
s[1..s.len() - 1].to_string()
} else {
s.to_string()
}
}