Skip to content

CaperTML is a strong typed DSL-style html template generator for kotlin.

License

Notifications You must be signed in to change notification settings

cao-awa/CaperTML

Repository files navigation

CaperTML

CaperTML is a DSL-style strong type html template generator for kotlin.

Do notice

CaperTML are not a assembly as will tool, it enforces a subset of HTML content rules at compile time, this is not a string template engine.

It's making invalid HTML content cannot be produce.

Samples

Execute the code:

fun main() {
    val html = html {
        lang("en")
        head {
            meta {
                charset(Charsets.UTF_8)
            }
            meta {
                viewport {
                    width(DEVICE_WIDTH)
                    initialScale(1.0)
                }
            }
            pageTitle {
                +"TestPage"
            }
        }
        body {
            div {
                draggable()
                title("This is a title")
                h1 {
                    +"Section title"
                }
                span {
                    p {
                        +"This is a p text"
                        img {
                            src("/awa.png")
                            width(DEVICE_WIDTH)
                            height(DEVICE_HEIGHT)
                        }
                        br()
                        em {
                            +"notice"
                        }
                        b {
                            +"Notice 2"
                            classes("the-b")
                        }
                        classes("the-p")
                    }
                }
                br()
                br()
                a {
                    +"awa"
                    // Custom tag attr.
                    custom("my-tag", "awa")
                    // Href.
                    href("https://example.org")
                    // Href lang.
                    hrefLang("zh")
                    // Target.
                    target(HTMLATarget.PARENT)
                    // Ping list.
                    ping {
                        +"https://www.google.com"
                        +"https://github.com"
                    }
                    // Standard media style.
                    media(
                        HTMLADevice.ALL,
                        HTMLAMediaOperator.AND,
                        orientation(HTMLAMediaOrientations.LANDSCAPE)
                    )
                    // Element classes.
                    classes("type", "test")
                }
                a {
                    href("https://www.awa.com")
                    // Shorter media style.
                    media(all and landscape)
                }
            }
        }
    }

    println(html.toString(true, ""))
}

You will get these output:

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        <title>TestPage</title>
    </head>
    <body>
        <div title="This is a title" draggable="true">
            <h1>Section title</h1>
            <span>
                <p class="the-p">
                    This is a p text
                    <img src="/awa.png" width="device-width" height="device-height">
                    <br />
                    <em>notice</em>
                    <b class="the-b">Notice 2</b>
                </p>
            </span>
            <br />
            <br />
            <a href="https://example.org" hreflang="zh" target="_parent" media="all and (orientation:landscape)" ping="https://www.google.com https://github.com" class="type test" class="type test" data-my-tag="awa">
                awa
            </a>
            <a href="https://www.awa.com" media="all and (orientation:landscape)">
                
            </a>
        </div>
    </body>
</html>

Compile-Time Enforcement of Content Model Rules

CaperTML enforces HTML content model constraints at compile time.

Each element in the DSL is bound to a specific content domain, encoded directly into the type system. This means that attempting to place an element in an invalid context (for example, inserting block-level elements such as <div> or <h1> inside a <p> element) will result in a compile-time error, not a runtime failure.

Invalid HTML structures are therefore unrepresentable in CaperTML.

This design intentionally shifts error detection from runtime to compile time, ensuring that only structurally valid HTML can be constructed. The compiler becomes the first line of validation, eliminating an entire class of markup errors before the application can run.

As a result:

  • Invalid element nesting is rejected by the compiler
  • Incorrect content-domain usage cannot be expressed
  • Generated HTML is structurally valid by construction

Correctness is enforced by design, not by convention.

Philosophy

CaperTML is not a general-purpose HTML template engine, nor a string-based HTML assembler.

It is a DSL-style, strongly-typed HTML generator whose primary goal is correctness.

Design Goal

The core design goal of CaperTML is simple:

If HTML is invalid by specification, it should be impossible to produce it.

Instead of validating HTML at runtime or relying on user discipline, CaperTML enforces a strict subset of HTML content rules at compile time through Kotlin’s type system.

This means:

  • Invalid tag nesting is rejected by the compiler
  • Invalid attributes for a given element cannot be expressed
  • Certain structural rules (e.g. document layout) are encoded into the DSL itself

As a result, generated HTML is structurally valid by construction.

Not a Template Engine

CaperTML is intentionally not a template engine.

It does not:

  • Perform string interpolation
  • Evaluate runtime expressions in templates
  • Attempt to replace frontend frameworks
  • Aim to be fully compatible with every browser quirk or framework-specific pattern

If you need maximum flexibility or free-form HTML generation, CaperTML is likely not the right tool.

Strong Typing over Flexibility

CaperTML favors strong typing and explicit modeling over permissive APIs.

HTML concepts such as:

  • attributes
  • media queries
  • targets
  • element-specific constraints

are represented as types, not strings.

This provides:

  • Compile-time safety
  • IDE auto-completion
  • Self-documenting APIs
  • Reduced reliance on external HTML references

When necessary, controlled escape hatches (such as custom attributes) are provided, but they are explicit, not implicit.

Subset by Design

CaperTML does not aim to model every possible HTML behavior.

Instead, it models a well-defined, safe subset of HTML that is:

  • predictable
  • spec-oriented
  • suitable for static generation and server-side rendering

This design choice is intentional and allows the DSL to remain:

  • readable
  • maintainable
  • analyzable by the compiler

Who Is This For?

CaperTML is suitable for:

  • Static HTML generation
  • Server-side HTML rendering
  • Projects where correctness matters more than permissiveness
  • Developers interested in DSL design and type-driven APIs

It is not intended for:

  • Complex SPA development
  • Framework-specific attribute hacks
  • Runtime-heavy template logic

Summary

CaperTML treats HTML as a structured language, not a string.

By encoding HTML rules into the type system, it shifts error detection from runtime to compile time and makes invalid HTML unrepresentable.

Correctness is not an option — it is the default.

About

CaperTML is a strong typed DSL-style html template generator for kotlin.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published