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,
fragment,
reserve,
withCapacity,
withQuery,
withFragment,
]
@ -22,21 +21,51 @@ interface Url
## a relative address, such as `/authors`. You can create one using [Url.fromStr].
Url := Str
withCapacity : Nat -> Url
withCapacity = \cap ->
# TODO use Str.withCapacity once it exists
@Url (Str.reserve "" cap)
## Reserve the given number of bytes as extra capacity. This can avoid reallocation
## when calling multiple functions that increase the length of the URL.
##
## 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 str, cap ->
@Url (Str.reserve str cap)
## Create a [Url] without validating or [percent-encoding](https://en.wikipedia.org/wiki/Percent-encoding)
## 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 str
## 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 -> str
@ -44,27 +73,27 @@ toStr = \@Url str -> str
## [path component](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax)
## and appends to the end of the URL's path.
##
## "https://example.com"
## Url.fromStr "https://example.com"
## |> Url.append "some stuff"
## # https://example.com/some%20stuff
##
## 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"
## # https://example.com/stuff?search=blah#fragment
##
## If the given string begins with a "/" and the URL already ends with a "/", one of
## them will be ignored. This avoids turning a single slash into a double slash.
## If the given path string begins with `"/"` and the URL already ends with `"/"`, one
## 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 "/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 ""
## # https://example.com/things
append : Url, Str -> Url
@ -146,9 +175,9 @@ appendHelp = \prefix, suffix ->
## double-encode things. If you really want to percent-encode an arbitrary string,
## you can always do:
##
## Path.fromStr ""
## |> Path.append myStrToEncode
## |> Path.toStr
## Url.fromStr ""
## |> Url.append myStrToEncode
## |> Url.toStr
##
## 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 `+`):
@ -190,19 +219,19 @@ percentEncode = \input ->
Str.concat output suffix
## Adds a [Str] query parameter to the end of the [Url]. Both the key
## and the value are [percent-encoded](https://en.wikipedia.org/wiki/Percent-encoding).
## Adds a [Str] query parameter to the end of the [Url]. The key
## and value both get [percent-encoded](https://en.wikipedia.org/wiki/Percent-encoding).
##
## "https://example.com"
## |> Url.param "email" "someone@example.com"
## Url.fromStr "https://example.com"
## |> Url.appendParam "email" "someone@example.com"
## # https://example.com?email=someone%40example.com
##
## This can be called multiple times on the same URL.
##
## "https://example.com"
## |> Url.param "café" "du Soleil"
## |> Url.param "email" "someone@example.com"
## # https://example.com?caf%C3%A9=du%20Soleil&email=someone%40example.com
## Url.fromStr "https://example.com"
## |> Url.appendParam "café" "du Monde"
## |> Url.appendParam "email" "hi@example.com"
## # https://example.com?caf%C3%A9=du%20Monde&email=hi%40example.com
appendParam : Url, Str, Str -> Url
appendParam = \@Url urlStr, key, value ->
{ withoutFragment, afterQuery } =
@ -235,6 +264,18 @@ appendParam = \@Url urlStr, key, value ->
|> Str.concat afterQuery
|> @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 urlStr, queryStr ->
{ withoutFragment, afterQuery } =
@ -269,15 +310,17 @@ withQuery = \@Url urlStr, queryStr ->
|> @Url
## 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.query # "key1=val1&key2=val2&key3=val3"
## |> Url.query
## # "key1=val1&key2=val2&key3=val3"
##
## Returns `""` if the URL has no query.
##
## Url.fromStr "https://example.com#stuff"
## Url.query # ""
## |> Url.query
## # ""
query : Url -> Str
query = \@Url urlStr ->
withoutFragment =
@ -290,6 +333,14 @@ query = \@Url urlStr ->
Err NotFound -> ""
## 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 urlStr ->
# TODO use Str.contains once it exists. It should have a "fast path"
@ -298,32 +349,40 @@ hasQuery = \@Url urlStr ->
|> List.contains (Num.toU8 '?')
## 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.fragment # "stuff"
## |> Url.fragment
## # "stuff"
##
## Returns `""` if the URL has no fragment.
##
## Url.fromStr "https://example.com"
## |> Url.fragment
## # ""
fragment : Url -> Str
fragment = \@Url urlStr ->
when Str.splitLast urlStr "#" is
Ok { after } -> after
Err NotFound -> ""
## Replaces the URL's current [fragment](https://en.wikipedia.org/wiki/URL#Syntax)
## with the given one.
## Replaces the URL's [fragment](https://en.wikipedia.org/wiki/URL#Syntax).
##
## 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.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.withFragment "" # https://example.com
##
## |> Url.withFragment ""
## # https://example.com
withFragment : Url, Str -> Url
withFragment = \@Url urlStr, fragmentStr ->
when Str.splitLast urlStr "#" is
@ -344,6 +403,14 @@ withFragment = \@Url urlStr, fragmentStr ->
@Url "\(urlStr)#\(fragmentStr)"
## 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 urlStr ->
# TODO use Str.contains once it exists. It should have a "fast path"