Skip to main content

dioxus_mdx/parser/
types.rs

1//! Type definitions for parsed MDX documentation.
2
3use serde::Deserialize;
4
5use super::openapi_types::OpenApiSpec;
6
7/// Parsed documentation page with frontmatter and content.
8#[derive(Debug, Clone, PartialEq)]
9pub struct ParsedDoc {
10    /// Extracted frontmatter metadata.
11    pub frontmatter: DocFrontmatter,
12    /// Parsed content as a tree of doc nodes.
13    pub content: Vec<DocNode>,
14    /// Raw markdown content (after stripping imports and MDX components).
15    pub raw_markdown: String,
16}
17
18/// YAML frontmatter metadata from MDX files.
19#[derive(Debug, Clone, Default, Deserialize, PartialEq)]
20pub struct DocFrontmatter {
21    /// Page title (used in H1 and browser tab).
22    #[serde(default)]
23    pub title: String,
24    /// Short description (used in meta tags and previews).
25    #[serde(default)]
26    pub description: Option<String>,
27    /// Sidebar title (shorter than main title).
28    #[serde(rename = "sidebarTitle")]
29    #[serde(default)]
30    pub sidebar_title: Option<String>,
31    /// Icon name (Lucide icon identifier).
32    #[serde(default)]
33    pub icon: Option<String>,
34}
35
36/// A node in the parsed documentation tree.
37#[derive(Debug, Clone, PartialEq)]
38pub enum DocNode {
39    /// Plain markdown content to be rendered as HTML.
40    Markdown(String),
41    /// Callout box (Tip, Note, Warning, Info).
42    Callout(CalloutNode),
43    /// Card with title, icon, optional link, and content.
44    Card(CardNode),
45    /// Group of cards in a grid layout.
46    CardGroup(CardGroupNode),
47    /// Tabbed content container.
48    Tabs(TabsNode),
49    /// Sequential steps guide.
50    Steps(StepsNode),
51    /// Collapsible accordion group.
52    AccordionGroup(AccordionGroupNode),
53    /// Code block with optional language.
54    CodeBlock(CodeBlockNode),
55    /// Code group with multiple language variants.
56    CodeGroup(CodeGroupNode),
57    /// API parameter field.
58    ParamField(ParamFieldNode),
59    /// API response field.
60    ResponseField(ResponseFieldNode),
61    /// Expandable section.
62    Expandable(ExpandableNode),
63    /// Request example container.
64    RequestExample(RequestExampleNode),
65    /// Response example container.
66    ResponseExample(ResponseExampleNode),
67    /// Changelog update entry.
68    Update(UpdateNode),
69    /// OpenAPI specification viewer.
70    OpenApi(OpenApiNode),
71}
72
73/// Callout variant type.
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub enum CalloutType {
76    Tip,
77    Note,
78    Warning,
79    Info,
80}
81
82impl CalloutType {
83    pub fn parse(s: &str) -> Option<Self> {
84        match s.to_lowercase().as_str() {
85            "tip" => Some(Self::Tip),
86            "note" => Some(Self::Note),
87            "warning" => Some(Self::Warning),
88            "info" => Some(Self::Info),
89            _ => None,
90        }
91    }
92
93    pub fn as_str(&self) -> &'static str {
94        match self {
95            Self::Tip => "Tip",
96            Self::Note => "Note",
97            Self::Warning => "Warning",
98            Self::Info => "Info",
99        }
100    }
101
102    /// DaisyUI alert class suffix.
103    pub fn alert_class(&self) -> &'static str {
104        match self {
105            Self::Tip => "alert-success",
106            Self::Note => "alert-info",
107            Self::Warning => "alert-warning",
108            Self::Info => "alert-info",
109        }
110    }
111
112    /// Icon name for the callout type.
113    pub fn icon_name(&self) -> &'static str {
114        match self {
115            Self::Tip => "lightbulb",
116            Self::Note => "info",
117            Self::Warning => "alert-triangle",
118            Self::Info => "info",
119        }
120    }
121}
122
123/// Callout box node.
124#[derive(Debug, Clone, PartialEq)]
125pub struct CalloutNode {
126    pub callout_type: CalloutType,
127    pub content: String,
128}
129
130/// Card node with optional link and icon.
131#[derive(Debug, Clone, PartialEq)]
132pub struct CardNode {
133    pub title: String,
134    pub icon: Option<String>,
135    pub href: Option<String>,
136    pub content: String,
137}
138
139/// Grid group of cards.
140#[derive(Debug, Clone, PartialEq)]
141pub struct CardGroupNode {
142    pub cols: u8,
143    pub cards: Vec<CardNode>,
144}
145
146/// Tab in a tabbed interface.
147#[derive(Debug, Clone, PartialEq)]
148pub struct TabNode {
149    pub title: String,
150    /// Content as parsed doc nodes (may contain nested components).
151    pub content: Vec<DocNode>,
152}
153
154/// Tabbed content container.
155#[derive(Debug, Clone, PartialEq)]
156pub struct TabsNode {
157    pub tabs: Vec<TabNode>,
158}
159
160/// Individual step in a steps guide.
161#[derive(Debug, Clone, PartialEq)]
162pub struct StepNode {
163    pub title: String,
164    /// Content as parsed doc nodes (may contain nested components).
165    pub content: Vec<DocNode>,
166}
167
168/// Sequential steps container.
169#[derive(Debug, Clone, PartialEq)]
170pub struct StepsNode {
171    pub steps: Vec<StepNode>,
172}
173
174/// Collapsible accordion item.
175#[derive(Debug, Clone, PartialEq)]
176pub struct AccordionNode {
177    pub title: String,
178    pub icon: Option<String>,
179    /// Content as parsed doc nodes (may contain nested components).
180    pub content: Vec<DocNode>,
181}
182
183/// Accordion group container.
184#[derive(Debug, Clone, PartialEq)]
185pub struct AccordionGroupNode {
186    pub items: Vec<AccordionNode>,
187}
188
189/// Fenced code block.
190#[derive(Debug, Clone, PartialEq)]
191pub struct CodeBlockNode {
192    pub language: Option<String>,
193    pub code: String,
194    pub filename: Option<String>,
195}
196
197/// Code group with multiple language variants.
198#[derive(Debug, Clone, PartialEq)]
199pub struct CodeGroupNode {
200    pub blocks: Vec<CodeBlockNode>,
201}
202
203/// Location of a parameter in an API request.
204#[derive(Debug, Clone, Copy, PartialEq, Eq)]
205pub enum ParamLocation {
206    Header,
207    Path,
208    Query,
209    Body,
210}
211
212impl ParamLocation {
213    pub fn parse(s: &str) -> Option<Self> {
214        match s.to_lowercase().as_str() {
215            "header" => Some(Self::Header),
216            "path" => Some(Self::Path),
217            "query" => Some(Self::Query),
218            "body" => Some(Self::Body),
219            _ => None,
220        }
221    }
222
223    pub fn as_str(&self) -> &'static str {
224        match self {
225            Self::Header => "header",
226            Self::Path => "path",
227            Self::Query => "query",
228            Self::Body => "body",
229        }
230    }
231
232    /// Badge color class for the location.
233    pub fn badge_class(&self) -> &'static str {
234        match self {
235            Self::Header => "badge-warning",
236            Self::Path => "badge-primary",
237            Self::Query => "badge-info",
238            Self::Body => "badge-secondary",
239        }
240    }
241}
242
243/// API parameter documentation field.
244#[derive(Debug, Clone, PartialEq)]
245pub struct ParamFieldNode {
246    /// Parameter name (from header/path/query/body attribute).
247    pub name: String,
248    /// Where the parameter appears.
249    pub location: ParamLocation,
250    /// Data type (string, number, boolean, etc.).
251    pub param_type: String,
252    /// Whether the parameter is required.
253    pub required: bool,
254    /// Default value if any.
255    pub default: Option<String>,
256    /// Description content as parsed doc nodes (may contain nested components).
257    pub content: Vec<DocNode>,
258}
259
260/// API response field documentation.
261#[derive(Debug, Clone, PartialEq)]
262pub struct ResponseFieldNode {
263    /// Field name in the response.
264    pub name: String,
265    /// Data type (string, array, object, etc.).
266    pub field_type: String,
267    /// Whether the field is always present.
268    pub required: bool,
269    /// Description content (may contain nested Expandable or ResponseField).
270    pub content: String,
271    /// Nested expandable sections (for object properties).
272    pub expandable: Option<ExpandableNode>,
273}
274
275/// Expandable section for nested content.
276#[derive(Debug, Clone, PartialEq)]
277pub struct ExpandableNode {
278    /// Section title.
279    pub title: String,
280    /// Nested response fields.
281    pub fields: Vec<ResponseFieldNode>,
282}
283
284/// Container for API request examples.
285#[derive(Debug, Clone, PartialEq)]
286pub struct RequestExampleNode {
287    /// Code blocks with different language examples.
288    pub blocks: Vec<CodeBlockNode>,
289}
290
291/// Container for API response examples.
292#[derive(Debug, Clone, PartialEq)]
293pub struct ResponseExampleNode {
294    /// Code blocks with different response scenarios.
295    pub blocks: Vec<CodeBlockNode>,
296}
297
298/// Changelog version update entry.
299#[derive(Debug, Clone, PartialEq)]
300pub struct UpdateNode {
301    /// Version label (e.g., "v0.9.0").
302    pub label: String,
303    /// Date description (e.g., "December 2025").
304    pub description: String,
305    /// Changelog content as parsed doc nodes.
306    pub content: Vec<DocNode>,
307}
308
309/// OpenAPI specification viewer node.
310#[derive(Debug, Clone, PartialEq)]
311pub struct OpenApiNode {
312    /// Parsed OpenAPI specification.
313    pub spec: OpenApiSpec,
314    /// Optional tag filter (only show endpoints with these tags).
315    pub tags: Option<Vec<String>>,
316    /// Whether to show schema definitions section.
317    pub show_schemas: bool,
318}