diff --git a/json/json.go b/json/json.go index e73aa56f..156a35bf 100644 --- a/json/json.go +++ b/json/json.go @@ -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 { @@ -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 + } - 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 + } + 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 diff --git a/json/json_test.go b/json/json_test.go index 211b3f8b..8942c05a 100644 --- a/json/json_test.go +++ b/json/json_test.go @@ -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)) +}