difftreelog
Add std.manifestJsonMinified()
in: master
It was added to jsonnet v0.18.0.
5 files changed
crates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth1use crate::error::Error::*;2use crate::error::Result;3use crate::{throw, Val};45#[derive(PartialEq, Clone, Copy)]6pub enum ManifestType {7 // Applied in manifestification8 Manifest,9 /// Used for std.manifestJson10 /// Empty array/objects extends to "[\n\n]" instead of "[ ]" as in manifest11 Std,12 /// No line breaks, used in `obj+''`13 ToString,14 /// Minified json15 Minify,16}1718pub struct ManifestJsonOptions<'s> {19 pub padding: &'s str,20 pub mtype: ManifestType,21 pub newline: &'s str,22 pub key_val_sep: &'s str,23}2425pub fn manifest_json_ex(val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {26 let mut out = String::new();27 manifest_json_ex_buf(val, &mut out, &mut String::new(), options)?;28 Ok(out)29}30fn manifest_json_ex_buf(31 val: &Val,32 buf: &mut String,33 cur_padding: &mut String,34 options: &ManifestJsonOptions<'_>,35) -> Result<()> {36 use std::fmt::Write;37 let mtype = options.mtype;38 match val {39 Val::Bool(v) => {40 if *v {41 buf.push_str("true");42 } else {43 buf.push_str("false");44 }45 }46 Val::Null => buf.push_str("null"),47 Val::Str(s) => escape_string_json_buf(s, buf),48 Val::Num(n) => write!(buf, "{}", n).unwrap(),49 Val::Arr(items) => {50 buf.push('[');51 if !items.is_empty() {52 if mtype != ManifestType::ToString && mtype != ManifestType::Minify {53 buf.push_str(options.newline);54 }5556 let old_len = cur_padding.len();57 cur_padding.push_str(options.padding);58 for (i, item) in items.iter().enumerate() {59 if i != 0 {60 buf.push(',');61 if mtype == ManifestType::ToString {62 buf.push(' ');63 } else if mtype != ManifestType::Minify {64 buf.push_str(options.newline);65 }66 }67 buf.push_str(cur_padding);68 manifest_json_ex_buf(&item?, buf, cur_padding, options)?;69 }70 cur_padding.truncate(old_len);7172 if mtype != ManifestType::ToString && mtype != ManifestType::Minify {73 buf.push_str(options.newline);74 buf.push_str(cur_padding);75 }76 } else if mtype == ManifestType::Std {77 buf.push_str("\n\n");78 buf.push_str(cur_padding);79 } else if mtype == ManifestType::ToString || mtype == ManifestType::Manifest {80 buf.push(' ');81 }82 buf.push(']');83 }84 Val::Obj(obj) => {85 obj.run_assertions()?;86 buf.push('{');87 let fields = obj.fields();88 if !fields.is_empty() {89 if mtype != ManifestType::ToString && mtype != ManifestType::Minify {90 buf.push_str(options.newline);91 }9293 let old_len = cur_padding.len();94 cur_padding.push_str(options.padding);95 for (i, field) in fields.into_iter().enumerate() {96 if i != 0 {97 buf.push(',');98 if mtype == ManifestType::ToString {99 buf.push(' ');100 } else if mtype != ManifestType::Minify {101 buf.push_str(options.newline);102 }103 }104 buf.push_str(cur_padding);105 escape_string_json_buf(&field, buf);106 buf.push_str(options.key_val_sep);107 crate::push(108 None,109 || format!("field <{}> manifestification", field.clone()),110 || {111 let value = obj.get(field.clone())?.unwrap();112 manifest_json_ex_buf(&value, buf, cur_padding, options)113 },114 )?;115 }116 cur_padding.truncate(old_len);117118 if mtype != ManifestType::ToString && mtype != ManifestType::Minify {119 buf.push_str(options.newline);120 buf.push_str(cur_padding);121 }122 } else if mtype == ManifestType::Std {123 buf.push_str("\n\n");124 buf.push_str(cur_padding);125 } else if mtype == ManifestType::ToString || mtype == ManifestType::Manifest {126 buf.push(' ');127 }128 buf.push('}');129 }130 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),131 };132 Ok(())133}134135pub fn escape_string_json(s: &str) -> String {136 let mut buf = String::new();137 escape_string_json_buf(s, &mut buf);138 buf139}140141fn escape_string_json_buf(s: &str, buf: &mut String) {142 use std::fmt::Write;143 buf.push('"');144 for c in s.chars() {145 match c {146 '"' => buf.push_str("\\\""),147 '\\' => buf.push_str("\\\\"),148 '\u{0008}' => buf.push_str("\\b"),149 '\u{000c}' => buf.push_str("\\f"),150 '\n' => buf.push_str("\\n"),151 '\r' => buf.push_str("\\r"),152 '\t' => buf.push_str("\\t"),153 c if c < 32 as char || (c >= 127 as char && c <= 159 as char) => {154 write!(buf, "\\u{:04x}", c as u32).unwrap()155 }156 c => buf.push(c),157 }158 }159 buf.push('"');160}161162pub struct ManifestYamlOptions<'s> {163 /// Padding before fields, i.e164 /// ```yaml165 /// a:166 /// b:167 /// ## <- this168 /// ```169 pub padding: &'s str,170 /// Padding before array elements in objects171 /// ```yaml172 /// a:173 /// - 1174 /// ## <- this175 /// ```176 pub arr_element_padding: &'s str,177}178179pub fn manifest_yaml_ex(val: &Val, options: &ManifestYamlOptions<'_>) -> Result<String> {180 let mut out = String::new();181 manifest_yaml_ex_buf(val, &mut out, &mut String::new(), options)?;182 Ok(out)183}184fn manifest_yaml_ex_buf(185 val: &Val,186 buf: &mut String,187 cur_padding: &mut String,188 options: &ManifestYamlOptions<'_>,189) -> Result<()> {190 use std::fmt::Write;191 match val {192 Val::Bool(v) => {193 if *v {194 buf.push_str("true")195 } else {196 buf.push_str("false")197 }198 }199 Val::Null => buf.push_str("null"),200 Val::Str(s) => {201 if s.is_empty() {202 buf.push_str("\"\"");203 } else if let Some(s) = s.strip_suffix('\n') {204 buf.push('|');205 for line in s.split('\n') {206 buf.push('\n');207 buf.push_str(options.padding);208 buf.push_str(line);209 }210 } else {211 escape_string_json_buf(s, buf)212 }213 }214 Val::Num(n) => write!(buf, "{}", *n).unwrap(),215 Val::Arr(a) => {216 if a.is_empty() {217 buf.push_str("[]");218 } else {219 for (i, item) in a.iter().enumerate() {220 if i != 0 {221 buf.push('\n');222 buf.push_str(cur_padding);223 }224 let item = item?;225 buf.push('-');226 match &item {227 Val::Arr(a) if !a.is_empty() => {228 buf.push('\n');229 buf.push_str(cur_padding);230 buf.push_str(options.padding);231 }232 _ => buf.push(' '),233 }234 let extra_padding = match &item {235 Val::Arr(a) => !a.is_empty(),236 Val::Obj(o) => !o.is_empty(),237 _ => false,238 };239 let prev_len = cur_padding.len();240 if extra_padding {241 cur_padding.push_str(options.padding);242 }243 manifest_yaml_ex_buf(&item, buf, cur_padding, options)?;244 cur_padding.truncate(prev_len);245 }246 }247 }248 Val::Obj(o) => {249 if o.is_empty() {250 buf.push_str("{}");251 } else {252 for (i, key) in o.fields().iter().enumerate() {253 if i != 0 {254 buf.push('\n');255 buf.push_str(cur_padding);256 }257 escape_string_json_buf(key, buf);258 buf.push(':');259 let prev_len = cur_padding.len();260 let item = o.get(key.clone())?.expect("field exists");261 match &item {262 Val::Arr(a) if !a.is_empty() => {263 buf.push('\n');264 buf.push_str(cur_padding);265 buf.push_str(options.arr_element_padding);266 cur_padding.push_str(options.arr_element_padding);267 }268 Val::Obj(o) if !o.is_empty() => {269 buf.push('\n');270 buf.push_str(cur_padding);271 buf.push_str(options.padding);272 cur_padding.push_str(options.padding);273 }274 _ => buf.push(' '),275 }276 manifest_yaml_ex_buf(&item, buf, cur_padding, options)?;277 cur_padding.truncate(prev_len);278 }279 }280 }281 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),282 }283 Ok(())284}crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -121,7 +121,7 @@
("trace".into(), builtin_trace),
("join".into(), builtin_join),
("escapeStringJson".into(), builtin_escape_string_json),
- ("manifestJsonEx".into(), builtin_manifest_json_ex),
+ ("manifestJsonExImpl".into(), builtin_manifest_json_ex_impl),
("manifestYamlDocImpl".into(), builtin_manifest_yaml_doc),
("reverse".into(), builtin_reverse),
("id".into(), builtin_id),
@@ -754,18 +754,22 @@
})
}
-fn builtin_manifest_json_ex(
+fn builtin_manifest_json_ex_impl(
context: Context,
_loc: Option<&ExprLocation>,
args: &ArgsDesc,
) -> Result<Val> {
- parse_args!(context, "manifestJsonEx", args, 2, [
+ parse_args!(context, "manifestJsonEx", args, 4, [
0, value: ty!(any);
1, indent: ty!(string) => Val::Str;
+ 2, newline: ty!(string) => Val::Str;
+ 3, key_val_sep: ty!(string) => Val::Str;
], {
Ok(Val::Str(manifest_json_ex(&value, &ManifestJsonOptions {
padding: &indent,
mtype: ManifestType::Std,
+ newline: &newline,
+ key_val_sep: &key_val_sep,
})?.into()))
})
}
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -810,6 +810,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": []}')"#,
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -451,6 +451,8 @@
&ManifestJsonOptions {
padding: "",
mtype: ManifestType::ToString,
+ newline: "\n",
+ key_val_sep: ": ",
},
)?
.into(),
@@ -535,6 +537,8 @@
} else {
ManifestType::Manifest
},
+ newline: "\n",
+ key_val_sep: ": ",
},
)
.map(|s| s.into())
@@ -547,6 +551,8 @@
&ManifestJsonOptions {
padding: &" ".repeat(padding),
mtype: ManifestType::Std,
+ newline: "\n",
+ key_val_sep: ": ",
},
)
.map(|s| s.into())
crates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/std.jsonnet
+++ b/crates/jrsonnet-stdlib/src/std.jsonnet
@@ -372,7 +372,11 @@
manifestJson(value):: std.manifestJsonEx(value, ' '),
- manifestJsonEx:: $intrinsic(manifestJsonEx),
+ manifestJsonMinified(value):: std.manifestJsonEx(value, '', '', ':'),
+
+ manifestJsonExImpl:: $intrinsic(manifestJsonExImpl),
+
+ manifestJsonEx(value, indent, newline='\n', key_val_sep=': '):: std.manifestJsonExImpl(value, indent, newline, key_val_sep),
manifestYamlDocImpl:: $intrinsic(manifestYamlDocImpl),