Declarative YAML format
OpenRewrite allows you to create recipes and styles in YAML. While doing so potentially reduces customizability, it makes up for that with development speed and portability.
To help you confidently define recipes and styles in YAML, this guide will walk you through all of the ways you can configure an OpenRewrite YAML file.
Where OpenRewrite YAML files can exist
There are two places where you can define an OpenRewrite YAML file:
Within the
rewrite.yml
file of a project that applies rewrite recipes via the rewrite-gradle-plugin or rewrite-maven-pluginInside the
META-INF/rewrite
folder of a JAR (such as in the rewrite-testing-frameworks)
If you define a recipe or style in the rewrite.yml
file, they will not be included in the JARs published from your project.
If you want to distribute a recipe or a style and apply them to other projects, you'll need to create them inside of the META-INF/rewrite
folder of a JAR.
Best practices
Please keep these conventions in mind when you're creating OpenRewrite YAML files:
A file may contain any number of recipes and styles, separated by
---
.Within a file, recipe and style names must be fully qualified.
Custom recipes should not be placed into the
org.openrewrite
namespace. Instead, they should follow the same reverse domain name notation used in Java packages.
Recipes
Format
You can find the full recipe schema here.
Key | Type | Description |
---|---|---|
type | const | A constant: |
name | string | A fully qualified, unique name for this recipe |
displayName | string | A human-readable name for this recipe (does not end with a period) |
description | string | A human-readable description for this recipe (ends with a period) |
tags | array of strings | A list of strings that help categorize this recipe |
estimatedEffortPerOccurrence | The expected amount of time saved each time this recipe fixes something | |
causesAnotherCycle | boolean | Whether or not this recipe can cause another cycle (defaults to false) |
array of recipes | The list of recipes which comprise this recipe |
Preconditions
Preconditions are used to limit which source files a recipe is run on. This is commonly used to target specific files or directories, but any recipe which is not a ScanningRecipe
can be used as a precondition.
Preconditions are a per-file check. If a file passes the precondition check, all recipes will be run on it.
If you need to check if your repository meets certain criteria, instead (e.g., ensuring that a test source set exists), then you will need to write a custom ScanningRecipe
.
When a recipe is used as a precondition, any file it would make a change to is considered to meet the precondition. When more than one recipe are used as preconditions, all of them must make a change to the file for it to be considered to meet the precondition.
Only when all preconditions are met will the recipes in the recipe list be run. When applying preconditions to ScanningRecipes
they limit both the scanning phase and the edit phase.
Changes made by preconditions are not included in the final result of the recipe. Changes made by preconditions are used only to determine if the recipe should be run.
To create these top-level preconditions, you'll need to add the preconditions
map to your declarative recipe's YAML. This object is a list of one or more recipes (formatted the same way as the recipeList).
On its own ChangeText
would change the contents of all text files in the project to 2
. But because Find
is used as a precondition, ChangeText
will only be run on files that contain a 1
.
Recipes commonly used as preconditions include:
org.openrewrite.FindSourceFiles
- limits the recipe to only run on files whose path matches a glob patternorg.openrewrite.text.Find
- limits the recipe to only run on files that contain a given stringorg.openrewrite.java.search.FindTypes
- limits the recipe to run only on source code which contain a given typeorg.openrewrite.java.search.HasJavaVersion
- limits the recipe to run only on Java source code with the specified source or target compatibility versions. Allowing a recipe to be targeted only at Java 8, 11, 17, etc., code.org.openrewrite.java.search.IsLikelyTest
- limits the recipe to run only on source code which is likely to be test code.org.openrewrite.java.search.IsLikelyNotTest
- limits the recipe to run only on source code which is likely to be production code.
Recipe list
A declarative recipe can be made up of one or more recipes. The recipes in the list could be other declarative recipes defined in the same file or they can be imperative recipes created elsewhere. Like imperative recipes, each recipe in this list can potentially have configuration options that need to be specified.
Recipes in the recipeList
will run in the order they are listed. That being said, a declarative recipe may include another declarative recipe declared later in the same rewrite.yml
file.
Recipe example
Consider this example declarative recipe:
If you wanted to run this recipe (but not distribute it to others), you would:
Copy the above YAML into a
rewrite.yml
file at the root of your projectConfigure the Gradle plugin or Maven plugin to have an active recipe of
com.yourorg.RecipeA
Run the
mvn rewrite:run
or thegradle rewriteRun
command
Styles
Format
You can find the full style schema here.
Key | Type | Description |
---|---|---|
type | const | A constant: |
name | string | A fully qualified, unique name for this style |
displayName | string | A human-readable name for this style (does not end with a period) |
description | string | A human-readable description for this style (ends with a period) |
tags | array of strings | A list of strings that help categorize this style |
styleConfigs | array of styles | The list of styles which comprise this style |
Style example
Consider this example declarative style, which specifies that tabs should be used for indentation and that at least 9999 imports from a given package should be required before collapsing them into a single star import:
To put this style in effect for any formatting performed by OpenRewrite within the current project:
Put the above into a
rewrite.yml
file at the project rootConfigure the gradle plugin or maven plugin with
com.yourorg.YesTabsNoStarImports
listed as the active style
The next time any OpenRewrite recipe is run in that project, any formatting it performs will take these styles into account.
Last updated