Skip to main content

socketry_markdown/mdast/
frontmatter.rs

1// Released under the MIT License.
2// Copyright, 2026, by Samuel Williams.
3
4use crate::unist::Position;
5use alloc::string::String;
6
7/// Language-agnostic frontmatter with an opaque format hint.
8///
9/// The contents are raw text: the Markdown parser does not interpret the
10/// named language. Untagged `---` and `+++` forms retain their legacy `Yaml`
11/// and `Toml` nodes; tagged forms and language-tagged code fences use this node.
12#[derive(Clone, Debug, Eq, PartialEq)]
13#[cfg_attr(
14    feature = "serde",
15    derive(serde::Serialize, serde::Deserialize),
16    serde(rename_all = "camelCase")
17)]
18pub struct Frontmatter {
19    /// Raw content between the fence lines, including its trailing line ending.
20    pub value: String,
21    /// The whole info string, with surrounding spaces and tabs removed.
22    /// Escapes and character references remain literal, as in Markly.
23    pub info: String,
24    /// Opening fence marker: a backtick, tilde, dash, or plus.
25    pub fence: char,
26    /// Number of opening fence markers. Serialization may lengthen the fence
27    /// to keep edited content from closing it prematurely.
28    pub fence_length: usize,
29    /// Number of closing fence markers. Closing code fences can be longer
30    /// than their opening fence.
31    pub closing_fence_length: usize,
32    /// Source position, including the fences.
33    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
34    pub position: Option<Position>,
35}
36
37impl Frontmatter {
38    /// Return the first ASCII-whitespace-separated word as a format or language hint.
39    /// The parser does not validate or interpret this hint.
40    #[must_use]
41    pub fn language(&self) -> Option<&str> {
42        self.info.split_ascii_whitespace().next()
43    }
44}