7
7
*/
8
8
module Uri
9
9
10
- from "string" include String
11
- from "char" include Char
12
- from "uint8" include Uint8
13
- from "number" include Number
14
- from "bytes" include Bytes
10
+ from "array" include Array
15
11
from "buffer" include Buffer
12
+ from "bytes" include Bytes
13
+ from "char" include Char
16
14
from "list" include List
17
- from "array" include Array
18
- from "map" include Map
15
+ from "number" include Number
19
16
from "option" include Option
20
17
from "result" include Result
18
+ from "string" include String
19
+ from "uint8" include Uint8
21
20
22
21
/**
23
22
* Represents a parsed RFC 3986 URI.
@@ -64,14 +63,14 @@ provide enum ResolveReferenceError {
64
63
/**
65
64
* Represents an error encountered while attempting to percent-decode a string.
66
65
*/
67
- provide enum PercentDecodingError {
68
- InvalidPercentEncoding ,
66
+ provide enum DecodingError {
67
+ InvalidEncoding ,
69
68
}
70
69
71
70
/**
72
71
* Used to specify which characters to percent-encode from a string.
73
72
*/
74
- provide enum PercentEncodeSet {
73
+ provide enum EncodeSet {
75
74
EncodeNonUnreserved,
76
75
EncodeUserinfo,
77
76
EncodeRegisteredHost,
@@ -108,7 +107,7 @@ let isPchar = char => {
108
107
isUnreservedChar(char) || isSubDelim(char) || char == ':' || char == '@'
109
108
}
110
109
111
- let makePercentEncoder = (encodeSet: PercentEncodeSet ) => {
110
+ let makeEncoder = (encodeSet: EncodeSet ) => {
112
111
let shouldEncodeForNonUnreserved = char => !isUnreservedChar(char)
113
112
114
113
let shouldEncodeForUserinfo = char => {
@@ -159,18 +158,18 @@ let hexValueToChar = val => {
159
158
}
160
159
}
161
160
162
- let percentDecodeValid = (str, onlyUnreserved=false) => {
161
+ let decodeValid = (str, onlyUnreserved=false) => {
163
162
let bytes = String.encode(str, String.UTF8)
164
163
let len = Bytes.length(bytes)
165
164
let out = Buffer.make(len)
166
- let cAt = i => Char.fromCode(Uint8.toNumber(Bytes.getUint8(i, bytes)))
165
+ let charAt = i => Char.fromCode(Uint8.toNumber(Bytes.getUint8(i, bytes)))
167
166
for (let mut i = 0; i < len; i += 1) {
168
- if (i >= len - 2 || cAt (i) != '%') {
167
+ if (i >= len - 2 || charAt (i) != '%') {
169
168
let byte = Bytes.getUint8(i, bytes)
170
169
Buffer.addUint8(byte, out)
171
170
} else {
172
- let next = cAt (i + 1)
173
- let nextNext = cAt (i + 2)
171
+ let next = charAt (i + 1)
172
+ let nextNext = charAt (i + 2)
174
173
let pctDecodedVal = charToHexValue(next) * 16 + charToHexValue(nextNext)
175
174
if (onlyUnreserved && !isUnreservedChar(Char.fromCode(pctDecodedVal))) {
176
175
Buffer.addChar('%', out)
@@ -185,7 +184,7 @@ let percentDecodeValid = (str, onlyUnreserved=false) => {
185
184
Buffer.toString(out)
186
185
}
187
186
188
- let isValidPercentEncoding = str => {
187
+ let isValidEncoding = str => {
189
188
let chars = String.explode(str)
190
189
let len = Array.length(chars)
191
190
for (let mut i = 0; i < len; i += 1) {
@@ -201,7 +200,7 @@ let isValidPercentEncoding = str => {
201
200
202
201
// Lowercase all non-percent-encoded alphabetical characters
203
202
let normalizeHost = str => {
204
- let str = percentDecodeValid (str, onlyUnreserved=true)
203
+ let str = decodeValid (str, onlyUnreserved=true)
205
204
206
205
let chars = String.explode(str)
207
206
let rec getChars = (i, acc) => {
@@ -259,7 +258,7 @@ let removeDotSegments = path => {
259
258
}
260
259
261
260
/**
262
- * Percent-encodes characters in a string based on the specified `PercentEncodeSet `.
261
+ * Percent-encodes characters in a string based on the specified `EncodeSet `.
263
262
*
264
263
* @param str: The string to encode
265
264
* @param encodeSet: An indication for which characters to percent-encode. `EncodeNonUnreserved` by default
@@ -272,7 +271,8 @@ let removeDotSegments = path => {
272
271
* @since v0.6.0
273
272
*/
274
273
provide let encode = (str, encodeSet=EncodeNonUnreserved) => {
275
- let shouldEncode = makePercentEncoder(encodeSet)
274
+ let shouldEncode = makeEncoder(encodeSet)
275
+ // TODO(#2053): use String.map when implemented
276
276
let chars = String.explode(str)
277
277
let rec getChars = (i, acc) => {
278
278
if (i < 0) {
@@ -308,10 +308,10 @@ provide let encode = (str, encodeSet=EncodeNonUnreserved) => {
308
308
* @since v0.6.0
309
309
*/
310
310
provide let decode = str => {
311
- if (!isValidPercentEncoding (str)) {
312
- Err(InvalidPercentEncoding )
311
+ if (isValidEncoding (str)) {
312
+ Ok(decodeValid(str) )
313
313
} else {
314
- Ok(percentDecodeValid(str) )
314
+ Err(InvalidEncoding )
315
315
}
316
316
}
317
317
@@ -342,9 +342,7 @@ provide let encodeQuery = (urlVals, encodeSet=EncodeNonUnreserved) => {
342
342
* @since v0.6.0
343
343
*/
344
344
provide let decodeQuery = str => {
345
- if (!isValidPercentEncoding(str)) {
346
- Err(InvalidPercentEncoding)
347
- } else {
345
+ if (isValidEncoding(str)) {
348
346
let parts = Array.toList(String.split("&", str))
349
347
Ok(List.map(part => {
350
348
match (String.indexOf("=", part)) {
@@ -353,10 +351,12 @@ provide let decodeQuery = str => {
353
351
Some(i) => {
354
352
let name = String.slice(0, end=i, part)
355
353
let val = String.slice(i + 1, part)
356
- (percentDecodeValid (name), percentDecodeValid (val))
354
+ (decodeValid (name), decodeValid (val))
357
355
},
358
356
}
359
357
}, parts))
358
+ } else {
359
+ Err(InvalidEncoding)
360
360
}
361
361
}
362
362
@@ -625,14 +625,14 @@ let parsePath = (i, str, isAbsolute, hasAuthority) => {
625
625
if (hasAuthority) {
626
626
let endI = Option.unwrap(pathAbempty(i, str))
627
627
let path = processPath(
628
- percentDecodeValid (String.slice(i, end=endI, str), onlyUnreserved=true)
628
+ decodeValid (String.slice(i, end=endI, str), onlyUnreserved=true)
629
629
)
630
630
(endI, path)
631
631
} else {
632
632
let extraOption = if (isAbsolute) pathRootless else pathNoScheme
633
633
let endI = Option.unwrap(any([pathAbsolute, extraOption, empty])(i, str))
634
634
let path = processPath(
635
- percentDecodeValid (String.slice(i, end=endI, str), onlyUnreserved=true)
635
+ decodeValid (String.slice(i, end=endI, str), onlyUnreserved=true)
636
636
)
637
637
(endI, path)
638
638
}
@@ -665,7 +665,7 @@ let parseQuery = (i, str, withDelim=false) => {
665
665
(
666
666
endI,
667
667
Some(
668
- percentDecodeValid (
668
+ decodeValid (
669
669
String.slice(i + (if (withDelim) 1 else 0), end=endI, str),
670
670
onlyUnreserved=true
671
671
),
@@ -682,7 +682,7 @@ let parseFragment = (i, str, withDelim=false) => {
682
682
(
683
683
endI,
684
684
Some(
685
- percentDecodeValid (
685
+ decodeValid (
686
686
String.slice(i + (if (withDelim) 1 else 0), end=endI, str),
687
687
onlyUnreserved=true
688
688
),
@@ -784,11 +784,11 @@ provide let resolveReference = (base, ref) => {
784
784
* @param path: The desired path for the URI. `""` by default
785
785
* @param query: `Some(query)` containing the desired query string component or `None` for a query-less URI
786
786
* @param fragment: `Some(fragment)` containing the desired fragment component or `None` for a fragment-less URI
787
- * @param percentEncodeComponents : Whether or not to apply percent encoding for each component to remove unsafe characters for each component
787
+ * @param encodeComponents : Whether or not to apply percent encoding for each component to remove unsafe characters for each component
788
788
*
789
789
* @example Uri.make(scheme=Some("https"), host=Some("grain-lang.org")) // https://grain-lang.org
790
- * @example Uri.make(host=Some("g/r@in"), percentEncodeComponents =false) // Err(Uri.InvalidHostError)
791
- * @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
790
+ * @example Uri.make(host=Some("g/r@in"), encodeComponents =false) // Err(Uri.InvalidHostError)
791
+ * @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
792
792
* @example Uri.make(port=Some(80)) // Err(Uri.PortWithNoHost)
793
793
*
794
794
* @since v0.6.0
@@ -801,7 +801,7 @@ provide let make = (
801
801
path="",
802
802
query=None,
803
803
fragment=None,
804
- percentEncodeComponents =false,
804
+ encodeComponents =false,
805
805
) => {
806
806
match ((host, userinfo, port)) {
807
807
(None, Some(_), None) => return Err(UserinfoWithNoHost),
@@ -833,7 +833,7 @@ provide let make = (
833
833
}
834
834
}
835
835
836
- let (userinfo, host, path, query, fragment) = if (percentEncodeComponents ) {
836
+ let (userinfo, host, path, query, fragment) = if (encodeComponents ) {
837
837
let encodeOption = (val, encodeSet) =>
838
838
Option.map(val => encode(val, encodeSet=encodeSet), val)
839
839
@@ -915,12 +915,12 @@ enum UpdateAction<a> {
915
915
* @param path: `Some(path)` containing the desired updated path component or `None` to maintain the base URI's path
916
916
* @param query: `Some(query)` containing the desired updated query string component or `None` to maintain the base URI's query
917
917
* @param fragment: `Some(fragment)` containing the desired updated fragment component or `None` to maintain the base URI's fragment
918
- * @param percentEncodeComponents : Whether or not to apply percent encoding for each updated component to remove unsafe characters
918
+ * @param encodeComponents : Whether or not to apply percent encoding for each updated component to remove unsafe characters
919
919
*
920
920
* @example let uri = Result.unwrap(Uri.parse("https://grain-lang.org/docs?k=v")) // Base URI for following examples
921
921
* @example Uri.update(uri, scheme=Some(Some("ftp"))) // ftp://grain-lang.org/docs?k=v
922
922
* @example Uri.update(uri, query=Some(None)) // https://grain-lang.org/docs
923
- * @example Uri.update(uri, host=Some(Some("g/r@in")), percentEncodeComponents =true) // https://g%2Fr%40in/docs?k=v
923
+ * @example Uri.update(uri, host=Some(Some("g/r@in")), encodeComponents =true) // https://g%2Fr%40in/docs?k=v
924
924
* @example Uri.update(uri, host=Some(None), port=Some(Some(80))) // Err(Uri.PortWithNoHost)
925
925
*
926
926
* @since v0.6.0
@@ -934,7 +934,7 @@ provide let update = (
934
934
path=None,
935
935
query=None,
936
936
fragment=None,
937
- percentEncodeComponents =false,
937
+ encodeComponents =false,
938
938
) => {
939
939
let (??) = (new, old) => Option.unwrapWithDefault(old, new)
940
940
match ((host ?? uri.host, userinfo ?? uri.userinfo, port ?? uri.port)) {
@@ -972,7 +972,7 @@ provide let update = (
972
972
}
973
973
}
974
974
975
- let (userinfo, host, path, query, fragment) = if (percentEncodeComponents ) {
975
+ let (userinfo, host, path, query, fragment) = if (encodeComponents ) {
976
976
let encodeOption = (val, encodeSet) => match (val) {
977
977
Some(Some(val)) => Some(Some(encode(val, encodeSet=encodeSet))),
978
978
val => val,
0 commit comments