Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:57:41 +08:00
commit c2d0b101b0
22 changed files with 6446 additions and 0 deletions

View File

@@ -0,0 +1,200 @@
package com.yourorg;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.EqualsAndHashCode;
import lombok.Value;
import org.jspecify.annotations.NonNull;
import org.openrewrite.*;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.tree.J;
/**
* TODO: Add recipe description
*
* Example usage in YAML:
* ```yaml
* type: specs.openrewrite.org/v1beta/recipe
* name: com.yourorg.MyRecipeGroup
* recipeList:
* - com.yourorg.TemplateRecipe:
* parameterName: value
* ```
*/
@Value
@EqualsAndHashCode(callSuper = false)
public class TemplateRecipe extends Recipe {
/**
* TODO: Add options for recipe configuration
* Each option becomes a parameter that can be configured in YAML
*/
@Option(
displayName = "Parameter Display Name",
description = "A clear description of what this parameter does.",
example = "com.example.ExampleValue"
)
@NonNull
String parameterName;
// Add more @Option fields as needed
// @Option(displayName = "Another Parameter", ...)
// String anotherParameter;
/**
* All recipes must be serializable via Jackson.
* Use @JsonCreator and @JsonProperty annotations.
*/
@JsonCreator
public TemplateRecipe(
@NonNull @JsonProperty("parameterName") String parameterName
) {
this.parameterName = parameterName;
}
@Override
public String getDisplayName() {
return "Your recipe display name";
}
@Override
public String getDescription() {
return "A clear description of what this recipe does. Use sentence case and end with a period.";
}
/**
* Optional: Add preconditions to improve performance
* Recipes only run on files that match these conditions
*/
// @Override
// public TreeVisitor<?, ExecutionContext> getVisitor() {
// return Preconditions.check(
// new UsesType<>("com.example.SomeType", true),
// new TemplateRecipeVisitor()
// );
// }
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
// IMPORTANT: Always return a NEW instance (no caching)
return new TemplateRecipeVisitor();
}
/**
* The visitor implements the actual transformation logic.
* Use JavaIsoVisitor when always returning the same LST type.
*/
public class TemplateRecipeVisitor extends JavaIsoVisitor<ExecutionContext> {
/**
* Optional: Create JavaTemplates for complex code generation
* Templates are parsed once and can be reused
*/
// private final JavaTemplate template = JavaTemplate
// .builder("your.code.template(#{any(String)})")
// .imports("your.imports.Here")
// .build();
/**
* Override visit methods for the LST elements you want to transform.
* Common visit methods:
* - visitCompilationUnit() - entire file
* - visitClassDeclaration() - class declarations
* - visitMethodDeclaration() - method declarations
* - visitMethodInvocation() - method calls
* - visitVariableDeclarations() - variable declarations
* - visitAssignment() - assignments
* - visitBinary() - binary operations
* - visitImport() - imports
*/
@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
// Step 1: ALWAYS call super to traverse the subtree
J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx);
// Step 2: Check if this element needs to be changed
// DO NO HARM: If unsure, return unchanged
if (!shouldChange(cd)) {
return cd;
}
// Step 3: Make your changes
// Never mutate the LST - always use .withX() methods
cd = makeYourChanges(cd, ctx);
// Step 4: Optional - chain other visitors
// doAfterVisit(new SomeOtherRecipe().getVisitor());
// Step 5: Optional - add/remove imports
// maybeAddImport("java.util.List");
// maybeRemoveImport("old.package.Type");
return cd;
}
/**
* Helper method to determine if changes are needed
*/
private boolean shouldChange(J.ClassDeclaration classDecl) {
// TODO: Implement your logic
// Check if change is necessary and safe
// Example: Check if class matches criteria
// Check for null type (avoid NPE)
if (classDecl.getType() == null) {
return false;
}
// Example: Check fully qualified name
// if (!classDecl.getType().getFullyQualifiedName().equals(parameterName)) {
// return false;
// }
// Example: Check if change already exists
// if (alreadyHasTheChange(classDecl)) {
// return false;
// }
return true;
}
/**
* Helper method to perform the transformation
*/
private J.ClassDeclaration makeYourChanges(J.ClassDeclaration classDecl, ExecutionContext ctx) {
// TODO: Implement your transformation logic
// Example: Using a JavaTemplate
// classDecl = classDecl.withBody(
// template.apply(
// new Cursor(getCursor(), classDecl.getBody()),
// classDecl.getBody().getCoordinates().lastStatement(),
// someParameter
// )
// );
// Example: Modifying using LST methods
// classDecl = classDecl.withName(classDecl.getName().withSimpleName("NewName"));
// Example: Using ListUtils to avoid mutation
// classDecl = classDecl.withModifiers(
// ListUtils.concat(classDecl.getModifiers(), newModifier)
// );
return classDecl;
}
/**
* Optional: Example of another visit method
*/
// @Override
// public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
// J.MethodInvocation m = super.visitMethodInvocation(method, ctx);
//
// // Your logic here
//
// return m;
// }
}
}