perl-regex 0.14.0

Regex parsing and validation helpers for Perl syntax
Documentation
mod code_execution;
mod complexity;
mod config;
mod group;
mod nested_quantifier;

pub use config::RegexValidationConfig;

use crate::error::RegexError;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RegexFinding {
    pub offset: usize,
    pub message: &'static str,
}

pub struct RegexValidator {
    config: RegexValidationConfig,
}

impl Default for RegexValidator {
    fn default() -> Self {
        Self::new()
    }
}

impl RegexValidator {
    pub fn new() -> Self {
        Self { config: RegexValidationConfig::default() }
    }

    pub fn with_config(config: RegexValidationConfig) -> Self {
        Self { config }
    }

    pub fn config(&self) -> &RegexValidationConfig {
        &self.config
    }

    pub fn validate(&self, pattern: &str, start_pos: usize) -> Result<(), RegexError> {
        if let Some(finding) = self.find_code_execution(pattern, start_pos) {
            return Err(RegexError::syntax(finding.message, finding.offset));
        }
        if let Some(finding) = self.find_nested_quantifier(pattern, start_pos) {
            return Err(RegexError::syntax(finding.message, finding.offset));
        }
        complexity::check_complexity(pattern, start_pos, &self.config)
    }

    pub fn detects_code_execution(&self, pattern: &str) -> bool {
        code_execution::detects_code_execution(pattern)
    }

    pub fn detect_nested_quantifiers(&self, pattern: &str) -> bool {
        nested_quantifier::detect_nested_quantifiers(pattern)
    }

    pub fn find_code_execution(&self, pattern: &str, start_pos: usize) -> Option<RegexFinding> {
        code_execution::find_code_execution(pattern, start_pos).map(|finding| {
            let message = match finding.kind {
                code_execution::EmbeddedCodeKind::Immediate => {
                    "Embedded code execution is not allowed in regex patterns"
                }
                code_execution::EmbeddedCodeKind::Deferred => {
                    "Deferred embedded code execution is not allowed in regex patterns"
                }
            };
            RegexFinding { offset: finding.offset, message }
        })
    }

    pub fn find_nested_quantifier(&self, pattern: &str, start_pos: usize) -> Option<RegexFinding> {
        nested_quantifier::find_nested_quantifier(pattern, start_pos).map(|offset| RegexFinding {
            offset,
            message: "Nested quantifiers may cause catastrophic backtracking",
        })
    }
}