mod ast;
mod error;
mod lexer;
mod parser;
mod token;
pub use ast::CommitAst;
pub use error::CompileError;
use lexer::Lexer;
use parser::Parser;
#[derive(Debug, Default)]
pub struct CompilerPipeline;
impl CompilerPipeline {
pub fn new() -> Self {
Self
}
pub fn compile(&self, input: &str) -> Result<CommitAst, CompileError> {
let tokens = Lexer::new(input).tokenize()?;
Parser::new(tokens).parse()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compiles_minimal() {
let ast = CompilerPipeline::new().compile("feat: add login").unwrap();
assert_eq!(ast.header.commit_type, "feat");
assert_eq!(ast.header.description, "add login");
}
#[test]
fn compiles_full() {
let input = "feat(auth)!: migrate to OAuth\n\n\
Body text here.\n\n\
BREAKING CHANGE: sessions invalidated\n\
Refs: #42";
let ast = CompilerPipeline::new().compile(input).unwrap();
assert_eq!(ast.header.commit_type, "feat");
assert_eq!(ast.header.scope, Some("auth".into()));
assert!(ast.header.breaking);
assert!(ast.body.is_some());
assert_eq!(ast.footers.len(), 2);
}
#[test]
fn compile_error_on_missing_colon() {
let result = CompilerPipeline::new().compile("feat add something");
assert!(matches!(result, Err(CompileError::Lex(_))));
}
#[test]
fn unknown_type_is_not_a_compile_error() {
let ast = CompilerPipeline::new()
.compile("notavalidtype: do something")
.unwrap();
assert_eq!(ast.header.commit_type, "notavalidtype");
}
}