Fix order for merging iterator

Consider the following YAML:

    trait1: &t1
      foo: 1

    trait2: &t2
      foo: 2

    merged:
      <<: *t1
      <<: *t2

yq reports:

    $ yq .merged.foo < /tmp/yaml
    2

while the order that yaml-cpp returns is different, since it will
firstly handle 1, and will not replace it with 2:

    $ util/parse < /tmp/yaml
    trait1:
      ? &1 foo
      : &2 1
    trait2:
      foo: 2
    merged:
      *1 : *2

(Don't mix up "*2" with "2", it is trait1)
This commit is contained in:
Azat Khuzhin 2024-05-03 10:55:38 +02:00
parent bcf7604479
commit 2acec3d15b
2 changed files with 21 additions and 3 deletions

View File

@ -97,8 +97,9 @@ void NodeBuilder::OnMapEnd() {
assert(m_mapDepth > 0); assert(m_mapDepth > 0);
detail::node& collection = *m_stack.back(); detail::node& collection = *m_stack.back();
auto& toMerge = *m_mergeDicts.rbegin(); auto& toMerge = *m_mergeDicts.rbegin();
for (detail::node* n : toMerge) { /// The elements for merging should be traversed in reverse order to prefer last values.
MergeMapCollection(collection, *n, m_pMemory); for (auto it = toMerge.rbegin(); it != toMerge.rend(); ++it) {
MergeMapCollection(collection, **it, m_pMemory);
} }
m_mapDepth--; m_mapDepth--;
m_mergeDicts.pop_back(); m_mergeDicts.pop_back();

View File

@ -199,6 +199,23 @@ TEST(LoadNodeTest, MergeKeyAIterator) {
ASSERT_EQ(z_b_keys, 1); ASSERT_EQ(z_b_keys, 1);
} }
TEST(LoadNodeTest, MergeKeyTwoOverrides) {
Node node = Load(R"(
trait1: &t1
foo: 1
trait2: &t2
foo: 2
merged:
<<: *t1
<<: *t2
)");
EXPECT_EQ(NodeType::Map, node["merged"].Type());
EXPECT_FALSE(node["merged"]["<<"]);
EXPECT_EQ(2, node["merged"]["foo"].as<int>());
}
TEST(LoadNodeTest, MergeKeyB) { TEST(LoadNodeTest, MergeKeyB) {
Node node = Load( Node node = Load(
"{x: &foo {a : 1,b : 1,c : 1}, y: &bar {d: 2, e : 2, f : 2, a : 2}, z: " "{x: &foo {a : 1,b : 1,c : 1}, y: &bar {d: 2, e : 2, f : 2, a : 2}, z: "
@ -211,7 +228,7 @@ TEST(LoadNodeTest, MergeKeyB) {
EXPECT_EQ(3, node["z"]["b"].as<int>()); EXPECT_EQ(3, node["z"]["b"].as<int>());
EXPECT_EQ(1, node["z"]["c"].as<int>()); EXPECT_EQ(1, node["z"]["c"].as<int>());
EXPECT_EQ(1, node["w"]["a"].as<int>()); EXPECT_EQ(2, node["w"]["a"].as<int>());
EXPECT_EQ(3, node["w"]["b"].as<int>()); EXPECT_EQ(3, node["w"]["b"].as<int>());
EXPECT_EQ(4, node["w"]["c"].as<int>()); EXPECT_EQ(4, node["w"]["c"].as<int>());
EXPECT_EQ(2, node["w"]["d"].as<int>()); EXPECT_EQ(2, node["w"]["d"].as<int>());