Skip to content

dexpace/kuri

Repository files navigation

kuri

A standards-faithful URI and URL library for Kotlin and Java.

License Kotlin Kotlin Multiplatform JDK Coverage

Contents

Installation · Quick start · Two models · Parsing and errors · Building and resolving · Standards · Conformance · Platforms · Versioning and stability · Building from source · Documentation · Contributing · Security · License

Installation

Note

Not yet published. kuri is not on Maven Central or any other repository, so it cannot be resolved as a dependency yet. Until the first release ships, build from source.

The coordinates reserved for the first release:

Coordinate Value
Group org.dexpace
Artifact kuri
Version 0.1.0-SNAPSHOT (pre-release)

The artifact id is identical across Kotlin Multiplatform targets; the Gradle plugin selects the right variant for your platform automatically. A copy-paste dependency snippet will be added here once the initial release is available.

Requirements

Java runtime Java 8 or newer (the JVM artifact is compiled to 1.8 bytecode for broad compatibility)
Kotlin consumers Kotlin 2.0 or newer; the public API lives in common Kotlin
Runtime dependencies None beyond the Kotlin standard library

Quick start

import org.dexpace.kuri.Url
import org.dexpace.kuri.error.getOrThrow

val url = Url.parse("https://Example.com:443/a/../b?q=1#frag").getOrThrow()

url.scheme                     // "https"
url.hostName                   // "example.com"  — lower-cased
url.port                       // null           — the default :443 is elided
url.effectivePort              // 443
url.pathSegments               // ["b"]          — /a/../b is resolved
url.queryParameters.get("q")   // "1"
url.toString()                 // "https://example.com/b?q=1#frag"

From Java:

import org.dexpace.kuri.Url;

Url url = Url.parse("https://example.com/a?b=1").getOrThrow();

url.scheme();    // "https"
url.hostName();  // "example.com"

Two models, one engine

Uri Url
Standard RFC 3986 (RFC 3987-aware) WHATWG URL
Posture preserve the input; normalize on request canonicalize eagerly
Scheme any, and may be absent (relative reference) always present; special schemes known
Host reg-name / IPv4 / IPv6 / IP-future IDNA, IPv4 shorthand, opaque hosts
Equality structural, plus normalizedEquals() for RFC §6.2 on the canonical serialization

Url.toUri() is near-lossless; Uri.toUrl() may fail when a generic URI is not a valid web URL.

Parsing and errors

Parsing returns a ParseResult<T> — errors are values, not exceptions — and you choose how to consume it:

Url.parse(input)                 // ParseResult<Url>  (Ok / Err)
Url.parse(input).getOrNull()     // Url?
Url.parse(input).getOrThrow()    // Url, or throws UriSyntaxException
Url.canParse(input)              // Boolean
Url.parse(input).fold(onOk = { it.host }, onErr = { it })

Err carries a structured UriParseError with the offending offset and reason.

Building and resolving

Values are immutable; builders produce new ones, and newBuilder() copies an existing value.

val url = Url.Builder()
    .scheme("https")
    .host("example.com")
    .addPathSegment("v1")
    .addPathSegment("users")
    .setQueryParameter("page", "2")
    .build()                                  // https://example.com/v1/users?page=2

val next = url.resolve("orgs").getOrThrow()   // https://example.com/v1/orgs

The generic Uri preserves what you parsed and normalizes only when asked:

val uri = Uri.parse("HTTP://Example.com/a/../b").getOrThrow()
uri.toString()                 // "HTTP://Example.com/a/../b"  — verbatim
uri.normalized().toString()    // "http://example.com/b"       — RFC 3986 §6.2

Standards

kuri implements the standards below; per-standard conformance is measured in Conformance.

Core syntax

Standard Governs Compliance Support
RFC 3986 (STD 66) URI generic syntax; the Uri model and parsing authority Conformant Default
RFC 3987 Internationalized Resource Identifiers (IRIs) Supported Default
WHATWG URL Standard the Url model — parser, special schemes, canonical serialization Ratcheting Default

Hosts, internationalization, and IP addresses

