use super::types::{NodeContext, VisitResult};
pub trait HtmlVisitor: std::fmt::Debug {
fn visit_element_start(&mut self, _ctx: &NodeContext) -> VisitResult {
VisitResult::Continue
}
fn visit_element_end(&mut self, _ctx: &NodeContext, _output: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_text(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_link(&mut self, _ctx: &NodeContext, _href: &str, _text: &str, _title: Option<&str>) -> VisitResult {
VisitResult::Continue
}
fn visit_image(&mut self, _ctx: &NodeContext, _src: &str, _alt: &str, _title: Option<&str>) -> VisitResult {
VisitResult::Continue
}
fn visit_heading(&mut self, _ctx: &NodeContext, _level: u32, _text: &str, _id: Option<&str>) -> VisitResult {
VisitResult::Continue
}
fn visit_code_block(&mut self, _ctx: &NodeContext, _lang: Option<&str>, _code: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_code_inline(&mut self, _ctx: &NodeContext, _code: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_list_item(&mut self, _ctx: &NodeContext, _ordered: bool, _marker: &str, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_list_start(&mut self, _ctx: &NodeContext, _ordered: bool) -> VisitResult {
VisitResult::Continue
}
fn visit_list_end(&mut self, _ctx: &NodeContext, _ordered: bool, _output: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_table_start(&mut self, _ctx: &NodeContext) -> VisitResult {
VisitResult::Continue
}
fn visit_table_row(&mut self, _ctx: &NodeContext, _cells: &[String], _is_header: bool) -> VisitResult {
VisitResult::Continue
}
fn visit_table_end(&mut self, _ctx: &NodeContext, _output: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_blockquote(&mut self, _ctx: &NodeContext, _content: &str, _depth: usize) -> VisitResult {
VisitResult::Continue
}
fn visit_strong(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_emphasis(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_strikethrough(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_underline(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_subscript(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_superscript(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_mark(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_line_break(&mut self, _ctx: &NodeContext) -> VisitResult {
VisitResult::Continue
}
fn visit_horizontal_rule(&mut self, _ctx: &NodeContext) -> VisitResult {
VisitResult::Continue
}
fn visit_custom_element(&mut self, _ctx: &NodeContext, _tag_name: &str, _html: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_definition_list_start(&mut self, _ctx: &NodeContext) -> VisitResult {
VisitResult::Continue
}
fn visit_definition_term(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_definition_description(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_definition_list_end(&mut self, _ctx: &NodeContext, _output: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_form(&mut self, _ctx: &NodeContext, _action: Option<&str>, _method: Option<&str>) -> VisitResult {
VisitResult::Continue
}
fn visit_input(
&mut self,
_ctx: &NodeContext,
_input_type: &str,
_name: Option<&str>,
_value: Option<&str>,
) -> VisitResult {
VisitResult::Continue
}
fn visit_button(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_audio(&mut self, _ctx: &NodeContext, _src: Option<&str>) -> VisitResult {
VisitResult::Continue
}
fn visit_video(&mut self, _ctx: &NodeContext, _src: Option<&str>) -> VisitResult {
VisitResult::Continue
}
fn visit_iframe(&mut self, _ctx: &NodeContext, _src: Option<&str>) -> VisitResult {
VisitResult::Continue
}
fn visit_details(&mut self, _ctx: &NodeContext, _open: bool) -> VisitResult {
VisitResult::Continue
}
fn visit_summary(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_figure_start(&mut self, _ctx: &NodeContext) -> VisitResult {
VisitResult::Continue
}
fn visit_figcaption(&mut self, _ctx: &NodeContext, _text: &str) -> VisitResult {
VisitResult::Continue
}
fn visit_figure_end(&mut self, _ctx: &NodeContext, _output: &str) -> VisitResult {
VisitResult::Continue
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeMap;
#[derive(Debug)]
struct NoOpVisitor;
impl HtmlVisitor for NoOpVisitor {}
#[test]
fn test_default_visitor_implementation() {
let mut visitor = NoOpVisitor;
let ctx = NodeContext {
node_type: super::super::types::NodeType::Text,
tag_name: String::new(),
attributes: BTreeMap::new(),
depth: 0,
index_in_parent: 0,
parent_tag: None,
is_inline: true,
};
matches!(visitor.visit_element_start(&ctx), VisitResult::Continue);
matches!(visitor.visit_element_end(&ctx, "output"), VisitResult::Continue);
matches!(visitor.visit_text(&ctx, "text"), VisitResult::Continue);
matches!(visitor.visit_link(&ctx, "href", "text", None), VisitResult::Continue);
matches!(visitor.visit_image(&ctx, "src", "alt", None), VisitResult::Continue);
matches!(visitor.visit_heading(&ctx, 1, "text", None), VisitResult::Continue);
matches!(visitor.visit_code_block(&ctx, None, "code"), VisitResult::Continue);
matches!(visitor.visit_code_inline(&ctx, "code"), VisitResult::Continue);
}
#[derive(Debug)]
struct CustomLinkVisitor;
impl HtmlVisitor for CustomLinkVisitor {
fn visit_link(&mut self, _ctx: &NodeContext, href: &str, text: &str, _title: Option<&str>) -> VisitResult {
VisitResult::Custom(format!("{} ({})", text, href))
}
fn visit_image(&mut self, _ctx: &NodeContext, _src: &str, _alt: &str, _title: Option<&str>) -> VisitResult {
VisitResult::Skip
}
}
#[test]
fn test_custom_visitor_implementation() {
let mut visitor = CustomLinkVisitor;
let ctx = NodeContext {
node_type: super::super::types::NodeType::Link,
tag_name: "a".to_string(),
attributes: BTreeMap::new(),
depth: 1,
index_in_parent: 0,
parent_tag: Some("p".to_string()),
is_inline: true,
};
let result = visitor.visit_link(&ctx, "https://example.com", "Example", None);
if let VisitResult::Custom(output) = result {
assert_eq!(output, "Example (https://example.com)");
} else {
panic!("Expected Custom result");
}
let img_result = visitor.visit_image(&ctx, "image.jpg", "Alt text", None);
matches!(img_result, VisitResult::Skip);
}
}