json-to-type-4.0.0: src/JsonToType/Nested.hs
{-# 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 JsonToType.Nested(
defaultImportedModules
, generateModuleImports
, inferType
, CodeFrag(..)
, TypeName
, TypeFrag
, ModuleImport
, PackageName
) where
import Data.Aeson
import JsonToType.CodeGen.Haskell(generateModuleImports, requiredPackages, importedModules, ModuleImport)
import JsonToType.CodeGen.HaskellFormat(displaySplitTypes)
import JsonToType.Extract(extractType, unifyTypes)
import JsonToType.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