Last active
October 26, 2023 21:28
-
-
Save AngelMunoz/c36746141c2801b742f7f30eefa484a0 to your computer and use it in GitHub Desktop.
Parse the segments + query + hash from a url with fparsec
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Routerish | |
type QueryValue = | |
| String of string option | |
| StringValues of string list | |
type RoutePart = | |
| Segment of segment: string | |
| ParamSegment of paramname: string | |
| Query of query: Map<string, QueryValue> | |
| Hash of hash: string | |
module UrlParser = | |
open FParsec | |
let segmentSeparator: Parser<char, unit> = pchar '/' | |
let paramStart: Parser<char, unit> = pchar ':' | |
let queryStart: Parser<char, unit> = pchar '?' | |
let queryDelimiter: Parser<char, unit> = pchar '&' | |
let hashStart: Parser<char, unit> = pchar '#' | |
let segment = | |
sepEndBy (manyChars (noneOf [ '/'; '#'; '?' ])) segmentSeparator | |
>>= (fun value -> | |
value | |
|> List.map (fun s -> | |
if s.StartsWith(':') then | |
ParamSegment(s.TrimStart(':')) | |
else | |
Segment(s)) | |
|> preturn) | |
let hash = manyChars anyChar >>= (fun content -> Hash(content) |> preturn) | |
let query = | |
let queryKv = | |
let separator = pchar '=' | |
let key = manyChars (noneOf [ '='; '&'; '#' ]) | |
let value = manyChars (noneOf [ '='; '&'; '#' ]) | |
key .>> opt separator .>>. opt value | |
let addOrUpdate (nextValue: string option) existing = | |
match existing with | |
| Some(String a) -> Some(StringValues [ nextValue |> Option.defaultValue ""; a |> Option.defaultValue "" ]) | |
| Some(StringValues values) -> Some(StringValues((nextValue |> Option.defaultValue "") :: values)) | |
| None -> Some(String nextValue) | |
let tupleListToMap current (nextKey: string, nextValue: string option) = | |
Map.change nextKey (addOrUpdate nextValue) current | |
sepEndBy queryKv queryDelimiter | |
>>= (fun values -> values |> List.fold tupleListToMap Map.empty |> Query |> preturn) | |
let urlParser = | |
segment .>>. opt (queryStart >>. query) .>>. opt (hashStart >>. hash) .>> eof |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment