Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add manifestToml(v) function #149

Closed
benley opened this issue Mar 31, 2016 · 9 comments · Fixed by #866
Closed

add manifestToml(v) function #149

benley opened this issue Mar 31, 2016 · 9 comments · Fixed by #866

Comments

@benley
Copy link
Contributor

benley commented Mar 31, 2016

It should be fairly easy to write a TOML output function; the syntax is simple and it maps unambiguously to json objects.

@sparkprime
Copy link
Contributor

Is there a formal grammar of it anywhere?

@benley
Copy link
Contributor Author

benley commented Mar 31, 2016

Oddly enough I don't think they have a finalized grammar, but there is an ABNF description in toml-lang/toml#236. I suppose the canonical specification is in this document: https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md, which links to a ton of implementations and a validation suite.

@benley
Copy link
Contributor Author

benley commented May 10, 2016

I've taken a stab at a basic version of this: https://gist.github.com/benley/4fe6d2d354c3ac004de82ab51499eccb

It probably still has some weird edge cases, but it works for what I've tried so far.

@flyingmutant
Copy link

Are there any plans to include the gist into the stdlib?

@sbarzowski
Copy link
Collaborator

@flyingmutant We're happy to accept PRs adding this functionality.

@benley
Copy link
Contributor Author

benley commented Oct 25, 2019

oh hey, I had forgotten all about this. I have some free time and will try to get a PR put together for it in the next couple of days.

@rawkode
Copy link

rawkode commented Mar 20, 2020

Hey @benley ... so it's been a few days :)

Do you need some help with this? I'd love to see this merged.

@valeneiko
Copy link
Contributor

I've added support for table arrays. And also fixed escapeKeyToml. Will try submitting a PR in the next few days.

But here is the code that worked for me:

// Render any jsonnet value (except functions) to TOML format.

local
  inlineTable(body) =
    "{" +
    std.join(", ", ["%s = %s" % [escapeKeyToml(k), renderBody(body[k])] for k in std.objectFields(body)]) +
    "}",

  renderArray(body) =
    local
      types = std.set([std.type(x) for x in body]),
      // If any of the values are non-integer, we need to force all values to be rendered as floats.
      forceFloat = std.foldl(function(result, item) result || (std.floor(item) != item), body, false);
    if std.length(types) > 1
    then error "TOML Arrays must be uniform-type. Multiple types found: %s" % std.join(", ", types)
    else "[" + std.join(", ", [renderBody(x, forceFloat=forceFloat) for x in body]) + "]",

  renderBody(body, forceFloat=false) =
    if std.type(body) == "object"               then inlineTable(body) else
    if std.type(body) == "array"                then renderArray(body) else
    if std.type(body) == "number" && forceFloat then "%f" % body else
    if std.type(body) == "number"               then body else
    if std.type(body) == "string"               then escapeStringToml(body) else
    if std.type(body) == "boolean"              then body else
      error "unsupported value for toml: got %s" % std.type(body),

  renderItem(k, v) =
    ["%s = %s" % [escapeKeyToml(k), renderBody(v)]],

  renderSection(path, v) =
    ["[%s]" % std.join(".", std.map(escapeKeyToml, path))] + topTable(v, path=path),

  renderSectionArray(path, v) =
    local lines = std.flattenArrays([
      (["[[%s]]" % std.join(".", std.map(escapeKeyToml, path))] + topTable(s, path=path) + [""])
      for s in v
    ]);
    std.slice(lines, 0, std.length(lines) - 1, 1),

  topTable(body, path=[]) =
    local
      nonObjects = std.flattenArrays([renderItem(k, body[k]) for k in std.objectFields(body) if std.type(body[k]) != "object" && (std.type(body[k]) != "array" || std.type(body[k][0]) != "object")]),
      objects = std.flattenArrays([renderSection(path + [k], body[k]) for k in std.objectFields(body) if std.type(body[k]) == "object"]),
      hasBoth = std.length(nonObjects) > 0 && std.length(objects) > 0,
      objectArrays = std.flattenArrays([renderSectionArray(path + [k], body[k]) for k in std.objectFields(body) if std.type(body[k]) == "array" && std.type(body[k][0]) == "object"]);
    nonObjects
    + (if hasBoth then [""] else [])
    + objects
    + (if std.length(objectArrays) > 0 && (std.length(nonObjects) > 0 || std.length(objects) > 0) then [""] else [])
    + objectArrays,

  escapeKeyToml(str) =
    local bare_allowed = std.set(std.stringChars("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"));
    if std.setUnion(std.set(std.stringChars(str)), bare_allowed) == bare_allowed then str else "%s" % escapeStringToml(str),

  // JSON string encoding rules are a superset of TOML's - ie. all valid JSON strings are valid TOML strings
  // but not vice versa (specifically, TOML only requires escaping control chars U+000, U+001f and U+007f,
  // whereas JSON does not allow any control chars). Allowed escapes are the same.
  escapeStringToml = std.escapeStringJson;

function(body)
  if std.type(body) != "object"
  then error "TOML body must be an object. Got %s" % std.type(body)
  else std.lines(topTable(body))

@benley
Copy link
Contributor Author

benley commented Nov 25, 2020

agh, I'm sorry for dropping the ball on this. I was unemployed for a year and was finding it hard to stay motivated on projects like these. @anyname2, please feel free to take over and finish this if you're so inclined.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants