Make MiniYaml inherits and removal more flexible

- Previously the Inherits syntax was only resolved when used for top-level nodes. Now it is also resolved for nested nodes as well.
- Previously the MiniYAML Merge feature supported the ability to remove nodes, but this only worked within the context of inherited nodes. Now, we allow node removal to work outside of the inheritance context.
This commit is contained in:
RoosterDragon
2024-06-30 10:51:51 +01:00
committed by Gustas
parent dccab8fd21
commit 4312a4d3f4
3 changed files with 108 additions and 21 deletions

View File

@@ -425,19 +425,23 @@ namespace OpenRA
static void MergeIntoResolved(MiniYamlNode overrideNode, List<MiniYamlNode> existingNodes, HashSet<string> existingNodeKeys,
Dictionary<string, MiniYaml> tree, ImmutableDictionary<string, MiniYamlNode.SourceLocation> inherited)
{
if (existingNodeKeys.Add(overrideNode.Key))
var existingNodeIndex = -1;
MiniYamlNode existingNode = null;
if (!existingNodeKeys.Add(overrideNode.Key))
{
existingNodes.Add(overrideNode);
return;
existingNodeIndex = IndexOfKey(existingNodes, overrideNode.Key);
existingNode = existingNodes[existingNodeIndex];
}
var existingNodeIndex = IndexOfKey(existingNodes, overrideNode.Key);
var existingNode = existingNodes[existingNodeIndex];
var value = MergePartial(existingNode.Value, overrideNode.Value);
var value = MergePartial(existingNode?.Value, overrideNode.Value);
var nodes = ResolveInherits(value, tree, inherited);
if (!value.Nodes.SequenceEqual(nodes))
value = value.WithNodes(nodes);
existingNodes[existingNodeIndex] = existingNode.WithValue(value);
if (existingNode != null)
existingNodes[existingNodeIndex] = existingNode.WithValue(value);
else
existingNodes.Add(overrideNode.WithValue(value));
}
static List<MiniYamlNode> ResolveInherits(MiniYaml node, Dictionary<string, MiniYaml> tree, ImmutableDictionary<string, MiniYamlNode.SourceLocation> inherited)

View File

