devup-editor-html 1.0.2

HTML ↔ Document conversion + clipboard-mode support (tables, Notion heuristics, data-devup-props round-trip) for devup-editor
Documentation
//! Parity test between Rust `is_safe_href` and TypeScript
//! `isSafeLinkHref`.
//!
//! These two functions enforce the same XSS / local-file / data-URI
//! policy. They live in separate languages but must never drift — a
//! link that the React render path considers safe to wrap in an
//! `<a href>` must also pass the clipboard export path's gate, and
//! vice versa.
//!
//! The corresponding TS tests live in
//! `packages/react/test/spansToHtml.test.ts`. If you add or change a
//! case in one place you MUST change it in the other.

// Import the non-public item for testing. `pub(crate)` means we can
// only reach it via the crate itself, so this file must live inside
// `crates/html` (which it does, as an integration test).

// Integration tests run as a separate binary — they can only touch
// `pub` items. We expose a test-only wrapper via a `#[cfg(feature)]`
// door rather than making `is_safe_href` fully public.

// Actually, integration tests can't reach `pub(crate)`. Work around:
// re-export a wrapper through a test-only module added by the lib.

use devup_editor_html::__test_is_safe_href as is_safe_href;

#[test]
fn accepts_http_https_mailto_tel() {
    assert!(is_safe_href("https://example.com"));
    assert!(is_safe_href("http://example.com"));
    assert!(is_safe_href("mailto:user@example.com"));
    assert!(is_safe_href("tel:+1234567890"));
}

#[test]
fn accepts_relative_hash_query_urls() {
    assert!(is_safe_href("/about"));
    assert!(is_safe_href("./docs"));
    assert!(is_safe_href("#section-2"));
    assert!(is_safe_href("?q=search"));
}

#[test]
fn rejects_javascript_scheme_xss() {
    assert!(!is_safe_href("javascript:alert(1)"));
    assert!(!is_safe_href("JavaScript:alert(1)"));
    assert!(!is_safe_href("  javascript:void(0)"));
}

#[test]
fn rejects_vbscript_scheme() {
    assert!(!is_safe_href("vbscript:msgbox(\"x\")"));
}

#[test]
fn rejects_file_scheme() {
    assert!(!is_safe_href("file:///etc/passwd"));
}

#[test]
fn rejects_generic_data_but_allows_data_image() {
    assert!(!is_safe_href("data:text/html,<script>alert(1)</script>"));
    assert!(is_safe_href("data:image/png;base64,iVBOR..."));
}

#[test]
fn rejects_empty_or_whitespace_only() {
    assert!(!is_safe_href(""));
    assert!(!is_safe_href("   "));
}