Skip to content

Commit

Permalink
fix: improved handling of complex yaml in YAMLNodeToJSON
Browse files Browse the repository at this point in the history
  • Loading branch information
TristanSpeakEasy committed Aug 5, 2024
1 parent 0a98b84 commit e9aaa58
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 12 deletions.
33 changes: 21 additions & 12 deletions json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ package json
import (
"encoding/json"
"fmt"
"reflect"

"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)

// YAMLNodeToJSON converts yaml/json stored in a yaml.Node to json ordered matching the original yaml/json
//
// NOTE: The limitation is this won't work with YAML that is not compatible with JSON, ie yaml with anchors or complex map keys
func YAMLNodeToJSON(node *yaml.Node, indentation string) ([]byte, error) {
v, err := handleYAMLNode(node)
if err != nil {
Expand All @@ -31,28 +30,38 @@ func handleYAMLNode(node *yaml.Node) (any, error) {
case yaml.ScalarNode:
return handleScalarNode(node)
case yaml.AliasNode:
panic("currently unsupported")
return handleYAMLNode(node.Alias)
default:
return nil, fmt.Errorf("unknown node kind: %v", node.Kind)
}
}

func handleMappingNode(node *yaml.Node) (any, error) {
m := orderedmap.New[string, yaml.Node]()
v := orderedmap.New[string, any]()
for i, n := range node.Content {
if i%2 == 0 {
continue
}
keyNode := node.Content[i-1]
kv, err := handleYAMLNode(keyNode)
if err != nil {
return nil, err

Check warning on line 48 in json/json.go

View check run for this annotation

Codecov / codecov/patch

json/json.go#L48

Added line #L48 was not covered by tests
}

if err := node.Decode(m); err != nil {
return nil, err
}
if reflect.TypeOf(kv).Kind() != reflect.String {
keyData, err := json.Marshal(kv)
if err != nil {
return nil, err

Check warning on line 54 in json/json.go

View check run for this annotation

Codecov / codecov/patch

json/json.go#L54

Added line #L54 was not covered by tests
}
kv = string(keyData)
}

v := orderedmap.New[string, any]()
for pair := orderedmap.First(m); pair != nil; pair = pair.Next() {
n := pair.Value()
vv, err := handleYAMLNode(&n)
vv, err := handleYAMLNode(n)
if err != nil {
return nil, err
}

v.Set(pair.Key(), vv)
v.Set(fmt.Sprintf("%v", kv), vv)
}

return v, nil
Expand Down
51 changes: 51 additions & 0 deletions json/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,54 @@ func TestYAMLNodeToJSON_FromJSON(t *testing.T) {

assert.Equal(t, j, string(o))
}

func TestYAMLNodeWithAnchorsToJSON(t *testing.T) {
y := `examples:
someExample: &someExample
key1: scalar1
key2: scalar2
someValue: *someExample`

var v yaml.Node

err := yaml.Unmarshal([]byte(y), &v)
require.NoError(t, err)

j, err := json.YAMLNodeToJSON(&v, " ")
require.NoError(t, err)

assert.Equal(t, `{
"examples": {
"someExample": {
"key1": "scalar1",
"key2": "scalar2"
}
},
"someValue": {
"key1": "scalar1",
"key2": "scalar2"
}
}`, string(j))
}

func TestYAMLNodeWithComplexKeysToJSON(t *testing.T) {
y := `someMapWithComplexKeys:
{key1: scalar1, key2: scalar2}: {key1: scalar1, key2: scalar2}`

var v yaml.Node

err := yaml.Unmarshal([]byte(y), &v)
require.NoError(t, err)

j, err := json.YAMLNodeToJSON(&v, " ")
require.NoError(t, err)

assert.Equal(t, `{
"someMapWithComplexKeys": {
"{\"key1\":\"scalar1\",\"key2\":\"scalar2\"}": {
"key1": "scalar1",
"key2": "scalar2"
}
}
}`, string(j))
}

0 comments on commit e9aaa58

Please sign in to comment.