# kotlin-codegen
A declaration model and renderer for generating Kotlin source code.
Declarations (files, classes, functions, properties, parameters, types,
annotations) are typed model values (`KtFile`, `KtClass`, `KtFun`, `KtType`,
…); imports and formatting derive from the model automatically via
`ImportSet`. Statement **bodies** stay raw Kotlin text, structured through the
indentation-aware `KtCode` builder rather than modeled as a full expression AST.
You build a `KtFile` out of typed pieces, and the renderer produces
formatted, import-complete Kotlin source text plus a file-writer that lays
the result out on disk.
## Examples
Two runnable examples, both checked against stored output by
`tests/examples.rs` so they cannot rot:
```sh
cargo run --example showcase # every construct the model can emit
cargo run --example invalid # a broken model, and what the validator says
```
`showcase` is a small but complete generator — it builds `KtFile` fragments,
merges them so each package collapses to one file, and renders classes,
objects, enums, data and value classes, sealed interfaces, `fun interface`s,
type aliases, extension functions, properties with accessors and delegates,
`external` natives, and raw blocks. `invalid` shows the two ways a mistake surfaces: as a diagnostic
from the validator, or as a builder that refuses to construct the value at all.
To accept an intended change to either output:
```sh
UPDATE_GOLDEN=1 cargo test --test examples # then review the diff
```
## Catching mistakes before `kotlinc` does
A *program* builds the model, so the mistakes are program mistakes: a name
derived from a Rust field that happens to be `object`, two generated classes
that mangle to the same name, a branch that built an `object` where it meant a
`data class`. Without a check, those first surface when the Kotlin compiler
runs — often in a different build, against a generated file that gives no hint
about what produced it.
Two things address that.
**Bad shapes are mostly unbuildable.** The kinds carry their own data, so an
`object` has nowhere to put constructor parameters, a `value class` holds
exactly one property, a `data class` cannot have zero, a `companion object`
cannot be a top-level declaration, a class cannot construct two superclasses,
a `fun interface` method cannot have a body, and `external` cannot be combined
with one.
**What is left is validated.** `KtFile::validate()` walks the file, every class
body and every companion body and reports what the model can prove is wrong:
names that are not legal Kotlin identifiers, redeclarations (per scope, with
Kotlin's separate type / value / function namespaces, so real overloads pass),
and the shapes the types could not rule out. `merge_files` and `write_files`
run it and refuse to write.
It is deliberately **not** a Kotlin compiler: no type resolution, no parsing of
body text, and no check that could fire on correct output. `ValidationPolicy`
sets any check to error, warning or off — `ValidationPolicy::warn_all()` is the
way to adopt validation in a generator that already produces output.
## Kotlin identifiers
Generated names come from somewhere else — a Rust field, a C symbol, a JSON
key — and some are never legal Kotlin. `is_valid_kotlin_ident`,
`mangle_kotlin_ident` (`my-name` → `my_name`, `object` → `object_`) and
`escape_kotlin_ident` (`` `object` ``, keeping the name instead of changing it)
are available for that, along with their package-path equivalents.
## Why
This crate was made for the [prebindgen-jni](https://crates.io/crates/prebindgen-jni)
library, which generates JNI bindings for Rust libraries. The existing
[kotlin-poet-rs](https://crates.io/crates/kotlin-poet-rs) crate was not used
for Not-Invented-Here reasons and because full control over the code generator was needed.
This crate will be supported as long as `prebindgen-jni` is alive.
## Status
Early, dependency-free, and intentionally minimal. No macros, no derive, no
external crates — just a plain declaration model, a renderer, and a validator.
## License
Licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
- MIT license ([LICENSE-MIT](LICENSE-MIT))
at your option.
## Releasing
Publishing is automated from GitHub Actions. See [RELEASING.md](RELEASING.md)
for the release process and [CHANGELOG.md](CHANGELOG.md) for release notes.