diff --git a/src/cli.rs b/src/cli.rs index 8165c87472..03025ebec3 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -179,6 +179,7 @@ pub async fn cli() -> Result<(), Box> { command("to-array", Box::new(to_array::to_array)), command("to-json", Box::new(to_json::to_json)), command("to-toml", Box::new(to_toml::to_toml)), + command("to-yaml", Box::new(to_yaml::to_yaml)), command("sort-by", Box::new(sort_by::sort_by)), command("sort-by", Box::new(sort_by::sort_by)), Arc::new(Open), diff --git a/src/commands.rs b/src/commands.rs index 3225923481..755d46ca1a 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -35,6 +35,7 @@ crate mod table; crate mod to_array; crate mod to_json; crate mod to_toml; +crate mod to_yaml; crate mod trim; crate mod view; crate mod vtable; diff --git a/src/commands/save.rs b/src/commands/save.rs index 6c61df3f94..0a236117f5 100644 --- a/src/commands/save.rs +++ b/src/commands/save.rs @@ -1,4 +1,7 @@ use crate::commands::command::SinkCommandArgs; +use crate::commands::to_json::value_to_json_value; +use crate::commands::to_toml::value_to_toml_value; +use crate::commands::to_yaml::value_to_yaml_value; use crate::errors::ShellError; use crate::object::{Primitive, Value}; use crate::parser::Spanned; @@ -48,15 +51,7 @@ pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> { "saving to toml requires a single object (or use --raw)", )); } - toml::to_string(&args.input[0]).unwrap() - } - Some(x) if x == "ini" && !save_raw => { - if args.input.len() != 1 { - return Err(ShellError::string( - "saving to ini requires a single object (or use --raw)", - )); - } - serde_ini::to_string(&args.input[0]).unwrap() + toml::to_string(&value_to_toml_value(&args.input[0])).unwrap() } Some(x) if x == "json" && !save_raw => { if args.input.len() != 1 { @@ -64,7 +59,7 @@ pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> { "saving to json requires a single object (or use --raw)", )); } - serde_json::to_string(&args.input[0]).unwrap() + serde_json::to_string(&value_to_json_value(&args.input[0])).unwrap() } Some(x) if x == "yml" && !save_raw => { if args.input.len() != 1 { @@ -72,7 +67,7 @@ pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> { "saving to yml requires a single object (or use --raw)", )); } - serde_yaml::to_string(&args.input[0]).unwrap() + serde_yaml::to_string(&value_to_yaml_value(&args.input[0])).unwrap() } Some(x) if x == "yaml" && !save_raw => { if args.input.len() != 1 { @@ -80,7 +75,7 @@ pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> { "saving to yaml requires a single object (or use --raw)", )); } - serde_yaml::to_string(&args.input[0]).unwrap() + serde_yaml::to_string(&value_to_yaml_value(&args.input[0])).unwrap() } _ => { let mut save_data = String::new(); diff --git a/src/commands/to_yaml.rs b/src/commands/to_yaml.rs new file mode 100644 index 0000000000..b9e3d56d77 --- /dev/null +++ b/src/commands/to_yaml.rs @@ -0,0 +1,60 @@ +use crate::object::{Primitive, Value}; +use crate::prelude::*; + +pub fn value_to_yaml_value(v: &Value) -> serde_yaml::Value { + match v { + Value::Primitive(Primitive::Boolean(b)) => serde_yaml::Value::Bool(*b), + Value::Primitive(Primitive::Bytes(b)) => { + serde_yaml::Value::Number(serde_yaml::Number::from(*b as u64)) + } + Value::Primitive(Primitive::Date(d)) => serde_yaml::Value::String(d.to_string()), + Value::Primitive(Primitive::EndOfStream) => serde_yaml::Value::Null, + Value::Primitive(Primitive::Float(f)) => { + serde_yaml::Value::Number(serde_yaml::Number::from(f.into_inner())) + } + Value::Primitive(Primitive::Int(i)) => { + serde_yaml::Value::Number(serde_yaml::Number::from(*i)) + } + Value::Primitive(Primitive::Nothing) => serde_yaml::Value::Null, + Value::Primitive(Primitive::String(s)) => serde_yaml::Value::String(s.clone()), + Value::Primitive(Primitive::Path(s)) => serde_yaml::Value::String(s.display().to_string()), + + Value::Filesystem => serde_yaml::Value::Null, + Value::List(l) => { + serde_yaml::Value::Sequence(l.iter().map(|x| value_to_yaml_value(x)).collect()) + } + Value::Block(_) => serde_yaml::Value::Null, + Value::Binary(b) => serde_yaml::Value::Sequence( + b.iter() + .map(|x| serde_yaml::Value::Number(serde_yaml::Number::from(*x))) + .collect(), + ), + Value::Object(o) => { + let mut m = serde_yaml::Mapping::new(); + for (k, v) in o.entries.iter() { + m.insert(serde_yaml::Value::String(k.clone()), value_to_yaml_value(v)); + } + serde_yaml::Value::Mapping(m) + } + } +} + +pub fn to_yaml(args: CommandArgs) -> Result { + let out = args.input; + let name_span = args.name_span; + Ok(out + .values + .map( + move |a| match serde_yaml::to_string(&value_to_yaml_value(&a)) { + Ok(x) => { + ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span)) + } + Err(_) => Err(ShellError::maybe_labeled_error( + "Can not convert to YAML string", + "can not convert piped data to YAML string", + name_span, + )), + }, + ) + .to_output_stream()) +}