aeson-options 0.0.0 → 0.1.0
raw patch · 3 files changed
+83/−12 lines, 3 filesdep ~aesondep ~basePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: aeson, base
API changes (from Hackage documentation)
+ Data.Aeson.Options: genericParseJSONStripType :: forall a. (Typeable a, Generic a, GFromJSON Zero (Rep a)) => Value -> Parser a
+ Data.Aeson.Options: genericToJSONStripType :: forall a. (Typeable a, Generic a, GToJSON Zero (Rep a)) => a -> Value
+ Data.Aeson.Options: stripTypeOptions :: forall a. Typeable a => Options
Files
- CHANGELOG.md +7/−0
- aeson-options.cabal +6/−5
- src/Data/Aeson/Options.hs +70/−7
CHANGELOG.md view
@@ -4,6 +4,13 @@ `aeson-options` uses [PVP Versioning][1]. The change log is available [on GitHub][2]. +0.1.0+=====++* Add options that strip type name from field prefixes.+* Support build with GHC-8.6.1.+ Disable build with GHC-8.0.2 on CI.+ 0.0.0 =====
aeson-options.cabal view
@@ -1,5 +1,6 @@+cabal-version: 2.0 name: aeson-options-version: 0.0.0+version: 0.1.0 synopsis: Options to derive FromJSON/ToJSON instances description: Options to derive FromJSON/ToJSON instances. homepage: https://github.com/serokell/aeson-options@@ -11,11 +12,11 @@ maintainer: Serokell <hi@serokell.io> copyright: 2018 Serokell build-type: Simple- extra-source-files: CHANGELOG.md , README.md-cabal-version: >=2.0-+tested-with: GHC == 8.2.2+ , GHC == 8.4.3+ , GHC == 8.6.1 source-repository head type: git@@ -25,7 +26,7 @@ hs-source-dirs: src exposed-modules: Data.Aeson.Options - build-depends: base >= 4.9 && < 5+ build-depends: base >= 4.10 && < 5 , aeson >= 1.0 && < 1.4 ghc-options: -Wall -fno-warn-orphans
src/Data/Aeson/Options.hs view
@@ -1,18 +1,32 @@--- | Options used to derive FromJSON/ToJSON instance. These options--- generally comply to our style regarding names. Of course sometimes--- they don't fit one's needs, so treat them as just sensible--- defaults.+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-} +{- | Options used to derive FromJSON/ToJSON instance. These options generally+comply to our style regarding names. Of course sometimes they don't fit one's+needs, so treat them as just sensible defaults.+-}+ module Data.Aeson.Options- ( defaultOptions+ ( -- * Custom options+ defaultOptions , leaveTagOptions , defaultOptionsPS+ , stripTypeOptions++ -- * Generic functions+ , genericParseJSONStripType+ , genericToJSONStripType ) where +import Data.Aeson.Types (Parser) import Data.Char (isLower, isPunctuation, isUpper, toLower)-import Data.List (findIndex)+import Data.List (findIndex, isPrefixOf)+import GHC.Generics (Generic, Rep)+import Type.Reflection (Typeable, typeRep) -import qualified Data.Aeson.TH as A+import qualified Data.Aeson as A headToLower :: String -> String headToLower [] = error "Can not use headToLower on empty String"@@ -58,3 +72,52 @@ A.defaultOptions { A.constructorTagModifier = headToLower . stripConstructorPrefix }++{- | Allows to create 'A.FromJSON' instance that strips the data type name prefix+from every field. Doesn't change name of the fields that doesn't start with the+type name.++>>> data Foo = Foo { fooBar :: String, fooQuux :: Int } deriving (Generic, Show)+>>> instance FromJSON Foo where parseJSON = genericParseJSONStripType+>>> decode @Foo "{ \"bar\": \"test\", \"quux\": 42 }"+Just (Foo {fooBar = "test", fooQuux = 42})+-}+genericParseJSONStripType+ :: forall a .+ (Typeable a, Generic a, A.GFromJSON A.Zero (Rep a))+ => A.Value+ -> Parser a+genericParseJSONStripType = A.genericParseJSON (stripTypeOptions @a)++{- | Allows to create 'A.ToJSON' instance that strips the data type name prefix+from every field. Doesn't change name of the fields that doesn't start with the+type name.++>>> data Foo = Foo { fooBar :: String, fooQuux :: Int } deriving (Generic, Show)+>>> instance ToJSON Foo where toJSON = genericToJSONStripType+>>> encode $ Foo { fooBar = "test", fooQuux = 42 }+"{\"quux\":42,\"bar\":\"test\"}"+-}+genericToJSONStripType+ :: forall a .+ (Typeable a, Generic a, A.GToJSON A.Zero (Rep a))+ => a+ -> A.Value+genericToJSONStripType = A.genericToJSON (stripTypeOptions @a)++{- | Options to strip type name from the field names. See+'genericParseJSONStripType' and 'genericToJSONStripType' for examples.+-}+stripTypeOptions :: forall a . Typeable a => A.Options+stripTypeOptions = A.defaultOptions+ { A.fieldLabelModifier = stripTypeNamePrefix+ }+ where+ typeName :: String+ typeName = headToLower $ show $ typeRep @a++ stripTypeNamePrefix :: String -> String+ stripTypeNamePrefix fieldName =+ if typeName `isPrefixOf` fieldName+ then headToLower $ drop (length typeName) fieldName+ else fieldName