apollo-errors 0.7.0

Structured error handling with automatic format conversion
Documentation
//! HTML escaping utilities for safe error rendering.

use std::fmt::{self, Display, Write};

/// A wrapper that escapes values when displayed.
///
/// Used by generated code to safely render error field values in HTML.
pub struct HtmlEscaped<T>(pub T);

impl<T: Display> Display for HtmlEscaped<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // to_string() heap allocation here that could be avoided if we find this is on the hot path.
        let s = self.0.to_string();
        for c in s.chars() {
            match c {
                '&' => f.write_str("&amp;")?,
                '<' => f.write_str("&lt;")?,
                '>' => f.write_str("&gt;")?,
                '"' => f.write_str("&quot;")?,
                '\'' => f.write_str("&#x27;")?,
                _ => f.write_char(c)?,
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_escapes_html_characters() {
        assert_eq!(
            format!("{}", HtmlEscaped("User <admin> & \"root's\"")),
            "User &lt;admin&gt; &amp; &quot;root&#x27;s&quot;"
        );
    }

    #[test]
    fn test_escapes_script_tag() {
        assert_eq!(
            format!("{}", HtmlEscaped("<script>alert('xss')</script>")),
            "&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;"
        );
    }

    #[test]
    fn test_preserves_normal_text() {
        assert_eq!(
            format!("{}", HtmlEscaped("/path/to/file.txt")),
            "/path/to/file.txt"
        );
    }
}