{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
module Yesod.Routes.Flow.Generator
( genFlowRoutes
, genFlowRoutesPrefix
, genFlowSource
, genFlowClasses
, classesToFlow
, Class(..)
, ClassMember(..)
, RenderedPiece(..)
, PieceType(..)
) where
import ClassyPrelude hiding (FilePath)
import qualified Data.Char as C
import qualified Data.List as L
import qualified Data.Map as Map
import Data.Text (dropWhileEnd)
import qualified Data.Text as T
import Filesystem (createTree, writeTextFile)
import Filesystem.Path (FilePath, directory)
import Yesod.Routes.TH.Types
type Overrides = Map.Map String PieceType
genFlowRoutes :: [ResourceTree String] -> FilePath -> IO ()
genFlowRoutes :: [ResourceTree String] -> FilePath -> IO ()
genFlowRoutes [ResourceTree String]
ra FilePath
fp = Overrides
-> [String]
-> [String]
-> [ResourceTree String]
-> FilePath
-> Text
-> IO ()
genFlowRoutesPrefix Overrides
forall k a. Map k a
Map.empty [] [] [ResourceTree String]
ra FilePath
fp Text
"''"
genFlowRoutesPrefix :: Overrides -> [String] -> [String] -> [ResourceTree String] -> FilePath -> Text -> IO ()
genFlowRoutesPrefix :: Overrides
-> [String]
-> [String]
-> [ResourceTree String]
-> FilePath
-> Text
-> IO ()
genFlowRoutesPrefix Overrides
overrides [String]
routePrefixes [String]
elidedPrefixes [ResourceTree String]
fullTree FilePath
fp Text
prefix = do
FilePath -> IO ()
createTree (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
directory FilePath
fp
FilePath -> Text -> IO ()
writeTextFile FilePath
fp (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ Overrides
-> [String] -> [String] -> Text -> [ResourceTree String] -> Text
genFlowSource Overrides
overrides [String]
routePrefixes [String]
elidedPrefixes Text
prefix [ResourceTree String]
fullTree
genFlowSource :: Overrides -> [String] -> [String] -> Text -> [ResourceTree String] -> Text
genFlowSource :: Overrides
-> [String] -> [String] -> Text -> [ResourceTree String] -> Text
genFlowSource Overrides
overrides [String]
routePrefixes [String]
elidedPrefixes Text
prefix [ResourceTree String]
fullTree =
[Text] -> Text
forall a. Monoid a => [a] -> a
mconcat
[ Text
"/* @flow */\n\n"
, [Class] -> Text
classesToFlow ([Class] -> Text) -> [Class] -> Text
forall a b. (a -> b) -> a -> b
$ Overrides
-> [String] -> [String] -> [ResourceTree String] -> [Class]
genFlowClasses Overrides
overrides [String]
routePrefixes [String]
elidedPrefixes [ResourceTree String]
fullTree
, Text
"\n\nvar PATHS: PATHS_TYPE_paths = new PATHS_TYPE_paths(" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
prefix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
");\n"
]
genFlowClasses :: Overrides -> [String] -> [String] -> [ResourceTree String] -> [Class]
genFlowClasses :: Overrides
-> [String] -> [String] -> [ResourceTree String] -> [Class]
genFlowClasses Overrides
overrides [String]
routePrefixes [String]
elidedPrefixes [ResourceTree String]
fullTree =
(Class -> Class) -> [Class] -> [Class]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map Class -> Class
disambiguateFields ([Class] -> [Class]) -> [Class] -> [Class]
forall a b. (a -> b) -> a -> b
$
Overrides -> [String] -> ResourceTree String -> [Class]
resourceTreeToClasses Overrides
overrides [String]
elidedPrefixes (ResourceTree String -> [Class]) -> ResourceTree String -> [Class]
forall a b. (a -> b) -> a -> b
$
String
-> CheckOverlap
-> [Piece String]
-> [ResourceTree String]
-> ResourceTree String
forall typ.
String
-> CheckOverlap
-> [Piece typ]
-> [ResourceTree typ]
-> ResourceTree typ
ResourceParent String
"paths" CheckOverlap
False [] [ResourceTree String]
hackedTree
where
landingRoutes :: [ResourceTree String]
landingRoutes = ((ResourceTree String -> CheckOverlap)
-> [ResourceTree String] -> [ResourceTree String])
-> [ResourceTree String]
-> (ResourceTree String -> CheckOverlap)
-> [ResourceTree String]
forall a b c. (a -> b -> c) -> b -> a -> c
flip (ResourceTree String -> CheckOverlap)
-> [ResourceTree String] -> [ResourceTree String]
forall seq.
IsSequence seq =>
(Element seq -> CheckOverlap) -> seq -> seq
filter [ResourceTree String]
fullTree ((ResourceTree String -> CheckOverlap) -> [ResourceTree String])
-> (ResourceTree String -> CheckOverlap) -> [ResourceTree String]
forall a b. (a -> b) -> a -> b
$ \case
ResourceParent {} -> CheckOverlap
False
ResourceLeaf Resource String
res -> Element [String] -> [String] -> CheckOverlap
forall mono.
(MonoFoldable mono, Eq (Element mono)) =>
Element mono -> mono -> CheckOverlap
notElem (Resource String -> String
forall typ. Resource typ -> String
resourceName Resource String
res) [String
"AuthR", String
"StaticR"]
parents :: [ResourceTree String]
parents =
(Element [ResourceTree String] -> CheckOverlap)
-> [ResourceTree String] -> [ResourceTree String]
forall seq.
IsSequence seq =>
(Element seq -> CheckOverlap) -> seq -> seq
filter (\Element [ResourceTree String]
n -> [String] -> CheckOverlap
forall mono. MonoFoldable mono => mono -> CheckOverlap
null [String]
routePrefixes CheckOverlap -> CheckOverlap -> CheckOverlap
|| (Element [String] -> CheckOverlap) -> [String] -> CheckOverlap
forall mono.
MonoFoldable mono =>
(Element mono -> CheckOverlap) -> mono -> CheckOverlap
any (ResourceTree String -> String -> CheckOverlap
parentName Element [ResourceTree String]
ResourceTree String
n) [String]
routePrefixes) [ResourceTree String]
fullTree
hackedTree :: [ResourceTree String]
hackedTree = String
-> CheckOverlap
-> [Piece String]
-> [ResourceTree String]
-> ResourceTree String
forall typ.
String
-> CheckOverlap
-> [Piece typ]
-> [ResourceTree typ]
-> ResourceTree typ
ResourceParent String
"staticPages" CheckOverlap
False [] [ResourceTree String]
landingRoutes ResourceTree String
-> [ResourceTree String] -> [ResourceTree String]
forall a. a -> [a] -> [a]
: [ResourceTree String]
parents
parentName :: ResourceTree String -> String -> Bool
parentName :: ResourceTree String -> String -> CheckOverlap
parentName (ResourceParent String
n CheckOverlap
_ [Piece String]
_ [ResourceTree String]
_) String
name = String
n String -> String -> CheckOverlap
forall a. Eq a => a -> a -> CheckOverlap
== String
name
parentName ResourceTree String
_ String
_ = CheckOverlap
False
data RenderedPiece
= Path Text
| Dyn PieceType
deriving (RenderedPiece -> RenderedPiece -> CheckOverlap
(RenderedPiece -> RenderedPiece -> CheckOverlap)
-> (RenderedPiece -> RenderedPiece -> CheckOverlap)
-> Eq RenderedPiece
forall a.
(a -> a -> CheckOverlap) -> (a -> a -> CheckOverlap) -> Eq a
/= :: RenderedPiece -> RenderedPiece -> CheckOverlap
$c/= :: RenderedPiece -> RenderedPiece -> CheckOverlap
== :: RenderedPiece -> RenderedPiece -> CheckOverlap
$c== :: RenderedPiece -> RenderedPiece -> CheckOverlap
Eq, Int -> RenderedPiece -> ShowS
[RenderedPiece] -> ShowS
RenderedPiece -> String
(Int -> RenderedPiece -> ShowS)
-> (RenderedPiece -> String)
-> ([RenderedPiece] -> ShowS)
-> Show RenderedPiece
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RenderedPiece] -> ShowS
$cshowList :: [RenderedPiece] -> ShowS
show :: RenderedPiece -> String
$cshow :: RenderedPiece -> String
showsPrec :: Int -> RenderedPiece -> ShowS
$cshowsPrec :: Int -> RenderedPiece -> ShowS
Show)
data PieceType
= NumberT
| StringT
| NonEmptyT PieceType
deriving (PieceType -> PieceType -> CheckOverlap
(PieceType -> PieceType -> CheckOverlap)
-> (PieceType -> PieceType -> CheckOverlap) -> Eq PieceType
forall a.
(a -> a -> CheckOverlap) -> (a -> a -> CheckOverlap) -> Eq a
/= :: PieceType -> PieceType -> CheckOverlap
$c/= :: PieceType -> PieceType -> CheckOverlap
== :: PieceType -> PieceType -> CheckOverlap
$c== :: PieceType -> PieceType -> CheckOverlap
Eq, Int -> PieceType -> ShowS
[PieceType] -> ShowS
PieceType -> String
(Int -> PieceType -> ShowS)
-> (PieceType -> String)
-> ([PieceType] -> ShowS)
-> Show PieceType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PieceType] -> ShowS
$cshowList :: [PieceType] -> ShowS
show :: PieceType -> String
$cshow :: PieceType -> String
showsPrec :: Int -> PieceType -> ShowS
$cshowsPrec :: Int -> PieceType -> ShowS
Show)
isVariable :: RenderedPiece -> Bool
isVariable :: RenderedPiece -> CheckOverlap
isVariable (Path Text
_) = CheckOverlap
False
isVariable (Dyn PieceType
_) = CheckOverlap
True
renderRoutePieces :: Overrides -> [Piece String] -> [RenderedPiece]
renderRoutePieces :: Overrides -> [Piece String] -> [RenderedPiece]
renderRoutePieces Overrides
overrides = (Piece String -> RenderedPiece)
-> [Piece String] -> [RenderedPiece]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map Piece String -> RenderedPiece
renderRoutePiece
where
renderRoutePiece :: Piece String -> RenderedPiece
renderRoutePiece (Static String
st) = Text -> RenderedPiece
Path (Text -> RenderedPiece) -> Text -> RenderedPiece
forall a b. (a -> b) -> a -> b
$ (Char -> CheckOverlap) -> Text -> Text
T.dropAround (Char -> Char -> CheckOverlap
forall a. Eq a => a -> a -> CheckOverlap
== Char
'/') (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ [Element Text] -> Text
forall seq. IsSequence seq => [Element seq] -> seq
pack String
[Element Text]
st
renderRoutePiece (Dynamic String
typ) = PieceType -> RenderedPiece
Dyn (PieceType -> RenderedPiece) -> PieceType -> RenderedPiece
forall a b. (a -> b) -> a -> b
$ String -> PieceType
parseType String
typ
parseType :: String -> PieceType
parseType String
type_ =
PieceType -> Maybe PieceType -> PieceType
forall a. a -> Maybe a -> a
fromMaybe
(PieceType -> (String -> PieceType) -> Maybe String -> PieceType
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
(String -> PieceType
forall seq.
(IsString seq, IsSequence seq, Eq seq, Eq (Element seq)) =>
seq -> PieceType
parseSimpleType String
type_)
(PieceType -> PieceType
NonEmptyT (PieceType -> PieceType)
-> (String -> PieceType) -> String -> PieceType
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. String -> PieceType
parseType)
(String -> String -> Maybe String
forall a. Eq a => [a] -> [a] -> Maybe [a]
L.stripPrefix String
"NonEmpty" String
type_))
(Maybe PieceType -> PieceType) -> Maybe PieceType -> PieceType
forall a b. (a -> b) -> a -> b
$ String -> Overrides -> Maybe PieceType
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup String
type_ Overrides
overrides
parseSimpleType :: seq -> PieceType
parseSimpleType seq
"Int" = PieceType
NumberT
parseSimpleType seq
type_
| seq
"Id" seq -> seq -> CheckOverlap
forall seq.
(IsSequence seq, Eq (Element seq)) =>
seq -> seq -> CheckOverlap
`isSuffixOf` seq
type_ = PieceType
NumberT
| CheckOverlap
otherwise = PieceType
StringT
data Class =
Class
{ Class -> Text
className :: Text
, Class -> [ClassMember]
classMembers :: [ClassMember]
}
deriving (Class -> Class -> CheckOverlap
(Class -> Class -> CheckOverlap)
-> (Class -> Class -> CheckOverlap) -> Eq Class
forall a.
(a -> a -> CheckOverlap) -> (a -> a -> CheckOverlap) -> Eq a
/= :: Class -> Class -> CheckOverlap
$c/= :: Class -> Class -> CheckOverlap
== :: Class -> Class -> CheckOverlap
$c== :: Class -> Class -> CheckOverlap
Eq, Int -> Class -> ShowS
[Class] -> ShowS
Class -> String
(Int -> Class -> ShowS)
-> (Class -> String) -> ([Class] -> ShowS) -> Show Class
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Class] -> ShowS
$cshowList :: [Class] -> ShowS
show :: Class -> String
$cshow :: Class -> String
showsPrec :: Int -> Class -> ShowS
$cshowsPrec :: Int -> Class -> ShowS
Show)
data ClassMember =
ChildClass
{ ClassMember -> Text
cmField :: Text
, ClassMember -> Text
cmClassName :: Text
}
| Method
{ cmField :: Text
, ClassMember -> [RenderedPiece]
cmPieces :: [RenderedPiece]
}
deriving (ClassMember -> ClassMember -> CheckOverlap
(ClassMember -> ClassMember -> CheckOverlap)
-> (ClassMember -> ClassMember -> CheckOverlap) -> Eq ClassMember
forall a.
(a -> a -> CheckOverlap) -> (a -> a -> CheckOverlap) -> Eq a
/= :: ClassMember -> ClassMember -> CheckOverlap
$c/= :: ClassMember -> ClassMember -> CheckOverlap
== :: ClassMember -> ClassMember -> CheckOverlap
$c== :: ClassMember -> ClassMember -> CheckOverlap
Eq, Int -> ClassMember -> ShowS
[ClassMember] -> ShowS
ClassMember -> String
(Int -> ClassMember -> ShowS)
-> (ClassMember -> String)
-> ([ClassMember] -> ShowS)
-> Show ClassMember
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ClassMember] -> ShowS
$cshowList :: [ClassMember] -> ShowS
show :: ClassMember -> String
$cshow :: ClassMember -> String
showsPrec :: Int -> ClassMember -> ShowS
$cshowsPrec :: Int -> ClassMember -> ShowS
Show)
variableCount :: ClassMember -> Int
variableCount :: ClassMember -> Int
variableCount ChildClass {} = Int
0
variableCount Method {[RenderedPiece]
Text
cmPieces :: [RenderedPiece]
cmField :: Text
cmPieces :: ClassMember -> [RenderedPiece]
cmField :: ClassMember -> Text
..} = [RenderedPiece] -> Int
forall mono. MonoFoldable mono => mono -> Int
length ((Element [RenderedPiece] -> CheckOverlap)
-> [RenderedPiece] -> [RenderedPiece]
forall seq.
IsSequence seq =>
(Element seq -> CheckOverlap) -> seq -> seq
filter Element [RenderedPiece] -> CheckOverlap
RenderedPiece -> CheckOverlap
isVariable [RenderedPiece]
cmPieces)
variableNames :: [Text]
variableNames :: [Text]
variableNames = Char -> Text -> Text
T.cons (Char -> Text -> Text) -> String -> [Text -> Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Char
'a'..Char
'z'] [Text -> Text] -> [Text] -> [Text]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Text
"" Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text]
variableNames)
resourceTreeToClasses :: Overrides -> [String] -> ResourceTree String -> [Class]
resourceTreeToClasses :: Overrides -> [String] -> ResourceTree String -> [Class]
resourceTreeToClasses Overrides
overrides [String]
elidedPrefixes = Either (Maybe ClassMember) ([ClassMember], [Class]) -> [Class]
forall a a a. Either a (a, [a]) -> [a]
finish (Either (Maybe ClassMember) ([ClassMember], [Class]) -> [Class])
-> (ResourceTree String
-> Either (Maybe ClassMember) ([ClassMember], [Class]))
-> ResourceTree String
-> [Class]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Maybe Text
-> [RenderedPiece]
-> ResourceTree String
-> Either (Maybe ClassMember) ([ClassMember], [Class])
go Maybe Text
forall a. Maybe a
Nothing []
where
finish :: Either a (a, [a]) -> [a]
finish (Right (a
_, [a]
classes)) = [a]
classes
finish (Left a
_) = []
go :: Maybe Text -> [RenderedPiece] -> ResourceTree String -> Either (Maybe ClassMember) ([ClassMember], [Class])
go :: Maybe Text
-> [RenderedPiece]
-> ResourceTree String
-> Either (Maybe ClassMember) ([ClassMember], [Class])
go Maybe Text
_parent [RenderedPiece]
routePrefix (ResourceLeaf Resource String
res) =
Maybe ClassMember
-> Either (Maybe ClassMember) ([ClassMember], [Class])
forall a b. a -> Either a b
Left (Maybe ClassMember
-> Either (Maybe ClassMember) ([ClassMember], [Class]))
-> Maybe ClassMember
-> Either (Maybe ClassMember) ([ClassMember], [Class])
forall a b. (a -> b) -> a -> b
$ do
Methods Maybe String
_ [String]
methods <- Dispatch String -> Maybe (Dispatch String)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Dispatch String -> Maybe (Dispatch String))
-> Dispatch String -> Maybe (Dispatch String)
forall a b. (a -> b) -> a -> b
$ Resource String -> Dispatch String
forall typ. Resource typ -> Dispatch typ
resourceDispatch Resource String
res
CheckOverlap -> Maybe ()
forall (f :: * -> *). Alternative f => CheckOverlap -> f ()
guard (CheckOverlap -> CheckOverlap
not (CheckOverlap -> CheckOverlap) -> CheckOverlap -> CheckOverlap
forall a b. (a -> b) -> a -> b
$ [String] -> CheckOverlap
forall mono. MonoFoldable mono => mono -> CheckOverlap
null [String]
methods)
let resName :: Text
resName = Text -> Text -> Text -> Text
T.replace Text
"." Text
"" (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Text -> Text
T.replace Text
"-" Text
"_" Text
fullName
fullName :: Element [Text]
fullName = Element [Text] -> [Text] -> Element [Text]
forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
Element mono -> mono -> Element mono
intercalate Element [Text]
"_" [[Element Text] -> Text
forall seq. IsSequence seq => [Element seq] -> seq
pack String
[Element Text]
st :: Text | Static String
st <- Resource String -> [Piece String]
forall typ. Resource typ -> [Piece typ]
resourcePieces Resource String
res]
ClassMember -> Maybe ClassMember
forall (f :: * -> *) a. Applicative f => a -> f a
pure Method :: Text -> [RenderedPiece] -> ClassMember
Method
{ cmField :: Text
cmField = if Text -> CheckOverlap
forall mono. MonoFoldable mono => mono -> CheckOverlap
null Text
fullName then Text
"_" else Text
resName
, cmPieces :: [RenderedPiece]
cmPieces = [RenderedPiece]
routePrefix [RenderedPiece] -> [RenderedPiece] -> [RenderedPiece]
forall a. Semigroup a => a -> a -> a
<> Overrides -> [Piece String] -> [RenderedPiece]
renderRoutePieces Overrides
overrides (Resource String -> [Piece String]
forall typ. Resource typ -> [Piece typ]
resourcePieces Resource String
res) }
go Maybe Text
parent [RenderedPiece]
routePrefix (ResourceParent String
name CheckOverlap
_ [Piece String]
pieces [ResourceTree String]
children) =
let elideThisPrefix :: CheckOverlap
elideThisPrefix = String
Element [String]
name Element [String] -> [String] -> CheckOverlap
forall mono.
(MonoFoldable mono, Eq (Element mono)) =>
Element mono -> mono -> CheckOverlap
`elem` [String]
elidedPrefixes
pref :: Text
pref = Text -> Text
cleanName (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ [Element Text] -> Text
forall seq. IsSequence seq => [Element seq] -> seq
pack String
[Element Text]
name
jsName :: Text
jsName = Text -> (Text -> Text) -> Maybe Text -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"" (Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_") Maybe Text
parent Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
pref
newParent :: Maybe Text
newParent = if CheckOverlap
elideThisPrefix then Maybe Text
parent else Text -> Maybe Text
forall a. a -> Maybe a
Just Text
jsName
newRoutePrefix :: [RenderedPiece]
newRoutePrefix = [RenderedPiece]
routePrefix [RenderedPiece] -> [RenderedPiece] -> [RenderedPiece]
forall a. Semigroup a => a -> a -> a
<> Overrides -> [Piece String] -> [RenderedPiece]
renderRoutePieces Overrides
overrides [Piece String]
pieces
membersMethods :: [ClassMember]
membersMethods = [Maybe ClassMember] -> [ClassMember]
forall (f :: * -> *) t.
(IsSequence (f (Maybe t)), Functor f,
Element (f (Maybe t)) ~ Maybe t) =>
f (Maybe t) -> f t
catMaybes [Maybe ClassMember]
childrenMethods
([Maybe ClassMember]
childrenMethods, [([ClassMember], [Class])]
childrenClasses) = [Either (Maybe ClassMember) ([ClassMember], [Class])]
-> ([Maybe ClassMember], [([ClassMember], [Class])])
forall a b. [Either a b] -> ([a], [b])
partitionEithers ([Either (Maybe ClassMember) ([ClassMember], [Class])]
-> ([Maybe ClassMember], [([ClassMember], [Class])]))
-> [Either (Maybe ClassMember) ([ClassMember], [Class])]
-> ([Maybe ClassMember], [([ClassMember], [Class])])
forall a b. (a -> b) -> a -> b
$ (ResourceTree String
-> Either (Maybe ClassMember) ([ClassMember], [Class]))
-> [ResourceTree String]
-> [Either (Maybe ClassMember) ([ClassMember], [Class])]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map (Maybe Text
-> [RenderedPiece]
-> ResourceTree String
-> Either (Maybe ClassMember) ([ClassMember], [Class])
go Maybe Text
newParent [RenderedPiece]
newRoutePrefix) [ResourceTree String]
children
([ClassMember]
membersClasses, [Class]
moreClasses) = [[ClassMember]] -> [ClassMember]
forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
mono -> Element mono
concat ([[ClassMember]] -> [ClassMember])
-> ([[Class]] -> [Class])
-> ([[ClassMember]], [[Class]])
-> ([ClassMember], [Class])
forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** [[Class]] -> [Class]
forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
mono -> Element mono
concat (([[ClassMember]], [[Class]]) -> ([ClassMember], [Class]))
-> ([[ClassMember]], [[Class]]) -> ([ClassMember], [Class])
forall a b. (a -> b) -> a -> b
$ [([ClassMember], [Class])] -> ([[ClassMember]], [[Class]])
forall (f :: * -> *) a b. Zip f => f (a, b) -> (f a, f b)
unzip [([ClassMember], [Class])]
childrenClasses
in ([ClassMember], [Class])
-> Either (Maybe ClassMember) ([ClassMember], [Class])
forall a b. b -> Either a b
Right (([ClassMember], [Class])
-> Either (Maybe ClassMember) ([ClassMember], [Class]))
-> ([ClassMember], [Class])
-> Either (Maybe ClassMember) ([ClassMember], [Class])
forall a b. (a -> b) -> a -> b
$
if CheckOverlap
elideThisPrefix
then ([ClassMember]
membersClasses, [Class]
moreClasses)
else
let ourClass :: Class
ourClass =
Class :: Text -> [ClassMember] -> Class
Class
{ className :: Text
className = Text
"PATHS_TYPE_" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
jsName
, classMembers :: [ClassMember]
classMembers = [ClassMember]
membersClasses [ClassMember] -> [ClassMember] -> [ClassMember]
forall m. Monoid m => m -> m -> m
++ [ClassMember]
membersMethods }
ourReference :: ClassMember
ourReference =
ChildClass :: Text -> Text -> ClassMember
ChildClass
{ cmClassName :: Text
cmClassName = Class -> Text
className Class
ourClass
, cmField :: Text
cmField = Text
pref }
in ([ClassMember
ourReference], Class
ourClass Class -> [Class] -> [Class]
forall a. a -> [a] -> [a]
: [Class]
moreClasses)
cleanName :: Text -> Text
cleanName :: Text -> Text
cleanName = Text -> Text
underscorize (Text -> Text) -> (Text -> Text) -> Text -> Text
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> Text
forall seq. Textual seq => seq -> seq
uncapitalize (Text -> Text) -> (Text -> Text) -> Text -> Text
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Char -> CheckOverlap) -> Text -> Text
dropWhileEnd Char -> CheckOverlap
C.isUpper
where uncapitalize :: seq -> seq
uncapitalize seq
t = seq -> seq
forall seq. Textual seq => seq -> seq
toLower (Index seq -> seq -> seq
forall seq. IsSequence seq => Index seq -> seq -> seq
take Index seq
1 seq
t) seq -> seq -> seq
forall a. Semigroup a => a -> a -> a
<> Index seq -> seq -> seq
forall seq. IsSequence seq => Index seq -> seq -> seq
drop Index seq
1 seq
t
underscorize :: Text -> Text
underscorize = String -> Text
T.pack (String -> Text) -> (Text -> String) -> Text -> Text
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ShowS
go ShowS -> (Text -> String) -> Text -> String
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> String
T.unpack
where go :: ShowS
go (Char
c:String
cs) | Char -> CheckOverlap
C.isUpper Char
c = Char
'_' Char -> ShowS
forall a. a -> [a] -> [a]
: Char -> Char
C.toLower Char
c Char -> ShowS
forall a. a -> [a] -> [a]
: ShowS
go String
cs
| CheckOverlap
otherwise = Char
c Char -> ShowS
forall a. a -> [a] -> [a]
: ShowS
go String
cs
go [] = []
disambiguateFields :: Class -> Class
disambiguateFields :: Class -> Class
disambiguateFields Class
klass = Class
klass { classMembers :: [ClassMember]
classMembers = [ClassMember] -> [ClassMember]
processMembers ([ClassMember] -> [ClassMember]) -> [ClassMember] -> [ClassMember]
forall a b. (a -> b) -> a -> b
$ Class -> [ClassMember]
classMembers Class
klass }
where
processMembers :: [ClassMember] -> [ClassMember]
processMembers = Map Text [ClassMember] -> [ClassMember]
forall k. Map k [ClassMember] -> [ClassMember]
fromMap (Map Text [ClassMember] -> [ClassMember])
-> ([ClassMember] -> Map Text [ClassMember])
-> [ClassMember]
-> [ClassMember]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ([ClassMember] -> [ClassMember])
-> Map Text [ClassMember] -> Map Text [ClassMember]
disambiguate [ClassMember] -> [ClassMember]
viaLetters (Map Text [ClassMember] -> Map Text [ClassMember])
-> ([ClassMember] -> Map Text [ClassMember])
-> [ClassMember]
-> Map Text [ClassMember]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ([ClassMember] -> [ClassMember])
-> Map Text [ClassMember] -> Map Text [ClassMember]
disambiguate [ClassMember] -> [ClassMember]
viaArgCount (Map Text [ClassMember] -> Map Text [ClassMember])
-> ([ClassMember] -> Map Text [ClassMember])
-> [ClassMember]
-> Map Text [ClassMember]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [ClassMember] -> Map Text [ClassMember]
toMap
fromMap :: Map k [ClassMember] -> [ClassMember]
fromMap = [[ClassMember]] -> [ClassMember]
forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
mono -> Element mono
concat ([[ClassMember]] -> [ClassMember])
-> (Map k [ClassMember] -> [[ClassMember]])
-> Map k [ClassMember]
-> [ClassMember]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Map k [ClassMember] -> [[ClassMember]]
forall k a. Map k a -> [a]
Map.elems
toMap :: [ClassMember] -> Map Text [ClassMember]
toMap = ([ClassMember] -> [ClassMember] -> [ClassMember])
-> [(Text, [ClassMember])] -> Map Text [ClassMember]
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith [ClassMember] -> [ClassMember] -> [ClassMember]
forall m. Monoid m => m -> m -> m
(++) ([(Text, [ClassMember])] -> Map Text [ClassMember])
-> ([ClassMember] -> [(Text, [ClassMember])])
-> [ClassMember]
-> Map Text [ClassMember]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [ClassMember] -> [(Text, [ClassMember])]
labelled
labelled :: [ClassMember] -> [(Text, [ClassMember])]
labelled = (ClassMember -> (Text, [ClassMember]))
-> [ClassMember] -> [(Text, [ClassMember])]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map (ClassMember -> Text
cmField (ClassMember -> Text)
-> (ClassMember -> [ClassMember])
-> ClassMember
-> (Text, [ClassMember])
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& ClassMember -> [ClassMember]
forall (f :: * -> *) a. Applicative f => a -> f a
pure)
append :: (ClassMember -> Text) -> ClassMember -> ClassMember
append ClassMember -> Text
t ClassMember
cm = ClassMember
cm { cmField :: Text
cmField = ClassMember -> Text
cmField ClassMember
cm Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ClassMember -> Text
t ClassMember
cm }
disambiguate :: ([ClassMember] -> [ClassMember]) -> Map.Map Text [ClassMember] -> Map.Map Text [ClassMember]
disambiguate :: ([ClassMember] -> [ClassMember])
-> Map Text [ClassMember] -> Map Text [ClassMember]
disambiguate [ClassMember] -> [ClassMember]
inner = ([ClassMember] -> [ClassMember] -> [ClassMember])
-> [(Text, [ClassMember])] -> Map Text [ClassMember]
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith [ClassMember] -> [ClassMember] -> [ClassMember]
forall m. Monoid m => m -> m -> m
(++) ([(Text, [ClassMember])] -> Map Text [ClassMember])
-> (Map Text [ClassMember] -> [(Text, [ClassMember])])
-> Map Text [ClassMember]
-> Map Text [ClassMember]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Element [(Text, [ClassMember])] -> [(Text, [ClassMember])])
-> [(Text, [ClassMember])] -> [(Text, [ClassMember])]
forall mono m.
(MonoFoldable mono, Monoid m) =>
(Element mono -> m) -> mono -> m
concatMap (Text, [ClassMember]) -> [(Text, [ClassMember])]
Element [(Text, [ClassMember])] -> [(Text, [ClassMember])]
f ([(Text, [ClassMember])] -> [(Text, [ClassMember])])
-> (Map Text [ClassMember] -> [(Text, [ClassMember])])
-> Map Text [ClassMember]
-> [(Text, [ClassMember])]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Map Text [ClassMember] -> [(Text, [ClassMember])]
forall k a. Map k a -> [(k, a)]
Map.toList
where
f :: (Text, [ClassMember]) -> [(Text, [ClassMember])]
f :: (Text, [ClassMember]) -> [(Text, [ClassMember])]
f y :: (Text, [ClassMember])
y@(Text
_, [ ]) = [(Text, [ClassMember])
y]
f y :: (Text, [ClassMember])
y@(Text
_, [ClassMember
_]) = [(Text, [ClassMember])
y]
f (Text
_, [ClassMember]
xs ) = [ClassMember] -> [(Text, [ClassMember])]
labelled ([ClassMember] -> [(Text, [ClassMember])])
-> [ClassMember] -> [(Text, [ClassMember])]
forall a b. (a -> b) -> a -> b
$ [ClassMember] -> [ClassMember]
inner [ClassMember]
xs
viaArgCount :: [ClassMember] -> [ClassMember]
viaArgCount = (ClassMember -> ClassMember) -> [ClassMember] -> [ClassMember]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map ((ClassMember -> ClassMember) -> [ClassMember] -> [ClassMember])
-> (ClassMember -> ClassMember) -> [ClassMember] -> [ClassMember]
forall a b. (a -> b) -> a -> b
$ (ClassMember -> Text) -> ClassMember -> ClassMember
append (String -> Text
T.pack (String -> Text) -> (ClassMember -> String) -> ClassMember -> Text
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Int -> String
forall a. Show a => a -> String
show (Int -> String) -> (ClassMember -> Int) -> ClassMember -> String
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ClassMember -> Int
variableCount)
viaLetters :: [ClassMember] -> [ClassMember]
viaLetters = (Text -> ClassMember -> ClassMember)
-> [Text] -> [ClassMember] -> [ClassMember]
forall (f :: * -> *) a b c.
Zip f =>
(a -> b -> c) -> f a -> f b -> f c
zipWith ((ClassMember -> Text) -> ClassMember -> ClassMember
append ((ClassMember -> Text) -> ClassMember -> ClassMember)
-> (Text -> ClassMember -> Text)
-> Text
-> ClassMember
-> ClassMember
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> ClassMember -> Text
forall a b. a -> b -> a
const) [Text]
variableNames
classMemberToFlowDef :: ClassMember -> Text
classMemberToFlowDef :: ClassMember -> Text
classMemberToFlowDef ChildClass {Text
cmClassName :: Text
cmField :: Text
cmClassName :: ClassMember -> Text
cmField :: ClassMember -> Text
..} = Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
cmField Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" : " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
cmClassName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
";\n"
classMemberToFlowDef Method {[RenderedPiece]
Text
cmPieces :: [RenderedPiece]
cmField :: Text
cmPieces :: ClassMember -> [RenderedPiece]
cmField :: ClassMember -> Text
..} = Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
cmField Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"(" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
args Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"): string { " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
body Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"; }\n"
where
args :: Element [Text]
args = Element [Text] -> [Text] -> Element [Text]
forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
Element mono -> mono -> Element mono
intercalate Element [Text]
", " ([Text] -> Element [Text]) -> [Text] -> Element [Text]
forall a b. (a -> b) -> a -> b
$ (Text -> PieceType -> Text) -> [Text] -> [PieceType] -> [Text]
forall (f :: * -> *) a b c.
Zip f =>
(a -> b -> c) -> f a -> f b -> f c
zipWith Text -> PieceType -> Text
forall a. (Semigroup a, IsString a) => a -> PieceType -> a
render [Text]
variableNames ([PieceType] -> [Text]) -> [PieceType] -> [Text]
forall a b. (a -> b) -> a -> b
$ (RenderedPiece -> Maybe PieceType)
-> [RenderedPiece] -> [PieceType]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe RenderedPiece -> Maybe PieceType
getType [RenderedPiece]
cmPieces
where
render :: a -> PieceType -> a
render a
name PieceType
typ = a
name a -> a -> a
forall a. Semigroup a => a -> a -> a
<> a
": " a -> a -> a
forall a. Semigroup a => a -> a -> a
<> PieceType -> a
forall p. (IsString p, Semigroup p) => PieceType -> p
argType PieceType
typ
getType :: RenderedPiece -> Maybe PieceType
getType (Path Text
_) = Maybe PieceType
forall a. Maybe a
Nothing
getType (Dyn PieceType
t) = PieceType -> Maybe PieceType
forall a. a -> Maybe a
Just PieceType
t
argType :: PieceType -> p
argType PieceType
NumberT = p
"number"
argType PieceType
StringT = p
"string"
argType (NonEmptyT PieceType
t) = p
"Array<" p -> p -> p
forall a. Semigroup a => a -> a -> a
<> PieceType -> p
argType PieceType
t p -> p -> p
forall a. Semigroup a => a -> a -> a
<> p
">"
body :: Text
body = Text
"return this.root + '" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Text] -> [RenderedPiece] -> Text
routeStr [Text]
variableNames [RenderedPiece]
cmPieces Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"'"
where
routeStr :: [Text] -> [RenderedPiece] -> Text
routeStr [Text]
vars (Path Text
p:[RenderedPiece]
rest) = (if Text -> CheckOverlap
forall mono. MonoFoldable mono => mono -> CheckOverlap
null Text
p then Text
"" else Text
"/" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
p) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Text] -> [RenderedPiece] -> Text
routeStr [Text]
vars [RenderedPiece]
rest
routeStr (Text
v:[Text]
vars) (Dyn PieceType
t:[RenderedPiece]
rest) = Text
"/' + " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Int -> PieceType -> Text
convert Text
v Int
0 PieceType
t Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" + '" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Text] -> [RenderedPiece] -> Text
routeStr [Text]
vars [RenderedPiece]
rest
routeStr [Text]
_ [RenderedPiece]
_ = Text
""
convert :: Text -> Int -> PieceType -> Text
convert Text
v Int
i PieceType
StringT = Text -> Int -> Text
name Text
v Int
i
convert Text
v Int
i PieceType
NumberT = Text -> Int -> Text
name Text
v Int
i Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
".toString()"
convert Text
v Int
i (NonEmptyT PieceType
t) =
[Text] -> Text
T.concat
[ Text -> Int -> Text
name Text
v Int
i
, Text
".map(function("
, Text -> Int -> Text
name Text
v (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
, Text
") { return "
, Text -> Int -> PieceType -> Text
convert Text
v (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) PieceType
t
, Text
" }).join(',')"
]
name :: Text -> Int -> Text
name :: Text -> Int -> Text
name Text
v Int
0 = Text
v
name Text
v Int
i = Text
v Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Element Text] -> Text
forall seq. IsSequence seq => [Element seq] -> seq
pack (Int -> String
forall a. Show a => a -> String
show Int
i)
classMemberToFlowInit :: ClassMember -> Text
classMemberToFlowInit :: ClassMember -> Text
classMemberToFlowInit ChildClass {Text
cmClassName :: Text
cmField :: Text
cmClassName :: ClassMember -> Text
cmField :: ClassMember -> Text
..} = Text
" this." Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
cmField Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" = new " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
cmClassName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"(root);\n"
classMemberToFlowInit Method {} = Text
""
classToFlow :: Class -> Text
classToFlow :: Class -> Text
classToFlow Class {[ClassMember]
Text
classMembers :: [ClassMember]
className :: Text
classMembers :: Class -> [ClassMember]
className :: Class -> Text
..} =
Text
"class " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
className Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" {\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Text] -> Element [Text]
forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
mono -> Element mono
concat (ClassMember -> Text
classMemberToFlowDef (ClassMember -> Text) -> [ClassMember] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [ClassMember]
classMembers)
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" root: string;\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" constructor(root: string) {\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" this.root = root;\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Text] -> Element [Text]
forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
mono -> Element mono
concat (ClassMember -> Text
classMemberToFlowInit (ClassMember -> Text) -> [ClassMember] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [ClassMember]
classMembers)
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" }\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"}\n"
classesToFlow :: [Class] -> Text
classesToFlow :: [Class] -> Text
classesToFlow = Element [Text] -> [Text] -> Element [Text]
forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
Element mono -> mono -> Element mono
intercalate Element [Text]
"\n" ([Text] -> Text) -> ([Class] -> [Text]) -> [Class] -> Text
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Class -> Text) -> [Class] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map Class -> Text
classToFlow
#if !MIN_VERSION_yesod_core(1, 6, 2)
deriving instance (Show a) => Show (ResourceTree a)
deriving instance (Show a) => Show (FlatResource a)
#endif