json-autotype-3.1.0: src/Data/Aeson/AutoType/Nested.hs
{-# language DeriveGeneric #-}
{-# language OverloadedStrings #-}
-- | Simple interface for using AutoType inference
-- in other code generators.
--
-- Simply takes a list of Aeson values,
-- and returns a type description.
--
-- For this type description,
-- we can use function to generate an entire new module.
--
-- Note that while we can put more code in the module,
-- it is recommended to avoid multiple automatically
-- generated types in order to avoid name conflicts.
module Data.Aeson.AutoType.Nested(
defaultImportedModules
, generateModuleImports
, inferType
, CodeFragment
, TypeName
, DeclaredType(..)
) where
import Data.Aeson
import Data.Aeson.AutoType.CodeGen.Haskell(generateModuleImports, requiredPackages, importedModules)
import Data.Aeson.AutoType.CodeGen.HaskellFormat(displaySplitTypes)
import Data.Aeson.AutoType.Extract(extractType, unifyTypes)
import Data.Aeson.AutoType.Split(splitTypeByLabel)
import Data.Default
import Data.Typeable
import Data.Text(Text)
import GHC.Generics
-- FIXME: general type to compose generated types
-- move to JSON Autotype as library interface?
-- * API Response Structures
type CodeFragment = Text
type TypeName = Text
type ImportedModule = Text
type PackageName = Text
-- | Type declaration and its requirements
-- Content to embed in an autogenerated module:
-- * name of the type to reference
-- * declarations to describe it
-- * module imports necessary for declarations
-- to work
data DeclaredType = DeclaredType
{
-- | Code fragment to be inserted in generated module
typeCodeFragment :: CodeFragment
-- | Toplevel type name to refer to
, typeName :: TypeName
-- | List of clauses to add to imports list
, typeImportedModules :: [ImportedModule]
-- | List of packages to add to generated package dependencies
, typePackages :: [PackageName]
}
deriving
( Eq
, Show
, Generic
, Typeable
)
instance Default DeclaredType where
-- Minimal placeholder to use in case we cannot infer proper type
def = DeclaredType {
typeCodeFragment = ""
, typeName = "Data.Aeson.Value"
, typeImportedModules = ["qualified Data.Aeson"]
, typePackages = ["aeson"]
}
-- | List of modules imported for Autotyped declarations
defaultImportedModules = importedModules
-- | Given intended type name, and a list of
-- text fields with JSON, return
-- either an error, or an `EndpointResponse`
-- that allows to declare and use this type
-- in generated module.
inferType :: Text -> [Value] -> DeclaredType
inferType typeName [] = def
inferType typeName jsonValues =
DeclaredType {
typeImportedModules = defaultImportedModules
, typeCodeFragment = displaySplitTypes splitTypeDescriptors
, typeName = typeName
, typePackages = requiredPackages
}
where
valueTypes = map extractType jsonValues
-- FIXME: should be <> in Typelike?
unifiedType = foldr1 unifyTypes valueTypes
splitTypeDescriptors = splitTypeByLabel typeName unifiedType