Remove old html code
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
mod walk;
|
||||
pub use walk::*;
|
||||
|
||||
mod walk_mut;
|
||||
pub use walk_mut::*;
|
||||
@@ -1,384 +0,0 @@
|
||||
use markdown::mdast::Node;
|
||||
use std::fmt::Debug;
|
||||
use std::marker::PhantomPinned;
|
||||
|
||||
pub enum AstWalkStep<'a, T> {
|
||||
Enter(&'a T),
|
||||
Exit(&'a T),
|
||||
}
|
||||
|
||||
impl<T: Debug> Debug for AstWalkStep<'_, T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Enter(x) => f.debug_tuple("AstWalkStep::Enter").field(x).finish(),
|
||||
Self::Exit(x) => f.debug_tuple("AstWalkStep::Exit").field(x).finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AstWalk<'a> {
|
||||
_pin: PhantomPinned,
|
||||
child_stack: Vec<usize>,
|
||||
node_stack: Vec<&'a Node>,
|
||||
}
|
||||
|
||||
impl<'a> AstWalk<'a> {
|
||||
pub fn new(root: &'a Node) -> Self {
|
||||
let mut res = Self {
|
||||
_pin: PhantomPinned {},
|
||||
node_stack: Vec::with_capacity(32),
|
||||
child_stack: Vec::with_capacity(32),
|
||||
};
|
||||
|
||||
res.node_stack.push(root);
|
||||
return res;
|
||||
}
|
||||
|
||||
fn _next_inner(&mut self) -> Option<AstWalkStep<'a, Node>> {
|
||||
if self.node_stack.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let current_node = *self.node_stack.last().unwrap();
|
||||
|
||||
// The index of the next child we should look at.
|
||||
// If `None`, we look at the parent.
|
||||
let current_child = {
|
||||
let n_nodes = self.node_stack.len();
|
||||
let n_childs = self.child_stack.len();
|
||||
match n_nodes - n_childs {
|
||||
2.. => unreachable!(),
|
||||
1 => None,
|
||||
0 => Some(self.child_stack.pop().unwrap()),
|
||||
}
|
||||
};
|
||||
|
||||
match current_child {
|
||||
None => {
|
||||
self.child_stack.push(0);
|
||||
return Some(AstWalkStep::Enter(current_node));
|
||||
}
|
||||
|
||||
Some(current_child) => {
|
||||
let child = current_node
|
||||
.children()
|
||||
.map(|x| x.get(current_child))
|
||||
.flatten();
|
||||
|
||||
match child {
|
||||
None => {
|
||||
self.node_stack.pop();
|
||||
return Some(AstWalkStep::Exit(current_node));
|
||||
}
|
||||
|
||||
Some(x) => {
|
||||
self.child_stack.push(current_child + 1);
|
||||
self.node_stack.push(&x);
|
||||
self.child_stack.push(0);
|
||||
return Some(AstWalkStep::Enter(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for AstWalk<'a> {
|
||||
type Item = AstWalkStep<'a, Node>;
|
||||
|
||||
fn next(self: &mut Self) -> Option<Self::Item> {
|
||||
return self._next_inner();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// MARK: tests
|
||||
//
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use markdown::mdast::{Emphasis, Paragraph, Root, Strong, Text};
|
||||
|
||||
#[test]
|
||||
fn single_leaf() {
|
||||
let node = Node::Text(Text {
|
||||
value: "Hello".to_string(),
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalk::new(&node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
assert_eq!(steps.len(), 2);
|
||||
assert!(matches!(steps[0], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_child() {
|
||||
let node = Node::Paragraph(Paragraph {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "Hello".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalk::new(&node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Should be: Enter(Paragraph), Leaf(Text), Exit(Paragraph)
|
||||
assert_eq!(steps.len(), 4);
|
||||
assert!(matches!(steps[0], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[2], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[3], AstWalkStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_children() {
|
||||
let node = Node::Paragraph(Paragraph {
|
||||
children: vec![
|
||||
Node::Text(Text {
|
||||
value: "Hello".to_string(),
|
||||
position: None,
|
||||
}),
|
||||
Node::Text(Text {
|
||||
value: " ".to_string(),
|
||||
position: None,
|
||||
}),
|
||||
Node::Text(Text {
|
||||
value: "World".to_string(),
|
||||
position: None,
|
||||
}),
|
||||
],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalk::new(&node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Should be: Enter(Paragraph), Leaf(Text1), Leaf(Text2), Leaf(Text3), Exit(Paragraph)
|
||||
assert_eq!(steps.len(), 8);
|
||||
assert!(matches!(steps[0], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[2], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[3], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[4], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[5], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[6], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[7], AstWalkStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_1() {
|
||||
let node = Node::Paragraph(Paragraph {
|
||||
children: vec![Node::Emphasis(Emphasis {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "emphasized".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalk::new(&node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Should be: Enter(Paragraph), Enter(Emphasis), Leaf(Text), Exit(Emphasis), Exit(Paragraph)
|
||||
assert_eq!(steps.len(), 6);
|
||||
assert!(matches!(steps[0], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[2], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[3], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[4], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[5], AstWalkStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_2() {
|
||||
// Create: Paragraph -> [Text, Strong -> Text, Text]
|
||||
let node = Node::Paragraph(Paragraph {
|
||||
children: vec![
|
||||
Node::Text(Text {
|
||||
value: "Before ".to_string(),
|
||||
position: None,
|
||||
}),
|
||||
Node::Strong(Strong {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "bold".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
}),
|
||||
Node::Text(Text {
|
||||
value: " after".to_string(),
|
||||
position: None,
|
||||
}),
|
||||
],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalk::new(&node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Expected order:
|
||||
// 0: Enter(Paragraph)
|
||||
// 1: Leaf(Text "Before ")
|
||||
// 2: Enter(Strong)
|
||||
// 3: Leaf(Text "bold")
|
||||
// 4: Exit(Strong)
|
||||
// 5: Leaf(Text " after")
|
||||
// 6: Exit(Paragraph)
|
||||
assert_eq!(steps.len(), 10);
|
||||
assert!(matches!(steps[0], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[2], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[3], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[4], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[5], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[6], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[7], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[8], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[9], AstWalkStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_3() {
|
||||
let node = Node::Paragraph(Paragraph {
|
||||
children: vec![Node::Emphasis(Emphasis {
|
||||
children: vec![Node::Strong(Strong {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "deeply nested".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalk::new(&node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Should be: Enter(Paragraph), Enter(Emphasis), Enter(Strong), Leaf(Text), Exit(Strong), Exit(Emphasis), Exit(Paragraph)
|
||||
assert_eq!(steps.len(), 8);
|
||||
assert!(matches!(steps[0], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[2], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[3], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[4], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[5], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[6], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[7], AstWalkStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_parent() {
|
||||
let node = Node::Paragraph(Paragraph {
|
||||
children: vec![],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalk::new(&node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Should be: Enter(Paragraph), Exit(Paragraph)
|
||||
assert_eq!(steps.len(), 2);
|
||||
assert!(matches!(steps[0], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_paragraphs() {
|
||||
let node = Node::Root(Root {
|
||||
children: vec![
|
||||
Node::Paragraph(Paragraph {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "First".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
}),
|
||||
Node::Paragraph(Paragraph {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "Second".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
}),
|
||||
],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalk::new(&node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Expected order:
|
||||
// 0: Enter(Root)
|
||||
// 1: Enter(Paragraph)
|
||||
// 2: Enter(Text "First")
|
||||
// 2: Exit(Text "First")
|
||||
// 3: Exit(Paragraph)
|
||||
// 4: Enter(Paragraph)
|
||||
// 5: Enter(Text "Second")
|
||||
// 5: Exit(Text "Second")
|
||||
// 6: Exit(Paragraph)
|
||||
// 7: Exit(Root)
|
||||
assert_eq!(steps.len(), 10);
|
||||
assert!(matches!(steps[0], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[2], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[3], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[4], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[5], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[6], AstWalkStep::Enter(_)));
|
||||
assert!(matches!(steps[7], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[8], AstWalkStep::Exit(_)));
|
||||
assert!(matches!(steps[9], AstWalkStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enter_exit() {
|
||||
let node = Node::Root(Root {
|
||||
children: vec![Node::Paragraph(Paragraph {
|
||||
children: vec![
|
||||
Node::Emphasis(Emphasis {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "a".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
}),
|
||||
Node::Strong(Strong {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "b".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
}),
|
||||
],
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalk::new(&node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
let enter_count = steps
|
||||
.iter()
|
||||
.filter(|s| matches!(s, AstWalkStep::Enter(_)))
|
||||
.count();
|
||||
let exit_count = steps
|
||||
.iter()
|
||||
.filter(|s| matches!(s, AstWalkStep::Exit(_)))
|
||||
.count();
|
||||
|
||||
assert_eq!(enter_count, exit_count);
|
||||
assert_eq!(enter_count, 6);
|
||||
}
|
||||
}
|
||||
@@ -1,378 +0,0 @@
|
||||
use markdown::mdast::Node;
|
||||
use std::{fmt::Debug, marker::PhantomData};
|
||||
|
||||
pub enum AstWalkMutStep<'a, T> {
|
||||
Enter(&'a T),
|
||||
Exit(&'a mut T),
|
||||
}
|
||||
|
||||
impl<T: Debug> Debug for AstWalkMutStep<'_, T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Enter(x) => f.debug_tuple("AstWalkMutStep::Enter").field(x).finish(),
|
||||
Self::Exit(x) => f.debug_tuple("AstWalkMutStep::Exit").field(x).finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AstWalkMut<'a> {
|
||||
_life: PhantomData<&'a mut Node>,
|
||||
child_stack: Vec<usize>,
|
||||
node_stack: Vec<*mut Node>,
|
||||
}
|
||||
|
||||
impl<'a> AstWalkMut<'a> {
|
||||
pub fn new(root: &'a mut Node) -> Self {
|
||||
let mut res = Self {
|
||||
_life: PhantomData,
|
||||
node_stack: Vec::with_capacity(32),
|
||||
child_stack: Vec::with_capacity(32),
|
||||
};
|
||||
|
||||
res.node_stack.push(root);
|
||||
return res;
|
||||
}
|
||||
|
||||
fn _next_inner(&mut self) -> Option<AstWalkMutStep<'a, Node>> {
|
||||
if self.node_stack.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let current_node = unsafe { &mut **self.node_stack.last().unwrap_unchecked() };
|
||||
|
||||
// The index of the next child we should look at.
|
||||
// If `None`, we look at the parent.
|
||||
let current_child = {
|
||||
let n_nodes = self.node_stack.len();
|
||||
let n_childs = self.child_stack.len();
|
||||
match n_nodes - n_childs {
|
||||
2.. => unreachable!(),
|
||||
1 => None,
|
||||
0 => Some(self.child_stack.pop().unwrap()),
|
||||
}
|
||||
};
|
||||
|
||||
match current_child {
|
||||
None => {
|
||||
self.child_stack.push(0);
|
||||
return Some(AstWalkMutStep::Enter(current_node));
|
||||
}
|
||||
|
||||
Some(current_child) => {
|
||||
if current_node.children().is_none()
|
||||
|| current_child >= current_node.children().unwrap().len()
|
||||
{
|
||||
self.node_stack.pop();
|
||||
return Some(AstWalkMutStep::Exit(current_node));
|
||||
}
|
||||
|
||||
let child = &mut current_node.children_mut().unwrap()[current_child];
|
||||
|
||||
self.child_stack.push(current_child + 1);
|
||||
self.node_stack.push(child);
|
||||
self.child_stack.push(0);
|
||||
return Some(AstWalkMutStep::Enter(child));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for AstWalkMut<'a> {
|
||||
type Item = AstWalkMutStep<'a, Node>;
|
||||
|
||||
fn next(self: &mut Self) -> Option<Self::Item> {
|
||||
return self._next_inner();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// MARK: tests
|
||||
//
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use markdown::mdast::{Emphasis, Paragraph, Root, Strong, Text};
|
||||
|
||||
#[test]
|
||||
fn single_leaf() {
|
||||
let mut node = Node::Text(Text {
|
||||
value: "Hello".to_string(),
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalkMut::new(&mut node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
assert_eq!(steps.len(), 2);
|
||||
assert!(matches!(steps[0], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkMutStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_child() {
|
||||
let mut node = Node::Paragraph(Paragraph {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "Hello".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalkMut::new(&mut node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Should be: Enter(Paragraph), Leaf(Text), Exit(Paragraph)
|
||||
assert_eq!(steps.len(), 4);
|
||||
assert!(matches!(steps[0], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[2], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[3], AstWalkMutStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_children() {
|
||||
let mut node = Node::Paragraph(Paragraph {
|
||||
children: vec![
|
||||
Node::Text(Text {
|
||||
value: "Hello".to_string(),
|
||||
position: None,
|
||||
}),
|
||||
Node::Text(Text {
|
||||
value: " ".to_string(),
|
||||
position: None,
|
||||
}),
|
||||
Node::Text(Text {
|
||||
value: "World".to_string(),
|
||||
position: None,
|
||||
}),
|
||||
],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalkMut::new(&mut node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Should be: Enter(Paragraph), Leaf(Text1), Leaf(Text2), Leaf(Text3), Exit(Paragraph)
|
||||
assert_eq!(steps.len(), 8);
|
||||
assert!(matches!(steps[0], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[2], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[3], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[4], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[5], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[6], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[7], AstWalkMutStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_1() {
|
||||
let mut node = Node::Paragraph(Paragraph {
|
||||
children: vec![Node::Emphasis(Emphasis {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "emphasized".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalkMut::new(&mut node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Should be: Enter(Paragraph), Enter(Emphasis), Leaf(Text), Exit(Emphasis), Exit(Paragraph)
|
||||
assert_eq!(steps.len(), 6);
|
||||
assert!(matches!(steps[0], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[2], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[3], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[4], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[5], AstWalkMutStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_2() {
|
||||
// Create: Paragraph -> [Text, Strong -> Text, Text]
|
||||
let mut node = Node::Paragraph(Paragraph {
|
||||
children: vec![
|
||||
Node::Text(Text {
|
||||
value: "Before ".to_string(),
|
||||
position: None,
|
||||
}),
|
||||
Node::Strong(Strong {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "bold".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
}),
|
||||
Node::Text(Text {
|
||||
value: " after".to_string(),
|
||||
position: None,
|
||||
}),
|
||||
],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalkMut::new(&mut node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Expected order:
|
||||
// 0: Enter(Paragraph)
|
||||
// 1: Leaf(Text "Before ")
|
||||
// 2: Enter(Strong)
|
||||
// 3: Leaf(Text "bold")
|
||||
// 4: Exit(Strong)
|
||||
// 5: Leaf(Text " after")
|
||||
// 6: Exit(Paragraph)
|
||||
assert_eq!(steps.len(), 10);
|
||||
assert!(matches!(steps[0], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[2], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[3], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[4], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[5], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[6], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[7], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[8], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[9], AstWalkMutStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_3() {
|
||||
let mut node = Node::Paragraph(Paragraph {
|
||||
children: vec![Node::Emphasis(Emphasis {
|
||||
children: vec![Node::Strong(Strong {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "deeply nested".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalkMut::new(&mut node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Should be: Enter(Paragraph), Enter(Emphasis), Enter(Strong), Leaf(Text), Exit(Strong), Exit(Emphasis), Exit(Paragraph)
|
||||
assert_eq!(steps.len(), 8);
|
||||
assert!(matches!(steps[0], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[2], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[3], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[4], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[5], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[6], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[7], AstWalkMutStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_parent() {
|
||||
let mut node = Node::Paragraph(Paragraph {
|
||||
children: vec![],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalkMut::new(&mut node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Should be: Enter(Paragraph), Exit(Paragraph)
|
||||
assert_eq!(steps.len(), 2);
|
||||
assert!(matches!(steps[0], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkMutStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_paragraphs() {
|
||||
let mut node = Node::Root(Root {
|
||||
children: vec![
|
||||
Node::Paragraph(Paragraph {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "First".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
}),
|
||||
Node::Paragraph(Paragraph {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "Second".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
}),
|
||||
],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalkMut::new(&mut node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
// Expected order:
|
||||
// 0: Enter(Root)
|
||||
// 1: Enter(Paragraph)
|
||||
// 2: Enter(Text "First")
|
||||
// 2: Exit(Text "First")
|
||||
// 3: Exit(Paragraph)
|
||||
// 4: Enter(Paragraph)
|
||||
// 5: Enter(Text "Second")
|
||||
// 5: Exit(Text "Second")
|
||||
// 6: Exit(Paragraph)
|
||||
// 7: Exit(Root)
|
||||
assert_eq!(steps.len(), 10);
|
||||
assert!(matches!(steps[0], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[1], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[2], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[3], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[4], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[5], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[6], AstWalkMutStep::Enter(_)));
|
||||
assert!(matches!(steps[7], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[8], AstWalkMutStep::Exit(_)));
|
||||
assert!(matches!(steps[9], AstWalkMutStep::Exit(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enter_exit() {
|
||||
let mut node = Node::Root(Root {
|
||||
children: vec![Node::Paragraph(Paragraph {
|
||||
children: vec![
|
||||
Node::Emphasis(Emphasis {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "a".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
}),
|
||||
Node::Strong(Strong {
|
||||
children: vec![Node::Text(Text {
|
||||
value: "b".to_string(),
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
}),
|
||||
],
|
||||
position: None,
|
||||
})],
|
||||
position: None,
|
||||
});
|
||||
|
||||
let walker = AstWalkMut::new(&mut node);
|
||||
let steps: Vec<_> = walker.collect();
|
||||
|
||||
let enter_count = steps
|
||||
.iter()
|
||||
.filter(|s| matches!(s, AstWalkMutStep::Enter(_)))
|
||||
.count();
|
||||
let exit_count = steps
|
||||
.iter()
|
||||
.filter(|s| matches!(s, AstWalkMutStep::Exit(_)))
|
||||
.count();
|
||||
|
||||
assert_eq!(enter_count, exit_count);
|
||||
assert_eq!(enter_count, 6);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ use axum::Router;
|
||||
use libservice::ToService;
|
||||
use utoipa::OpenApi;
|
||||
|
||||
mod ast;
|
||||
mod components;
|
||||
mod routes;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user