Skip to content

Commit afc5028

Browse files
DeleteProperty: preserve inline comments when deleting entries (#6797)
* DeleteProperty: preserve inline comments when deleting entries When an entry was deleted from a mapping, the newline fix-up logic checked `startsWithNewline(prefix)` to decide whether to prepend a newline. Inline comments are stored in the prefix of the next element (e.g. ` # comment\n `), which starts with a space, not `\n`. This caused the comment to be moved onto its own line. Changed the check to `containsNewline(prefix)` so that prefixes which already contain a line break (even if preceded by an inline comment) are left intact. * Show limitation of the current approach * DeleteProperty: preserve inline comments when deleting last entry When the deleted entry is the last in a mapping, its prefix contains the inline comment from the previous entry's line. Transfer that comment to the previous kept entry's scalar value so it is not lost. * Use `ListUtils.mapLast` --------- Co-authored-by: Tim te Beek <tim@moderne.io>
1 parent 5d457b1 commit afc5028

2 files changed

Lines changed: 53 additions & 5 deletions

File tree

rewrite-yaml/src/main/java/org/openrewrite/yaml/DeleteProperty.java

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public Yaml.Sequence visitSequence(Yaml.Sequence sequence, ExecutionContext ctx)
129129
for (int i = 1; i < entries.size(); i++) {
130130
Yaml.Sequence.Entry entry = entries.get(i);
131131
Yaml.Sequence.Entry prevEntry = entries.get(i - 1);
132-
if (!startsWithNewline(entry.getPrefix()) && !endsWithBlockScalar(prevEntry.getBlock())) {
132+
if (!containsNewline(entry.getPrefix()) && !endsWithBlockScalar(prevEntry.getBlock())) {
133133
if (fixedEntries == null) {
134134
fixedEntries = new ArrayList<>(entries);
135135
}
@@ -165,6 +165,7 @@ public Yaml.Mapping visitMapping(Yaml.Mapping mapping, ExecutionContext ctx) {
165165
List<Yaml.Mapping.Entry> entries = new ArrayList<>();
166166
String firstDeletedPrefix = null;
167167
boolean previousWasDeleted = false;
168+
String trailingInlineComment = null;
168169
for (Yaml.Mapping.Entry entry : m.getEntries()) {
169170
if (ToBeRemoved.hasMarker(entry.getValue()) ||
170171
ToBeRemoved.hasMarker(entry) ||
@@ -173,19 +174,38 @@ public Yaml.Mapping visitMapping(Yaml.Mapping mapping, ExecutionContext ctx) {
173174
if (entries.isEmpty() && firstDeletedPrefix == null) {
174175
firstDeletedPrefix = entry.getPrefix();
175176
}
177+
// Capture inline comment from the first deleted entry after kept entries
178+
if (trailingInlineComment == null && !entries.isEmpty()) {
179+
trailingInlineComment = extractInlineComment(entry.getPrefix());
180+
}
176181
changed = true;
177182
previousWasDeleted = true;
178183
} else {
179184
if (entries.isEmpty() && firstDeletedPrefix != null && containsOnlyWhitespace(entry.getPrefix())) {
180185
entry = entry.withPrefix(firstDeletedPrefix);
181-
} else if (previousWasDeleted && !entries.isEmpty() && !startsWithNewline(entry.getPrefix())) {
186+
} else if (previousWasDeleted && !entries.isEmpty() && !containsNewline(entry.getPrefix())) {
182187
entry = entry.withPrefix("\n" + entry.getPrefix());
183188
}
184189
entries.add(entry);
185190
previousWasDeleted = false;
191+
trailingInlineComment = null;
186192
}
187193
}
188194

195+
// Preserve inline comment from deleted trailing entries on the last kept entry
196+
if (trailingInlineComment != null) {
197+
String comment = trailingInlineComment;
198+
entries = ListUtils.mapLast(entries, lastKept -> {
199+
if (lastKept.getValue() instanceof Yaml.Scalar &&
200+
((Yaml.Scalar) lastKept.getValue()).getStyle() == Yaml.Scalar.Style.PLAIN) {
201+
Yaml.Scalar scalar = (Yaml.Scalar) lastKept.getValue();
202+
return lastKept.withValue(
203+
scalar.withValue(scalar.getValue() + comment));
204+
}
205+
return lastKept;
206+
});
207+
}
208+
189209
if (changed) {
190210
m = m.withEntries(entries);
191211
if (entries.isEmpty()) {
@@ -206,7 +226,7 @@ public Yaml.Mapping visitMapping(Yaml.Mapping mapping, ExecutionContext ctx) {
206226
for (int i = 1; i < currentEntries.size(); i++) {
207227
Yaml.Mapping.Entry entry = currentEntries.get(i);
208228
Yaml.Mapping.Entry prevEntry = currentEntries.get(i - 1);
209-
if (!startsWithNewline(entry.getPrefix()) && !endsWithBlockScalar(prevEntry)) {
229+
if (!containsNewline(entry.getPrefix()) && !endsWithBlockScalar(prevEntry)) {
210230
if (fixedEntries == null) {
211231
fixedEntries = new ArrayList<>(currentEntries);
212232
}
@@ -238,8 +258,18 @@ private static boolean containsOnlyWhitespace(@Nullable String str) {
238258
return true;
239259
}
240260

241-
private static boolean startsWithNewline(@Nullable String str) {
242-
return str != null && !str.isEmpty() && str.charAt(0) == '\n';
261+
private static boolean containsNewline(@Nullable String str) {
262+
return str != null && str.indexOf('\n') >= 0;
263+
}
264+
265+
/**
266+
* Extract an inline comment from a prefix string. Inline comments appear before the
267+
* first newline in the prefix (e.g. {@code " # comment\n "} → {@code " # comment"}).
268+
*/
269+
private static @Nullable String extractInlineComment(String prefix) {
270+
int newlineIndex = prefix.indexOf('\n');
271+
String beforeNewline = newlineIndex >= 0 ? prefix.substring(0, newlineIndex) : prefix;
272+
return beforeNewline.contains("#") ? beforeNewline : null;
243273
}
244274

245275
private static boolean endsWithBlockScalar(Yaml.Mapping.Entry entry) {

rewrite-yaml/src/test/java/org/openrewrite/yaml/DeletePropertyKeyTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,4 +544,22 @@ void globPatternWithFoldedBlockScalarHigherParent() {
544544
)
545545
);
546546
}
547+
548+
@Test
549+
void deleteLastEntryPreservesInlineCommentOnPreviousEntry() {
550+
rewriteRun(
551+
spec -> spec.recipe(new DeleteProperty("root.delete-me", null, null, null)),
552+
yaml(
553+
"""
554+
root:
555+
keep: yes # inline comment
556+
delete-me: val
557+
""",
558+
"""
559+
root:
560+
keep: yes # inline comment
561+
"""
562+
)
563+
);
564+
}
547565
}

0 commit comments

Comments
 (0)