Created
March 22, 2023 17:56
-
-
Save nedtwigg/a629e23ec5269894f0ad9558cf5f8d60 to your computer and use it in GitHub Desktop.
A gradle plugin which generates Kotlin model files for each JTE template
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import gg.jte.ContentType; | |
import gg.jte.compiler.TemplateParserVisitorAdapter; | |
import gg.jte.gradle.JteExtension; | |
import gg.jte.gradle.JteGradle; | |
import java.io.File; | |
import java.io.IOException; | |
import java.nio.charset.StandardCharsets; | |
import java.nio.file.Files; | |
import java.util.ArrayList; | |
import java.util.LinkedHashMap; | |
import java.util.LinkedHashSet; | |
import javax.naming.Name; | |
import org.gradle.api.DefaultTask; | |
import org.gradle.api.Plugin; | |
import org.gradle.api.Project; | |
import org.gradle.api.file.DirectoryProperty; | |
import org.gradle.api.file.FileType; | |
import org.gradle.api.plugins.JavaPluginExtension; | |
import org.gradle.api.provider.Property; | |
import org.gradle.api.tasks.Input; | |
import org.gradle.api.tasks.InputDirectory; | |
import org.gradle.api.tasks.OutputDirectory; | |
import org.gradle.api.tasks.PathSensitive; | |
import org.gradle.api.tasks.PathSensitivity; | |
import org.gradle.api.tasks.SourceSet; | |
import org.gradle.api.tasks.TaskAction; | |
import org.gradle.work.ChangeType; | |
import org.gradle.work.Incremental; | |
import gg.jte.TemplateConfig; | |
import gg.jte.compiler.TemplateParser; | |
import gg.jte.compiler.TemplateType; | |
import org.gradle.work.InputChanges; | |
public class JteModelPlugin implements Plugin<Project> { | |
@Override | |
public void apply(Project project) { | |
project.getPlugins().apply(JteGradle.class); | |
var extension = project.getExtensions().getByType(JteExtension.class); | |
JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class); | |
SourceSet main = javaPluginExtension.getSourceSets().findByName("main"); | |
var jteModelsTask = project.getTasks().register("jteModels", RenderModelClasses.class, task -> { | |
var jteModels = new File(project.getBuildDir(), "jte-models"); | |
main.getJava().srcDir(jteModels); | |
task.getOutputDir().set(jteModels); | |
task.getInputDir().set(extension.getSourceDirectory().get().toFile()); | |
task.getPackageName().set(extension.getPackageName()); | |
task.getContentType().set(extension.getContentType()); | |
}); | |
project.getTasks().named("compileKotlin").configure(task -> task.dependsOn(jteModelsTask)); | |
} | |
public static abstract class RenderModelClasses extends DefaultTask { | |
@Incremental | |
@PathSensitive(PathSensitivity.RELATIVE) | |
@InputDirectory | |
abstract DirectoryProperty getInputDir(); | |
@OutputDirectory | |
abstract DirectoryProperty getOutputDir(); | |
@Input | |
abstract Property<String> getPackageName(); | |
@Input | |
abstract Property<ContentType> getContentType(); | |
@TaskAction | |
public void render(InputChanges changes) throws IOException { | |
var templateConfig = new TemplateConfig(getContentType().get(), getPackageName().get()); | |
var renderer = new JteRenderer(getInputDir().getAsFile().get(), templateConfig); | |
for (var change : changes.getFileChanges(getInputDir())) { | |
if (change.getFileType() == FileType.DIRECTORY) { | |
return; | |
} | |
if (!change.getFile().getName().endsWith(".jte")) { | |
continue; | |
} | |
var targetFileJte = getOutputDir().file(change.getNormalizedPath()).get().getAsFile().getAbsolutePath(); | |
var targetFile = new File(targetFileJte.substring(0, targetFileJte.length() - 4) + ".kt"); | |
if (change.getChangeType() == ChangeType.REMOVED) { | |
targetFile.delete(); | |
} else { | |
targetFile.getParentFile().mkdirs(); | |
Files.write(targetFile.toPath(), renderer.render(change.getFile()).getBytes(StandardCharsets.UTF_8)); | |
} | |
} | |
} | |
} | |
static String convertJavaToKotlin(String javaType) { | |
if (javaType.equals("boolean")) { | |
return "Boolean"; | |
} else { | |
return javaType; | |
} | |
} | |
static class JteRenderer { | |
final File rootDir; | |
final TemplateConfig config; | |
JteRenderer(File rootDir, TemplateConfig config) { | |
this.rootDir = rootDir; | |
this.config = config; | |
} | |
String render(File file) throws IOException { | |
var pkg = file.getParentFile().getAbsolutePath().substring(rootDir.getAbsolutePath().length() + 1).replace(File.separatorChar, '.'); | |
var name = file.getName(); | |
var lastDot = name.lastIndexOf('.'); | |
name = name.substring(0, lastDot); | |
var imports = new LinkedHashSet<String>(); | |
imports.add("gg.jte.TemplateEngine"); | |
imports.add("gg.jte.TemplateOutput"); | |
var params = new LinkedHashMap<String, String>(); | |
new TemplateParser(Files.readString(file.toPath()), TemplateType.Template, new TemplateParserVisitorAdapter() { | |
@Override | |
public void onImport(String importClass) { | |
imports.add(importClass); | |
} | |
@Override | |
public void onParam(String parameter) { | |
var spaceIdx = parameter.indexOf(' '); | |
var type = parameter.substring(0, spaceIdx).trim(); | |
var name = parameter.substring(spaceIdx + 1).trim(); | |
params.put(name, convertJavaToKotlin(type)); | |
} | |
}, config).parse(); | |
var builder = new StringBuilder(); | |
builder.append("package " + pkg + "\n"); | |
builder.append("\n"); | |
for (var imp : imports) { | |
builder.append("import " + imp + "\n"); | |
} | |
builder.append("\n"); | |
builder.append("class " + name + "(\n"); | |
params.forEach((paramName, type) -> { | |
builder.append("\tval " + paramName + ": " + type + ",\n"); | |
}); | |
builder.append("\t) : common.JteModel {\n"); | |
builder.append("\n"); | |
builder.append("\toverride fun render(engine: TemplateEngine, output: TemplateOutput) {\n"); | |
builder.append("\t\tengine.render(\"" + pkg.replace('.', '/') + "/" + name + ".jte\", mapOf(\n"); | |
params.forEach((paramName, type) -> { | |
builder.append("\t\t\t\"" + paramName + "\" to " + paramName + ",\n"); | |
}); | |
builder.append("\t\t), output)\n"); | |
builder.append("\t}\n"); | |
builder.append("}"); | |
return builder.toString(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a Gradle plugin which you can stick into your
buildSrc
directory. It generates model files which match the jte templates. You can see example output in this gist.casid/jte#205 for further context.