openrewrite / rewrite

Automated mass refactoring of source code.
https://docs.openrewrite.org
Apache License 2.0
1.98k stars 293 forks source link

Enhance XPath matcher with child selection predicates #593

Closed aegershman closed 2 years ago

aegershman commented 3 years ago

see: https://github.com/openrewrite/rewrite/issues/571 see: https://github.com/openrewrite/rewrite/pull/588

In order to enable more powerful declarative recipes, enhance the XPath Matcher (XML and YAML) with the ability to match paths of elements based on selection criteria. For example:

/project/build/plugins/plugin[artifactId="rewrite-maven-plugin"]/configuration/activeRecipes

Where plugin[artifactId="rewrite-maven-plugin"] enables selecting elements of <plugin> which have <artifactId>rewrite-maven-plugin</artifactId> as subchildren.

This opens the door to declarative recipes which could use a string parsed into an xpath expression that can be more refined with how it selects elements. For example, a hypothetical Maven recipe such as RemoveDeprecatedMavenGoal could just be defined as a "base" recipe, hypothetically, "RemoveXmlContentByPath". The need to remove a deprecated Maven goal could then just be defined as:

- org.openrewrite.example.RemoveXmlContentByPath:
     xpathExpression: "/project/*/plugins/plugin[artifactId="some-plugin"]/executions/execution/goals/goal[. = "deprecated-goal"]

Without the ability to select a plugin to operate on based on a artifactId subchild value within the xpath expression, this would select all plugins, which isn't always desired. Additionally, adding content using a declarative recipe could be done by path as well. Additionally additionally, assuming the xpath matcher logic could be used with rewrite-yaml, this has implications for downstream libraries such as rewrite-kubernetes as well.

Note, the goal is not to have our xpath matcher be completely equivalent to an actual xpath evaluator-- specifically this is for enabling selection criteria based on subelement values.

sambsnyd commented 2 years ago

This is a good idea. We can implement it when we decide to create a recipe which would benefit from it.