@@ -159,6 +159,71 @@ Root2:
Assert.That(tabs, Is.EqualTo(mixed));
}
[TestCase(TestName = "Yaml files should be able to remove nodes")]
public void NodeRemoval()
{
const string BaseString = @"
Parent:
Child:
Key: value
-Key:
";
const string ResultString = "Parent:\n\tChild:\n";
var baseYaml = MiniYaml.FromString(BaseString, "");
var resultYaml = MiniYaml.Merge(new[] { baseYaml });
Assert.AreEqual(ResultString, resultYaml.WriteToString());
}
[TestCase(TestName = "Merged yaml files should be able to remove nodes")]
public void MergedNodeRemoval()
{
const string BaseString = @"
Parent:
Child:
Key: value
";
const string MergeString = @"
Parent:
Child:
-Key:
";
const string ResultString = "Parent:\n\tChild:\n";
var baseYaml = MiniYaml.FromString(BaseString, "");
var mergeYaml = MiniYaml.FromString(MergeString, "");
var resultYaml = MiniYaml.Merge(new[] { baseYaml, mergeYaml });
Assert.AreEqual(ResultString, resultYaml.WriteToString());
}
[TestCase(TestName = "Merged yaml files should be able to remove nodes from inherited parents")]
public void MergedInheritedNodeRemoval()
{
const string BaseString = @"
^Base:
Child:
Key: value
Parent:
Inherits: ^Base
";
const string MergeString = @"
Parent:
Child:
-Key:
";
const string ResultString = "^Base:\n\tChild:\n\t\tKey: value\nParent:\n\tChild:\n";
var baseYaml = MiniYaml.FromString(BaseString, "");
var mergeYaml = MiniYaml.FromString(MergeString, "");
var resultYaml = MiniYaml.Merge(new[] { baseYaml, mergeYaml });
Assert.AreEqual(ResultString, resultYaml.WriteToString());
}
[TestCase(TestName = "Inheritance and removal can be composed")]
public void InheritanceAndRemovalCanBeComposed()
{
@@ -365,6 +430,33 @@ Test:
"CollectionOfStrings value has not been set with the correct override value for StringC.");
}
[TestCase(TestName = "Inheritance works for nested nodes")]
public void InheritanceWorksForNestedNodes()
{
const string BaseYaml = @"
^DefaultKey:
Key: value
";
const string ExtendedYaml = @"
Parent:
Child:
Inherits: ^DefaultKey
";
const string ResultString =
@"^DefaultKey:
Key: value
Parent:
Child:
Key: value
";
var baseYaml = MiniYaml.FromString(BaseYaml, "");
var mergeYaml = MiniYaml.FromString(ExtendedYaml, "");
var resultYaml = MiniYaml.Merge(new[] { baseYaml, mergeYaml });
Assert.AreEqual(ResultString, resultYaml.WriteToString());
}
[TestCase(TestName = "Empty lines should count toward line numbers")]
public void EmptyLinesShouldCountTowardLineNumbers()
{
@@ -436,7 +528,7 @@ Test:
Assert.That(mergeNode.Nodes[0].Value.Value, Is.EqualTo("override"), "Merge node Child value should be 'override', but is not");
}
[TestCase(TestName = "Duplicated child nodes do not throw if parent does not require merging")]
[TestCase(TestName = "Duplicated child nodes throw merge error if parent does not require merging")]
public void TestMergeConflictsNoMerge()
{
const string BaseYaml = @"
@@ -446,10 +538,10 @@ Test:
Child:
";
var result = MiniYaml.Merge(new[] { BaseYaml }.Select(s => MiniYaml.FromString(s, "")));
var testNodes = result.First(n => n.Key == "Test").Value.Nodes;
var mergeNode = testNodes.First(n => n.Key == "Merge").Value;
Assert.That(mergeNode.Nodes.Count, Is.EqualTo(2));
static void Merge() => MiniYaml.Merge(new[] { BaseYaml }.Select(s => MiniYaml.FromString(s, "test-filename")));
Assert.That(Merge, Throws.Exception.TypeOf<ArgumentException>().And.Message.EqualTo(
"MiniYaml.Merge, duplicate values found for the following keys: Child: [Child (at test-filename:4),Child (at test-filename:5)]"));
}
[TestCase(TestName = "Duplicated child nodes throw merge error if first parent requires merging")]

View File

@@ -83,7 +83,6 @@ light_inf:
Filename: DATA.R16
Start: 4272
Offset: -30,-24
-Remap:
trooper:
Defaults:
@@ -169,7 +168,6 @@ trooper:
Filename: DATA.R16
Start: 4273
Offset: -30,-24
-Remap:
engineer:
Defaults:
@@ -244,7 +242,6 @@ engineer:
Filename: DATA.R16
Start: 4274
Offset: -30,-24
-Remap:
thumper:
Defaults:
@@ -304,7 +301,6 @@ thumper:
Length: 5
Tick: 480
BlendMode: Multiply
-Remap:
die1:
Filename: DATA.R16
Frames: 1543, 1550, 1557, 1564, 1571, 1578, 1585, 1592, 1599, 1600, 1601, 1602
@@ -335,7 +331,6 @@ thumper:
Filename: DATA.R16
Start: 4275
Offset: -30,-24
-Remap:
fremen:
Defaults:
@@ -422,7 +417,6 @@ fremen:
Filename: DATA.R16
Start: 4293
Offset: -30,-24
-Remap:
saboteur:
Defaults:
@@ -497,7 +491,6 @@ saboteur:
Filename: DATA.R16
Start: 4295
Offset: -30,-24
-Remap:
sardaukar:
Defaults:
@@ -586,7 +579,6 @@ sardaukar:
Filename: DATA.R16
Start: 4276
Offset: -30,-24
-Remap:
grenadier:
Defaults:
@@ -662,7 +654,6 @@ grenadier:
Filename: DATA.R16
Start: 4297
Offset: -30,-24
-Remap:
sandworm:
mouth: