-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | DSL for generating API boilerplate and docs -- -- api-tools provides a compact DSL for describing an API. It uses -- Template Haskell to generate the corresponding data types and assorted -- tools for working with it, including Aeson and QuickCheck instances -- for converting between JSON and the generated types and writing unit -- tests. @package api-tools @version 0.8.0.1 module Data.Binary.Serialise.CBOR.JSON cborToJson :: Term -> Value jsonToCbor :: Value -> Term encodeJSON :: Value -> Encoding decodeJSON :: Decoder s Value instance Codec.Serialise.Class.Serialise Data.Aeson.Types.Internal.Value module Data.Binary.Serialise.CBOR.Extra encodeListWith :: (a -> Encoding) -> [a] -> Encoding encodeMaybeWith :: (a -> Encoding) -> Maybe a -> Encoding encodeRecordFields :: [Encoding] -> Encoding -- | Encode an element of a union as single-element map from a field name -- to a value. encodeUnion :: Text -> Encoding -> Encoding decodeUnion :: [(Text, Decoder s a)] -> Decoder s a decodeListWith :: Decoder s a -> Decoder s [a] decodeMaybeWith :: Decoder s a -> Decoder s (Maybe a) -- | Strict version of <$>. (<$!>) :: Monad m => (a -> b) -> m a -> m b infixl 4 <$!> module Data.API.Utils mkUTC :: UTCTime -> Value mkUTC' :: UTCTime -> Text mkUTC_ :: UTCTime -> String parseUTC' :: Text -> Maybe UTCTime parseUTC_ :: String -> Maybe UTCTime -- | The "oh noes!" operator. (?!) :: Maybe a -> e -> Either e a (?!?) :: Either e a -> (e -> e') -> Either e' a data MergeResult a b OnlyInLeft :: a -> MergeResult a b InBoth :: a -> b -> MergeResult a b OnlyInRight :: b -> MergeResult a b mergeMaps :: Ord k => Map k a -> Map k b -> Map k (MergeResult a b) diffMaps :: (Eq a, Ord k) => Map k a -> Map k a -> Map k (MergeResult a a) -- | Attempts to match the keys of the maps to produce a map from keys to -- pairs. matchMaps :: Ord k => Map k a -> Map k b -> Either (k, Either a b) (Map k (a, b)) instance (GHC.Show.Show b, GHC.Show.Show a) => GHC.Show.Show (Data.API.Utils.MergeResult a b) instance (GHC.Classes.Eq b, GHC.Classes.Eq a) => GHC.Classes.Eq (Data.API.Utils.MergeResult a b) module Data.API.Types -- | an API spec is made up of a list of type/element specs, each -- specifying a Haskell type and JSON wrappers type API = [Thing] data Thing ThComment :: MDComment -> Thing ThNode :: APINode -> Thing -- | Specifies an individual element/type of the API data APINode APINode :: TypeName -> MDComment -> Prefix -> Spec -> Conversion -> APINode -- | name of Haskell type [anName] :: APINode -> TypeName -- | comment describing type in Markdown [anComment] :: APINode -> MDComment -- | distinct short prefix (see below) [anPrefix] :: APINode -> Prefix -- | the type specification [anSpec] :: APINode -> Spec -- | optional conversion functions [anConvert] :: APINode -> Conversion -- | TypeName must contain a valid Haskell type constructor newtype TypeName TypeName :: Text -> TypeName [_TypeName] :: TypeName -> Text -- | FieldName identifies recod fields and union alternatives must contain -- a valid identifier valid in Haskell and any API client wrappers (e.g., -- if Ruby wrappers are to be generated the names should easily map into -- Ruby) newtype FieldName FieldName :: Text -> FieldName [_FieldName] :: FieldName -> Text -- | Markdown comments are represented by strings type MDComment = String -- | a distinct case-insensitive short prefix used to form unique record -- field names and data constructors: -- -- type Prefix = CI String -- | type/element specs are either simple type isomorphisms of basic JSON -- types, records, unions or enumerated types data Spec SpNewtype :: SpecNewtype -> Spec SpRecord :: SpecRecord -> Spec SpUnion :: SpecUnion -> Spec SpEnum :: SpecEnum -> Spec SpSynonym :: APIType -> Spec -- | SpecNewtype elements are isomorphisms of string, inetgers or booleans data SpecNewtype SpecNewtype :: BasicType -> Maybe Filter -> SpecNewtype [snType] :: SpecNewtype -> BasicType [snFilter] :: SpecNewtype -> Maybe Filter -- | SpecRecord is your classsic product type. data SpecRecord SpecRecord :: [(FieldName, FieldType)] -> SpecRecord [srFields] :: SpecRecord -> [(FieldName, FieldType)] -- | In addition to the type and comment, record fields may carry a flag -- indicating that they are read-only, and may have a default value, -- which must be of a compatible type. data FieldType FieldType :: APIType -> Bool -> Maybe DefaultValue -> MDComment -> FieldType [ftType] :: FieldType -> APIType [ftReadOnly] :: FieldType -> Bool [ftDefault] :: FieldType -> Maybe DefaultValue [ftComment] :: FieldType -> MDComment -- | SpecUnion is your classsic union type data SpecUnion SpecUnion :: [(FieldName, (APIType, MDComment))] -> SpecUnion [suFields] :: SpecUnion -> [(FieldName, (APIType, MDComment))] -- | SpecEnum is your classic enumerated type data SpecEnum SpecEnum :: [(FieldName, MDComment)] -> SpecEnum [seAlts] :: SpecEnum -> [(FieldName, MDComment)] -- | Conversion possibly converts to an internal representation. If -- specified, a conversion is a pair of an injection function name and a -- projection function name. type Conversion = Maybe (FieldName, FieldName) -- | Type is either a list, Maybe, a named element of the API or a basic -- type data APIType -- | list elements are types TyList :: APIType -> APIType -- | Maybe elements are types TyMaybe :: APIType -> APIType -- | the referenced type must be defined by the API TyName :: TypeName -> APIType -- | a JSON string, int, bool etc. TyBasic :: BasicType -> APIType -- | a generic JSON value TyJSON :: APIType -- | A default value for a field data DefaultValue DefValList :: DefaultValue DefValMaybe :: DefaultValue DefValString :: Text -> DefaultValue DefValBool :: Bool -> DefaultValue DefValInt :: Int -> DefaultValue DefValUtc :: UTCTime -> DefaultValue -- | the basic JSON types (N.B., no floating point numbers, yet) data BasicType -- | a JSON UTF-8 string BTstring :: BasicType -- | a base-64-encoded byte string BTbinary :: BasicType -- | a JSON bool BTbool :: BasicType -- | a JSON integral number BTint :: BasicType -- | a JSON UTC string BTutc :: BasicType data Filter FtrStrg :: RegEx -> Filter FtrIntg :: IntRange -> Filter FtrUTC :: UTCRange -> Filter data IntRange IntRange :: Maybe Int -> Maybe Int -> IntRange [ir_lo] :: IntRange -> Maybe Int [ir_hi] :: IntRange -> Maybe Int data UTCRange UTCRange :: Maybe UTCTime -> Maybe UTCTime -> UTCRange [ur_lo] :: UTCRange -> Maybe UTCTime [ur_hi] :: UTCRange -> Maybe UTCTime data RegEx RegEx :: Text -> Regex -> RegEx [re_text] :: RegEx -> Text [re_regex] :: RegEx -> Regex -- | Binary data is represented in JSON format as a base64-encoded string newtype Binary Binary :: ByteString -> Binary [_Binary] :: Binary -> ByteString -- | Convert a default value to an Aeson Value. This differs from -- toJSON as it will not round-trip with fromJSON: UTC -- default values are turned into strings. defaultValueAsJsValue :: DefaultValue -> Value mkRegEx :: Text -> RegEx inIntRange :: Int -> IntRange -> Bool inUTCRange :: UTCTime -> UTCRange -> Bool base64ToBinary :: Text -> Either String Binary instance Data.Aeson.Types.ToJSON.ToJSON s0 => Data.Aeson.Types.ToJSON.ToJSON (Data.CaseInsensitive.Internal.CI s0) instance Data.Aeson.Types.FromJSON.FromJSON s0 => Data.Aeson.Types.FromJSON.FromJSON (Data.CaseInsensitive.Internal.CI s0) instance Language.Haskell.TH.Syntax.Lift Data.API.Types.Thing instance Language.Haskell.TH.Syntax.Lift Data.API.Types.APINode instance Language.Haskell.TH.Syntax.Lift Data.API.Types.TypeName instance Language.Haskell.TH.Syntax.Lift Data.API.Types.FieldName instance Language.Haskell.TH.Syntax.Lift Data.API.Types.Spec instance Language.Haskell.TH.Syntax.Lift Data.API.Types.SpecNewtype instance Language.Haskell.TH.Syntax.Lift Data.API.Types.Filter instance Language.Haskell.TH.Syntax.Lift Data.API.Types.IntRange instance Language.Haskell.TH.Syntax.Lift Data.API.Types.UTCRange instance Language.Haskell.TH.Syntax.Lift Data.API.Types.RegEx instance Language.Haskell.TH.Syntax.Lift Data.API.Types.SpecRecord instance Language.Haskell.TH.Syntax.Lift Data.API.Types.FieldType instance Language.Haskell.TH.Syntax.Lift Data.API.Types.SpecUnion instance Language.Haskell.TH.Syntax.Lift Data.API.Types.SpecEnum instance Language.Haskell.TH.Syntax.Lift Data.API.Types.APIType instance Language.Haskell.TH.Syntax.Lift Data.API.Types.BasicType instance Language.Haskell.TH.Syntax.Lift Data.API.Types.DefaultValue instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.BasicType instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.BasicType instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.UTCRange instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.UTCRange instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.IntRange instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.IntRange instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.Filter instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.Filter instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.SpecNewtype instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.SpecNewtype instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.FieldType instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.FieldType instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.SpecRecord instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.SpecRecord instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.SpecUnion instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.SpecUnion instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.SpecEnum instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.SpecEnum instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.DefaultValue instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.DefaultValue instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.APIType instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.APIType instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.Spec instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.Spec instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.FieldName instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.FieldName instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.TypeName instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.TypeName instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.APINode instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.APINode instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.Thing instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.Thing instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.Types.Binary instance Codec.Serialise.Class.Serialise Data.API.Types.Binary instance Control.DeepSeq.NFData Data.API.Types.Binary instance GHC.Classes.Ord Data.API.Types.Binary instance GHC.Classes.Eq Data.API.Types.Binary instance GHC.Show.Show Data.API.Types.Binary instance GHC.Show.Show Data.API.Types.Thing instance GHC.Classes.Eq Data.API.Types.Thing instance GHC.Show.Show Data.API.Types.APINode instance GHC.Classes.Eq Data.API.Types.APINode instance GHC.Show.Show Data.API.Types.Spec instance GHC.Classes.Eq Data.API.Types.Spec instance GHC.Show.Show Data.API.Types.SpecRecord instance GHC.Classes.Eq Data.API.Types.SpecRecord instance GHC.Show.Show Data.API.Types.FieldType instance GHC.Classes.Eq Data.API.Types.FieldType instance GHC.Show.Show Data.API.Types.DefaultValue instance GHC.Classes.Eq Data.API.Types.DefaultValue instance GHC.Show.Show Data.API.Types.SpecNewtype instance GHC.Classes.Eq Data.API.Types.SpecNewtype instance GHC.Show.Show Data.API.Types.SpecUnion instance GHC.Classes.Eq Data.API.Types.SpecUnion instance GHC.Show.Show Data.API.Types.APIType instance GHC.Classes.Eq Data.API.Types.APIType instance GHC.Show.Show Data.API.Types.BasicType instance GHC.Classes.Eq Data.API.Types.BasicType instance GHC.Show.Show Data.API.Types.SpecEnum instance GHC.Classes.Eq Data.API.Types.SpecEnum instance GHC.Show.Show Data.API.Types.Filter instance GHC.Classes.Eq Data.API.Types.Filter instance GHC.Show.Show Data.API.Types.UTCRange instance GHC.Classes.Eq Data.API.Types.UTCRange instance GHC.Show.Show Data.API.Types.IntRange instance GHC.Classes.Eq Data.API.Types.IntRange instance Data.String.IsString Data.API.Types.FieldName instance Control.DeepSeq.NFData Data.API.Types.FieldName instance GHC.Show.Show Data.API.Types.FieldName instance GHC.Classes.Ord Data.API.Types.FieldName instance GHC.Classes.Eq Data.API.Types.FieldName instance Data.String.IsString Data.API.Types.TypeName instance Control.DeepSeq.NFData Data.API.Types.TypeName instance GHC.Show.Show Data.API.Types.TypeName instance GHC.Classes.Ord Data.API.Types.TypeName instance GHC.Classes.Eq Data.API.Types.TypeName instance Control.DeepSeq.NFData Data.API.Types.Thing instance Control.DeepSeq.NFData Data.API.Types.APINode instance Control.DeepSeq.NFData Data.API.Types.Spec instance Control.DeepSeq.NFData Data.API.Types.SpecNewtype instance Control.DeepSeq.NFData Data.API.Types.Filter instance Control.DeepSeq.NFData Data.API.Types.IntRange instance Control.DeepSeq.NFData Data.API.Types.UTCRange instance Control.DeepSeq.NFData Data.API.Types.RegEx instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.RegEx instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.RegEx instance GHC.Classes.Eq Data.API.Types.RegEx instance GHC.Show.Show Data.API.Types.RegEx instance Control.DeepSeq.NFData Data.API.Types.SpecRecord instance Control.DeepSeq.NFData Data.API.Types.FieldType instance Control.DeepSeq.NFData Data.API.Types.SpecUnion instance Control.DeepSeq.NFData Data.API.Types.SpecEnum instance Data.String.IsString Data.API.Types.APIType instance Control.DeepSeq.NFData Data.API.Types.APIType instance Control.DeepSeq.NFData Data.API.Types.BasicType instance Control.DeepSeq.NFData Data.API.Types.DefaultValue instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Types.Binary instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Types.Binary instance Test.QuickCheck.Arbitrary.Arbitrary Data.Text.Internal.Text instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.Types.Binary module Data.API.Tools.Combinators -- | A Tool a is something that can generate TH -- declarations from a value of type a. Tools can be combined -- using the Monoid instance. data Tool a type APITool = Tool API type APINodeTool = Tool APINode -- | Execute a tool to generate some TH declarations. runTool :: Tool a -> ToolSettings -> a -> Q [Dec] -- | Construct a tool that does not depend on any settings simpleTool :: (a -> Q [Dec]) -> Tool a -- | Construct a tool that may depend on the settings mkTool :: (ToolSettings -> a -> Q [Dec]) -> Tool a -- | Tool is a contravariant functor contramapTool :: (a -> b) -> Tool b -> Tool a -- | Make a tool that reads its argument to decide what to do readTool :: (a -> Tool a) -> Tool a -- | Apply a tool that acts on elements of a list to the entire list subTools :: Tool a -> Tool [a] -- | Apply a tool that acts on nodes to an entire API apiNodeTool :: Tool APINode -> Tool API -- | Apply a tool that acts on datatype nodes (i.e. those that are not -- synonyms) to an entire API apiDataTypeTool :: Tool APINode -> Tool API -- | Create a tool that acts on nodes from its action on individual specs. apiSpecTool :: Tool (APINode, SpecNewtype) -> Tool (APINode, SpecRecord) -> Tool (APINode, SpecUnion) -> Tool (APINode, SpecEnum) -> Tool (APINode, APIType) -> Tool APINode -- | Settings to control the behaviour of API tools. This record may be -- extended in the future, so you should construct a value by overriding -- individual fields of defaultToolSettings. data ToolSettings -- | Generate a warning when an instance declaration is omitted because it -- already exists warnOnOmittedInstance :: ToolSettings -> Bool -- | Rename the constructors of filtered newtypes and generate smart -- constructors that enforce the invariants newtypeSmartConstructors :: ToolSettings -> Bool -- | Default settings designed to be overridden. defaultToolSettings :: ToolSettings instance GHC.Base.Monoid (Data.API.Tools.Combinators.Tool a) -- | This module defines some utilities for working with Template Haskell, -- which may be useful for defining Tools, but should be -- considered internal implementation details of this package. module Data.API.TH -- | Construct an idiomatic expression (an expression in an Applicative -- context), i.e. -- --
--   app ke []             = ke
--   app ke [e1,e2,...,en] = ke <$> e1 <*> e2 ... <*> en
--   
applicativeE :: ExpQ -> [ExpQ] -> ExpQ -- | Add an instance declaration for a class, if such an instance does not -- already exist optionalInstanceD :: ToolSettings -> Name -> [TypeQ] -> [DecQ] -> Q [Dec] -- | Construct a TH function with a type signature funSigD :: Name -> TypeQ -> [ClauseQ] -> Q [Dec] -- | Construct a simple TH definition simpleD :: Name -> ExpQ -> Q Dec -- | Construct a simple TH definition with a type signature simpleSigD :: Name -> TypeQ -> ExpQ -> Q [Dec] mkNameText :: Text -> Name -- | Field name as a string expression fieldNameE :: FieldName -> ExpQ -- | Field name as a variable fieldNameVarE :: FieldName -> ExpQ typeNameE :: TypeName -> ExpQ module Data.API.Tools.Datatypes -- | Tool to generate datatypes and type synonyms corresponding to an API datatypesTool :: APITool -- | Tool to generate datatypes and type synonyms corresponding to an API, -- where the function specifies the derived classes for each datatype. datatypesTool' :: (APINode -> [Name]) -> APITool -- | Default names of classes for which to derive instances, depending on -- the type of API node. defaultDerivedClasses :: APINode -> [Name] -- | Name of the type corresponding to the API node, e.g. JobId type_nm :: APINode -> Name -- | Name of the representation type corresponding to the API node, which -- differs from the type_nm only if custom conversion functions -- are specified. This is also the name of the sole constructor for -- newtypes and records. rep_type_nm :: APINode -> Name -- | The type corresponding to an API node nodeT :: APINode -> TypeQ -- | The representation type corresponding to an API node nodeRepT :: APINode -> TypeQ -- | The constructor for a record API node nodeConE :: APINode -> ExpQ -- | The constructor for a newtype, which might be renamed nodeNewtypeConE :: ToolSettings -> APINode -> SpecNewtype -> ExpQ -- | A record field in an API node, as an expression nodeFieldE :: APINode -> FieldName -> ExpQ -- | A record field in an API node, as a pattern nodeFieldP :: APINode -> FieldName -> PatQ -- | A prefixed constructor for a union or enum, as an expression nodeAltConE :: APINode -> FieldName -> ExpQ -- | A prefixed constructor for a union or enum, as a pattern nodeAltConP :: APINode -> FieldName -> [PatQ] -> PatQ -- | The projection function from a newtype API node, as an epxression newtypeProjectionE :: APINode -> ExpQ module Data.API.Tools.Lens -- | Tool to make lenses for fields in generated types. lensTool :: APITool binary :: Iso' Binary ByteString module Data.API.Tools.SafeCopy -- | Tool to derive SafeCopy instances for generated types. At -- present, this derives only base version instances. safeCopyTool :: APITool module Data.API.Tools.DeepSeq -- | Tool to generate NFData instances for generated types. deepSeqTool :: APITool -- | A tool to generate maps to and from Text values corresponding -- to inhabitants of enumerated types module Data.API.Tools.Enum -- | Tool to generate the maps between enumerations and Text -- strings named by text_enum_nm and map_enum_nm. enumTool :: APITool -- | For an enum type E, name a function _text_E :: E -> -- Text that gives a string corresponding to the inhabitant -- of the type. For example, we generate something like this: -- --
--   _text_FrameRate :: FrameRate -> T.Text
--   _text_FrameRate fr =
--           case fr of
--             FRauto    -> "auto"
--             FR10      -> "10"
--             FR15      -> "15"
--             FR23_97   -> "23.97"
--             FR24      -> "24"
--             FR25      -> "25"
--             FR29_97   -> "29.97"
--             FR30      -> "30"
--             FR60      -> "60"
--   
text_enum_nm :: APINode -> Name -- | For an enum type E, name a map from Text values to -- inhabitants of the type, for example: -- --
--   _map_FrameRate :: Map Text FrameRate
--   _map_FrameRate = genTextMap _text_FrameRate
--   
map_enum_nm :: APINode -> Name module Data.API.Tools.CBOR -- | Tool to generate Serialise instances for types generated by -- datatypesTool. This depends on enumTool. cborTool :: APITool -- | Tool for generating documentation-friendly examples module Data.API.Tools.Example -- | The Example class is used to generate a documentation-friendly example -- for each type in the model class Example a where example = arbitrary -- | Generator for example values; defaults to arbitrary if not -- specified example :: Example a => Gen a -- | Generator for example values; defaults to arbitrary if not -- specified example :: (Example a, Arbitrary a) => Gen a -- | Tool to generate Example instances for types generated by -- datatypesTool. This depends on quickCheckTool. exampleTool :: APITool -- | Generate a list of (type name, sample generator) pairs corresponding -- to each type in the API, with samples encoded as JSON. This depends on -- the Example instances generated by exampleTool. It -- generates something like this: -- --
--   samples :: [(String, Gen Value)]
--   samples = [("Foo", fmap toJSON (example :: Gen Foo)), ... ]
--   
samplesTool :: Name -> APITool instance Data.API.Tools.Example.Example a => Data.API.Tools.Example.Example (GHC.Base.Maybe a) instance Data.API.Tools.Example.Example a => Data.API.Tools.Example.Example [a] instance Data.API.Tools.Example.Example GHC.Types.Int instance Data.API.Tools.Example.Example GHC.Types.Bool instance Data.API.Tools.Example.Example Data.Text.Internal.Text instance Data.API.Tools.Example.Example Data.API.Types.Binary instance Data.API.Tools.Example.Example Data.Aeson.Types.Internal.Value instance Data.API.Tools.Example.Example Data.Time.Clock.UTC.UTCTime module Data.API.Tools.QuickCheck -- | Tool to generate Arbitrary instances for generated types. quickCheckTool :: APITool instance Test.QuickCheck.Arbitrary.Arbitrary Data.Time.Clock.UTC.UTCTime -- | A cheap and cheerful pretty-printing library module Data.API.PP class PP t pp :: PP t => t -> String class PPLines t ppLines :: PPLines t => t -> [String] inFrontOf :: String -> [String] -> [String] indent :: [String] -> [String] instance Data.API.PP.PP [GHC.Types.Char] instance Data.API.PP.PP Data.Version.Version instance Data.API.PP.PP t => Data.API.PP.PP (Data.Set.Base.Set t) instance Data.API.PP.PP Data.Text.Internal.Text instance Data.API.PP.PPLines Data.Aeson.Types.Internal.Value instance Data.API.PP.PP Data.API.Types.TypeName instance Data.API.PP.PP Data.API.Types.FieldName instance Data.API.PP.PP Data.API.Types.APIType instance Data.API.PP.PP Data.API.Types.BasicType instance Data.API.PP.PP Data.API.Types.DefaultValue instance Data.API.PP.PPLines t => Data.API.PP.PPLines [t] instance (Data.API.PP.PPLines s, Data.API.PP.PPLines t) => Data.API.PP.PPLines (s, t) -- | This module defines a normalised representation of APIs, used for -- comparing them in the migrations changelog, and to analyse -- dependencies. module Data.API.NormalForm -- | The API type has too much extra info for us to be able to simply -- compare them with (==). Our strategy is to strip out -- ancillary information and normalise into a canonical form, and then we -- can use a simple (==) compare. -- -- Our normalised API discards most of the details of each type, keeping -- just essential information about each type. We discard order of types -- and fields, so we can use just associative maps. type NormAPI = Map TypeName NormTypeDecl -- | The normal or canonical form for a type declaration, an -- APINode. Equality of the normal form indicates equivalence of -- APIs. -- -- We track all types. data NormTypeDecl NRecordType :: NormRecordType -> NormTypeDecl NUnionType :: NormUnionType -> NormTypeDecl NEnumType :: NormEnumType -> NormTypeDecl NTypeSynonym :: APIType -> NormTypeDecl NNewtype :: BasicType -> NormTypeDecl -- | The canonical form of a record type is a map from fields to values... type NormRecordType = Map FieldName APIType -- | ...similarly a union is a map from fields to alternatives... type NormUnionType = Map FieldName APIType -- | ...and an enum is a set of values. type NormEnumType = Set FieldName -- | Compute the normal form of an API, discarding extraneous information. apiNormalForm :: API -> NormAPI -- | Compute the normal form of a single type declaration. declNF :: Spec -> NormTypeDecl -- | Find the set of type names used in an API typeDeclsFreeVars :: NormAPI -> Set TypeName -- | Find the set of type names used in a declaration typeDeclFreeVars :: NormTypeDecl -> Set TypeName -- | Find the set of type names used in an type typeFreeVars :: APIType -> Set TypeName -- | Check if a type is declared in the API typeDeclaredInApi :: TypeName -> NormAPI -> Bool -- | Check if a type is used anywhere in the API typeUsedInApi :: TypeName -> NormAPI -> Bool -- | Check if the first type's transitive dependencies include the second -- type typeUsedInTransitiveDep :: TypeName -> TypeName -> NormAPI -> Bool -- | Compute the transitive dependencies of a set of types transitiveDeps :: NormAPI -> Set TypeName -> Set TypeName -- | Compute the set of types that depend (transitively) on the given types transitiveReverseDeps :: NormAPI -> Set TypeName -> Set TypeName -- | Test that all the types used in the API are declared. If not, return -- the set of undeclared types. apiInvariant :: NormAPI -> Either (Set TypeName) () -- | Test that all the types used in a type declaration are declared in the -- API. If not, return the set of undeclared types. declIsValid :: NormTypeDecl -> NormAPI -> Either (Set TypeName) () -- | Test that all the free type names in a type are declared in the API. -- If not, return the set of undeclared types. typeIsValid :: APIType -> NormAPI -> Either (Set TypeName) () -- | Substitute types for type names in a declaration substTypeDecl :: (TypeName -> APIType) -> NormTypeDecl -> NormTypeDecl -- | Substitute types for type names in a type substType :: (TypeName -> APIType) -> APIType -> APIType -- | Rename the first type to the second throughout the API renameTypeUses :: TypeName -> TypeName -> NormAPI -> NormAPI instance GHC.Show.Show Data.API.NormalForm.NormTypeDecl instance GHC.Classes.Eq Data.API.NormalForm.NormTypeDecl instance Control.DeepSeq.NFData Data.API.NormalForm.NormTypeDecl instance Data.API.PP.PPLines Data.API.NormalForm.NormTypeDecl module Data.API.Tools.Traversal -- | Build a traversal of the root type (first argument) that updates -- values of the second type, e.g. traversalTool Root -- Sub produces -- --
--   traverseSubRoot :: Applicative f => (Sub -> f Sub) -> Root -> f Root
--   
-- -- along with similar functions for all the types nested inside -- Root that depend on Sub. -- -- Note that types with custom representations will not have traversals -- generated automatically: if required, these must be defined manually -- in the same module as the call to traversalTool, otherwise the -- generated code will lead to scope errors. traversalTool :: TypeName -> TypeName -> APITool -- | This module generates Markdown-formatted documentation for an API, -- like this: -- --
--   ### Foo
--   
--   a test defn
--   
--   JSON Type : **union object** (Haskell prefix is 'foo')
--   
--   | Alternative | Type    | Comment
--   | ----------- | ------- | -----------
--   | _`Baz`_     | boolean | just a bool
--   | _`Qux`_     | integer | just an int
--   
module Data.API.Markdown -- | Create human-readable API documentation in Markdown format markdown :: MarkdownMethods -> API -> MDComment data MarkdownMethods MDM :: (TypeName -> MDComment) -> (TypeName -> MDComment) -> (MDComment -> MDComment -> MDComment) -> (FieldName -> APIType -> Maybe DefaultValue) -> MarkdownMethods [mdmSummaryPostfix] :: MarkdownMethods -> TypeName -> MDComment [mdmLink] :: MarkdownMethods -> TypeName -> MDComment [mdmPp] :: MarkdownMethods -> MDComment -> MDComment -> MDComment [mdmFieldDefault] :: MarkdownMethods -> FieldName -> APIType -> Maybe DefaultValue defaultMarkdownMethods :: MarkdownMethods -- | Document a single API comment or node in Markdown format thing :: MarkdownMethods -> Thing -> MDComment -> MDComment module Data.API.Doc.Subst type Dict = Map String String subst :: Dict -> String -> String prep :: Dict -> [String] -> String mkDict :: [(String, String)] -> Dict extDict :: [(String, String)] -> Dict -> Dict module Data.API.Doc -- | Generate a web page documenting a Call callHtml :: DocInfo -> Dict -> Call -> String -- | Generate a web page documenting all the Calls in a web -- application dirHtml :: DocInfo -> Dict -> [Call] -> String -- | Documents a single method call on a resource in a web application data Call Call :: HTTPMethod -> [String] -> String -> Bool -> [Header] -> Maybe (APIType, String) -> [Param] -> [View] -> [Sample] -> Call -- | HTTP method being documented [call_http_method] :: Call -> HTTPMethod -- | Relative URL path of the resource [call_path] :: Call -> [String] -- | Free-form text description [call_description] :: Call -> String -- | Does the call require authentication? [call_auth_required] :: Call -> Bool -- | HTTP headers relevant to the call [call_headers] :: Call -> [Header] -- | Type and example of request body [call_body] :: Call -> Maybe (APIType, String) -- | Query parameters relevant to the call [call_params] :: Call -> [Param] -- | Available views of the result data [call_views] :: Call -> [View] -- | Example responses [call_samples] :: Call -> [Sample] -- | Documents a HTTP header that may be supplied to a Call data Header Header :: String -> String -> String -> APIType -> Bool -> Header -- | Header name [header_name] :: Header -> String -- | Example value for header [header_expl] :: Header -> String -- | Free-form text description [header_desc] :: Header -> String -- | Type of data in header [header_type] :: Header -> APIType -- | Is including the header with the request mandatory? [header_required] :: Header -> Bool -- | Documents a URL query parameter that may be included with a -- Call data Param Param :: String -> String -> String -> Either String APIType -> Bool -> Param -- | Parameter name [param_name] :: Param -> String -- | Example value for parameter [param_expl] :: Param -> String -- | Free-form text description [param_desc] :: Param -> String -- | Type of data in the parameter [param_type] :: Param -> Either String APIType -- | Is including the parameter mandatory? [param_required] :: Param -> Bool -- | Documents a specific view of the result data available in a -- Call data View View :: String -> APIType -> String -> [Param] -> View -- | View name [view_id] :: View -> String -- | Type of result data returned [view_type] :: View -> APIType -- | Free-form text description [view_doc] :: View -> String -- | Query parameters that may be supplied for this view [view_params] :: View -> [Param] -- | Example response data from a Call data Sample Sample :: StatusCode -> Body APIType -> Maybe String -> Sample -- | HTTP status code for this example response [sample_status] :: Sample -> StatusCode -- | Type of example response [sample_type] :: Sample -> Body APIType -- | Content of response, or Nothing for empty response [sample_response] :: Sample -> Maybe String -- | Type for Sample response body, parameterised by possible JSON -- types data Body t -- | An empty response EmptyBody :: Body t -- | A JSON response of the given type JSONBody :: t -> Body t -- | A non-empty, non-JSON response OtherBody :: String -> Body t -- | Record of arguments that must be supplied to generate HTML -- documentation for a Call data DocInfo DocInfo :: (HTTPMethod -> [String] -> URL) -> (TypeName -> URL) -> DocInfo -- | URL for individual call documentation from the index [doc_info_call_url] :: DocInfo -> HTTPMethod -> [String] -> URL -- | URL for documentation of an API type [doc_info_type_url] :: DocInfo -> TypeName -> URL type URL = String type HTTPMethod = String type StatusCode = Int renderAPIType :: DocInfo -> APIType -> String renderBodyType :: DocInfo -> Body APIType -> String mk_link :: URL -> String -> String module Data.API.Changes.Types type APIWithChangelog = (API, APIChangelog) -- | An API changelog, consisting of a list of versions with the changes -- from one version to the next. The versions must be in descending order -- (according to the Ord Version instance). data APIChangelog -- | The changes from the previous version up to this version. ChangesUpTo :: VersionExtra -> [APIChange] -> APIChangelog -> APIChangelog -- | The initial version ChangesStart :: Version -> APIChangelog -- | A single change within a changelog data APIChange ChAddType :: TypeName -> NormTypeDecl -> APIChange ChDeleteType :: TypeName -> APIChange ChRenameType :: TypeName -> TypeName -> APIChange ChAddField :: TypeName -> FieldName -> APIType -> (Maybe DefaultValue) -> APIChange ChDeleteField :: TypeName -> FieldName -> APIChange ChRenameField :: TypeName -> FieldName -> FieldName -> APIChange ChChangeField :: TypeName -> FieldName -> APIType -> MigrationTag -> APIChange ChAddUnionAlt :: TypeName -> FieldName -> APIType -> APIChange ChDeleteUnionAlt :: TypeName -> FieldName -> APIChange ChRenameUnionAlt :: TypeName -> FieldName -> FieldName -> APIChange ChAddEnumVal :: TypeName -> FieldName -> APIChange ChDeleteEnumVal :: TypeName -> FieldName -> APIChange ChRenameEnumVal :: TypeName -> FieldName -> FieldName -> APIChange ChCustomType :: TypeName -> MigrationTag -> APIChange ChCustomAll :: MigrationTag -> APIChange -- | Within the changelog, custom migrations are represented as strings, so -- we have less type-safety. type MigrationTag = String -- | Represents either a released version (with a version number) or the -- version under development, which is newer than any release data VersionExtra Release :: Version -> VersionExtra DevVersion :: VersionExtra showVersionExtra :: VersionExtra -> String -- | Represents the positions in a type to apply an update data UpdateTypePos UpdateList :: UpdateTypePos -> UpdateTypePos UpdateMaybe :: UpdateTypePos -> UpdateTypePos UpdateNamed :: TypeName -> UpdateTypePos -- | Represents the positions in a declaration to apply an update data UpdateDeclPos UpdateHere :: (Maybe UpdateDeclPos) -> UpdateDeclPos UpdateRecord :: (Map FieldName (Maybe UpdateTypePos)) -> UpdateDeclPos UpdateUnion :: (Map FieldName (Maybe UpdateTypePos)) -> UpdateDeclPos UpdateType :: UpdateTypePos -> UpdateDeclPos data APITableChange -- | An initial API, an APIChange and the positions in which to apply it APIChange :: NormAPI -> APIChange -> (Map TypeName UpdateDeclPos) -> APITableChange -- | Request to validate the dataset against the given API ValidateData :: NormAPI -> APITableChange instance GHC.Show.Show Data.API.Changes.Types.APITableChange instance GHC.Classes.Eq Data.API.Changes.Types.APITableChange instance GHC.Show.Show Data.API.Changes.Types.UpdateDeclPos instance GHC.Classes.Eq Data.API.Changes.Types.UpdateDeclPos instance GHC.Show.Show Data.API.Changes.Types.UpdateTypePos instance GHC.Classes.Eq Data.API.Changes.Types.UpdateTypePos instance GHC.Show.Show Data.API.Changes.Types.APIChangelog instance GHC.Classes.Eq Data.API.Changes.Types.APIChangelog instance GHC.Show.Show Data.API.Changes.Types.VersionExtra instance GHC.Classes.Ord Data.API.Changes.Types.VersionExtra instance GHC.Classes.Eq Data.API.Changes.Types.VersionExtra instance GHC.Show.Show Data.API.Changes.Types.APIChange instance GHC.Classes.Eq Data.API.Changes.Types.APIChange instance Data.API.PP.PPLines Data.API.Changes.Types.APIChange instance Data.API.PP.PP Data.API.Changes.Types.VersionExtra instance Data.API.PP.PPLines Data.API.Changes.Types.APITableChange module Data.API.Error -- | Represents an error that can be encountered while parsing data JSONError Expected :: Expected -> String -> Value -> JSONError BadFormat :: FormatExpected -> String -> Text -> JSONError MissingField :: JSONError MissingAlt :: [String] -> JSONError UnexpectedField :: JSONError UnexpectedEnumVal :: [Text] -> Text -> JSONError IntRangeError :: String -> Int -> IntRange -> JSONError UTCRangeError :: String -> UTCTime -> UTCRange -> JSONError RegexError :: String -> Text -> RegEx -> JSONError SyntaxError :: String -> JSONError -- | At present, we do not distinguish between errors and warnings type JSONWarning = JSONError -- | JSON type expected at a particular position, when a value of a -- different type was encountered data Expected ExpArray :: Expected ExpBool :: Expected ExpInt :: Expected ExpObject :: Expected ExpString :: Expected -- | Special format expected of a string data FormatExpected FmtBinary :: FormatExpected FmtUTC :: FormatExpected FmtOther :: FormatExpected -- | A position inside a JSON value is a list of steps, ordered innermost -- first (so going inside an object prepends a step). type Position = [Step] -- | Each step may be into a field of an object, or a specific element of -- an array. data Step InField :: Text -> Step InElem :: Int -> Step inField :: FieldName -> Step -- | Human-readable presentation of a list of parse errors with their -- positions prettyJSONErrorPositions :: [(JSONError, Position)] -> String -- | Human-readable description of a JSON parse error prettyJSONError :: JSONError -> String -- | Human-readable description of a single step in a position prettyStep :: Step -> String expectedArray :: Value -> JSONError expectedBool :: Value -> JSONError expectedInt :: Value -> JSONError expectedObject :: Value -> JSONError expectedString :: Value -> JSONError badFormat :: String -> Text -> JSONError -- | Errors that can be discovered when migrating data values data ValueError -- | Data doesn't match schema JSONError :: JSONError -> ValueError -- | Error generated during custom migration CustomMigrationError :: String -> Value -> ValueError -- | An API change was invalid InvalidAPI :: ApplyFailure -> ValueError -- | Errors that may be discovered when validating a changelog data ValidateFailure -- | the changelog must be in descending order of versions ChangelogOutOfOrder :: VersionExtra -> VersionExtra -> ValidateFailure [vfLaterVersion] :: ValidateFailure -> VersionExtra [vfEarlierVersion] :: ValidateFailure -> VersionExtra -- | forbid migrating from one version to an earlier version CannotDowngrade :: VersionExtra -> VersionExtra -> ValidateFailure [vfFromVersion] :: ValidateFailure -> VersionExtra [vfToVersion] :: ValidateFailure -> VersionExtra -- | an API uses types that are not declared ApiInvalid :: VersionExtra -> Set TypeName -> ValidateFailure [vfInvalidVersion] :: ValidateFailure -> VersionExtra [vfMissingDeclarations] :: ValidateFailure -> Set TypeName -- | changelog entry does not apply ChangelogEntryInvalid :: [APITableChange] -> APIChange -> ApplyFailure -> ValidateFailure [vfSuccessfullyApplied] :: ValidateFailure -> [APITableChange] [vfFailedToApply] :: ValidateFailure -> APIChange [vfApplyFailure] :: ValidateFailure -> ApplyFailure -- | changelog is incomplete (ie all entries apply ok but result isn't the -- target api) ChangelogIncomplete :: VersionExtra -> VersionExtra -> Map TypeName (MergeResult NormTypeDecl NormTypeDecl) -> ValidateFailure [vfChangelogVersion] :: ValidateFailure -> VersionExtra [vfTargetVersion] :: ValidateFailure -> VersionExtra [vfDifferences] :: ValidateFailure -> Map TypeName (MergeResult NormTypeDecl NormTypeDecl) data ValidateWarning -- | Errors that may occur applying a single API change data ApplyFailure -- | for adding or renaming type TypeExists :: TypeName -> ApplyFailure [afExistingType] :: ApplyFailure -> TypeName -- | for deleting or renaming a type TypeDoesNotExist :: TypeName -> ApplyFailure [afMissingType] :: ApplyFailure -> TypeName -- | e.g. it's not a record type TypeWrongKind :: TypeName -> TypeKind -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName [afExpectedKind] :: ApplyFailure -> TypeKind -- | cannot delete/modify types that are still used TypeInUse :: TypeName -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName -- | type refers to a non-existent type TypeMalformed :: APIType -> Set TypeName -> ApplyFailure [afType] :: ApplyFailure -> APIType [afMissingTypes] :: ApplyFailure -> Set TypeName -- | decl refers to a non-existent type DeclMalformed :: TypeName -> NormTypeDecl -> Set TypeName -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName [afDecl] :: ApplyFailure -> NormTypeDecl [afMissingTypes] :: ApplyFailure -> Set TypeName -- | for adding or renaming a field FieldExists :: TypeName -> TypeKind -> FieldName -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName [afTypeKind] :: ApplyFailure -> TypeKind [afExistingField] :: ApplyFailure -> FieldName -- | for deleting or renaming a field FieldDoesNotExist :: TypeName -> TypeKind -> FieldName -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName [afTypeKind] :: ApplyFailure -> TypeKind [afMissingField] :: ApplyFailure -> FieldName -- | for adding a field, must be a default value compatible with the type FieldBadDefaultValue :: TypeName -> FieldName -> APIType -> DefaultValue -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName [afFieldName] :: ApplyFailure -> FieldName [afFieldType] :: ApplyFailure -> APIType [afBadDefault] :: ApplyFailure -> DefaultValue -- | for adding a field to a table DefaultMissing :: TypeName -> FieldName -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName [afFieldName] :: ApplyFailure -> FieldName -- | custom error in tableChange TableChangeError :: String -> ApplyFailure [afCustomMessage] :: ApplyFailure -> String data TypeKind TKRecord :: TypeKind TKUnion :: TypeKind TKEnum :: TypeKind TKNewtype :: TypeKind TKTypeSynonym :: TypeKind data MigrateFailure ValidateFailure :: ValidateFailure -> MigrateFailure ValueError :: ValueError -> Position -> MigrateFailure type MigrateWarning = ValidateWarning prettyMigrateFailure :: MigrateFailure -> String prettyValidateFailure :: ValidateFailure -> String prettyValueError :: ValueError -> String prettyValueErrorPosition :: (ValueError, Position) -> String instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.Error.Step instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Error.Step instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Error.Step instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Error.FormatExpected instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Error.FormatExpected instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Error.Expected instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Error.Expected instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Error.JSONError instance Data.Aeson.Types.FromJSON.FromJSON Data.API.Error.JSONError instance GHC.Show.Show Data.API.Error.MigrateFailure instance GHC.Classes.Eq Data.API.Error.MigrateFailure instance GHC.Show.Show Data.API.Error.ValueError instance GHC.Classes.Eq Data.API.Error.ValueError instance GHC.Show.Show Data.API.Error.ValidateFailure instance GHC.Classes.Eq Data.API.Error.ValidateFailure instance GHC.Show.Show Data.API.Error.ApplyFailure instance GHC.Classes.Eq Data.API.Error.ApplyFailure instance GHC.Show.Show Data.API.Error.TypeKind instance GHC.Classes.Eq Data.API.Error.TypeKind instance GHC.Show.Show Data.API.Error.ValidateWarning instance GHC.Show.Show Data.API.Error.Step instance GHC.Classes.Eq Data.API.Error.Step instance GHC.Show.Show Data.API.Error.JSONError instance GHC.Classes.Eq Data.API.Error.JSONError instance GHC.Show.Show Data.API.Error.FormatExpected instance GHC.Classes.Eq Data.API.Error.FormatExpected instance GHC.Show.Show Data.API.Error.Expected instance GHC.Classes.Eq Data.API.Error.Expected instance Data.API.PP.PPLines Data.API.Error.Step instance Data.API.PP.PP Data.API.Error.TypeKind instance Data.API.PP.PPLines Data.API.Error.MigrateFailure instance Data.API.PP.PPLines Data.API.Error.ValidateFailure instance Data.API.PP.PPLines Data.API.Error.ApplyFailure instance Data.API.PP.PPLines Data.API.Error.ValueError -- | This module defines a JSON parser, like Aeson's FromJSON, but -- with more detailed error-reporting capabilities. In particular, it -- reports errors in a structured format, and can report multiple -- independent errors rather than stopping on the first one encountered. module Data.API.JSON -- | Like Parser, but keeping track of locations within the JSON -- structure and able to report multiple errors. -- -- Careful! The Monad instance does not agree with the -- Applicative instance in all circumstances, and you should use -- the Applicative instance where possible. In particular: -- -- data ParserWithErrs a -- | Options to modify the behaviour of the JSON parser data ParseFlags -- | Use this as a basis for overriding individual fields of the -- ParseFlags record, in case more flags are added in the future. defaultParseFlags :: ParseFlags -- | Run a parser with given flags, starting in the outermost location, and -- returning warnings even if the parse was successful runParserWithErrsTop :: ParseFlags -> ParserWithErrs a -> Either [(JSONError, Position)] (a, [(JSONWarning, Position)]) -- | Like FromJSON, but keeping track of multiple errors and their -- positions. Moreover, this class is more liberal in accepting invalid -- inputs: -- -- class FromJSONWithErrs a where parseJSONWithErrs v = case fromJSON v of { Error e -> failWith $ SyntaxError e Success a -> pure a } -- | Parse a JSON value with structured error-reporting support. If this -- method is omitted, fromJSON will be used instead: note that -- this will result in less precise errors. parseJSONWithErrs :: FromJSONWithErrs a => Value -> ParserWithErrs a -- | Parse a JSON value with structured error-reporting support. If this -- method is omitted, fromJSON will be used instead: note that -- this will result in less precise errors. parseJSONWithErrs :: (FromJSONWithErrs a, FromJSON a) => Value -> ParserWithErrs a -- | Run the JSON parser on a value to produce a result or a list of errors -- with their positions. This should not be used inside an implementation -- of parseJSONWithErrs as it will not pass on the current -- position. fromJSONWithErrs :: FromJSONWithErrs a => Value -> Either [(JSONError, Position)] a -- | Run the JSON parser on a value to produce a result or a list of errors -- with their positions. This version allows the ParseFlags to be -- specified. fromJSONWithErrs' :: FromJSONWithErrs a => ParseFlags -> Value -> Either [(JSONError, Position)] a -- | Run the JSON parser on a value to produce a result or a list of errors -- with their positions. This version allows the ParseFlags to be -- specified, and produces warnings even if the parse succeeded. fromJSONWithErrs'' :: FromJSONWithErrs a => ParseFlags -> Value -> Either [(JSONError, Position)] (a, [(JSONWarning, Position)]) -- | Decode a ByteString and run the JSON parser decodeWithErrs :: FromJSONWithErrs a => ByteString -> Either [(JSONError, Position)] a -- | Decode a ByteString and run the JSON parser, allowing the -- ParseFlags to be specified decodeWithErrs' :: FromJSONWithErrs a => ParseFlags -> ByteString -> Either [(JSONError, Position)] a -- | Suitable as an implementation of parseJSON that uses the -- FromJSONWithErrs instance (provided said instance was not -- defined using fromJSON!). parseJSONDefault :: FromJSONWithErrs a => Value -> Parser a withParseFlags :: (ParseFlags -> ParserWithErrs a) -> ParserWithErrs a -- | It's contrary to my principles, but I'll accept a string containing a -- number instead of an actual number, and will silently truncate -- floating point numbers to integers... withInt :: String -> (Int -> ParserWithErrs a) -> Value -> ParserWithErrs a withIntRange :: IntRange -> String -> (Int -> ParserWithErrs a) -> Value -> ParserWithErrs a withBinary :: String -> (Binary -> ParserWithErrs a) -> Value -> ParserWithErrs a withBool :: String -> (Bool -> ParserWithErrs a) -> Value -> ParserWithErrs a withText :: String -> (Text -> ParserWithErrs a) -> Value -> ParserWithErrs a withRegEx :: RegEx -> String -> (Text -> ParserWithErrs a) -> Value -> ParserWithErrs a withUTC :: String -> (UTCTime -> ParserWithErrs a) -> Value -> ParserWithErrs a withUTCRange :: UTCRange -> String -> (UTCTime -> ParserWithErrs a) -> Value -> ParserWithErrs a withVersion :: String -> (Version -> ParserWithErrs a) -> Value -> ParserWithErrs a -- | Look up the value of a field, treating missing fields as null withField :: Text -> (Value -> ParserWithErrs a) -> Object -> ParserWithErrs a -- | Look up the value of a field, which may be read-only or use a default -- value (depending on the ParseFlags). withDefaultField :: Bool -> Maybe Value -> Text -> (Value -> ParserWithErrs a) -> Object -> ParserWithErrs a -- | Parse the value of a field, treating missing fields as null (.:.) :: FromJSONWithErrs a => Object -> Text -> ParserWithErrs a -- | Parse the value of a field, failing on missing fields (.::) :: FromJSONWithErrs a => Object -> Text -> ParserWithErrs a -- | Match an inhabitant of a disjoint union, which should be an object -- with a single field, and call the continuation corresponding to the -- field name. withUnion :: [(Text, Value -> ParserWithErrs a)] -> Value -> ParserWithErrs a -- | Represents an error that can be encountered while parsing data JSONError Expected :: Expected -> String -> Value -> JSONError BadFormat :: FormatExpected -> String -> Text -> JSONError MissingField :: JSONError MissingAlt :: [String] -> JSONError UnexpectedField :: JSONError UnexpectedEnumVal :: [Text] -> Text -> JSONError IntRangeError :: String -> Int -> IntRange -> JSONError UTCRangeError :: String -> UTCTime -> UTCRange -> JSONError RegexError :: String -> Text -> RegEx -> JSONError SyntaxError :: String -> JSONError -- | At present, we do not distinguish between errors and warnings type JSONWarning = JSONError -- | JSON type expected at a particular position, when a value of a -- different type was encountered data Expected ExpArray :: Expected ExpBool :: Expected ExpInt :: Expected ExpObject :: Expected ExpString :: Expected -- | Special format expected of a string data FormatExpected FmtBinary :: FormatExpected FmtUTC :: FormatExpected FmtOther :: FormatExpected -- | A position inside a JSON value is a list of steps, ordered innermost -- first (so going inside an object prepends a step). type Position = [Step] -- | Each step may be into a field of an object, or a specific element of -- an array. data Step InField :: Text -> Step InElem :: Int -> Step -- | Human-readable presentation of a list of parse errors with their -- positions prettyJSONErrorPositions :: [(JSONError, Position)] -> String -- | Human-readable description of a JSON parse error prettyJSONError :: JSONError -> String -- | Human-readable description of a single step in a position prettyStep :: Step -> String failWith :: JSONError -> ParserWithErrs a expectedArray :: Value -> JSONError expectedBool :: Value -> JSONError expectedInt :: Value -> JSONError expectedObject :: Value -> JSONError expectedString :: Value -> JSONError badFormat :: String -> Text -> JSONError instance GHC.Base.Functor Data.API.JSON.ParserWithErrs instance GHC.Base.Applicative Data.API.JSON.ParserWithErrs instance GHC.Base.Alternative Data.API.JSON.ParserWithErrs instance GHC.Base.Monad Data.API.JSON.ParserWithErrs instance Data.API.JSON.FromJSONWithErrs Data.Aeson.Types.Internal.Value instance Data.API.JSON.FromJSONWithErrs () instance Data.API.JSON.FromJSONWithErrs a => Data.API.JSON.FromJSONWithErrs (GHC.Base.Maybe a) instance Data.API.JSON.FromJSONWithErrs a => Data.API.JSON.FromJSONWithErrs [a] instance Data.API.JSON.FromJSONWithErrs GHC.Types.Int instance Data.API.JSON.FromJSONWithErrs GHC.Integer.Type.Integer instance Data.API.JSON.FromJSONWithErrs GHC.Types.Bool instance Data.API.JSON.FromJSONWithErrs Data.API.Types.Binary instance Data.API.JSON.FromJSONWithErrs Data.Text.Internal.Text instance Data.API.JSON.FromJSONWithErrs Data.Time.Clock.UTC.UTCTime instance Data.API.JSON.FromJSONWithErrs Data.Version.Version module Data.API.Tools.JSON -- | Tool to generate ToJSON and FromJSONWithErrs instances -- for types generated by datatypesTool. This depends on -- enumTool. For historical reasons this does not generate -- FromJSON instances; you probably want to use jsonTool' -- instead. jsonTool :: APITool -- | Tool to generate ToJSON, FromJSON and -- FromJSONWithErrs instances for types generated by -- datatypesTool. This depends on enumTool. Note that -- generated FromJSON and FromJSONWithErrs instances will -- always agree on the decoding of a value, but that the -- FromJSONWithErrs instances for basic types are more liberal -- than FromJSON. jsonTool' :: APITool -- | Tool to generate ToJSON instance for an API node toJsonNodeTool :: APINodeTool -- | Tool to generate FromJSON instance for an API node, which -- relies on the FromJSONWithErrs instance. fromJsonNodeTool :: APINodeTool -- | Tool to generate FromJSONWithErrs instance for an API node fromJsonWithErrsNodeTool :: APINodeTool -- | This module defines a generic representation of values belonging to a -- schema, for use during data migration. module Data.API.Value -- | Generic representation of a data value belonging to a schema type. -- This representation has the following properties: -- -- data Value String :: !Text -> Value UTCTime :: !UTCTime -> Value Bytes :: !Binary -> Value Bool :: !Bool -> Value Int :: !Int -> Value List :: ![Value] -> Value Maybe :: !(Maybe Value) -> Value Union :: !FieldName -> !Value -> Value Enum :: !FieldName -> Value Record :: !Record -> Value JSON :: !Value -> Value -- | A record is represented as a list of (field name, value) pairs. -- -- Invariant: these are in ascending order by field name, and there are -- no duplicates. -- -- TODO: consider if it would be worth using Map instead. type Record = [Field] data Field Field :: FieldName -> Value -> Field [fieldName] :: Field -> FieldName [fieldValue] :: Field -> Value -- | Convert a DefaultValue into a generic Value, failing if -- the type is not compatible. This requires type information so that it -- can introduce type distinctions absent in DefaultValue, e.g. -- when DefValList is used at type TyMaybe -- (TyList t). fromDefaultValue :: NormAPI -> APIType -> DefaultValue -> Maybe Value -- | Parse a generic Value from a JSON Value, given the -- schema and expected type. This is not particularly optimized. For the -- other direction, use toJSON. fromJSON :: NormAPI -> APIType -> Value -> Either [(JSONError, Position)] (Value, [(JSONWarning, Position)]) parseJSON :: NormAPI -> APIType -> Value -> ParserWithErrs Value -- | Efficiently encode a generic Value in CBOR format. encode :: Value -> Encoding -- | Efficiently decode CBOR as a generic Value, given the schema -- and expected type. decode :: NormAPI -> APIType -> Decoder s Value -- | Check that the value is of the given type in the schema, reporting the -- first error encountered if it does not conform. matchesNormAPI :: NormAPI -> APIType -> Value -> Position -> Either (ValueError, Position) () expectRecord :: Value -> Position -> Either (ValueError, Position) Record expectEnum :: Value -> Position -> Either (ValueError, Position) FieldName expectUnion :: Value -> Position -> Either (ValueError, Position) (FieldName, Value) expectList :: Value -> Position -> Either (ValueError, Position) [Value] expectMaybe :: Value -> Position -> Either (ValueError, Position) (Maybe Value) lookupType :: TypeName -> NormAPI -> Either ApplyFailure NormTypeDecl recordToMap :: Record -> Map FieldName Value mapToRecord :: Map FieldName Value -> Record -- | Insert a (field, value) pair into a record, replacing the existing -- field if it is present and preserving the ordering invariant. insertField :: FieldName -> Value -> Record -> Record -- | Rename a field in a record, preserving the ordering invariant. renameField :: FieldName -> FieldName -> Record -> Record -- | Delete a field from a record, trivially preserving the ordering -- invariant. deleteField :: FieldName -> Record -> Record -- | Split a record at a given field, returning the preceding fields, value -- and succeeding fields. Fails if the field is absent. findField :: FieldName -> Record -> Maybe (Record, Value, Record) -- | Join together two records with a (field, value) pair in between. The -- ordering invariant is not checked! joinRecords :: Record -> FieldName -> Value -> Record -> Record -- | Given a schema, generate an arbitrary type corresponding to the schema -- and an arbitrary value of that type. arbitrary :: NormAPI -> Gen (APIType, Value) -- | Given a schema and a type, generate an arbitrary value of that type. arbitraryOfType :: NormAPI -> APIType -> Gen Value -- | A reasonably varied generator for JSON Values. -- -- Hack alert: we do not generate Null, because Aeson fails to -- round-trip Just Null :: Maybe -- Value. arbitraryJSONValue :: Gen Value -- | QuickCheck property that converting a Value to and from JSON -- gives back the original value. prop_jsonRoundTrip :: NormAPI -> Property -- | QuickCheck property that the type-specific JSON serialisation agrees -- with deserialising as generic JSON and then serialising again. prop_jsonGeneric :: ToJSON a => API -> TypeName -> a -> Result -- | QuickCheck property that converting a Value to and from CBOR -- gives back the original value. prop_cborRoundTrip :: NormAPI -> Property -- | QuickCheck property that the type-specific CBOR serialisation agrees -- with deserialising as generic CBOR and then serialising again. prop_cborGeneric :: Serialise a => API -> TypeName -> a -> Result instance GHC.Show.Show Data.API.Value.Value instance GHC.Classes.Eq Data.API.Value.Value instance GHC.Show.Show Data.API.Value.Field instance GHC.Classes.Eq Data.API.Value.Field instance Control.DeepSeq.NFData Data.API.Value.Value instance Control.DeepSeq.NFData Data.API.Value.Field instance Data.Aeson.Types.ToJSON.ToJSON Data.API.Value.Value -- | This module deals with validating API changelogs and migrating JSON -- data between different versions of a schema. module Data.API.Changes -- | Migrate a dataset from one version of an API schema to another. The -- data must be described by a named type, the name of which is assumed -- not to change. -- -- The db, rec and fld types must be -- enumerations of all the custom migration tags in the changelog, as -- generated by generateMigrationKind. migrateDataDump :: (Read db, Read rec, Read fld) => (API, Version) -> (API, VersionExtra) -> APIChangelog -> CustomMigrations Object Value db rec fld -> TypeName -> DataChecks -> Value -> Either MigrateFailure (Value, [MigrateWarning]) migrateDataDump' :: (Read db, Read rec, Read fld) => (API, Version) -> (API, VersionExtra) -> APIChangelog -> CustomMigrations Record Value db rec fld -> TypeName -> DataChecks -> Value -> Either MigrateFailure (Value, [MigrateWarning]) -- | Check that a changelog adequately describes how to migrate from one -- version to another. validateChanges :: (Read db, Read rec, Read fld) => (API, Version) -> (API, VersionExtra) -> APIChangelog -> CustomMigrations o v db rec fld -> TypeName -> DataChecks -> Either ValidateFailure [ValidateWarning] -- | Check that a dataset matches an API, which is necessary for succesful -- migration. The name of the dataset's type must be specified. dataMatchesAPI :: TypeName -> API -> Value -> Either (ValueError, Position) () -- | When to validate the data against the schema (each level implies the -- preceding levels): data DataChecks -- | Not at all NoChecks :: DataChecks -- | At start and end of the migration CheckStartAndEnd :: DataChecks -- | After custom migrations CheckCustom :: DataChecks -- | After every change CheckAll :: DataChecks -- | An API changelog, consisting of a list of versions with the changes -- from one version to the next. The versions must be in descending order -- (according to the Ord Version instance). data APIChangelog -- | The changes from the previous version up to this version. ChangesUpTo :: VersionExtra -> [APIChange] -> APIChangelog -> APIChangelog -- | The initial version ChangesStart :: Version -> APIChangelog type APIWithChangelog = (API, APIChangelog) -- | A single change within a changelog data APIChange ChAddType :: TypeName -> NormTypeDecl -> APIChange ChDeleteType :: TypeName -> APIChange ChRenameType :: TypeName -> TypeName -> APIChange ChAddField :: TypeName -> FieldName -> APIType -> (Maybe DefaultValue) -> APIChange ChDeleteField :: TypeName -> FieldName -> APIChange ChRenameField :: TypeName -> FieldName -> FieldName -> APIChange ChChangeField :: TypeName -> FieldName -> APIType -> MigrationTag -> APIChange ChAddUnionAlt :: TypeName -> FieldName -> APIType -> APIChange ChDeleteUnionAlt :: TypeName -> FieldName -> APIChange ChRenameUnionAlt :: TypeName -> FieldName -> FieldName -> APIChange ChAddEnumVal :: TypeName -> FieldName -> APIChange ChDeleteEnumVal :: TypeName -> FieldName -> APIChange ChRenameEnumVal :: TypeName -> FieldName -> FieldName -> APIChange ChCustomType :: TypeName -> MigrationTag -> APIChange ChCustomAll :: MigrationTag -> APIChange -- | Represents either a released version (with a version number) or the -- version under development, which is newer than any release data VersionExtra Release :: Version -> VersionExtra DevVersion :: VersionExtra showVersionExtra :: VersionExtra -> String -- | The earliest version in the changelog changelogStartVersion :: APIChangelog -> Version -- | The latest version in the changelog changelogVersion :: APIChangelog -> VersionExtra -- | Custom migrations used in the changelog must be implemented in -- Haskell, and supplied in this record. There are three kinds: -- -- -- -- For database and type migrations, if the schema is unchanged, the -- corresponding function should return Nothing. -- -- The db, ty and fld parameters should be -- instantiated with the enumeration types generated by -- generateMigrationKinds, which correspond to the exact set of -- custom migration tags used in the changelog. data CustomMigrations o v db ty fld CustomMigrations :: (db -> o -> Either ValueError o) -> (db -> NormAPI -> Either ApplyFailure (Maybe NormAPI)) -> (ty -> v -> Either ValueError v) -> (ty -> NormTypeDecl -> Either ApplyFailure (Maybe NormTypeDecl)) -> (fld -> v -> Either ValueError v) -> CustomMigrations o v db ty fld [databaseMigration] :: CustomMigrations o v db ty fld -> db -> o -> Either ValueError o [databaseMigrationSchema] :: CustomMigrations o v db ty fld -> db -> NormAPI -> Either ApplyFailure (Maybe NormAPI) [typeMigration] :: CustomMigrations o v db ty fld -> ty -> v -> Either ValueError v [typeMigrationSchema] :: CustomMigrations o v db ty fld -> ty -> NormTypeDecl -> Either ApplyFailure (Maybe NormTypeDecl) [fieldMigration] :: CustomMigrations o v db ty fld -> fld -> v -> Either ValueError v -- | Lift a custom record migration to work on arbitrary values mkRecordMigration :: (Object -> Either ValueError Object) -> (Value -> Either ValueError Value) mkRecordMigration' :: (Record -> Either ValueError Record) -> (Value -> Either ValueError Value) -- | Lift a schema change on record types to work on arbitrary type -- declarations mkRecordMigrationSchema :: TypeName -> (NormRecordType -> Either ApplyFailure (Maybe NormRecordType)) -> (NormTypeDecl -> Either ApplyFailure (Maybe NormTypeDecl)) -- | Use for databaseMigration, typeMigration or -- fieldMigration to indicate that changes to the data are not -- required noDataChanges :: a -> Either ValueError a -- | Use for databaseMigrationSchema or typeMigrationSchema -- to indicate that the schema should not be changed noSchemaChanges :: a -> Either ApplyFailure (Maybe a) -- | Generate enumeration datatypes corresponding to the custom migrations -- used in an API migration changelog. generateMigrationKinds :: APIChangelog -> String -> String -> String -> Q [Dec] -- | Within the changelog, custom migrations are represented as strings, so -- we have less type-safety. type MigrationTag = String -- | The API type has too much extra info for us to be able to simply -- compare them with (==). Our strategy is to strip out -- ancillary information and normalise into a canonical form, and then we -- can use a simple (==) compare. -- -- Our normalised API discards most of the details of each type, keeping -- just essential information about each type. We discard order of types -- and fields, so we can use just associative maps. type NormAPI = Map TypeName NormTypeDecl -- | The normal or canonical form for a type declaration, an -- APINode. Equality of the normal form indicates equivalence of -- APIs. -- -- We track all types. data NormTypeDecl NRecordType :: NormRecordType -> NormTypeDecl NUnionType :: NormUnionType -> NormTypeDecl NEnumType :: NormEnumType -> NormTypeDecl NTypeSynonym :: APIType -> NormTypeDecl NNewtype :: BasicType -> NormTypeDecl -- | The canonical form of a record type is a map from fields to values... type NormRecordType = Map FieldName APIType -- | ...similarly a union is a map from fields to alternatives... type NormUnionType = Map FieldName APIType -- | ...and an enum is a set of values. type NormEnumType = Set FieldName -- | Compute the normal form of an API, discarding extraneous information. apiNormalForm :: API -> NormAPI -- | Compute the normal form of a single type declaration. declNF :: Spec -> NormTypeDecl data MigrateFailure ValidateFailure :: ValidateFailure -> MigrateFailure ValueError :: ValueError -> Position -> MigrateFailure type MigrateWarning = ValidateWarning -- | Errors that may be discovered when validating a changelog data ValidateFailure -- | the changelog must be in descending order of versions ChangelogOutOfOrder :: VersionExtra -> VersionExtra -> ValidateFailure [vfLaterVersion] :: ValidateFailure -> VersionExtra [vfEarlierVersion] :: ValidateFailure -> VersionExtra -- | forbid migrating from one version to an earlier version CannotDowngrade :: VersionExtra -> VersionExtra -> ValidateFailure [vfFromVersion] :: ValidateFailure -> VersionExtra [vfToVersion] :: ValidateFailure -> VersionExtra -- | an API uses types that are not declared ApiInvalid :: VersionExtra -> Set TypeName -> ValidateFailure [vfInvalidVersion] :: ValidateFailure -> VersionExtra [vfMissingDeclarations] :: ValidateFailure -> Set TypeName -- | changelog entry does not apply ChangelogEntryInvalid :: [APITableChange] -> APIChange -> ApplyFailure -> ValidateFailure [vfSuccessfullyApplied] :: ValidateFailure -> [APITableChange] [vfFailedToApply] :: ValidateFailure -> APIChange [vfApplyFailure] :: ValidateFailure -> ApplyFailure -- | changelog is incomplete (ie all entries apply ok but result isn't the -- target api) ChangelogIncomplete :: VersionExtra -> VersionExtra -> Map TypeName (MergeResult NormTypeDecl NormTypeDecl) -> ValidateFailure [vfChangelogVersion] :: ValidateFailure -> VersionExtra [vfTargetVersion] :: ValidateFailure -> VersionExtra [vfDifferences] :: ValidateFailure -> Map TypeName (MergeResult NormTypeDecl NormTypeDecl) data ValidateWarning -- | Errors that may occur applying a single API change data ApplyFailure -- | for adding or renaming type TypeExists :: TypeName -> ApplyFailure [afExistingType] :: ApplyFailure -> TypeName -- | for deleting or renaming a type TypeDoesNotExist :: TypeName -> ApplyFailure [afMissingType] :: ApplyFailure -> TypeName -- | e.g. it's not a record type TypeWrongKind :: TypeName -> TypeKind -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName [afExpectedKind] :: ApplyFailure -> TypeKind -- | cannot delete/modify types that are still used TypeInUse :: TypeName -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName -- | type refers to a non-existent type TypeMalformed :: APIType -> Set TypeName -> ApplyFailure [afType] :: ApplyFailure -> APIType [afMissingTypes] :: ApplyFailure -> Set TypeName -- | decl refers to a non-existent type DeclMalformed :: TypeName -> NormTypeDecl -> Set TypeName -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName [afDecl] :: ApplyFailure -> NormTypeDecl [afMissingTypes] :: ApplyFailure -> Set TypeName -- | for adding or renaming a field FieldExists :: TypeName -> TypeKind -> FieldName -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName [afTypeKind] :: ApplyFailure -> TypeKind [afExistingField] :: ApplyFailure -> FieldName -- | for deleting or renaming a field FieldDoesNotExist :: TypeName -> TypeKind -> FieldName -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName [afTypeKind] :: ApplyFailure -> TypeKind [afMissingField] :: ApplyFailure -> FieldName -- | for adding a field, must be a default value compatible with the type FieldBadDefaultValue :: TypeName -> FieldName -> APIType -> DefaultValue -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName [afFieldName] :: ApplyFailure -> FieldName [afFieldType] :: ApplyFailure -> APIType [afBadDefault] :: ApplyFailure -> DefaultValue -- | for adding a field to a table DefaultMissing :: TypeName -> FieldName -> ApplyFailure [afTypeName] :: ApplyFailure -> TypeName [afFieldName] :: ApplyFailure -> FieldName -- | custom error in tableChange TableChangeError :: String -> ApplyFailure [afCustomMessage] :: ApplyFailure -> String data TypeKind TKRecord :: TypeKind TKUnion :: TypeKind TKEnum :: TypeKind TKNewtype :: TypeKind TKTypeSynonym :: TypeKind data MergeResult a b OnlyInLeft :: a -> MergeResult a b InBoth :: a -> b -> MergeResult a b OnlyInRight :: b -> MergeResult a b -- | Errors that can be discovered when migrating data values data ValueError -- | Data doesn't match schema JSONError :: JSONError -> ValueError -- | Error generated during custom migration CustomMigrationError :: String -> Value -> ValueError -- | An API change was invalid InvalidAPI :: ApplyFailure -> ValueError prettyMigrateFailure :: MigrateFailure -> String prettyValidateFailure :: ValidateFailure -> String prettyValueError :: ValueError -> String prettyValueErrorPosition :: (ValueError, Position) -> String instance GHC.Classes.Ord Data.API.Changes.DataChecks instance GHC.Classes.Eq Data.API.Changes.DataChecks module Data.API.JSONToCBOR -- | Serialise a JSON value as a CBOR term in a generic but -- schema-dependent fashion. This is necessary because the JSON -- representation carries less information than we need in CBOR (e.g. it -- lacks a distinction between bytestrings and text). serialiseJSONWithSchema :: API -> TypeName -> Value -> ByteString -- | Convert a JSON value into a CBOR term in a generic but -- schema-dependent fashion. jsonToCBORWithSchema :: API -> TypeName -> Value -> Term -- | When a JSON value has been deserialised from CBOR, the representation -- may need some modifications in order to match the result of -- toJSON on a Haskell datatype. In particular, Aeson's -- representation of Maybe does not round-trip (because -- Nothing is encoded as Null and Just x as -- toJSON x), so CBOR uses a different representation (as -- an empty or 1-element list). deserialiseJSONWithSchema :: API -> TypeName -> ByteString -> Value postprocessJSON :: API -> TypeName -> Value -> Either ValueError Value module Data.API.Tools.JSONTests -- | Tool to generate a list of JSON round-trip tests of type -- [(String, Property)] with the given name. This -- depends on jsonTool and quickCheckTool. jsonTestsTool :: Name -> APITool -- | Tool to generate a list of CBOR round-trip tests of type -- [(String, Property)] with the given name. This -- depends on cborTool and quickCheckTool. cborTestsTool :: Name -> APITool -- | Tool to generate a list of CBOR-to-JSON conversion tests of type -- [(String, Property)]. The first name must be -- the API being tested, and the second should be the name of the -- declaration to be produced. This depends on cborTool, -- jsonTool and quickCheckTool. cborToJSONTestsTool :: Name -> Name -> APITool -- | Tool to generate a list of JSON-to-CBOR conversion tests of type -- [(String, Property)]. The first name must be -- the API being tested, and the second should be the name of the -- declaration to be produced. This depends on cborTool, -- jsonTool and quickCheckTool. jsonToCBORTestsTool :: Name -> Name -> APITool -- | Tool to generate a list of tests that the Value generic -- representation agrees with the type-specific JSON representation. jsonGenericValueTestsTool :: Name -> Name -> APITool -- | Tool to generate a list of tests that the Value generic -- representation agrees with the type-specific CBOR representation. cborGenericValueTestsTool :: Name -> Name -> APITool -- | QuickCheck property that a Value decodes to an expected Haskell -- value, using fromJSONWithErrs prop_decodesTo :: forall a. (Eq a, FromJSONWithErrs a) => Value -> a -> Bool -- | QuickCheck property that a Value decodes to an expected Haskell -- value, using fromJSONWithErrs' with the given ParseFlags prop_decodesTo' :: forall a. (Eq a, FromJSONWithErrs a) => ParseFlags -> Value -> a -> Bool -- | QuickCheck property that Haskell values can be encoded with -- toJSON and decoded with fromJSONWithErrs to get the -- original value prop_resultsMatchRoundtrip :: forall a. (Eq a, ToJSON a, FromJSONWithErrs a) => a -> Bool -- | QuickCheck property that CBOR decoding is a left inverse for encoding prop_cborRoundtrip :: forall a. (Eq a, Serialise a) => a -> Bool -- | QuickCheck property that toJSON agrees with encoding to CBOR -- directly and then decoding using the schema-aware generic decoder. -- From this and prop_resultsMatchRoundtrip it follows that -- --
--   fromJSONWithErrs . deserialiseJSONWithSchema . serialise == id
--   
prop_cborToJSON :: forall a. (Eq a, Serialise a, ToJSON a) => API -> TypeName -> a -> Result -- | QuickCheck property that direct encoding to CBOR agrees with -- conversion to JSON followed by the schema-aware generic encoder. From -- this and prop_cborRoundtrip it follows that -- --
--   deserialise . serialiseJSONWithSchema . toJSON == id
--   
prop_jsonToCBOR :: forall a. (Eq a, Serialise a, ToJSON a) => API -> TypeName -> a -> Result -- | This module provides an interface for generating TH declarations from -- an API. To use it, splice in a call to generate followed -- by one or more calls to generateAPITools, like so: -- --
--   $(generate myAPI)
--   $(generateAPITools [enumTool, jsonTool', quickCheckTool] myAPI)
--   
-- -- If you wish to override any of the instances generated by the tools, -- you can do so by writing instance declarations after the call to -- generate but before the call to generateAPITools. module Data.API.Tools -- | Generate the datatypes corresponding to an API. generate :: API -> Q [Dec] -- | Apply a list of tools to an API, generating TH declarations. -- See the individual tool descriptions for details. Note that -- generate must be called first, and some tools have -- dependencies, which must be included in the same or a preceding call -- to generateAPITools. generateAPITools :: API -> [APITool] -> Q [Dec] -- | Generate the datatypes corresponding to an API, allowing the -- ToolSettings to be overriden. generateWith :: ToolSettings -> API -> Q [Dec] -- | Apply a list of tools to an API, generating TH declarations. -- This form allows the ToolSettings to be overridden. generateAPIToolsWith :: ToolSettings -> API -> [APITool] -> Q [Dec] -- | Settings to control the behaviour of API tools. This record may be -- extended in the future, so you should construct a value by overriding -- individual fields of defaultToolSettings. data ToolSettings -- | Default settings designed to be overridden. defaultToolSettings :: ToolSettings -- | Generate a warning when an instance declaration is omitted because it -- already exists warnOnOmittedInstance :: ToolSettings -> Bool -- | Rename the constructors of filtered newtypes and generate smart -- constructors that enforce the invariants newtypeSmartConstructors :: ToolSettings -> Bool -- | Tool to generate the maps between enumerations and Text -- strings named by text_enum_nm and map_enum_nm. enumTool :: APITool -- | Tool to generate Example instances for types generated by -- datatypesTool. This depends on quickCheckTool. exampleTool :: APITool -- | Tool to generate NFData instances for generated types. deepSeqTool :: APITool -- | Tool to generate ToJSON and FromJSONWithErrs instances -- for types generated by datatypesTool. This depends on -- enumTool. For historical reasons this does not generate -- FromJSON instances; you probably want to use jsonTool' -- instead. jsonTool :: APITool -- | Tool to generate ToJSON, FromJSON and -- FromJSONWithErrs instances for types generated by -- datatypesTool. This depends on enumTool. Note that -- generated FromJSON and FromJSONWithErrs instances will -- always agree on the decoding of a value, but that the -- FromJSONWithErrs instances for basic types are more liberal -- than FromJSON. jsonTool' :: APITool -- | Tool to generate Serialise instances for types generated by -- datatypesTool. This depends on enumTool. cborTool :: APITool -- | Tool to generate a list of JSON round-trip tests of type -- [(String, Property)] with the given name. This -- depends on jsonTool and quickCheckTool. jsonTestsTool :: Name -> APITool -- | Tool to generate a list of CBOR round-trip tests of type -- [(String, Property)] with the given name. This -- depends on cborTool and quickCheckTool. cborTestsTool :: Name -> APITool -- | Tool to generate a list of CBOR-to-JSON conversion tests of type -- [(String, Property)]. The first name must be -- the API being tested, and the second should be the name of the -- declaration to be produced. This depends on cborTool, -- jsonTool and quickCheckTool. cborToJSONTestsTool :: Name -> Name -> APITool -- | Tool to generate a list of JSON-to-CBOR conversion tests of type -- [(String, Property)]. The first name must be -- the API being tested, and the second should be the name of the -- declaration to be produced. This depends on cborTool, -- jsonTool and quickCheckTool. jsonToCBORTestsTool :: Name -> Name -> APITool -- | Tool to generate a list of tests that the Value generic -- representation agrees with the type-specific JSON representation. jsonGenericValueTestsTool :: Name -> Name -> APITool -- | Tool to generate a list of tests that the Value generic -- representation agrees with the type-specific CBOR representation. cborGenericValueTestsTool :: Name -> Name -> APITool -- | Tool to make lenses for fields in generated types. lensTool :: APITool -- | Tool to generate Arbitrary instances for generated types. quickCheckTool :: APITool -- | Tool to derive SafeCopy instances for generated types. At -- present, this derives only base version instances. safeCopyTool :: APITool -- | Generate a list of (type name, sample generator) pairs corresponding -- to each type in the API, with samples encoded as JSON. This depends on -- the Example instances generated by exampleTool. It -- generates something like this: -- --
--   samples :: [(String, Gen Value)]
--   samples = [("Foo", fmap toJSON (example :: Gen Foo)), ... ]
--   
samplesTool :: Name -> APITool module Data.API.Parse parseAPI :: String -> (Int, Int) -> String -> API parseAPIWithChangelog :: String -> (Int, Int) -> String -> APIWithChangelog api :: QuasiQuoter apiWithChangelog :: QuasiQuoter module Data.API.Tutorial module Data.API.API.DSL -- | API description of the api-tools API itself apiAPI :: API -- | This module contains datatypes generated from the DSL description of -- the api-tools API; they thus correspond to the types in -- Data.API.Types. module Data.API.API.Gen newtype RegularExpression RegularExpression :: Text -> RegularExpression [_RegularExpression] :: RegularExpression -> Text data IntRange IntRange :: !(Maybe Int) -> !(Maybe Int) -> IntRange [_ir_lo] :: IntRange -> !(Maybe Int) [_ir_hi] :: IntRange -> !(Maybe Int) data UTCRange UTCRange :: !(Maybe UTCTime) -> !(Maybe UTCTime) -> UTCRange [_ur_lo] :: UTCRange -> !(Maybe UTCTime) [_ur_hi] :: UTCRange -> !(Maybe UTCTime) data Filter FT_string :: !RegularExpression -> Filter FT_integer :: !IntRange -> Filter FT_utc :: !UTCRange -> Filter data Conversion Conversion :: !Text -> !Text -> Conversion [_cv_injection] :: Conversion -> !Text [_cv_projection] :: Conversion -> !Text newtype TypeRef TypeRef :: Text -> TypeRef [_TypeRef] :: TypeRef -> Text data BasicType BT_string :: BasicType BT_binary :: BasicType BT_boolean :: BasicType BT_integer :: BasicType BT_utc :: BasicType data APIType TY_list :: !APIType -> APIType TY_maybe :: !APIType -> APIType TY_ref :: !TypeRef -> APIType TY_basic :: !BasicType -> APIType TY_json :: !Int -> APIType data SpecNewtype SpecNewtype :: !BasicType -> !(Maybe Filter) -> SpecNewtype [_sn_type] :: SpecNewtype -> !BasicType [_sn_filter] :: SpecNewtype -> !(Maybe Filter) data DefaultValue DV_list :: !Int -> DefaultValue DV_maybe :: !Int -> DefaultValue DV_string :: !Text -> DefaultValue DV_boolean :: !Bool -> DefaultValue DV_integer :: !Int -> DefaultValue DV_utc :: !UTCTime -> DefaultValue data Field Field :: !Text -> !APIType -> !Bool -> !(Maybe DefaultValue) -> !Text -> Field [_fd_name] :: Field -> !Text [_fd_type] :: Field -> !APIType [_fd_readonly] :: Field -> !Bool [_fd_default] :: Field -> !(Maybe DefaultValue) [_fd_comment] :: Field -> !Text data Spec SP_newtype :: !SpecNewtype -> Spec SP_record :: ![Field] -> Spec SP_union :: ![Field] -> Spec SP_enum :: ![Text] -> Spec SP_synonym :: !APIType -> Spec data APINode APINode :: !Text -> !Text -> !Text -> !Spec -> !(Maybe Conversion) -> APINode [_an_name] :: APINode -> !Text [_an_comment] :: APINode -> !Text [_an_prefix] :: APINode -> !Text [_an_spec] :: APINode -> !Spec [_an_convert] :: APINode -> !(Maybe Conversion) type APISpec = [APINode] apiAPITestsJSONToCBOR :: [(String, Property)] apiAPITestsCBORToJSON :: [(String, Property)] apiAPITestsCBOR :: [(String, Property)] apiAPITestsJSON :: [(String, Property)] apiAPISamples :: [(String, Gen Value)] typeRef :: Iso' TypeRef Text fd_type :: Lens' Field APIType fd_readonly :: Lens' Field Bool fd_name :: Lens' Field Text fd_default :: Lens' Field (Maybe DefaultValue) fd_comment :: Lens' Field Text cv_projection :: Lens' Conversion Text cv_injection :: Lens' Conversion Text ur_lo :: Lens' UTCRange (Maybe UTCTime) ur_hi :: Lens' UTCRange (Maybe UTCTime) ir_lo :: Lens' IntRange (Maybe Int) ir_hi :: Lens' IntRange (Maybe Int) regularExpression :: Iso' RegularExpression Text sn_type :: Lens' SpecNewtype BasicType sn_filter :: Lens' SpecNewtype (Maybe Filter) an_spec :: Lens' APINode Spec an_prefix :: Lens' APINode Text an_name :: Lens' APINode Text an_convert :: Lens' APINode (Maybe Conversion) an_comment :: Lens' APINode Text _map_BasicType :: Map Text BasicType _text_BasicType :: BasicType -> Text instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.APINode instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.APINode instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.APINode instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.Spec instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.Spec instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.Spec instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.SpecNewtype instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.SpecNewtype instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.SpecNewtype instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.Filter instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.Filter instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.Filter instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.RegularExpression instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.RegularExpression instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.RegularExpression instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.IntRange instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.IntRange instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.IntRange instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.UTCRange instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.UTCRange instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.UTCRange instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.Conversion instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.Conversion instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.Conversion instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.Field instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.Field instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.Field instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.APIType instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.APIType instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.APIType instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.TypeRef instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.TypeRef instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.TypeRef instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.BasicType instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.BasicType instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.BasicType instance Data.Aeson.Types.ToJSON.ToJSON Data.API.API.Gen.DefaultValue instance Data.Aeson.Types.FromJSON.FromJSON Data.API.API.Gen.DefaultValue instance Data.API.JSON.FromJSONWithErrs Data.API.API.Gen.DefaultValue instance Codec.Serialise.Class.Serialise Data.API.API.Gen.APINode instance Codec.Serialise.Class.Serialise Data.API.API.Gen.Spec instance Codec.Serialise.Class.Serialise Data.API.API.Gen.SpecNewtype instance Codec.Serialise.Class.Serialise Data.API.API.Gen.Filter instance Codec.Serialise.Class.Serialise Data.API.API.Gen.RegularExpression instance Codec.Serialise.Class.Serialise Data.API.API.Gen.IntRange instance Codec.Serialise.Class.Serialise Data.API.API.Gen.UTCRange instance Codec.Serialise.Class.Serialise Data.API.API.Gen.Conversion instance Codec.Serialise.Class.Serialise Data.API.API.Gen.Field instance Codec.Serialise.Class.Serialise Data.API.API.Gen.APIType instance Codec.Serialise.Class.Serialise Data.API.API.Gen.TypeRef instance Codec.Serialise.Class.Serialise Data.API.API.Gen.BasicType instance Codec.Serialise.Class.Serialise Data.API.API.Gen.DefaultValue instance Control.DeepSeq.NFData Data.API.API.Gen.APINode instance Control.DeepSeq.NFData Data.API.API.Gen.Spec instance Control.DeepSeq.NFData Data.API.API.Gen.SpecNewtype instance Control.DeepSeq.NFData Data.API.API.Gen.Filter instance Control.DeepSeq.NFData Data.API.API.Gen.RegularExpression instance Control.DeepSeq.NFData Data.API.API.Gen.IntRange instance Control.DeepSeq.NFData Data.API.API.Gen.UTCRange instance Control.DeepSeq.NFData Data.API.API.Gen.Conversion instance Control.DeepSeq.NFData Data.API.API.Gen.Field instance Control.DeepSeq.NFData Data.API.API.Gen.APIType instance Control.DeepSeq.NFData Data.API.API.Gen.TypeRef instance Control.DeepSeq.NFData Data.API.API.Gen.BasicType instance Control.DeepSeq.NFData Data.API.API.Gen.DefaultValue instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.APINode instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.Spec instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.SpecNewtype instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.Filter instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.RegularExpression instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.IntRange instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.UTCRange instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.Conversion instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.Field instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.APIType instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.TypeRef instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.BasicType instance Test.QuickCheck.Arbitrary.Arbitrary Data.API.API.Gen.DefaultValue instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.APINode instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.Spec instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.SpecNewtype instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.Filter instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.RegularExpression instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.IntRange instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.UTCRange instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.Conversion instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.Field instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.APIType instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.TypeRef instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.BasicType instance Data.SafeCopy.SafeCopy.SafeCopy Data.API.API.Gen.DefaultValue instance Data.API.Tools.Example.Example Data.API.API.Gen.APINode instance Data.API.Tools.Example.Example Data.API.API.Gen.Spec instance Data.API.Tools.Example.Example Data.API.API.Gen.SpecNewtype instance Data.API.Tools.Example.Example Data.API.API.Gen.Filter instance Data.API.Tools.Example.Example Data.API.API.Gen.RegularExpression instance Data.API.Tools.Example.Example Data.API.API.Gen.IntRange instance Data.API.Tools.Example.Example Data.API.API.Gen.UTCRange instance Data.API.Tools.Example.Example Data.API.API.Gen.Conversion instance Data.API.Tools.Example.Example Data.API.API.Gen.Field instance Data.API.Tools.Example.Example Data.API.API.Gen.APIType instance Data.API.Tools.Example.Example Data.API.API.Gen.TypeRef instance Data.API.Tools.Example.Example Data.API.API.Gen.BasicType instance Data.API.Tools.Example.Example Data.API.API.Gen.DefaultValue instance GHC.Classes.Eq Data.API.API.Gen.APINode instance GHC.Show.Show Data.API.API.Gen.APINode instance GHC.Classes.Eq Data.API.API.Gen.Spec instance GHC.Show.Show Data.API.API.Gen.Spec instance GHC.Classes.Eq Data.API.API.Gen.Field instance GHC.Show.Show Data.API.API.Gen.Field instance GHC.Classes.Eq Data.API.API.Gen.DefaultValue instance GHC.Show.Show Data.API.API.Gen.DefaultValue instance GHC.Classes.Eq Data.API.API.Gen.SpecNewtype instance GHC.Show.Show Data.API.API.Gen.SpecNewtype instance GHC.Classes.Eq Data.API.API.Gen.APIType instance GHC.Show.Show Data.API.API.Gen.APIType instance GHC.Enum.Enum Data.API.API.Gen.BasicType instance GHC.Enum.Bounded Data.API.API.Gen.BasicType instance GHC.Classes.Ord Data.API.API.Gen.BasicType instance GHC.Classes.Eq Data.API.API.Gen.BasicType instance GHC.Show.Show Data.API.API.Gen.BasicType instance GHC.Classes.Ord Data.API.API.Gen.TypeRef instance GHC.Classes.Eq Data.API.API.Gen.TypeRef instance GHC.Show.Show Data.API.API.Gen.TypeRef instance Data.String.IsString Data.API.API.Gen.TypeRef instance GHC.Classes.Eq Data.API.API.Gen.Conversion instance GHC.Show.Show Data.API.API.Gen.Conversion instance GHC.Classes.Eq Data.API.API.Gen.Filter instance GHC.Show.Show Data.API.API.Gen.Filter instance GHC.Classes.Eq Data.API.API.Gen.UTCRange instance GHC.Show.Show Data.API.API.Gen.UTCRange instance GHC.Classes.Eq Data.API.API.Gen.IntRange instance GHC.Show.Show Data.API.API.Gen.IntRange instance GHC.Classes.Ord Data.API.API.Gen.RegularExpression instance GHC.Classes.Eq Data.API.API.Gen.RegularExpression instance GHC.Show.Show Data.API.API.Gen.RegularExpression instance Data.String.IsString Data.API.API.Gen.RegularExpression -- | This module converts an API specified with the DSL into a JSON-encoded -- object so that it can be used in clients. module Data.API.API -- | API description of the api-tools API itself apiAPI :: API -- | Take an API spec and generate a JSON description of the API extractAPI :: API -> Value convertAPI :: API -> APISpec unconvertAPI :: APISpec -> API instance Data.API.JSON.FromJSONWithErrs Data.API.Types.Thing