{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TypeFamilies #-}
module FieldParser where
import Control.Category qualified as Cat
import Control.Monad ((<=<))
import Data.Aeson qualified as Json
import Data.Aeson.BetterErrors qualified as Json
import Data.Aeson.Types qualified as Json
import Data.Attoparsec.ByteString qualified as AttoBytes
import Data.Attoparsec.Text qualified as Atto
import Data.CaseInsensitive qualified as CaseInsensitive
import Data.Error.Tree
import Data.List.NonEmpty qualified as NonEmpty
import Data.Map.Strict qualified as Map
import Data.Scientific (Scientific)
import Data.Scientific qualified as Scientific
import Data.Semigroup.Foldable (Foldable1 (toNonEmpty))
import Data.Semigroupoid qualified as Semigroupoid
import Data.Text qualified as Text
import PossehlAnalyticsPrelude
import Text.ParserCombinators.ReadPrec qualified as Read
newtype FieldParser' err from to = FieldParser (from -> Either err to)
deriving stock (forall a b. a -> FieldParser' err from b -> FieldParser' err from a
forall a b.
(a -> b) -> FieldParser' err from a -> FieldParser' err from b
forall err from a b.
a -> FieldParser' err from b -> FieldParser' err from a
forall err from a b.
(a -> b) -> FieldParser' err from a -> FieldParser' err from b
forall (f :: Type -> Type).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> FieldParser' err from b -> FieldParser' err from a
$c<$ :: forall err from a b.
a -> FieldParser' err from b -> FieldParser' err from a
fmap :: forall a b.
(a -> b) -> FieldParser' err from a -> FieldParser' err from b
$cfmap :: forall err from a b.
(a -> b) -> FieldParser' err from a -> FieldParser' err from b
Functor)
type FieldParser from to = FieldParser' Error from to
instance Semigroupoid (FieldParser' err) where
o :: FieldParser' err middle to -> FieldParser' err from middle -> FieldParser' err from to
o :: forall j k1 i.
FieldParser' err j k1
-> FieldParser' err i j -> FieldParser' err i k1
o (FieldParser middle -> Either err to
f) (FieldParser from -> Either err middle
g) = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser (middle -> Either err to
f forall (m :: Type -> Type) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< from -> Either err middle
g)
instance Cat.Category (FieldParser' err) where
id :: FieldParser' err a a
id :: forall a. FieldParser' err a a
id = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall (f :: Type -> Type) a. Applicative f => a -> f a
pure
. :: forall b c a.
FieldParser' err b c
-> FieldParser' err a b -> FieldParser' err a c
(.) = forall {k} (c :: k -> k -> Type) (j :: k) (k1 :: k) (i :: k).
Semigroupoid c =>
c j k1 -> c i j -> c i k1
Semigroupoid.o
instance Profunctor (FieldParser' err) where
dimap :: (from' -> from) -> (to -> to') -> FieldParser' err from to -> FieldParser' err from' to'
dimap :: forall a b c d.
(a -> b)
-> (c -> d) -> FieldParser' err b c -> FieldParser' err a d
dimap from' -> from
pre to -> to'
post (FieldParser from -> Either err to
parser) = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser (forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap to -> to'
post forall b c a. (b -> c) -> (a -> b) -> a -> c
. from -> Either err to
parser forall b c a. (b -> c) -> (a -> b) -> a -> c
. from' -> from
pre)
runFieldParser :: FieldParser' err from to -> from -> Either err to
runFieldParser :: forall err from to.
FieldParser' err from to -> from -> Either err to
runFieldParser (FieldParser from -> Either err to
fn) = from -> Either err to
fn
mapError :: (err1 -> err2) -> FieldParser' err1 from to -> FieldParser' err2 from to
mapError :: forall err1 err2 from to.
(err1 -> err2)
-> FieldParser' err1 from to -> FieldParser' err2 from to
mapError err1 -> err2
f (FieldParser from -> Either err1 to
original) = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \from
from -> from -> Either err1 to
original from
from forall a b. a -> (a -> b) -> b
& forall (p :: Type -> Type -> Type) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first err1 -> err2
f
toParseJSON ::
FieldParser Json.Value a ->
Json.Value ->
Json.Parser a
toParseJSON :: forall a. FieldParser Value a -> Value -> Parser a
toParseJSON FieldParser Value a
parser =
forall err a. (err -> Text) -> Parse err a -> Value -> Parser a
Json.toAesonParser
Error -> Text
prettyError
(forall (m :: Type -> Type) err to.
Monad m =>
FieldParser' err Value to -> ParseT err m to
jsonParser FieldParser Value a
parser)
toParseJSONErrorTree ::
FieldParser' ErrorTree Json.Value a ->
Json.Value ->
Json.Parser a
toParseJSONErrorTree :: forall a. FieldParser' ErrorTree Value a -> Value -> Parser a
toParseJSONErrorTree FieldParser' ErrorTree Value a
parser =
forall err a. (err -> Text) -> Parse err a -> Value -> Parser a
Json.toAesonParser
ErrorTree -> Text
prettyErrorTree
(forall (m :: Type -> Type) err to.
Monad m =>
FieldParser' err Value to -> ParseT err m to
jsonParser FieldParser' ErrorTree Value a
parser)
toReadPrec ::
Read.ReadPrec from ->
FieldParser from to ->
Read.ReadPrec to
toReadPrec :: forall from to. ReadPrec from -> FieldParser from to -> ReadPrec to
toReadPrec ReadPrec from
innerReadPrec FieldParser from to
parser = do
from
from :: from <- ReadPrec from
innerReadPrec
case forall err from to.
FieldParser' err from to -> from -> Either err to
runFieldParser FieldParser from to
parser from
from of
Left Error
err -> forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail (Error
err forall a b. a -> (a -> b) -> b
& Error -> Text
prettyError forall a b. a -> (a -> b) -> b
& Text -> String
textToString)
Right to
a -> forall (f :: Type -> Type) a. Applicative f => a -> f a
pure to
a
jsonParser :: Monad m => FieldParser' err Json.Value to -> Json.ParseT err m to
jsonParser :: forall (m :: Type -> Type) err to.
Monad m =>
FieldParser' err Value to -> ParseT err m to
jsonParser FieldParser' err Value to
parser =
( forall (m :: Type -> Type) err.
(Functor m, Monad m) =>
ParseT err m Value
Json.asValue
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= ( \Value
from ->
forall err from to.
FieldParser' err from to -> from -> Either err to
runFieldParser FieldParser' err Value to
parser Value
from forall a b. a -> (a -> b) -> b
& \case
Right to
a -> forall (f :: Type -> Type) a. Applicative f => a -> f a
pure to
a
Left err
err -> forall (m :: Type -> Type) err a.
(Functor m, Monad m) =>
err -> ParseT err m a
Json.throwCustomError err
err
)
)
jsonBool :: FieldParser Json.Value Bool
jsonBool :: FieldParser Value Bool
jsonBool = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \case
Json.Bool Bool
b -> forall a b. b -> Either a b
Right Bool
b
Value
_ -> forall a b. a -> Either a b
Left Error
"Not a json boolean"
jsonNull :: FieldParser Json.Value ()
jsonNull :: FieldParser Value ()
jsonNull = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \case
Value
Json.Null -> forall a b. b -> Either a b
Right ()
Value
_ -> forall a b. a -> Either a b
Left Error
"Not a json `null`"
jsonNumber :: FieldParser Json.Value Scientific
jsonNumber :: FieldParser Value Scientific
jsonNumber = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \case
Json.Number Scientific
s -> forall a b. b -> Either a b
Right Scientific
s
Value
_ -> forall a b. a -> Either a b
Left Error
"Not a json number"
jsonString :: FieldParser Json.Value Text
jsonString :: FieldParser Value Text
jsonString = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \case
Json.String Text
s -> forall a b. b -> Either a b
Right Text
s
Value
_ -> forall a b. a -> Either a b
Left Error
"Not a json string"
utf8 :: FieldParser ByteString Text
utf8 :: FieldParser ByteString Text
utf8 = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \ByteString
bytes -> case ByteString -> Either Error Text
bytesToTextUtf8 ByteString
bytes of
Left Error
_err -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ Error
"Not a valid UTF-8 string"
Right Text
a -> forall a b. b -> Either a b
Right Text
a
signedDecimal :: FieldParser Text Integer
signedDecimal :: FieldParser Text Integer
signedDecimal =
forall a. (Text -> Error) -> Parser a -> FieldParser Text a
attoparsecText
(\Text
t -> [fmt|Not a signed decimal number: "{t}"|])
(forall a. Num a => Parser a -> Parser a
Atto.signed (forall a. Integral a => Parser a
Atto.decimal @Integer))
decimalNatural :: FieldParser Text Natural
decimalNatural :: FieldParser Text Natural
decimalNatural =
forall a. (Text -> Error) -> Parser a -> FieldParser Text a
attoparsecText
(\Text
t -> [fmt|Not a natural number: "{t}"|])
(forall a. Integral a => Parser a
Atto.decimal @Integer)
forall {k} (cat :: k -> k -> Type) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
Cat.>>> forall i. Integral i => FieldParser i Natural
integralToNatural @Integer
signedDecimalNatural :: FieldParser Text Natural
signedDecimalNatural :: FieldParser Text Natural
signedDecimalNatural =
forall a. (Text -> Error) -> Parser a -> FieldParser Text a
attoparsecText
(\Text
t -> [fmt|Not a signed natural number: "{t}"|])
(forall a. Num a => Parser a -> Parser a
Atto.signed (forall a. Integral a => Parser a
Atto.decimal @Integer))
forall {k} (cat :: k -> k -> Type) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
Cat.>>> forall i. Integral i => FieldParser i Natural
integralToNatural @Integer
integralToNatural :: Integral i => FieldParser i Natural
integralToNatural :: forall i. Integral i => FieldParser i Natural
integralToNatural =
forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser (\i
i -> i
i forall a b. a -> (a -> b) -> b
& forall a. Integral a => a -> Maybe Natural
intToNatural forall a b. a -> (a -> b) -> b
& forall err a. err -> Maybe a -> Either err a
annotate [fmt|Number must be 0 or positive, but was negative: {toInteger i}|])
integralToInteger :: Integral i => FieldParser' err i Integer
integralToInteger :: forall i err. Integral i => FieldParser' err i Integer
integralToInteger = forall (p :: Type -> Type -> Type) a b c.
Profunctor p =>
(a -> b) -> p b c -> p a c
lmap (forall a b. (Integral a, Num b) => a -> b
fromIntegral @_ @Integer) forall {k} (cat :: k -> k -> Type) (a :: k).
Category cat =>
cat a a
Cat.id
scientific :: FieldParser Text Scientific
scientific :: FieldParser Text Scientific
scientific = forall a. (Text -> Error) -> Parser a -> FieldParser Text a
attoparsecText (\Text
t -> [fmt|Not a scientific number: "{t}"|]) Parser Scientific
Atto.scientific
boundedScientificIntegral :: forall i. (Integral i, Bounded i) => Error -> FieldParser Scientific i
boundedScientificIntegral :: forall i.
(Integral i, Bounded i) =>
Error -> FieldParser Scientific i
boundedScientificIntegral Error
err = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \Scientific
s -> case forall i. (Integral i, Bounded i) => Scientific -> Maybe i
Scientific.toBoundedInteger Scientific
s of
Maybe i
Nothing -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ (Error
err forall a b. a -> (a -> b) -> b
& Text -> Error -> Error
errorContext [fmt|Must be between {iMinBound} and {iMaxBound}|])
Just i
i -> forall a b. b -> Either a b
Right i
i
where
iMinBound :: Integer
iMinBound = forall a. Integral a => a -> Integer
toInteger (forall a. Bounded a => a
minBound :: i)
iMaxBound :: Integer
iMaxBound = forall a. Integral a => a -> Integer
toInteger (forall a. Bounded a => a
maxBound :: i)
boundedScientificRealFloat :: RealFloat d => FieldParser Scientific d
boundedScientificRealFloat :: forall d. RealFloat d => FieldParser Scientific d
boundedScientificRealFloat = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \Scientific
s ->
forall a. RealFloat a => Scientific -> Either a a
Scientific.toBoundedRealFloat Scientific
s
forall a b. a -> (a -> b) -> b
& forall (p :: Type -> Type -> Type) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first
( \d
zeroOrInf ->
( if
| d
0 forall a. Eq a => a -> a -> Bool
== d
zeroOrInf -> [fmt|Number {show s} is too small to fit into floating point.|]
| forall a. RealFloat a => a -> Bool
isInfinite d
zeroOrInf -> [fmt|Number {show s} is too big to fit into floating point.|]
| Bool
otherwise -> [fmt|Number {show s} did not fit into floating point, but we don’t know why (BUG).|]
)
)
bounded :: forall i. (Integral i, Bounded i) => Text -> FieldParser Integer i
bounded :: forall i. (Integral i, Bounded i) => Text -> FieldParser Integer i
bounded Text
err = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \Integer
num -> case Integer
num forall a b. a -> (a -> b) -> b
& Integer -> Maybe i
fromIntegerBounded of
Maybe i
Nothing -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ (Text -> Error -> Error
errorContext Text
err [fmt|Must be between {iMinBound} and {iMaxBound}, but was: {num & toInteger}|])
Just i
i -> forall a b. b -> Either a b
Right i
i
where
fromIntegerBounded :: Integer -> Maybe i
fromIntegerBounded :: Integer -> Maybe i
fromIntegerBounded Integer
i
| Integer
i forall a. Ord a => a -> a -> Bool
< Integer
iMinBound Bool -> Bool -> Bool
|| Integer
i forall a. Ord a => a -> a -> Bool
> Integer
iMaxBound = forall a. Maybe a
Nothing
| Bool
otherwise = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Num a => Integer -> a
fromInteger Integer
i
iMinBound :: Integer
iMinBound = forall a. Integral a => a -> Integer
toInteger (forall a. Bounded a => a
minBound :: i)
iMaxBound :: Integer
iMaxBound = forall a. Integral a => a -> Integer
toInteger (forall a. Bounded a => a
maxBound :: i)
clamped ::
(Ord a, Show a) =>
a ->
a ->
FieldParser a a
clamped :: forall a. (Ord a, Show a) => a -> a -> FieldParser a a
clamped a
lower a
upperExcl = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \a
a ->
if a
a forall a. Ord a => a -> a -> Bool
>= a
lower Bool -> Bool -> Bool
&& a
a forall a. Ord a => a -> a -> Bool
< a
upperExcl
then forall a b. b -> Either a b
Right a
a
else forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ [fmt|Value not between {lower & show} (inclusive) and {upperExcl & show} (exclusive), was: {show a}|]
oneOf :: Ord from => (from -> Text) -> [(from, to)] -> FieldParser from to
oneOf :: forall from to.
Ord from =>
(from -> Text) -> [(from, to)] -> FieldParser from to
oneOf from -> Text
errDisplay [(from, to)]
m =
forall from to.
Ord from =>
(from -> Text) -> Map from to -> FieldParser from to
oneOfMap from -> Text
errDisplay (forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(from, to)]
m)
oneOfMap :: (Ord from) => (from -> Text) -> Map from to -> FieldParser from to
oneOfMap :: forall from to.
Ord from =>
(from -> Text) -> Map from to -> FieldParser from to
oneOfMap from -> Text
errDisplay Map from to
m = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \from
from ->
Map from to
m
forall a b. a -> (a -> b) -> b
& forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup from
from
forall a b. a -> (a -> b) -> b
& \case
Maybe to
Nothing -> do
let prettyFrom :: from -> Text
prettyFrom from
f = [fmt|"{f & errDisplay}"|]
forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ [fmt|Not one of: {m & Map.keys <&> prettyFrom & Text.intercalate ", "}, was {from & prettyFrom}|]
Just to
to -> forall a b. b -> Either a b
Right to
to
textEnum :: (Bounded to, Enum to) => (to -> Text) -> FieldParser Text to
textEnum :: forall to.
(Bounded to, Enum to) =>
(to -> Text) -> FieldParser Text to
textEnum to -> Text
displayEnum = forall from to.
Ord from =>
(from -> Text) -> Map from to -> FieldParser from to
oneOfMap forall a. a -> a
id (forall a k. (Bounded a, Enum a, Ord k) => (a -> k) -> Map k a
inverseMap to -> Text
displayEnum)
either :: FieldParser from to1 -> FieldParser from to2 -> FieldParser' ErrorTree from (Either to1 to2)
either :: forall from to1 to2.
FieldParser from to1
-> FieldParser from to2
-> FieldParser' ErrorTree from (Either to1 to2)
either FieldParser from to1
first' FieldParser from to2
second' =
forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \from
from -> case forall err from to.
FieldParser' err from to -> from -> Either err to
runFieldParser FieldParser from to1
first' from
from of
Left Error
err -> case forall err from to.
FieldParser' err from to -> from -> Either err to
runFieldParser FieldParser from to2
second' from
from of
Left Error
err2 ->
forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ Error -> NonEmpty Error -> ErrorTree
errorTree Error
"Neither the left nor the right parser succeeded" forall a b. (a -> b) -> a -> b
$ Error
err forall a. a -> [a] -> NonEmpty a
:| [Error
err2]
Right to2
a -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right to2
a
Right to1
a -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left to1
a
or :: NonEmpty (FieldParser from to) -> FieldParser' ErrorTree from to
or :: forall from to.
NonEmpty (FieldParser from to) -> FieldParser' ErrorTree from to
or NonEmpty (FieldParser from to)
parsers =
forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \from
from ->
NonEmpty (FieldParser from to)
parsers
forall a b. a -> (a -> b) -> b
& forall (t :: Type -> Type) a. Foldable1 t => t a -> NonEmpty a
toNonEmpty
forall a b. a -> (a -> b) -> b
& forall (t :: Type -> Type) (f :: Type -> Type) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse
( \FieldParser from to
p ->
forall err from to.
FieldParser' err from to -> from -> Either err to
runFieldParser FieldParser from to
p from
from
forall a b. a -> (a -> b) -> b
& forall a b. Either a b -> Either b a
flipEither
)
forall a b. a -> (a -> b) -> b
& \case
Left to
a -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ to
a
Right NonEmpty Error
errs -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ Error -> NonEmpty Error -> ErrorTree
errorTree Error
"Neither of these parsers succeeded" NonEmpty Error
errs
where
flipEither :: Either a b -> Either b a
flipEither :: forall a b. Either a b -> Either b a
flipEither (Left a
err) = forall a b. b -> Either a b
Right a
err
flipEither (Right b
a) = forall a b. a -> Either a b
Left b
a
invertPretty :: (Bounded to, Enum to) => (to -> Text) -> FieldParser Text to
invertPretty :: forall to.
(Bounded to, Enum to) =>
(to -> Text) -> FieldParser Text to
invertPretty to -> Text
prettyFn = forall from to.
Ord from =>
(from -> Text) -> Map from to -> FieldParser from to
oneOfMap forall a. a -> a
id (forall a k. (Bounded a, Enum a, Ord k) => (a -> k) -> Map k a
inverseMap to -> Text
prettyFn)
invertPrettyCaseInsensitive :: (Bounded to, Enum to) => (to -> Text) -> FieldParser Text to
invertPrettyCaseInsensitive :: forall to.
(Bounded to, Enum to) =>
(to -> Text) -> FieldParser Text to
invertPrettyCaseInsensitive to -> Text
prettyFn =
forall from to.
Ord from =>
(from -> Text) -> Map from to -> FieldParser from to
oneOfMap
forall s. CI s -> s
CaseInsensitive.original
(forall a k. (Bounded a, Enum a, Ord k) => (a -> k) -> Map k a
inverseMap (\to
t -> to -> Text
prettyFn to
t forall a b. a -> (a -> b) -> b
& forall s. FoldCase s => s -> CI s
CaseInsensitive.mk))
forall a b. a -> (a -> b) -> b
& forall (p :: Type -> Type -> Type) a b c.
Profunctor p =>
(a -> b) -> p b c -> p a c
lmap forall s. FoldCase s => s -> CI s
CaseInsensitive.mk
exactly :: Eq from => (from -> Text) -> from -> FieldParser from from
exactly :: forall from.
Eq from =>
(from -> Text) -> from -> FieldParser from from
exactly from -> Text
errDisplay from
from = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \from
from' ->
if from
from forall a. Eq a => a -> a -> Bool
== from
from'
then forall a b. b -> Either a b
Right from
from'
else forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ [fmt|Field has to be exactly {errDisplay from}, was: {errDisplay from'}|]
multiple ::
Text ->
(Natural -> from -> Text) ->
FieldParser from to ->
FieldParser' ErrorTree [from] [to]
multiple :: forall from to.
Text
-> (Natural -> from -> Text)
-> FieldParser from to
-> FieldParser' ErrorTree [from] [to]
multiple Text
topLevelErr Natural -> from -> Text
displayValOnErr FieldParser from to
inner = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \[from]
ta ->
[from]
ta forall a b. a -> (a -> b) -> b
& forall (t :: Type -> Type) a. Foldable t => t a -> [a]
toList forall a b. a -> (a -> b) -> b
& forall {b}. [b] -> [(Natural, b)]
indexed forall a b. a -> (a -> b) -> b
& forall (t :: Type -> Type) (f :: Type -> Type) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (Natural, from) -> Validation (NonEmpty Error) to
run forall a b. a -> (a -> b) -> b
& \case
Success [to]
b -> forall a b. b -> Either a b
Right [to]
b
Failure NonEmpty Error
errs -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ Error -> NonEmpty Error -> ErrorTree
errorTree (Text -> Error
newError Text
topLevelErr) NonEmpty Error
errs
where
indexed :: [b] -> [(Natural, b)]
indexed = forall a b. [a] -> [b] -> [(a, b)]
zip [Natural
1 :: Natural ..]
run :: (Natural, from) -> Validation (NonEmpty Error) to
run (Natural
index, from
a) = case forall err from to.
FieldParser' err from to -> from -> Either err to
runFieldParser FieldParser from to
inner from
a of
Left Error
err -> forall e a. e -> Validation e a
Failure (forall a. a -> NonEmpty a
singleton forall a b. (a -> b) -> a -> b
$ Text -> Error -> Error
errorContext (Natural -> from -> Text
displayValOnErr Natural
index from
a) Error
err)
Right to
res -> forall e a. a -> Validation e a
Success to
res
nonEmpty :: err -> FieldParser' err [from] (NonEmpty from)
nonEmpty :: forall err from. err -> FieldParser' err [from] (NonEmpty from)
nonEmpty err
msg = forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \[from]
from -> do
case [from]
from forall a b. a -> (a -> b) -> b
& forall a. [a] -> Maybe (NonEmpty a)
NonEmpty.nonEmpty of
Maybe (NonEmpty from)
Nothing -> forall a b. a -> Either a b
Left err
msg
Just NonEmpty from
ne -> forall a b. b -> Either a b
Right NonEmpty from
ne
data FieldParserDesc' err from to = FieldParserDesc
{
forall err from to. FieldParserDesc' err from to -> Text
symbolicDesc :: Text,
forall err from to.
FieldParserDesc' err from to -> FieldParser' err from to
fieldParser :: FieldParser' err from to
}
type FieldParserDesc from to = FieldParserDesc' Error from to
separatedBy ::
Text ->
(Natural -> Text -> Text) ->
FieldParserDesc Text to ->
FieldParser' ErrorTree Text [to]
separatedBy :: forall to.
Text
-> (Natural -> Text -> Text)
-> FieldParserDesc Text to
-> FieldParser' ErrorTree Text [to]
separatedBy Text
separator Natural -> Text -> Text
displayValOnErr FieldParserDesc Text to
innerParser =
( forall {k} (cat :: k -> k -> Type) (a :: k).
Category cat =>
cat a a
Cat.id
forall a b. a -> (a -> b) -> b
& forall (p :: Type -> Type -> Type) b c a.
Profunctor p =>
(b -> c) -> p a b -> p a c
rmap (Text -> Text -> [Text]
Text.splitOn Text
separator)
forall a b. a -> (a -> b) -> b
& forall (p :: Type -> Type -> Type) b c a.
Profunctor p =>
(b -> c) -> p a b -> p a c
rmap
( \case
[Text
""] -> []
[Text]
xs -> [Text]
xs
)
forall a b. a -> (a -> b) -> b
& forall err1 err2 from to.
(err1 -> err2)
-> FieldParser' err1 from to -> FieldParser' err2 from to
mapError Error -> ErrorTree
singleError
)
forall {k} (cat :: k -> k -> Type) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
Cat.>>> ( forall from to.
Text
-> (Natural -> from -> Text)
-> FieldParser from to
-> FieldParser' ErrorTree [from] [to]
multiple
( let d :: Text
d = FieldParserDesc Text to
innerParser.symbolicDesc
in [fmt|Must be a {separator}-separated list of {d} (e.g. "{d}{separator}{d}"), but some elements could not be parsed|]
)
Natural -> Text -> Text
displayValOnErr
FieldParserDesc Text to
innerParser.fieldParser
)
ignoreSurroundingWhitespace :: FieldParser Text a -> FieldParser Text a
ignoreSurroundingWhitespace :: forall a. FieldParser Text a -> FieldParser Text a
ignoreSurroundingWhitespace = forall (p :: Type -> Type -> Type) a b c.
Profunctor p =>
(a -> b) -> p b c -> p a c
lmap Text -> Text
Text.strip
attoparsecText ::
(Text -> Error) ->
Atto.Parser a ->
FieldParser Text a
attoparsecText :: forall a. (Text -> Error) -> Parser a -> FieldParser Text a
attoparsecText Text -> Error
err Parser a
parser =
let parseAll :: Text -> Either String a
parseAll = forall a. Parser a -> Text -> Either String a
Atto.parseOnly (Parser a
parser forall (f :: Type -> Type) a b. Applicative f => f a -> f b -> f a
<* forall t. Chunk t => Parser t ()
Atto.endOfInput)
in forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \Text
text -> case Text -> Either String a
parseAll Text
text of
Left String
_attoErr -> forall a b. a -> Either a b
Left (Text -> Error
err Text
text)
Right a
a -> forall a b. b -> Either a b
Right a
a
attoparsecBytes ::
Error ->
AttoBytes.Parser a ->
FieldParser ByteString a
attoparsecBytes :: forall a. Error -> Parser a -> FieldParser ByteString a
attoparsecBytes Error
err Parser a
parser =
let parseAll :: ByteString -> Either String a
parseAll = forall a. Parser a -> ByteString -> Either String a
AttoBytes.parseOnly (Parser a
parser forall (f :: Type -> Type) a b. Applicative f => f a -> f b -> f a
<* forall t. Chunk t => Parser t ()
AttoBytes.endOfInput)
in forall err from to.
(from -> Either err to) -> FieldParser' err from to
FieldParser forall a b. (a -> b) -> a -> b
$ \ByteString
bytes -> case ByteString -> Either String a
parseAll ByteString
bytes of
Left String
_attoErr -> forall a b. a -> Either a b
Left Error
err
Right a
a -> forall a b. b -> Either a b
Right a
a