Skip to content

Commit

Permalink
Add indent with multiline to json.encode
Browse files Browse the repository at this point in the history
- allow json.encode to receive an indent named argument:
  ```
  json.encode('{"a":"b"}', indent=2)
  ```
- indent greater than 0 indicates the json shall be rendered as a
  multiline string indented with the specified number of spaces
- indent=0 and omitting indent both result in a single line json string
- errors are returned if indent > 4 or if arguments other than indent
  are included

Issue carvel-dev#410

Co-authored-by: Tyler Schultz <[email protected]>
  • Loading branch information
mcwumbly and tylerschultz committed Jun 3, 2021
1 parent 357b87d commit 0bad57f
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 19 deletions.
28 changes: 28 additions & 0 deletions pkg/template/core/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package core

import (
"fmt"

"github.com/k14s/starlark-go/starlark"
)

Expand All @@ -19,3 +21,29 @@ func BoolArg(kwargs []starlark.Tuple, keyToFind string) (bool, error) {
}
return false, nil
}

func Int64Arg(kwargs []starlark.Tuple, keyToFind string) (int64, error) {
for _, arg := range kwargs {
key, err := NewStarlarkValue(arg.Index(0)).AsString()
if err != nil {
return 0, err
}
if key == keyToFind {
return NewStarlarkValue(arg.Index(1)).AsInt64()
}
}
return 0, nil
}

func CheckArgNames(kwargs []starlark.Tuple, validKeys map[string]struct{}) error {
for _, arg := range kwargs {
key, err := NewStarlarkValue(arg.Index(0)).AsString()
if err != nil {
return err
}
if _, ok := validKeys[key]; !ok {
return fmt.Errorf("invalid argument name: %s", key)
}
}
return nil
}
63 changes: 45 additions & 18 deletions pkg/yamltemplate/filetests/ytt-library/json.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,51 @@ fragment:
piece1: false
#@ end

test1: #@ json.encode({"a": [1,2,3,{"c":456}], "b": "str"})
test1a: #@ json.encode(yaml_fragment())
test1b: #@ json.encode({"inside_map": yaml_fragment(), "inside_array": [yaml_fragment()]})
test2: #@ json.encode({})
test3: #@ json.decode("{}")
test4: #@ json.decode('{"a":[1,2,3,{"c":456}],"b":"str"}')
encode:
test1: #@ json.encode({})
test2: #@ json.encode({"a": [1,2,3,{"c":456}], "b": "str"})
test3: #@ json.encode(yaml_fragment())
test4: #@ json.encode({"inside_map": yaml_fragment(), "inside_array": [yaml_fragment()]})
indent:
test1: #@ json.encode({"a": [1,2,3,{"c":456}], "b": "str"}, indent=4)
test2: #@ json.encode({"a": [1,2,3,{"c":456}], "b": "str"}, indent=0)
#! TODO: how should we test error cases like these?
#! test1e: #@ json.encode({"a": [1,2,3,{"c":456}], "b": "str"}, indent=5)
#! test1f: #@ json.encode({"a": [1,2,3,{"c":456}], "b": "str"}, inschment=4)
#!
#! TODO: update docs to include indent:
#! https://github.com/vmware-tanzu/carvel.dev/blob/develop/content/ytt/docs/latest/lang-ref-ytt.md#serialization-modules
decode:
test1: #@ json.decode("{}")
test2: #@ json.decode('{"a":[1,2,3,{"c":456}],"b":"str"}')

+++

test1: '{"a":[1,2,3,{"c":456}],"b":"str"}'
test1a: '{"fragment":["piece1",{"piece1":false,"piece2":true}]}'
test1b: '{"inside_array":[{"fragment":["piece1",{"piece1":false,"piece2":true}]}],"inside_map":{"fragment":["piece1",{"piece1":false,"piece2":true}]}}'
test2: '{}'
test3: {}
test4:
a:
- 1
- 2
- 3
- c: 456
b: str
encode:
test1: '{}'
test2: '{"a":[1,2,3,{"c":456}],"b":"str"}'
test3: '{"fragment":["piece1",{"piece1":false,"piece2":true}]}'
test4: '{"inside_array":[{"fragment":["piece1",{"piece1":false,"piece2":true}]}],"inside_map":{"fragment":["piece1",{"piece1":false,"piece2":true}]}}'
indent:
test1: |-
{
"a": [
1,
2,
3,
{
"c": 456
}
],
"b": "str"
}
test2: '{"a":[1,2,3,{"c":456}],"b":"str"}'
decode:
test1: {}
test2:
a:
- 1
- 2
- 3
- c: 456
b: str
22 changes: 21 additions & 1 deletion pkg/yttlibrary/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package yttlibrary
import (
"encoding/json"
"fmt"
"strings"

"github.com/k14s/starlark-go/starlark"
"github.com/k14s/starlark-go/starlarkstruct"
Expand All @@ -24,6 +25,9 @@ var (
},
},
}
JSONKWARGS = map[string]struct{}{
"indent": struct{}{},
}
)

type jsonModule struct{}
Expand All @@ -32,14 +36,30 @@ func (b jsonModule) Encode(thread *starlark.Thread, f *starlark.Builtin, args st
if args.Len() != 1 {
return starlark.None, fmt.Errorf("expected exactly one argument")
}
if err := core.CheckArgNames(kwargs, JSONKWARGS); err != nil {
return starlark.None, err
}

val, err := core.NewStarlarkValue(args.Index(0)).AsGoValue()
if err != nil {
return starlark.None, err
}
val = orderedmap.Conversion{yamlmeta.NewGoFromAST(val)}.AsUnorderedStringMaps()

valBs, err := json.Marshal(val)
var valBs []byte
indent, err := core.Int64Arg(kwargs, "indent")
if err != nil {
return starlark.None, err
}
if indent > 4 || indent < 0 {
return starlark.None, fmt.Errorf("indent value must be between 0 and 4")
}
if indent > 0 {
valBs, err = json.MarshalIndent(val, "", strings.Repeat(" ", int(indent)))
} else {
valBs, err = json.Marshal(val)
}

if err != nil {
return starlark.None, err
}
Expand Down

0 comments on commit 0bad57f

Please sign in to comment.