#[doc(hidden)]
#[macro_export]
macro_rules! attributes_impl {
([$($acc:tt)*] $name:expr => $value:expr, $($rest:tt)*) => {
$crate::attributes_impl!(
[$($acc)* ((&$name).to_string(), (&$value).to_string()),]
$($rest)*
)
};
([$($acc:tt)*] $name:expr => $value:expr) => {
$crate::attributes_impl!([$($acc)* ((&$name).to_string(), (&$value).to_string()),])
};
([$($acc:tt)*]) => {
[$($acc)*] as [(String, String); _]
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! html_impl {
([$($acc:tt)*] (text $t:expr) $($rest:tt)*) => {{
let text = $crate::text($t);
$crate::html_impl!(
[$($acc)* text,]
$($rest)*
)
}};
([$($acc:tt)*] (raw $t:expr) $($rest:tt)*) => {{
let text = $crate::raw_text($t);
$crate::html_impl!(
[$($acc)* text,]
$($rest)*
)
}};
([$($acc:tt)*] (> $children:expr) $($rest:tt)*) => {{
let fragment = $crate::fragment($children);
$crate::html_impl!(
[$($acc)* fragment,]
$($rest)*
)
}};
([$($acc:tt)*] ([$tagname:expr] [$($attributes:tt)*] $($children:tt)*) $($rest:tt)*) => {{
let attributes = $crate::attributes_impl!([] $($attributes)*);
let element = $crate::tag($tagname, attributes, []);
element.append($crate::html_impl!(
[]
$($children)*
));
$crate::html_impl!(
[$($acc)* element,]
$($rest)*
)
}};
([$($acc:tt)*] ($tagname:ident [$($attributes:tt)*] $($children:tt)*) $($rest:tt)*) => {{
let tagname = stringify!($tagname);
$crate::html_impl!(
[$($acc)*]
([tagname] [$($attributes)*] $($children)*)
$($rest)*
)
}};
([$($acc:tt)*] ($tagname:ident $($children:tt)*) $($rest:tt)*) => {{
let tagname = stringify!($tagname);
$crate::html_impl!(
[$($acc)*]
([tagname] [] $($children)*)
$($rest)*
)
}};
([$($acc:tt)*] ([$tagname:expr] $($children:tt)*) $($rest:tt)*) => {{
$crate::html_impl!(
[$($acc)*]
([$tagname] [] $($children)*)
$($rest)*
)
}};
([$($top:tt)*]) => {
$crate::fragment([$($top)*])
}
}
#[macro_export]
macro_rules! html {
($($dsl:tt)*) => {
$crate::html_impl!([] $($dsl)*)
};
}
#[cfg(test)]
mod macro_tests {
#[test]
fn empty() {
let res = html!();
assert_eq!(res.to_string(), "");
}
#[test]
fn tag_names() {
let res = html!((span)(header));
assert_eq!(res.to_string(), "<span></span><header></header>");
}
#[test]
fn non_rust_literal_tag_names() {
let res = html!((["!@wow"])(["very odd"]));
assert_eq!(res.to_string(), "<!@wow></!@wow><very odd></very odd>");
}
#[test]
fn with_attributes() {
let res = html!(
(a ['a' => "b", String::from("wow") => 1, &3.2 => &'c'])
);
assert_eq!(res.html(), "<a 3.2=\"c\" a=\"b\" wow=\"1\"></a>");
}
#[test]
fn with_children() {
let without_attributes = html!((div(span)));
assert_eq!(without_attributes.html(), "<div><span></span></div>");
let with_attributes = html!(
(div ["class" => "card"]
(span)
)
);
assert_eq!(
with_attributes.html(),
"<div class=\"card\"><span></span></div>"
);
}
#[test]
fn with_text() {
let res = html!(
(div (text "<>"))
(span (raw "<>"))
);
assert_eq!(res.html(), "<div><></div><span><></span>");
}
#[test]
fn with_node_iterators() {
let opt = Some(html!((p)));
let list = vec![crate::text("hello "), crate::text("world")];
let single = crate::text("how goes it");
let res = html!(
(> opt)
(> list)
(> single)
);
assert_eq!(res.html(), "<p></p>hello worldhow goes it");
}
}