diff --git a/readme.md b/readme.md index 2f9275f..1065ab5 100644 --- a/readme.md +++ b/readme.md @@ -128,7 +128,7 @@ The list includes the comment text, the file path, and additional metadata, such Todoctor supports the following command-line options: -### --month \ +### --month Specifies the number of months to include when tracking TODOs in the repository. If not provided, defaults to 3 months. @@ -191,6 +191,16 @@ Example: todoctor --exclude-keywords WARNING --exclude-keywords DEPRECATED ``` +### --output-format + +You can specify the format of the report. Possible options are `html` and `json`. The default value is `html`. + +Example: + +```sh +todoctor --output-format json +``` + ### --output You can define the folder where the report file will be saved. By default it is `todoctor` folder in the project root. diff --git a/src/main.rs b/src/main.rs index caf618e..c081c1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,8 @@ -use clap::{ArgAction, CommandFactory, Parser}; +use clap::{ArgAction, CommandFactory, Parser, ValueEnum}; use futures::future::join_all; use indicatif::{ProgressBar, ProgressStyle}; use open; -use serde_json::json; +use serde_json::{json, Value}; use std::fs::File; use std::io::{self, BufRead, BufReader, BufWriter, Write}; use std::path::{Path, PathBuf}; @@ -33,6 +33,12 @@ use tokio::sync::Semaphore; const HISTORY_TEMP_FILE: &str = "todo_history_temp.json"; +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)] +enum OutputFormat { + Html, + Json, +} + #[derive(Parser, Debug)] #[command( name = "todoctor", @@ -58,6 +64,10 @@ struct Cli { #[arg(short = 'E', long, action = ArgAction::Append)] exclude_keywords: Vec, + /// Output format + #[arg(short, long, default_value = "html")] + output_format: OutputFormat, + /// Output directory #[arg(short, long, default_value = "todoctor")] output: String, @@ -91,6 +101,8 @@ async fn main() { .map(|values| values.map(String::from).collect()) .unwrap_or_else(Vec::new); + let output_format = args.get_one::("output_format").unwrap(); + let output_directory = args.get_one::("output").unwrap(); if !check_git_repository(".").await { @@ -358,41 +370,60 @@ async fn main() { "version": version, }); - let mut escaped_json_data = json_data.clone(); - escape_json_values(&mut escaped_json_data); - - let escaped_json_string = serde_json::to_string(&escaped_json_data) - .expect("Error: Could not serializing JSON"); + generate_output(*output_format, output_directory, json_data).await; +} - let dist_path: PathBuf = - get_dist_path().expect("Error: Could not get current dist path."); +async fn generate_output( + output_format: OutputFormat, + output_directory: &str, + json_data: Value, +) { + match output_format { + OutputFormat::Html => { + let dist_path: PathBuf = get_dist_path() + .expect("Error: Could not get current dist path."); + + copy_dir_recursive(&dist_path, Path::new(output_directory)) + .await + .expect("Error copying directory"); - copy_dir_recursive(&dist_path, Path::new(output_directory)) - .await - .expect("Error copying directory"); + let mut escaped_json_data = json_data.clone(); + escape_json_values(&mut escaped_json_data); - let index_path = Path::new(output_directory).join("index.html"); - if fs::metadata(&index_path).await.is_ok() { - let mut index_content = fs::read_to_string(&index_path) - .await - .expect("Error reading index.html"); + let escaped_json_string = serde_json::to_string(&escaped_json_data) + .expect("Error: Could not serializing JSON"); - if let Some(pos) = index_content.find("") { - let script_tag: String = format!( - "", - escaped_json_string - ); - index_content.insert_str(pos, &script_tag); + let index_path = Path::new(output_directory).join("index.html"); + if fs::metadata(&index_path).await.is_ok() { + let mut index_content = fs::read_to_string(&index_path) + .await + .expect("Error reading index.html"); + + if let Some(pos) = index_content.find("") { + let script_tag = format!( + "", + escaped_json_string + ); + index_content.insert_str(pos, &script_tag); + + fs::write(&index_path, index_content) + .await + .expect("Error writing modified index.html"); + } else { + eprintln!("Error: No tag found in index.html"); + } - fs::write(&index_path, index_content) - .await - .expect("Error writing modified index.html"); - } else { - eprintln!("Error: No tag found in index.html"); + if let Err(e) = open::that(&index_path) { + eprintln!("Error: Cannot open index.html: {:?}", e); + } + } + } + OutputFormat::Json => { + let json_path = Path::new(output_directory).join("report.json"); + let mut file = File::create(&json_path) + .expect("Failed to create JSON report file"); + file.write_all(json_data.to_string().as_bytes()) + .expect("Failed to write JSON data"); } - } - - if let Err(e) = open::that(&index_path) { - eprintln!("Error: Cannot open index.html: {:?}", e); } }