Skip to content

feat: Implement nested JSON in api subcommand#389

Draft
khatibomar wants to merge 10 commits into
unikraft-cloud:prod-stagingfrom
khatibomar:feat/nested-JSON
Draft

feat: Implement nested JSON in api subcommand#389
khatibomar wants to merge 10 commits into
unikraft-cloud:prod-stagingfrom
khatibomar:feat/nested-JSON

Conversation

@khatibomar

@khatibomar khatibomar commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Signed-off-by: ayn [email protected]

Signed-off-by: ayn <[email protected]>
Comment thread internal/jason/jason.go
return json.Unmarshal([]byte("{}"), &v.Value)
}
var items []string
for line := range strings.SplitSeq(s, "\n") {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently it expects that input is being seperated with a \n for each element.

Need some thinking.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above, we can allow multiple Unmarshals.

@jedevc jedevc left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for my slowness! I finally got round to it (chaos week sorry) - just some early feedback, I saw this is still in draft. But it's so neat!

Much love for this new Jason type 🎉

Comment thread internal/cmd/api.go
Comment on lines +214 to +219
var bodyData jason.Jason[map[string]any]
data := []byte(strings.Join(items, "\n"))
if err := jason.Unmarshal(data, &bodyData); err != nil {
return nil, err
}
return jason.Marshal(bodyData)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of this, you could just loop over all items, and unmarshal them one-by-one.

So essentially:

  • tags = []
  • Unmarshal("tags[]=production")
  • tags = [production]
  • Unmarshal("tags[]=eu-west")
  • tags = [production, eu-west]

@khatibomar khatibomar Jul 4, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the way I am thinking of it, is that, a valid JSON is [....] or {} with proper syntax that have proper key value.

On other hand a valid nested-JSON is list of key=value pairs or valid JSON

so jason.Unmarshal somehow should take all of these and parse them as a one unit, that was my vision behind that Unmarshaling.

What we can do is keep parser to expect a \n to seperate them with clear comment about expected input, but in api.go we pass items one by one instead of joining them which also results in a valid end result.
Another thing we can do is make the parser bit smarter about spaces, but that ofc will come with complexity cost depends if spaces are allowed or not. For example tags [] = production is this valid nested-JSON or not, based on that the parsing becomes complex.

Comment thread internal/cmd/api.go Outdated
}

for _, arg := range c.Args {
if strings.HasPrefix(arg, "@") {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a check here and also in readBodyItems. It's probably worth consolidating them, ideally if we could just have all the parsing logic in one place, like readBodyItems.

Comment thread internal/jason/jason.go

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so neat, I quite like this.

Any reason for naming it Jason? It's cute.

My only real big comment here is that we should split the package down. jason.go contains top-level public interfaces, while the parsing goes in parse.go, debug goes in debug.go, etc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I first named it nested, but it's not only nested, it's nested-JSON + JSON together.
Couldn't find a better name, jason was closest to my head because of a meme stuck in my head from youtube I guess. Prob Primeagen can't remember.

JavaScript Advanced Object Notation 🥼

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha, I love that 🎉 Maybe just make a note of it in the file, then it's all good 😁

Comment thread internal/jason/jason.go Outdated

// VisualizeItems is a convenience function that parses the given items
// and returns a tree visualization of the result.
func VisualizeItems(items []string) (string, error) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably best to just have Visualize.

Comment thread internal/jason/jason.go Outdated
case []any:
b.WriteString("[\n")
for i, elem := range val {
b.WriteString(indent)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use fmt.Fprintf(b, "%s [%d] =, indent, i)` to simplify some of this string building.

Comment thread internal/jason/jason.go Outdated
Comment on lines +437 to +443
// DebugTree returns a detailed multi-line breakdown showing how each
// input item is parsed and where it lands in the final tree. This is
// useful for understanding the parsing of complex nested expressions.
//
// The output shows every item grouped by its top-level key, with parsed
// path segments and the final assigned value.
func DebugTree(items []string) (string, error) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can make this debugTree to keep it internal?

Comment thread internal/jason/jason.go
return json.Unmarshal([]byte("{}"), &v.Value)
}
var items []string
for line := range strings.SplitSeq(s, "\n") {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above, we can allow multiple Unmarshals.

Comment thread internal/jason/jason.go Outdated
// or more bracketed segments. After the path an '=' or ':=' separates the
// value. If the item is a valid JSON object or array it is returned as a
// raw value with an empty path so callers can merge it at the root.
func parseItem(item string) (parsedItem, error) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: read and review this code in a little depth.

Comment thread internal/jason/jason_test.go Outdated
assert.Equal(t, expected, output)
}

func ExampleDebugTree() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fun little idea. Because this writing a new (fairly fiddly) parser, what do you think about writing a little fuzzer to search for issues? https://go.dev/doc/security/fuzz/

Then just run it for an hour or so, and see if it can find any crashes 🎉 (we've had some really annoying and difficult crashes in the last week, so hardening things to avoid needing to debug broken stuff later is very nice).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use nested JSON syntax in unikraft api

2 participants