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}