-- 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 0.2.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:
--   
--   <ul>
--   <li>Smoother user experience: no need to reload the whole page.</li>
--   <li>Form rendering is separated and lives only in GET handler, POST
--   (or whatever method you deem appropriate for your use case) handler
--   only handles validation and actual effects that form submission should
--   initiate.</li>
--   <li>You get a chance to organize form input just like you want.</li>
--   </ul>
--   
--   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:
--   
--   <ul>
--   <li>Define form parser using type-safe applicative notation with field
--   labels being stored on the type label which excludes any possibility
--   of typos and will force all your field labels be always up to
--   date.</li>
--   <li>Parse JSON <a>Value</a> according to the definition of form you
--   created.</li>
--   <li>Stop parsing immediately if given form is malformed and cannot be
--   processed.</li>
--   <li>Validate forms using any number of <i>composable</i> checkers that
--   you write for your specific problem domain. Once you have a vocabulary
--   of checkers, creation of new forms is just a matter of combining them,
--   and yes they do combine nicely.</li>
--   <li>Collect validation errors from multiple branches of parsing (one
--   branch per form field) in parallel, so validation errors in one branch
--   do not prevent us from collecting validation errors from other
--   branches. This allows for a better user experience as the user can see
--   all validation errors at the same time.</li>
--   <li>Use <a>optional</a> and <tt>(<a>&lt;|&gt;</a>)</tt> from
--   <a>Control.Applicative</a> in your form definitions instead of ugly
--   ad-hoc stuff (yes <tt>digestive-functors</tt>, I'm looking at
--   you).</li>
--   <li>When individual validation of fields is done, you get a chance to
--   perform some actions and either decide that form submission has
--   succeeded, or indeed perform additional checks that may depend on
--   several form fields at once and signal a validation error assigned to
--   a specific field(s). This constitute the “second level” of validation,
--   so to speak.</li>
--   </ul>
--   
--   <b>This library requires at least GHC 8 to work.</b>
--   
--   You need to enable at least <tt>DataKinds</tt> and
--   <tt>TypeApplications</tt> language extensions to use this library.
module Web.Forma

-- | Construct a parser for a field. Combine multiple <a>field</a>s using
--   applicative syntax like so:
--   
--   <pre>
--   type LoginFields = '["username", "password", "remember_me"]
--   
--   data LoginForm = LoginForm
--     { loginUsername   :: Text
--     , loginPassword   :: Text
--     , loginRememberMe :: Bool
--     }
--   
--   loginForm :: Monad m =&gt; FormParser LoginFields m LoginForm
--   loginForm = LoginForm
--     &lt;$&gt; field @"username" notEmpty
--     &lt;*&gt; field @"password" notEmpty
--     &lt;*&gt; field' @"remember_me"
--   
--   notEmpty :: Monad m =&gt; Text -&gt; ExceptT Text m Text
--   notEmpty txt =
--     if T.null txt
--       then throwError "This field cannot be empty"
--       else return txt
--   </pre>
--   
--   Referring to the types in the function's signature, <tt>s</tt> is
--   extracted from JSON <a>Value</a> for you automatically using its
--   <a>FromJSON</a> instance. The field value is taken in assumption that
--   top level <a>Value</a> 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:
--   
--   <pre>
--   {
--     "username": "Bob",
--     "password": "123",
--     "remember_me": true
--   }
--   </pre>
--   
--   Once value of type <tt>s</tt> is extracted, validation phase beings.
--   The supplied checker (you can easy compose them with
--   <tt>(<a>&gt;=&gt;</a>)</tt>, as they are Kleisli arrows) is applied to
--   the <tt>s</tt> value and validation either succeeds producing an
--   <tt>a</tt> value, or we collect an error in the form of a value of
--   <tt>e</tt> type, which is fed into <a>mkFieldError</a> internally.
--   
--   To run a form composed from <a>field</a>s, see <a>runForm</a>.
field :: forall (name :: Symbol) (names :: [Symbol]) m e s a. (KnownSymbol name, InSet name names, Monad m, ToJSON e, FromJSON s) => (s -> ExceptT e m a) -> FormParser names m a

-- | The same as <a>field</a>, but does not require a checker.
field' :: forall (name :: Symbol) (names :: [Symbol]) m a. (KnownSymbol name, InSet name names, Monad m, FromJSON a) => FormParser names m a

-- | Transform a form by applying a checker on its result.
--   
--   <pre>
--   passwordsMatch (a, b) = do
--     if a == b
--       then return a
--       else throwError "Passwords don't match!"
--   
--   createNewPasswordForm =
--     withCheck @"password_confirmation" passwordsMatch
--       ((,) &lt;$&gt; field @"password" notEmpty
--            &lt;*&gt; field @"password_confirmation" notEmpty)
--   </pre>
--   
--   Note that you must specify the field name on which to add a validation
--   error message in case the check fails.
withCheck :: forall (name :: Symbol) (names :: [Symbol]) m e s a. (KnownSymbol name, InSet name names, Monad m, ToJSON e) => (s -> ExceptT e m a) -> FormParser names m s -> FormParser names m a

