Skip to main content

vecslide_core/
typst_render.rs

1/// Compiles a Typst source string into a pure SVG string.
2///
3/// 🔒 The output is SVG — no trace of Typst remains. The compiled HTML viewer
4/// receives only the SVG bytes and has no knowledge of Typst or this module.
5#[cfg(feature = "native")]
6pub fn compile_typst_to_svg(source: &str, fonts: &[Vec<u8>]) -> Result<String, crate::error::VecslideError> {
7    use typst::layout::PagedDocument;
8    use typst_as_lib::TypstEngine;
9
10    let engine = TypstEngine::builder()
11        .main_file(source)
12        .fonts(fonts.iter().map(|f| f.as_slice()))
13        .build();
14
15    let doc: PagedDocument = engine
16        .compile()
17        .output
18        .map_err(|e| crate::error::VecslideError::TypstCompile(format!("{e:?}")))?;
19
20    let page = doc.pages.into_iter().next().ok_or_else(|| {
21        crate::error::VecslideError::TypstCompile("no pages in compiled Typst document".into())
22    })?;
23
24    Ok(typst_svg::svg(&page))
25}
26
27#[cfg(all(test, feature = "native"))]
28mod tests {
29    use super::*;
30    use crate::typst_fonts::bundled_fonts;
31
32    #[test]
33    fn simple_text_compiles_to_svg() {
34        let source = r#"
35#set page(width: 400pt, height: 300pt, margin: 1em, fill: none)
36Hello, *world*!
37"#;
38        let fonts = bundled_fonts();
39        let svg = compile_typst_to_svg(source, &fonts).expect("compilation failed");
40        assert!(svg.contains("<svg"), "output must be an SVG element");
41    }
42
43    #[test]
44    fn math_formula_compiles_to_svg() {
45        let source = r#"
46#set page(width: 400pt, height: 300pt, margin: 1em, fill: none)
47#show math.equation: set text(font: "New Computer Modern Sans Math", weight: "regular")
48$ E = m c^2 $
49"#;
50        let fonts = bundled_fonts();
51        let svg = compile_typst_to_svg(source, &fonts).expect("math compilation failed");
52        assert!(svg.contains("<svg"), "output must be an SVG element");
53    }
54
55    #[test]
56    fn invalid_typst_returns_error() {
57        let source = "#this_is_not_a_valid_function_call(";
58        let fonts = bundled_fonts();
59        let result = compile_typst_to_svg(source, &fonts);
60        assert!(result.is_err(), "invalid Typst should return an error");
61    }
62
63}