ktrs_compose/lib.rs
1//! Port of mrmans0n/compose-rules (pin: `tools/sync-compose-rules.sh`), its ktlint flavour
2//! (`io.nlopez.compose.rules:ktlint`): the rules of `ComposeRuleSetProvider` (rule set `compose`), run natively
3//! when a ktlint run loads that release's JAR (`-R`); every other rule set JAR goes to the real ktlint jar.
4//!
5//! Layout mirrors upstream, one Rust file per Kotlin file and one fn per Kotlin fn in the same order: `core` =
6//! `rules/common/.../core` (`util/` = `core/util`), `rules` = `rules/common/.../rules`, `ktlint` = `rules/ktlint`
7//! (the `KtlintRule` adapter, `.editorconfig` properties, the `*Check` modules, the provider).
8//!
9//! # Porting a rule
10//! 1. `rules/<rule>.rs`: a unit struct implementing [`ComposeKtVisitor`]; messages are `pub const` strings with the
11//! `trimIndent()`ed text (lines joined by `\n`, no trailing newline).
12//! 2. `ktlint/<rule>_check.rs`: `pub fn <rule>_check() -> KtlintRule` with upstream's id and properties
13//! (`ComposeProperty::String(&CUSTOM_MODIFIERS)`, ...), and `pub const CHECK = Some(<rule>_check)`. A check that
14//! overrides a visit method to gate it (`Material2Check`, `PreviewNamingCheck`, ...) is a struct holding the rule
15//! and implementing [`ComposeKtVisitor`] itself, like [`ktlint::preview_naming_check`]. No shared file changes:
16//! `rules/mod.rs`, `ktlint/mod.rs` and the provider already list every rule.
17//! 3. Goldens: `cargo test -p ktrs-compose --release --test golden` (`GOLDEN_FILTER=<rule-dir>`), then
18//! `UPDATE_PASSING=1` to ratchet `tests/golden-passing.txt`.
19//!
20//! # Kotlin -> Rust
21//! - PSI is `ktrs_ast::psi` over the mutable tree (its module docs have the conventions): `x is KtFoo` ->
22//! `KtFoo::is(ast, n)`, `x as? KtFoo` -> `KtFoo::cast(ast, n)`, getters drop `get` and take `ast`; expression
23//! results are bare `NodeId`s. `KtAnnotated`/`KtModifierListOwner`/`KtCallableDeclaration` receivers of the
24//! util extensions are bare nodes: `function.isComposable` -> `is_composable(ast, function.node())`.
25//! - Visitor hooks get `ast: &mut Ast`; read through it freely (`&mut Ast` coerces to `&Ast`). Collect a Kotlin
26//! sequence into a `Vec` before reporting, unless a fix inside the loop edits the tree and the sequence is lazy
27//! upstream: then step a [`core::util::psi_elements::ChildrenByClass`].
28//! - `emitter.report(e, msg)` -> `emitter.report(ast, e.node(), MSG, false)`; `report(e, msg, true).ifFix { .. }`
29//! -> `emitter.report(ast, e.node(), MSG, true).if_fix(|| { .. })` (the closure may mutate `ast`).
30//! - `config.getSet(key, emptySet())` -> `config.get_set(key, &[])`; a Kotlin `Set<String>` is a `Vec<String>`
31//! without duplicates (insertion order). Regexes are `ktrs_lint::rules::internal::KotlinRegex` (Java syntax,
32//! `matches` = full match).
33//! - `element.text` -> `ast.text(n)` or `x.text(ast)`; `startOffset` -> `ast.start_offset(n)`; `parents`,
34//! `parentsWithSelf`, `siblings(forward, withItself)` -> `ast.parents(n)`, `ast.parents_with_self(n)`,
35//! `ast.siblings_with_itself(n, forward, with_itself)`; `findAllChildrenByClass<T>()` ->
36//! `find_all_children::<T>(ast, n)` (breadth first over `getChildren()`, root included).
37//! - Where ktlint 1.8.0 (Kotlin 2.2.21) and 2.0.0-ALPHA-4 (Kotlin 2.4.10) PSI differ, pass
38//! `config.embedded_kotlin()` (known: `quoteIfNeeded` on Latin-1 letters in `setName`, `getContextParameters`).
39//!
40//! Status, the parity gate and how to bump the pin: research/27-custom-rulesets-impl.md.
41
42pub mod core;
43pub mod jar;
44pub mod ktlint;
45pub mod rules;
46
47pub use core::compose_kt_visitor::ComposeKtVisitor;
48pub use ktlint::compose_rule_set_provider::compose_rule_providers;
49
50/// The ported release.
51pub const COMPOSE_RULES_VERSION: &str = "0.6.7";
52
53/// (release, content fingerprint) of the ktlint JARs that run natively; the fingerprint is computed by
54/// `ktrs-cli`'s `compose_jar.rs`. Per release: the published `ktlint-compose-<release>-all.jar`, and the Maven
55/// artifacts `io.nlopez.compose.rules:ktlint` + `common-ktlint` merged (as the ktlint Gradle plugin passes them;
56/// same bytecode, the `-all` JAR only relocates kotlin-compiler `psiUtil` calls: research/29).
57pub const NATIVE_JARS: &[(&str, &str)] = &[
58 ("0.6.7", "00de57c180c50a3fb36c345558d15e078bfe056bc158d79cc5e5ecbe6ee3bfdf"),
59 ("0.6.7", "a9b34195dddeb441ab1eb2ef78e7080a6781d25654df05a9e1a569c88dc23878"),
60];