sjsonnet
sjsonnet copied to clipboard
Add std.manifestToml
This was recently added to the standard library. I don't frankly know how useful it is.
https://github.com/google/jsonnet/pull/866
This is an incompatibility issue as tracked by #73
@coderplay hit a need for this when interfacing with TiDB, which uses TOML for config. For now, we just vendored the implementation from the upstream std.jsonnet
(below) and it seems to work, but we should pick this up in the next maintenance pass and port it to Scala for improved performance and consistency with the rest of Std.scala
{
manifestToml(value):: self.manifestTomlEx(value, ' '),
all(arr)::
assert std.isArray(arr) : 'all() parameter should be an array, got ' + std.type(arr);
local arrLen = std.length(arr);
local aux(idx) =
if idx >= arrLen then
true
else
local e = arr[idx];
assert std.isBoolean(e) : std.format('element "%s" of type %s is not a boolean', e, std.type(e));
if !e then
false
else
aux(idx + 1);
aux(0),
manifestTomlEx(value, indent)::
local
escapeStringToml = std.escapeStringJson,
escapeKeyToml(key) =
local bare_allowed = std.set(std.stringChars('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'));
if std.setUnion(std.set(std.stringChars(key)), bare_allowed) == bare_allowed then key else escapeStringToml(key),
isTableArray(v) = std.isArray(v) && std.length(v) > 0 && self.all(std.map(std.isObject, v)),
isSection(v) = std.isObject(v) || isTableArray(v),
renderValue(v, indexedPath, inline, cindent) =
if v == true then
'true'
else if v == false then
'false'
else if v == null then
error 'Tried to manifest "null" at ' + indexedPath
else if std.isNumber(v) then
'' + v
else if std.isString(v) then
escapeStringToml(v)
else if std.isFunction(v) then
error 'Tried to manifest function at ' + indexedPath
else if std.isArray(v) then
if std.length(v) == 0 then
'[]'
else
local range = std.range(0, std.length(v) - 1);
local new_indent = if inline then '' else cindent + indent;
local separator = if inline then ' ' else '\n';
local lines = ['[' + separator]
+ std.join([',' + separator],
[
[new_indent + renderValue(v[i], indexedPath + [i], true, '')]
for i in range
])
+ [separator + (if inline then '' else cindent) + ']'];
std.join('', lines)
else if std.isObject(v) then
local lines = ['{ ']
+ std.join([', '],
[
[escapeKeyToml(k) + ' = ' + renderValue(v[k], indexedPath + [k], true, '')]
for k in std.objectFields(v)
])
+ [' }'];
std.join('', lines),
renderTableInternal(v, path, indexedPath, cindent) =
local kvp = std.flattenArrays([
[cindent + escapeKeyToml(k) + ' = ' + renderValue(v[k], indexedPath + [k], false, cindent)]
for k in std.objectFields(v)
if !isSection(v[k])
]);
local sections = [std.join('\n', kvp)] + [
(
if std.isObject(v[k]) then
renderTable(v[k], path + [k], indexedPath + [k], cindent)
else
renderTableArray(v[k], path + [k], indexedPath + [k], cindent)
)
for k in std.objectFields(v)
if isSection(v[k])
];
std.join('\n\n', sections),
renderTable(v, path, indexedPath, cindent) =
cindent + '[' + std.join('.', std.map(escapeKeyToml, path)) + ']'
+ (if v == {} then '' else '\n')
+ renderTableInternal(v, path, indexedPath, cindent + indent),
renderTableArray(v, path, indexedPath, cindent) =
local range = std.range(0, std.length(v) - 1);
local sections = [
(cindent + '[[' + std.join('.', std.map(escapeKeyToml, path)) + ']]'
+ (if v[i] == {} then '' else '\n')
+ renderTableInternal(v[i], path, indexedPath + [i], cindent + indent))
for i in range
];
std.join('\n\n', sections);
if std.isObject(value) then
renderTableInternal(value, [], [], '')
else
error 'TOML body must be an object. Got ' + std.type(value),
}.manifestTomlEx({ key1: "value", key2: 1, section: { a: 1, b: "str", c: false, d: [1, "s", [2, 3]], subsection: { k: "v", }, }, sectionArray: [ { k: "v1", v: 123 }, { k: "v2", c: "value2" }, ], }, " ")
~/universe$ bin/sjsonnet foo.jsonnet
"key1 = \"value\"\nkey2 = 1\n\n[section]\n a = 1\n b = \"str\"\n c = false\n d = [\n 1,\n \"s\",\n [ 2, 3 ]\n ]\n\n [section.subsection]\n k = \"v\"\n\n[[sectionArray]]\n k = \"v1\"\n v = 123\n\n[[sectionArray]]\n c = \"value2\"\n k = \"v2\""
Thanks a lot Haoyi, for reviewing this feature! Looking forward to the scala implementation.