RFC3986 compliant URI parsing library for MoonBit
{
"deps": {
"username/uri": "^0.1.0"
}
}// Parse a URI
let uri_result = @uri.of_string("https://example.com:8080/path?query=value#fragment")
match uri_result {
Ok(uri) => {
println(@uri.scheme(uri)) // Some("https")
println(@uri.host(uri)) // Some("example.com")
println(@uri.port(uri)) // Some(8080)
println(@uri.path(uri)) // "/path"
println(@uri.query(uri)) // Some("query=value")
println(@uri.fragment(uri)) // Some("fragment")
}
Err(error) => println("Parse error: " + error.to_string())
}
// Build a URI
let uri = @uri.empty()
|> @uri.with_scheme(Some("https"))
|> @uri.with_host(Some("api.example.com"))
|> @uri.with_path("/v1/users")
|> @uri.with_query(Some("limit=10&offset=0"))
println(@uri.to_string(uri)) // "https://api.example.com/v1/users?limit=10&offset=0"let uri = @uri.of_string("https://example.com/path")let uri_string = @uri.to_string(uri)let normalized = @uri.normalize(uri)let base = @uri.of_string("https://example.com/dir/")
let relative = @uri.of_string("../other/file.html")
match @uri.resolve(base, relative) {
Ok(resolved) => println(@uri.to_string(resolved))
Err(error) => println("Resolution error")
}let pairs = @uri.parse_query("name=John&age=30&city=NYC")
// Returns [("name", "John"), ("age", "30"), ("city", "NYC")]let query = @uri.build_query([("search", "moonbit"), ("limit", "10")])
// Returns "search=moonbit&limit=10"let encoded = @uri.encode("hello world!")
// Returns "hello%20world%21"test "parse_http_uri" {
match @uri.of_string("https://user:pass@example.com:8080/path?query=value#section") {
Ok(uri) => {
assert @uri.scheme(uri) == Some("https")
assert @uri.host(uri) == Some("example.com")
assert @uri.port(uri) == Some(8080)
assert @uri.path(uri) == "/path"
assert @uri.query(uri) == Some("query=value")
assert @uri.fragment(uri) == Some("section")
}
Err(_) => fail("Failed to parse URI")
}
}test "build_api_uri" {
let api_uri = @uri.empty()
|> @uri.with_scheme(Some("https"))
|> @uri.with_host(Some("api.github.com"))
|> @uri.with_path("/repos/owner/repo/issues")
|> @uri.with_query(Some("state=open&per_page=50"))
let expected = "https://api.github.com/repos/owner/repo/issues?state=open&per_page=50"
assert @uri.to_string(api_uri) == expected
}test "resolve_relative_uri" {
let base = @uri.of_string("https://example.com/docs/guide/").unwrap()
let relative = @uri.of_string("../api/reference.html").unwrap()
match @uri.resolve(base, relative) {
Ok(resolved) => {
let expected = "https://example.com/docs/api/reference.html"
assert @uri.to_string(resolved) == expected
}
Err(_) => fail("Failed to resolve URI")
}
}test "query_parameters" {
let uri = @uri.of_string("https://search.example.com/?q=moonbit&lang=en&safe=on").unwrap()
match @uri.query(uri) {
Some(query_str) => {
let params = @uri.parse_query(query_str)
assert params.length() == 3
assert params[0] == ("q", "moonbit")
assert params[1] == ("lang", "en")
assert params[2] == ("safe", "on")
// Rebuild query
let rebuilt = @uri.build_query(params)
assert rebuilt == query_str
}
None => fail("Expected query string")
}
}test "ipv6_uri" {
match @uri.of_string("http://[2001:db8::1]:8080/path") {
Ok(uri) => {
assert @uri.scheme(uri) == Some("http")
assert @uri.host(uri) == Some("[2001:db8::1]")
assert @uri.port(uri) == Some(8080)
assert @uri.path(uri) == "/path"
}
Err(_) => fail("Failed to parse IPv6 URI")
}
}test "uri_normalization" {
let uri = @uri.of_string("https://example.com:443/./path/../other/./file.html").unwrap()
let normalized = @uri.normalize(uri)
// Default HTTPS port (443) should be removed
assert @uri.port(normalized) == None
// Path should be normalized
assert @uri.path(normalized) == "/other/file.html"
let expected = "https://example.com/other/file.html"
assert @uri.to_string(normalized) == expected
}match @uri.of_string("invalid://") {
Ok(uri) => {
// Use the parsed URI
}
Err(error) => {
match error {
@uri.InvalidScheme(scheme) => println("Invalid scheme: " + scheme)
@uri.InvalidAuthority(auth) => println("Invalid authority: " + auth)
@uri.EmptyUri => println("URI cannot be empty")
_ => println("Other parsing error")
}
}
}moon testpub struct Authority {
userinfo : String?
host : String
port : Int?
}pub struct Uri {
scheme : String?
authority : Authority?
path : String
query : String?
fragment : String?
}pub enum UriError {
InvalidScheme(String)
InvalidAuthority(String)
InvalidPath(String)
InvalidQuery(String)
InvalidFragment(String)
InvalidPort(String)
EmptyUri
}RFC3986 compliant URI parsing library for MoonBit