Improved overlap checking for nesting #632

This commit is contained in:
Michael Snoyman 2013-12-18 08:24:32 +02:00
parent 5bc9f06959
commit 1429ae83eb
3 changed files with 55 additions and 15 deletions

View File

@ -8,15 +8,42 @@ module Yesod.Routes.Overlap
import Yesod.Routes.TH.Types
import Data.List (intercalate)
data Flattened t = Flattened
{ fNames :: [String]
, fPieces :: [(CheckOverlap, Piece t)]
, fHasSuffix :: Bool
}
flatten :: ResourceTree t -> [Flattened t]
flatten =
go id id
where
go names pieces (ResourceLeaf r) = return Flattened
{ fNames = names [resourceName r]
, fPieces = pieces (resourcePieces r)
, fHasSuffix = hasSuffix $ ResourceLeaf r
}
go names pieces (ResourceParent newname newpieces children) =
concatMap (go names' pieces') children
where
names' = names . (newname:)
pieces' = pieces . (newpieces ++)
data Overlap t = Overlap
{ overlapParents :: [String] -> [String] -- ^ parent resource trees
, overlap1 :: ResourceTree t
, overlap2 :: ResourceTree t
}
data OverlapF = OverlapF
{ overlapF1 :: [String]
, overlapF2 :: [String]
}
findOverlaps :: ([String] -> [String]) -> [ResourceTree t] -> [Overlap t]
findOverlaps _ [] = []
findOverlaps front (x:xs) = concatMap (findOverlap front x) xs ++ findOverlaps front xs
{-# DEPRECATED findOverlaps "This function is no longer used" #-}
findOverlap :: ([String] -> [String]) -> ResourceTree t -> ResourceTree t -> [Overlap t]
findOverlap front x y =
@ -30,14 +57,6 @@ findOverlap front x y =
ResourceParent name _ children -> findOverlaps (front . (name:)) children
ResourceLeaf{} -> []
hasSuffix :: ResourceTree t -> Bool
hasSuffix (ResourceLeaf r) =
case resourceDispatch r of
Subsite{} -> True
Methods Just{} _ -> True
Methods Nothing _ -> False
hasSuffix ResourceParent{} = True
overlaps :: [(CheckOverlap, Piece t)] -> [(CheckOverlap, Piece t)] -> Bool -> Bool -> Bool
-- No pieces on either side, will overlap regardless of suffix
@ -66,9 +85,26 @@ piecesOverlap _ _ = True
findOverlapNames :: [ResourceTree t] -> [(String, String)]
findOverlapNames =
map go . findOverlaps id
map go . findOverlapsF . concatMap Yesod.Routes.Overlap.flatten
where
go (Overlap front x y) =
(go' $ resourceTreeName x, go' $ resourceTreeName y)
go (OverlapF x y) =
(go' x, go' y)
where
go' = intercalate "/" . front . return
go' = intercalate "/"
findOverlapsF :: [Flattened t] -> [OverlapF]
findOverlapsF [] = []
findOverlapsF (x:xs) = concatMap (findOverlapF x) xs ++ findOverlapsF xs
findOverlapF :: Flattened t -> Flattened t -> [OverlapF]
findOverlapF x y
| overlaps (fPieces x) (fPieces y) (fHasSuffix x) (fHasSuffix y) = [OverlapF (fNames x) (fNames y)]
| otherwise = []
hasSuffix :: ResourceTree t -> Bool
hasSuffix (ResourceLeaf r) =
case resourceDispatch r of
Subsite{} -> True
Methods Just{} _ -> True
Methods Nothing _ -> False
hasSuffix ResourceParent{} = True

View File

@ -29,7 +29,7 @@ parseRoutes = QuasiQuoter { quoteExp = x }
let res = resourcesFromString s
case findOverlapNames res of
[] -> lift res
z -> error $ "Overlapping routes: " ++ unlines (map show z)
z -> error $ unlines $ "Overlapping routes: " : map show z
parseRoutesFile :: FilePath -> Q Exp
parseRoutesFile = parseRoutesFileWith parseRoutes

View File

@ -89,14 +89,18 @@ do
/nest2 Nest2:
/get Get2 GET
/post Post2 POST
/#Int Delete2 DELETE
-- /#Int Delete2 DELETE
/nest3 Nest3:
/get Get3 GET
/post Post3 POST
/#Int Delete3 DELETE
-- /#Int Delete3 DELETE
/afterwards AfterR:
/ After GET
-- /trailing-nest TrailingNestR:
-- /foo TrailingFooR GET
-- /#Int TrailingIntR GET
|]
rrinst <- mkRenderRouteInstance (ConT ''Hierarchy) $ map (fmap parseType) resources