{-# language DeriveGeneric #-} {-# language OverloadedStrings #-} {-# language TypeSynonymInstances #-} {-# language FlexibleInstances #-} -- | 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. -- -- NOTE: this interface is yet unstable module Data.Aeson.AutoType.Nested( defaultImportedModules , generateModuleImports , inferType , CodeFrag(..) , TypeName , TypeFrag , ModuleImport , PackageName ) where import Data.Aeson import Data.Aeson.AutoType.CodeGen.Haskell(generateModuleImports, requiredPackages, importedModules, ModuleImport) 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 Code = Text type TypeName = Text type PackageName = Text -- | Generated code reference and its requirements -- Content to embed in an autogenerated module: -- -- * name of the reference -- * declarations to describe it -- * module imports necessary for declarations -- to work data CodeFrag a = CodeFrag { -- | Code fragment to be inserted in generated module codeFragCode :: Code -- | Toplevel type name to refer to , codeFragName :: a -- | List of clauses to add to imports list , codeFragImports :: [ModuleImport] -- | List of packages to add to generated package dependencies , codeFragPackages :: [PackageName] } deriving ( Eq , Show , Generic , Typeable ) type TypeFrag = CodeFrag TypeName instance Default TypeFrag where -- Minimal placeholder to use in case we cannot infer proper type def = CodeFrag { codeFragCode = "" , codeFragName = "Data.Aeson.Value" , codeFragImports = ["qualified Data.Aeson"] , codeFragPackages = ["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] -> TypeFrag inferType typeName [] = def inferType typeName jsonValues = CodeFrag { codeFragImports = defaultImportedModules , codeFragCode = displaySplitTypes splitTypeDescriptors , codeFragName = typeName , codeFragPackages = requiredPackages } where valueTypes = map extractType jsonValues -- FIXME: should be <> in Typelike? unifiedType = foldr1 unifyTypes valueTypes splitTypeDescriptors = splitTypeByLabel typeName unifiedType