use super::{Pass, PassResult};
use crate::ast::{Document, NodeKind};
pub struct RemoveDesc;
const EDITOR_PATTERNS: &[&str] = &[
"Created with",
"Created using",
"Generator:",
"Made with",
"Produced by",
];
impl Pass for RemoveDesc {
fn name(&self) -> &'static str {
"removeDesc"
}
fn run(&self, doc: &mut Document) -> PassResult {
let mut changed = false;
let ids = doc.traverse();
for id in ids {
if let NodeKind::Element(ref elem) = doc.node(id).kind
&& elem.name == "desc"
&& elem.prefix.is_none()
&& should_remove(doc, id)
{
doc.remove(id);
changed = true;
}
}
if changed {
PassResult::Changed
} else {
PassResult::Unchanged
}
}
}
fn should_remove(doc: &Document, id: crate::ast::NodeId) -> bool {
let children: Vec<_> = doc.children(id).collect();
if children.is_empty() {
return true;
}
if children.len() == 1
&& let NodeKind::Text(ref text) = doc.node(children[0]).kind
{
let trimmed = text.trim();
if trimmed.is_empty() {
return true;
}
for pattern in EDITOR_PATTERNS {
if trimmed.starts_with(pattern) {
return true;
}
}
}
false
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::parse;
use crate::serializer::serialize;
#[test]
fn removes_editor_desc() {
let input = r#"<svg xmlns="http://www.w3.org/2000/svg"><desc>Created with Figma</desc><rect/></svg>"#;
let mut doc = parse(input).unwrap();
assert_eq!(RemoveDesc.run(&mut doc), PassResult::Changed);
let output = serialize(&doc);
assert!(!output.contains("desc"));
}
#[test]
fn removes_empty_desc() {
let input = r#"<svg xmlns="http://www.w3.org/2000/svg"><desc></desc><rect/></svg>"#;
let mut doc = parse(input).unwrap();
assert_eq!(RemoveDesc.run(&mut doc), PassResult::Changed);
let output = serialize(&doc);
assert!(!output.contains("desc"));
}
#[test]
fn removes_whitespace_only_desc() {
let input = r#"<svg xmlns="http://www.w3.org/2000/svg"><desc> </desc><rect/></svg>"#;
let mut doc = parse(input).unwrap();
assert_eq!(RemoveDesc.run(&mut doc), PassResult::Changed);
}
#[test]
fn keeps_custom_desc() {
let input = r#"<svg xmlns="http://www.w3.org/2000/svg"><desc>A chart showing revenue growth</desc><rect/></svg>"#;
let mut doc = parse(input).unwrap();
assert_eq!(RemoveDesc.run(&mut doc), PassResult::Unchanged);
let output = serialize(&doc);
assert!(output.contains("desc"));
}
#[test]
fn does_not_remove_title() {
let input = r#"<svg xmlns="http://www.w3.org/2000/svg"><title>My SVG</title><rect/></svg>"#;
let mut doc = parse(input).unwrap();
assert_eq!(RemoveDesc.run(&mut doc), PassResult::Unchanged);
let output = serialize(&doc);
assert!(output.contains("title"));
}
#[test]
fn removes_created_using_pattern() {
let input = r#"<svg xmlns="http://www.w3.org/2000/svg"><desc>Created using Inkscape</desc><rect/></svg>"#;
let mut doc = parse(input).unwrap();
assert_eq!(RemoveDesc.run(&mut doc), PassResult::Changed);
}
#[test]
fn removes_generator_pattern() {
let input = r#"<svg xmlns="http://www.w3.org/2000/svg"><desc>Generator: Adobe Illustrator 24.0</desc><rect/></svg>"#;
let mut doc = parse(input).unwrap();
assert_eq!(RemoveDesc.run(&mut doc), PassResult::Changed);
}
}