Chisle
코딩 에이전트 플러그인, 20개 실시간 작업에서 기본 모델 52% 활용, 간결한 페르소나와 출력 압축 제공
A safe, dependency-free HTML DSL for Rust and WebAssembly.
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A safe, dependency-free HTML DSL for Rust and WebAssembly.
🌐 molt-framework.io · 📦 crates.io · 📚 docs.rs · 🚀 Getting started · 🇧🇷 Português
Molt is an embedded DSL: you describe the page in Rust, with a fluent builder or the html!
macro, and the compiler checks it. The result is a tree of plain values rendered once as a
string, compact or pretty. There is no DOM, no runtime, no template language and no
reflection, so there is nothing to parse at run time and nothing to keep in sync.
It is the HTML layer and only that: the element tree, the renderer, metadata, an
accessibility audit, sitemaps, feeds, static site output and a WebAssembly build. Routing,
servers and Markdown stay in the crates that already do them well, and plug in through a
String.
use molt::prelude::*;
use molt::Document;
let page = Document::new(Some("pt-BR"))
.head_children([
meta().attr("charset", "UTF-8"),
title().text("RideKeeper — track every service"),
stylesheet("/css/style.css"),
])
.body_children([
header().child(nav().child(link_to("/").add_class("logo").text("RideKeeper"))),
main_tag().child(
article()
.add_class("card p-4")
.child(h1().text("Track every service"))
.child(p().text("Fuel, tyres & chain — all in one place.")),
),
]);
println!("{}", page.render());
Or with the html! macro, which expands to the same builder calls, never a second code path:
use molt::{html, prelude::*};
let items = ["Fuel", "Tyres", "Chain"];
let markup = html! {
section(class = "log") {
h2 { "Service log" }
ul { @for item in items { li { (item) } } }
}
};
Secure by construction. The one guarantee is that text and attribute values you pass in cannot become markup, and it is enforced where the data enters, not where you remember to.
href, src, action, srcset, …) that resolve to javascript:,
vbscript: or data:text/html are written as #, including through character references.
srcdoc is never written with a value you did not vouch for.<script> goes through its own escaper, so a </script> in a value cannot end
the element.raw_text, Node::raw, Attribute::raw and trusted_url are the only ways around any of
this. They are named so an audit is one grep.unsafe_code = "forbid", cargo deny on the dependency graph, four fuzz targets scheduled
to run every night, and SECURITY.md maps every guarantee onto the OWASP
Top 10.# use molt::prelude::*;
assert_eq!(p().text("<script>alert(1)</script>").render(),
"<p><script>alert(1)</script></p>");
assert_eq!(a().attr("href", "javascript:alert(1)").render(), r##"<a href="#"></a>"##);
Robust under hostile input. Rendering, cloning, comparing, auditing and dropping a tree
all walk an explicit stack, never the call stack, so nesting depth cannot be turned into a
process abort; Debug stops at 128 levels and writes ..., so even a failing assert_eq!
on a deep tree cannot abort. A 100,000-level tree renders in both modes in the test suite, and
RenderOptions::with_max_depth bounds depth that comes from outside. Output is pinned
byte for byte by golden fixtures: a change in markup is a failing test, never a surprise in
production. The crate is 2.x, so what compiles today keeps compiling, and
MIGRATION.md shows every change that altered output.
Light. Zero mandatory dependencies: cargo tree on the default features shows one crate,
this one. wasm-bindgen and rayon are opt-in features. The WebAssembly build is about
25 KB gzipped. The renderer writes the whole tree into one buffer, allocation counts are
asserted in CI, and Node is Send + Sync, so bulk generation parallelises without
ceremony.
Fast enough that it is not the bottleneck. Measured on the development machine with
cargo bench --bench render (Criterion, opt-level = 3):
| bench | median |
|---|---|
| compact render, 10,000-item list | ≈ 400 µs |
| full 50-card document, pretty / compact | ≈ 8 µs / 6.5 µs |
Building the tree costs more than rendering it; both are far below the cost of the request that asked for the page.
The crate is on crates.io and its API
documentation on docs.rs. It is published as
molt-framework — molt on crates.io is an unrelated project — and imported as molt.
cargo add molt-framework
or, by hand, in Cargo.toml:
[dependencies]
molt-framework = "2.0"
New to Rust? docs/new-to-rust.md goes from installing Rust to a page
open in your browser, and says how to run it.
여기까지가 README 앞부분입니다. 나머지는 원문에서 읽을 수 있습니다. README 전문 보기 ↗