use std::fs;
use std::io::{BufRead, BufReader};
use aurora_core::{AuroraError, AuroraResult, Pipeline, Value};
use regex::Regex;
use walkdir::WalkDir;
pub fn find_todos(path: &str) -> AuroraResult<Pipeline> {
let pattern = r"(TODO|FIXME|HACK|XXX|BUG|OPTIMIZE|NOTE)[: ]?(.*)";
let re = Regex::new(pattern)
.map_err(|e| AuroraError::ContextError(format!("regex: {e}")))?;
let headers = vec![
"file".to_string(),
"line".to_string(),
"tag".to_string(),
"comment".to_string(),
];
let mut rows: Vec<Vec<Value>> = Vec::new();
for entry in WalkDir::new(path)
.follow_links(false)
.into_iter()
.filter_entry(|e| {
let name = e.file_name().to_string_lossy();
name != "target" && name != ".git" && name != "node_modules" && !name.starts_with('.')
})
.filter_map(|e| e.ok())
{
if !entry.file_type().is_file() {
continue;
}
let file_path = entry.path().to_string_lossy().to_string();
let file = match fs::File::open(entry.path()) {
Ok(f) => f,
Err(_) => continue,
};
let reader = BufReader::new(file);
for (line_no, line) in reader.lines().enumerate() {
let line = match line {
Ok(l) => l,
Err(_) => continue,
};
for cap in re.captures_iter(&line) {
let tag = cap.get(1)
.map(|m| m.as_str().to_string())
.unwrap_or_default();
let comment = cap.get(2)
.map(|m| m.as_str().trim().to_string())
.unwrap_or_default();
rows.push(vec![
Value::String(file_path.clone()),
Value::Int((line_no + 1) as i64),
Value::String(tag),
Value::String(comment),
]);
}
}
}
Ok(Pipeline::table(headers, rows))
}