use std::path::PathBuf;
use std::rc::Rc;
use maud::Markup;
use maud::PreEscaped;
use maud::Render;
use maud::html;
use wdl_ast::AstToken;
use wdl_ast::SupportedVersion;
use wdl_ast::SyntaxTokenExt;
use wdl_ast::VersionStatement;
use crate::HTMLPage;
use crate::Markdown;
use crate::VersionBadge;
use crate::docs_tree::Header;
use crate::docs_tree::PageSections;
use crate::docs_tree::PageType;
use crate::runnable::Runnable;
pub fn parse_preamble_comments(version: &VersionStatement) -> String {
let comments = version
.keyword()
.inner()
.preceding_trivia()
.map(|t| match t.kind() {
wdl_ast::SyntaxKind::Comment => match t.to_string().strip_prefix("## ") {
Some(comment) => comment.to_string(),
None => "".to_string(),
},
wdl_ast::SyntaxKind::Whitespace => "".to_string(),
_ => {
panic!("Unexpected token kind: {:?}", t.kind())
}
})
.collect::<Vec<_>>();
comments.join("\n")
}
#[derive(Debug)]
pub(crate) struct Document {
name: String,
version: VersionBadge,
version_statement: VersionStatement,
local_pages: Vec<(PathBuf, Rc<HTMLPage>)>,
}
impl Document {
pub(crate) fn new(
name: String,
version: SupportedVersion,
version_statement: VersionStatement,
local_pages: Vec<(PathBuf, Rc<HTMLPage>)>,
) -> Self {
Self {
name,
version: VersionBadge::new(version),
version_statement,
local_pages,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn render_version(&self) -> Markup {
self.version.render()
}
pub fn render_preamble(&self) -> Option<Markup> {
let preamble = parse_preamble_comments(&self.version_statement);
if preamble.is_empty() {
return None;
}
Some(html! {
div class="markdown-body" {
(Markdown(&preamble).render())
}
})
}
pub fn render(&self) -> (Markup, PageSections) {
let rows = self.local_pages.iter().map(|page| {
html! {
div class="main__grid-row" x-data="{ description_expanded: false }" {
@match page.1.page_type() {
PageType::Struct(_) => {
div class="main__grid-cell" {
a class="text-pink-400 hover:text-pink-300" href=(page.0.to_string_lossy()) {
(page.1.name())
}
}
div class="main__grid-cell" { code { "struct" } }
div class="main__grid-cell" { "N/A" }
}
PageType::Task(t) => {
div class="main__grid-cell" {
a class="text-violet-400 hover:text-violet-300" href=(page.0.to_string_lossy()) {
(page.1.name())
}
}
div class="main__grid-cell" { code { "task" } }
div class="main__grid-cell" {
(t.render_description(true))
}
}
PageType::Workflow(w) => {
div class="main__grid-cell" {
a class="text-emerald-400 hover:text-emerald-300" href=(page.0.to_string_lossy()) {
(page.1.name())
}
}
div class="main__grid-cell" { code { "workflow" } }
div class="main__grid-cell" {
(w.render_description(true))
}
}
PageType::Index(_) => {
div class="main__grid-cell" { "ERROR" }
div class="main__grid-cell" { "ERROR" }
div class="main__grid-cell" { "ERROR" }
}
}
div x-show="description_expanded" class="main__grid-full-width-cell" {
@match page.1.page_type() {
PageType::Struct(_) => "ERROR"
PageType::Task(t) => {
(t.render_description(false))
}
PageType::Workflow(w) => {
(w.render_description(false))
}
PageType::Index(_) => "ERROR"
}
}
}
}
}.into_string()).collect::<Vec<_>>().join(&html! { div class="main__grid-row-separator" {} }.into_string());
let markup = html! {
div class="main__container" {
h1 id="title" class="main__title" { (self.name()) }
div class="main__badge-container" {
(self.render_version())
}
@if let Some(preamble) = self.render_preamble() {
div id="preamble" class="main__section" {
(preamble)
}
}
div class="main__section" {
h2 id="toc" class="main__section-header" { "Table of Contents" }
div class="main__grid-container" {
div class="main__grid-toc-container" {
div class="main__grid-header-cell" { "Page" }
div class="main__grid-header-cell" { "Type" }
div class="main__grid-header-cell" { "Description" }
div class="main__grid-header-separator" {}
(PreEscaped(rows))
}
}
}
}
};
let mut headers = PageSections::default();
headers.push(Header::Header(
"Preamble".to_string(),
"preamble".to_string(),
));
headers.push(Header::Header(
"Table of Contents".to_string(),
"toc".to_string(),
));
(markup, headers)
}
}