2222import org .openrewrite .*;
2323import org .openrewrite .internal .ListUtils ;
2424import org .openrewrite .internal .NameCaseConvention ;
25+ import org .openrewrite .internal .NameCaseConvention .Compiled ;
2526import org .openrewrite .marker .Marker ;
2627import org .openrewrite .yaml .tree .Yaml ;
2728
3738@ EqualsAndHashCode (callSuper = false )
3839public class DeleteProperty extends Recipe {
3940 @ Option (displayName = "Property key" ,
40- description = "The key to be deleted." ,
41- example = "management.metrics.binders.files.enabled " )
41+ description = "The key to be deleted. Supports glob patterns. " ,
42+ example = "management.metrics.binders.files.* " )
4243 String propertyKey ;
4344
4445 @ Deprecated
@@ -71,11 +72,14 @@ public class DeleteProperty extends Recipe {
7172
7273 @ Override
7374 public TreeVisitor <?, ExecutionContext > getVisitor () {
75+ Compiled keyMatcher = (!Boolean .FALSE .equals (relaxedBinding ) ?
76+ NameCaseConvention .LOWER_CAMEL :
77+ NameCaseConvention .EXACT ).compile (propertyKey );
78+
7479 return Preconditions .check (new FindSourceFiles (filePattern ), new YamlIsoVisitor <ExecutionContext >() {
7580
7681 @ Override
7782 public Yaml .Documents visitDocuments (Yaml .Documents documents , ExecutionContext ctx ) {
78- // TODO: Update DeleteProperty to support documents having Anchor / Alias Pairs
7983 if (documents != new ReplaceAliasWithAnchorValueVisitor <ExecutionContext >().visit (documents , ctx )) {
8084 return documents ;
8185 }
@@ -95,94 +99,81 @@ public Yaml.Mapping.Entry visitMappingEntry(Yaml.Mapping.Entry entry, ExecutionC
9599 .map (e2 -> e2 .getKey ().getValue ())
96100 .collect (joining ("." ));
97101
98- if (! Boolean . FALSE . equals ( relaxedBinding ) ? NameCaseConvention . equalsRelaxedBinding ( prop , propertyKey ) : prop . equals ( propertyKey )) {
99- doAfterVisit ( new DeletePropertyVisitor <>( entry ) );
102+ if (keyMatcher . matchesGlob ( prop )) {
103+ e = ToBeRemoved . withMarker ( e );
100104 if (Boolean .TRUE .equals (coalesce )) {
101105 maybeCoalesceProperties ();
102106 }
103107 }
104108
105109 return e ;
106110 }
107- });
108- }
109-
110- private static class DeletePropertyVisitor <P > extends YamlVisitor <P > {
111- private final Yaml .Mapping .Entry scope ;
112111
113- private DeletePropertyVisitor (Yaml .Mapping .Entry scope ) {
114- this .scope = scope ;
115- }
112+ @ Override
113+ public Yaml .Sequence visitSequence (Yaml .Sequence sequence , ExecutionContext ctx ) {
114+ Yaml .Sequence s = super .visitSequence (sequence , ctx );
115+ List <Yaml .Sequence .Entry > entries = s .getEntries ();
116+ if (entries .isEmpty ()) {
117+ return s ;
118+ }
116119
117- @ Override
118- public Yaml visitSequence (Yaml .Sequence sequence , P p ) {
119- sequence = (Yaml .Sequence ) super .visitSequence (sequence , p );
120- List <Yaml .Sequence .Entry > entries = sequence .getEntries ();
121- if (entries .isEmpty ()) {
122- return sequence ;
120+ entries = ListUtils .map (entries , entry -> ToBeRemoved .hasMarker (entry ) ? null : entry );
121+ return entries .isEmpty () ? ToBeRemoved .withMarker (s ) : s .withEntries (entries );
123122 }
124123
125- entries = ListUtils .map (entries , entry -> ToBeRemoved .hasMarker (entry ) ? null : entry );
126- return entries .isEmpty () ? ToBeRemoved .withMarker (sequence ) : sequence .withEntries (entries );
127- }
128-
129- @ Override
130- public Yaml visitSequenceEntry (Yaml .Sequence .Entry entry , P p ) {
131- entry = (Yaml .Sequence .Entry ) super .visitSequenceEntry (entry , p );
132- if (entry .getBlock () instanceof Yaml .Mapping ) {
133- Yaml .Mapping m = (Yaml .Mapping ) entry .getBlock ();
134- if (ToBeRemoved .hasMarker (m )) {
135- return ToBeRemoved .withMarker (entry );
124+ @ Override
125+ public Yaml .Sequence .Entry visitSequenceEntry (Yaml .Sequence .Entry entry , ExecutionContext ctx ) {
126+ Yaml .Sequence .Entry e = super .visitSequenceEntry (entry , ctx );
127+ if (e .getBlock () instanceof Yaml .Mapping ) {
128+ Yaml .Mapping m = (Yaml .Mapping ) e .getBlock ();
129+ if (ToBeRemoved .hasMarker (m )) {
130+ return ToBeRemoved .withMarker (e );
131+ }
136132 }
133+ return e ;
137134 }
138- return entry ;
139- }
140-
141- @ Override
142- public Yaml visitMapping (Yaml .Mapping mapping , P p ) {
143- Yaml .Mapping m = (Yaml .Mapping ) super .visitMapping (mapping , p );
144-
145- boolean changed = false ;
146- List <Yaml .Mapping .Entry > entries = new ArrayList <>();
147- String deletedPrefix = null ;
148- int count = 0 ;
149- for (Yaml .Mapping .Entry entry : m .getEntries ()) {
150- if (ToBeRemoved .hasMarker (entry .getValue ())) {
151- changed = true ;
152- continue ;
153- }
154135
155- if (entry == scope || (entry .getValue () instanceof Yaml .Mapping && ((Yaml .Mapping ) entry .getValue ()).getEntries ().isEmpty ())) {
156- deletedPrefix = entry .getPrefix ();
157- changed = true ;
158- } else {
159- if (deletedPrefix != null ) {
160- if (count == 0 && containsOnlyWhitespace (entry .getPrefix ())) {
161- // do this only if the entry will be the first element
162- entry = entry .withPrefix (deletedPrefix );
136+ @ Override
137+ public Yaml .Mapping visitMapping (Yaml .Mapping mapping , ExecutionContext ctx ) {
138+ Yaml .Mapping m = super .visitMapping (mapping , ctx );
139+
140+ boolean changed = false ;
141+ List <Yaml .Mapping .Entry > entries = new ArrayList <>();
142+ String firstDeletedPrefix = null ;
143+ for (Yaml .Mapping .Entry entry : m .getEntries ()) {
144+ if (ToBeRemoved .hasMarker (entry .getValue ()) ||
145+ ToBeRemoved .hasMarker (entry ) ||
146+ (entry .getValue () instanceof Yaml .Mapping && ((Yaml .Mapping ) entry .getValue ()).getEntries ().isEmpty ())) {
147+ // Entry is being deleted - capture prefix from the first deleted entry before any kept entries
148+ if (entries .isEmpty () && firstDeletedPrefix == null ) {
149+ firstDeletedPrefix = entry .getPrefix ();
150+ }
151+ changed = true ;
152+ } else {
153+ if (entries .isEmpty () && firstDeletedPrefix != null && containsOnlyWhitespace (entry .getPrefix ())) {
154+ // This is the first kept entry and there were deleted entries before it
155+ entry = entry .withPrefix (firstDeletedPrefix );
163156 }
164- deletedPrefix = null ;
157+ entries . add ( entry ) ;
165158 }
166- entries .add (entry );
167- count ++;
168159 }
169- }
170160
171- if (changed ) {
172- m = m .withEntries (entries );
173- if (entries .isEmpty ()) {
174- m = ToBeRemoved .withMarker (m );
175- }
161+ if (changed ) {
162+ m = m .withEntries (entries );
163+ if (entries .isEmpty ()) {
164+ m = ToBeRemoved .withMarker (m );
165+ }
176166
177- if (getCursor ().getParentOrThrow ().getValue () instanceof Yaml .Document ) {
178- Yaml .Document document = getCursor ().getParentOrThrow ().getValue ();
179- if (!document .isExplicit ()) {
180- m = m .withEntries (m .getEntries ());
167+ if (getCursor ().getParentOrThrow ().getValue () instanceof Yaml .Document ) {
168+ Yaml .Document document = getCursor ().getParentOrThrow ().getValue ();
169+ if (!document .isExplicit ()) {
170+ m = m .withEntries (m .getEntries ());
171+ }
181172 }
182173 }
174+ return m ;
183175 }
184- return m ;
185- }
176+ });
186177 }
187178
188179 private static boolean containsOnlyWhitespace (@ Nullable String str ) {
0 commit comments