Skip to content

Commit 64b62fa

Browse files
committed
Fix routing for query strings
1 parent 8b71fc5 commit 64b62fa

File tree

2 files changed

+34
-34
lines changed

2 files changed

+34
-34
lines changed

src/Routing/Parser.purs

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,45 @@
1-
module Routing.Parser (
2-
parse
3-
) where
1+
module Routing.Parser (parse) where
42

5-
import Control.MonadPlus (guard)
3+
import Prelude
4+
5+
import Routing.Types (Route, RoutePart(..))
66
import Data.Array as A
7-
import Data.Either (fromRight)
8-
import Data.List (fromFoldable, List)
97
import Data.Map as M
10-
import Data.Maybe (Maybe, fromMaybe)
118
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(..))
1412
import Data.Traversable (traverse)
1513
import Data.Tuple (Tuple(..))
16-
import Partial.Unsafe (unsafePartial)
17-
import Prelude (map, discard, (>>>), ($), (<<<), (==), (<*>), (<$>), (<=))
18-
import Routing.Types (Route, RoutePart(..))
1914

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
2116
-- | 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 "&")
2821
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
4127

4228
-- | Parse hash string to `Route` with `decoder` function
4329
-- | applied to every hash part (usually `decodeURIComponent`)
4430
parse :: (String -> String) -> String -> Route
4531
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

test/Test/Main.purs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,17 @@ routing =
3838
<|> Quux <$> (lit "" *> lit "quux" *> int)
3939
-- Order matters here. `list` is greedy, and `end` wont match after it
4040
<|> End <$> (lit "" *> int <* end)
41-
<|> Baz <$> (lit "" *> list num)
41+
<|> Baz <$> (list num)
4242

4343

4444
main :: Eff (assert :: ASSERT, console :: CONSOLE) Unit
4545
main = do
4646
assertEq (match routing "foo/12/?welp='hi'&b=false") (Right (Foo 12.0 (M.fromFoldable [Tuple "welp" "'hi'", Tuple "b" "false"])))
4747
assertEq (match routing "foo/12?welp='hi'&b=false") (Right (Foo 12.0 (M.fromFoldable [Tuple "welp" "'hi'", Tuple "b" "false"])))
4848
assertEq (match routing "/quux/42") (Right (Quux 42))
49-
assertEq (match routing "/123/") (Right (Baz (L.fromFoldable [123.0])))
49+
assertEq (match routing "123/") (Right (Baz (L.fromFoldable [123.0])))
5050
assertEq (match routing "/1") (Right (End 1))
51+
assertEq (match routing "foo/0/?test=a/b/c") (Right (Foo 0.0 (M.fromFoldable [Tuple "test" "a/b/c"])))
5152

5253
assertEq
5354
:: forall a eff

0 commit comments

Comments
 (0)