Skip to content

Commit

Permalink
Address review feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-snezhko committed Mar 2, 2024
1 parent e731f87 commit aa9ef0c
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 60 deletions.
40 changes: 20 additions & 20 deletions compiler/test/stdlib/uri.test.gr
Expand Up @@ -281,23 +281,23 @@ testResolve("a://a.com?a#a", "", "a://a.com?a")

// make

assert Uri.make(scheme=Some("+"), percentEncodeComponents=false) ==
assert Uri.make(scheme=Some("+"), encodeComponents=false) ==
Err(Uri.InvalidSchemeError)
assert Uri.make(
userinfo=Some("%"),
host=Some("a"),
percentEncodeComponents=false
encodeComponents=false
) ==
Err(Uri.InvalidUserinfoError)
assert Uri.make(host=Some("#"), percentEncodeComponents=false) ==
assert Uri.make(host=Some("#"), encodeComponents=false) ==
Err(Uri.InvalidHostError)
assert Uri.make(port=Some(-1), host=Some("a"), percentEncodeComponents=false) ==
assert Uri.make(port=Some(-1), host=Some("a"), encodeComponents=false) ==
Err(Uri.InvalidPortError)
assert Uri.make(path="%2", percentEncodeComponents=false) ==
assert Uri.make(path="%2", encodeComponents=false) ==
Err(Uri.InvalidPathError)
assert Uri.make(query=Some("#"), percentEncodeComponents=false) ==
assert Uri.make(query=Some("#"), encodeComponents=false) ==
Err(Uri.InvalidQueryError)
assert Uri.make(fragment=Some("%"), percentEncodeComponents=false) ==
assert Uri.make(fragment=Some("%"), encodeComponents=false) ==
Err(Uri.InvalidFragmentError)
assert Uri.make(userinfo=Some("me")) == Err(Uri.UserinfoWithNoHost)
assert Uri.make(port=Some(80)) == Err(Uri.PortWithNoHost)
Expand All @@ -324,7 +324,7 @@ assert Result.map(
path="/%20d:o'c#s!",
query=Some("/a?b#c=d:ef"),
fragment=Some("Ur#i-m/ake"),
percentEncodeComponents=true
encodeComponents=true
)
) ==
Ok(
Expand All @@ -335,37 +335,37 @@ assert Result.map(
Uri.make(
scheme=Some("http"),
host=Some("[1::1]"),
percentEncodeComponents=true
encodeComponents=true
)
) ==
Ok("http://[1::1]")

// update

let orig = Result.unwrap(Uri.make())
assert Uri.update(orig, scheme=Some(Some("+")), percentEncodeComponents=false) ==
assert Uri.update(orig, scheme=Some(Some("+")), encodeComponents=false) ==
Err(Uri.InvalidSchemeError)
assert Uri.update(
orig,
userinfo=Some(Some("%")),
host=Some(Some("a")),
percentEncodeComponents=false
encodeComponents=false
) ==
Err(Uri.InvalidUserinfoError)
assert Uri.update(orig, host=Some(Some("#")), percentEncodeComponents=false) ==
assert Uri.update(orig, host=Some(Some("#")), encodeComponents=false) ==
Err(Uri.InvalidHostError)
assert Uri.update(
orig,
port=Some(Some(1.1)),
host=Some(Some("a")),
percentEncodeComponents=false
encodeComponents=false
) ==
Err(Uri.InvalidPortError)
assert Uri.update(orig, path=Some("%2"), percentEncodeComponents=false) ==
assert Uri.update(orig, path=Some("%2"), encodeComponents=false) ==
Err(Uri.InvalidPathError)
assert Uri.update(orig, query=Some(Some("#")), percentEncodeComponents=false) ==
assert Uri.update(orig, query=Some(Some("#")), encodeComponents=false) ==
Err(Uri.InvalidQueryError)
assert Uri.update(orig, fragment=Some(Some("%")), percentEncodeComponents=false) ==
assert Uri.update(orig, fragment=Some(Some("%")), encodeComponents=false) ==
Err(Uri.InvalidFragmentError)
assert Uri.update(orig, port=Some(Some(80))) == Err(Uri.PortWithNoHost)

Expand Down Expand Up @@ -398,15 +398,15 @@ assert Result.map(
path=Some("/%20d:o'c#s!"),
query=Some(Some("/a?b#c=d:ef")),
fragment=Some(Some("Ur#i-m/ake")),
percentEncodeComponents=true
encodeComponents=true
)
) ==
Ok(
"ht+1-tp://me%40pw@g+r%2Fa*in%3A80:80/%2520d:o'c%23s!?/a?b%23c=d:ef#Ur%23i-m/ake",
)
assert Result.map(
Uri.toString,
Uri.update(orig, host=Some(Some("[1::1]")), percentEncodeComponents=true)
Uri.update(orig, host=Some(Some("[1::1]")), encodeComponents=true)
) ==
Ok("https://me:pw@[1::1]:80/docs?k=v#frag")

