Compare commits
4 Commits
ce92e1fae9
...
cf09799bc6
| Author | SHA1 | Date | |
|---|---|---|---|
| cf09799bc6 | |||
| a856d5e425 | |||
| f56ec93498 | |||
| 66878900f5 |
18
.editorconfig
Normal file
18
.editorconfig
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.{kt, kts}]
|
||||||
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
|
continuation_indent_size=4
|
||||||
|
max_line_length = 120
|
||||||
|
disabled_rules = no-wildcard-imports
|
||||||
|
kotlin_imports_layout = idea
|
||||||
37
config.toml
37
config.toml
@ -29,48 +29,47 @@ url = "https://dl.bintray.com/arrow-kt/arrow-kt/"
|
|||||||
[dependencies.http4k]
|
[dependencies.http4k]
|
||||||
groupId = "org.http4k"
|
groupId = "org.http4k"
|
||||||
artifactId = "http4k-core"
|
artifactId = "http4k-core"
|
||||||
version = "3.261.0"
|
version = "3.264.0"
|
||||||
category = "server"
|
category = "http4k"
|
||||||
default = true
|
default = true
|
||||||
|
|
||||||
[dependencies.http4k-server-jetty]
|
[dependencies.http4k-server-jetty]
|
||||||
groupId = "org.http4k"
|
groupId = "org.http4k"
|
||||||
artifactId = "http4k-server-jetty"
|
artifactId = "http4k-server-jetty"
|
||||||
version = "3.261.0"
|
version = "3.264.0"
|
||||||
category = "server"
|
category = "http4k"
|
||||||
default = true
|
default = true
|
||||||
logger = "org.eclipse.jetty"
|
logger = "org.eclipse.jetty"
|
||||||
|
|
||||||
[dependencies.http4k-server-apache]
|
[dependencies.http4k-server-apache]
|
||||||
groupId = "org.http4k"
|
groupId = "org.http4k"
|
||||||
artifactId = "http4k-server-apache"
|
artifactId = "http4k-server-apache"
|
||||||
version = "3.261.0"
|
version = "3.264.0"
|
||||||
category = "server"
|
category = "http4k"
|
||||||
|
|
||||||
[dependencies.http4k-client-apache]
|
[dependencies.http4k-client-apache]
|
||||||
groupId = "org.http4k"
|
groupId = "org.http4k"
|
||||||
artifactId = "http4k-client-apache"
|
artifactId = "http4k-client-apache"
|
||||||
version = "3.261.0"
|
version = "3.264.0"
|
||||||
category = "server"
|
category = "http4k"
|
||||||
|
|
||||||
[dependencies.http4k-format-jackson]
|
[dependencies.http4k-format-jackson]
|
||||||
groupId = "org.http4k"
|
groupId = "org.http4k"
|
||||||
artifactId = "http4k-format-jackson"
|
artifactId = "http4k-format-jackson"
|
||||||
version = "3.261.0"
|
version = "3.264.0"
|
||||||
category = "server"
|
category = "http4k"
|
||||||
|
|
||||||
|
[dependencies.http4k-format-kotlinx-serialization]
|
||||||
|
groupId = "org.http4k"
|
||||||
|
artifactId = "http4k-format-kotlinx-serialization"
|
||||||
|
version = "3.264.0"
|
||||||
|
category = "http4k"
|
||||||
|
|
||||||
[dependencies.http4k-contract]
|
[dependencies.http4k-contract]
|
||||||
groupId = "org.http4k"
|
groupId = "org.http4k"
|
||||||
artifactId = "http4k-contract"
|
artifactId = "http4k-contract"
|
||||||
version = "3.261.0"
|
version = "3.264.0"
|
||||||
category = "server"
|
category = "http4k"
|
||||||
|
|
||||||
[dependencies.javalin]
|
|
||||||
groupId = "io.javalin"
|
|
||||||
artifactId = "javalin"
|
|
||||||
version = "3.10.1"
|
|
||||||
category = "server"
|
|
||||||
logger = "org.eclipse.jetty"
|
|
||||||
|
|
||||||
[dependencies.pebble]
|
[dependencies.pebble]
|
||||||
groupId = "io.pebbletemplates"
|
groupId = "io.pebbletemplates"
|
||||||
|
|||||||
6
pom.xml
6
pom.xml
@ -10,6 +10,7 @@
|
|||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<kotlin.version>1.4.10</kotlin.version>
|
<kotlin.version>1.4.10</kotlin.version>
|
||||||
|
<kotlin.code.style>official</kotlin.code.style>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
@ -51,6 +52,11 @@
|
|||||||
<artifactId>koin-core</artifactId>
|
<artifactId>koin-core</artifactId>
|
||||||
<version>2.1.6</version>
|
<version>2.1.6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>1.7.30</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
purge: {
|
purge: {
|
||||||
content: [
|
content: [
|
||||||
'../main/resources/views/**/*.twig'
|
'../main/resources/views/**/*.twig',
|
||||||
|
'../main/kotlin/starter/PebbleModule.kt',
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
theme: {},
|
theme: {},
|
||||||
|
|||||||
@ -45,5 +45,4 @@ class Config {
|
|||||||
|
|
||||||
return StarterConfig(dependencies, inputs, repositories)
|
return StarterConfig(dependencies, inputs, repositories)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,34 @@
|
|||||||
package starter
|
package starter
|
||||||
|
|
||||||
|
import org.http4k.core.then
|
||||||
|
import org.http4k.filter.ServerFilters
|
||||||
|
import org.http4k.routing.ResourceLoader
|
||||||
|
import org.http4k.routing.RoutingHttpHandler
|
||||||
|
import org.http4k.routing.routes
|
||||||
|
import org.http4k.routing.static
|
||||||
|
import org.http4k.server.SunHttp
|
||||||
|
import org.http4k.server.asServer
|
||||||
import org.koin.core.context.startKoin
|
import org.koin.core.context.startKoin
|
||||||
import org.koin.dsl.bind
|
import org.koin.dsl.bind
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
import org.koin.dsl.onClose
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import starter.routes.IndexRouteSupplier
|
||||||
|
import starter.routes.RouteSupplier
|
||||||
|
import starter.routes.ZipRouteSupplier
|
||||||
|
import starter.routes.toRouter
|
||||||
import starter.templates.*
|
import starter.templates.*
|
||||||
|
|
||||||
val mainModule = module {
|
val mainModule = module {
|
||||||
|
single(createdAtStart = true) {
|
||||||
|
get<Logger>().info("Starting on http://localhost:7000")
|
||||||
|
get<RoutingHttpHandler>().asServer(SunHttp(7000)).start()
|
||||||
|
} onClose { it?.stop() }
|
||||||
|
|
||||||
single { Config().load() }
|
single { Config().load() }
|
||||||
single { PebbleModule().engine() }
|
single { LoggerFactory.getLogger("Starter") }
|
||||||
single { Server(get(), get(), get()) }
|
single { Views(get(), get()) }
|
||||||
single { Views(get()) }
|
|
||||||
single { ProjectZip(getAll()) }
|
single { ProjectZip(getAll()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,10 +39,20 @@ val templateModule = module {
|
|||||||
single { GitignoreTemplate(get()) } bind Template::class
|
single { GitignoreTemplate(get()) } bind Template::class
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main() {
|
val routesModule = module {
|
||||||
val koin = startKoin {
|
single { IndexRouteSupplier(get()) } bind RouteSupplier::class
|
||||||
modules(mainModule, templateModule)
|
single { ZipRouteSupplier(get(), get()) } bind RouteSupplier::class
|
||||||
}.koin
|
single {
|
||||||
val server = koin.get<Server>()
|
ServerFilters.CatchAll().then(
|
||||||
server.run()
|
routes(
|
||||||
|
static(ResourceLoader.Classpath("/assets")),
|
||||||
|
getAll<RouteSupplier>().toRouter()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
startKoin {
|
||||||
|
modules(mainModule, pebbleModule, templateModule, routesModule)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package starter
|
package starter
|
||||||
|
|
||||||
enum class Category {
|
enum class Category {
|
||||||
Server, Injection, Database, Serialization, Test, Other
|
Http4k, Injection, Database, Serialization, Test, Other
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Scope {
|
enum class Scope {
|
||||||
|
|||||||
@ -1,15 +1,57 @@
|
|||||||
package starter
|
package starter
|
||||||
|
|
||||||
import com.mitchellbosecke.pebble.PebbleEngine
|
import com.mitchellbosecke.pebble.extension.escaper.SafeString
|
||||||
import com.mitchellbosecke.pebble.loader.ClasspathLoader
|
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.utils.PebbleEngineBuilder
|
||||||
|
import starter.utils.PebbleEngineBuilder.CacheType.ConcurrentMap
|
||||||
|
import starter.utils.PebbleFunction
|
||||||
|
|
||||||
class PebbleModule {
|
class DepAsXmlPebbleFunction : PebbleFunction {
|
||||||
fun engine(): PebbleEngine {
|
override val name = "depAsXml"
|
||||||
val loader = ClasspathLoader()
|
override fun getArgumentNames() = listOf("dependency")
|
||||||
loader.suffix = ".twig"
|
override fun execute(args: Map<String, Any>, self: PebbleTemplate, context: EvaluationContext, lineNumber: Int): Any {
|
||||||
return PebbleEngine.Builder()
|
val dep = args["dependency"] as Dependency
|
||||||
.loader(loader)
|
|
||||||
.cacheActive(true)
|
fun startTag(name: String): String {
|
||||||
.build()
|
@Language("html") @Suppress("UnnecessaryVariable")
|
||||||
|
val result = """<span class="text-gray-700"><</span><span class="text-red-700">$name</span><span class="text-gray-700">></span>"""
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun endTag(name: String): String {
|
||||||
|
@Language("html") @Suppress("UnnecessaryVariable")
|
||||||
|
val result = """<span class="text-gray-700"></</span><span class="text-red-700">$name</span><span class="text-gray-700">></span>"""
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tag(name: String, content: String): String {
|
||||||
|
return """${startTag(name)}$content${endTag(name)}"""
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = """
|
||||||
|
|${startTag("dependency")}
|
||||||
|
| ${tag("groupId", dep.groupId)}
|
||||||
|
| ${tag("artifactId", dep.artifactId)}
|
||||||
|
| ${tag("version", dep.version)}
|
||||||
|
|${endTag("dependency")}
|
||||||
|
""".trimMargin()
|
||||||
|
|
||||||
|
return SafeString(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val pebbleModule = module {
|
||||||
|
single { DepAsXmlPebbleFunction() } bind PebbleFunction::class
|
||||||
|
|
||||||
|
single {
|
||||||
|
PebbleEngineBuilder {
|
||||||
|
cache = ConcurrentMap
|
||||||
|
functions(getAll())
|
||||||
|
classPath { suffix = ".twig" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,5 +17,4 @@ class ProjectZip(private val templates: List<Template>) {
|
|||||||
}
|
}
|
||||||
return zipOutput.outputStream
|
return zipOutput.outputStream
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,68 +0,0 @@
|
|||||||
package starter
|
|
||||||
|
|
||||||
import org.http4k.core.HttpHandler
|
|
||||||
import org.http4k.core.Method
|
|
||||||
import org.http4k.core.Response
|
|
||||||
import org.http4k.core.Status
|
|
||||||
import org.http4k.core.body.form
|
|
||||||
import org.http4k.core.body.formAsMap
|
|
||||||
import org.http4k.routing.ResourceLoader
|
|
||||||
import org.http4k.routing.bind
|
|
||||||
import org.http4k.routing.routes
|
|
||||||
import org.http4k.routing.static
|
|
||||||
import org.http4k.server.SunHttp
|
|
||||||
import org.http4k.server.asServer
|
|
||||||
import starter.utils.sanitizeFilename
|
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
|
|
||||||
class Server(
|
|
||||||
private val views: Views,
|
|
||||||
private val conf: StarterConfig,
|
|
||||||
private val projectZip: ProjectZip,
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun run() {
|
|
||||||
val indexHandler: HttpHandler = {
|
|
||||||
Response(Status.OK).body(views.index(conf.dependencies, conf.inputs)).header("Content-Type", "text/html")
|
|
||||||
}
|
|
||||||
val zipHandler: HttpHandler = { req ->
|
|
||||||
val deps = conf.dependencies.filter {
|
|
||||||
req.form(it.name) != null
|
|
||||||
}
|
|
||||||
|
|
||||||
val inputKeys = conf.inputs.map { it.name }
|
|
||||||
val inputs = req.formAsMap()
|
|
||||||
.filter { it.key in inputKeys }
|
|
||||||
.map { (name, value) ->
|
|
||||||
conf.inputs.find { it.name == name }!!.copy(value = value.first())
|
|
||||||
}
|
|
||||||
|
|
||||||
val projectName = inputs.find { it.name == "name" }!!.value!!
|
|
||||||
val basePackage = inputs.find { it.name == "basePackage" }!!.value!!
|
|
||||||
|
|
||||||
if (basePackage.contains("/") || basePackage.contains("..")) {
|
|
||||||
Response(Status.BAD_REQUEST).body("Invalid Base Package")
|
|
||||||
} else {
|
|
||||||
val repositories = conf.repositories
|
|
||||||
.filter { repo -> repo.name in deps.mapNotNull { it.repository } }
|
|
||||||
|
|
||||||
val project = Project(projectName, basePackage, inputs, deps, repositories)
|
|
||||||
val outputStream = projectZip.createZip(project)
|
|
||||||
|
|
||||||
Response(Status.OK).header("Content-Type", "application/zip")
|
|
||||||
.header("Content-Disposition", "attachment; filename=\"${sanitizeFilename(projectName)}.zip\"")
|
|
||||||
.body(ByteArrayInputStream(outputStream.toByteArray()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val app = routes(
|
|
||||||
"/" bind Method.GET to indexHandler,
|
|
||||||
"/" bind Method.POST to zipHandler,
|
|
||||||
static(ResourceLoader.Classpath("/assets"))
|
|
||||||
)
|
|
||||||
|
|
||||||
app.asServer(SunHttp(7000)).start()
|
|
||||||
println("Started on http://localhost:7000")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,17 +1,13 @@
|
|||||||
package starter
|
package starter
|
||||||
|
|
||||||
import com.mitchellbosecke.pebble.PebbleEngine
|
import com.mitchellbosecke.pebble.PebbleEngine
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import starter.utils.render
|
import starter.utils.render
|
||||||
|
|
||||||
class Views(private val engine: PebbleEngine) {
|
class Views(private val engine: PebbleEngine, config: StarterConfig) {
|
||||||
private val logger = LoggerFactory.getLogger(javaClass)
|
private val args = mapOf(
|
||||||
|
"dependencies" to config.dependencies.groupBy { it.category }.toSortedMap(),
|
||||||
fun index(dependencies: List<Dependency>, inputs: List<Input>): String {
|
"inputs" to config.inputs
|
||||||
val dependenciesByCategory = dependencies.groupBy { it.category }.toSortedMap()
|
|
||||||
return engine.render("views/index",
|
|
||||||
mapOf("dependencies" to dependenciesByCategory, "inputs" to inputs)
|
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
|
fun index() = engine.render("views/index", args)
|
||||||
}
|
}
|
||||||
17
src/main/kotlin/starter/extensions/Http4kExtensions.kt
Normal file
17
src/main/kotlin/starter/extensions/Http4kExtensions.kt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
@file:Suppress("NOTHING_TO_INLINE")
|
||||||
|
|
||||||
|
package starter.extensions
|
||||||
|
|
||||||
|
import org.http4k.core.Response
|
||||||
|
import org.http4k.core.Status
|
||||||
|
import starter.utils.sanitizeFilename
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
inline fun Response.Companion.ok() = Response(Status.OK)
|
||||||
|
inline fun Response.Companion.badRequest() = Response(Status.BAD_REQUEST)
|
||||||
|
|
||||||
|
fun attachment(value: InputStream, name: String, contentType: String) = { res: Response ->
|
||||||
|
res.header("Content-Type", contentType)
|
||||||
|
.header("Content-Disposition", "attachment; filename=\"${sanitizeFilename(name)}\"")
|
||||||
|
.body(value)
|
||||||
|
}
|
||||||
16
src/main/kotlin/starter/routes/IndexRouteSupplier.kt
Normal file
16
src/main/kotlin/starter/routes/IndexRouteSupplier.kt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package starter.routes
|
||||||
|
|
||||||
|
import org.http4k.core.Method
|
||||||
|
import org.http4k.core.Response
|
||||||
|
import org.http4k.core.Status
|
||||||
|
import org.http4k.routing.bind
|
||||||
|
import starter.StarterConfig
|
||||||
|
import starter.Views
|
||||||
|
|
||||||
|
class IndexRouteSupplier(private val views: Views) : RouteSupplier {
|
||||||
|
override fun get() = "/" bind Method.GET to {
|
||||||
|
Response(Status.OK)
|
||||||
|
.body(views.index())
|
||||||
|
.header("Content-Type", "text/html")
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/main/kotlin/starter/routes/RouteSupplier.kt
Normal file
10
src/main/kotlin/starter/routes/RouteSupplier.kt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package starter.routes
|
||||||
|
|
||||||
|
import org.http4k.routing.RoutingHttpHandler
|
||||||
|
import org.http4k.routing.routes
|
||||||
|
|
||||||
|
interface RouteSupplier {
|
||||||
|
fun get(): RoutingHttpHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
fun List<RouteSupplier>.toRouter() = routes(*map { it.get() }.toTypedArray())
|
||||||
56
src/main/kotlin/starter/routes/ZipRouteSupplier.kt
Normal file
56
src/main/kotlin/starter/routes/ZipRouteSupplier.kt
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package starter.routes
|
||||||
|
|
||||||
|
import org.http4k.core.Method
|
||||||
|
import org.http4k.core.Response
|
||||||
|
import org.http4k.core.body.form
|
||||||
|
import org.http4k.core.body.formAsMap
|
||||||
|
import org.http4k.core.with
|
||||||
|
import org.http4k.routing.bind
|
||||||
|
import starter.Project
|
||||||
|
import starter.ProjectZip
|
||||||
|
import starter.StarterConfig
|
||||||
|
import starter.extensions.attachment
|
||||||
|
import starter.extensions.badRequest
|
||||||
|
import starter.extensions.ok
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
|
||||||
|
class ZipRouteSupplier(
|
||||||
|
private val conf: StarterConfig,
|
||||||
|
private val projectZip: ProjectZip,
|
||||||
|
) : RouteSupplier {
|
||||||
|
|
||||||
|
override fun get() = "/" bind Method.POST to { req ->
|
||||||
|
|
||||||
|
val deps = conf.dependencies.filter {
|
||||||
|
req.form(it.name) != null
|
||||||
|
}
|
||||||
|
|
||||||
|
val inputKeys = conf.inputs.map { it.name }
|
||||||
|
val inputs = req.formAsMap()
|
||||||
|
.filter { it.key in inputKeys }
|
||||||
|
.map { (name, value) ->
|
||||||
|
conf.inputs.find { it.name == name }!!.copy(value = value.first())
|
||||||
|
}
|
||||||
|
|
||||||
|
val projectName = inputs.find { it.name == "name" }!!.value!!
|
||||||
|
val basePackage = inputs.find { it.name == "basePackage" }!!.value!!
|
||||||
|
|
||||||
|
if (basePackage.contains("/") || basePackage.contains("..")) {
|
||||||
|
Response.badRequest()
|
||||||
|
} else {
|
||||||
|
val repositories = conf.repositories
|
||||||
|
.filter { repo -> repo.name in deps.mapNotNull { it.repository } }
|
||||||
|
|
||||||
|
val project = Project(projectName, basePackage, inputs, deps, repositories)
|
||||||
|
val outputStream = projectZip.createZip(project)
|
||||||
|
|
||||||
|
Response.ok().with(
|
||||||
|
attachment(
|
||||||
|
value = ByteArrayInputStream(outputStream.toByteArray()),
|
||||||
|
name = "$projectName.zip",
|
||||||
|
contentType = "application/zip"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,87 @@
|
|||||||
package starter.utils
|
package starter.utils
|
||||||
|
|
||||||
import com.mitchellbosecke.pebble.PebbleEngine
|
import com.mitchellbosecke.pebble.PebbleEngine
|
||||||
|
import com.mitchellbosecke.pebble.cache.tag.CaffeineTagCache
|
||||||
|
import com.mitchellbosecke.pebble.cache.tag.ConcurrentMapTagCache
|
||||||
|
import com.mitchellbosecke.pebble.cache.tag.NoOpTagCache
|
||||||
|
import com.mitchellbosecke.pebble.cache.template.CaffeineTemplateCache
|
||||||
|
import com.mitchellbosecke.pebble.cache.template.ConcurrentMapTemplateCache
|
||||||
|
import com.mitchellbosecke.pebble.cache.template.NoOpTemplateCache
|
||||||
|
import com.mitchellbosecke.pebble.extension.AbstractExtension
|
||||||
|
import com.mitchellbosecke.pebble.extension.Filter
|
||||||
|
import com.mitchellbosecke.pebble.extension.Function
|
||||||
|
import com.mitchellbosecke.pebble.loader.ClasspathLoader
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
|
|
||||||
fun PebbleEngine.render(name: String, args: Map<String, Any?> = mapOf()): String {
|
fun PebbleEngine.render(name: String, args: Map<String, Any?> = mapOf()) =
|
||||||
val template = getTemplate(name)
|
getTemplate(name).let { StringWriter().apply { it.evaluate(this, args) }.toString() }
|
||||||
val writer = StringWriter()
|
|
||||||
template.evaluate(writer, args)
|
fun PebbleEngine.render(name: String, vararg args: Pair<String, Any?>) =
|
||||||
return writer.toString()
|
render(name, mapOf(*args))
|
||||||
|
|
||||||
|
interface PebbleFunction : Function {
|
||||||
|
val name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PebbleFilter : Filter {
|
||||||
|
val name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
class PebbleEngineBuilder {
|
||||||
|
enum class CacheType {
|
||||||
|
None, Caffeine, ConcurrentMap
|
||||||
|
}
|
||||||
|
|
||||||
|
private var loader = ClasspathLoader()
|
||||||
|
var cache = CacheType.ConcurrentMap
|
||||||
|
|
||||||
|
private val functions = mutableListOf<PebbleFunction>()
|
||||||
|
private val filters = mutableListOf<PebbleFilter>()
|
||||||
|
|
||||||
|
fun function(function: PebbleFunction) {
|
||||||
|
functions.add(function)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun functions(functions: Iterable<PebbleFunction>) {
|
||||||
|
this.functions.addAll(functions)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun filter(filter: PebbleFilter) {
|
||||||
|
filters.add(filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun filters(filters: Iterable<PebbleFilter>) {
|
||||||
|
this.filters.addAll(filters)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun classPath(block: ClasspathLoader.() -> Unit) {
|
||||||
|
loader = ClasspathLoader().apply(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
operator fun invoke(block: PebbleEngineBuilder.() -> Unit): PebbleEngine =
|
||||||
|
PebbleEngineBuilder().apply(block).let { builder ->
|
||||||
|
PebbleEngine.Builder()
|
||||||
|
.loader(builder.loader)
|
||||||
|
.cacheActive(builder.cache != CacheType.None)
|
||||||
|
.templateCache(when (builder.cache) {
|
||||||
|
CacheType.None -> NoOpTemplateCache()
|
||||||
|
CacheType.Caffeine -> CaffeineTemplateCache()
|
||||||
|
CacheType.ConcurrentMap -> ConcurrentMapTemplateCache()
|
||||||
|
})
|
||||||
|
.tagCache(when (builder.cache) {
|
||||||
|
CacheType.None -> NoOpTagCache()
|
||||||
|
CacheType.Caffeine -> CaffeineTagCache()
|
||||||
|
CacheType.ConcurrentMap -> ConcurrentMapTagCache()
|
||||||
|
})
|
||||||
|
.extension(object : AbstractExtension() {
|
||||||
|
override fun getFunctions(): Map<String, Function>? =
|
||||||
|
builder.functions.associateBy { it.name }.ifEmpty { null }
|
||||||
|
|
||||||
|
override fun getFilters(): Map<String, Filter>? =
|
||||||
|
builder.filters.associateBy { it.name }.ifEmpty { null }
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -13,7 +13,6 @@ import javax.xml.transform.stream.StreamResult
|
|||||||
import javax.xml.xpath.XPathConstants
|
import javax.xml.xpath.XPathConstants
|
||||||
import javax.xml.xpath.XPathFactory
|
import javax.xml.xpath.XPathFactory
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@see https://stackoverflow.com/a/33541820
|
@see https://stackoverflow.com/a/33541820
|
||||||
*/
|
*/
|
||||||
@ -26,9 +25,11 @@ fun prettyPrintXml(xml: String, indent: Int = 4): String {
|
|||||||
// Remove whitespaces outside tags
|
// Remove whitespaces outside tags
|
||||||
document.normalize()
|
document.normalize()
|
||||||
val xPath = XPathFactory.newInstance().newXPath()
|
val xPath = XPathFactory.newInstance().newXPath()
|
||||||
val nodeList = xPath.evaluate("//text()[normalize-space()='']",
|
val nodeList = xPath.evaluate(
|
||||||
|
"//text()[normalize-space()='']",
|
||||||
document,
|
document,
|
||||||
XPathConstants.NODESET) as NodeList
|
XPathConstants.NODESET
|
||||||
|
) as NodeList
|
||||||
for (i in 0 until nodeList.length) {
|
for (i in 0 until nodeList.length) {
|
||||||
val node = nodeList.item(i)
|
val node = nodeList.item(i)
|
||||||
node.parentNode.removeChild(node)
|
node.parentNode.removeChild(node)
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1,9 +1,14 @@
|
|||||||
{% macro dependency(dependency) %}
|
{% macro dependency(dependency) %}
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
<label class="m-2">
|
<label class="m-2">
|
||||||
<input name="{{ dependency.name }}"
|
<input name="{{ dependency.name }}"
|
||||||
type="checkbox"{% if dependency.default %} checked{% endif %}>
|
type="checkbox"{% if dependency.default %} checked{% endif %}>
|
||||||
<span>{{ dependency.name }}</span>
|
<span>{{ dependency.name }}</span>
|
||||||
</label>
|
</label>
|
||||||
|
</summary>
|
||||||
|
<pre><code>{{ depAsXml(dependency) }}</code></pre>
|
||||||
|
</details>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro input(input) %}
|
{% macro input(input) %}
|
||||||
|
|||||||
@ -21,6 +21,6 @@
|
|||||||
</section>
|
</section>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="w-full btn btn-purple">Submit</button>
|
<button type="submit" class="my-4 w-full btn btn-purple">Submit</button>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user