casid / jte

Secure and speedy templates for Java and Kotlin.
https://jte.gg
Apache License 2.0
748 stars 56 forks source link

Ease migration from `.jte` to `.kte` #266

Closed nedtwigg closed 1 year ago

nedtwigg commented 1 year ago

We have a bunch of .jte templates. We just learned a great trick we can use only in .kte that we're really excited about

and it's worth it for us to switch from .jte to .kte just for this. But it's kinda brutal that we have to switch absolutely everything at once.

It would make our life wayyy easier if we could call from a .kte template into .jte. It doesn't have to be full interop, just the ability to migrate a leaf template by itself, then other leaves, until we can finally migrate the root template.

I'm sure full interop is tricky, but even just partial one-way .kte -> .jte interop would be a big win, and I bet it would be a lot easier to implement.

casid commented 1 year ago

Hey @nedtwigg,

just a few things you should probably check if they work for you, before moving to kte:

Besides that, I think what you need is already working: https://github.com/casid/jte/blob/f432fcd713a49117b06d4c1e9131ced4418565a7/jte-kotlin/src/test/java/gg/jte/kotlin/TemplateEngineTest.java#L1155

Especially this would be the one you're after, right? https://github.com/casid/jte/blob/f432fcd713a49117b06d4c1e9131ced4418565a7/jte-kotlin/src/test/java/gg/jte/kotlin/TemplateEngineTest.java#L1169

nedtwigg commented 1 year ago

Hmm, I made a little Gradle reproducer project here: https://github.com/nedtwigg/jte-reproduce

As soon as I have a kte template that depends on a jte template, the Gradle build fails with:

Execution failed for task ':generateJte'.
> There was a failure while executing work items
   > A failure occurred while executing gg.jte.gradle.GenerateJteWorker
      > No parameter information for example/RootJ.kte

...

Caused by: java.lang.IllegalStateException: No parameter information for example/RootJ.kte
        at gg.jte.compiler.kotlin.KotlinCodeGenerator.appendParams(KotlinCodeGenerator.java:521)
        at gg.jte.compiler.kotlin.KotlinCodeGenerator.onTemplateCall(KotlinCodeGenerator.java:435)
        at gg.jte.compiler.TemplateParser.lambda$doParse$3(TemplateParser.java:260)
        at gg.jte.compiler.TemplateParser.extract(TemplateParser.java:961)
        at gg.jte.compiler.TemplateParser.doParse(TemplateParser.java:260)
        at gg.jte.compiler.TemplateParser.parse(TemplateParser.java:94)
        at gg.jte.compiler.TemplateParser.parse(TemplateParser.java:89)
        at gg.jte.compiler.TemplateCompiler.generateTemplateCall(TemplateCompiler.java:265)
        at gg.jte.compiler.TemplateCompiler.generate(TemplateCompiler.java:169)
        at gg.jte.compiler.TemplateCompiler.generateAll(TemplateCompiler.java:83)
        at gg.jte.TemplateEngine.generateAll(TemplateEngine.java:306)
        at gg.jte.gradle.GenerateJteWorker.execute(GenerateJteWorker.java:43)
casid commented 1 year ago

Thanks for sharing a reproducer, that was very helpful to reproduce this nasty bug!

I just pushed a fix, would it be possible for you to test with 3.0.4-SNAPSHOT and check if everything is working in the project you would like to migrate?

Problem was, that example/RootJ.jte was already generated, and when the template call lookup was made only the generated class name was checked (gg.jte.generated.ondemand.example.JteRootJGenerated), but not the extension java vs kt.

With this change your example project builds fine. There was a little typo in the filename of the last test J_needs_K, I changed that from J_needs_K.kte to J_needs_K.jte.

nedtwigg commented 1 year ago

Amazing! I took a random .jte in the middle of our template hierarchy, switched it to .kte, everything went flawlessly. Except the IntelliJ plugin which bugged out, but I'm not sure how to run the -SNAPSHOT version there. Thanks a ton, can't wait for 3.0.4.

The kte templates are so similar to the jte, we'll probably stick with jte for speed, and randomly swap some to kte when we want the expressiveness of the val lambda = {arg: Type -> @ trick. It's awesome that the system allows us that flexibility.

casid commented 1 year ago

Glad it is working!

The IntelliJ plugin is not going to be affected by the 3.0.4 version, since it has no dependency to jte. What problems are you experiencing there with kte/jte interoperability?

nedtwigg commented 1 year ago

I'm getting "Unresolved template" in that same example project. I pushed up changes so that it will run using 3.0.4-SNAPSHOT. The screenshot below was taken while the tests are passing thanks to 3.0.4-SNAPSHOT.

image
casid commented 1 year ago

I had a look at the IntelliJ plugin this morning and so far jte and kte template languages where strictly divided from each other.

I've added rudimentary support, so that autocompletion for template names is working between both languages and I've fixed the error annotations.

I just published a new version of the plugin (2.1.2), it should be available in 1-2 days after JetBrains approved it.

casid commented 1 year ago

@nedtwigg the new IntelliJ plugin version got approved today 😊

nedtwigg commented 1 year ago

Been using this and 3.1.0 for a day, and it's been an absolute dream! We can pretty much just rename a .jte to .kte, apply this regex to turn the @param from Java-style to Kotlin-style, and then we can use handy Kotlin constructs for clean subtemplating as discussed at #263.

replaceRegex 'convert jte imports to kte', '^@param ([\\w<>, ]*) (\\w+)$', '@param $2: $1'

and it's been all seamless from there.

casid commented 1 year ago

Thanks for the follow up, glad it is working!