typst_library/loading/yaml.rs
1use ecow::eco_format;
2use typst_syntax::Spanned;
3
4use crate::diag::{At, SourceResult};
5use crate::engine::Engine;
6use crate::foundations::{func, scope, Str, Value};
7use crate::loading::{DataSource, Load, Readable};
8
9/// Reads structured data from a YAML file.
10///
11/// The file must contain a valid YAML object or array. YAML mappings will be
12/// converted into Typst dictionaries, and YAML sequences will be converted into
13/// Typst arrays. Strings and booleans will be converted into the Typst
14/// equivalents, null-values (`null`, `~` or empty ``) will be converted into
15/// `{none}`, and numbers will be converted to floats or integers depending on
16/// whether they are whole numbers. Custom YAML tags are ignored, though the
17/// loaded value will still be present.
18///
19/// Be aware that integers larger than 2<sup>63</sup>-1 will be converted to
20/// floating point numbers, which may give an approximative value.
21///
22/// The YAML files in the example contain objects with authors as keys,
23/// each with a sequence of their own submapping with the keys
24/// "title" and "published"
25///
26/// # Example
27/// ```example
28/// #let bookshelf(contents) = {
29/// for (author, works) in contents {
30/// author
31/// for work in works [
32/// - #work.title (#work.published)
33/// ]
34/// }
35/// }
36///
37/// #bookshelf(
38/// yaml("scifi-authors.yaml")
39/// )
40/// ```
41#[func(scope, title = "YAML")]
42pub fn yaml(
43 engine: &mut Engine,
44 /// A [path]($syntax/#paths) to a YAML file or raw YAML bytes.
45 source: Spanned<DataSource>,
46) -> SourceResult<Value> {
47 let data = source.load(engine.world)?;
48 serde_yaml::from_slice(data.as_slice())
49 .map_err(|err| eco_format!("failed to parse YAML ({err})"))
50 .at(source.span)
51}
52
53#[scope]
54impl yaml {
55 /// Reads structured data from a YAML string/bytes.
56 #[func(title = "Decode YAML")]
57 #[deprecated = "`yaml.decode` is deprecated, directly pass bytes to `yaml` instead"]
58 pub fn decode(
59 engine: &mut Engine,
60 /// YAML data.
61 data: Spanned<Readable>,
62 ) -> SourceResult<Value> {
63 yaml(engine, data.map(Readable::into_source))
64 }
65
66 /// Encode structured data into a YAML string.
67 #[func(title = "Encode YAML")]
68 pub fn encode(
69 /// Value to be encoded.
70 value: Spanned<Value>,
71 ) -> SourceResult<Str> {
72 let Spanned { v: value, span } = value;
73 serde_yaml::to_string(&value)
74 .map(|v| v.into())
75 .map_err(|err| eco_format!("failed to encode value as YAML ({err})"))
76 .at(span)
77 }
78}