-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Parse and validate forms in JSON format -- -- Parse and validate forms in JSON format. @package forma @version 1.0.0 -- | This module provides a tool for validation of forms that are -- represented in the JSON format. Sending forms in JSON format via an -- AJAX request instead of traditional submitting of forms has a number -- of advantages: -- -- -- -- The task of validation of a form in the JSON format may seem simple, -- but it's not trivial to get it right. The library allows you to: -- -- -- -- You need to enable at least DataKinds and -- OverloadedLabels language extensions to use this library. -- -- Note: version 1.0.0 is completely different from older -- versions. module Web.Forma -- | Construct a parser for a field. Combine multiple fields using -- applicative syntax like so: -- --
--   type LoginFields = '["username", "password", "remember_me"]
--   
--   data LoginForm = LoginForm
--     { loginUsername   :: Text
--     , loginPassword   :: Text
--     , loginRememberMe :: Bool
--     }
--   
--   loginForm :: Monad m => FormParser LoginFields Text m LoginForm
--   loginForm = LoginForm
--     <$> field #username notEmpty
--     <*> field #password notEmpty
--     <*> field' #remember_me
--   
--   notEmpty :: Monad m => Text -> ExceptT Text m Text
--   notEmpty txt =
--     if T.null txt
--       then throwError "This field cannot be empty"
--       else return txt
--   
-- -- Referring to the types in the function's signature, s is -- extracted from JSON Value for you automatically using its -- FromJSON instance. The field value is taken in assumption that -- top level Value is a dictionary, and field name is a key in -- that dictionary. So for example a valid JSON input for the form shown -- above could be this: -- --
--   {
--     "username": "Bob",
--     "password": "123",
--     "remember_me": true
--   }
--   
-- -- Once value of type s is extracted, validation phase beings. -- The supplied checker (you can easily compose them with -- (>=>), as they are Kleisli arrows) is applied to -- the s value and validation either succeeds producing an -- a value, or we collect an error as a value of e -- type. -- -- To run a form composed from fields, see runForm. -- --
--   field fieldName check = withCheck fieldName check (field' fieldName)
--   
field :: forall (names :: [Symbol]) e m a s. (Monad m, FromJSON s) => FieldName names -> (s -> ExceptT e m a) -> FormParser names e m a -- | The same as field, but does not require a checker. -- --
--   field' fieldName = subParser fieldName value
--   
field' :: forall (names :: [Symbol]) e m a. (Monad m, FromJSON a) => FieldName names -> FormParser names e m a -- | Interpret the current field as a value of type a. value :: (Monad m, FromJSON a) => FormParser names e m a -- | Use a given parser to parse a field. Suppose that you have a parser -- loginForm that parses a structure like this one: -- --
--   {
--     "username": "Bob",
--     "password": "123",
--     "remember_me": true
--   }
--   
-- -- Then subParser #login loginForm will parse this: -- --
--   {
--     "login": {
--        "username": "Bob",
--        "password": "123",
--        "remember_me": true
--      }
--   }
--   
subParser :: forall (names :: [Symbol]) e m a. Monad m => FieldName names -> FormParser names e m a -> FormParser names e m a -- | Transform a form by applying a checker on its result. -- --
--   passwordsMatch (a, b) = do
--     if a == b
--       then return a
--       else throwError "Passwords don't match!"
--   
--   passwordForm =
--     withCheck #password_confirmation passwordsMatch
--       ((,) <$> field #password notEmpty
--            <*> field #password_confirmation notEmpty)
--   
-- -- Note that you must specify the field name on which to add a validation -- error message in case the check fails. The field name should be -- relative and point to a field in the argument parser, not full path -- from top-level of the form. For example this form: -- --
--   biggerForm = subParser #password_form passwordForm
--   
-- -- will report validation error for the field -- "password_form.password_confirmation" if the check fails -- (note that "password_form" is correctly prepended to the -- field path). withCheck :: forall (names :: [Symbol]) e m a s. Monad m => FieldName names -> (s -> ExceptT e m a) -> FormParser names e m s -> FormParser names e m a -- | Run a parser on given input. runForm :: Monad m => FormParser names e m a -> Value -> m (FormResult names e a) -- | Project field path from a FieldName. unFieldName :: FieldName names -> NonEmpty Text -- | Project textual representation of path to a field. showFieldName :: FieldName names -> Text -- | The type represents the parser that you can run on a Value with -- the help of runForm. The only way for the user of the library -- to create a parser is via the field function and its friends, -- see below. Users can combine existing parsers using applicative -- notation. -- -- FormParser is parametrized by four type variables: -- -- -- -- FormParser is not a monad because it's not possible to write a -- Monad instance with the properties that we want (validation -- errors should not lead to short-cutting behavior). data FormParser (names :: [Symbol]) e m a -- | Result of parsing. names is the collection of allowed field -- names, e is the type of validation errors, and a is -- the type of parsing result. data FormResult (names :: [Symbol]) e a -- | Parsing of JSON failed, this is fatal, we shut down and report the -- parsing error. The first component specifies path to a problematic -- field and the second component is the text of error message. ParsingFailed :: (Maybe (FieldName names)) -> Text -> FormResult e a -- | Validation of a field failed. This is also fatal but we still try to -- validate other branches (fields) to collect as many validation errors -- as possible. ValidationFailed :: (Map (FieldName names) e) -> FormResult e a -- | Success, we've got a result to return. Succeeded :: a -> FormResult e a -- | FieldName names represents a non-empty vector of -- Text components that serve as a path to some field in a JSON -- structure. Every component is guaranteed to be in the names, -- which is a set of strings on type level. The purpose if this type is -- to avoid typos and to force users to update field names everywhere -- when they decide to change them. The only way to obtain a value of the -- type FieldName is by using OverloadedLabels. Note that -- you can combine field names using (<>). -- --
--   showFieldName (#login_form <> #username) = "login_form.username"
--   
data FieldName (names :: [Symbol]) -- | The type function computes a Constraint which is satisfied when -- its first argument is contained in its second argument. Otherwise a -- friendly type error is displayed. instance GHC.Base.Functor (Web.Forma.FormResult names e) instance (GHC.Show.Show a, GHC.Show.Show e) => GHC.Show.Show (Web.Forma.FormResult names e a) instance (GHC.Classes.Eq a, GHC.Classes.Eq e) => GHC.Classes.Eq (Web.Forma.FormResult names e a) instance GHC.Show.Show (Web.Forma.FieldName names) instance GHC.Classes.Ord (Web.Forma.FieldName names) instance GHC.Classes.Eq (Web.Forma.FieldName names) instance (GHC.TypeLits.KnownSymbol name, Web.Forma.InSet name names) => GHC.OverloadedLabels.IsLabel name (Web.Forma.FieldName names) instance GHC.Base.Functor m => GHC.Base.Functor (Web.Forma.FormParser names e m) instance GHC.Base.Applicative m => GHC.Base.Applicative (Web.Forma.FormParser names e m) instance GHC.Base.Applicative m => GHC.Base.Alternative (Web.Forma.FormParser names e m) instance (Data.Aeson.Types.ToJSON.ToJSON e, Data.Aeson.Types.ToJSON.ToJSON a) => Data.Aeson.Types.ToJSON.ToJSON (Web.Forma.FormResult names e a) instance GHC.Base.Applicative (Web.Forma.FormResult names e) instance Data.Semigroup.Semigroup (Web.Forma.FieldName names) instance Data.Aeson.Types.ToJSON.ToJSON (Web.Forma.FieldName names)