Skip to content

feat(jvm): add a desktop Compose path and drop hand-declared compiler artifact - #13

Merged
ulite-Amr merged 6 commits into
mainfrom
feat/compose-compiler-turnkey
Aug 30, 2026
Merged

feat(jvm): add a desktop Compose path and drop hand-declared compiler artifact#13
ulite-Amr merged 6 commits into
mainfrom
feat/compose-compiler-turnkey

Conversation

@ulite-Amr

Copy link
Copy Markdown
Contributor

What changed

  • JvmConfig gains a compose key. When jvm.compose = true the compile-kotlin task locates compose-compiler-plugin on the compile classpath (the companion Uliab PR injects it alongside the BOM-managed runtime deps) and passes it via -Xplugin=<jar>. A module with jvm.compose but no .kt sources is rejected at configure time.
  • New helpers kotlinc_args / find_compose_compiler_jar / map_compose_error.
  • The android/kmp compose = true but no compiler jar on the classpath configure errors no longer tell the author to hand-declare the artifact (the host injects it); the message now describes host-injection failure.
  • docs/jvm-plugin.md documents the compose key and the -Xplugin invocation.

DSL syntax

jvm {
  sources = ["src/Main.kt"]
  classesDir = "build/classes"
  jarFile = "build/app.jar"
  compose = true
}

Definition of Done

  • cargo build --all-targets zero warnings
  • cargo clippy --all-targets --all-features -- -D warnings clean
  • cargo fmt --all --check clean
  • cargo test (jvm 18, android 53, kmp 24) green
  • rustdoc on new public items
  • PROGRESS.md updated
  • DOCS in same commit (docs/jvm-plugin.md)
  • process-tell grep clean on touched files

Tests

New jvm-plugin tests: kotlinc_invocation_loads_compose_plugin_via_xplugin, kotlinc_invocation_matches_plain_shape_without_compose, compose_jar_is_found_among_compile_classpath_entries, compose_jar_is_absent_when_not_on_classpath, compose_error_is_actionable_when_jar_missing. 6 new tests.

Depends on Uliab compose-compiler injection (PR #41).

… artifact

The jvm plugin previously ran plain kotlinc with no plugin mechanism, so a
desktop-Compose module could not compile. JvmConfig gains a compose key; when
jvm.compose is true the compile-kotlin task locates the compose-compiler-plugin
jar on the compile classpath (the host now injects it alongside the BOM-managed
runtime deps) and passes it via -Xplugin=<jar>. A module with jvm.compose but
no .kt sources is rejected at configure time. New kotlinc_args /
find_compose_compiler_jar / map_compose_error helpers and 6 tests.

The android/kmp 'compose = true but no compiler jar on the classpath' configure
errors no longer tell the author to hand-declare the artifact, since the host
injects it; the message now describes host-injection failure. docs/jvm-plugin.md
documents the compose key and the -Xplugin invocation; PROGRESS.md updated.
@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d2abe781-0633-4bf9-a57d-b220d01641e3


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…note AAR gap

The predicate used to locate the Compose compiler plugin jar on the compile
classpath looked for the substring compose-compiler-plugin, which also matches
the wrong artifact. The host now injects the real coordinate
org.jetbrains.kotlin:kotlin-compose-compiler-plugin, whose resolved jar filename
carries the kotlin- prefix, so tighten all three plugins' find_compose_compiler_jar
predicates (plus their fixtures and doc comments) to that name.

docs/jvm-plugin.md and PROGRESS now record that the injected runtime/ui/material3
managed artifacts are Android AARs the jar-only resolver does not materialize, so
@composable API classes are not yet on a compile classpath and an end-to-end
@composable compile still requires AAR unwrapping plus a kotlinc host.
Uliab master moved the plugin SDK to ABI 0.8, but the CI E2E jobs still
seeded a local registry index whose plugin rows declared {min: 0.7, max: 0.7},
so the ABI-0.8 host refused every E2E build with 'no published build of
ulite/* supports plugin-ABI 0.8'. Widen the newest row of each plugin (hello,
jvm, android, kmp) to {min: 0.7, max: 0.8} in both the eight E2E-seeded
indexes in the workflow and the committed registry index, so each row covers
the host ABI and the manifest-reported ABI version. Older rows stay capped at
their original ABI. Sync docs/registry.md and the kmp crate version in
docs/architecture.md to match.
The host hands the project directory and the DSL block's output paths
over under camelCase keys (`projectDir`, `classesDir`, `jarFile`),
and consumes `configure()`'s typed `PluginConfig` via serde. But
`#[ulb(rename)]` only shapes the embedded schema, not serde's field
lookup, so the snake_case Rust fields (`project_dir`, `classes_dir`,
`jar_file`) never matched once the ABI-0.8 host re-exercised the
plugin, failing configure with `missing field 'classes_dir'`.

Add the equivalent `#[serde(rename = ...)]` to those three fields and
cover the host-shaped JSON in a regression test. android/kmp unaffected:
they deserialize to `serde_json::Value` and read DSL keys directly.
The ksp task declared both `build/generated/ksp/kotlin` and
`.../java` as outputs, but KSP2 creates only the Kotlin dir; a
processor that emits no `.java` never creates the java dir, and the
host rejects a declared output the action did not produce (`task 'ksp'
declared output '.../build/generated/ksp/java' but it does not exist
after the action ran`).

Declare only the Kotlin output dir as a task output. `-java-output-dir`
is still passed so KSP generates into it when it does emit java; it is
just no longer a required output.
The `kotlinc_args` doc described the no-plugin-jar case as "keeping an
empty compose jar", which read as nonsense (the parameter is `None`,
not an empty jar); rephrase to state the invocation is identical to the
plain compiler shape. Give `map_compose_error` an \ note.

PROGRESS.md claimed a `jvm.compose` module with no `.kt` sources is
rejected at configure time; it is not — the compose logic lives inside
the Kotlin-compile branch, so such a module simply gets no `-Xplugin`.
Correct the tracking note to match the code and docs/jvm-plugin.md.
@ulite-Amr
ulite-Amr merged commit ab103c2 into main Aug 30, 2026
9 checks passed
@ulite-Amr
ulite-Amr deleted the feat/compose-compiler-turnkey branch August 30, 2026 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant