gitignore-in 0.2.1

A command line tool for managing .gitignore files with gitignore.in
pub(crate) const GENERATED_HEADER_LINES: [&str; 5] = [
    "# DO NOT EDIT THIS FILE",
    "# Generated by gitignore.in",
    "# See https://gitignore.in/",
    "# Edit .gitignore.in instead of this file",
    "# Run `gitignore.in` to build .gitignore",
];

// build .gitignore from .gitignore.in script

use crate::{
    gi::gi_command,
    gibo::gibo_command,
    script::{Comment, Echo, Gi, Gibo, GitIgnoreIn, GitIgnoreStatement, Meaningless},
};

pub(crate) fn build(script: GitIgnoreIn) -> std::io::Result<String> {
    let mut result = String::new();
    for line in GENERATED_HEADER_LINES {
        result.push_str(line);
        result.push('\n');
    }
    for statement in script.content {
        match statement {
            GitIgnoreStatement::Comment(Comment::Content(c)) => {
                result.push_str(&format!("# {c}\n"));
            }
            GitIgnoreStatement::Meaningless(Meaningless::Content(_m)) => {}
            GitIgnoreStatement::Gibo(Gibo::Target(target)) => {
                let content = gibo_command(&target)?;
                result.push_str(&separator());
                result.push_str(&format!("# gibo dump {target}\n"));
                result.push_str(&content);
            }
            GitIgnoreStatement::Gi(Gi::Target(target)) => {
                let content = gi_command(&target)?;
                result.push_str(&separator());
                result.push_str(&format!("# gi {target}\n"));
                result.push_str(&content);
            }
            GitIgnoreStatement::Echo(Echo::Content(echo)) => {
                result.push_str(&separator());
                result.push_str(&format!("{echo}\n"));
            }
        }
    }
    Ok(result)
}

fn separator() -> String {
    "# -----------------------------------------------------------------------------\n".to_string()
}

#[cfg(test)]
mod tests {
    use crate::parser::parse_text;

    use super::*;

    #[test]
    fn test_parse_text() {
        let text = r#"# comment
function meaningless() { echo "meaningless" }
gibo dump C++
gi C++
echo hello
"#;
        let result = parse_text(text);
        let result = build(result).unwrap();
        assert!(result.contains("# gi C++"));
        assert!(result.contains("# Created by https://www.toptal.com/developers/gitignore/api/C++"));
        assert!(
            result.contains("# Edit at https://www.toptal.com/developers/gitignore?templates=C++")
        );
        assert!(result.contains("# gibo dump C++"));
        assert!(result.contains("# Generated by gibo (https://github.com/simonwhitaker/gibo)"));
        assert!(result.contains("hello"));
    }

    #[test]
    fn generated_header_includes_official_site() {
        let result = build(GitIgnoreIn {
            content: Vec::new(),
        })
        .unwrap();
        assert!(result.contains("# See https://gitignore.in/"));
    }
}