Skip to main content

dioxus_mdx/parser/
types.rs

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