Expand All @@ -420,7 +420,7 @@ let decoded = "馃尵"
assert Uri.decode(encoded) == Ok(decoded)
assert Uri.encode(decoded) == encoded

assert Uri.decode("%2") == Err(Uri.InvalidPercentEncoding)
assert Uri.decode("%2") == Err(Uri.InvalidEncoding)

// encodeQuery/decodeQuery

Expand All @@ -429,4 +429,4 @@ let decoded = [("val", "馃尵"), ("val馃П2", "x=y&a=b")]
assert Uri.encodeQuery(decoded) == encoded
assert Uri.decodeQuery(encoded) == Ok(decoded)

assert Uri.decodeQuery("%2") == Err(Uri.InvalidPercentEncoding)
assert Uri.decodeQuery("%2") == Err(Uri.InvalidEncoding)
80 changes: 40 additions & 40 deletions stdlib/uri.gr
Expand Up @@ -7,17 +7,16 @@
*/
module Uri

from "string" include String
from "char" include Char
from "uint8" include Uint8
from "number" include Number
from "bytes" include Bytes
from "array" include Array
from "buffer" include Buffer
from "bytes" include Bytes
from "char" include Char
from "list" include List
from "array" include Array
from "map" include Map
from "number" include Number
from "option" include Option
from "result" include Result
from "string" include String
from "uint8" include Uint8

