url

WHATWG URL Standard parser implementation in MoonBit

url
moon add tonyfettes/url@0.3.3
Download zip
Version
0.3.3
License
Apache-2.0
Last updated
2 months ago
Downloads
1K

Dependencies

README

#url

WHATWG URL Standard parser implementation in MoonBit. Parses and serializes URLs according to the WHATWG URL Standard with web-platform-tests (WPT) compliance.

#Installation

moon add tonyfettes/url

#Usage

// Parse a URL
let url = @url.Url::parse("https://user:pass@example.com:8080/path?query=value#fragment")
match url {
Some(url) => {
println(url.protocol()) // "https:"
println(url.hostname()) // "example.com"
println(url.pathname()) // "/path"
println(url.search()) // "?query=value"
println(url.hash()) // "#fragment"
println(url.to_string()) // full URL
}
None => println("Invalid URL")
}

// Parse relative URLs with a base
let base = @url.Url::parse("https://example.com/a/b/c").unwrap()
let relative = @url.Url::parse("../d", base~)
// Result: "https://example.com/a/d"

// Modify URL components
let url = @url.Url::parse("http://example.com/path").unwrap()
url.set_protocol("https:")
url.set_port("8080")
url.set_pathname("/new/path")
url.set_search("?foo=bar")
url.set_hash("#section")

#API

#Parsing

  • Url::parse(input: String, base?: Url) -> Url? - Parse a URL string, optionally with a base URL for relative resolution

#Getters

MethodDescription
href()Full serialized URL
protocol()Scheme with trailing colon (e.g., "https:")
get_username()Username component
get_password()Password component
get_host()Host with port (e.g., "example.com:8080")
hostname()Host without port
get_port()Port as string (empty if default/none)
pathname()Path component
search()Query string with leading ?
hash()Fragment with leading #
origin()Origin (scheme + host + port)

#Setters

MethodDescription
set_protocol(protocol: String)Set scheme
set_username(username: String)Set username
set_password(password: String)Set password
set_host(host: String)Set host (with optional port)
set_hostname(hostname: String)Set hostname only
set_port(port: String)Set port
set_pathname(pathname: String)Set path
set_search(search: String)Set query string
set_hash(hash: String)Set fragment

#Host Types

The parser recognizes four host types:

  • Domain(String) - Domain names (with IDNA/Punycode support)
  • IPv4(IPv4) - IPv4 addresses (supports decimal, octal, hex notation)
  • IPv6(IPv6) - IPv6 addresses (supports :: compression and IPv4-mapped)
  • Opaque(String) - Opaque hosts for non-special schemes

#Features

  • Full WHATWG URL Standard compliance
  • 3700+ WPT test vectors passing
  • Special scheme handling (http, https, ftp, file, ws, wss)
  • Default port normalization
  • Relative URL resolution
  • Percent-encoding/decoding
  • IPv4 and IPv6 address parsing
  • IDNA/Punycode domain name support
  • Windows drive letter handling for file URLs

#Build

moon check # Type check and lint moon build # Build the project moon test # Run all tests

#License

Apache-2.0

#
ValidationError

type ValidationError derive(ToJson,
Debug
)

URL parsing validation errors per the WHATWG URL Standard. Each variant represents a specific parsing failure condition.

#
ValidationErrors

pub suberror ValidationErrors {
ValidationErrors(Array[ValidationError])
} derive(
Debug
)

#
Host

pub enum Host {
Domain(String)
IPv4(IPv4)
IPv6(IPv6)
Opaque(String)
} derive(ToJson,
Debug
)

Represents a URL host per the WHATWG URL Standard. See: https://url.spec.whatwg.org/#host-representation Can be a domain name, IPv4 address, IPv6 address, or opaque string.
impl Show for Host

#
Host::parse

fn Host::parse(input : StringView, is_opaque? : Bool) -> Host raise ValidationError

Parse a host string per WHATWG URL spec. See: https://url.spec.whatwg.org/#host-parsing Handles IPv4, IPv6 (in brackets), domain names with IDNA/Punycode, and opaque hosts.

The host parser takes a string input with an optional boolean isOpaque (default false), and then runs these steps:
  1. If input starts with U+005B ([), then: 1.1. If input does not end with U+005D (]), IPv6-unclosed validation error, return failure. 1.2. Return the result of IPv6 parsing input with its leading U+005B ([) and trailing U+005D (]) removed.
  2. If isOpaque is true, then return the result of opaque-host parsing input.
  3. Assert: input is not the empty string.
  4. Let domain be the result of running UTF-8 decode without BOM on the percent-decoding of input.
  5. Let asciiDomain be the result of running domain to ASCII with domain and false.
  6. If asciiDomain is failure, then return failure.
  7. If asciiDomain contains a forbidden domain code point, domain-invalid-code-point validation error, return failure.
  8. If asciiDomain ends in a number, then return the result of IPv4 parsing asciiDomain.
  9. Return asciiDomain.

