Fix error during expansion of !!merge <<: anchor tags (#4383)

* WIP

* Fix merge corner cases

* Add test for explicit !!merge tag

* Fix tests

* Cleanup

* Cleanup

* Fix deanchoring lists

* Add test case for keeping comments

* Add MapEntrySetter and fix json marshalling after deanchoring

* Keep duplicated keys

* Move MergeTag definition to yaml alias

* Remove go-spew from api

* Add support for sequence nodes on merge tags

* Add docstring to MapEntrySetter.Key

* Add docstring to MapEntrySetter struct

* Add tests to MapEntrySetter

* Fix duplicate merge key

* Revert whitespace changes on forked go-yaml

* Remove AssocMapEntry function

* Refactoring merge order

* Return errors on VisitFields and PipeE

* Add tests for each non-conforming map merges
This commit is contained in:
Rafael Leal
2022-03-23 13:36:17 -03:00
committed by GitHub
parent 3490fb8716
commit 97de780feb
8 changed files with 787 additions and 10 deletions

View File

@@ -612,6 +612,50 @@ func Set(value *RNode) FieldSetter {
return FieldSetter{Value: value}
}
// MapEntrySetter sets a map entry to a value. If it finds a key with the same
// value, it will override both Key and Value RNodes, including style and any
// other metadata. If it doesn't find the key, it will insert a new map entry.
// It will set the field, even if it's empty or nil, unlike the FieldSetter.
// This is useful for rebuilding some pre-existing RNode structure.
type MapEntrySetter struct {
// Name is the name of the field or key to lookup in a MappingNode.
// If Name is unspecified, it will use the Key's Value
Name string `yaml:"name,omitempty"`
// Value is the value to set.
Value *RNode `yaml:"value,omitempty"`
// Key is the map key to set.
Key *RNode `yaml:"key,omitempty"`
}
func (s MapEntrySetter) Filter(rn *RNode) (*RNode, error) {
if rn == nil {
return nil, errors.Errorf("Can't set map entry on a nil RNode")
}
if err := ErrorIfInvalid(rn, yaml.MappingNode); err != nil {
return nil, err
}
if s.Name == "" {
s.Name = GetValue(s.Key)
}
for i := 0; i < len(rn.Content()); i = IncrementFieldIndex(i) {
isMatchingField := rn.Content()[i].Value == s.Name
if isMatchingField {
rn.Content()[i] = s.Key.YNode()
rn.Content()[i+1] = s.Value.YNode()
return rn, nil
}
}
// create the field
rn.YNode().Content = append(
rn.YNode().Content,
s.Key.YNode(),
s.Value.YNode())
return rn, nil
}
// FieldSetter sets a field or map entry to a value.
type FieldSetter struct {
Kind string `yaml:"kind,omitempty"`