Skip to content

Commit ebd193a

Browse files
authored
Add an applyTo option to the UnfoldProperties recipe (#5500)
* Add an `applyTo` option to the UnfoldProperties recipe * Add an `applyTo` option to the UnfoldProperties recipe * Add an `applyTo` option to the UnfoldProperties recipe * Add an `applyTo` option to the UnfoldProperties recipe * Add an `applyTo` option to the UnfoldProperties recipe * Add an `applyTo` option to the UnfoldProperties recipe
1 parent 297352b commit ebd193a

File tree

2 files changed

+85
-14
lines changed

2 files changed

+85
-14
lines changed

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

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,19 @@ public class UnfoldProperties extends Recipe {
4242
private static final Pattern LINE_BREAK = Pattern.compile("\\R");
4343

4444
@Option(displayName = "Exclusions",
45-
description = "A list of [JsonPath](https://docs.openrewrite.org/reference/jsonpath-and-jsonpathmatcher-reference) expressions to specify keys that should not be unfolded.",
45+
description = "An optional list of [JsonPath](https://docs.openrewrite.org/reference/jsonpath-and-jsonpathmatcher-reference) expressions to specify keys that should not be unfolded.",
4646
example = "$..[org.springframework.security]")
4747
List<String> exclusions;
4848

49-
public UnfoldProperties(@Nullable final List<String> exclusions) {
49+
@Option(displayName = "Apply to",
50+
description = "An optional list of [JsonPath](https://docs.openrewrite.org/reference/jsonpath-and-jsonpathmatcher-reference) expressions that specify which keys the recipe should target only. " +
51+
"Only the properties matching these expressions will be unfolded.",
52+
example = "$..[org.springframework.security]")
53+
List<String> applyTo;
54+
55+
public UnfoldProperties(@Nullable final List<String> exclusions, @Nullable final List<String> applyTo) {
5056
this.exclusions = exclusions == null ? emptyList() : exclusions;
57+
this.applyTo = applyTo == null ? emptyList() : applyTo;
5158
}
5259

5360
@Override
@@ -62,7 +69,7 @@ public String getDescription() {
6269

6370
@Override
6471
public TreeVisitor<?, ExecutionContext> getVisitor() {
65-
List<JsonPathMatcher> matchers = exclusions.stream().map(JsonPathMatcher::new).collect(toList());
72+
List<JsonPathMatcher> exclusionMatchers = exclusions.stream().map(JsonPathMatcher::new).collect(toList());
6673
return new YamlIsoVisitor<ExecutionContext>() {
6774
@Override
6875
public Yaml.Document visitDocument(Yaml.Document document, ExecutionContext ctx) {
@@ -79,10 +86,10 @@ public Yaml.Mapping.Entry visitMappingEntry(Yaml.Mapping.Entry e, ExecutionConte
7986
if (key.contains(".")) {
8087
boolean foundMatch = false;
8188
Cursor c = getCursor();
82-
while (!foundMatch && c.getValue() != Cursor.ROOT_VALUE) {
89+
while (!foundMatch && !c.isRoot()) {
8390
Cursor current = c;
84-
foundMatch = matchers.stream().anyMatch(matcher -> matcher.matches(current));
85-
if(foundMatch) {
91+
foundMatch = exclusionMatchers.stream().anyMatch(it -> it.matches(current));
92+
if (foundMatch) {
8693
break;
8794
} else {
8895
c = c.getParent();
@@ -113,6 +120,7 @@ public Yaml.Mapping.Entry visitMappingEntry(Yaml.Mapping.Entry e, ExecutionConte
113120
/**
114121
* Splits a key into parts while respecting certain exclusion rules.
115122
* The method ensures certain segments of the key are kept together as defined in the exclusion list.
123+
* It also considers the applyTo list during the split process.
116124
*
117125
* @param key the full key to be split into parts
118126
* @return a list of strings representing the split parts of the key
@@ -143,6 +151,12 @@ private List<String> getParts(String key) {
143151
i++;
144152
}
145153

154+
if (!applyTo.isEmpty()) {
155+
if (applyTo.stream().allMatch(it -> matches(key, it, parentKey).isEmpty())) {
156+
return emptyList();
157+
}
158+
}
159+
146160
return result;
147161
}
148162

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

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@
2828
class UnfoldPropertiesTest implements RewriteTest {
2929
@Override
3030
public void defaults(RecipeSpec spec) {
31-
spec.recipe(new UnfoldProperties(null));
31+
spec.recipe(new UnfoldProperties(null, null));
3232
}
3333

3434
@DocumentExample
3535
@Test
3636
void unfold() {
3737
rewriteRun(
38-
spec -> spec.recipe(new UnfoldProperties(List.of("$..[logging.level][?(@property.match(/.*/))]", "$..[enable.process.files]"))),
38+
spec -> spec.recipe(new UnfoldProperties(List.of("$..[logging.level][?(@property.match(/.*/))]", "$..[enable.process.files]"), null)),
3939
yaml(
4040
"""
4141
spring.application.name: my-app
@@ -145,7 +145,7 @@ void exclusions() {
145145
"$..[show.details]",
146146
"$.management.endpoint.health[show.controllers]",
147147
"$.management.endpoint.health.show.views"
148-
))),
148+
), null)),
149149
yaml(
150150
"""
151151
management:
@@ -163,7 +163,7 @@ void exclusions() {
163163
@Test
164164
void exclusionWithSubSetOfKey() {
165165
rewriteRun(
166-
spec -> spec.recipe(new UnfoldProperties(List.of("$..['com.service']"))),
166+
spec -> spec.recipe(new UnfoldProperties(List.of("$..['com.service']"), null)),
167167
yaml(
168168
"""
169169
logging.level.com.service.A: DEBUG
@@ -183,7 +183,7 @@ void exclusionWithSubSetOfKey() {
183183
@Test
184184
void exclusionWithRegex() {
185185
rewriteRun(
186-
spec -> spec.recipe(new UnfoldProperties(List.of("$..[?(@property.match(/some.*/))]"))),
186+
spec -> spec.recipe(new UnfoldProperties(List.of("$..[?(@property.match(/some.*/))]"), null)),
187187
yaml(
188188
"""
189189
A.B:
@@ -202,7 +202,7 @@ void exclusionWithRegex() {
202202
@Test
203203
void exclusionWithParentAndRegex() {
204204
rewriteRun(
205-
spec -> spec.recipe(new UnfoldProperties(List.of("$..[logging.level][?(@property.match(/^com.*/))]"))),
205+
spec -> spec.recipe(new UnfoldProperties(List.of("$..[logging.level][?(@property.match(/^com.*/))]"), null)),
206206
yaml(
207207
"""
208208
first:
@@ -228,7 +228,7 @@ void exclusionWithParentAndRegex() {
228228
@Test
229229
void exclusionWithSingleLineAndMatchAll() {
230230
rewriteRun(
231-
spec -> spec.recipe(new UnfoldProperties(List.of("$..[logging.level][?(@property.match(/.*/))]"))),
231+
spec -> spec.recipe(new UnfoldProperties(List.of("$..[logging.level][?(@property.match(/.*/))]"), null)),
232232
yaml(
233233
"""
234234
logging.level.com.company.extern.service: DEBUG
@@ -251,7 +251,7 @@ void exclusionWithSingleLineAndMatchAll() {
251251
*/
252252
void exclusionWithSingleLineAndGroupMatcherAndMatchAll() {
253253
rewriteRun(
254-
spec -> spec.recipe(new UnfoldProperties(List.of("$..[root.group][?(@property.match(/^sub.*group\\./))][?(@property.match(/.*/))]"))),
254+
spec -> spec.recipe(new UnfoldProperties(List.of("$..[root.group][?(@property.match(/^sub.*group\\./))][?(@property.match(/.*/))]"), null)),
255255
yaml(
256256
"""
257257
root.group.sub1.group.org.key1: value1
@@ -388,4 +388,61 @@ void mergeDuplicatedSectionsWitComments() {
388388
)
389389
);
390390
}
391+
392+
@Test
393+
void applyTo() {
394+
rewriteRun(
395+
spec -> spec.recipe(new UnfoldProperties(
396+
null,
397+
List.of("$..[?(@property.match(/logging.*/))]", "$..[logging.level][?(@property.match(/.*/))]")
398+
)),
399+
yaml(
400+
"""
401+
spring.application:
402+
name: my-app
403+
logging.level:
404+
root: INFO
405+
org.springframework.web: DEBUG
406+
""",
407+
"""
408+
spring.application:
409+
name: my-app
410+
logging:
411+
level:
412+
root: INFO
413+
org:
414+
springframework:
415+
web: DEBUG
416+
"""
417+
)
418+
);
419+
}
420+
421+
@Test
422+
void applyToWithExclusion() {
423+
rewriteRun(
424+
spec -> spec.recipe(new UnfoldProperties(
425+
List.of("$..[logging.level][?(@property.match(/.*springframework.*/))]"),
426+
List.of("$..[?(@property.match(/logging.*/))]", "$..[logging.level][?(@property.match(/.*/))]")
427+
)),
428+
yaml(
429+
"""
430+
spring.application:
431+
name: my-app
432+
logging.level:
433+
root: INFO
434+
org.springframework.web: DEBUG
435+
""",
436+
"""
437+
spring.application:
438+
name: my-app
439+
logging:
440+
level:
441+
root: INFO
442+
org:
443+
springframework.web: DEBUG
444+
"""
445+
)
446+
);
447+
}
391448
}

0 commit comments

Comments
 (0)