Update a bunch of Url docs

This commit is contained in:
Richard Feldman 2022-07-06 22:49:13 -04:00
parent 5a566c721e
commit d6d33541b1
No known key found for this signature in database
GPG Key ID: 7E4127D1E4241798

View File

@ -10,7 +10,6 @@ interface Url
query, query,
fragment, fragment,
reserve, reserve,
withCapacity,
withQuery, withQuery,
withFragment, withFragment,
] ]
@ -22,21 +21,51 @@ interface Url
## a relative address, such as `/authors`. You can create one using [Url.fromStr]. ## a relative address, such as `/authors`. You can create one using [Url.fromStr].
Url := Str Url := Str
withCapacity : Nat -> Url ## Reserve the given number of bytes as extra capacity. This can avoid reallocation
withCapacity = \cap -> ## when calling multiple functions that increase the length of the URL.
# TODO use Str.withCapacity once it exists ##
@Url (Str.reserve "" cap) ## Url.fromStr "https://example.com"
## |> Url.reserve 50 # We're about to add 50 UTF-8 bytes to it
## |> Url.append "stuff"
## |> Url.appendParam "café" "du Monde"
## |> Url.appendParam "email" "hi@example.com"
## # https://example.com/stuff?caf%C3%A9=du%20Monde&email=hi%40example.com
##
## The [Str.countUtf8Bytes] function can be helpful in finding out how many bytes to reserve.
##
## There is no `Url.withCapacity` because it's better to reserve extra capacity
## on a [Str] first, and then pass that string to [Url.fromStr]. This function will make use
## of the extra capacity.
reserve : Url, Nat -> Url reserve : Url, Nat -> Url
reserve = \@Url str, cap -> reserve = \@Url str, cap ->
@Url (Str.reserve str cap) @Url (Str.reserve str cap)
## Create a [Url] without validating or [percent-encoding](https://en.wikipedia.org/wiki/Percent-encoding) ## Create a [Url] without validating or [percent-encoding](https://en.wikipedia.org/wiki/Percent-encoding)
## anything. ## anything.
##
## Url.fromStr "https://example.com#stuff"
## # https://example.com#stuff
##
## URLs can be absolute, like `https://example.com`, or they can be relative, like `/blah`.
##
## Url.fromStr "/this/is#relative"
## # /this/is#relative
##
## Since nothing is validated, this can return invalid URLs.
##
## Url.fromStr "https://this is not a valid URL, not at all!"
## # https://this is not a valid URL, not at all!
##
## Naturally, passing invalid URLs to functions that need valid ones will tend to result in errors.
fromStr : Str -> Url fromStr : Str -> Url
fromStr = \str -> @Url str fromStr = \str -> @Url str
## Return a [Str] representation of this URL. ## Return a [Str] representation of this URL.
##
## Url.fromStr "https://example.com"
## |> Url.append "two words"
## |> Url.toStr
## # "https://example.com/two%20words"
toStr : Url -> Str toStr : Url -> Str
toStr = \@Url str -> str toStr = \@Url str -> str
@ -44,27 +73,27 @@ toStr = \@Url str -> str
## [path component](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax) ## [path component](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax)
## and appends to the end of the URL's path. ## and appends to the end of the URL's path.
## ##
## "https://example.com" ## Url.fromStr "https://example.com"
## |> Url.append "some stuff" ## |> Url.append "some stuff"
## # https://example.com/some%20stuff ## # https://example.com/some%20stuff
## ##
## This will be appended before any queries and fragments. ## This will be appended before any queries and fragments.
## ##
## "https://example.com?search=blah#fragment" ## Url.fromStr "https://example.com?search=blah#fragment"
## |> Url.append "stuff" ## |> Url.append "stuff"
## # https://example.com/stuff?search=blah#fragment ## # https://example.com/stuff?search=blah#fragment
## ##
## If the given string begins with a "/" and the URL already ends with a "/", one of ## If the given path string begins with `"/"` and the URL already ends with `"/"`, one
## them will be ignored. This avoids turning a single slash into a double slash. ## will be ignored. This avoids turning a single slash into a double slash.
## ##
## "https://example.com/things/" ## Url.fromStr "https://example.com/things/"
## |> Url.append "/stuff/" ## |> Url.append "/stuff/"
## |> Url.append "/more/etc/" ## |> Url.append "/more/etc/"
## # https://example.com/things/stuff/more/etc/" ## # https://example.com/things/stuff/more/etc/"
## ##
## If either the given URL or the given string is empty, no "/" will be added. ## If either the given URL or the given string is empty, no `"/"` will be added.
## ##
## "https://example.com/things" ## Url.fromStr "https://example.com/things"
## |> Url.append "" ## |> Url.append ""
## # https://example.com/things ## # https://example.com/things
append : Url, Str -> Url append : Url, Str -> Url
@ -146,9 +175,9 @@ appendHelp = \prefix, suffix ->
## double-encode things. If you really want to percent-encode an arbitrary string, ## double-encode things. If you really want to percent-encode an arbitrary string,
## you can always do: ## you can always do:
## ##
## Path.fromStr "" ## Url.fromStr ""
## |> Path.append myStrToEncode ## |> Url.append myStrToEncode
## |> Path.toStr ## |> Url.toStr
## ##
## Note that it's not necessary to situationally encode spaces as `+` instead of `%20` - ## Note that it's not necessary to situationally encode spaces as `+` instead of `%20` -
## it's apparently always safe to use `%20` (but not always safe to use `+`): ## it's apparently always safe to use `%20` (but not always safe to use `+`):
@ -190,19 +219,19 @@ percentEncode = \input ->
Str.concat output suffix Str.concat output suffix
## Adds a [Str] query parameter to the end of the [Url]. Both the key ## Adds a [Str] query parameter to the end of the [Url]. The key
## and the value are [percent-encoded](https://en.wikipedia.org/wiki/Percent-encoding). ## and value both get [percent-encoded](https://en.wikipedia.org/wiki/Percent-encoding).
## ##
## "https://example.com" ## Url.fromStr "https://example.com"
## |> Url.param "email" "someone@example.com" ## |> Url.appendParam "email" "someone@example.com"
## # https://example.com?email=someone%40example.com ## # https://example.com?email=someone%40example.com
## ##
## This can be called multiple times on the same URL. ## This can be called multiple times on the same URL.
## ##
## "https://example.com" ## Url.fromStr "https://example.com"
## |> Url.param "café" "du Soleil" ## |> Url.appendParam "café" "du Monde"
## |> Url.param "email" "someone@example.com" ## |> Url.appendParam "email" "hi@example.com"
## # https://example.com?caf%C3%A9=du%20Soleil&email=someone%40example.com ## # https://example.com?caf%C3%A9=du%20Monde&email=hi%40example.com
appendParam : Url, Str, Str -> Url appendParam : Url, Str, Str -> Url
appendParam = \@Url urlStr, key, value -> appendParam = \@Url urlStr, key, value ->
{ withoutFragment, afterQuery } = { withoutFragment, afterQuery } =
@ -235,6 +264,18 @@ appendParam = \@Url urlStr, key, value ->
|> Str.concat afterQuery |> Str.concat afterQuery
|> @Url |> @Url
## Replaces the URL's [query](https://en.wikipedia.org/wiki/URL#Syntax)—the part after
## the `?`, if it has one, but before any `#` it might have.
##
## Url.fromStr "https://example.com?key1=val1&key2=val2#stuff"
## |> Url.withQuery "newQuery=thisRightHere"
## # https://example.com?newQuery=thisRightHere#stuff
##
## Passing `""` removes the `?` (if there was one).
##
## Url.fromStr "https://example.com?key1=val1&key2=val2#stuff"
## |> Url.withQuery ""
## # https://example.com#stuff
withQuery : Url, Str -> Url withQuery : Url, Str -> Url
withQuery = \@Url urlStr, queryStr -> withQuery = \@Url urlStr, queryStr ->
{ withoutFragment, afterQuery } = { withoutFragment, afterQuery } =
@ -269,15 +310,17 @@ withQuery = \@Url urlStr, queryStr ->
|> @Url |> @Url
## Returns the URL's [query](https://en.wikipedia.org/wiki/URL#Syntax)—the part after ## Returns the URL's [query](https://en.wikipedia.org/wiki/URL#Syntax)—the part after
## the `?`, if it has one, but before any `#`. ## the `?`, if it has one, but before any `#` it might have.
## ##
## Url.fromStr "https://example.com?key1=val1&key2=val2&key3=val3#stuff" ## Url.fromStr "https://example.com?key1=val1&key2=val2&key3=val3#stuff"
## Url.query # "key1=val1&key2=val2&key3=val3" ## |> Url.query
## # "key1=val1&key2=val2&key3=val3"
## ##
## Returns `""` if the URL has no query. ## Returns `""` if the URL has no query.
## ##
## Url.fromStr "https://example.com#stuff" ## Url.fromStr "https://example.com#stuff"
## Url.query # "" ## |> Url.query
## # ""
query : Url -> Str query : Url -> Str
query = \@Url urlStr -> query = \@Url urlStr ->
withoutFragment = withoutFragment =
@ -290,6 +333,14 @@ query = \@Url urlStr ->
Err NotFound -> "" Err NotFound -> ""
## Returns `True` if the URL has a `?` in it. ## Returns `True` if the URL has a `?` in it.
##
## Url.fromStr "https://example.com?key=value#stuff"
## |> Url.hasQuery
## # True
##
## Url.fromStr "https://example.com#stuff"
## |> Url.hasQuery
## # False
hasQuery : Url -> Bool hasQuery : Url -> Bool
hasQuery = \@Url urlStr -> hasQuery = \@Url urlStr ->
# TODO use Str.contains once it exists. It should have a "fast path" # TODO use Str.contains once it exists. It should have a "fast path"
@ -298,32 +349,40 @@ hasQuery = \@Url urlStr ->
|> List.contains (Num.toU8 '?') |> List.contains (Num.toU8 '?')
## Returns the URL's [fragment](https://en.wikipedia.org/wiki/URL#Syntax)—the part after ## Returns the URL's [fragment](https://en.wikipedia.org/wiki/URL#Syntax)—the part after
## the `#`, if it has one. Returns `""` if the URL has no fragment. ## the `#`, if it has one.
## ##
## Url.fromStr "https://example.com#stuff" ## Url.fromStr "https://example.com#stuff"
## Url.fragment # "stuff" ## |> Url.fragment
## # "stuff"
##
## Returns `""` if the URL has no fragment.
##
## Url.fromStr "https://example.com"
## |> Url.fragment
## # ""
fragment : Url -> Str fragment : Url -> Str
fragment = \@Url urlStr -> fragment = \@Url urlStr ->
when Str.splitLast urlStr "#" is when Str.splitLast urlStr "#" is
Ok { after } -> after Ok { after } -> after
Err NotFound -> "" Err NotFound -> ""
## Replaces the URL's current [fragment](https://en.wikipedia.org/wiki/URL#Syntax) ## Replaces the URL's [fragment](https://en.wikipedia.org/wiki/URL#Syntax).
## with the given one.
## ##
## Url.fromStr "https://example.com#stuff" ## Url.fromStr "https://example.com#stuff"
## |> Url.withFragment "things" # https://example.com#things ## |> Url.withFragment "things"
## # https://example.com#things
## ##
## If the URL didn't have a fragment, this adds one. ## If the URL didn't have a fragment, adds one.
## ##
## Url.fromStr "https://example.com" ## Url.fromStr "https://example.com"
## |> Url.withFragment "things" # https://example.com#things ## |> Url.withFragment "things"
## # https://example.com#things
## ##
## Passing a fragment of `#` means the returned URL will not have a fragment. ## Passing `""` removes the fragment.
## ##
## Url.fromStr "https://example.com#stuff" ## Url.fromStr "https://example.com#stuff"
## |> Url.withFragment "" # https://example.com ## |> Url.withFragment ""
## ## # https://example.com
withFragment : Url, Str -> Url withFragment : Url, Str -> Url
withFragment = \@Url urlStr, fragmentStr -> withFragment = \@Url urlStr, fragmentStr ->
when Str.splitLast urlStr "#" is when Str.splitLast urlStr "#" is
@ -344,6 +403,14 @@ withFragment = \@Url urlStr, fragmentStr ->
@Url "\(urlStr)#\(fragmentStr)" @Url "\(urlStr)#\(fragmentStr)"
## Returns `True` if the URL has a `#` in it. ## Returns `True` if the URL has a `#` in it.
##
## Url.fromStr "https://example.com?key=value#stuff"
## |> Url.hasFragment
## # True
##
## Url.fromStr "https://example.com?key=value"
## |> Url.hasFragment
## # False
hasFragment : Url -> Bool hasFragment : Url -> Bool
hasFragment = \@Url urlStr -> hasFragment = \@Url urlStr ->
# TODO use Str.contains once it exists. It should have a "fast path" # TODO use Str.contains once it exists. It should have a "fast path"