{-# 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