Skip to main content

molt/
lib.rs

1//! Fast, type-safe HTML generation for Rust and WebAssembly.
2//!
3//! A port of [Winged-Swift](https://github.com/micheltlutz/Winged-Swift) 2.0.0: the same
4//! composite tree, the same escape-by-default guarantee, the same compact and pretty
5//! render modes — compiled to native code or to `wasm32-unknown-unknown`.
6//!
7//! # Getting started
8//!
9//! ```
10//! use molt::prelude::*;
11//!
12//! let card = article()
13//!     .add_class("card p-4")
14//!     .child(h1().text("Welcome to Molt!").add_class("text-2xl"))
15//!     .child(p().text("Ultra-fast HTML generation compiled to WebAssembly."));
16//!
17//! println!("{}", card.render_pretty());
18//! ```
19//!
20//! # Escaping
21//!
22//! Text content and attribute values are escaped **when they enter the tree**, not when it
23//! is rendered, so nothing is escaped twice and nothing is missed. [`Node::Raw`] is the
24//! documented way to inject markup you already trust.
25//!
26//! URL attributes are checked **when the tree is written**. `href`, `src`, `action`,
27//! `formaction`, `poster`, `cite`, `background`, `xlink:href` and `data` render as `#`
28//! when the value is a `javascript:`, `vbscript:` or `data:text/html` URL, including a
29//! value stored with [`Attribute::raw`](core::Attribute::raw). [`Element::trusted_url`]
30//! opts out for a URL you wrote yourself. See `SECURITY.md`.
31//!
32//! ```
33//! use molt::prelude::*;
34//! assert_eq!(p().text("<script>").render(), "<p>&lt;script&gt;</p>");
35//! ```
36//!
37//! # Render modes
38//!
39//! [`Render::render`] produces a single line; [`Render::render_pretty`] indents. Both take
40//! their configuration from a [`RenderOptions`] value rather than global state, so two
41//! threads can render the same tree differently at the same time.
42//!
43//! # Limits
44//!
45//! Rendering has no depth limit: the writer walks an explicit stack instead of recursing.
46//! What deep trees do cost is output size in pretty mode, which is quadratic in depth
47//! because every line carries one indent string per level. See [`Render`] and
48//! `SECURITY.md`.
49//!
50//! # Parity
51//!
52//! The crate is verified against Winged-Swift's own golden fixtures — the same bytes, from
53//! the same page, built through both APIs. Behavioural differences that were introduced on
54//! purpose are listed in `PORTING.md`.
55
56#![cfg_attr(docsrs, feature(doc_cfg))]
57
58pub mod accessibility;
59pub mod core;
60pub mod document;
61pub mod elements;
62pub mod feed;
63pub mod layout;
64#[macro_use]
65pub mod macros;
66pub mod prelude;
67pub mod seo;
68pub mod sitemap;
69#[cfg(all(feature = "ssg", not(target_arch = "wasm32")))]
70#[cfg_attr(docsrs, doc(cfg(feature = "ssg")))]
71pub mod ssg;
72#[cfg(feature = "wasm")]
73#[cfg_attr(docsrs, doc(cfg(feature = "wasm")))]
74pub mod wasm;
75
76pub use crate::core::{Attribute, Element, Node, Render, RenderOptions};
77pub use crate::document::Document;
78pub use crate::layout::Layout;