1pub mod autolink;
2pub mod clover;
3pub mod comment;
4pub mod frontmatter;
5pub mod inline_tags;
6pub mod statement;
7pub mod tags;
8pub mod template;
9
10pub use frontmatter::{extract_preamble_and_frontmatter, PreambleResult};
11
12use crate::CloverExtensions;
13use markdown_it::{parser::block::BlockState, MarkdownIt, Node, NodeValue, Renderer};
14use oxc_diagnostics::OxcDiagnostic;
15
16/// Register all markodown extensions.
17/// If `markdown_only` is true, skip Marko-specific rules (tags, templates, statements).
18pub fn add_all(
19 md: &mut MarkdownIt,
20 markdown_only: bool,
21 clover_extensions: &Option<CloverExtensions>,
22) {
23 // Always add frontmatter parsing (YAML metadata is standard markdown extension)
24 md.block.add_rule::<frontmatter::Rule>();
25
26 if !markdown_only {
27 // Marko-specific block rules
28 md.block.add_rule::<statement::Rule>();
29 md.block.add_rule::<comment::Rule>();
30 md.block.add_rule::<tags::Rule>();
31
32 // Marko-specific inline rules
33 md.inline.add_rule::<autolink::Rule>();
34 md.inline.add_rule::<template::Rule>();
35 md.inline.add_rule::<tags::Rule>();
36
37 // Post-processor for matching inline tag markers
38 inline_tags::add(md);
39 }
40
41 // Clover's Q+A extensions (can be used with or without Marko features)
42 if let Some(config) = clover_extensions {
43 clover::add(md, config.clone());
44 }
45}
46
47/// An AST node representing a JavaScript error
48#[derive(Debug, Clone)]
49pub(crate) struct ErrorBlock {
50 /// Positions are local to where this parsing began, for simplicity.
51 pub errors: Vec<OxcDiagnostic>,
52}
53
54impl NodeValue for ErrorBlock {
55 fn render(&self, _: &Node, _: &mut dyn Renderer) {
56 panic!("cannot render ErrorBlock");
57 }
58}
59
60/// A raw node that passes Marko syntax verbatim
61#[derive(Debug)]
62pub(crate) struct RawBlock {
63 pub content: String,
64}
65
66impl NodeValue for RawBlock {
67 fn render(&self, _node: &Node, fmt: &mut dyn Renderer) {
68 fmt.text_raw(&self.content);
69 }
70}
71
72/// A statement block (import, export, static, server, client) that needs hoisting.
73/// These are kept separate from RawBlock so they can be extracted before Layout wrapping.
74#[derive(Debug)]
75pub struct StatementBlock {
76 pub content: String,
77}
78
79impl NodeValue for StatementBlock {
80 fn render(&self, _node: &Node, fmt: &mut dyn Renderer) {
81 fmt.text_raw(&self.content);
82 }
83}
84
85/// Helper to get a line with original whitespace preserved
86pub(crate) fn get_line_raw<'a, 'b>(state: &'a BlockState<'a, 'b>, line: usize) -> &'b str {
87 if line < state.line_max {
88 let start = state.line_offsets[line].line_start;
89 let end = state.line_offsets[line].line_end;
90 &state.src[start..end]
91 } else {
92 ""
93 }
94}