task_graph_mcp/cli/
diff.rs1use clap::Args;
6use std::path::PathBuf;
7
8#[derive(Args, Debug)]
10pub struct DiffArgs {
11 #[arg(value_name = "FILE")]
13 pub source: PathBuf,
14
15 #[arg(value_name = "FILE")]
17 pub target: Option<PathBuf>,
18
19 #[arg(short, long, default_value = "text", value_name = "FORMAT")]
21 pub format: DiffFormat,
22
23 #[arg(long, value_name = "LIST", value_delimiter = ',')]
25 pub tables: Option<Vec<String>>,
26
27 #[arg(long)]
29 pub summary_only: bool,
30
31 #[arg(long)]
33 pub include_unchanged: bool,
34}
35
36#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
38pub enum DiffFormat {
39 #[default]
40 Text,
41 Json,
42 Summary,
43}
44
45impl std::str::FromStr for DiffFormat {
46 type Err = String;
47
48 fn from_str(s: &str) -> Result<Self, Self::Err> {
49 match s.to_lowercase().as_str() {
50 "text" => Ok(DiffFormat::Text),
51 "json" => Ok(DiffFormat::Json),
52 "summary" => Ok(DiffFormat::Summary),
53 _ => Err(format!(
54 "Invalid format '{}'. Valid options: text, json, summary",
55 s
56 )),
57 }
58 }
59}
60
61impl std::fmt::Display for DiffFormat {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 match self {
64 DiffFormat::Text => write!(f, "text"),
65 DiffFormat::Json => write!(f, "json"),
66 DiffFormat::Summary => write!(f, "summary"),
67 }
68 }
69}
70
71impl DiffArgs {
72 pub fn is_two_file_diff(&self) -> bool {
74 self.target.is_some()
75 }
76
77 pub fn should_include_table(&self, table_name: &str) -> bool {
79 match &self.tables {
80 Some(tables) => tables.iter().any(|t| t == table_name),
81 None => true,
82 }
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_diff_format_parse() {
92 assert_eq!("text".parse::<DiffFormat>().unwrap(), DiffFormat::Text);
93 assert_eq!("json".parse::<DiffFormat>().unwrap(), DiffFormat::Json);
94 assert_eq!(
95 "summary".parse::<DiffFormat>().unwrap(),
96 DiffFormat::Summary
97 );
98 assert_eq!("JSON".parse::<DiffFormat>().unwrap(), DiffFormat::Json);
99 assert!("invalid".parse::<DiffFormat>().is_err());
100 }
101
102 #[test]
103 fn test_diff_args_table_filter() {
104 let args = DiffArgs {
105 source: PathBuf::from("test.json"),
106 target: None,
107 format: DiffFormat::Text,
108 tables: Some(vec!["tasks".to_string(), "dependencies".to_string()]),
109 summary_only: false,
110 include_unchanged: false,
111 };
112
113 assert!(args.should_include_table("tasks"));
114 assert!(args.should_include_table("dependencies"));
115 assert!(!args.should_include_table("attachments"));
116 }
117
118 #[test]
119 fn test_diff_args_no_filter() {
120 let args = DiffArgs {
121 source: PathBuf::from("test.json"),
122 target: None,
123 format: DiffFormat::Text,
124 tables: None,
125 summary_only: false,
126 include_unchanged: false,
127 };
128
129 assert!(args.should_include_table("tasks"));
130 assert!(args.should_include_table("attachments"));
131 }
132}