katana-canvas-forge 0.1.7

Versioned diagram rendering and document export runtime for KatanA (Mermaid, Draw.io, HTML/PDF/PNG/JPEG).
Documentation
pub(super) struct HtmlFileUri;

impl HtmlFileUri {
    pub(super) fn from_path(path: &std::path::Path) -> String {
        let normalized_path = path.to_string_lossy().replace('\\', "/");
        let encoded_path = Self::encode_path(&normalized_path);
        if Self::has_windows_drive_prefix(&encoded_path) {
            return format!("file:///{encoded_path}");
        }
        format!("file://{encoded_path}")
    }

    fn has_windows_drive_prefix(path: &str) -> bool {
        let bytes = path.as_bytes();
        bytes.len() >= 2 && bytes[0].is_ascii_alphabetic() && bytes[1] == b':'
    }

    fn encode_path(path: &str) -> String {
        let mut encoded = String::with_capacity(path.len());
        for byte in path.as_bytes() {
            if Self::is_path_byte(*byte) {
                encoded.push(*byte as char);
            } else {
                encoded.push_str(&format!("%{byte:02X}"));
            }
        }
        encoded
    }

    fn is_path_byte(byte: u8) -> bool {
        matches!(
            byte,
            b'A'..=b'Z'
                | b'a'..=b'z'
                | b'0'..=b'9'
                | b'-'
                | b'.'
                | b'_'
                | b'~'
                | b'/'
                | b':'
        )
    }
}

#[cfg(test)]
#[path = "html_uri_tests.rs"]
mod tests;