Remove old html code

This commit is contained in:
2025-11-03 09:54:45 -08:00
parent 4ee5c16098
commit 05bdac5b4f
4 changed files with 0 additions and 768 deletions

View File

@@ -1,5 +0,0 @@
mod walk;
pub use walk::*;
mod walk_mut;
pub use walk_mut::*;

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -2,7 +2,6 @@ use axum::Router;
use libservice::ToService;
use utoipa::OpenApi;
mod ast;
mod components;
mod routes;