URI parser for Moonbit
moon add username/uri{
"import": ["username/uri"]
}// Parse a complete URI
let uri_string = "https://example.com:8080/path?query=value#fragment"
match parse_uri(uri_string) {
Ok(uri) => {
println("Scheme: \{uri.scheme}")
println("Host: \{uri.authority}")
println("Path: \{uri.path}")
}
Err(error) => println("Parse error: \{error}")
}// Build an HTTP URI fluently
let uri = new_builder()
.scheme("https")
.host("api.example.com")
.port(443)
.path("/v1/users")
.add_query_param("limit", "10")
.add_query_param("offset", "20")
.fragment("results")
.build()
match uri {
Ok(u) => println("Built URI: \{uri_to_string(u)}")
Err(e) => println("Build error: \{e}")
}pub struct URI {
scheme : String // Required scheme (http, https, ftp, etc.)
authority : Authority? // Optional authority component
path : String // Path component
path_type : PathType // Classification of path type
query : String? // Optional query string
fragment : String? // Optional fragment identifier
}pub struct Authority {
userinfo : String? // Optional user information
host : HostType // Host (required in authority)
port : Int? // Optional port number
}
pub enum HostType {
IPv4(String) // IPv4 address (e.g., "192.168.1.1")
IPv6(String) // IPv6 address (e.g., "::1")
IPvFuture(String) // Future IP version
RegName(String) // Regular domain name (e.g., "example.com")
}let result = parse_uri("https://user@example.com:8080/path?q=val#frag")// Absolute URI
let abs_uri = parse_uri_reference("https://example.com/path")
// Relative reference
let rel_ref = parse_uri_reference("/path?query=value")pub fn create_uri(
scheme : String,
authority : Authority?,
path : String,
query : String?,
fragment : String?
) -> URIResult[URI]// Simple URI with scheme and path
create_simple_uri("file", "/path/to/file.txt")
// HTTP URI
create_http_uri("example.com", Some(8080), "/api", Some("v=1"), None)
// HTTPS URI
create_https_uri("secure.example.com", None, "/", None, Some("top"))
// File URI
create_file_uri("/home/user/document.pdf")new_builder()
.scheme("https") // Set scheme
.host("api.example.com") // Set host (creates authority)
.port(443) // Set port
.userinfo("user:pass") // Set userinfo
.path("/v1/endpoint") // Set path
.add_path_segment("users") // Add path segment
.query("format=json") // Set query string
.add_query_param("page", "1") // Add single parameter
.fragment("section1") // Set fragment
.build() // Build final URIlet uri_string = uri_to_string(parsed_uri)let base = parse_uri("https://example.com/base/path")
let reference = parse_uri_reference("../other/file")
let resolved = resolve_reference(base, reference)pub enum URIError {
InvalidScheme(String)
InvalidAuthority(String)
InvalidHost(String)
InvalidPort(String)
InvalidPath(String)
InvalidQuery(String)
InvalidFragment(String)
InvalidPercentEncoding(String)
MalformedURI(String)
}fn example_web_url() {
let url = new_builder()
.scheme("https")
.host("www.example.com")
.add_path_segment("products")
.add_path_segment("123")
.add_query_param("color", "blue")
.add_query_param("size", "large")
.build()
match url {
Ok(uri) => {
// Output: https://www.example.com/products/123?color=blue&size=large
println(uri_to_string(uri))
}
Err(e) => println("Error: \{e}")
}
}fn example_file_uri() {
let file_uri = create_file_uri("/home/user/documents/report.pdf")
match file_uri {
Ok(uri) => {
// Output: file:///home/user/documents/report.pdf
println(uri_to_string(uri))
}
Err(e) => println("Error: \{e}")
}
}fn example_ipv6_uri() {
let host_type = HostType::IPv6("2001:db8::1")
let authority = { userinfo: None, host: host_type, port: Some(8080) }
let uri = create_uri(
"http",
Some(authority),
"/api/v1/data",
Some("format=json"),
Some("results")
)
match uri {
Ok(u) => {
// Output: http://[2001:db8::1]:8080/api/v1/data?format=json#results
println(uri_to_string(u))
}
Err(e) => println("Error: \{e}")
}
}fn validate_user_uri(input : String) -> Bool {
match parse_uri_reference(input) {
Ok(uri) => {
// Additional validation can be performed here
true
}
Err(_) => false
}
}
fn example_validation() {
let test_urls = [
"https://example.com",
"ftp://files.example.com/path",
"/relative/path",
"invalid::uri",
]
for url in test_urls {
if validate_user_uri(url) {
println("\{url} is valid")
} else {
println("\{url} is invalid")
}
}
}fn example_query_handling() {
let params = [
("search", "moon programming"),
("page", "1"),
("sort", "date"),
("order", "desc")
]
let uri = new_builder()
.scheme("https")
.host("search.example.com")
.path("/results")
.query_params(params)
.build()
match uri {
Ok(u) => {
// Properly encoded query string
println(uri_to_string(u))
}
Err(e) => println("Error: \{e}")
}
}moon testpub(all) enum HostType {
IPv4(String)
IPv6(String)
IPvFuture(String)
RegName(String)
}pub(all) enum PathType {
AbEmpty
Absolute
NoScheme
Rootless
Empty
}pub struct URIBuilder {
scheme : String
authority : Authority?
path : String
query : String?
fragment : String?
}impl Show for URIBuilderpub enum URIError {
InvalidScheme(String)
InvalidAuthority(String)
InvalidHost(String)
InvalidPort(String)
InvalidPath(String)
InvalidQuery(String)
InvalidFragment(String)
InvalidPercentEncoding(String)
MalformedURI(String)
}fn encode_fragment(s : String) -> Stringfn encode_path_segment(s : String) -> Stringfn encode_reg_name(s : String) -> Stringfn encode_userinfo(s : String) -> Stringfn find_char_index(s : String, c : Char) -> Int?fn find_last_index_str(s : String, substr : String) -> Int?fn is_fragment_char(c : Char) -> Boolfn is_gen_delim(c : Char) -> Boolfn is_pchar(c : Char) -> Boolfn is_query_char(c : Char) -> Boolfn is_reg_name_char(c : Char) -> Boolfn is_reserved(c : Char) -> Boolfn is_scheme_char(c : Char) -> Boolfn is_segment_nz_nc_char(c : Char) -> Boolfn is_sub_delim(c : Char) -> Boolfn is_unreserved(c : Char) -> Boolfn is_userinfo_char(c : Char) -> Boolfn is_valid_encoded_string(s : String, char_validator : (Char) -> Bool) -> Boolfn is_valid_percent_encoding(s : String) -> Boolfn is_valid_uri(uri_string : String) -> Boolfn is_valid_uri_reference(uri_ref_string : String) -> Boolfn normalize_path(path : String) -> Stringfn percent_encode(s : String, should_encode : (Char) -> Bool) -> Stringfn schemes_equal(scheme1 : String, scheme2 : String) -> BoolURI parser for Moonbit