--- a/crates/jrsonnet-evaluator/src/builtin/manifest.rs +++ b/crates/jrsonnet-evaluator/src/builtin/manifest.rs @@ -19,6 +19,8 @@ pub struct ManifestJsonOptions<'s> { pub padding: &'s str, pub mtype: ManifestType, + pub newline: &'s str, + pub key_val_sep: &'s str, } pub fn manifest_json_ex(val: &Val, options: &ManifestJsonOptions<'_>) -> Result { @@ -49,7 +51,7 @@ buf.push('['); if !items.is_empty() { if mtype != ManifestType::ToString && mtype != ManifestType::Minify { - buf.push('\n'); + buf.push_str(options.newline); } let old_len = cur_padding.len(); @@ -60,7 +62,7 @@ if mtype == ManifestType::ToString { buf.push(' '); } else if mtype != ManifestType::Minify { - buf.push('\n'); + buf.push_str(options.newline); } } buf.push_str(cur_padding); @@ -69,7 +71,7 @@ cur_padding.truncate(old_len); if mtype != ManifestType::ToString && mtype != ManifestType::Minify { - buf.push('\n'); + buf.push_str(options.newline); buf.push_str(cur_padding); } } else if mtype == ManifestType::Std { @@ -86,7 +88,7 @@ let fields = obj.fields(); if !fields.is_empty() { if mtype != ManifestType::ToString && mtype != ManifestType::Minify { - buf.push('\n'); + buf.push_str(options.newline); } let old_len = cur_padding.len(); @@ -97,12 +99,12 @@ if mtype == ManifestType::ToString { buf.push(' '); } else if mtype != ManifestType::Minify { - buf.push('\n'); + buf.push_str(options.newline); } } buf.push_str(cur_padding); escape_string_json_buf(&field, buf); - buf.push_str(": "); + buf.push_str(options.key_val_sep); push_description_frame( || format!("field <{}> manifestification", field.clone()), || { @@ -115,7 +117,7 @@ cur_padding.truncate(old_len); if mtype != ManifestType::ToString && mtype != ManifestType::Minify { - buf.push('\n'); + buf.push_str(options.newline); buf.push_str(cur_padding); } } else if mtype == ManifestType::Std { --- a/crates/jrsonnet-evaluator/src/builtin/mod.rs +++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs @@ -1,6 +1,5 @@ use crate::function::StaticBuiltin; -use crate::typed::{Any, Null, PositiveF64, VecVal, M1}; -use crate::{self as jrsonnet_evaluator, Either, ObjValue}; +use crate::typed::{Any, PositiveF64, VecVal, M1}; use crate::{ builtin::manifest::{manifest_yaml_ex, ManifestYamlOptions}, equals, @@ -10,6 +9,7 @@ typed::{Either2, Either4}, with_state, ArrValue, Context, FuncVal, IndexableVal, Val, }; +use crate::{Either, ObjValue}; use format::{format_arr, format_obj}; use gcmodule::Cc; use jrsonnet_interner::IStr; @@ -145,7 +145,7 @@ fn builtin_length(x: Either![IStr, VecVal, ObjValue, Cc]) -> Result { use Either4::*; Ok(match x { - A(x) => x.len(), + A(x) => x.chars().count(), B(x) => x.0.len(), C(x) => x .fields_visibility() @@ -566,12 +566,21 @@ } #[jrsonnet_macros::builtin] -fn builtin_manifest_json_ex(value: Any, indent: IStr) -> Result { +fn builtin_manifest_json_ex( + value: Any, + indent: IStr, + newline: Option, + key_val_sep: Option, +) -> Result { + let newline = newline.as_deref().unwrap_or("\n"); + let key_val_sep = key_val_sep.as_deref().unwrap_or(": "); manifest_json_ex( &value.0, &ManifestJsonOptions { padding: &indent, mtype: ManifestType::Std, + newline, + key_val_sep, }, ) } --- a/crates/jrsonnet-evaluator/src/lib.rs +++ b/crates/jrsonnet-evaluator/src/lib.rs @@ -5,6 +5,9 @@ clippy::ptr_arg )] +// For jrsonnet-macros +extern crate self as jrsonnet_evaluator; + mod builtin; mod ctx; mod dynamic; @@ -976,6 +979,14 @@ } #[test] + fn json_minified() { + assert_json!( + r#"std.manifestJsonMinified({a:3, b:4, c:6})"#, + r#""{\"a\":3,\"b\":4,\"c\":6}""# + ); + } + + #[test] fn parse_json() { assert_json!( r#"std.parseJson('{"a": -1,"b": 1,"c": 3.141,"d": []}')"#, --- a/crates/jrsonnet-evaluator/src/typed/conversions.rs +++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs @@ -19,7 +19,7 @@ ($($ty:ty)*) => {$( impl Typed for $ty { const TYPE: &'static ComplexValType = - &ComplexValType::BoundedNumber(Some(<$ty>::MIN as f64), Some(<$ty>::MAX as f64)); + &ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64)); } impl TryFrom for $ty { type Error = LocError; --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -400,6 +400,8 @@ &ManifestJsonOptions { padding: "", mtype: ManifestType::ToString, + newline: "\n", + key_val_sep: ": ", }, )? .into(), @@ -484,6 +486,8 @@ } else { ManifestType::Manifest }, + newline: "\n", + key_val_sep: ": ", }, ) .map(|s| s.into()) @@ -496,6 +500,8 @@ &ManifestJsonOptions { padding: &" ".repeat(padding), mtype: ManifestType::Std, + newline: "\n", + key_val_sep: ": ", }, ) .map(|s| s.into()) --- a/crates/jrsonnet-macros/src/lib.rs +++ b/crates/jrsonnet-macros/src/lib.rs @@ -105,7 +105,7 @@ if let Some(opt_ty) = extract_type_from_option(&t.ty) { quote! {{ if let Some(value) = parsed.get(#ident) { - Some(jrsonnet_evaluator::push_description_frame( + Some(::jrsonnet_evaluator::push_description_frame( || format!("argument <{}> evaluation", #ident), || <#opt_ty>::try_from(value.evaluate()?), )?) @@ -117,7 +117,7 @@ quote! {{ let value = parsed.get(#ident).unwrap(); - jrsonnet_evaluator::push_description_frame( + ::jrsonnet_evaluator::push_description_frame( || format!("argument <{}> evaluation", #ident), || <#ty>::try_from(value.evaluate()?), )? @@ -136,7 +136,7 @@ #[derive(Clone, Copy, gcmodule::Trace)] #vis struct #name {} const _: () = { - use jrsonnet_evaluator::function::{Builtin, StaticBuiltin, BuiltinParam, ArgsLike}; + use ::jrsonnet_evaluator::function::{Builtin, StaticBuiltin, BuiltinParam, ArgsLike}; const PARAMS: &'static [BuiltinParam] = &[ #(#params),* ]; @@ -156,7 +156,7 @@ PARAMS } fn call(&self, context: Context, loc: Option<&ExprLocation>, args: &dyn ArgsLike) -> Result { - let parsed = jrsonnet_evaluator::function::parse_builtin_call(context, &PARAMS, args, false)?; + let parsed = ::jrsonnet_evaluator::function::parse_builtin_call(context, &PARAMS, args, false)?; let result: #result = #name(#(#args),*); let result = result?; --- a/crates/jrsonnet-stdlib/src/std.jsonnet +++ b/crates/jrsonnet-stdlib/src/std.jsonnet @@ -373,6 +373,8 @@ manifestJson(value):: std.manifestJsonEx(value, ' ') tailstrict, + manifestJsonMinified(value):: std.manifestJsonEx(value, '', '', ':'), + manifestJsonEx:: $intrinsic(manifestJsonEx), manifestYamlDoc:: $intrinsic(manifestYamlDoc), @@ -530,6 +532,9 @@ else patch, + get(o, f, default = null, inc_hidden = true):: + if std.objectHasEx(o, f, inc_hidden) then o[f] else default, + objectFields(o):: std.objectFieldsEx(o, false),