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::Decl;
use wdl_ast::v1::MetadataValue;
use wdl_ast::v1::StructDefinition;
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::MetaMapValueSource;
use crate::meta::doc_comments;
use crate::meta::main_container;
use crate::meta::parse_metadata_items;
#[derive(Debug)]
struct Member {
decl: Decl,
meta: MetaMap,
}
impl Member {
fn new(decl: Decl, meta: MetaMap) -> Self {
Self { decl, meta }
}
}
impl DefinitionMeta for Member {
fn meta(&self) -> &MetaMap {
&self.meta
}
}
#[derive(Debug)]
pub struct Struct {
meta: MetaMap,
members: Vec<Member>,
definition: StructDefinition,
version: VersionBadge,
external: bool,
}
impl DefinitionMeta for Struct {
fn meta(&self) -> &MetaMap {
&self.meta
}
}
impl Struct {
pub fn new(
definition: StructDefinition,
version: SupportedVersion,
external: bool,
enable_doc_comments: bool,
) -> Self {
let mut meta = definition
.metadata()
.map(|meta| parse_metadata_items(meta.items()))
.fold(MetaMap::new(), |mut acc, mut meta| {
acc.append(&mut meta);
acc
});
if enable_doc_comments && let Some(comments) = definition.doc_comments() {
meta.append(&mut doc_comments(comments));
}
let parameter_meta = definition
.parameter_metadata()
.map(|meta| parse_metadata_items(meta.items()))
.fold(MetaMap::new(), |mut acc, mut meta| {
acc.append(&mut meta);
acc
});
let members = parse_member_meta(&definition, ¶meter_meta, enable_doc_comments);
Self {
meta,
members,
definition,
version: VersionBadge::new(version),
external,
}
}
pub fn render(&self, assets: &Path) -> (Markup, PageSections) {
let name = self.definition.name();
let name = name.text();
let members = html! {
div class="main__section" {
h2 id="struct-members" class="main__section-header" { "Members" }
div class="main__grid-container" {
div class="main__grid-struct-member-container" {
div class="main__grid-header-cell" { "Name" }
div class="main__grid-header-cell" { "Type" }
div class="main__grid-header-cell" { "Description" }
div class="main__grid-header-separator" {}
@for member in self.members.iter() {
@let member_name = member.decl.name();
@let member_id = format!("member.{}", member_name.text());
div id=(member_id) class="main__grid-row" x-data="{ description_expanded: false }" {
div class="main__grid-cell" {
code { (member_name.text()) }
}
div class="main__grid-cell" {
code { (member.decl.ty()) }
}
div class="main__grid-cell" {
(member.meta().render_description(true))
}
div x-show="description_expanded" class="main__grid-full-width-cell" {
(member.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 markup = html! {
p class="text-brand-pink-400" data-pagefind-filter="type:struct" { "Struct" }
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" {
(self.definition)
}
}
div class="main__section" {
(meta_markup)
}
(members)
};
(
main_container("struct", self.external, markup),
PageSections::default(),
)
}
}
fn parse_member_meta(
definition: &StructDefinition,
parameter_meta: &MetaMap,
enable_doc_comments: bool,
) -> Vec<Member> {
definition
.members()
.map(|decl| {
let name = decl.name().text().to_owned();
let mut meta_map = MetaMap::default();
if let Some(MetaMapValueSource::MetaValue(meta)) = parameter_meta.get(&name) {
match meta {
MetadataValue::Object(o) => {
for item in o.items() {
meta_map.insert(
item.name().text().to_string(),
MetaMapValueSource::MetaValue(item.value().clone()),
);
}
}
MetadataValue::String(_s) => {
meta_map.insert(
DESCRIPTION_KEY.to_string(),
MetaMapValueSource::MetaValue(meta.clone()),
);
}
_ => {}
}
}
if enable_doc_comments && let Some(comments) = decl.doc_comments() {
meta_map.append(&mut doc_comments(comments));
}
Member::new(Decl::Unbound(decl), meta_map)
})
.collect()
}