2 Generated Code
nillpoe edited this page 2026-09-29 08:18:50 +00:00

Generated Code

The compiler turns every .kmx file into one Kotlin file that calls the kmx-runtime builders. Reading it explains the rules on the Expressions page and helps with kotlinc errors, which point at this file.

Example

src/main/kmx/shop/order_card.kmx:

import com.example.Order

props: Order

val total = items.sumOf { it.price * it.qty }

<div class="order" data-id="{id}">
  <p>Order #{id}: {items.size} items, {total}</p>
  @for (item in items) {
    <span title={item.note}>{item.name}</span>
  } separator {
    {", "}
  }
  {coupon?.let { <b>{it.code}</b> }}
</div>

build/generated/kmx/main/kotlin/shop/OrderCard.kt, exactly as the compiler writes it:

// Generated by KMX from shop/order_card.kmx. Do not edit.
@file:Suppress("RedundantVisibilityModifier", "RemoveRedundantQualifierName", "unused")

package shop

import com.example.Order

public object OrderCard : xyz.nillpoe.kmx.KmxTemplate<Order> {
    override val source: String get() = "shop/order_card.kmx"

    override fun render(props: Order, scope: xyz.nillpoe.kmx.RenderScope): xyz.nillpoe.kmx.Node =
        kotlin.with(scope) {
            kotlin.with(props) {
                val total = items.sumOf { it.price * it.qty } // shop/order_card.kmx:5
                xyz.nillpoe.kmx.markup {
                    element("div") {
                        attribute("class", "order")
                        attribute("data-id", (xyz.nillpoe.kmx.interpolate(id))) // shop/order_card.kmx:7
                        element("p") {
                            text("Order #")
                            insert(id) // shop/order_card.kmx:8
                            text(": ")
                            insert(items.size) // shop/order_card.kmx:8
                            text(" items, ")
                            insert(total) // shop/order_card.kmx:8
                        }
                        kotlin.run {
                            var kmxFirst0 = true
                            for (item in items) { // shop/order_card.kmx:9
                                val kmxItem0 = xyz.nillpoe.kmx.markup {
                                    element("span") {
                                        attribute("title", item.note) // shop/order_card.kmx:10
                                        insert(item.name) // shop/order_card.kmx:10
                                    }
                                }
                                if (!kmxFirst0) {
                                    insert(", ") // shop/order_card.kmx:12
                                }
                                kmxFirst0 = false
                                insert(kmxItem0)
                            }
                        }
                        insert(coupon?.let { xyz.nillpoe.kmx.markup {
                            element("b") {
                                insert(it.code) // shop/order_card.kmx:14
                            }
                        } }) // shop/order_card.kmx:14
                    }
                }
            }
        }
}

What maps to what

Template Generated
file shop/order_card.kmx package shop, object OrderCard (PascalCase file name)
import ... copied, plus the build's default imports
props: Order KmxTemplate<Order>, and kotlin.with(props) so members read directly
props(a: A, b: B) nested class Props(val a: A, val b: B) with toString, and render(a, b, scope)
no props KmxTemplate<kotlin.Unit> and render(scope)
component Card(...) fun xyz.nillpoe.kmx.RenderScope.Card(...): xyz.nillpoe.kmx.Node
header code copied before markup { }
<tag> element("tag") { ... }, or element("tag") when empty
literal text text("..."), with whitespace and entities already resolved
{expr} in text insert(expr)
name="..." attribute("name", "...")
name={expr} attribute("name", expr)
name="a{expr}" attribute("name", ("a" + xyz.nillpoe.kmx.interpolate(expr)))
name attribute("name", true)
{...map} attributes(map)
<Card title="x">body</Card> insert(Card(title = "x", children = xyz.nillpoe.kmx.markup { ... }))
<!-- c --> comment(" c ")
<>...</> the children, inline
markup inside Kotlin xyz.nillpoe.kmx.markup { ... }
@if / else if / else if / else if / else
@for for; with separator or empty, wrapped in kotlin.run with a kmxFirstN flag. With a separator, each item is built into kmxItemN first and inserted after the separator, so the code keeps the template's order
@when when, each branch a block
@{ ... } the statements

The // file.kmx:line comment on a statement names the template line it came from. KmxOutput.mappings lists every range of template Kotlin copied into the code, in the same order in both; editors use it to move diagnostics and positions between the two, see Editor Support. Runtime and stdlib calls are fully qualified (kotlin.with, kotlin.run, xyz.nillpoe.kmx.markup) so names in the template cannot capture them. The builder calls (element, text, insert, attribute) are members of the innermost builder.

Visibility

Declarations are public by default. The Gradle plugin's kmx { internal = true }, kmxc --internal, or KmxOptions(visibility = KmxVisibility.INTERNAL) make them internal.