This commit is contained in:
Mike Farah 2020-11-02 13:43:45 +11:00
parent e515b8c2db
commit d6ff198d63
4 changed files with 84 additions and 32 deletions

View File

@ -50,35 +50,35 @@ func explodeNode(node *yaml.Node) error {
}
return nil
case yaml.MappingNode:
var newContent = list.New()
for index := 0; index < len(node.Content); index = index + 2 {
keyNode := node.Content[index]
valueNode := node.Content[index+1]
log.Debugf("traversing %v", keyNode.Value)
if keyNode.Value != "<<" {
errorInContent := explodeNode(valueNode)
if errorInContent != nil {
return errorInContent
}
errorInContent = explodeNode(keyNode)
if errorInContent != nil {
return errorInContent
err := overrideEntry(node, keyNode, valueNode, index, newContent)
if err != nil {
return err
}
} else {
if valueNode.Kind == yaml.SequenceNode {
log.Debugf("an alias merge list!")
for index := len(valueNode.Content) - 1; index >= 0; index = index - 1 {
for index := 0; index < len(valueNode.Content); index = index + 1 {
aliasNode := valueNode.Content[index]
applyAlias(node, aliasNode.Alias)
applyAlias(node, aliasNode.Alias, index, newContent)
}
} else {
log.Debugf("an alias merge!")
applyAlias(node, valueNode.Alias)
applyAlias(node, valueNode.Alias, index, newContent)
}
node.Content = append(node.Content[:index], node.Content[index+2:]...)
//replay that index, since the array is shorter now.
index = index - 2
}
}
node.Content = make([]*yaml.Node, newContent.Len())
index := 0
for newEl := newContent.Front(); newEl != nil; newEl = newEl.Next() {
node.Content[index] = newEl.Value.(*yaml.Node)
index++
}
return nil
default:
@ -86,27 +86,57 @@ func explodeNode(node *yaml.Node) error {
}
}
func applyAlias(node *yaml.Node, alias *yaml.Node) {
func applyAlias(node *yaml.Node, alias *yaml.Node, aliasIndex int, newContent *list.List) error {
if alias == nil {
return
return nil
}
for index := 0; index < len(alias.Content); index = index + 2 {
keyNode := alias.Content[index]
log.Debugf("applying alias key %v", keyNode.Value)
valueNode := alias.Content[index+1]
setIfNotThere(node, keyNode.Value, valueNode)
err := overrideEntry(node, keyNode, valueNode, aliasIndex, newContent)
if err != nil {
return err
}
}
return nil
}
func overrideEntry(node *yaml.Node, key *yaml.Node, value *yaml.Node, startIndex int, newContent *list.List) error {
err := explodeNode(value)
if err != nil {
return err
}
for newEl := newContent.Front(); newEl != nil; newEl = newEl.Next() {
valueEl := newEl.Next() // move forward twice
keyNode := newEl.Value.(*yaml.Node)
log.Debugf("checking new content %v:%v", keyNode.Value, valueEl.Value.(*yaml.Node).Value)
if keyNode.Value == key.Value && keyNode.Alias == nil && key.Alias == nil {
log.Debugf("overridign new content")
valueEl.Value = value
return nil
}
newEl = valueEl // move forward twice
}
for index := startIndex + 2; index < len(node.Content); index = index + 2 {
keyNode := node.Content[index]
if keyNode.Value == key.Value && keyNode.Alias == nil {
log.Debugf("content will be overridden at index %v", index)
return nil
}
}
func setIfNotThere(node *yaml.Node, key string, value *yaml.Node) {
for index := 0; index < len(node.Content); index = index + 2 {
keyNode := node.Content[index]
if keyNode.Value == key {
return
err = explodeNode(key)
if err != nil {
return err
}
}
// need to add it to the map
mapEntryKey := yaml.Node{Value: key, Kind: yaml.ScalarNode}
node.Content = append(node.Content, &mapEntryKey)
node.Content = append(node.Content, value)
log.Debugf("adding %v:%v", key.Value, value.Value)
newContent.PushBack(key)
newContent.PushBack(value)
return nil
}

View File

@ -4,6 +4,8 @@ import (
"testing"
)
//nested alias
var explodeTest = []expressionScenario{
{
document: `{a: mike}`,
@ -20,10 +22,26 @@ var explodeTest = []expressionScenario{
},
},
{
document: mergeDocSample,
expression: `.foo* | explode(.)`,
document: `{f : {a: &a cat, *a: b}}`,
expression: `explode(.f)`,
expected: []string{
"D0, P[], (doc)::{f: {a: cat, b: cat}}\n",
"D0, P[], (doc)::{f: {a: cat, cat: b}}\n",
},
},
{
document: mergeDocSample,
expression: `.foo* | explode(.) | (. style="flow")`,
expected: []string{
"D0, P[foo], (!!map)::{a: foo_a, thing: foo_thing, c: foo_c}\n",
"D0, P[foobarList], (!!map)::{b: bar_b, a: foo_a, thing: bar_thing, c: foobarList_c}\n",
"D0, P[foobar], (!!map)::{c: foo_c, a: foo_a, thing: foobar_thing}\n",
},
},
{
document: `{f : {a: &a cat, b: &b {f: *a}, *a: *b}}`,
expression: `explode(.f)`,
expected: []string{
"D0, P[], (doc)::{f: {a: cat, b: {f: cat}, cat: {f: cat}}}\n",
},
},
}

View File

@ -109,6 +109,11 @@ var pathTests = []struct {
append(make([]interface{}, 0), " (string)"),
append(make([]interface{}, 0), " (string)"),
},
{
`.foo* | (. style="flow")`,
append(make([]interface{}, 0), "foo*", "PIPE", "(", "SELF", "ASSIGN_STYLE", "flow (string)", ")"),
append(make([]interface{}, 0), "foo*", "SELF", "flow (string)", "ASSIGN_STYLE", "PIPE"),
},
// {".animals | .==cat", append(make([]interface{}, 0), "animals", "TRAVERSE", "SELF", "EQUALS", "cat")},
// {".animals | (. == cat)", append(make([]interface{}, 0), "animals", "TRAVERSE", "(", "SELF", "EQUALS", "cat", ")")},

View File

@ -1 +0,0 @@
package treeops