wdl_doc/callable/
workflow.rs1use maud::Markup;
4use wdl_ast::AstToken;
5use wdl_ast::v1::InputSection;
6use wdl_ast::v1::MetadataSection;
7use wdl_ast::v1::MetadataValue;
8use wdl_ast::v1::OutputSection;
9use wdl_ast::v1::ParameterMetadataSection;
10
11use super::*;
12use crate::meta::render_value;
13use crate::parameter::Parameter;
14
15#[derive(Debug)]
17pub struct Workflow {
18 name: String,
20 meta: MetaMap,
22 inputs: Vec<Parameter>,
24 outputs: Vec<Parameter>,
26}
27
28impl Workflow {
29 pub fn new(
31 name: String,
32 meta_section: Option<MetadataSection>,
33 parameter_meta: Option<ParameterMetadataSection>,
34 input_section: Option<InputSection>,
35 output_section: Option<OutputSection>,
36 ) -> Self {
37 let meta = match meta_section {
38 Some(mds) => parse_meta(&mds),
39 _ => MetaMap::default(),
40 };
41 let parameter_meta = match parameter_meta {
42 Some(pmds) => parse_parameter_meta(&pmds),
43 _ => MetaMap::default(),
44 };
45 let inputs = match input_section {
46 Some(is) => parse_inputs(&is, ¶meter_meta),
47 _ => Vec::new(),
48 };
49 let outputs = match output_section {
50 Some(os) => parse_outputs(&os, &meta, ¶meter_meta),
51 _ => Vec::new(),
52 };
53
54 Self {
55 name,
56 meta,
57 inputs,
58 outputs,
59 }
60 }
61
62 pub fn name_override(&self) -> Option<Markup> {
64 self.meta.get("name").map(render_value)
65 }
66
67 pub fn category(&self) -> Option<String> {
69 self.meta.get("category").and_then(|v| match v {
70 MetadataValue::String(s) => Some(s.text().unwrap().text().to_string()),
71 _ => None,
72 })
73 }
74
75 pub fn render_meta(&self) -> Markup {
80 let mut kv = self
81 .meta
82 .iter()
83 .filter(|(k, _)| !matches!(k.as_str(), "name" | "category" | "description" | "outputs"))
84 .peekable();
85 html! {
86 @if kv.peek().is_some() {
87 div {
88 h2 { "Meta" }
89 @for (key, value) in kv {
90 p {
91 b { (key) ":" } " " (render_value(value))
92 }
93 }
94 }
95 }
96 }
97 }
98
99 pub fn render(&self) -> Markup {
101 html! {
102 div class="table-auto border-collapse" {
103 h1 { @if let Some(name) = self.name_override() { (name) } @else { (self.name) } }
104 @if let Some(category) = self.category() {
105 h2 { "Category: " (category) }
106 }
107 (self.description())
108 (self.render_meta())
109 (self.render_inputs())
110 (self.render_outputs())
111 }
112 }
113 }
114}
115
116impl Callable for Workflow {
117 fn name(&self) -> &str {
118 &self.name
119 }
120
121 fn meta(&self) -> &MetaMap {
122 &self.meta
123 }
124
125 fn inputs(&self) -> &[Parameter] {
126 &self.inputs
127 }
128
129 fn outputs(&self) -> &[Parameter] {
130 &self.outputs
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use wdl_ast::Document;
137
138 use super::*;
139
140 #[test]
141 fn test_workflow() {
142 let (doc, _) = Document::parse(
143 r#"
144 version 1.0
145 workflow test {
146 input {
147 String name
148 }
149 output {
150 String greeting = "Hello, ${name}!"
151 }
152 }
153 "#,
154 );
155
156 let doc_item = doc.ast().into_v1().unwrap().items().next().unwrap();
157 let ast_workflow = doc_item.into_workflow_definition().unwrap();
158
159 let workflow = Workflow::new(
160 ast_workflow.name().text().to_string(),
161 ast_workflow.metadata(),
162 ast_workflow.parameter_metadata(),
163 ast_workflow.input(),
164 ast_workflow.output(),
165 );
166
167 assert_eq!(workflow.name(), "test");
168 assert_eq!(workflow.inputs.len(), 1);
169 assert_eq!(workflow.outputs.len(), 1);
170 }
171}