Add optional ecosystem parameter to ChangeType#7833
Conversation
`ChangeType` applies to every `JavaSourceFile`. Because Python and JavaScript reuse the Java LST model (their compilation units implement `JavaSourceFile`), a JVM-targeted type change still runs its full `UsesType` precondition scan over every Python/JS file, even though those languages can never reference a JVM type. Add an optional `ecosystem` option (`jvm`, `python`, `javascript`) that scopes the change to a single ecosystem. Default (null) is unchanged: the recipe runs on all source files. Reference-based files (XML, properties) are always processed since they may carry type references.
| case "js": | ||
| return "javascript"; | ||
| case "py": | ||
| return "python"; |
There was a problem hiding this comment.
Shouldn't the alternatives also be in the valid set at that point?
|
I think really a core of the problem is that yes, this really would affect all the One suggestion I saw proposed was related to having a Additionally the posibility of having an applicable languages property on a recipe generically might allow you to scope things through that rather than having to pass it as an option: declarative recipes could be scoped in yaml and imperative could be scoped via overriding a method. That too changes the exposed api for a recipe, which gets messy in different ways. Not sure how I feel about all these yet, as it's a not-insubstantial change for any path here. |
Problem
org.openrewrite.java.ChangeTypeapplies to everyJavaSourceFile:Python and JavaScript reuse the Java LST model —
Py.CompilationUnitandJS.CompilationUnitboth implementJavaSourceFile. So a JVM-targetedChangeTypeaccepts every Python/JS file and runs itsUsesTypeprecondition, walking the entire AST looking for a JVM fully-qualified type that can never appear there.In telemetry from a single recipe run (see issue for the full table),
ChangeTypespent 423 s onfinos/symphony-bdk-python— which has zero Java files — and changed nothing. On Python-heavy repos this is enough to push recipe runs past the timeout.Proposal
Add an optional
ecosystemoption (jvm,python,javascript) that scopes the change to a single ecosystem:null) — unchanged behavior: the recipe runs on all source files.UsesTypescan.The new constructor is annotated
@JsonCreator; the prior 3-arg constructor is preserved for backward compatibility.Open questions for discussion
org.openrewrite.python.*,org.openrewrite.javascript.*, elsejvm). Is there a cleaner / more robust signal we'd prefer (e.g. a marker or aSourceFile-level capability)?ChangeMethodName,UsesType-based recipes, …). Should this live onChangeTypealone, or be lifted into a shared precondition/utility so every affected recipe benefits?ecosystemstring vs. a more general include/exclude list? Naming (jvmvsjava)?Changes
ChangeType: new optionalecosystemoption + ecosystem-skip logic, backward-compatible constructor.ChangeTypeTest(jvm applies / non-jvm skips Java files) andChangeTypeIntegTest(jvm scope skips Python files).Possible follow-up: roll this out broadly via a best-practices recipe
The per-recipe option above is only worthwhile if it actually gets set across the large meta-recipes that drive the cost (Spring Boot upgrades,
migrate-java, etc.), where hundreds ofChangeTypesteps each scan every Python/JS file.Rather than hand-editing each declarative recipe, we could add a recipe to rewrite best practices that infers the right
ecosystemfor an existingChangeTypestep from indicators already present in the declarative YAML — e.g. the package of the changed class (org.springframework.*,javax.*, … →jvm) — and fills in theecosystemoption automatically.Run across
rewrite-migrate-java,rewrite-spring, and the other recipe libraries, that would scope everyChangeType(and ideally the otherUsesType-based steps) tojvmin one sweep — turning this from a single-recipe opt-in into a broad win, where the biggest savings land precisely on the Python/JS-heavy repos that pay the most today.