yamd 0.19.0

Yet Another Markdown Document (flavour)
Documentation
use crate::{
    lexer::{Token, TokenKind},
    op::{Node, Op, Parser},
};

fn is_three_dashes(t: &Token) -> bool {
    t.kind == TokenKind::Minus && t.position.column == 0 && t.range.len() == 3
}

pub fn metadata(p: &mut Parser) -> bool {
    let start = p.pos;
    let Some(start_range) = p.eat(is_three_dashes) else {
        return false;
    };

    let Some((body_range, end_range)) = p.eat_until(is_three_dashes) else {
        p.pos = start;
        return false;
    };

    let start_content = p.span(start_range);
    let body_content = p.span(body_range);
    let end_content = p.span(end_range);
    p.ops.push(Op::new_start(Node::Metadata, start_content));
    p.ops.push(Op::new_value(body_content));
    p.ops.push(Op::new_end(Node::Metadata, end_content));
    true
}

#[cfg(test)]
mod tests {
    use crate::{
        lexer::{Position, Token, TokenKind},
        op::{Node, Op, metadata::metadata},
    };

    #[test]
    fn happy_path() {
        let mut p = "---\ncontent\n---".into();
        assert!(metadata(&mut p));
        assert_eq!(
            p.ops,
            vec![
                Op::new_start(Node::Metadata, p.span(0..1)),
                Op::new_value(p.span(1..4)),
                Op::new_end(Node::Metadata, p.span(4..5)),
            ]
        );
    }

    #[test]
    fn no_closing_delimiter() {
        let mut p = "---\ncontent".into();
        assert!(!metadata(&mut p));
        assert!(p.ops.is_empty());
        assert_eq!(
            p.peek(),
            Some((0, &Token::new(TokenKind::Minus, 0..3, Position::default())))
        );
    }

    #[test]
    fn no_content() {
        let mut p = "---\n---".into();
        assert!(metadata(&mut p));
        assert_eq!(
            p.ops,
            vec![
                Op::new_start(Node::Metadata, p.span(0..1)),
                Op::new_value(p.span(1..2)),
                Op::new_end(Node::Metadata, p.span(2..3)),
            ],
        );
    }

    #[test]
    fn only_opening_token() {
        let mut p = "---".into();
        assert!(!metadata(&mut p));
        assert!(p.ops.is_empty());
        assert_eq!(
            p.peek(),
            Some((0, &Token::new(TokenKind::Minus, 0..3, Position::default())))
        );
    }
}