Skip to main content

mdcast_client/
request.rs

1//! Constructors for the two wire request bodies.
2//!
3//! [`RenderMarkdownRequest`] and [`RenderTemplateRequest`] are plain serde
4//! structs in `mdcast-api` with no `Default` (markdown and target are not
5//! optional), so building one by hand means naming every field. These give the
6//! common case one expression; everything else is a struct-update:
7//!
8//! ```
9//! use mdcast_client::request;
10//! use mdcast_api::{Target, wire::RenderOptions};
11//!
12//! let mut req = request::markdown("# Q3", Target::Pdf);
13//! req.options = RenderOptions {
14//!     mermaid: true,
15//!     toc_depth: Some(2),
16//!     ..RenderOptions::default()
17//! };
18//! ```
19//!
20//! The `assets` manifest is deliberately left empty: the client fills it from
21//! the [`crate::AssetBundle`] handed to the render call.
22
23use mdcast_api::wire::{RenderMarkdownRequest, RenderTemplateRequest};
24use mdcast_api::{AssetManifest, DocMeta, Target};
25
26/// Render `markdown` to `target`, with no brand and no options.
27pub fn markdown(markdown: impl Into<String>, target: Target) -> RenderMarkdownRequest {
28    RenderMarkdownRequest {
29        markdown: markdown.into(),
30        meta: DocMeta::default(),
31        brand: None,
32        target,
33        assets: AssetManifest::new(),
34        options: Default::default(),
35    }
36}
37
38/// Render a typst template over `data` (raw JSON text, the bytes that become
39/// the virtual `/data.json`) to PDF.
40pub fn template(
41    template_source: impl Into<String>,
42    data: impl Into<String>,
43) -> RenderTemplateRequest {
44    RenderTemplateRequest {
45        template_source: template_source.into(),
46        data: data.into(),
47        meta: DocMeta::default(),
48        brand: None,
49        format: Default::default(),
50        assets: AssetManifest::new(),
51        fonts: Vec::new(),
52        generated: Vec::new(),
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use mdcast_api::wire::{RenderOptions, TemplateFormat};
60
61    #[test]
62    fn markdown_defaults_everything_but_the_body_and_target() {
63        let req = markdown("# Hi", Target::HtmlReveal);
64
65        assert_eq!(req.markdown, "# Hi");
66        assert_eq!(req.target, Target::HtmlReveal);
67        assert_eq!(req.meta, DocMeta::default());
68        assert_eq!(req.brand, None);
69        assert_eq!(req.options, RenderOptions::default());
70        assert!(
71            req.assets.is_empty(),
72            "the bundle fills the manifest, not the caller"
73        );
74    }
75
76    #[test]
77    fn template_defaults_to_pdf() {
78        let req = template("= Invoice", r#"{"number":"INV-042"}"#);
79
80        assert_eq!(req.format, TemplateFormat::Pdf);
81        assert_eq!(req.data, r#"{"number":"INV-042"}"#);
82        assert!(req.assets.is_empty());
83        assert!(req.fonts.is_empty());
84        assert!(req.generated.is_empty());
85    }
86}