/**
* Represents a parsed RFC 3986 URI.
Expand Down Expand Up @@ -64,14 +63,14 @@ provide enum ResolveReferenceError {
/**
* Represents an error encountered while attempting to percent-decode a string.
*/
provide enum PercentDecodingError {
InvalidPercentEncoding,
provide enum DecodingError {
InvalidEncoding,
}

/**
* Used to specify which characters to percent-encode from a string.
*/
provide enum PercentEncodeSet {
provide enum EncodeSet {
EncodeNonUnreserved,
EncodeUserinfo,
EncodeRegisteredHost,
Expand Down Expand Up @@ -108,7 +107,7 @@ let isPchar = char => {
isUnreservedChar(char) || isSubDelim(char) || char == ':' || char == '@'
}

let makePercentEncoder = (encodeSet: PercentEncodeSet) => {
let makeEncoder = (encodeSet: EncodeSet) => {
let shouldEncodeForNonUnreserved = char => !isUnreservedChar(char)

let shouldEncodeForUserinfo = char => {
Expand Down Expand Up @@ -159,18 +158,18 @@ let hexValueToChar = val => {
}
}

let percentDecodeValid = (str, onlyUnreserved=false) => {
let decodeValid = (str, onlyUnreserved=false) => {
let bytes = String.encode(str, String.UTF8)
let len = Bytes.length(bytes)
let out = Buffer.make(len)
let cAt = i => Char.fromCode(Uint8.toNumber(Bytes.getUint8(i, bytes)))
let charAt = i => Char.fromCode(Uint8.toNumber(Bytes.getUint8(i, bytes)))
for (let mut i = 0; i < len; i += 1) {
if (i >= len - 2 || cAt(i) != '%') {
if (i >= len - 2 || charAt(i) != '%') {
let byte = Bytes.getUint8(i, bytes)
Buffer.addUint8(byte, out)
} else {
let next = cAt(i + 1)
let nextNext = cAt(i + 2)
let next = charAt(i + 1)
let nextNext = charAt(i + 2)
let pctDecodedVal = charToHexValue(next) * 16 + charToHexValue(nextNext)
if (onlyUnreserved && !isUnreservedChar(Char.fromCode(pctDecodedVal))) {
Buffer.addChar('%', out)
Expand All @@ -185,7 +184,7 @@ let percentDecodeValid = (str, onlyUnreserved=false) => {
Buffer.toString(out)
}

let isValidPercentEncoding = str => {
let isValidEncoding = str => {
let chars = String.explode(str)
let len = Array.length(chars)
for (let mut i = 0; i < len; i += 1) {
Expand All @@ -201,7 +200,7 @@ let isValidPercentEncoding = str => {

// Lowercase all non-percent-encoded alphabetical characters
let normalizeHost = str => {
let str = percentDecodeValid(str, onlyUnreserved=true)
let str = decodeValid(str, onlyUnreserved=true)

let chars = String.explode(str)
let rec getChars = (i, acc) => {
Expand Down Expand Up @@ -259,7 +258,7 @@ let removeDotSegments = path => {
}

/**
* Percent-encodes characters in a string based on the specified `PercentEncodeSet`.
* Percent-encodes characters in a string based on the specified `EncodeSet`.
*
* @param str: The string to encode
* @param encodeSet: An indication for which characters to percent-encode. `EncodeNonUnreserved` by default
Expand All @@ -272,7 +271,8 @@ let removeDotSegments = path => {
* @since v0.6.0
*/
provide let encode = (str, encodeSet=EncodeNonUnreserved) => {
let shouldEncode = makePercentEncoder(encodeSet)
let shouldEncode = makeEncoder(encodeSet)
// TODO(#2053): use String.map when implemented
let chars = String.explode(str)
let rec getChars = (i, acc) => {
if (i < 0) {
Expand Down Expand Up @@ -308,10 +308,10 @@ provide let encode = (str, encodeSet=EncodeNonUnreserved) => {
* @since v0.6.0
*/
provide let decode = str => {
if (!isValidPercentEncoding(str)) {
Err(InvalidPercentEncoding)
if (isValidEncoding(str)) {
Ok(decodeValid(str))
} else {
Ok(percentDecodeValid(str))
Err(InvalidEncoding)
}
}

Expand Down Expand Up @@ -342,9 +342,7 @@ provide let encodeQuery = (urlVals, encodeSet=EncodeNonUnreserved) => {
* @since v0.6.0
*/
provide let decodeQuery = str => {
if (!isValidPercentEncoding(str)) {
Err(InvalidPercentEncoding)
} else {
if (isValidEncoding(str)) {
let parts = Array.toList(String.split("&", str))
Ok(List.map(part => {
match (String.indexOf("=", part)) {
Expand All @@ -353,10 +351,12 @@ provide let decodeQuery = str => {
Some(i) => {
let name = String.slice(0, end=i, part)
let val = String.slice(i + 1, part)
(percentDecodeValid(name), percentDecodeValid(val))
(decodeValid(name), decodeValid(val))
},
}
}, parts))
} else {
Err(InvalidEncoding)
}
}

Expand Down Expand Up @@ -625,14 +625,14 @@ let parsePath = (i, str, isAbsolute, hasAuthority) => {
if (hasAuthority) {
let endI = Option.unwrap(pathAbempty(i, str))
let path = processPath(
percentDecodeValid(String.slice(i, end=endI, str), onlyUnreserved=true)
decodeValid(String.slice(i, end=endI, str), onlyUnreserved=true)
)
(endI, path)
} else {
let extraOption = if (isAbsolute) pathRootless else pathNoScheme
let endI = Option.unwrap(any([pathAbsolute, extraOption, empty])(i, str))
let path = processPath(
percentDecodeValid(String.slice(i, end=endI, str), onlyUnreserved=true)
decodeValid(String.slice(i, end=endI, str), onlyUnreserved=true)
)
(endI, path)
}
Expand Down Expand Up @@ -665,7 +665,7 @@ let parseQuery = (i, str, withDelim=false) => {
(
endI,
Some(
percentDecodeValid(
decodeValid(
String.slice(i + (if (withDelim) 1 else 0), end=endI, str),
onlyUnreserved=true
),
Expand All @@ -682,7 +682,7 @@ let parseFragment = (i, str, withDelim=false) => {
(
endI,
Some(
percentDecodeValid(
decodeValid(
String.slice(i + (if (withDelim) 1 else 0), end=endI, str),
onlyUnreserved=true
),
Expand Down Expand Up @@ -784,11 +784,11 @@ provide let resolveReference = (base, ref) => {
* @param path: The desired path for the URI. `""` by default
* @param query: `Some(query)` containing the desired query string component or `None` for a query-less URI
* @param fragment: `Some(fragment)` containing the desired fragment component or `None` for a fragment-less URI
* @param percentEncodeComponents: Whether or not to apply percent encoding for each component to remove unsafe characters for each component
* @param encodeComponents: Whether or not to apply percent encoding for each component to remove unsafe characters for each component
*
* @example Uri.make(scheme=Some("https"), host=Some("grain-lang.org")) // https://grain-lang.org
* @example Uri.make(host=Some("g/r@in"), percentEncodeComponents=false) // Err(Uri.InvalidHostError)
* @example Uri.make(scheme=Some("abc"), host=Some("g/r@in"), query=Some("k/ey=v^@l"), percentEncodeComponents=true) // abc://g%2Fr%40in?k/ey=v%5E@l
* @example Uri.make(host=Some("g/r@in"), encodeComponents=false) // Err(Uri.InvalidHostError)
* @example Uri.make(scheme=Some("abc"), host=Some("g/r@in"), query=Some("k/ey=v^@l"), encodeComponents=true) // abc://g%2Fr%40in?k/ey=v%5E@l
* @example Uri.make(port=Some(80)) // Err(Uri.PortWithNoHost)
*
* @since v0.6.0
Expand All @@ -801,7 +801,7 @@ provide let make = (
path="",
query=None,
fragment=None,
percentEncodeComponents=false,
encodeComponents=false,
) => {
match ((host, userinfo, port)) {
(None, Some(_), None) => return Err(UserinfoWithNoHost),
Expand Down Expand Up @@ -833,7 +833,7 @@ provide let make = (
}
}

let (userinfo, host, path, query, fragment) = if (percentEncodeComponents) {
let (userinfo, host, path, query, fragment) = if (encodeComponents) {
let encodeOption = (val, encodeSet) =>
Option.map(val => encode(val, encodeSet=encodeSet), val)

Expand Down Expand Up @@ -915,12 +915,12 @@ enum UpdateAction<a> {
* @param path: `Some(path)` containing the desired updated path component or `None` to maintain the base URI's path
* @param query: `Some(query)` containing the desired updated query string component or `None` to maintain the base URI's query
* @param fragment: `Some(fragment)` containing the desired updated fragment component or `None` to maintain the base URI's fragment
* @param percentEncodeComponents: Whether or not to apply percent encoding for each updated component to remove unsafe characters
* @param encodeComponents: Whether or not to apply percent encoding for each updated component to remove unsafe characters
*
* @example let uri = Result.unwrap(Uri.parse("https://grain-lang.org/docs?k=v")) // Base URI for following examples
* @example Uri.update(uri, scheme=Some(Some("ftp"))) // ftp://grain-lang.org/docs?k=v
* @example Uri.update(uri, query=Some(None)) // https://grain-lang.org/docs
* @example Uri.update(uri, host=Some(Some("g/r@in")), percentEncodeComponents=true) // https://g%2Fr%40in/docs?k=v
* @example Uri.update(uri, host=Some(Some("g/r@in")), encodeComponents=true) // https://g%2Fr%40in/docs?k=v
* @example Uri.update(uri, host=Some(None), port=Some(Some(80))) // Err(Uri.PortWithNoHost)
*
* @since v0.6.0
Expand All @@ -934,7 +934,7 @@ provide let update = (
path=None,
query=None,
fragment=None,
percentEncodeComponents=false,
encodeComponents=false,
) => {
let (??) = (new, old) => Option.unwrapWithDefault(old, new)
match ((host ?? uri.host, userinfo ?? uri.userinfo, port ?? uri.port)) {
Expand Down Expand Up @@ -972,7 +972,7 @@ provide let update = (
}
}

let (userinfo, host, path, query, fragment) = if (percentEncodeComponents) {
let (userinfo, host, path, query, fragment) = if (encodeComponents) {
let encodeOption = (val, encodeSet) => match (val) {
Some(Some(val)) => Some(Some(encode(val, encodeSet=encodeSet))),
val => val,
Expand Down

0 comments on commit aa9ef0c

Please sign in to comment.