Output
The output module combines a formatter and a writer to produce scan results in the requested format and destination.
Output
#![allow(unused)] fn main() { pub struct Output { writer: WriterImpl, formatter: FormatterImpl, } }
Constructor
#![allow(unused)] fn main() { pub fn new( output_format: OutputFormat, output_path: Option<PathBuf>, ) -> Result<Self, TowlOutputError> }
Creates an output handler by selecting the appropriate formatter and writer.
Format-to-writer mapping:
| Format | Writer | Output path |
|---|---|---|
Table / Terminal | StdoutWriter | Must be None |
Json | FileWriter | Required, must end in .json |
Csv | FileWriter | Required, must end in .csv |
Toml | FileWriter | Required, must end in .toml |
Markdown | FileWriter | Required, must end in .md |
save
#![allow(unused)] fn main() { pub async fn save(&self, todos: &[TodoComment]) -> Result<(), TowlOutputError> }
Formats the TODOs and writes them to the destination. TODOs are grouped by type before formatting.
OutputFormat
#![allow(unused)] fn main() { pub enum OutputFormat { Table, Json, Csv, Toml, Markdown, Terminal, } }
Used as a CLI argument via clap::ValueEnum. Table and Terminal are treated identically.
Formatter Dispatch
Internally, FormatterImpl is an enum that dispatches to the correct formatter without dynamic dispatch:
#![allow(unused)] fn main() { pub(crate) enum FormatterImpl { Csv(CsvFormatter), Json(JsonFormatter), Markdown(MarkdownFormatter), Table(TableFormatter), Toml(TomlFormatter), } }
Each formatter implements the internal Formatter trait:
#![allow(unused)] fn main() { pub(crate) trait Formatter { fn format( &self, todos: &HashMap<&TodoType, Vec<&TodoComment>>, total_count: usize, ) -> Result<Vec<String>, FormatterError>; } }
Writer Dispatch
WriterImpl dispatches between stdout and file output:
#![allow(unused)] fn main() { pub(crate) enum WriterImpl { Stdout(StdoutWriter), File(FileWriter), } }
Each writer implements the internal Writer trait:
#![allow(unused)] fn main() { pub(crate) trait Writer { async fn write(&self, content: Vec<String>) -> Result<(), WriterError>; } }
FileWriter
Validates the output path on construction:
- Rejects path traversal (
..components) - Resolves symlinks before writing
StdoutWriter
Writes each formatted line to stdout followed by a newline.
Errors
TowlOutputError
#![allow(unused)] fn main() { pub enum TowlOutputError { InvalidOutputPath(String), UnableToFormatTodos(FormatterError), UnableToWriteTodos(WriterError), } }
FormatterError
#![allow(unused)] fn main() { pub enum FormatterError { SerializationError(String), IntegerOverflow(usize), } }
WriterError
#![allow(unused)] fn main() { pub enum WriterError { IoError(std::io::Error), PathTraversal(PathBuf), } }