Skip to content

Commit

Permalink
#596 Merge sequence of anchors in reverse order
Browse files Browse the repository at this point in the history
+semver:breaking
  • Loading branch information
aaubry authored Apr 1, 2021
2 parents 528999e + 28b31f8 commit ccc272e
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 12 deletions.
58 changes: 50 additions & 8 deletions YamlDotNet.Test/Serialization/SerializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1103,13 +1103,7 @@ public void ExampleFromSpecificationIsHandledCorrectly()
label: center/big
- # Override
#<< : [ *BIG, *LEFT, *SMALL ] # This does not work because, in the current implementation,
# later keys override former keys. This could be fixed, but that
# is not trivial because the deserializer allows aliases to refer to
# an anchor that is defined later in the document, and the way it is
# implemented, the value is assigned later when the anchored value is
# deserialized.
<< : [ *SMALL, *LEFT, *BIG ]
<< : [ *BIG, *LEFT, *SMALL ]
x: 1
label: center/big
"));
Expand Down Expand Up @@ -1163,7 +1157,7 @@ public void MergeNestedReferenceCorrectly()

result["derived3"].Should()
.Contain("key", "D3", "key should be overriden by the actual mapping")
.And.Contain("level", "2", "level should be inherited from the backreferenced mapping");
.And.Contain("level", "1", "level should be inherited from the backreferenced mapping");
}

[Fact]
Expand Down Expand Up @@ -1971,6 +1965,54 @@ public void ShouldIndentSequences()

Assert.Equal(expected.NormalizeNewLines(), yaml.NormalizeNewLines().TrimNewLines());
}

[Fact]
public void ExampleFromSpecificationIsHandledCorrectlyWithLateDefine()
{
var parser = new MergingParser(Yaml.ParserForText(@"
# All the following maps are equal:
results:
- # Explicit keys
x: 1
y: 2
r: 10
label: center/big
- # Merge one map
<< : *CENTER
r: 10
label: center/big
- # Merge multiple maps
<< : [ *CENTER, *BIG ]
label: center/big
- # Override
<< : [ *BIG, *LEFT, *SMALL ]
x: 1
label: center/big
obj:
- &CENTER { x: 1, y: 2 }
- &LEFT { x: 0, y: 2 }
- &SMALL { r: 1 }
- &BIG { r: 10 }
"));

var result = Deserializer.Deserialize<Dictionary<string, List<Dictionary<string, string>>>>(parser);

int index = 0;
foreach (var mapping in result["results"])
{
mapping.Should()
.Contain("x", "1", "'x' should be '1' in result #{0}", index)
.And.Contain("y", "2", "'y' should be '2' in result #{0}", index)
.And.Contain("r", "10", "'r' should be '10' in result #{0}", index)
.And.Contain("label", "center/big", "'label' should be 'center/big' in result #{0}", index);

++index;
}
}

public class CycleTestEntity
{
Expand Down
26 changes: 22 additions & 4 deletions YamlDotNet/Core/MergingParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ private bool HandleMerge(LinkedListNode<ParsingEvent>? node)

if (node.Value is AnchorAlias anchorAlias)
{
return HandleAnchorAlias(node, anchorAlias);
return HandleAnchorAlias(node, node, anchorAlias);
}

if (node.Value is SequenceStart)
Expand All @@ -100,23 +100,41 @@ private bool HandleMerge(LinkedListNode<ParsingEvent>? node)
return false;
}

private bool HandleMergeSequence(LinkedListNode<ParsingEvent> sequenceStart, LinkedListNode<ParsingEvent>? node)
{
if (node is null)
{
return false;
}
if (node.Value is AnchorAlias anchorAlias)
{
return HandleAnchorAlias(sequenceStart, node, anchorAlias);
}
if (node.Value is SequenceStart)
{
return HandleSequence(node);
}
return false;
}

private bool IsMergeToken(LinkedListNode<ParsingEvent> node)
{
return node.Value is Scalar merge && merge.Value == "<<";
}

private bool HandleAnchorAlias(LinkedListNode<ParsingEvent> node, AnchorAlias anchorAlias)
private bool HandleAnchorAlias(LinkedListNode<ParsingEvent> node, LinkedListNode<ParsingEvent> anchorNode, AnchorAlias anchorAlias)
{
var mergedEvents = GetMappingEvents(anchorAlias.Value);

events.AddAfter(node, mergedEvents);
events.MarkDeleted(node);
events.MarkDeleted(anchorNode);

return true;
}

private bool HandleSequence(LinkedListNode<ParsingEvent> node)
{
var sequenceStart = node;
events.MarkDeleted(node);

var current = node;
Expand All @@ -129,7 +147,7 @@ private bool HandleSequence(LinkedListNode<ParsingEvent> node)
}

var next = current.Next;
HandleMerge(next);
HandleMergeSequence(sequenceStart, next);
current = next;
}

Expand Down

0 comments on commit ccc272e

Please sign in to comment.