Building a Type-Safe HTML/Config DSL
Implement a simple configuration DSL using builder patterns and extension lambdas.
Goal: A Practical DSL
We will build a minimal but realistic HTML builder DSL in Kotlin. The same patterns apply to any config, test fixture, or report builder. The result is a typesafe, IDE-friendly API that replaces string concatenation.
Define the Tag Base Class
All HTML elements share a common shape: a name, attributes, and children. Start with a base class:
open class Tag(val name: String) {
val attrs = mutableMapOf<String, String>()
val children = mutableListOf<Tag>()
fun render(indent: Int = 0): String {
val pad = " ".repeat(indent)
val attrStr = if (attrs.isEmpty()) "" else " " + attrs.entries.joinToString(" ") { "${it.key}=\"${it.value}\"" }
val body = children.joinToString("\n") { it.render(indent + 2) }
return "$pad<$name$attrStr>\n$body\n$pad</$name>"
}
}All lessons in this course
- Lambda with Receiver: The DSL Foundation
- @DslMarker: Preventing Receiver Leakage
- Building a Type-Safe HTML/Config DSL
- Testing and Evolving DSLs Without Breaking Users