use pulldown_cmark_escape::StrWrite;
pub fn escape_html(output: &mut String, text: &str) {
for c in text.chars() {
match c {
'<' => output.push_str("<"),
'>' => output.push_str(">"),
'"' => output.push_str("""),
'&' => output.push_str("&"),
'\'' => output.push_str("'"),
_ => output.push(c),
}
}
}
pub fn escape_href(output: &mut String, href: &str) {
for c in href.chars() {
match c {
'<' | '>' | '"' | '\'' | ' ' | '\n' | '\r' | '\t' => {
write!(output, "%{:02X}", c as u32).unwrap();
}
c => output.push(c),
}
}
}
pub fn sanitize_id(text: &str) -> String {
text.chars()
.map(|c| {
if c.is_alphanumeric() {
c.to_ascii_lowercase()
} else {
'-'
}
})
.collect::<String>()
.split('-')
.filter(|s| !s.is_empty())
.collect::<Vec<&str>>()
.join("-")
}
pub fn unicode_length(text: &str) -> usize {
text.chars().count()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_escape_html() {
let mut output = String::new();
escape_html(&mut output, "<div class=\"test\">&");
assert_eq!(output, "<div class="test">&");
}
#[test]
fn test_escape_href() {
let mut output = String::new();
escape_href(
&mut output,
"https://example.com/path with spaces?q=test&x=1",
);
assert!(output.contains("%20"));
assert!(!output.contains(' '));
assert!(output.contains('&')); }
#[test]
fn test_sanitize_id() {
assert_eq!(sanitize_id("Hello World!"), "hello-world");
assert_eq!(sanitize_id("Test 123"), "test-123");
assert_eq!(sanitize_id("Multiple Spaces"), "multiple-spaces");
assert_eq!(sanitize_id("special@#chars"), "special-chars");
assert_eq!(sanitize_id("--multiple---dashes--"), "multiple-dashes");
}
#[test]
fn test_unicode_length() {
assert_eq!(unicode_length("Hello"), 5);
assert_eq!(unicode_length("👋 Hello"), 7);
assert_eq!(unicode_length("汉å—"), 2);
assert_eq!(unicode_length(""), 0);
}
#[test]
fn test_complex_escaping() {
let mut output = String::new();
escape_html(&mut output, "<script>alert('xss')</script>");
assert_eq!(
output,
"<script>alert('xss')</script>"
);
}
#[test]
fn test_href_special_chars() {
let mut output = String::new();
escape_href(&mut output, "/path/with\"quotes'and<brackets>");
assert!(output.contains("%22")); assert!(output.contains("%27")); assert!(output.contains("%3C")); assert!(output.contains("%3E")); }
}