packages feed

domain-0.1.1.5: library/Domain/Resolvers/TypeCentricDoc.hs

module Domain.Resolvers.TypeCentricDoc where

import qualified Data.Text as Text
import qualified Domain.Models.TypeCentricDoc as Doc
import qualified Domain.Models.TypeString as TypeString
import Domain.Prelude hiding (lookup)
import qualified Domain.Text as Text
import DomainCore.Model

eliminateDoc :: (Applicative f) => Doc.Doc -> f [TypeDec]
eliminateDoc =
  traverse (uncurry (structureTypeDecs [])) >>> fmap join

structureTypeDecs :: (Applicative f) => [Text] -> Text -> Doc.Structure -> f [TypeDec]
structureTypeDecs namespace name structure =
  (:) <$> primary <*> structureGeneratedTypeDecs nextNamespace structure
  where
    primary =
      TypeDec renderedName <$> structureTypeDef nextNamespace structure
      where
        renderedName =
          Text.concat (reverse nextNamespace)
    nextNamespace =
      name : namespace

structureGeneratedTypeDecs :: (Applicative f) => [Text] -> Doc.Structure -> f [TypeDec]
structureGeneratedTypeDecs namespace =
  \case
    Doc.ProductStructure structure ->
      traverse (uncurry (nestedTypeExpressionTypeDecs namespace . Text.ucFirst)) structure
        & fmap join
    Doc.SumStructure structure ->
      traverse (\(a, b) -> traverse (nestedTypeExpressionTypeDecs namespace (Text.ucFirst a)) b) structure
        & fmap (join . join)
    _ ->
      pure []

nestedTypeExpressionTypeDecs :: (Applicative f) => [Text] -> Text -> Doc.NestedTypeExpression -> f [TypeDec]
nestedTypeExpressionTypeDecs namespace name =
  \case
    Doc.StructureNestedTypeExpression a ->
      structureTypeDecs namespace name a
    _ ->
      pure []

structureTypeDef :: (Applicative f) => [Text] -> Doc.Structure -> f TypeDef
structureTypeDef namespace =
  \case
    Doc.ProductStructure structure ->
      ProductTypeDef <$> traverse (uncurry (eliminateProductStructureUnit namespace)) structure
    Doc.SumStructure structure ->
      SumTypeDef <$> traverse (uncurry (eliminateSumStructureUnit namespace)) structure
    Doc.EnumStructure variants ->
      pure (SumTypeDef (fmap (,[]) variants))

eliminateProductStructureUnit :: (Applicative f) => [Text] -> Text -> Doc.NestedTypeExpression -> f (Text, Type)
eliminateProductStructureUnit namespace name productTypeExpression =
  (,) name <$> nestedTypeExpressionType namespace name productTypeExpression

eliminateSumStructureUnit :: (Applicative f) => [Text] -> Text -> [Doc.NestedTypeExpression] -> f (Text, [Type])
eliminateSumStructureUnit namespace name sumTypeExpression =
  (,) name <$> traverse (nestedTypeExpressionType namespace name) sumTypeExpression

nestedTypeExpressionType :: (Applicative f) => [Text] -> Text -> Doc.NestedTypeExpression -> f Type
nestedTypeExpressionType namespace name =
  \case
    Doc.AppSeqNestedTypeExpression a ->
      AppType <$> eliminateTypeStringAppSeq a
    Doc.StructureNestedTypeExpression _ ->
      pure (RefType (Text.concat (reverse (Text.ucFirst name : namespace))))

eliminateTypeStringCommaSeq :: (Traversable t, Applicative f) => t (NonEmpty TypeString.Unit) -> f (t (NonEmpty Type))
eliminateTypeStringCommaSeq =
  traverse eliminateTypeStringAppSeq

eliminateTypeStringAppSeq :: (Applicative f) => NonEmpty TypeString.Unit -> f (NonEmpty Type)
eliminateTypeStringAppSeq =
  traverse eliminateTypeStringUnit

eliminateTypeStringUnit :: (Applicative f) => TypeString.Unit -> f Type
eliminateTypeStringUnit =
  \case
    TypeString.InSquareBracketsUnit appSeq ->
      eliminateTypeStringAppSeq appSeq
        & fmap (ListType . AppType)
    TypeString.InParensUnit commaSeq ->
      eliminateTypeStringCommaSeq commaSeq
        & fmap (tupleIfNotOne . fmap AppType)
      where
        tupleIfNotOne =
          \case
            [a] -> a
            a -> TupleType a
    TypeString.RefUnit typeRef ->
      eliminateTypeRef typeRef
        & fmap RefType

eliminateTypeRef :: (Applicative f) => NonEmpty Text -> f Text
eliminateTypeRef =
  pure . Text.intercalate "." . toList