Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#91): add decoder for NonEmptyString #94

Merged
merged 4 commits into from
Dec 24, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Notable changes to this project are documented in this file. The format is based
Breaking changes (😱!!!):

New features:
- 2020-12-23: Per #91 - add decoders for NonEmptyString and add decodeNonempty function

Bugfixes:

Expand Down Expand Up @@ -181,4 +182,4 @@ Updated dependencies

## [v0.1.0](https://github.com/purescript-contrib/purescript-argonaut-codecs/releases/tag/v0.1.0) - 2015-07-13

- Initial release
- Initial release
2 changes: 1 addition & 1 deletion src/Data/Argonaut/Decode.purs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module Data.Argonaut.Decode
) where

import Data.Argonaut.Decode.Class (class DecodeJson, decodeJson)
import Data.Argonaut.Decode.Combinators
import Data.Argonaut.Decode.Combinators
( getField
, getFieldOptional
, getFieldOptional'
Expand Down
4 changes: 4 additions & 0 deletions src/Data/Argonaut/Decode/Class.purs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Data.Either (Either(..))
import Data.Identity (Identity)
import Data.List (List)
import Data.List.NonEmpty (NonEmptyList)
import Data.String.NonEmpty (NonEmptyString)
import Data.Map as M
import Data.Maybe (Maybe(..))
import Data.NonEmpty (NonEmpty)
Expand Down Expand Up @@ -54,6 +55,9 @@ instance decodeJsonInt :: DecodeJson Int where
instance decodeJsonString :: DecodeJson String where
decodeJson = decodeString

instance decodeJsonNonEmptyString :: DecodeJson NonEmptyString where
decodeJson = decodeNonEmptyString

instance decodeJsonJson :: DecodeJson Json where
decodeJson = Right

Expand Down
94 changes: 52 additions & 42 deletions src/Data/Argonaut/Decode/Decoders.purs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import Data.List (List, fromFoldable)
import Data.List as L
import Data.List.NonEmpty (NonEmptyList)
import Data.List.NonEmpty as NEL
import Data.String.NonEmpty (NonEmptyString)
import Data.String.NonEmpty as NonEmptyString
import Data.Map as M
import Data.Maybe (maybe, Maybe(..))
import Data.NonEmpty (NonEmpty, (:|))
Expand All @@ -25,14 +27,14 @@ import Data.TraversableWithIndex (traverseWithIndex)
import Data.Tuple (Tuple(..))
import Foreign.Object as FO

decodeIdentity
decodeIdentity
:: forall a
. (Json -> Either JsonDecodeError a)
-> Json
-> Either JsonDecodeError (Identity a)
decodeIdentity decoder json = Identity <$> decoder json

decodeMaybe
decodeMaybe
:: forall a
. (Json -> Either JsonDecodeError a)
-> Json
Expand All @@ -41,26 +43,26 @@ decodeMaybe decoder json
| isNull json = pure Nothing
| otherwise = Just <$> decoder json

decodeTuple
decodeTuple
:: forall a b
. (Json -> Either JsonDecodeError a)
. (Json -> Either JsonDecodeError a)
-> (Json -> Either JsonDecodeError b)
-> Json
-> Json
-> Either JsonDecodeError (Tuple a b)
decodeTuple decoderA decoderB json = decodeArray Right json >>= f
where
f :: Array Json -> Either JsonDecodeError (Tuple a b)
f = case _ of
f = case _ of
[a, b] -> Tuple <$> decoderA a <*> decoderB b
_ -> Left $ TypeMismatch "Tuple"

decodeEither
decodeEither
:: forall a b
. (Json -> Either JsonDecodeError a)
-> (Json -> Either JsonDecodeError b)
-> Json
-> Either JsonDecodeError (Either a b)
decodeEither decoderA decoderB json =
decodeEither decoderA decoderB json =
lmap (Named "Either") $ decodeJObject json >>= \obj -> do
tag <- note (AtKey "tag" MissingValue) $ FO.lookup "tag" obj
val <- note (AtKey "value" MissingValue) $ FO.lookup "value" obj
Expand All @@ -84,61 +86,69 @@ decodeInt = note (TypeMismatch "Integer") <<< fromNumber <=< decodeNumber
decodeString :: Json -> Either JsonDecodeError String
decodeString = caseJsonString (Left $ TypeMismatch "String") Right

decodeNonEmpty_Array
decodeNonEmptyString :: Json -> Either JsonDecodeError NonEmptyString
decodeNonEmptyString json =
note (Named "NonEmptyString" $ UnexpectedValue json)
=<< map (NonEmptyString.fromString) (decodeString json)

decodeNonempty :: Json -> Either JsonDecodeError String
decodeNonempty = map NonEmptyString.toString <<< decodeNonEmptyString
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not include this function; it's pretty easy to do map NonEmptyString.toString in your own code and we don't otherwise provide functions beyond the initial parse in the library.


decodeNonEmpty_Array
:: forall a
. (Json -> Either JsonDecodeError a)
-> Json
-> Either JsonDecodeError (NonEmpty Array a)
decodeNonEmpty_Array decoder =
lmap (Named "NonEmpty Array")
<<< traverse decoder
<=< map (\x -> x.head :| x.tail)
<<< note (TypeMismatch "NonEmpty Array")
decodeNonEmpty_Array decoder =
lmap (Named "NonEmpty Array")
<<< traverse decoder
<=< map (\x -> x.head :| x.tail)
<<< note (TypeMismatch "NonEmpty Array")
<<< Arr.uncons
<=< decodeJArray

decodeNonEmptyArray
decodeNonEmptyArray
:: forall a
. (Json -> Either JsonDecodeError a)
-> Json
-> Json
-> Either JsonDecodeError (NonEmptyArray a)
decodeNonEmptyArray decoder =
lmap (Named "NonEmptyArray")
<<< traverse decoder
<<< traverse decoder
<=< map (\x -> NEA.cons' x.head x.tail)
<<< note (TypeMismatch "NonEmptyArray")
<<< note (TypeMismatch "NonEmptyArray")
<<< Arr.uncons
<=< decodeJArray

decodeNonEmpty_List
decodeNonEmpty_List
:: forall a
. (Json -> Either JsonDecodeError a)
-> Json
-> Either JsonDecodeError (NonEmpty List a)
decodeNonEmpty_List decoder =
lmap (Named "NonEmpty List")
<<< traverse decoder
<<< traverse decoder
<=< map (\x -> x.head :| x.tail)
<<< note (TypeMismatch "NonEmpty List")
<<< L.uncons
<=< map (map fromFoldable) decodeJArray

decodeNonEmptyList
decodeNonEmptyList
:: forall a
. (Json -> Either JsonDecodeError a)
-> Json
-> Either JsonDecodeError (NonEmptyList a)
decodeNonEmptyList decoder =
lmap (Named "NonEmptyList")
<<< traverse decoder
<<< traverse decoder
<=< map (\x -> NEL.cons' x.head x.tail)
<<< note (TypeMismatch "NonEmptyList")
<<< L.uncons
<=< map (map fromFoldable) decodeJArray

decodeCodePoint :: Json -> Either JsonDecodeError CodePoint
decodeCodePoint json =
note (Named "CodePoint" $ UnexpectedValue json)
decodeCodePoint json =
note (Named "CodePoint" $ UnexpectedValue json)
=<< map (codePointAt 0) (decodeString json)

decodeForeignObject
Expand All @@ -147,47 +157,47 @@ decodeForeignObject
-> Json
-> Either JsonDecodeError (FO.Object a)
decodeForeignObject decoder =
lmap (Named "ForeignObject")
<<< traverse decoder
lmap (Named "ForeignObject")
<<< traverse decoder
<=< decodeJObject

decodeArray
decodeArray
:: forall a
. (Json -> Either JsonDecodeError a)
-> Json
-> Either JsonDecodeError (Array a)
decodeArray decoder =
lmap (Named "Array")
<<< traverseWithIndex (\i -> lmap (AtIndex i) <<< decoder)
<<< traverseWithIndex (\i -> lmap (AtIndex i) <<< decoder)
<=< decodeJArray

decodeList
decodeList
:: forall a
. (Json -> Either JsonDecodeError a)
-> Json
-> Either JsonDecodeError (List a)
decodeList decoder =
lmap (Named "List")
<<< traverse decoder
<<< traverse decoder
<=< map (map fromFoldable) decodeJArray

decodeSet
decodeSet
:: forall a
. Ord a
. Ord a
=> (Json -> Either JsonDecodeError a)
-> Json
-> Either JsonDecodeError (S.Set a)
decodeSet decoder =
decodeSet decoder =
map (S.fromFoldable :: List a -> S.Set a) <<< decodeList decoder

decodeMap
decodeMap
:: forall a b
. Ord a
. Ord a
=> (Json -> Either JsonDecodeError a)
-> (Json -> Either JsonDecodeError b)
-> Json
-> Either JsonDecodeError (M.Map a b)
decodeMap decoderA decoderB =
decodeMap decoderA decoderB =
map (M.fromFoldable :: List (Tuple a b) -> M.Map a b)
<<< decodeList (decodeTuple decoderA decoderB)

Expand All @@ -200,7 +210,7 @@ decodeJArray = note (TypeMismatch "Array") <<< toArray
decodeJObject :: Json -> Either JsonDecodeError (FO.Object Json)
decodeJObject = note (TypeMismatch "Object") <<< toObject

getField
getField
:: forall a
. (Json -> Either JsonDecodeError a)
-> FO.Object Json
Expand All @@ -212,7 +222,7 @@ getField decoder obj str =
(lmap (AtKey str) <<< decoder)
(FO.lookup str obj)

getFieldOptional
getFieldOptional
:: forall a
. (Json -> Either JsonDecodeError a)
-> FO.Object Json
Expand All @@ -223,7 +233,7 @@ getFieldOptional decoder obj str =
where
decode = lmap (AtKey str) <<< decoder

getFieldOptional'
getFieldOptional'
:: forall a
. (Json -> Either JsonDecodeError a)
-> FO.Object Json
Expand All @@ -232,8 +242,8 @@ getFieldOptional'
getFieldOptional' decoder obj str =
maybe (pure Nothing) decode (FO.lookup str obj)
where
decode json =
if isNull json then
decode json =
if isNull json then
pure Nothing
else
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where did all these come from? 😅 Thanks for trimming the whitespace.

else
Just <$> (lmap (AtKey str) <<< decoder) json
2 changes: 1 addition & 1 deletion src/Data/Argonaut/Decode/Error.purs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-- | Originally implemented in:
-- | Originally implemented in:
-- | https://github.com/garyb/purescript-codec-argonaut
module Data.Argonaut.Decode.Error where

Expand Down
2 changes: 1 addition & 1 deletion src/Data/Argonaut/Decode/Parser.purs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ import Data.Either (Either)
-- | Attempt to parse a string as `Json`, failing with a typed error if the
-- | JSON string is malformed.
parseJson :: String -> Either JsonDecodeError Json
parseJson = lmap (\_ -> TypeMismatch "JSON") <<< jsonParser
parseJson = lmap (\_ -> TypeMismatch "JSON") <<< jsonParser
2 changes: 1 addition & 1 deletion src/Data/Argonaut/Encode/Combinators.purs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Data.Maybe (Maybe)
import Data.Tuple (Tuple)
import Data.Argonaut.Encode.Encoders as Encoders

-- | Creates a `Tuple String Json` entry, representing a key/value pair for
-- | Creates a `Tuple String Json` entry, representing a key/value pair for
-- | an object.
infix 7 assoc as :=

Expand Down
6 changes: 3 additions & 3 deletions src/Data/Argonaut/Encode/Encoders.purs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ encodeSet :: forall a. Ord a => (a -> Json) -> S.Set a -> Json
encodeSet encoder = encodeList encoder <<< (S.toUnfoldable :: S.Set a -> List a)

encodeMap :: forall a b. Ord a => (a -> Json) -> (b -> Json) -> M.Map a b -> Json
encodeMap encoderA encoderB =
encodeList (encodeTuple encoderA encoderB)
encodeMap encoderA encoderB =
encodeList (encodeTuple encoderA encoderB)
<<< (M.toUnfoldable :: M.Map a b -> List (Tuple a b))

encodeVoid :: Void -> Json
Expand All @@ -113,6 +113,6 @@ extend encoder (Tuple k v) =

-- | The named Encoders of the `(~>?)` operator.
extendOptional :: forall a. (a -> Json) -> Maybe (Tuple String Json) -> a -> Json
extendOptional encoder = case _ of
extendOptional encoder = case _ of
Just kv -> extend encoder kv
Nothing -> encoder