Fix inline map exploding when it contains aliases

This commit is contained in:
Steven WdV 2025-06-16 16:09:55 +02:00
parent 4734be9a4d
commit ce9a4af0df
No known key found for this signature in database
2 changed files with 42 additions and 4 deletions

View File

@ -226,19 +226,23 @@ func explodeNode(node *CandidateNode, context Context) error {
} }
func applyMergeAnchor(node *CandidateNode, merge *CandidateNode, mergeIndex int, newContent Context) error { func applyMergeAnchor(node *CandidateNode, merge *CandidateNode, mergeIndex int, newContent Context) error {
inline := true
if merge.Kind == AliasNode { if merge.Kind == AliasNode {
inline = false
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, newContent) return applyMergeAnchorMap(node, merge, mergeIndex, inline, newContent)
case SequenceNode: case SequenceNode:
log.Debugf("a merge list!") log.Debugf("a merge list!")
// Earlier keys take precedence // Earlier keys take precedence
for index := len(merge.Content) - 1; index >= 0; index = index - 1 { for index := len(merge.Content) - 1; index >= 0; index = index - 1 {
childValue := merge.Content[index] childValue := merge.Content[index]
childInline := inline
if childValue.Kind == AliasNode { if childValue.Kind == AliasNode {
childInline = false
childValue = childValue.Alias childValue = childValue.Alias
} }
if childValue.Kind != MappingNode { if childValue.Kind != MappingNode {
@ -246,7 +250,7 @@ func applyMergeAnchor(node *CandidateNode, merge *CandidateNode, mergeIndex int,
"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)
} }
err := applyMergeAnchorMap(node, childValue, mergeIndex, newContent) err := applyMergeAnchorMap(node, childValue, mergeIndex, inline && childInline, newContent)
if err != nil { if err != nil {
return err return err
} }
@ -257,7 +261,7 @@ func applyMergeAnchor(node *CandidateNode, merge *CandidateNode, mergeIndex int,
} }
} }
func applyMergeAnchorMap(node *CandidateNode, mergeMap *CandidateNode, mergeIndex int, newContent Context) error { func applyMergeAnchorMap(node *CandidateNode, mergeMap *CandidateNode, mergeIndex int, explode bool, newContent Context) error {
if mergeMap == nil { if mergeMap == nil {
log.Debug("merge map is nil") log.Debug("merge map is nil")
return nil return nil
@ -267,11 +271,18 @@ func applyMergeAnchorMap(node *CandidateNode, mergeMap *CandidateNode, mergeInde
return fmt.Errorf("applyMergeAnchorMap expects !!map, got %v instead", mergeMap.Tag) return fmt.Errorf("applyMergeAnchorMap expects !!map, got %v instead", mergeMap.Tag)
} }
if explode {
err := explodeNode(mergeMap, newContent)
if err != nil {
return err
}
}
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, mergeIndex, false, newContent) err := overrideEntry(node, keyNode, valueNode, mergeIndex, explode, newContent)
if err != nil { if err != nil {
return err return err
} }

View File

@ -316,6 +316,33 @@ var anchorOperatorScenarios = []expressionScenario{
"D0, P[], (!!map)::{b: &b {a: &a 42}, r: *a, c: {a: &a 42}}\n", "D0, P[], (!!map)::{b: &b {a: &a 42}, r: *a, c: {a: &a 42}}\n",
}, },
}, },
{ // Exploding sequence 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",
},
},
{ // Exploding inline merge anchor
skipDoc: true,
// `<<` map must be exploded, otherwise `c: *b` will become invalid
document: `{a: {b: &b 42}, <<: {c: *b}}`,
expression: `explode(.)`,
expected: []string{
"D0, P[], (!!map)::{a: {b: 42}, c: 42}\n",
},
},
{ // Exploding inline merge anchor in sequence
skipDoc: true,
// `<<` map must be exploded, otherwise `c: *b` will become invalid
document: `{a: {b: &b 42}, <<: [{c: *b}]}`,
expression: `explode(.)`,
expected: []string{
"D0, P[], (!!map)::{a: {b: 42}, c: 42}\n",
},
},
} }
func TestAnchorAliasOperatorScenarios(t *testing.T) { func TestAnchorAliasOperatorScenarios(t *testing.T) {