-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | ditto is a type-safe HTML form generation and validation library
--
-- ditto follows in the footsteps of formlets and digestive-functors
-- <= 0.2. It provides a type-safe and composable method for
-- generating an HTML form that includes validation.
@package ditto
@version 0.4.1
-- | Types relevant to forms and their validation.
module Ditto.Types
-- | An ID used to identify forms
data FormId
FormId :: {-# UNPACK #-} !Text -> {-# UNPACK #-} !NonEmpty Int -> FormId
FormIdName :: {-# UNPACK #-} !Text -> {-# UNPACK #-} !Int -> FormId
-- | A range of ID's to specify a group of forms
data FormRange
FormRange :: FormId -> FormId -> FormRange
-- | Encoding a FormId: use this instead of show for the
-- name of the input / query string parameter
encodeFormId :: FormId -> Text
-- | get the head Int from a FormId
formIdentifier :: FormId -> Int
-- | used to represent whether a value was found in the form submission
-- data, missing from the form submission data, or expected that the
-- default value should be used
data Value a
Default :: Value a
Missing :: Value a
Found :: a -> Value a
-- | views, values as a result of the environment, etc.
--
-- Function which creates the form view
newtype View err v
View :: ([(FormRange, err)] -> v) -> View err v
[unView] :: View err v -> [(FormRange, err)] -> v
-- | Proved records a value, the location that value came from, and
-- something that was proved about the value.
data Proved a
Proved :: FormRange -> a -> Proved a
[pos] :: Proved a -> FormRange
[unProved] :: Proved a -> a
-- | Type for failing computations Similar to Either but with an
-- accumilating Applicative instance
newtype Result e ok
Result :: Either [(FormRange, e)] ok -> Result e ok
[getResult] :: Result e ok -> Either [(FormRange, e)] ok
pattern Error :: forall e ok. [(FormRange, e)] -> Result e ok
pattern Ok :: forall e ok. ok -> Result e ok
instance GHC.Show.Show Ditto.Types.FormId
instance GHC.Classes.Ord Ditto.Types.FormId
instance GHC.Classes.Eq Ditto.Types.FormId
instance GHC.Show.Show Ditto.Types.FormRange
instance GHC.Classes.Eq Ditto.Types.FormRange
instance GHC.Base.Functor (Ditto.Types.View err)
instance GHC.Base.Monoid v => GHC.Base.Monoid (Ditto.Types.View err v)
instance GHC.Base.Semigroup v => GHC.Base.Semigroup (Ditto.Types.View err v)
instance Data.Foldable.Foldable Ditto.Types.Value
instance Data.Traversable.Traversable Ditto.Types.Value
instance GHC.Base.Functor Ditto.Types.Value
instance GHC.Show.Show a => GHC.Show.Show (Ditto.Types.Value a)
instance GHC.Classes.Eq a => GHC.Classes.Eq (Ditto.Types.Value a)
instance GHC.Base.Monad (Ditto.Types.Result e)
instance Data.Traversable.Traversable (Ditto.Types.Result e)
instance Data.Foldable.Foldable (Ditto.Types.Result e)
instance GHC.Base.Functor (Ditto.Types.Result e)
instance (GHC.Classes.Eq e, GHC.Classes.Eq ok) => GHC.Classes.Eq (Ditto.Types.Result e ok)
instance (GHC.Show.Show e, GHC.Show.Show ok) => GHC.Show.Show (Ditto.Types.Result e ok)
instance Data.Traversable.Traversable Ditto.Types.Proved
instance Data.Foldable.Foldable Ditto.Types.Proved
instance GHC.Base.Functor Ditto.Types.Proved
instance GHC.Show.Show a => GHC.Show.Show (Ditto.Types.Proved a)
instance GHC.Base.Applicative (Ditto.Types.Result e)
instance GHC.Base.Applicative Ditto.Types.Value
instance GHC.Base.Alternative Ditto.Types.Value
instance GHC.Base.Semigroup a => GHC.Base.Semigroup (Ditto.Types.Value a)
instance Data.String.IsString Ditto.Types.FormId
-- | This module contains two classes. FormInput is a class which is
-- parameterized over the input type used to represent form data
-- in different web frameworks. There should be one instance for each
-- framework, such as Happstack, Snap, WAI, etc.
--
-- The FormError class is used to map error messages into an
-- application specific error type.
module Ditto.Backend
-- | an error type used to represent errors that are common to all backends
--
-- These errors should only occur if there is a bug in the ditto-*
-- packages. Perhaps we should make them an Exception so that we
-- can get rid of the FormError class.
data CommonFormError input
InputMissing :: FormId -> CommonFormError input
NoStringFound :: input -> CommonFormError input
NoFileFound :: input -> CommonFormError input
MultiFilesFound :: input -> CommonFormError input
MultiStringsFound :: input -> CommonFormError input
MissingDefaultValue :: CommonFormError input
-- | some default error messages for CommonFormError
commonFormErrorStr :: (input -> String) -> CommonFormError input -> String
-- | some default error messages for CommonFormError
commonFormErrorText :: (input -> Text) -> CommonFormError input -> Text
-- | A Class to lift a CommonFormError into an application-specific
-- error type
class FormError input err
commonFormError :: FormError input err => CommonFormError input -> err
-- | Class which all backends should implement.
class FormInput input where {
-- | input is here the type that is used to represent a value
-- uploaded by the client in the request.
type family FileType input;
}
-- | Parse the input into a string. This is used for simple text fields
-- among other things
getInputString :: (FormInput input, FormError input err) => input -> Either err String
getInputStrings :: FormInput input => input -> [String]
-- | Parse the input value into Text
getInputText :: (FormInput input, FormError input err) => input -> Either err Text
getInputTexts :: FormInput input => input -> [Text]
-- | Get a file descriptor for an uploaded file
getInputFile :: (FormInput input, FormError input err) => input -> Either err (FileType input)
instance GHC.Show.Show input => GHC.Show.Show (Ditto.Backend.CommonFormError input)
instance GHC.Classes.Ord input => GHC.Classes.Ord (Ditto.Backend.CommonFormError input)
instance GHC.Classes.Eq input => GHC.Classes.Eq (Ditto.Backend.CommonFormError input)
instance Ditto.Backend.FormError Data.Text.Internal.Text Data.Text.Internal.Text
-- | The core module for ditto.
--
-- This module provides the Form type and helper functions for
-- constructing typesafe forms inside arbitrary "views" / web frameworks.
-- ditto is meant to be a generalized formlet library used to
-- write formlet libraries specific to a web / gui framework
module Ditto.Core
-- | The Form's state is just the range of identifiers so far
type FormState m = StateT FormRange m
-- | ditto's representation of a formlet
--
-- It's reccommended to use ApplicativeDo where possible when
-- constructing forms
data Form m input err view a
Form :: (input -> m (Either err a)) -> m a -> FormState m (View err view, Result err (Proved a)) -> Form m input err view a
-- | Decode the value from the input
[formDecodeInput] :: Form m input err view a -> input -> m (Either err a)
-- | The initial value
[formInitialValue] :: Form m input err view a -> m a
-- | A FormState which produces a View and a
-- Result
[formFormlet] :: Form m input err view a -> FormState m (View err view, Result err (Proved a))
-- | The environment typeclass: the interface between ditto and a given
-- framework
class Monad m => Environment m input | m -> input
environment :: Environment m input => FormId -> m (Value input)
-- | Run the form, but always return the initial value
newtype NoEnvironment input m a
NoEnvironment :: m a -> NoEnvironment input m a
[getNoEnvironment] :: NoEnvironment input m a -> m a
-- | Run the form, but with a given environment function
newtype WithEnvironment input m a
WithEnvironment :: ReaderT (FormId -> m (Value input)) m a -> WithEnvironment input m a
[getWithEnvironment] :: WithEnvironment input m a -> ReaderT (FormId -> m (Value input)) m a
-- | environment which will always return the initial value
noEnvironment :: Applicative m => FormId -> m (Value input)
-- | infix mapView: succinctly mix the view dsl and the formlets
-- dsl e.g. div_ [class_ "my cool form"] @$ do (_ :: Form m input err
-- view' a).
(@$) :: Monad m => (view -> view') -> Form m input err view a -> Form m input err view' a
infixr 0 @$
-- | Catch errors purely
catchFormError :: Monad m => ([err] -> a) -> Form m input err view a -> Form m input err view a
-- | Catch errors inside Form / m
catchFormErrorM :: Monad m => Form m input err view a -> ([err] -> Form m input err view a) -> Form m input err view a
-- | Evaluate a form
--
-- Returns:
--
--
-- - Left view on failure. The view will be
-- produced by a View err view, which can be modified with
-- functions like withChildErrors for the sake of rendering
-- errors.
-- - Right a on success.
--
eitherForm :: Monad m => Text -> Form m input err view a -> m (Either view a)
-- | Get a FormId from the FormState
getFormId :: Monad m => FormState m FormId
-- | Utility function: Get the current input
getFormInput :: Environment m input => FormState m (Value input)
-- | Utility function: Gets the input of an arbitrary FormId.
getFormInput' :: Environment m input => FormId -> FormState m (Value input)
-- | Utility function: Get the current range
getFormRange :: Monad m => FormState m FormRange
-- | Get a FormIdName from the FormState
getNamedFormId :: Monad m => Text -> FormState m FormId
-- | Increment a form ID
incrementFormId :: FormId -> FormId
-- | Check if a FormId is contained in a FormRange
isInRange :: FormId -> FormRange -> Bool
-- | Map over the Result and View of a form
mapResult :: Monad m => (Result err (Proved a) -> Result err (Proved a)) -> (View err view -> View err view) -> Form m input err view a -> Form m input err view a
-- | Common operations on Forms
--
-- Change the view of a form using a simple function
--
-- This is useful for wrapping a form inside of a <fieldset> or
-- other markup element.
mapView :: Functor m => (view -> view') -> Form m input err view a -> Form m input err view' a
-- | Utility Function: turn a view and pure value into a successful
-- FormState
mkOk :: Monad m => FormId -> view -> a -> FormState m (View err view, Result err (Proved a))
-- | Select the errors originating from this form or from any of the
-- children of this form
retainChildErrors :: FormRange -> [(FormRange, e)] -> [e]
-- | Select the errors for a certain range
retainErrors :: FormRange -> [(FormRange, e)] -> [e]
-- | Run a form
runForm :: Monad m => Text -> Form m input err view a -> m (View err view, Result err (Proved a))
-- | Run a form, and unwrap the result
runForm_ :: Monad m => Text -> Form m input err view a -> m (view, Maybe a)
-- | Always succeed decoding
successDecode :: Applicative m => a -> input -> m (Either err a)
-- | Turns a FormId into a FormRange by incrementing the
-- base for the end Id
unitRange :: FormId -> FormRange
-- | Make a form which renders a view, accepts no input and
-- produces no output
view :: Monad m => view -> Form m input err view ()
-- | Run the form with no environment, return only the html. This means
-- that the values will always be their defaults
viewForm :: Monad m => Text -> Form m input err view a -> m view
-- | lift the result of a decoding to a Form
pureRes :: (Monad m, Monoid view, FormError input err) => a -> Either err a -> Form m input err view a
-- | Form is a MonadTrans, but we can't have an instance
-- of it because of the order and kind of its type variables
liftForm :: (Monad m, Monoid view) => m a -> Form m input err view a
instance GHC.Base.Functor m => GHC.Base.Functor (Ditto.Core.Form m input err view)
instance GHC.Base.Applicative m => GHC.Base.Applicative (Ditto.Core.NoEnvironment input m)
instance GHC.Base.Functor m => GHC.Base.Functor (Ditto.Core.NoEnvironment input m)
instance GHC.Base.Monad m => GHC.Base.Monad (Ditto.Core.NoEnvironment input m)
instance GHC.Base.Applicative m => GHC.Base.Applicative (Ditto.Core.WithEnvironment input m)
instance GHC.Base.Functor m => GHC.Base.Functor (Ditto.Core.WithEnvironment input m)
instance GHC.Base.Monad m => GHC.Base.Monad (Ditto.Core.WithEnvironment input m)
instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (Ditto.Types.FormId -> m (Ditto.Types.Value input)) (Ditto.Core.WithEnvironment input m)
instance Control.Monad.Trans.Class.MonadTrans (Ditto.Core.WithEnvironment input)
instance GHC.Base.Monad m => Ditto.Core.Environment (Ditto.Core.WithEnvironment input m) input
instance GHC.Base.Monad m => Ditto.Core.Environment (Ditto.Core.NoEnvironment input m) input
instance (Ditto.Core.Environment m input, GHC.Base.Monoid view, Ditto.Backend.FormError input err) => GHC.Base.Monad (Ditto.Core.Form m input err view)
instance (GHC.Base.Monad m, GHC.Base.Monoid view, Ditto.Backend.FormError input err, Ditto.Core.Environment m input) => GHC.Base.Alternative (Ditto.Core.Form m input err view)
instance (GHC.Base.Monad m, GHC.Base.Monoid view) => GHC.Base.Applicative (Ditto.Core.Form m input err view)
instance (GHC.Base.Monad m, GHC.Base.Monoid view, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Ditto.Core.Form m input err view a)
instance (GHC.Base.Monad m, GHC.Base.Monoid view, GHC.Base.Monoid a) => GHC.Base.Monoid (Ditto.Core.Form m input err view a)
instance GHC.Base.Functor m => Data.Bifunctor.Bifunctor (Ditto.Core.Form m input err)
-- | This module defines the Proof type, some proofs, and some
-- helper functions.
--
-- A Proof does three things:
--
--
-- - verifies that the input value meets some criteria
-- - optionally transforms the input value to another value while
-- preserving that criteria
-- - puts the proof name in type-signature where the type-checker can
-- use it
--
module Ditto.Proof
-- | A Proof attempts to prove something about a value.
--
-- If successful, it can also transform the value to a new value. The
-- proof should hold for the new value as well.
--
-- Generally, each Proof has a unique data-type associated with it
-- which names the proof, such as:
data Proof m err a b
Proof :: (a -> m (Either err b)) -> (a -> b) -> Proof m err a b
-- | function which provides the proof
[proofFunction] :: Proof m err a b -> a -> m (Either err b)
-- | usually const b
[proofNewInitialValue] :: Proof m err a b -> a -> b
-- | apply a Proof to a Form
prove :: (Monad m, Monoid view, FormError input error) => Form m input error view a -> Proof m error a b -> Form m input error view b
-- | transform the Form result using a monadic Either
-- function.
transformEitherM :: (Monad m, Monoid view, FormError input error) => Form m input error view a -> (a -> m (Either error b)) -> (a -> b) -> Form m input error view b
-- | transform the Form result using an Either function.
transformEither :: (Monad m, Monoid view, FormError input error) => Form m input error view a -> (a -> Either error b) -> (a -> b) -> Form m input error view b
-- | prove that a list is not empty
notNullProof :: Monad m => error -> Proof m error [a] [a]
-- | read an unsigned number in decimal notation
decimal :: (Monad m, Eq i, Num i) => (String -> error) -> i -> Proof m error String i
-- | read signed decimal number
signedDecimal :: (Monad m, Eq i, Real i) => (String -> error) -> i -> Proof m error String i
-- | read RealFrac number
realFrac :: (Monad m, RealFrac a) => (String -> error) -> a -> Proof m error String a
-- | read a signed RealFrac number
realFracSigned :: (Monad m, RealFrac a) => (String -> error) -> a -> Proof m error String a
instance GHC.Base.Functor m => GHC.Base.Functor (Ditto.Proof.Proof m err a)
-- | This module provides helper functions for HTML input elements. These
-- helper functions are not specific to any particular web framework or
-- html library.
--
-- Additionally, the inputs generated with the functions from this module
-- will have their names/ids automatically enumerated.
--
-- For named formlets, see Ditto.Generalized.Named
module Ditto.Generalized.Unnamed
-- | a choice for inputChoice
data Choice lbl a
Choice :: FormId -> lbl -> Bool -> a -> Choice lbl a
-- | the formId
[choiceFormId] :: Choice lbl a -> FormId
-- | label
[choiceLabel] :: Choice lbl a -> lbl
-- | is the choice selected
[choiceIsSelected] :: Choice lbl a -> Bool
-- | the haskell value of the choice
[choiceVal] :: Choice lbl a -> a
-- | used for constructing elements like <input
-- type="text">, which pure a single input value.
input :: (Environment m input, FormError input err) => (input -> Either err a) -> (FormId -> a -> view) -> a -> Form m input err view a
-- | used for elements like <input type="submit"> which are
-- not always present in the form submission data.
inputMaybe :: (Environment m input, FormError input err) => (input -> Either err a) -> (FormId -> Maybe a -> view) -> Maybe a -> Form m input err view (Maybe a)
-- | used for elements like <input type="reset"> which take
-- a value, but are never present in the form data set.
inputNoData :: Environment m input => (FormId -> view) -> Form m input err view ()
-- | used for <input type="file">
inputFile :: forall m input err view ft. (Environment m input, FormInput input, FormError input err, ft ~ FileType input, Monoid ft) => (FormId -> view) -> Form m input err view (FileType input)
-- | used for groups of checkboxes, <select
-- multiple="multiple"> boxes
inputMulti :: forall m input err view a lbl. (FormError input err, FormInput input, Environment m input, Eq a) => [(a, lbl)] -> (input -> Either err [a]) -> (FormId -> [Choice lbl a] -> view) -> (a -> Bool) -> Form m input err view [a]
-- | radio buttons, single <select> boxes
inputChoice :: forall a m err input lbl view. (FormError input err, FormInput input, Environment m input, Eq a, Monoid view) => (a -> Bool) -> NonEmpty (a, lbl) -> (input -> Either err a) -> (FormId -> [Choice lbl a] -> view) -> Form m input err view a
-- | this is necessary in order to basically map over the decoding function
inputList :: forall m input err a view. (Monad m, FormError input err, Environment m input) => (input -> m (Either err [a])) -> ([view] -> view) -> [a] -> view -> (a -> Form m input err view a) -> Form m input err view [a]
-- | used to create <label> elements
label :: Environment m input => (FormId -> view) -> Form m input err view ()
-- | used to add a list of err messages to a Form
--
-- This function automatically takes care of extracting only the errors
-- that are relevent to the form element it is attached to via
-- <* or *>.
errors :: Environment m input => ([err] -> view) -> Form m input err view ()
-- | similar to errors but includes err messages from children of
-- the form as well.
childErrors :: Environment m input => ([err] -> view) -> Form m input err view ()
-- | modify the view of a form based on its errors
withErrors :: Environment m input => (view -> [err] -> view) -> Form m input err view a -> Form m input err view a
-- | modify the view of a form based on its child errors
withChildErrors :: Monad m => (view -> [err] -> view) -> Form m input err view a -> Form m input err view a
-- | This module provides helper functions for HTML input elements. These
-- helper functions are not specific to any particular web framework or
-- html library.
--
-- For unnamed (enumerated) formlets, see
-- Ditto.Generalized.Unnamed
module Ditto.Generalized.Named
-- | a choice for inputChoice
data Choice lbl a
Choice :: FormId -> lbl -> Bool -> a -> Choice lbl a
-- | the formId
[choiceFormId] :: Choice lbl a -> FormId
-- | label
[choiceLabel] :: Choice lbl a -> lbl
-- | is the choice selected
[choiceIsSelected] :: Choice lbl a -> Bool
-- | the haskell value of the choice
[choiceVal] :: Choice lbl a -> a
-- | used for constructing elements like <input
-- type="text">, which pure a single input value.
input :: (Environment m input, FormError input err) => Text -> (input -> Either err a) -> (FormId -> a -> view) -> a -> Form m input err view a
-- | used for elements like <input type="submit"> which are
-- not always present in the form submission data.
inputMaybe :: (Environment m input, FormError input err) => Text -> (input -> Either err a) -> (FormId -> Maybe a -> view) -> Maybe a -> Form m input err view (Maybe a)
-- | used for elements like <input type="reset"> which take
-- a value, but are never present in the form data set.
inputNoData :: Environment m input => Text -> (FormId -> view) -> Form m input err view ()
-- | used for <input type="file">
inputFile :: forall m input err view ft. (Environment m input, FormInput input, FormError input err, ft ~ FileType input, Monoid ft) => Text -> (FormId -> view) -> Form m input err view (FileType input)
-- | used for groups of checkboxes, <select
-- multiple="multiple"> boxes
inputMulti :: forall m input err view a lbl. (FormError input err, FormInput input, Environment m input, Eq a) => Text -> [(a, lbl)] -> (input -> Either err [a]) -> (FormId -> [Choice lbl a] -> view) -> (a -> Bool) -> Form m input err view [a]
-- | radio buttons, single <select> boxes
inputChoice :: forall a m err input lbl view. (FormError input err, FormInput input, Environment m input, Eq a, Monoid view) => Text -> (a -> Bool) -> NonEmpty (a, lbl) -> (input -> Either err a) -> (FormId -> [Choice lbl a] -> view) -> Form m input err view a
-- | this is necessary in order to basically map over the decoding function
inputList :: forall m input err a view. (Monad m, FormError input err, Environment m input) => Text -> (input -> m (Either err [a])) -> ([view] -> view) -> [a] -> view -> (a -> Form m input err view a) -> Form m input err view [a]
-- | used to create <label> elements
label :: Environment m input => Text -> (FormId -> view) -> Form m input err view ()
-- | used to add a list of err messages to a Form
--
-- This function automatically takes care of extracting only the errors
-- that are relevent to the form element it is attached to via
-- <* or *>.
errors :: Environment m input => ([err] -> view) -> Form m input err view ()
-- | similar to errors but includes err messages from children of
-- the form as well.
childErrors :: Environment m input => ([err] -> view) -> Form m input err view ()
-- | modify the view of a form based on its errors
withErrors :: Environment m input => (view -> [err] -> view) -> Form m input err view a -> Form m input err view a
-- | modify the view of a form based on its child errors
withChildErrors :: Monad m => (view -> [err] -> view) -> Form m input err view a -> Form m input err view a
-- | a Form with no view
ireq :: forall m input view err a. (Monoid view, Environment m input, FormError input err) => Text -> (input -> Either err a) -> a -> Form m input err view a
-- | an optional Form with no view
iopt :: forall m input view err a. (Monoid view, Environment m input, FormError input err) => Text -> (input -> Either err a) -> Maybe a -> Form m input err view (Maybe a)
-- | Reexports important modules of ditto
module Ditto