Skip to main content

easi_publish/
lib.rs

1#![warn(missing_docs)]
2//! # easi-publish
3//!
4//! Compile Typst templates with user data into PDF or HTML documents.
5//!
6//! ## Outputs are opt-in features
7//!
8//! Two output backends live behind cargo features, so you pull only what you
9//! use:
10//! - `pdf` (**default**) — [`render_pdf`] and friends, plus [`PdfConfig`].
11//! - `html` — [`render_html`] and friends, plus [`HtmlConfig`]. Equations are
12//!   exported to MathML automatically.
13//!
14//! Enable both with `features = ["pdf", "html"]`, or take HTML only with
15//! `default-features = false, features = ["html"]`.
16//!
17//! ## Quick start
18//!
19//! ```no_run
20//! # #[cfg(feature = "pdf")] {
21//! use easi_publish::{SharedFonts, TemplateSource, DataSet, PdfConfig, render_pdf};
22//!
23//! let fonts = SharedFonts::new();
24//! let template = TemplateSource::FilePath("templates/invoice.typ".into());
25//! let data = DataSet::from_json_file(
26//!     "invoice.json",
27//!     serde_json::json!({"invoice_number": "INV-001"}),
28//! ).unwrap();
29//! let pdf_bytes = render_pdf(&fonts, template, data, &PdfConfig::default()).unwrap();
30//! # }
31//! ```
32//!
33//! ## Trust model
34//!
35//! This crate is built for app-authored (trusted) templates with untrusted data.
36//! The pattern is a fixed template plus user data supplied as a [`DataSet`]
37//! (`sys.inputs` and/or virtual files), which is the recommended safe shape. 
38//! 
39//! It is not recommended to render user-supplied templates here: there is no compile 
40//! timeout or memory bound (a! template can loop or allocate without limit), and a 
41//! template can read any file under its root. File reads are confined to the template's 
42//! root, package imports (`@preview/...`) are denied, and there is no network access. 
43//! Set the template root to `None` (an in-memory template with no root) to deny all
44//! disk reads. Safely rendering untrusted templates requires process isolation
45//! and is currently out of scope.
46
47mod clock;
48mod data;
49mod error;
50mod fonts;
51
52#[cfg(feature = "image")]
53mod image_util;
54
55mod renderer;
56mod template;
57
58#[cfg(feature = "html")]
59mod html;
60#[cfg(feature = "pdf")]
61mod pdf;
62
63// Diagnostic mapping and the Typst `World` impl back both output backends, skip
64// them entirely when neither is enabled.
65#[cfg(any(feature = "pdf", feature = "html"))]
66mod diagnostics;
67#[cfg(any(feature = "pdf", feature = "html"))]
68mod world;
69
70pub use clock::Clock;
71#[cfg(feature = "pdf")]
72pub use pdf::{PdfConfig, render_pdf, render_pdf_prepared, render_pdf_to_file};
73pub use data::DataSet;
74pub use error::{Diagnostic, Hint, PublishError, Result, Severity};
75pub use fonts::SharedFonts;
76
77#[cfg(feature = "html")]
78pub use html::{HtmlConfig, render_html, render_html_prepared};
79#[cfg(feature = "image")]
80pub use image_util::downscale_image;
81
82pub use renderer::Renderer;
83pub use template::{PreparedTemplate, TemplateSource};
84
85// `Dict` lets callers pass a pre-built typst dictionary as data (no feature
86// needed). The PDF-config types come from the PDF backend, so they're gated.
87pub use typst::foundations::Dict;
88#[cfg(feature = "pdf")]
89pub use typst::layout::PageRanges;
90#[cfg(feature = "pdf")]
91pub use typst_pdf::{PdfStandard, Timestamp, Timezone};
92
93/// Evict Typst's memoization-cache entries unused for the last `max_age` calls
94/// to this function.
95///
96/// Typst caches compilation work (parsing, layout, image decode, ...) in a
97/// process-global cache that otherwise grows unbounded. Long-running servers
98/// should call this periodically, e.g. every N renders or on a timer to bound
99/// memory. `evict_cache(0)` clears the cache entirely. A small value like
100/// `evict_cache(10)` keeps recently-used entries (useful when the same template
101/// or images recur, so they aren't re-decoded immediately).
102pub fn evict_cache(max_age: usize) {
103    comemo::evict(max_age);
104}