diff --git a/.changeset/fix-unknown-format-warning.md b/.changeset/fix-unknown-format-warning.md new file mode 100644 index 00000000..10fc73a3 --- /dev/null +++ b/.changeset/fix-unknown-format-warning.md @@ -0,0 +1,5 @@ +--- +"gws": patch +--- + +fix: warn to stderr when unknown --format value is provided diff --git a/src/formatter.rs b/src/formatter.rs index 22d75a01..c77007df 100644 --- a/src/formatter.rs +++ b/src/formatter.rs @@ -35,14 +35,26 @@ pub enum OutputFormat { impl OutputFormat { /// Parse from a string argument. - pub fn from_str(s: &str) -> Self { + /// + /// Returns `Ok(format)` for known values, or `Err(unknown_value)` if the + /// string is not recognised. Call sites should warn the user on `Err` and + /// decide whether to fall back to JSON or surface an error. + pub fn parse(s: &str) -> Result { match s.to_lowercase().as_str() { - "table" => Self::Table, - "yaml" | "yml" => Self::Yaml, - "csv" => Self::Csv, - _ => Self::Json, + "json" => Ok(Self::Json), + "table" => Ok(Self::Table), + "yaml" | "yml" => Ok(Self::Yaml), + "csv" => Ok(Self::Csv), + other => Err(other.to_string()), } } + + /// Parse from a string argument, falling back to JSON for unknown values. + /// + /// Prefer `parse()` at call sites where you want to surface a warning. + pub fn from_str(s: &str) -> Self { + Self::parse(s).unwrap_or(Self::Json) + } } /// Format a JSON value according to the specified output format. @@ -371,6 +383,25 @@ mod tests { assert_eq!(OutputFormat::from_str("unknown"), OutputFormat::Json); } + #[test] + fn test_output_format_parse_known() { + assert_eq!(OutputFormat::parse("json"), Ok(OutputFormat::Json)); + assert_eq!(OutputFormat::parse("table"), Ok(OutputFormat::Table)); + assert_eq!(OutputFormat::parse("yaml"), Ok(OutputFormat::Yaml)); + assert_eq!(OutputFormat::parse("yml"), Ok(OutputFormat::Yaml)); + assert_eq!(OutputFormat::parse("csv"), Ok(OutputFormat::Csv)); + // Case-insensitive + assert_eq!(OutputFormat::parse("JSON"), Ok(OutputFormat::Json)); + assert_eq!(OutputFormat::parse("TABLE"), Ok(OutputFormat::Table)); + } + + #[test] + fn test_output_format_parse_unknown_returns_err() { + assert!(OutputFormat::parse("bogus").is_err()); + assert_eq!(OutputFormat::parse("bogus").unwrap_err(), "bogus"); + assert!(OutputFormat::parse("").is_err()); + } + #[test] fn test_format_json() { let val = json!({"name": "test"}); diff --git a/src/main.rs b/src/main.rs index 9df91c7e..9d23511d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -139,10 +139,18 @@ async fn run() -> Result<(), GwsError> { })?; // Resolve --format flag - let output_format = matches - .get_one::("format") - .map(|s| formatter::OutputFormat::from_str(s)) - .unwrap_or_default(); + let output_format = match matches.get_one::("format") { + Some(s) => match formatter::OutputFormat::parse(s) { + Ok(fmt) => fmt, + Err(unknown) => { + eprintln!( + "warning: unknown output format '{unknown}'; falling back to json (valid options: json, table, yaml, csv)" + ); + formatter::OutputFormat::Json + } + }, + None => formatter::OutputFormat::default(), + }; // Resolve --sanitize template (flag or env var) let sanitize_template = matches