use oxvg_ast::{
element::Element,
has_attribute, is_element,
visitor::{Context, Visitor},
};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "wasm")]
use tsify::Tsify;
use crate::error::JobsError;
#[cfg_attr(feature = "wasm", derive(Tsify))]
#[cfg_attr(feature = "napi", napi(object))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct RemoveEmptyText {
#[cfg_attr(feature = "wasm", tsify(optional))]
pub text: Option<bool>,
#[cfg_attr(feature = "wasm", tsify(optional))]
pub tspan: Option<bool>,
#[cfg_attr(feature = "wasm", tsify(optional))]
pub tref: Option<bool>,
}
impl<'input, 'arena> Visitor<'input, 'arena> for RemoveEmptyText {
type Error = JobsError<'input>;
fn element(
&self,
element: &Element<'input, 'arena>,
_context: &mut Context<'input, 'arena, '_>,
) -> Result<(), Self::Error> {
if self.text.unwrap_or(true) && is_element!(element, Text) && element.is_empty() {
element.remove();
}
if self.tspan.unwrap_or(true) && is_element!(element, TSpan) && element.is_empty() {
element.remove();
}
if self.tref.unwrap_or(true)
&& is_element!(element, TRef)
&& !has_attribute!(element, XLinkHref)
{
element.remove();
}
Ok(())
}
}
#[test]
fn remove_empty_text() -> anyhow::Result<()> {
use crate::test_config;
insta::assert_snapshot!(test_config(
r#"{ "removeEmptyText": {} }"#,
Some(
r#"<svg xmlns="http://www.w3.org/2000/svg">
<!-- remove empty text -->
<g>
<text></text>
</g>
</svg>"#
),
)?);
insta::assert_snapshot!(test_config(
r#"{ "removeEmptyText": {} }"#,
Some(
r#"<svg xmlns="http://www.w3.org/2000/svg">
<!-- remove empty tspan -->
<g>
<tspan></tspan>
</g>
</svg>"#
),
)?);
insta::assert_snapshot!(test_config(
r#"{ "removeEmptyText": {} }"#,
Some(
r#"<svg xmlns="http://www.w3.org/2000/svg">
<!-- remove non-linking tref -->
<g>
<tref>...</tref>
</g>
</svg>"#
),
)?);
Ok(())
}