#
Host::to_string

fn Host::to_string(self : Host) -> String

Serialize host per WHATWG URL spec

#
Host::to_unicode

fn Host::to_unicode(self : Host) -> String

Convert host to Unicode form for display (Punycode → Unicode)

#
IPv4

Represents an IPv4 address as a 32-bit unsigned integer. See: https://url.spec.whatwg.org/#concept-ipv4
impl Show for IPv4
impl ToJson for IPv4

#
IPv4::parse

fn IPv4::parse(input : StringView) -> IPv4 raise ValidationError

Parse an IPv4 address per WHATWG URL spec. See: https://url.spec.whatwg.org/#concept-ipv4-parser Supports decimal, octal (0-prefix), and hexadecimal (0x-prefix) notation.

The IPv4 parser takes an ASCII string input and then runs these steps:
  1. Let parts be the result of strictly splitting input on U+002E (.).
  2. If the last item in parts is the empty string, then: 2.1. IPv4-empty-part validation error. 2.2. If parts's size is greater than 1, then remove the last item from parts.
  3. If parts's size is greater than 4, IPv4-too-many-parts validation error, return failure.
  4. Let numbers be an empty list.
  5. For each part of parts: 5.1. Let result be the result of parsing part. 5.2. If result is failure, IPv4-non-numeric-part validation error, return failure. 5.3. Append result to numbers.
  6. If any item in numbers is greater than 255, IPv4-out-of-range-part validation error.
  7. If the last item in numbers is greater than or equal to 256^(5 - numbers's size), IPv4-out-of-range-part validation error, return failure.
  8. If any but the last item in numbers is greater than 255, then return failure.
  9. Let ipv4 be the last item in numbers.
  10. Remove the last item from numbers.
  11. Let counter be 0.
  12. For each n of numbers: 12.1. Increment ipv4 by n * 256^(3 - counter). 12.2. Increment counter by 1.
  13. Return ipv4.

#
IPv4::to_string

fn IPv4::to_string(self : IPv4) -> String

Serialize IPv4 address to dotted-decimal notation (e.g., "192.168.1.1"). See: https://url.spec.whatwg.org/#concept-ipv4-serializer

#
IPv6

Represents an IPv6 address as 8 16-bit pieces
impl Show for IPv6
impl ToJson for IPv6

#
IPv6::parse

fn IPv6::parse(input : StringView) -> IPv6 raise ValidationError

Parse an IPv6 address per WHATWG URL spec. Supports :: compression and embedded IPv4 addresses.

#
IPv6::to_string

fn IPv6::to_string(self : IPv6) -> String

Serialize IPv6 address per WHATWG URL spec Finds longest run of consecutive zeros for :: compression

#
Path

type Path

URL path representation per WHATWG URL spec. See: https://url.spec.whatwg.org/#url-path A URL's path is either a URL path segment (opaque) or a list of URL path segments (hierarchical).
impl Show for Path

#
Path::to_string

fn Path::to_string(self : Path) -> String

Serialize path per WHATWG URL spec. See: https://url.spec.whatwg.org/#url-path-serializer

#
Url

pub struct Url {
scheme : String
username : String
password : String
host : Host?
port : UInt16?
path : Path
query : String?
fragment : String?
}

Represents a parsed URL per the WHATWG URL Standard. See: https://url.spec.whatwg.org/#url-representation

Contains scheme, credentials (username/password), host, port, path, query, and fragment.
impl Show for Url
impl ToJson for Url

#
Url::hash

fn Url::hash(self : Url) -> String

Get the hash (fragment with leading "#" if present)

#
Url::host

fn Url::host(self : Url) -> String

Get the host (hostname + ":" + port if port is present)

#
Url::hostname

fn Url::hostname(self : Url) -> String

Get the hostname (serialized host without port)

#
Url::href

fn Url::href(self : Url) -> String

Get the full URL as a string (alias for to_string)

#
Url::origin

fn Url::origin(self : Url) -> String

Get the origin (scheme + "://" + host + ":" + port for special schemes)

#
Url::parse

#as_free_fn
fn Url::parse(input : StringView, base? : Url) -> Url raise ValidationErrors

#
Url::password

fn Url::password(self : Url) -> String

Get the password

#
Url::pathname

fn Url::pathname(self : Url) -> String

Get the pathname (serialized path)

#
Url::port

fn Url::port(self : Url) -> String

Get the port as a string (empty string if no port or default port)

#
Url::protocol

fn Url::protocol(self : Url) -> String

Get the protocol (scheme + ":")

#
Url::search

fn Url::search(self : Url) -> String

Get the search (query string with leading "?" if present)

#
Url::search_params

fn Url::search_params(self : Url) -> UrlSearchParams

Get the URL search params. Returns a new UrlSearchParams instance parsed from the current query string. Note: Changes to the returned UrlSearchParams will NOT automatically update the URL. Use set_search_params() to update the URL with modified search params. See: https://url.spec.whatwg.org/#dom-url-searchparams

#
Url::set_hash

fn Url::set_hash(self : Url, hash : String) -> Unit

Set the hash (fragment). See: https://url.spec.whatwg.org/#dom-url-hash The hash setter steps are:
  1. If the given value is the empty string, then set this's URL's fragment to null.
  2. Otherwise: 2.1. Let input be the given value with a single leading U+0023 (#) removed, if any. 2.2. Set this's URL's fragment to the empty string. 2.3. Basic URL parse input with this's URL as url and fragment state as state override.

#
Url::set_host

fn Url::set_host(self : Url, host_str : String) -> Unit

Set the host (hostname and optional port). See: https://url.spec.whatwg.org/#dom-url-host The host setter steps are:
  1. If this's URL has an opaque path, then return.
  2. Basic URL parse the given value with this's URL as url and host state as state override.

#
Url::set_hostname

fn Url::set_hostname(self : Url, hostname : String) -> Unit

Set the hostname (without port). See: https://url.spec.whatwg.org/#dom-url-hostname The hostname setter steps are:
  1. If this's URL has an opaque path, then return.
  2. Basic URL parse the given value with this's URL as url and hostname state as state override.

#
Url::set_href

fn Url::set_href(self : Url, href : String) -> Unit raise ValidationErrors

Set the full URL (re-parse and replace all components). See: https://url.spec.whatwg.org/#dom-url-href The href setter steps are:
  1. Let parsedURL be the result of running the basic URL parser on the given value.
  2. If parsedURL is failure, then throw a TypeError.
  3. Set this's URL to parsedURL.

#
Url::set_password

fn Url::set_password(self : Url, password : String) -> Unit

Set the password. See: https://url.spec.whatwg.org/#dom-url-password The password setter steps are:
  1. If this's URL cannot have a username/password/port, then return.
  2. Set the password given this's URL and the given value.

#
Url::set_pathname

fn Url::set_pathname(self : Url, pathname : String) -> Unit

Set the pathname. See: https://url.spec.whatwg.org/#dom-url-pathname The pathname setter steps are:
  1. If this's URL has an opaque path, then return.
  2. Empty this's URL's path.
  3. Basic URL parse the given value with this's URL as url and path start state as state override.

#
Url::set_port

fn Url::set_port(self : Url, port_str : String) -> Unit

Set the port. See: https://url.spec.whatwg.org/#dom-url-port The port setter steps are:
  1. If this's URL cannot have a username/password/port, then return.
  2. If the given value is the empty string, then set this's URL's port to null.
  3. Otherwise, basic URL parse the given value with this's URL as url and port state as state override.

#
Url::set_protocol

fn Url::set_protocol(self : Url, protocol : String) -> Unit

Set the protocol (scheme). See: https://url.spec.whatwg.org/#dom-url-protocol The protocol setter steps are to basic URL parse the given value, followed by U+003A (:), with this's URL as url and scheme start state as state override.
fn Url::set_search(self : Url, search : String) -> Unit

Set the search (query string). See: https://url.spec.whatwg.org/#dom-url-search The search setter steps are:
  1. If the given value is the empty string, set this's URL's query to null.
  2. Otherwise: 2.1. Let input be the given value with a single leading U+003F (?) removed, if any. 2.2. Set this's URL's query to the empty string. 2.3. Basic URL parse input with this's URL as url and query state as state override.

#
Url::set_search_params

fn Url::set_search_params(self : Url, params : UrlSearchParams) -> Unit

Set the URL query from UrlSearchParams. This serializes the search params and updates the URL's query.

#
Url::set_username

fn Url::set_username(self : Url, username : String) -> Unit

Set the username. See: https://url.spec.whatwg.org/#dom-url-username The username setter steps are:
  1. If this's URL cannot have a username/password/port, then return.
  2. Set the username given this's URL and the given value.

#
Url::to_string

fn Url::to_string(self : Url) -> String

Serialize URL to string per WHATWG URL spec. See: https://url.spec.whatwg.org/#url-serializing

#
Url::try_parse

#as_free_fn
fn Url::try_parse(input : StringView, base? : Url, validation_errors? : Array[ValidationError]) -> Url?

Parse a URL string, optionally with a base URL for relative resolution

#
Url::username

fn Url::username(self : Url) -> String

Get the username

#
UrlSearchParams

pub struct UrlSearchParams {
list : Array[(String, String)]
}

Represents URL search parameters per the WHATWG URL Standard. See: https://url.spec.whatwg.org/#interface-urlsearchparams Provides methods to work with the query string of a URL using application/x-www-form-urlencoded format.

#
UrlSearchParams::append

fn UrlSearchParams::append(self : UrlSearchParams, name : String, value : String) -> Unit

Append a new name-value pair. See: https://url.spec.whatwg.org/#dom-urlsearchparams-append

#
UrlSearchParams::delete

fn UrlSearchParams::delete(self : UrlSearchParams, name : String, value? : String) -> Unit

Delete all pairs with the given name. If value is provided, only delete pairs where both name and value match. See: https://url.spec.whatwg.org/#dom-urlsearchparams-delete

#
UrlSearchParams::entries

fn UrlSearchParams::entries(self : UrlSearchParams) -> Iter[(String, String)]

Iterate over all (name, value) pairs (alias for iter). See: https://url.spec.whatwg.org/#dom-urlsearchparams-entries

#
UrlSearchParams::from_pairs

fn UrlSearchParams::from_pairs(pairs : Array[(String, String)]) -> UrlSearchParams

Create UrlSearchParams from an array of (name, value) pairs.

#
UrlSearchParams::from_string

fn UrlSearchParams::from_string(input : String) -> UrlSearchParams

Parse a query string into UrlSearchParams. Strips a leading "?" if present. See: https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams

#
UrlSearchParams::get

fn UrlSearchParams::get(self : UrlSearchParams, name : String) -> String?

Get the first value for the given name, or None if not found. See: https://url.spec.whatwg.org/#dom-urlsearchparams-get

#
UrlSearchParams::get_all

fn UrlSearchParams::get_all(self : UrlSearchParams, name : String) -> Array[String]

Get all values for the given name. See: https://url.spec.whatwg.org/#dom-urlsearchparams-getall

#
UrlSearchParams::has

fn UrlSearchParams::has(self : UrlSearchParams, name : String, value? : String) -> Bool

Check if a name exists in the search params. If value is provided, check if a pair with both name and value exists. See: https://url.spec.whatwg.org/#dom-urlsearchparams-has

#
UrlSearchParams::iter

fn UrlSearchParams::iter(self : UrlSearchParams) -> Iter[(String, String)]

Iterate over all (name, value) pairs. See: https://url.spec.whatwg.org/#urlsearchparams-iteration

#
UrlSearchParams::keys

fn UrlSearchParams::keys(self : UrlSearchParams) -> Iter[String]

Iterate over all names. See: https://url.spec.whatwg.org/#dom-urlsearchparams-keys

#
UrlSearchParams::new

Create a new empty UrlSearchParams instance.

#
UrlSearchParams::set

fn UrlSearchParams::set(self : UrlSearchParams, name : String, value : String) -> Unit

Set a value for the given name. If name already exists, replaces the first occurrence and removes any others. Otherwise, appends a new pair. See: https://url.spec.whatwg.org/#dom-urlsearchparams-set

#
UrlSearchParams::size

fn UrlSearchParams::size(self : UrlSearchParams) -> Int

Return the number of name-value pairs. See: https://url.spec.whatwg.org/#dom-urlsearchparams-size

#
UrlSearchParams::sort

fn UrlSearchParams::sort(self : UrlSearchParams) -> Unit

Sort all name-value pairs by name using stable sort. Uses UTF-16 code unit order per WHATWG URL Standard. See: https://url.spec.whatwg.org/#dom-urlsearchparams-sort

#
UrlSearchParams::to_string

fn UrlSearchParams::to_string(self : UrlSearchParams) -> String

Serialize UrlSearchParams to application/x-www-form-urlencoded string. See: https://url.spec.whatwg.org/#concept-urlencoded-serializer

#
UrlSearchParams::values

fn UrlSearchParams::values(self : UrlSearchParams) -> Iter[String]

Iterate over all values. See: https://url.spec.whatwg.org/#dom-urlsearchparams-values