diff --git a/config.toml b/config.toml index ec5ad51..fba50bf 100644 --- a/config.toml +++ b/config.toml @@ -16,6 +16,11 @@ display = "Java Version" default = "1.4.10" display = "Kotlin Version" +[features] + +[features.ktlint] +default = true + [versions] http4k = "3.265.0" pebble = "3.1.4" diff --git a/pom.xml b/pom.xml index 21bf4dd..779057a 100644 --- a/pom.xml +++ b/pom.xml @@ -150,7 +150,6 @@ maven-compiler-plugin 3.8.1 - org.apache.maven.plugins maven-antrun-plugin @@ -195,7 +194,6 @@ - diff --git a/src/main/kotlin/pebble/DepAsXmlPebbleFunction.kt b/src/main/kotlin/pebble/DepAsXmlPebbleFunction.kt new file mode 100644 index 0000000..d63036f --- /dev/null +++ b/src/main/kotlin/pebble/DepAsXmlPebbleFunction.kt @@ -0,0 +1,51 @@ +package pebble + +import com.mitchellbosecke.pebble.extension.escaper.SafeString +import com.mitchellbosecke.pebble.template.EvaluationContext +import com.mitchellbosecke.pebble.template.PebbleTemplate +import org.intellij.lang.annotations.Language +import starter.Dependency +import starter.utils.PebbleFunction + +// We need a custom function since pebble inserts whitespace everywhere +class DepAsXmlPebbleFunction : PebbleFunction { + override val name = "depAsXml" + override fun getArgumentNames() = listOf("dependency") + + override fun execute( + args: Map, + self: PebbleTemplate, + context: EvaluationContext, + lineNumber: Int, + ): SafeString { + val dep = args["dependency"] as Dependency + + fun tagName(name: String) = """$name""" + + fun startTag(name: String): String { + @Language("html") @Suppress("UnnecessaryVariable") + val result = """<""" + + """${tagName(name)}>""" + return result + } + + fun endTag(name: String): String { + @Language("html") @Suppress("UnnecessaryVariable") + val result = """</""" + + """${tagName(name)}>""" + return result + } + + fun tag(name: String, content: String) = """${startTag(name)}$content${endTag(name)}""" + + val result = """ + |${startTag("dependency")} + | ${tag("groupId", dep.groupId)} + | ${tag("artifactId", dep.artifactId)} + | ${tag("version", dep.version.value)} + |${endTag("dependency")} + """.trimMargin() + + return SafeString(result) + } +} diff --git a/src/main/kotlin/pebble/HasFeatureFilter.kt b/src/main/kotlin/pebble/HasFeatureFilter.kt new file mode 100644 index 0000000..1b5d5d0 --- /dev/null +++ b/src/main/kotlin/pebble/HasFeatureFilter.kt @@ -0,0 +1,27 @@ +package pebble + +import com.mitchellbosecke.pebble.template.EvaluationContext +import com.mitchellbosecke.pebble.template.PebbleTemplate +import starter.Feature +import starter.utils.PebbleFilter + +class HasFeatureFilter : PebbleFilter { + override val name = "hasFeature" + + override fun getArgumentNames() = listOf("name") + + override fun apply( + input: Any, + args: MutableMap, + self: PebbleTemplate, + context: EvaluationContext, + lineNumber: Int, + ): Boolean { + @Suppress("UNCHECKED_CAST") + val features = input as List + + val name = args["name"] as String + + return features.any { it.name == name } + } +} diff --git a/src/main/kotlin/starter/Models.kt b/src/main/kotlin/starter/Models.kt index b554376..c02efeb 100644 --- a/src/main/kotlin/starter/Models.kt +++ b/src/main/kotlin/starter/Models.kt @@ -24,10 +24,13 @@ data class Repository(val name: String, val url: String) data class Input(val name: String, val display: String, val value: String? = null) +data class Feature(val name: String, val value: Boolean = false) + data class Project( val name: String, val basePackage: String, val inputs: List, + val features: List, val dependencies: List, val repositories: Collection, ) diff --git a/src/main/kotlin/starter/config/Config.kt b/src/main/kotlin/starter/config/Config.kt index d6557ad..de0101a 100644 --- a/src/main/kotlin/starter/config/Config.kt +++ b/src/main/kotlin/starter/config/Config.kt @@ -7,6 +7,7 @@ import com.electronwill.nightconfig.core.Config as NightConfig data class StarterConfig( val dependencies: List, val inputs: List, + val features: List, ) class Config(private val cfg: NightConfig) { @@ -54,6 +55,11 @@ class Config(private val cfg: NightConfig) { Input(name, values["display"], values["default"]) } - return StarterConfig(dependencies, inputs) + val features = cfg.configMap("features") + .map { (name, values) -> + Feature(name, values["default"] ?: false) + } + + return StarterConfig(dependencies, inputs, features) } } diff --git a/src/main/kotlin/starter/modules/PebbleModule.kt b/src/main/kotlin/starter/modules/PebbleModule.kt index 09cce3c..98b8c2f 100644 --- a/src/main/kotlin/starter/modules/PebbleModule.kt +++ b/src/main/kotlin/starter/modules/PebbleModule.kt @@ -1,65 +1,23 @@ package starter.modules -import com.mitchellbosecke.pebble.extension.escaper.SafeString -import com.mitchellbosecke.pebble.template.EvaluationContext -import com.mitchellbosecke.pebble.template.PebbleTemplate -import org.intellij.lang.annotations.Language import org.koin.dsl.bind import org.koin.dsl.module -import starter.Dependency +import pebble.DepAsXmlPebbleFunction +import pebble.HasFeatureFilter import starter.utils.PebbleEngineBuilder import starter.utils.PebbleEngineBuilder.CacheType.ConcurrentMap +import starter.utils.PebbleFilter import starter.utils.PebbleFunction -class DepAsXmlPebbleFunction : PebbleFunction { - override val name = "depAsXml" - override fun getArgumentNames() = listOf("dependency") - - override fun execute( - args: Map, - self: PebbleTemplate, - context: EvaluationContext, - lineNumber: Int, - ): Any { - val dep = args["dependency"] as Dependency - - fun tagName(name: String) = """$name""" - - fun startTag(name: String): String { - @Language("html") @Suppress("UnnecessaryVariable") - val result = """<""" + - """${tagName(name)}>""" - return result - } - - fun endTag(name: String): String { - @Language("html") @Suppress("UnnecessaryVariable") - val result = """</""" + - """${tagName(name)}>""" - return result - } - - fun tag(name: String, content: String) = """${startTag(name)}$content${endTag(name)}""" - - val result = """ - |${startTag("dependency")} - | ${tag("groupId", dep.groupId)} - | ${tag("artifactId", dep.artifactId)} - | ${tag("version", dep.version.value)} - |${endTag("dependency")} - """.trimMargin() - - return SafeString(result) - } -} - val pebbleModule = module { single { DepAsXmlPebbleFunction() } bind PebbleFunction::class + single { HasFeatureFilter() } bind PebbleFilter::class single { PebbleEngineBuilder { cache = ConcurrentMap functions(getAll()) + filters(getAll()) classPath { suffix = ".twig" } } } diff --git a/src/main/kotlin/starter/routes/ZipRouteSupplier.kt b/src/main/kotlin/starter/routes/ZipRouteSupplier.kt index 177986f..38ecabf 100644 --- a/src/main/kotlin/starter/routes/ZipRouteSupplier.kt +++ b/src/main/kotlin/starter/routes/ZipRouteSupplier.kt @@ -25,13 +25,21 @@ class ZipRouteSupplier( req.form(it.name) != null } + val formMap = req.formAsMap() + val inputKeys = conf.inputs.map { it.name } - val inputs = req.formAsMap() + val inputs = formMap .filter { it.key in inputKeys } .map { (name, value) -> conf.inputs.find { it.name == name }!!.copy(value = value.first()) } + val features = formMap + .filter { it.key in conf.features.map { it.name } } + .map { (name, _) -> + conf.features.find { it.name == name }!!.copy(value = true) + } + val projectName = inputs.find { it.name == "name" }!!.value!! val basePackage = inputs.find { it.name == "basePackage" }!!.value!! @@ -39,7 +47,7 @@ class ZipRouteSupplier( Response.badRequest() } else { val repositories = deps.mapNotNull { it.repository }.toSet() - val project = Project(projectName, basePackage, inputs, deps, repositories) + val project = Project(projectName, basePackage, inputs, features, deps, repositories) val outputStream = projectZip.createZip(project) Response.ok().with( diff --git a/src/main/kotlin/starter/templates/PomTemplate.kt b/src/main/kotlin/starter/templates/PomTemplate.kt index d1310fb..774912e 100644 --- a/src/main/kotlin/starter/templates/PomTemplate.kt +++ b/src/main/kotlin/starter/templates/PomTemplate.kt @@ -13,6 +13,7 @@ class PomTemplate(private val engine: PebbleEngine) : Template { "dependencies" to project.dependencies.sortedBy { it.scope }, "repositories" to project.repositories, "kotlinxSerialization" to project.dependencies.any { it.name == "kotlinx-serialization" }, + "features" to project.features, "versions" to project.dependencies.map { it.version }.toSet() ) @@ -20,6 +21,8 @@ class PomTemplate(private val engine: PebbleEngine) : Template { args[it.name] = it.value } + println(args.entries.joinToString("\n")) + val rendered = engine.render("starter/pom/index", args) return prettyPrintXml(rendered) } diff --git a/src/main/kotlin/starter/views/Views.kt b/src/main/kotlin/starter/views/Views.kt index 6fe4267..6cd0c63 100644 --- a/src/main/kotlin/starter/views/Views.kt +++ b/src/main/kotlin/starter/views/Views.kt @@ -7,7 +7,8 @@ import starter.utils.render class Views(private val engine: PebbleEngine, config: StarterConfig) { private val args = mapOf( "dependencies" to config.dependencies.groupBy { it.category }.toSortedMap(), - "inputs" to config.inputs + "inputs" to config.inputs, + "features" to config.features, ) fun index() = engine.render("views/index", args) diff --git a/src/main/resources/starter/pom/@plugins.twig b/src/main/resources/starter/pom/@plugins.twig index a81ac19..f527ea6 100644 --- a/src/main/resources/starter/pom/@plugins.twig +++ b/src/main/resources/starter/pom/@plugins.twig @@ -10,5 +10,7 @@ {% include "starter/pom/plugins/@shade" %} + {% include "starter/pom/plugins/@ktlint" %} + - \ No newline at end of file + diff --git a/src/main/resources/starter/pom/index.twig b/src/main/resources/starter/pom/index.twig index e4c546c..e908666 100644 --- a/src/main/resources/starter/pom/index.twig +++ b/src/main/resources/starter/pom/index.twig @@ -8,6 +8,7 @@ {{ javaVersion }} {{ kotlinVersion }} + official ${java.version} ${java.version} UTF-8 diff --git a/src/main/resources/starter/pom/plugins/@ktlint.twig b/src/main/resources/starter/pom/plugins/@ktlint.twig new file mode 100644 index 0000000..7761bc4 --- /dev/null +++ b/src/main/resources/starter/pom/plugins/@ktlint.twig @@ -0,0 +1,46 @@ +{% if features | hasFeature("ktlint") %} + + org.apache.maven.plugins + maven-antrun-plugin + 1.7 + + + ktlint + verify + + + + + + + + + run + + + + ktlint-format + + + + + + + + + + run + + + + + + com.pinterest + ktlint + 0.39.0 + + + +{% endif %} diff --git a/src/main/resources/views/index.twig b/src/main/resources/views/index.twig index 7315e72..244f41e 100644 --- a/src/main/resources/views/index.twig +++ b/src/main/resources/views/index.twig @@ -10,6 +10,19 @@ {% endfor %}
+
+

Features

+
    + {% for feature in features %} + + {% endfor %} +
+
+ {% for category in dependencies %}

{{ category.key }}

diff --git a/src/test/kotlin/starter/templates/PomTemplateTest.kt b/src/test/kotlin/starter/templates/PomTemplateTest.kt index 4eb6b81..4fcc25b 100644 --- a/src/test/kotlin/starter/templates/PomTemplateTest.kt +++ b/src/test/kotlin/starter/templates/PomTemplateTest.kt @@ -30,6 +30,7 @@ internal class PomTemplateTest { name = "Test", basePackage = "org.test", inputs = conf.inputs, + features = emptyList(), dependencies = conf.dependencies, repositories = conf.dependencies.mapNotNull { it.repository }.toSet() )