Skip to main content

typst_library/model/
asset.rs

1use typst_macros::elem;
2
3use crate::diag::bail;
4use crate::foundations::{BundlePath, Bytes, ShowFn, Str, cast};
5use crate::introspection::Locatable;
6
7/// Adds a custom file to a bundle.
8///
9/// This function creates a single file in a @reference:bundle[bundle], from
10/// @bytes[raw byte data]. Unlike @document[documents], assets will be emitted
11/// as-is without undergoing compilation.
12///
13/// The `asset` function can be combined with @read to copy a file from the
14/// project into the output bundle. The first argument to `asset` defines the
15/// output path for the asset in the bundle, while the path passed to `read`
16/// defines where in the project to read the data from.
17///
18/// ```typ
19/// // Copy the file `styles.css` into the bundle.
20/// #asset("styles.css", read("styles.css"))
21/// ```
22///
23/// That said, `asset` is not tied to `read`. You can also generate bytes
24/// directly or use a function like @json.encode to emit serialized data.
25///
26/// ```typ
27/// // Emits a JSON file with the number
28/// // of headings in the document.
29/// #context {
30///   let headings = query(heading)
31///   let meta = (
32///     count: headings.len(),
33///   )
34///   asset("meta.json", json.encode(meta))
35/// }
36///
37/// #document("doc.pdf")[
38///   = Introduction
39///   = Conclusion
40/// ]
41/// ```
42///
43/// This would emit a `meta.json` file with the following contents into the
44/// resulting bundle:
45///
46/// ```json
47/// {
48///   "count": 2
49/// }
50/// ```
51///
52/// This function may only be used in the @reference:bundle[bundle] target.
53#[elem(Locatable)]
54pub struct AssetElem {
55    /// The path in the bundle at which the asset will be placed.
56    ///
57    /// May contain interior slashes, in which case intermediate directories
58    /// will be automatically created.
59    #[required]
60    pub path: BundlePath,
61
62    /// The raw data that will be written into the file at the specified path.
63    ///
64    /// If a string is given, it will be encoded using UTF-8.
65    #[required]
66    pub data: AssetData,
67}
68
69pub const ASSET_UNSUPPORTED_RULE: ShowFn<AssetElem> = |elem, _, _| {
70    bail!(
71        elem.span(),
72        "assets are only supported in the bundle target";
73        // TODO: Support for CLI-specific hints would be nice.
74        hint: "try enabling the bundle target";
75    )
76};
77
78/// The raw data for an asset.
79#[derive(Debug, Clone, Eq, PartialEq, Hash)]
80pub struct AssetData(pub Bytes);
81
82cast! {
83    AssetData,
84    self => self.0.into_value(),
85    v: Str => Self(Bytes::from_string(v)),
86    v: Bytes => Self(v),
87}