module Ema.Route.Prism (
  module X,

  -- * Handy encoders
  eitherRoutePrism,

  -- * Handy lenses
  htmlSuffixPrism,
  stringIso,
  showReadPrism,
) where

import Data.Text qualified as T
import Ema.Route.Prism.Check as X
import Ema.Route.Prism.Type as X
import Optics.Core (Iso', Prism', iso, preview, prism', review)

stringIso :: (ToString a, IsString a) => Iso' String a
stringIso :: forall a. (ToString a, IsString a) => Iso' FilePath a
stringIso = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso forall a. IsString a => FilePath -> a
fromString forall a. ToString a => a -> FilePath
toString

showReadPrism :: (Show a, Read a) => Prism' String a
showReadPrism :: forall a. (Show a, Read a) => Prism' FilePath a
showReadPrism = forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism' forall b a. (Show a, IsString b) => a -> b
show forall a. Read a => FilePath -> Maybe a
readMaybe

htmlSuffixPrism :: Prism' FilePath FilePath
htmlSuffixPrism :: Prism' FilePath FilePath
htmlSuffixPrism = forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism' (forall a. Semigroup a => a -> a -> a
<> FilePath
".html") (forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. ToString a => a -> FilePath
toString forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text -> Maybe Text
T.stripSuffix Text
".html" forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ToText a => a -> Text
toText)

{- | Returns a new route `Prism_` that supports *either* of the input routes.

  The resulting route `Prism_`'s model type becomes the *product* of the input models.
-}
eitherRoutePrism ::
  (a -> Prism_ FilePath r1) ->
  (b -> Prism_ FilePath r2) ->
  ((a, b) -> Prism_ FilePath (Either r1 r2))
eitherRoutePrism :: forall a r1 b r2.
(a -> Prism_ FilePath r1)
-> (b -> Prism_ FilePath r2)
-> (a, b)
-> Prism_ FilePath (Either r1 r2)
eitherRoutePrism a -> Prism_ FilePath r1
enc1 b -> Prism_ FilePath r2
enc2 (a
m1, b
m2) =
  forall s a. Prism' s a -> Prism_ s a
toPrism_ forall a b. (a -> b) -> a -> b
$ forall a b.
Prism' FilePath a
-> Prism' FilePath b -> Prism' FilePath (Either a b)
eitherPrism (forall s a. Prism_ s a -> Prism' s a
fromPrism_ forall a b. (a -> b) -> a -> b
$ a -> Prism_ FilePath r1
enc1 a
m1) (forall s a. Prism_ s a -> Prism' s a
fromPrism_ forall a b. (a -> b) -> a -> b
$ b -> Prism_ FilePath r2
enc2 b
m2)

{- | Given two @Prism'@'s whose filepaths are distinct (ie., both @a@ and @b@
 encode to distinct filepaths), return a new @Prism'@ that combines both.

 If this distinctness property does not hold between the input @Prism'@'s, then
 the resulting @Prism'@ will not be lawful.
-}
eitherPrism :: Prism' FilePath a -> Prism' FilePath b -> Prism' FilePath (Either a b)
eitherPrism :: forall a b.
Prism' FilePath a
-> Prism' FilePath b -> Prism' FilePath (Either a b)
eitherPrism Prism' FilePath a
p1 Prism' FilePath b
p2 =
  forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism'
    ( forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either
        (forall k (is :: IxList) t b.
Is k A_Review =>
Optic' k is t b -> b -> t
review Prism' FilePath a
p1)
        (forall k (is :: IxList) t b.
Is k A_Review =>
Optic' k is t b -> b -> t
review Prism' FilePath b
p2)
    )
    ( \FilePath
fp ->
        forall (t :: Type -> Type) (f :: Type -> Type) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum
          [ forall a b. a -> Either a b
Left forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> forall k (is :: IxList) s a.
Is k An_AffineFold =>
Optic' k is s a -> s -> Maybe a
preview Prism' FilePath a
p1 FilePath
fp
          , forall a b. b -> Either a b
Right forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> forall k (is :: IxList) s a.
Is k An_AffineFold =>
Optic' k is s a -> s -> Maybe a
preview Prism' FilePath b
p2 FilePath
fp
          ]
    )