lint 0.1.3

A versatile linting tool with CLI, MCP, and library interfaces
Documentation
use crate::output::{LintMessage, Severity};
use crate::rules::Rule;
use regex::Regex;
use std::path::Path;
use std::sync::LazyLock;

pub struct UnsafeEvalRule;

static EVAL_PATTERN: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\beval\s*\(").unwrap());

impl Rule for UnsafeEvalRule {
    fn name(&self) -> &str {
        "unsafe-eval"
    }

    fn category(&self) -> &str {
        "security"
    }

    fn description(&self) -> &str {
        "Detects unsafe eval() calls which can lead to code injection vulnerabilities."
    }

    fn default_severity(&self) -> Severity {
        Severity::Error
    }

    fn check(&self, content: &str, file_path: &Path) -> Vec<LintMessage> {
        let mut messages = Vec::new();
        let ext = file_path.extension().and_then(|e| e.to_str()).unwrap_or("");
        if !matches!(ext, "js" | "ts" | "jsx" | "tsx") {
            return messages;
        }
        let pattern = &*EVAL_PATTERN;
        for (line_num, line) in content.lines().enumerate() {
            if pattern.is_match(line) && !line.trim_start().starts_with("//") {
                messages.push(LintMessage::new(
                    line_num + 1,
                    line.find("eval").unwrap_or(0),
                    self.default_severity(),
                    "Unsafe eval() call detected".to_string(),
                    self.name().to_string(),
                    Some("Avoid eval(). Use JSON.parse for JSON data, or structured parsing for other formats".to_string()),
                ));
            }
        }
        messages
    }
}