jsonnet
jsonnet copied to clipboard
Return the keys of dictionaries in order
Using jsonnet with k8s I've noticed an interesting pattern—whenever you specify a list of key-value strings in k8s, jsonnet's objects work better. One way to use that is to map command line aruments, e.g.
args_+: {
tls_cert: '/abc',
tls_key: '/def',
}
becomes
--tls-cert=/abc --tls-key=/def
One problem with that approach is that jsonnet sorts all the keys, thus making it very hard to deal with situations when key order is important.
I'd like to see a mechanism to turn objects into what's basically an OrderedDict of python.
I think this goes against the spirit of JSON quite a lot. Having an ordered dict type would be a fairly minor improvement in expressiveness compared to forcing people to use lists of pairs (or lists of singleton objects).
args_+: [
{ tls_cert: '/abc' },
{ tls_key: '/def' },
]
Could this be reconsidered? I've got a large collection of CloudFormation templates to work with, and a lot of different people working on them. CloudFormation's preferred formatting is a "logical" order, which is not alphanumeric.
It would make transitioning to Jsonnet easier if I could preserve the general ordering of the keys so that the resulting artifacts can be read the same way as their not-yet-converted counterparts. As it is, changesets are tricky to review and the resulting artifact has an unexpected format, making it more difficult to read.
Hmmm... One way to handle this use case that would be to add a hidden __field_order field, which is an array of object keys. The json could then have fields listed in the order determined by this field. If __field_order was provided explicitly it could even be done without changes to the interpreter (using custom manifester) - it's on the same level as outputting canonical yaml.
So for example:
{
a: {},
b: {},
c: {
'test': 123
'aaa': 123
__field_order:: ['test', 'aaa']
},
__field_order:: ['c', 'b', 'a']
}
could produce the following json:
{
"c": {
"test": 123,
"aaa": 123
},
"b": {},
"a": {}
}
EDIT: of course you wouldn't add field_order manually, but use some kind of adapter/wrapper.
~~I hacked this thing together that turns a list of k8s objects into a map by their name and then turnes them back into a list preserving the order:~~
I was thinking about a different thing, was a while since I checked on this ticket. Still, this solution solves at least some problems with ordering.
{
named(objectlist)::
{
[k.kind + '/' +
(if std.objectHas(k.metadata, 'namespace') then k.metadata.namespace + '/' else '') +
k.metadata.name]: k,
for k in
std.makeArray(
std.length(objectlist),
function(i)
objectlist[i] + {_named_object_index:: i})
},
list(objecthash)::
local objs = [objecthash[f] for f in std.objectFields(objecthash)];
local objsKeyed = {[std.toString(o._named_object_index)]: o for o in objs};
std.makeArray(
std.length(objs),
function(i) objsKeyed[std.toString(i)])
}
It works nice in case when I use jsonnet to monkeypatch a bunch of objects but not as good if I need to add new objects to the map.