-- | Run the supplied parser on given input and call the specified callback
--   that uses the result of parsing on success.
--   
--   The callback can either report a <a>FieldError</a> (one or more), or
--   report success providing a value that will be converted to JSON and
--   included in the resulting <a>Value</a> (response).
--   
--   The resulting <a>Value</a> has the following format:
--   
--   <pre>
--   {
--     "parse_error": "Text or null."
--     "field_errors":
--       {
--         "foo": "Foo's error serialized to JSON.",
--         "bar": "Bar's error…"
--       }
--     "result": "What you return from the callback in FormResultSuccess."
--   }
--   </pre>
runForm :: (Monad m, ToJSON b) => FormParser names m a -> Value -> (a -> m (FormResult names b)) -> m Value

-- | Pick a name from a given collection of names.
--   
--   Typical usage:
--   
--   <pre>
--   type Fields = '["foo", "bar", "baz"]
--   
--   myName :: SelectedName Fields
--   myName = pick @"foo" @Fields
--   </pre>
--   
--   It's a good idea to use <a>pick</a> to get field names not only where
--   this approach is imposed by the library, but everywhere you need to
--   use the field names, in your templates for example.
pick :: forall (name :: Symbol) (names :: [Symbol]). (KnownSymbol name, InSet name names) => SelectedName names

-- | Extract a <a>Text</a> value from <a>SelectedName</a>.
unSelectedName :: SelectedName names -> Text

-- | This is a smart constructor for the <a>FieldError</a> type, and the
--   only way to obtain values of that type.
--   
--   Typical usage:
--   
--   <pre>
--   type Fields = '["foo", "bar", "baz"]
--   
--   myError :: FieldError Fields
--   myError = mkFieldError (pick @"foo" @Fields) "That's all wrong."
--   </pre>
--   
--   See also: <a>pick</a> (to create <a>SelectedName</a>).
mkFieldError :: ToJSON e => SelectedName names -> e -> FieldError names

-- | The type represents the parser that you can run on a <a>Value</a> with
--   the help of <a>runForm</a>. The only way for the user of the library
--   to create a parser is via the <a>field</a> function. Users can combine
--   existing parsers using the applicative notation.
--   
--   <a>FormParser</a> is parametrized by three type variables:
--   
--   <ul>
--   <li><tt>names</tt>—collection of field names we can use in a form to
--   be parsed with this parser.</li>
--   <li><tt>m</tt>—underlying monad, <a>FormParser</a> is not a monad
--   itself, so it's not a monad transformer, but validation can make use
--   of the <tt>m</tt> monad.</li>
--   <li><tt>a</tt>—result of parsing.</li>
--   </ul>
--   
--   <a>FormParser</a> is not a monad because it's not possible to write a
--   <a>Monad</a> instance with the properties that we want (validation
--   errors should not lead to short-cutting behavior).
data FormParser (names :: [Symbol]) m a

-- | This a type that user must return in the callback passed to the
--   <a>runForm</a> function. Quite simply, it allows you either report a
--   error or finish successfully.
data FormResult (names :: [Symbol]) a

-- | Form submission failed, here are the validation errors.
FormResultError :: (FieldError names) -> FormResult a

-- | Form submission succeeded, send this info.
FormResultSuccess :: a -> FormResult a

-- | <tt><a>SelectedName</a> names</tt> represents a name (<a>Text</a>
--   value) that is guaranteed to be in the <tt>names</tt>, 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 type
--   <a>SelectedName</a> is via the <a>pick</a> function, which see.
data SelectedName (names :: [Symbol])

-- | The type function computes a <a>Constraint</a> which is satisfied when
--   its first argument is contained in its second argument. Otherwise a
--   friendly type error is displayed.

-- | Error info in JSON format associated with a particular form field.
--   Parametrized by <tt>names</tt>, which is a collection of field names
--   (on type level) the target field belongs to. <a>FieldError</a> is an
--   instance of <a>Semigroup</a> and that's how you combine values of that
--   type. Note that it's not a <a>Monoid</a>, because we do not want to
--   allow empty <a>FieldError</a>s.
data FieldError (names :: [Symbol])
instance GHC.Base.Functor (Web.Forma.BranchState names)
instance GHC.Show.Show a => GHC.Show.Show (Web.Forma.FormResult names a)
instance GHC.Classes.Eq a => GHC.Classes.Eq (Web.Forma.FormResult names a)
instance GHC.Show.Show (Web.Forma.FieldError names)
instance GHC.Classes.Eq (Web.Forma.FieldError names)
instance GHC.Show.Show (Web.Forma.SelectedName names)
instance GHC.Classes.Eq (Web.Forma.SelectedName names)
instance Data.Default.Class.Default (Web.Forma.Response names)
instance Data.Aeson.Types.ToJSON.ToJSON (Web.Forma.Response names)
instance GHC.Base.Functor m => GHC.Base.Functor (Web.Forma.FormParser names m)
instance GHC.Base.Applicative m => GHC.Base.Applicative (Web.Forma.FormParser names m)
instance GHC.Base.Applicative m => GHC.Base.Alternative (Web.Forma.FormParser names m)
instance GHC.Base.Applicative (Web.Forma.BranchState names)
instance Data.Semigroup.Semigroup (Web.Forma.FieldError names)
instance Data.Aeson.Types.ToJSON.ToJSON (Web.Forma.FieldError names)
