Handle precedence in routing example.

This commit is contained in:
Dillon Kearns 2021-04-27 10:13:53 -07:00
parent 9e1f3b7b73
commit ab87bc049a

View File

@ -1,6 +1,7 @@
module RouteTests exposing (..) module RouteTests exposing (..)
import Expect import Expect
import List.Extra
import Regex import Regex
import Test exposing (Test, describe, test) import Test exposing (Test, describe, test)
@ -38,22 +39,104 @@ all =
Nothing Nothing
} }
|> Expect.equal (Cats__Name__ { name = Nothing } |> Just) |> Expect.equal (Cats__Name__ { name = Nothing } |> Just)
, test "multiple matchers" <|
\() ->
"/slide/123"
|> firstMatch exampleMatchers
|> Expect.equal (Slide__Number_ { number = "123" } |> Just)
, test "hardcoded routes have precedence over dynamic segments" <|
\() ->
"/post/create"
|> firstMatch postPrecedenceExample
|> Expect.equal (Post__Create {} |> Just)
, test "dynamic segments match when they are not overshadowed by a hardcoded route" <|
\() ->
"/post/update"
|> firstMatch postPrecedenceExample
|> Expect.equal (Post__Slug_ { slug = "update" } |> Just)
] ]
exampleMatchers : List (Matcher Route)
exampleMatchers =
[ { pattern = "^cats(?:\\/([^/]+))?$"
, toRoute =
\matches ->
case matches of
[ name ] ->
Cats__Name__ { name = name } |> Just
_ ->
Nothing
}
, { pattern = "^slide\\/(?:([^/]+))$"
, toRoute =
\matches ->
case matches of
[ Just number ] ->
Slide__Number_ { number = number } |> Just
_ ->
Nothing
}
]
postPrecedenceExample : List (Matcher Route)
postPrecedenceExample =
[ { pattern = "^post\\/create$"
, toRoute =
\_ ->
Just (Post__Create {})
}
, { pattern = "^post\\/(?:([^/]+))$"
, toRoute =
\matches ->
case matches of
[ Just slug ] ->
Post__Slug_ { slug = slug } |> Just
_ ->
Nothing
}
]
firstMatch : List (Matcher Route) -> String -> Maybe Route
firstMatch matchers path =
List.Extra.findMap
(\matcher ->
if Regex.contains (matcher.pattern |> toRegex) (normalizePath path) then
tryMatch matcher path
else
Nothing
)
matchers
toRegex : String -> Regex.Regex
toRegex pattern =
Regex.fromString pattern
|> Maybe.withDefault Regex.never
type alias Matcher route =
{ pattern : String, toRoute : List (Maybe String) -> Maybe route }
tryMatch : { pattern : String, toRoute : List (Maybe String) -> Maybe Route } -> String -> Maybe Route tryMatch : { pattern : String, toRoute : List (Maybe String) -> Maybe Route } -> String -> Maybe Route
tryMatch { pattern, toRoute } path = tryMatch { pattern, toRoute } path =
path path
|> normalizePath |> normalizePath
|> submatches "^cats(?:\\/([^/]+))?$" |> submatches pattern
|> toRoute |> toRoute
submatches : String -> String -> List (Maybe String) submatches : String -> String -> List (Maybe String)
submatches pattern path = submatches pattern path =
Regex.find Regex.find
(Regex.fromString (Regex.fromString pattern
"^cats(?:\\/([^/]+))?$"
|> Maybe.withDefault Regex.never |> Maybe.withDefault Regex.never
) )
path path
@ -89,3 +172,5 @@ type Route
= Slide {} = Slide {}
| Cats__Name__ { name : Maybe String } | Cats__Name__ { name : Maybe String }
| Slide__Number_ { number : String } | Slide__Number_ { number : String }
| Post__Create {}
| Post__Slug_ { slug : String }