Reputation: 12972
i'm building a Kotlin DSL for HTML that caters for very specific requirements i have (hence not using kotlinx.html)
DIV(classes = "div1") {
+"text1"
a(href = "#0") {
+"text2"
div(classes = "div2") {
+"text3"
href = "#1"
}
div(classes = "div3") {
+"text4"
href = "#2"
}
}
hr(classes = "hr1")
span(classes = "span1") {
+"text5"
}
}
In the example above, i'm able to call href
in any of the child elements of a
instead of having to do [email protected] = ""
. How do i limit the scope so that this
will only be of type DIV
in this example and throw a compiler error when calling href
since DIV
doesn't have an href
property?
Here's a shortened version of the DIV
class
https://github.com/persephone-unframework/dsl/blob/master/src/main/kotlin/io/persephone/dsl/element/DIV.kt
@DslMarker
annotation class DivMarker
@DivMarker
class DIV(
classes: String? = null,
....
init: (DIV.() -> Unit)? = null
) : Tag(
tagName = "div",
selfClosing = false
) {
fun a(
classes: String? = null,
....
init: (A.() -> Unit)? = null
) = A().let {
this.children.add(it)
....
init?.invoke(it)
it
}
....
}
Similarly, class A is also marked: https://github.com/persephone-unframework/dsl/blob/master/src/main/kotlin/io/persephone/dsl/element/A.kt
@DslMarker
annotation class AMarker
@AMarker
class A(
href: String? = null,
...
init: (A.() -> Unit)? = null
) : Tag(
tagName = "a",
selfClosing = false
) {
fun div(
classes: String? = null,
init: (DIV.() -> Unit)? = null
) = DIV().let {
this.children.add(it)
....
init?.invoke(it)
it
}
....
}
Any idea why the @DslMarker
annotation is not limiting the scope in this scenario and how i can fix it?
Upvotes: 1
Views: 1016
Reputation: 11
You need to use the very same marker.
In your code you are using DivMarker
and AMarker
.
Contexts marked with a given "label" will hide outer contexts marked with the very same "label". They will not hide outer contexts marked with any other "label".
You might not be fully aware, but in your own answer where you tagged the base class with TagMarker
you achieved sharing the same marker on all children classes. That is the reason why that code is effective.
Upvotes: 1
Reputation: 12972
It seems annotating the base class, in this case Tag
, does the trick, that probably means all those other annotations serve no purpose?
@DslMarker
annotation class TagMarker
@TagMarker
abstract class Tag(val tagName: String, var selfClosing: Boolean = false): Element {
val children = arrayListOf<Element>()
val attributes = hashMapOf<String, String>()
Upvotes: 1