Skip to main content

foundry_runtime/
codegen.rs

1//! Code generation for `foundry build`.
2//!
3//! `foundry build` does not compile HTML to machine code itself: it generates a
4//! small Cargo project whose `main.rs` embeds the (escaped) HTML as a string
5//! literal and calls [`crate::run_embedded`], then shells out to `cargo build
6//! --release`. The helpers here produce that generated source, and are kept
7//! separate from the CLI so they can be unit-tested.
8
9/// Version of `alia-foundry` used for the crates.io fallback dependency.
10pub const CRATE_VERSION: &str = env!("CARGO_PKG_VERSION");
11
12/// Package name published on crates.io.
13pub const CRATE_NAME: &str = "alia-foundry";
14
15/// Build the `[dependencies]` line pointing at the Foundry runtime.
16///
17/// When the CLI is running from a checkout, `local_crate_path` is the directory
18/// containing this crate's `Cargo.toml` and a path dependency is emitted.
19/// Otherwise (e.g. `cargo install alia-foundry`) we fall back to crates.io,
20/// pinned to the version of the CLI that generated the project.
21pub fn foundry_dep_line(local_crate_path: Option<&str>) -> String {
22    match local_crate_path {
23        Some(path) => format!(
24            "foundry_runtime = {{ package = \"{}\", path = \"{}\" }}",
25            CRATE_NAME,
26            path.replace('\\', "/")
27        ),
28        None => format!(
29            "foundry_runtime = {{ package = \"{}\", version = \"{}\" }}",
30            CRATE_NAME, CRATE_VERSION
31        ),
32    }
33}
34
35/// Render the `Cargo.toml` of the generated project.
36pub fn generate_cargo_toml(bin_name: &str, dep_line: &str) -> String {
37    format!(
38        r#"[package]
39name = "{name}"
40version = "0.1.0"
41edition = "2021"
42
43[dependencies]
44{dep}
45env_logger = "0.11"
46
47[profile.release]
48opt-level = "z"
49lto = true
50codegen-units = 1
51strip = true
52panic = "abort"
53"#,
54        name = bin_name,
55        dep = dep_line,
56    )
57}
58
59/// Escape an HTML document so it can be embedded as a Rust string literal.
60pub fn escape_html_literal(html: &str) -> String {
61    html.replace('\\', "\\\\")
62        .replace('"', "\\\"")
63        .replace('\n', "\\n")
64        .replace('\r', "\\r")
65        .replace('\t', "\\t")
66}
67
68/// Render the `src/main.rs` of the generated project.
69pub fn generate_main_rs(html: &str, title: &str) -> String {
70    format!(
71        r#"fn main() {{
72    foundry_runtime::run_embedded(
73        "{html}",
74        "{title}",
75    );
76}}
77"#,
78        html = escape_html_literal(html),
79        title = escape_html_literal(title),
80    )
81}