Standard Governs Compliance Support
UTS #46 Unicode IDNA Compatibility Processing (host ToASCII / ToUnicode) Ratcheting Default
RFC 5891 Internationalized Domain Names in Applications (IDNA2008) — protocol Ratcheting Default
RFC 5892 IDNA2008 — Unicode code points and derived properties Ratcheting Default
RFC 3492 Punycode — the Bootstring encoding of Unicode Conformant Default
UAX #15 Unicode Normalization Forms (NFC) Conformant Default
RFC 5952 IPv6 address text representation (canonical form) Conformant Default
RFC 6874 IPv6 zone identifiers in URLs Opt-in Opt-in

Query

Standard Governs Compliance Support
application/x-www-form-urlencoded Form-encoded query parsing and serialization Conformant Default

Notation and requirement levels

Standard Governs Compliance Support
RFC 5234 (STD 68) ABNF — the grammar notation used by the specification Notation
RFC 2119 · RFC 8174 (BCP 14) Requirement-level keywords (MUST / SHOULD / MAY) Notation

ComplianceConformant: passes the standard's conformance corpus, or its controlling table, with no known failures · Ratcheting: conformant except for cases pinned in the known-failures baseline, which can only shrink ( see Conformance) · Opt-in: conformant when explicitly enabled · Supported: implemented as an input dialect, not measured by a dedicated corpus · Notation: used to author the specification, with no runtime behavior to conform to.

SupportDefault: active in the default configuration of both profiles · Opt-in: available behind an explicit flag, off by default · : not applicable.

Conformance

Behavior is checked against the conformance corpora the standards ship with:

Suite Result
WHATWG urltestdata.json — parsing 880 / 886
WHATWG urltestdata.json — parse → serialize (href) 611 / 611
IDNA IdnaTestV2 + toascii 2732 / 2760
Unicode NormalizationTest.txt (NFC) 19 966 / 19 966
RFC 3986 §5.4 reference resolution all rows

Any case that does not yet pass is pinned in a checked-in known-failures baseline; the build fails if a passing case later regresses.

Platforms

The entire public API lives in common Kotlin and compiles for every target below.

Tier Targets
JVM jvm
JavaScript js (browser, Node.js)
WebAssembly wasmJs (browser, Node.js)
Native — Apple macosArm64, iosArm64, iosX64, iosSimulatorArm64, watchosArm64, watchosSimulatorArm64, tvosArm64, tvosSimulatorArm64
Native — Linux linuxX64, linuxArm64
Native — Windows mingwX64

The java.net.URI / java.net.URL conversions are JVM-only extensions. Every target compiles on any host; executing the native test suites requires a matching operating system or simulator.

Versioning and stability

kuri follows Semantic Versioning 2.0.0. At 0.1.0-SNAPSHOT the public API is not yet frozen and may change before 1.0.0, and minor releases in the 0.x series may carry breaking changes, so pin to an exact version. Every public signature is tracked in a checked-in binary-compatibility snapshot under api/, so an unintended API change fails the build (see Building from source).

Building from source

Building kuri requires a JDK 21 toolchain; the bundled Gradle wrapper provisions the rest.

./gradlew build

build compiles every target and runs the full quality gate. Each check below fails the build:

  • ktlint (formatting) and detekt (static analysis)
  • Kotlin allWarningsAsErrors
  • explicit-API strict mode
  • the binary-compatibility validator (apiCheck)
  • an 80% Kover line-coverage floor

After an intentional public-API change, regenerate and commit the API snapshot in the same change:

./gradlew apiDump

Documentation

  • docs/SPEC.md — the normative behavior specification. It defines the character repertoire, the percent-encoding matrix, the host pipeline, the parsing algorithm, reference resolution, the query model, normalization and equivalence semantics, and the error model that a conforming implementation must exhibit for each profile.

Contributing

Issues and pull requests are welcome on the project repository. ./gradlew build must pass — the full quality gate and the conformance baselines included — before a change can merge, and a public-API change must commit the regenerated api/ snapshot (see Building from source). New or changed behavior should be grounded in the relevant standard and reflected in docs/SPEC.md. Commits and pull-request titles use the feat: / fix: / test: / docs: / chore: prefix convention.

Security

There is no formal security policy yet. Please report suspected vulnerabilities privately to the maintainers rather than opening a public issue, so a fix can be prepared before disclosure.

License

kuri is released under the MIT License, Copyright (c) 2026 dexpace.

About

A URI/URL parsing and manipulation library for the Java and Kotlin

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors