Skip to content

Commit 96b3b51

Browse files
committed
fix(types,merge): treat List/Dictionary as subtypes and add idempotent resolve test
- Replace exact blueId checks in `Types.isListType`/`Types.isDictionaryType` with `isSubtype(...)` using `NodeProvider` to recognize derived types. - Update `ListProcessor` and `DictionaryProcessor` to use the provider-aware checks. - Add `MergerIntegrationTest` verifying `Blue.resolve` is idempotent. Why: Prevent false errors when `itemType`/`keyType` exist on subtype nodes and ensure resolving an already-resolved node is stable.
1 parent 74332fa commit 96b3b51

File tree

4 files changed

+65
-6
lines changed

4 files changed

+65
-6
lines changed

src/main/java/blue/language/merge/processor/DictionaryProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class DictionaryProcessor implements MergingProcessor {
1515

1616
@Override
1717
public void process(Node target, Node source, NodeProvider nodeProvider, NodeResolver nodeResolver) {
18-
if ((source.getKeyType() != null || source.getValueType() != null) && !Types.isDictionaryType(source.getType())) {
18+
if ((source.getKeyType() != null || source.getValueType() != null) && !Types.isDictionaryType(source.getType(), nodeProvider)) {
1919
throw new IllegalArgumentException("Source node with keyType or valueType must have a Dictionary type");
2020
}
2121

src/main/java/blue/language/merge/processor/ListProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class ListProcessor implements MergingProcessor {
1414
@Override
1515
public void process(Node target, Node source, NodeProvider nodeProvider, NodeResolver nodeResolver) {
1616

17-
if (source.getItemType() != null && !Types.isListType(source.getType())) {
17+
if (source.getItemType() != null && !Types.isListType(source.getType(), nodeProvider)) {
1818
throw new IllegalArgumentException("Source node with itemType must have a List type");
1919
}
2020

src/main/java/blue/language/utils/Types.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,12 @@ public static boolean isBooleanType(Node typeNode, NodeProvider nodeProvider) {
113113
}
114114

115115

116-
public static boolean isListType(Node typeNode) {
117-
return typeNode.getBlueId() != null && LIST_TYPE_BLUE_ID.equals(typeNode.getBlueId());
116+
public static boolean isListType(Node typeNode, NodeProvider nodeProvider) {
117+
return isSubtype(typeNode, new Node().blueId(LIST_TYPE_BLUE_ID), nodeProvider);
118118
}
119119

120-
public static boolean isDictionaryType(Node typeNode) {
121-
return typeNode.getBlueId() != null && DICTIONARY_TYPE_BLUE_ID.equals(typeNode.getBlueId());
120+
public static boolean isDictionaryType(Node typeNode, NodeProvider nodeProvider) {
121+
return isSubtype(typeNode, new Node().blueId(DICTIONARY_TYPE_BLUE_ID), nodeProvider);
122122
}
123123

124124
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package blue.language.merge;
2+
3+
import blue.language.Blue;
4+
import blue.language.model.Node;
5+
import blue.language.provider.BasicNodeProvider;
6+
import org.junit.jupiter.api.BeforeEach;
7+
import org.junit.jupiter.api.Test;
8+
9+
import static org.junit.jupiter.api.Assertions.*;
10+
11+
public class MergerIntegrationTest {
12+
13+
private BasicNodeProvider nodeProvider;
14+
15+
@BeforeEach
16+
public void setup() {
17+
nodeProvider = new BasicNodeProvider();
18+
}
19+
20+
@Test
21+
public void shouldBeIdempotentWhenResolvingTheSameNodeTwice() {
22+
nodeProvider.addSingleDocs(
23+
"name: Document Anchor\n" +
24+
"template:\n" +
25+
" description: Optional Blue document template.\n"
26+
);
27+
28+
nodeProvider.addSingleDocs(
29+
"name: Document Anchors\n" +
30+
"type: Dictionary\n" +
31+
"keyType: Text\n" +
32+
"valueType:\n" +
33+
" blueId: " + nodeProvider.getBlueIdByName("Document Anchor") + "\n"
34+
);
35+
36+
nodeProvider.addSingleDocs(
37+
"name: My Entry\n" +
38+
"type:\n" +
39+
" blueId: " + nodeProvider.getBlueIdByName("Document Anchors") + "\n" +
40+
"anchor1:\n" +
41+
" type:\n" +
42+
" blueId: " + nodeProvider.getBlueIdByName("Document Anchor") + "\n" +
43+
"anchor2:\n" +
44+
" type:\n" +
45+
" blueId: " + nodeProvider.getBlueIdByName("Document Anchor") + "\n"
46+
);
47+
48+
Blue blue = new Blue(nodeProvider);
49+
50+
Node myEntry = nodeProvider.getNodeByName("My Entry");
51+
52+
Node resolvedNode = blue.resolve(myEntry);
53+
Node resolvedNode2 = blue.resolve(resolvedNode);
54+
55+
assertEquals(blue.nodeToJson(resolvedNode), blue.nodeToJson(resolvedNode2));
56+
}
57+
}
58+
59+

0 commit comments

Comments
 (0)