Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,37 @@ public class AddToTagVisitor<P> extends XmlVisitor<P> {
@Nullable
private final Comparator<Content> tagComparator;

private final boolean allowDuplicates;

public AddToTagVisitor(Xml.Tag scope, Xml.Tag tagToAdd) {
this(scope, tagToAdd, null);
this(scope, tagToAdd, null, false);
}

public AddToTagVisitor(Xml.Tag scope, Xml.Tag tagToAdd, boolean allowDuplicates) {
this(scope, tagToAdd, null, allowDuplicates);
}

public AddToTagVisitor(Xml.Tag scope, Xml.Tag tagToAdd, @Nullable Comparator<Content> tagComparator) {
this(scope, tagToAdd, tagComparator, false);
}

public AddToTagVisitor(Xml.Tag scope, Xml.Tag tagToAdd, @Nullable Comparator<Content> tagComparator, boolean allowDuplicates) {
this.scope = scope;
this.tagToAdd = tagToAdd;
this.tagComparator = tagComparator;
this.allowDuplicates = allowDuplicates;
}

@Override
public Xml visitTag(Xml.Tag t, P p) {
if (scope.isScope(t)) {
if (!allowDuplicates && t.getContent() != null) {
for (Content existing : t.getContent()) {
if (existing instanceof Xml.Tag && SemanticallyEqual.areEqual(existing, tagToAdd)) {
return super.visitTag(t, p);
}
}
}
assert getCursor().getParent() != null;
if (t.getClosing() == null) {
t = t.withClosing(autoFormat(new Xml.Tag.Closing(Tree.randomId(), "\n",
Expand Down
96 changes: 96 additions & 0 deletions rewrite-xml/src/test/java/org/openrewrite/xml/AddToTagTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,102 @@ public Xml visitDocument(Xml.Document x, ExecutionContext ctx) {
);
}

@Test
void doesNotAddSemanticallyEqualDuplicate() {
rewriteRun(
spec -> spec.recipe(toRecipe(() -> new XmlVisitor<>() {
@Override
public Xml visitDocument(Xml.Document x, ExecutionContext ctx) {
doAfterVisit(new AddToTagVisitor<>(x.getRoot(), Xml.Tag.build("<bean id=\"myBean\"/>")));
return super.visitDocument(x, ctx);
}
})),
xml(
"""
<beans>
<bean id="myBean"/>
</beans>
"""
)
);
}

@Test
void doesNotAddDuplicateIgnoringAttributeOrder() {
rewriteRun(
spec -> spec.recipe(toRecipe(() -> new XmlVisitor<>() {
@Override
public Xml visitDocument(Xml.Document x, ExecutionContext ctx) {
doAfterVisit(new AddToTagVisitor<>(x.getRoot(),
Xml.Tag.build("<bean class=\"C\" id=\"myBean\"/>")));
return super.visitDocument(x, ctx);
}
})),
xml(
"""
<beans>
<bean id="myBean" class="C"/>
</beans>
"""
)
);
}

@Test
void addsSemanticallyEqualDuplicateWhenAllowDuplicatesTrue() {
rewriteRun(
spec -> spec.recipe(toRecipe(() -> new XmlVisitor<>() {
@Override
public Xml visitDocument(Xml.Document x, ExecutionContext ctx) {
if (x.getRoot().getChildren().size() == 1) {
doAfterVisit(new AddToTagVisitor<>(x.getRoot(),
Xml.Tag.build("<bean id=\"myBean\"/>"), true));
}
return super.visitDocument(x, ctx);
}
})),
xml(
"""
<beans>
<bean id="myBean"/>
</beans>
""",
"""
<beans>
<bean id="myBean"/>
<bean id="myBean"/>
</beans>
"""
)
);
}

@Test
void addsWhenChildrenShareNameButDifferentAttributes() {
rewriteRun(
spec -> spec.recipe(toRecipe(() -> new XmlVisitor<>() {
@Override
public Xml visitDocument(Xml.Document x, ExecutionContext ctx) {
doAfterVisit(new AddToTagVisitor<>(x.getRoot(), Xml.Tag.build("<bean id=\"myBean2\"/>")));
return super.visitDocument(x, ctx);
}
})),
xml(
"""
<beans>
<bean id="myBean"/>
</beans>
""",
"""
<beans>
<bean id="myBean"/>
<bean id="myBean2"/>
</beans>
"""
)
);
}

@Issue("https://github.com/openrewrite/rewrite/issues/1392")
@Test
void preserveNonTagContent() {
Expand Down
Loading