diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/CommentOutProperty.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/CommentOutProperty.java index 83d5563bc10..8d94aa04c3b 100644 --- a/rewrite-yaml/src/main/java/org/openrewrite/yaml/CommentOutProperty.java +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/CommentOutProperty.java @@ -17,7 +17,11 @@ import lombok.EqualsAndHashCode; import lombok.Value; -import org.openrewrite.*; +import org.jspecify.annotations.Nullable; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Option; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; import org.openrewrite.yaml.tree.Yaml; import java.util.ArrayDeque; @@ -40,6 +44,12 @@ public class CommentOutProperty extends Recipe { example = "The `foo` property is deprecated, please migrate") String commentText; + @Option(example = "true", displayName = "Comment out property", + description = "If false, property wouldn't be commented out, only comment will be added. By default, set to true", + required = false) + @Nullable + Boolean commentOutProperty; + @Override public String getDisplayName() { return "Comment out property"; @@ -61,6 +71,7 @@ public TreeVisitor getVisitor() { private boolean nextDocNeedsNewline; private String comment = ""; private String indentation = ""; + private boolean isBlockCommentExists; @Override public Yaml.Document visitDocument(Yaml.Document document, ExecutionContext ctx) { @@ -72,7 +83,7 @@ public Yaml.Document visitDocument(Yaml.Document document, ExecutionContext ctx) } // Add any leftover comment to the end of document - if (!comment.isEmpty()) { + if (!comment.isEmpty() && !Boolean.FALSE.equals(commentOutProperty)) { String newPrefix = String.format("%s# %s%s%s", indentation, commentText, @@ -89,7 +100,9 @@ public Yaml.Document visitDocument(Yaml.Document document, ExecutionContext ctx) public Yaml.Sequence.Entry visitSequenceEntry(Yaml.Sequence.Entry entry, ExecutionContext ctx) { indentation = entry.getPrefix(); - if (!comment.isEmpty()) { + if (Boolean.FALSE.equals(commentOutProperty)) { + return addBockCommentIfNecessary(entry, ctx); + } else if (!comment.isEmpty()) { // add comment and return String newPrefix = entry.getPrefix() + "# " + commentText + comment + entry.getPrefix(); comment = ""; @@ -103,20 +116,13 @@ public Yaml.Mapping.Entry visitMappingEntry(Yaml.Mapping.Entry entry, ExecutionC String lastIndentation = indentation; indentation = entry.getPrefix(); - if (!comment.isEmpty()) { + if (!comment.isEmpty() && !Boolean.FALSE.equals(commentOutProperty)) { String newPrefix = entry.getPrefix() + "# " + commentText + comment + entry.getPrefix(); comment = ""; return entry.withPrefix(newPrefix); } - Deque propertyEntries = getCursor().getPathAsStream() - .filter(Yaml.Mapping.Entry.class::isInstance) - .map(Yaml.Mapping.Entry.class::cast) - .collect(Collectors.toCollection(ArrayDeque::new)); - - String prop = stream(spliteratorUnknownSize(propertyEntries.descendingIterator(), 0), false) - .map(e2 -> e2.getKey().getValue()) - .collect(Collectors.joining(".")); + String prop = calculateCurrentKeyPath(); if (prop.equals(propertyKey)) { String prefix = entry.getPrefix(); @@ -128,12 +134,50 @@ public Yaml.Mapping.Entry visitMappingEntry(Yaml.Mapping.Entry entry, ExecutionC comment = lastIndentation + "#" + entry.print(getCursor().getParentTreeCursor()); } - doAfterVisit(new DeleteProperty(propertyKey, null, null, null).getVisitor()); + if (Boolean.FALSE.equals(commentOutProperty)) { + if (!entry.getPrefix().contains(commentText) && !isBlockCommentExists) { + return entry.withPrefix(entry.getPrefix() + "# " + commentText + (entry.getPrefix().contains("\n") ? entry.getPrefix() : "\n" + entry.getPrefix())); + } + } else { + doAfterVisit(new DeleteProperty(propertyKey, null, null, null).getVisitor()); + } return entry; } return super.visitMappingEntry(entry, ctx); } + + private Yaml.Sequence.Entry addBockCommentIfNecessary(Yaml.Sequence.Entry entry, ExecutionContext ctx) { + boolean propertyExistsInSequence = isPropertyExistsInSequence(entry); + if (propertyExistsInSequence) { + isBlockCommentExists = true; + if (!entry.getPrefix().contains(commentText)) { + return entry.withPrefix(entry.getPrefix() + "# " + commentText + (entry.getPrefix().contains("\n") ? entry.getPrefix() : "\n" + entry.getPrefix())); + } + } + return super.visitSequenceEntry(entry, ctx); + } + + private boolean isPropertyExistsInSequence(Yaml.Sequence.Entry entry) { + if (!(entry.getBlock() instanceof Yaml.Mapping)) { + return false; + } + Yaml.Mapping mapping = (Yaml.Mapping) entry.getBlock(); + String prop = calculateCurrentKeyPath(); + return mapping.getEntries().stream() + .anyMatch(e -> propertyKey.equals(prop + "." + e.getKey().getValue())); + } + + private String calculateCurrentKeyPath() { + Deque propertyEntries = getCursor().getPathAsStream() + .filter(Yaml.Mapping.Entry.class::isInstance) + .map(Yaml.Mapping.Entry.class::cast) + .collect(Collectors.toCollection(ArrayDeque::new)); + + return stream(spliteratorUnknownSize(propertyEntries.descendingIterator(), 0), false) + .map(e2 -> e2.getKey().getValue()) + .collect(Collectors.joining(".")); + } }; } } diff --git a/rewrite-yaml/src/test/java/org/openrewrite/yaml/CommentOutPropertyTest.java b/rewrite-yaml/src/test/java/org/openrewrite/yaml/CommentOutPropertyTest.java index 57334b24734..9f5d7dcf239 100644 --- a/rewrite-yaml/src/test/java/org/openrewrite/yaml/CommentOutPropertyTest.java +++ b/rewrite-yaml/src/test/java/org/openrewrite/yaml/CommentOutPropertyTest.java @@ -17,24 +17,17 @@ import org.junit.jupiter.api.Test; import org.openrewrite.DocumentExample; -import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; import static org.openrewrite.yaml.Assertions.yaml; class CommentOutPropertyTest implements RewriteTest { - @Override - public void defaults(RecipeSpec spec) { - spec.recipe(new CommentOutProperty("management.metrics.binders.files.enabled", "some comments")); - } - @DocumentExample("comment out a map entry") @Test void regular() { rewriteRun( - spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence.propertyA", - "Some comments")), + spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence.propertyA", "Some comments", null)), yaml( """ foo: @@ -63,8 +56,7 @@ void regular() { @Test void commentSequence() { rewriteRun( - spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence", - "Some comments")), + spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence", "Some comments", null)), yaml( """ foo: @@ -92,8 +84,7 @@ void commentSequence() { @Test void commentSingleProperty() { rewriteRun( - spec -> spec.recipe(new CommentOutProperty("with.java-version", - "Some comments")), + spec -> spec.recipe(new CommentOutProperty("with.java-version", "Some comments", null)), yaml( """ with: @@ -115,8 +106,7 @@ void commentSingleProperty() { @Test void commentLastPropertyWithIndent() { rewriteRun( - spec -> spec.recipe(new CommentOutProperty("with.java-version", - "Some comments")), + spec -> spec.recipe(new CommentOutProperty("with.java-version", "Some comments", null)), yaml( """ with: @@ -136,8 +126,7 @@ void commentLastPropertyWithIndent() { @Test void commentLastPropertyOfFirstDocument() { rewriteRun( - spec -> spec.recipe(new CommentOutProperty("with.java-version", - "Some comments")), + spec -> spec.recipe(new CommentOutProperty("with.java-version", "Some comments", null)), yaml( """ with: @@ -159,8 +148,7 @@ void commentLastPropertyOfFirstDocument() { @Test void commentLastProperty() { rewriteRun( - spec -> spec.recipe(new CommentOutProperty("test", - "Some comments")), + spec -> spec.recipe(new CommentOutProperty("test", "Some comments", null)), yaml( """ test: foo @@ -172,4 +160,172 @@ void commentLastProperty() { ) ); } + + @DocumentExample("comment out a map entry") + @Test + void sequenceKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence.propertyA", + "Some comments", false)), + yaml( + """ + foo: + bar: + sequence: + - name: name + - propertyA: fieldA + - propertyB: fieldB + scalar: value + """, + """ + foo: + bar: + sequence: + - name: name + # Some comments + - propertyA: fieldA + - propertyB: fieldB + scalar: value + """ + ) + ); + } + + @DocumentExample("comment out a map entry") + @Test + void sequenceFirstKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence.name", "Some comments", false)), + yaml( + """ + foo: + bar: + sequence: + - name: name + - propertyA: fieldA + - propertyB: fieldB + scalar: value + """, + """ + foo: + bar: + sequence: + # Some comments + - name: name + - propertyA: fieldA + - propertyB: fieldB + scalar: value + """ + ) + ); + } + + @DocumentExample("comment out entire sequence") + @Test + void commentSequenceKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence", "Some comments", false)), + yaml( + """ + foo: + bar: + sequence: + - name: name + - propertyA: fieldA + - propertyB: fieldB + scalar: value + """, + """ + foo: + bar: + # Some comments + sequence: + - name: name + - propertyA: fieldA + - propertyB: fieldB + scalar: value + """ + ) + ); + } + + @Test + void commentSinglePropertyKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("with.java-version", "Some comments", false)), + yaml( + """ + with: + java-cache: 'maven' + java-version: 11 + test: 'bar' + """, + """ + with: + java-cache: 'maven' + # Some comments + java-version: 11 + test: 'bar' + """ + ) + ); + } + + @Test + void commentLastPropertyWithIndentKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("with.java-version", "Some comments", false)), + yaml( + """ + with: + java-cache: 'maven' + java-version: 11 + """, + """ + with: + java-cache: 'maven' + # Some comments + java-version: 11 + """ + ) + ); + } + + @Test + void commentLastPropertyOfFirstDocumentKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("with.java-version", "Some comments", false)), + yaml( + """ + with: + java-cache: 'maven' + java-version: 11 + --- + """, + """ + with: + java-cache: 'maven' + # Some comments + java-version: 11 + --- + """ + ) + ); + } + + @Test + void commentLastPropertyKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("test", "Some comments", false)), + yaml( + """ + test: foo + """, + """ + # Some comments + test: foo + """ + ) + ); + } }