Repository navigation
Explore a modular architecture: lean core + optional IDNA module, one conformance suite on every target #10
Description
A proposal to restructure kuri (currently a single :kuri module) into a lean, dependency-light core with internationalization as an opt-in module, and to make all-target conformance the explicit contract. To be explored as a follow-up — not blocking the current layers.
Where we are today
Everything lives in one :kuri module (org.dexpace.kuri), all commonMain, already zero expect/actual — the parser, percent-encoding, scheme, host, serializer, and the IDNA stack (Punycode, the UTS-46 mapping table at Unicode 16.0, NFC, ContextJ/validity) are all pure Kotlin. That portability is great, but the bundled Unicode tables (the mapping table alone is ~150 KB of generated source, plus NFC and validity data) ship to every consumer, including those who only ever touch ASCII hosts. The host pipeline calls Idna.domainToAscii directly, so core and IDNA are entangled.
Proposal
1. Core module — commonMain, zero platform code, zero expect/actual.
The WHATWG state-machine parser + the RFC 3986 mode, percent-encoding with explicit per-component encode sets, the Url/Uri two-type design, immutable values + builders. ASCII host handling only (registered names and Punycode-literal xn-- pass-through; IPv4/IPv6 stay in core). This runs identically on every target, today, with a small footprint.
2. IDNA module — separate, optional, still pure commonMain.
UTS-46 + Punycode with the compressed tables. Consumers who need internationalized hosts add this module; everyone else stays lean. Because it is pure Kotlin (no platform IDN fallback), it works on Wasm too, with no platform-specific behavior that could desync from the common implementation. The host pipeline gets a pluggable domain-to-ASCII seam: present → full UTS-46; absent → the core's ASCII-only path.
3. One conformance suite, every target.
Vendor urltestdata.json (and the IDNA/toascii/IdnaTestV2, NFC, and RFC §5.4 corpora) and run them in CI across JVM / JS / Native / Wasm. Green-on-all is the contract.
Why
- Footprint — most users don't pay for the Unicode tables they don't use.
- Portability without divergence — no
expect/actualand nojava.net.IDN-style platform fallback means one behavior everywhere, Wasm included. - A single, enforceable correctness contract — the same suite, green on every target.
What this would take (rough)
- Extract the
idnapackage + its generated tables (and the IDNA conformance fixtures) into akuri-idnamodule; introduce a pluggable host→ASCII seam inHostParserso core degrades to ASCII-only when IDNA is absent. - Decide where NFC lives (it is only needed by IDNA today, so likely the IDNA module).
- The conformance fixtures already sit in
commonTest, so running them on all targets is mostly a CI/build-matrix change (we currently exercisejvmTestlocally); addjsTest/nativeTest/wasmJsTestto CI. - Decide the module/artifact split and whether it's a breaking change relative to the single-module layout.
Open questions
- Core's behavior for a non-ASCII host when IDNA is absent: reject, or percent-encode/opaque per a documented degraded mode?
- One umbrella artifact (
kuri) that depends on both, plus à-la-cartekuri-core/kuri-idna? - Does the optional-IDNA seam interact with the host-validity follow-ups (IDNA: implement CheckBidi (RFC 5893) for the URL profile #4, IDNA: re-validate decoded A-labels (UTS-46 V1/V4) #5)?
Activity