use std::path::Path;
use maud::Markup;
use maud::html;
use wdl_ast::AstToken;
use wdl_ast::Documented;
use wdl_ast::SupportedVersion;
use wdl_ast::v1::EnumDefinition;
use wdl_ast::v1::EnumVariant;
use crate::VersionBadge;
use crate::docs_tree::PageSections;
use crate::meta::DESCRIPTION_KEY;
use crate::meta::DefinitionMeta;
use crate::meta::MetaMap;
use crate::meta::MetaMapExt;
use crate::meta::doc_comments;
use crate::meta::main_container;
#[derive(Debug)]
pub(crate) struct DocumentedEnumChoice {
meta: MetaMap,
choice: EnumVariant,
}
impl DefinitionMeta for DocumentedEnumChoice {
fn meta(&self) -> &MetaMap {
&self.meta
}
}
#[derive(Debug)]
pub(crate) struct Enum {
meta: MetaMap,
choices: Vec<DocumentedEnumChoice>,
definition: EnumDefinition,
version: VersionBadge,
external: bool,
}
impl DefinitionMeta for Enum {
fn meta(&self) -> &MetaMap {
&self.meta
}
}
impl Enum {
pub fn new(
definition: EnumDefinition,
version: SupportedVersion,
external: bool,
enable_doc_comments: bool,
) -> Self {
let (meta, choices) = parse_meta(&definition, enable_doc_comments);
Self {
meta,
choices,
definition,
version: VersionBadge::new(version),
external,
}
}
pub fn render(&self, assets: &Path) -> (Markup, PageSections) {
let name = self.definition.name();
let name = name.text();
let choices = html! {
div class="main__section" {
h2 id="choices" class="main__section-header" { "Choices" }
div class="main__grid-container" {
div class="main__grid-enum-choice-container" {
div class="main__grid-header-cell" { "Name" }
div class="main__grid-header-cell" { "Description" }
div class="main__grid-header-separator" {}
@for choice in self.choices.iter() {
@let choice_name = choice.choice.name();
@let choice_id = format!("choice.{}", choice_name.text());
div id=(choice_id) class="main__grid-row" x-data="{ description_expanded: false }" {
div class="main__grid-cell" {
code { (choice_name.text()) }
}
div class="main__grid-cell" {
(choice.meta().render_description(true))
}
div x-show="description_expanded" class="main__grid-full-width-cell" {
(choice.meta().render_description(false))
}
}
div class="main__grid-row-separator" {}
}
}
}
}
};
let meta_markup = self
.meta
.render_remaining(&[DESCRIPTION_KEY], assets)
.map_or_else(|| html! {}, |markup| html! { (markup) });
let definition = self.definition.display(None);
let markup = html! {
p class="text-brand-lime-300" data-pagefind-filter="type:enum" { "Enum" }
h1 id="title" class="main__title" data-pagefind-meta="title" { code { (name) } }
div class="markdown-body mb-4" {
(self.meta.render_description(false))
}
div class="main__badge-container" {
(self.version.render())
}
div class="main__section" {
sprocket-code language="wdl" {
(definition)
}
}
div class="main__section" {
(meta_markup)
}
(choices)
};
(
main_container("enum", self.external, markup),
PageSections::default(),
)
}
}
fn parse_meta(
definition: &EnumDefinition,
enable_doc_comments: bool,
) -> (MetaMap, Vec<DocumentedEnumChoice>) {
let enum_docs = if enable_doc_comments && let Some(comments) = definition.doc_comments() {
doc_comments(comments)
} else {
MetaMap::new()
};
let mut choice_docs = Vec::new();
for choice in definition.variants() {
let meta = if enable_doc_comments && let Some(comments) = choice.doc_comments() {
doc_comments(comments)
} else {
MetaMap::new()
};
choice_docs.push(DocumentedEnumChoice {
meta,
choice: choice.clone(),
});
}
(enum_docs, choice_docs)
}
#[cfg(test)]
mod tests {
use wdl_ast::AstToken;
use wdl_ast::Document;
use wdl_ast::SupportedVersion;
use wdl_ast::version::V1;
use crate::r#enum::Enum;
use crate::meta::DESCRIPTION_KEY;
use crate::meta::MetaMapExt;
#[test]
fn test_enum() {
let (doc, _) = Document::parse(
r##"
version 1.3
## An RGB24 color enum
##
## Each variant is represented as a 24-bit hexadecimal RGB string with exactly one non-zero channel.
enum Color[String] {
## Pure red
Red = "#FF0000",
## Pure green
Green = "#00FF00",
Blue = "#0000FF" # No description
}
"##,
None,
);
let doc_item = doc.ast().into_v1().unwrap().items().next().unwrap();
let ast_enum = doc_item.into_enum_definition().unwrap();
let enum_def = Enum::new(ast_enum, SupportedVersion::V1(V1::Three), false, true);
assert_eq!(
enum_def.meta.full_description().as_deref(),
Some(
"An RGB24 color enum\n\nEach variant is represented as a 24-bit hexadecimal RGB \
string with exactly one non-zero channel."
)
);
assert_eq!(enum_def.definition.name().text(), "Color");
let mut found_red = false;
let mut found_green = false;
let mut found_blue = false;
for choice in enum_def.choices {
match choice.choice.name().text() {
"Red" => {
assert_eq!(
choice.meta.get(DESCRIPTION_KEY).unwrap().text().unwrap(),
"Pure red"
);
found_red = true;
}
"Green" => {
assert_eq!(
choice.meta.get(DESCRIPTION_KEY).unwrap().text().unwrap(),
"Pure green"
);
found_green = true;
}
"Blue" => {
assert!(!choice.meta.contains_key(DESCRIPTION_KEY));
found_blue = true;
}
other => unreachable!("unexpected choice: {other}"),
}
}
assert!(found_red);
assert!(found_green);
assert!(found_blue);
}
}