1. Problem with binary +
operator
Merging Jsonnet and JSON with +
doesn't recursively merge objects because there is no way for the JSON to use the +:
syntax sugar.
For example, evaluating the following Jsonnet:
local jsonnet = { a: { b: 2, z: 26 } }; local json = std.parseJson('{ "a": { "c": 3 } }'); jsonnet + json
Produces the JSON:
{ "a": { "c": 3 } }
2. Problem with std.mergePatch
Because std.mergePatch
adheres to RFC 7396, it doesn't respect hidden Jsonnet fields.
For example, evaluating the following Jsonnet:
local jsonnet = { visible: true, hidden:: true }; local json = std.parseJson('{ "additional": true }'); local merged = std.mergePatch(jsonnet, json); { local visible_fields = std.objectFields(merged), hidden_fields: std.setDiff(std.objectFieldsAll(merged), visible_fields), visible_fields: visible_fields, }
Produces the JSON (note the absent "hidden" field):
{ "hidden_fields": [ ], "visible_fields": [ "additional", "visible" ] }
3. Defining mergePatchAll
Semantics of std.mergePatch
but including hidden fields.
local mergePatchAll(target, patch) = if std.isObject(patch) then local target_object = if std.isObject(target) then target else {}; local visible_target_fields = if std.isObject(target_object) then std.objectFields(target_object) else []; local hidden_target_fields = if std.isObject(target_object) then std.setDiff(std.objectFieldsAll(target_object), visible_target_fields) else []; local patch_fields = std.objectFields(patch); local patch_null_fields = [k for k in patch_fields if patch[k] == null]; local visible_target_fields_also_in_patch = std.setUnion(visible_target_fields, patch_fields); local hidden_target_fields_also_in_patch = std.setUnion(hidden_target_fields, patch_fields); std.foldr( function(k, acc) acc + if !std.objectHas(patch, k) then { [k]:: target_object[k] } else if !std.objectHasAll(target_object, k) then { [k]: $.mergePatchAll(null, patch[k]) tailstrict } else { [k]: $.mergePatchAll(target_object[k], patch[k]) tailstrict } , std.setDiff(hidden_target_fields_also_in_patch, patch_null_fields), { [k]: if !std.objectHas(patch, k) then target_object[k] else if !std.objectHas(target_object, k) then $.mergePatchAll(null, patch[k]) tailstrict else $.mergePatchAll(target_object[k], patch[k]) tailstrict for k in std.setDiff(visible_target_fields_also_in_patch, patch_null_fields) } ) else patch;
For example, evaluating the following Jsonnet:
<<mergePatchAll>> local jsonnet = { visible: true, hidden:: true }; local json = std.parseJson('{ "additional": true }'); local merged = mergePatchAll(jsonnet, json); { local visible_fields = std.objectFields(merged), hidden_fields: std.setDiff(std.objectFieldsAll(merged), visible_fields), visible_fields: visible_fields, }
Produces the JSON:
{ "hidden_fields": [ "hidden" ], "visible_fields": [ "additional", "visible" ] }