Skip to content

Comments

Add PlainTextAs<T> recipes for parsing plain text as typed source files#6356

Open
DovOps wants to merge 1 commit intoopenrewrite:mainfrom
DovOps:feature/plain-text-as-type
Open

Add PlainTextAs<T> recipes for parsing plain text as typed source files#6356
DovOps wants to merge 1 commit intoopenrewrite:mainfrom
DovOps:feature/plain-text-as-type

Conversation

@DovOps
Copy link
Contributor

@DovOps DovOps commented Nov 30, 2025

THIS SOFTWARE IS CONTRIBUTED SUBJECT TO THE TERMS OF THE APACHE LICENSE V.2.0. YOU MAY OBTAIN A COPY OF THE LICENSE AT https://www.apache.org/licenses/LICENSE-2.0.

THIS SOFTWARE IS LICENSED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY WARRANTY OF NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE MAY BE REDISTRIBUTED TO OTHERS ONLY BY EFFECTIVELY USING THIS OR ANOTHER EQUIVALENT DISCLAIMER IN ADDITION TO ANY OTHER REQUIRED LICENSE TERMS.

Summary

This PR introduces a generic PlainTextAs<T> framework for converting plain text files with non-standard extensions into typed source files, enabling language-specific recipes to be applied to them.

Problem

In some environments, proprietary filenames or patterns represent known configuration file formats. OpenRewrite parses these as plain text since it doesn't recognize the file type. Users need a way to re-parse these files as their actual type within the LST so they can run type-specific recipes on them.

Solution

Added an abstract PlainTextAs<T> base recipe with concrete implementations for common file types:

Recipe Module Use Case
PlainTextAsXml rewrite-xml Proprietary config files containing XML
PlainTextAsYaml rewrite-yaml Custom extensions containing YAML
PlainTextAsProperties rewrite-properties Non-standard property files
PlainTextAsGroovy rewrite-groovy Jenkinsfiles and similar Groovy scripts

Key Design Decisions

  1. File pattern is required - These recipes specifically target non-standard extensions. Standard extensions (.xml, .yaml, .properties, .groovy) should be handled by configuring parsers at LST build time.

  2. Documentation emphasizes proper usage - The descriptions clearly state that this is for adjusting an existing LST when default parsers don't parse files into the target language.

Example Usage

---
type: specs.openrewrite.org/v1beta/recipe
name: com.example.ParseCustomConfigs
recipeList:
  - org.openrewrite.xml.PlainTextAsXml:
      filePattern: "**/*.myconfig"
  - org.openrewrite.xml.ChangeTagValue:
      elementName: /config/setting
      newValue: updated

Testing

Each implementation includes unit tests that:

  • Verify files are converted to the correct type
  • Confirm language-specific recipes can be applied after conversion
  • Ensure files not matching the pattern are left unchanged

Introduces a generic framework for converting plain text files with
non-standard extensions into typed source files (XML, YAML, Properties,
Groovy) so that language-specific recipes can be applied to them.

This is useful for proprietary configuration files or data formats that
use standard syntax (e.g., XML, YAML) but have custom file extensions
that OpenRewrite's default parsers don't recognize.

New classes:
- PlainTextAs<T> - Abstract base recipe in rewrite-core
- PlainTextAsXml - Parse plain text as XML
- PlainTextAsYaml - Parse plain text as YAML
- PlainTextAsProperties - Parse plain text as Properties
- PlainTextAsGroovy - Parse plain text as Groovy (e.g., Jenkinsfiles)

Each recipe requires a file pattern parameter since it specifically
targets files with non-standard extensions. For standard extensions,
users should configure parsers at LST build time instead.
@github-project-automation github-project-automation bot moved this to In Progress in OpenRewrite Nov 30, 2025
@timtebeek timtebeek self-requested a review December 1, 2025 10:05
@timtebeek timtebeek added the recipe Requested Recipe label Dec 1, 2025
@timtebeek timtebeek moved this from In Progress to Ready to Review in OpenRewrite Dec 1, 2025
@timtebeek
Copy link
Member

Thanks a lot for the work done here and the proposal; as discussed privately as well we'd rather explore a way to parse these correctly from the get go, such that we don't see unfortunate performance characteristics when it comes to running recipes, which ought to be quick, and have access to the full rich module provided by our parsers, as opposed to isolated parsing from text to some LST source file.

I understood you're in parallel exploring this in a private recipe module, which is definitely understandable in the interim; hope we can support your use case through the regular parser soon, for a fitting conclusion here. I'll go ahead and close this effort for now.

@timtebeek timtebeek closed this Dec 29, 2025
@github-project-automation github-project-automation bot moved this from Ready to Review to Done in OpenRewrite Dec 29, 2025
@jkschneider jkschneider reopened this Jan 1, 2026
@github-project-automation github-project-automation bot moved this from Done to In Progress in OpenRewrite Jan 1, 2026
@jkschneider
Copy link
Member

jkschneider commented Jan 1, 2026

@timtebeek I'd like us to take a look at this again. A recipe that takes both the file pattern and does the adaptation may not be best because it will result in an apparent change, but it may make sense for us to consider expanding on TreeVisitor's adapt mechanism.

image

Then this PlainTextAs recipe could still be layered compositionally at the front of a recipe list, and its purpose would only be to put the adaptation patterns on ExecutionContext. Just an idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

recipe Requested Recipe

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

3 participants