adblock-list-compiler 0.0.8

CLI tool to compile multiple adblock list sources into a single file
Documentation
use addr::parse_domain_name;
use lazy_static::lazy_static;
use regex::Regex;
use thiserror::Error;

#[derive(Debug, Eq, Hash, PartialEq)]
pub struct Domain(pub String);

fn parse_domain(value: &str) -> Option<Domain> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"(?P<domain>.{2,200}\.[a-z]{2,6})").unwrap();
    }

    RE.captures(value)
        .and_then(|cap| cap.name("domain"))
        .and_then(|d| {
            if d.as_str().starts_with("*.") {
                let as_str = d.as_str().replace("*.", "");
                parse_domain_name(&as_str)
                    .ok()
                    .map(|v| "*.".to_string() + v.as_str())
            } else {
                parse_domain_name(d.as_str())
                    .ok()
                    .map(|v| v.as_str().trim().to_string())
            }
        })
        .map(|d| d.as_str().trim().to_string())
        .and_then(|d| idna::domain_to_ascii(&d).ok())
        .map(Domain)
}

impl Domain {
    pub fn parse(value: &str) -> Option<Domain> {
        parse_domain(value)
    }
}

#[derive(Error, Debug)]
#[error("ParseDomainError")]
pub struct ParseDomainError;

impl TryFrom<&str> for Domain {
    type Error = ParseDomainError;

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        match parse_domain(value) {
            Some(d) => Ok(d),
            None => Err(ParseDomainError),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn test_parse_domain(input: &str, expected: &str) {
        let domain = Domain(expected.to_string());
        let output = Domain::parse(input);
        assert_eq!(output, Some(domain));
    }

    fn test_parse_domain_none(input: &str) {
        let output = Domain::parse(input);
        assert_eq!(output, None);
    }

    #[test]
    fn it_extract_domain() {
        test_parse_domain("abc.example.com", "abc.example.com");
        test_parse_domain("Bücher.example.com", "xn--bcher-kva.example.com");
        test_parse_domain_none("");
        test_parse_domain_none("# abc.example.com");
    }
}