Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Scanner

The scanner walks a directory tree, filters files by extension and exclude patterns, reads content, and delegates to the parser for TODO extraction.

Scanner

#![allow(unused)]
fn main() {
pub struct Scanner {
    parser: Parser,
    config: ParsingConfig,
}
}

Constructor

#![allow(unused)]
fn main() {
pub fn new(config: ParsingConfig) -> Result<Self, TowlScannerError>
}

Creates a new scanner. Compiles all regex patterns from the config during construction so pattern errors are caught early.

scan

#![allow(unused)]
fn main() {
pub async fn scan(&self, path: PathBuf) -> Result<ScanResult, TowlScannerError>
}

Recursively scans path for TODO comments. Returns a ScanResult on success.

Behaviour:

  1. Validates the path (rejects path traversal)
  2. Walks the directory using the ignore crate (respects .gitignore)
  3. Filters files by extension (file_extensions config)
  4. Skips files matching exclude_patterns
  5. Skips files larger than MAX_FILE_SIZE (10 MB)
  6. Reads and parses each file asynchronously via tokio::fs
  7. Collects results until a resource limit is reached or the walk completes

Errors:

  • InvalidPath -- Path contains traversal components (..)
  • FileTooLarge -- File exceeds 10 MB
  • TooManyTodos -- Single file exceeds 10,000 TODOs
  • TooManyFiles -- Walk exceeds 100,000 files
  • UnableToReadFileAtPath -- I/O error reading a specific file
  • UnableToWalkFile -- Directory walk error
  • ParsingError -- Regex or parsing failure (propagated from parser)

ScanResult

#![allow(unused)]
fn main() {
pub struct ScanResult {
    pub todos: Vec<TodoComment>,
    pub files_scanned: usize,
    pub files_skipped: usize,
    pub files_errored: usize,
    pub duration: std::time::Duration,
}
}

Methods

#![allow(unused)]
fn main() {
pub const fn all_files_failed(&self) -> bool
}

Returns true when files_scanned == 0 and files_errored > 0. Indicates a likely permissions or path issue where no files could be read.

#![allow(unused)]
fn main() {
pub const fn is_clean(&self) -> bool
}

Returns true when todos is empty and files_errored == 0. A clean scan with no issues.

Resource Limits

ConstantValueTrigger
MAX_FILE_SIZE10,485,760 bytes (10 MB)File skipped
MAX_TODO_COUNT10,000Error for that file
MAX_TOTAL_TODO_COUNT100,000Scan stops, returns partial
MAX_FILES_SCANNED100,000Scan stops, returns partial

Example

#![allow(unused)]
fn main() {
use towl::config::ParsingConfig;
use towl::scanner::Scanner;
use std::path::PathBuf;

let config = ParsingConfig::default();
let scanner = Scanner::new(config)?;
let result = scanner.scan(PathBuf::from(".")).await?;

println!("Found {} TODOs in {} files", result.todos.len(), result.files_scanned);

if result.all_files_failed() {
    eprintln!("Warning: no files could be read");
}
}