URLs for MoonBit: WHATWG and RFC 3986 parsing, IDNA, URI templates, percent coding.
// A string a browser and a generic parser disagree about.
@moonurl.Url::decode("HTTP://EXAMPLE.test:80/a/../b").encode()
// "HTTP://EXAMPLE.test:80/a/../b"
@moonurl.Url::decode("HTTP://EXAMPLE.test:80/a/../b", syntax=@moonurl.Whatwg).encode()
// "http://example.test/b"
// Host names, in and out of ASCII.
@moonurl.domain("MÜNCHEN.example") // "xn--mnchen-3ya.example"
@moonurl.Url::decode("http://192.0x00A80001/", syntax=@moonurl.Whatwg).host // Some("192.168.0.1")
// A template filled in, and a URI read back.
@template.Template::decode("/users/{id}{?page}").expand(values) // "/users/42?page=2"
@template.Template::decode("/users/{id}{?page}").capture("/users/42?page=2")| Package | What | Specification |
|---|---|---|
| moonurl | Url: parsing, recomposing, resolving, normalising, origins, setters | RFC 3986, WHATWG URL Standard |
| moonurl | Percent coding by component, Kind | RFC 3986 §2 |
| moonurl | Query: the pairs of a query or a form body | WHATWG URL Standard §5 |
| moonurl | domain: a host name in ASCII | UTS 46 |
| moonurl/idna | Punycode, and the mapping and validity rules behind it | RFC 3492, UTS 46 |
| moonurl/template | URI templates: parse, expand, capture | RFC 6570 |
| moonurl/dataurl | A whole representation written inside the reference to it | RFC 2397 |
let url = @moonurl.Url::decode("https://leo:pw@example.test:8443/a/b?x=1#top")
url.scheme // Some("https")
url.host // Some("example.test")
url.port // Some(8443)
url.query // Some("x=1")
url.origin() // "https://example.test:8443"let outcome = @idna.to_ascii("münchen.example")
outcome.name // "xn--mnchen-3ya.example"
outcome.is_ok() // true
// Two settings, for the two callers there are.
@idna.to_ascii("Faß.de").name // "xn--fa-hia.de"
@idna.to_ascii("Faß.de", options={ ..@idna.options, transitional: true }).name // "fass.de"let values : Map[String, @template.Value] = Map([])
values.set("list", @template.Value::List(["red", "green"]))
values.set("q", @template.Value::Text("moon bit"))
@template.Template::decode("{/list*}{?q}").expand(values) // "/red/green?q=moon%20bit"
@template.Template::decode("{/list*}{?q}").capture("/red/green?q=moon%20bit")| Item | Shape | What it does |
|---|---|---|
| Url::decode(text, syntax?, base?) | Url raise Refused | Read a reference, in either grammar |
| Url::encode() | String | Write it back |
| Url::resolve(reference) | Url | Resolve against this base (RFC 3986) |
| Url::normalize() | Url | Case, escapes and dot segments (§6.2.2) |
| Url::origin() | String | scheme://host:port, or "null" |
| Url::authority() | String? | The authority, brackets restored |
| Url::is_absolute() | Bool | A scheme and no fragment |
| Url::params() | Query raise Refused | The query as pairs |
| Url::set_* | Url | One component changed, the rest kept |
| Url::new(..) | Url | A reference built piece by piece |
| domain(text, strict?) | String raise Refused | A host name in ASCII |
| escape / escape_text | String | Percent-encode octets or text |
| unescape / unescape_text | Bytes / String | Undo it |
| escaped(text, kind?) | Bool | Whether every escape is complete |
| normalize_escapes(text) | String | Upper-case hex, unreserved octets plain |
| remove_dots(path) | String | The . and .. segments out |
| Query::decode(bytes, limits?) | Query raise Refused | A form body or a query |
| Query::encode() | String | The same body written back |
| idna::to_ascii / to_unicode | Outcome | A name in ASCII, or in Unicode |
| idna::encode / decode | String raise Refused | One label of Punycode |
| Template::decode(text) | Template raise Refused | Read a template |
| Template::expand(values) | String | Fill it in |
| Template::capture(uri) | Array[(String, String)]? | Read a URI back into names |
| dataurl::Url::decode(text) | Url raise Refused | A data URL |
test {
// RFC 3986 keeps the reference as it was written.
let url = @moonurl.Url::decode("HTTP://EXAMPLE.test:80/a/../b?q#f")
assert_eq(url.encode(), "HTTP://EXAMPLE.test:80/a/../b?q#f")
let whatwg = @moonurl.Url::decode(
"HTTP://EXAMPLE.test:80/a/../b",
syntax=@moonurl.Whatwg,
)
assert_eq(whatwg.encode(), "http://example.test/b")
}test {
let url = @moonurl.Url::decode(
"https://example.test/a",
syntax=@moonurl.Whatwg,
)
assert_eq(url.origin(), "https://example.test")
let file = @moonurl.Url::decode("file:///tmp/x", syntax=@moonurl.Whatwg)
assert_eq(file.origin(), "null")
}test {
let url = @moonurl.Url::decode(
"https://h/?a=1&a=2&b=x+y",
syntax=@moonurl.Whatwg,
)
assert_eq(url.params().values("a").length(), 2)
assert_eq(url.params().get("b").unwrap(), "x y")
}test {
let url = @moonurl.Url::decode(
"http://example.test/a",
syntax=@moonurl.Whatwg,
)
assert_eq(url.set_scheme("https").encode(), "https://example.test/a")
assert_eq(url.set_scheme("1bad").encode(), "http://example.test/a")
}test {
assert_eq(@moonurl.domain("MÜNCHEN.example"), "xn--mnchen-3ya.example")
assert_eq(@moonurl.domain("xn--a"), "xn--a")
}fn normalize_escapes(text : StringView) -> Stringfn remove_dots(path : String) -> Stringfn unescape(raw : BytesView) -> Bytesfn unescape_text(text : StringView) -> StringInstall
Download zipURLs for MoonBit: WHATWG and RFC 3986 parsing, IDNA, URI templates, percent coding.