Fix excessive exploding for merge anchor

This commit is contained in:
Steven WdV 2025-06-16 13:53:28 +02:00
parent 4d88d51b1b
commit 4734be9a4d
No known key found for this signature in database
2 changed files with 29 additions and 18 deletions

View File

@ -148,12 +148,12 @@ func reconstructAliasedMap(node *CandidateNode, context Context) error {
valueNode := node.Content[index+1] valueNode := node.Content[index+1]
log.Debugf("traversing %v", keyNode.Value) log.Debugf("traversing %v", keyNode.Value)
if keyNode.Tag != "!!merge" { if keyNode.Tag != "!!merge" {
err := overrideEntry(node, keyNode, valueNode, index, context.ChildContext(newContent)) err := overrideEntry(node, keyNode, valueNode, index, true, context.ChildContext(newContent))
if err != nil { if err != nil {
return err return err
} }
} else { } else {
err := applyMergeAnchor(node, valueNode, index, context, newContent) err := applyMergeAnchor(node, valueNode, index, context.ChildContext(newContent))
if err != nil { if err != nil {
return err return err
} }
@ -225,14 +225,14 @@ func explodeNode(node *CandidateNode, context Context) error {
} }
} }
func applyMergeAnchor(node *CandidateNode, merge *CandidateNode, mergeIndex int, context Context, newContent *list.List) error { func applyMergeAnchor(node *CandidateNode, merge *CandidateNode, mergeIndex int, newContent Context) error {
if merge.Kind == AliasNode { if merge.Kind == AliasNode {
merge = merge.Alias merge = merge.Alias
} }
switch merge.Kind { switch merge.Kind {
case MappingNode: case MappingNode:
log.Debugf("a merge map!") log.Debugf("a merge map!")
return applyMergeAnchorMap(node, merge, mergeIndex, context.ChildContext(newContent)) return applyMergeAnchorMap(node, merge, mergeIndex, newContent)
case SequenceNode: case SequenceNode:
log.Debugf("a merge list!") log.Debugf("a merge list!")
// Earlier keys take precedence // Earlier keys take precedence
@ -245,9 +245,8 @@ func applyMergeAnchor(node *CandidateNode, merge *CandidateNode, mergeIndex int,
return fmt.Errorf( return fmt.Errorf(
"can only use merge anchors with maps (!!map) or sequences (!!seq) of maps, but got sequence containing %v", "can only use merge anchors with maps (!!map) or sequences (!!seq) of maps, but got sequence containing %v",
childValue.Tag) childValue.Tag)
return nil
} }
err := applyMergeAnchorMap(node, childValue, mergeIndex, context.ChildContext(newContent)) err := applyMergeAnchorMap(node, childValue, mergeIndex, newContent)
if err != nil { if err != nil {
return err return err
} }
@ -258,20 +257,21 @@ func applyMergeAnchor(node *CandidateNode, merge *CandidateNode, mergeIndex int,
} }
} }
func applyMergeAnchorMap(node *CandidateNode, mergeMap *CandidateNode, aliasIndex int, newContent Context) error { func applyMergeAnchorMap(node *CandidateNode, mergeMap *CandidateNode, mergeIndex int, newContent Context) error {
log.Debug("merge map is nil ?")
if mergeMap == nil { if mergeMap == nil {
log.Debug("merge map is nil")
return nil return nil
} }
log.Debug("merge map: %v", NodeToString(mergeMap)) log.Debug("merge map: %v", NodeToString(mergeMap))
if mergeMap.Kind != MappingNode { if mergeMap.Kind != MappingNode {
return fmt.Errorf("applyMergeAnchorMap expects !!map, got %v instead", mergeMap.Tag) return fmt.Errorf("applyMergeAnchorMap expects !!map, got %v instead", mergeMap.Tag)
} }
for index := 0; index < len(mergeMap.Content); index = index + 2 { for index := 0; index < len(mergeMap.Content); index = index + 2 {
keyNode := mergeMap.Content[index] keyNode := mergeMap.Content[index]
log.Debugf("applying merge map key %v", keyNode.Value) log.Debugf("applying merge map key %v", keyNode.Value)
valueNode := mergeMap.Content[index+1] valueNode := mergeMap.Content[index+1]
err := overrideEntry(node, keyNode, valueNode, aliasIndex, newContent) err := overrideEntry(node, keyNode, valueNode, mergeIndex, false, newContent)
if err != nil { if err != nil {
return err return err
} }
@ -279,12 +279,12 @@ func applyMergeAnchorMap(node *CandidateNode, mergeMap *CandidateNode, aliasInde
return nil return nil
} }
func overrideEntry(node *CandidateNode, key *CandidateNode, value *CandidateNode, startIndex int, newContent Context) error { func overrideEntry(node *CandidateNode, key *CandidateNode, value *CandidateNode, startIndex int, explode bool, newContent Context) error {
if explode {
err := explodeNode(value, newContent) err := explodeNode(value, newContent)
if err != nil {
if err != nil { return err
return err }
} }
for newEl := newContent.MatchingNodes.Front(); newEl != nil; newEl = newEl.Next() { for newEl := newContent.MatchingNodes.Front(); newEl != nil; newEl = newEl.Next() {
@ -308,9 +308,11 @@ func overrideEntry(node *CandidateNode, key *CandidateNode, value *CandidateNode
} }
} }
err = explodeNode(key, newContent) if explode {
if err != nil { err := explodeNode(key, newContent)
return err if err != nil {
return err
}
} }
log.Debugf("adding %v:%v", key.Value, value.Value) log.Debugf("adding %v:%v", key.Value, value.Value)
newContent.MatchingNodes.PushBack(key) newContent.MatchingNodes.PushBack(key)

View File

@ -307,6 +307,15 @@ var anchorOperatorScenarios = []expressionScenario{
"D0, P[m], (!!map)::{a: 42}\n", "D0, P[m], (!!map)::{a: 42}\n",
}, },
}, },
{ // Exploding merge anchor should not explode neighbors
skipDoc: true,
// b must not be exploded, as `r: *a` will become invalid
document: `{b: &b {a: &a 42}, r: *a, c: {<<: *b}}`,
expression: `explode(.c)`,
expected: []string{
"D0, P[], (!!map)::{b: &b {a: &a 42}, r: *a, c: {a: &a 42}}\n",
},
},
} }
func TestAnchorAliasOperatorScenarios(t *testing.T) { func TestAnchorAliasOperatorScenarios(t *testing.T) {