0 | module Network.HTTP.Path
3 | import Data.String.Extra
6 | import Derive.Prelude
8 | %language ElabReflection
10 | data PathComponent : Type where
11 | Root : PathComponent
12 | Parent : PathComponent
13 | Current : PathComponent
15 | Named : String -> PathComponent
17 | %runElab derive "PathComponent" [Eq]
22 | components : List1 PathComponent
24 | zip_with_last : List a -> List (a, Maybe a)
25 | zip_with_last list =
26 | let (_ :: xs) = map Just list
28 | in zip list (snoc xs Nothing)
31 | normalize : Path -> Path
32 | normalize path = decompose $
trim_root path.components where
33 | is_current : PathComponent -> Bool
34 | is_current Current = True
35 | is_current (Named "") = True
36 | is_current _ = False
38 | rid_current : List PathComponent -> List PathComponent
39 | rid_current components = filter (not . is_current) components
41 | rid_parent : List PathComponent -> List PathComponent -> List PathComponent
42 | rid_parent acc [] = reverse acc
43 | rid_parent acc@(Parent :: as) (Parent :: xs) = rid_parent (Parent :: acc) xs
44 | rid_parent acc@(Root :: as) (Parent :: xs) = rid_parent acc xs
45 | rid_parent (a :: as) (Parent :: xs) = rid_parent as xs
46 | rid_parent acc (x :: xs) = rid_parent (x :: acc) xs
48 | append_current : List PathComponent -> List1 PathComponent
49 | append_current (Named x :: xs) = Current ::: (Named x :: xs)
50 | append_current [] = Current ::: []
51 | append_current (x :: xs) = (x ::: xs)
53 | decompose : List1 PathComponent -> Path
54 | decompose (x ::: xs) = MkPath $
append_current $
rid_parent [] (x :: rid_current xs)
56 | trim_root : List1 PathComponent -> List1 PathComponent
57 | trim_root list = case dropWhile (/= Root) $
forget list of [] => list;
(x :: xs) => x ::: xs
59 | concat : List a -> List1 a -> List1 a
61 | concat (x :: xs) (y ::: ys) = x ::: (xs <+> (y :: ys))
64 | Semigroup Path where
66 | let as = (normalize a).components
68 | in normalize $
MkPath $
concat ai (normalize b).components
72 | show path = trim_leading_roots $
join "/" $
map component_to_string path.components
74 | trim_leading_roots : String -> String
75 | trim_leading_roots str = assert_total $
if isPrefixOf "//" str then strTail str else str
77 | component_to_string : PathComponent -> String
78 | component_to_string Root = "/"
79 | component_to_string End = "/"
80 | component_to_string Parent = ".."
81 | component_to_string Current = "."
82 | component_to_string (Named x) = x
85 | FromString Path where
86 | fromString "" = MkPath $
singleton Current
88 | MkPath $
case split ('/' ==) string of
89 | ("" ::: xs) => Root ::: (map string_to_component xs)
90 | (x ::: xs) => map string_to_component $
(x ::: xs)
92 | string_to_component : String -> PathComponent
93 | string_to_component "" = End
94 | string_to_component "." = Current
95 | string_to_component ".." = Parent
96 | string_to_component x = Named x