|
1 | | -module Routing.Parser ( |
2 | | - parse |
3 | | - ) where |
| 1 | +module Routing.Parser (parse) where |
4 | 2 |
|
5 | | -import Control.MonadPlus (guard) |
| 3 | +import Prelude |
| 4 | + |
| 5 | +import Routing.Types (Route, RoutePart(..)) |
6 | 6 | import Data.Array as A |
7 | | -import Data.Either (fromRight) |
8 | | -import Data.List (fromFoldable, List) |
9 | 7 | import Data.Map as M |
10 | | -import Data.Maybe (Maybe, fromMaybe) |
11 | 8 | import Data.String as S |
12 | | -import Data.String.Regex (Regex, regex, split) as R |
13 | | -import Data.String.Regex.Flags (noFlags) as R |
| 9 | +import Control.MonadPlus (guard) |
| 10 | +import Data.List as L |
| 11 | +import Data.Maybe (Maybe(..)) |
14 | 12 | import Data.Traversable (traverse) |
15 | 13 | import Data.Tuple (Tuple(..)) |
16 | | -import Partial.Unsafe (unsafePartial) |
17 | | -import Prelude (map, discard, (>>>), ($), (<<<), (==), (<*>), (<$>), (<=)) |
18 | | -import Routing.Types (Route, RoutePart(..)) |
19 | 14 |
|
20 | | --- | Parse part of hash. Will return `Query (Map String String)` for query |
| 15 | +-- | Parse query part of hash. Will return `Map String String` for query |
21 | 16 | -- | i.e. `"?foo=bar&bar=baz"` --> |
22 | | --- | `Query (fromList [Tuple "foo" "bar", Tuple "bar" "baz"])` |
23 | | -parsePart :: String -> RoutePart |
24 | | -parsePart str = fromMaybe (Path str) do |
25 | | - guard $ S.take 1 str == "?" |
26 | | - map (Query <<< M.fromFoldable) |
27 | | - $ traverse part2tuple parts |
| 17 | +-- | `fromList [Tuple "foo" "bar", Tuple "bar" "baz"]` |
| 18 | +parseQueryPart :: (String -> String) -> String -> Maybe (M.Map String String) |
| 19 | +parseQueryPart decoder = |
| 20 | + map M.fromFoldable <<< traverse part2tuple <<< S.split (S.Pattern "&") |
28 | 21 | where |
29 | | - parts :: List String |
30 | | - parts = fromFoldable $ S.split (S.Pattern "&") $ S.drop 1 str |
31 | | - |
32 | | - part2tuple :: String -> Maybe (Tuple String String) |
33 | | - part2tuple input = do |
34 | | - let keyVal = S.split (S.Pattern "=") input |
35 | | - guard $ A.length keyVal <= 2 |
36 | | - Tuple <$> (A.head keyVal) <*> (keyVal A.!! 1) |
37 | | - |
38 | | - |
39 | | -splitRegex :: R.Regex |
40 | | -splitRegex = unsafePartial fromRight $ R.regex "\\/|(?=\\?)" R.noFlags |
| 22 | + part2tuple :: String -> Maybe (Tuple String String) |
| 23 | + part2tuple input = do |
| 24 | + let keyVal = decoder <$> S.split (S.Pattern "=") input |
| 25 | + guard $ A.length keyVal <= 2 |
| 26 | + Tuple <$> A.head keyVal <*> keyVal A.!! 1 |
41 | 27 |
|
42 | 28 | -- | Parse hash string to `Route` with `decoder` function |
43 | 29 | -- | applied to every hash part (usually `decodeURIComponent`) |
44 | 30 | parse :: (String -> String) -> String -> Route |
45 | 31 | parse decoder hash = |
46 | | - map ( decoder >>> parsePart ) $ fromFoldable (R.split splitRegex hash) |
| 32 | + case flip S.splitAt hash =<< S.indexOf (S.Pattern "?") hash of |
| 33 | + Just { before, after } -> |
| 34 | + pathParts before |
| 35 | + <> map Query (L.fromFoldable (parseQueryPart decoder (S.drop 1 after))) |
| 36 | + Nothing -> |
| 37 | + pathParts hash |
| 38 | + where |
| 39 | + pathParts str = |
| 40 | + let |
| 41 | + parts = L.fromFoldable $ map Path (S.split (S.Pattern "/") str) |
| 42 | + in |
| 43 | + case L.unsnoc parts of |
| 44 | + Just { init, last: Path "" } -> init |
| 45 | + _ -> parts |
0 commit comments