monoidmap-aeson (empty) → 0.0.0.0
raw patch · 11 files changed
+911/−0 lines, 11 filesdep +QuickCheckdep +aesondep +base
Dependencies added: QuickCheck, aeson, base, containers, hspec, hspec-golden-aeson, monoid-subclasses, monoidmap, monoidmap-aeson, quickcheck-classes, quickcheck-quid, text
Files
- CHANGELOG.md +3/−0
- LICENSE +201/−0
- README.md +6/−0
- components/monoidmap-aeson-test/Data/MonoidMap/JSONSpec.hs +99/−0
- components/monoidmap-aeson-test/Spec.hs +1/−0
- components/monoidmap-aeson-test/SpecHook.hs +6/−0
- components/monoidmap-aeson-test/Test/Common.hs +197/−0
- components/monoidmap-aeson-test/Test/Key.hs +91/−0
- components/monoidmap-aeson-test/Test/QuickCheck/Classes/Hspec.hs +63/−0
- components/monoidmap-aeson/Data/MonoidMap/JSON.hs +131/−0
- monoidmap-aeson.cabal +113/−0
+ CHANGELOG.md view
@@ -0,0 +1,3 @@+# 0.0.0.0++- Initial release.
+ LICENSE view
@@ -0,0 +1,201 @@+ Apache License+ Version 2.0, January 2004+ http://www.apache.org/licenses/++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++ 1. Definitions.++ "License" shall mean the terms and conditions for use, reproduction,+ and distribution as defined by Sections 1 through 9 of this document.++ "Licensor" shall mean the copyright owner or entity authorized by+ the copyright owner that is granting the License.++ "Legal Entity" shall mean the union of the acting entity and all+ other entities that control, are controlled by, or are under common+ control with that entity. For the purposes of this definition,+ "control" means (i) the power, direct or indirect, to cause the+ direction or management of such entity, whether by contract or+ otherwise, or (ii) ownership of fifty percent (50%) or more of the+ outstanding shares, or (iii) beneficial ownership of such entity.++ "You" (or "Your") shall mean an individual or Legal Entity+ exercising permissions granted by this License.++ "Source" form shall mean the preferred form for making modifications,+ including but not limited to software source code, documentation+ source, and configuration files.++ "Object" form shall mean any form resulting from mechanical+ transformation or translation of a Source form, including but+ not limited to compiled object code, generated documentation,+ and conversions to other media types.++ "Work" shall mean the work of authorship, whether in Source or+ Object form, made available under the License, as indicated by a+ copyright notice that is included in or attached to the work+ (an example is provided in the Appendix below).++ "Derivative Works" shall mean any work, whether in Source or Object+ form, that is based on (or derived from) the Work and for which the+ editorial revisions, annotations, elaborations, or other modifications+ represent, as a whole, an original work of authorship. For the purposes+ of this License, Derivative Works shall not include works that remain+ separable from, or merely link (or bind by name) to the interfaces of,+ the Work and Derivative Works thereof.++ "Contribution" shall mean any work of authorship, including+ the original version of the Work and any modifications or additions+ to that Work or Derivative Works thereof, that is intentionally+ submitted to Licensor for inclusion in the Work by the copyright owner+ or by an individual or Legal Entity authorized to submit on behalf of+ the copyright owner. For the purposes of this definition, "submitted"+ means any form of electronic, verbal, or written communication sent+ to the Licensor or its representatives, including but not limited to+ communication on electronic mailing lists, source code control systems,+ and issue tracking systems that are managed by, or on behalf of, the+ Licensor for the purpose of discussing and improving the Work, but+ excluding communication that is conspicuously marked or otherwise+ designated in writing by the copyright owner as "Not a Contribution."++ "Contributor" shall mean Licensor and any individual or Legal Entity+ on behalf of whom a Contribution has been received by Licensor and+ subsequently incorporated within the Work.++ 2. Grant of Copyright License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ copyright license to reproduce, prepare Derivative Works of,+ publicly display, publicly perform, sublicense, and distribute the+ Work and such Derivative Works in Source or Object form.++ 3. Grant of Patent License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ (except as stated in this section) patent license to make, have made,+ use, offer to sell, sell, import, and otherwise transfer the Work,+ where such license applies only to those patent claims licensable+ by such Contributor that are necessarily infringed by their+ Contribution(s) alone or by combination of their Contribution(s)+ with the Work to which such Contribution(s) was submitted. If You+ institute patent litigation against any entity (including a+ cross-claim or counterclaim in a lawsuit) alleging that the Work+ or a Contribution incorporated within the Work constitutes direct+ or contributory patent infringement, then any patent licenses+ granted to You under this License for that Work shall terminate+ as of the date such litigation is filed.++ 4. Redistribution. You may reproduce and distribute copies of the+ Work or Derivative Works thereof in any medium, with or without+ modifications, and in Source or Object form, provided that You+ meet the following conditions:++ (a) You must give any other recipients of the Work or+ Derivative Works a copy of this License; and++ (b) You must cause any modified files to carry prominent notices+ stating that You changed the files; and++ (c) You must retain, in the Source form of any Derivative Works+ that You distribute, all copyright, patent, trademark, and+ attribution notices from the Source form of the Work,+ excluding those notices that do not pertain to any part of+ the Derivative Works; and++ (d) If the Work includes a "NOTICE" text file as part of its+ distribution, then any Derivative Works that You distribute must+ include a readable copy of the attribution notices contained+ within such NOTICE file, excluding those notices that do not+ pertain to any part of the Derivative Works, in at least one+ of the following places: within a NOTICE text file distributed+ as part of the Derivative Works; within the Source form or+ documentation, if provided along with the Derivative Works; or,+ within a display generated by the Derivative Works, if and+ wherever such third-party notices normally appear. The contents+ of the NOTICE file are for informational purposes only and+ do not modify the License. You may add Your own attribution+ notices within Derivative Works that You distribute, alongside+ or as an addendum to the NOTICE text from the Work, provided+ that such additional attribution notices cannot be construed+ as modifying the License.++ You may add Your own copyright statement to Your modifications and+ may provide additional or different license terms and conditions+ for use, reproduction, or distribution of Your modifications, or+ for any such Derivative Works as a whole, provided Your use,+ reproduction, and distribution of the Work otherwise complies with+ the conditions stated in this License.++ 5. Submission of Contributions. Unless You explicitly state otherwise,+ any Contribution intentionally submitted for inclusion in the Work+ by You to the Licensor shall be under the terms and conditions of+ this License, without any additional terms or conditions.+ Notwithstanding the above, nothing herein shall supersede or modify+ the terms of any separate license agreement you may have executed+ with Licensor regarding such Contributions.++ 6. Trademarks. This License does not grant permission to use the trade+ names, trademarks, service marks, or product names of the Licensor,+ except as required for reasonable and customary use in describing the+ origin of the Work and reproducing the content of the NOTICE file.++ 7. Disclaimer of Warranty. Unless required by applicable law or+ agreed to in writing, Licensor provides the Work (and each+ Contributor provides its Contributions) on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+ implied, including, without limitation, any warranties or conditions+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+ PARTICULAR PURPOSE. You are solely responsible for determining the+ appropriateness of using or redistributing the Work and assume any+ risks associated with Your exercise of permissions under this License.++ 8. Limitation of Liability. In no event and under no legal theory,+ whether in tort (including negligence), contract, or otherwise,+ unless required by applicable law (such as deliberate and grossly+ negligent acts) or agreed to in writing, shall any Contributor be+ liable to You for damages, including any direct, indirect, special,+ incidental, or consequential damages of any character arising as a+ result of this License or out of the use or inability to use the+ Work (including but not limited to damages for loss of goodwill,+ work stoppage, computer failure or malfunction, or any and all+ other commercial damages or losses), even if such Contributor+ has been advised of the possibility of such damages.++ 9. Accepting Warranty or Additional Liability. While redistributing+ the Work or Derivative Works thereof, You may choose to offer,+ and charge a fee for, acceptance of support, warranty, indemnity,+ or other liability obligations and/or rights consistent with this+ License. However, in accepting such obligations, You may act only+ on Your own behalf and on Your sole responsibility, not on behalf+ of any other Contributor, and only if You agree to indemnify,+ defend, and hold each Contributor harmless for any liability+ incurred by, or claims asserted against, such Contributor by reason+ of your accepting any such warranty or additional liability.++ END OF TERMS AND CONDITIONS++ APPENDIX: How to apply the Apache License to your work.++ To apply the Apache License to your work, attach the following+ boilerplate notice, with the fields enclosed by brackets "[]"+ replaced with your own identifying information. (Don't include+ the brackets!) The text should be enclosed in the appropriate+ comment syntax for the file format. We also recommend that a+ file or class name and description of purpose be included on the+ same "printed page" as the copyright notice for easier+ identification within third-party archives.++ Copyright © 2022–2025 Jonathan Knowles++ Licensed under the Apache License, Version 2.0 (the "License");+ you may not use this file except in compliance with the License.+ You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++ Unless required by applicable law or agreed to in writing, software+ distributed under the License is distributed on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ See the License for the specific language governing permissions and+ limitations under the License.
+ README.md view
@@ -0,0 +1,6 @@+# `monoidmap-aeson` +<a href="https://jonathanknowles.github.io/monoidmap-aeson/"><img src="https://img.shields.io/badge/API-Documentation-227755" /></a> + +## Overview + +This package provides JSON serialisation support for the [`monoidmap`](https://hackage.haskell.org/package/monoidmap) package with [`aeson`](https://hackage.haskell.org/package/aeson).
+ components/monoidmap-aeson-test/Data/MonoidMap/JSONSpec.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE ExistentialQuantification #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++-- |+-- Copyright: © 2022–2025 Jonathan Knowles+-- License: Apache-2.0+--+module Data.MonoidMap.JSONSpec+ ( spec+ )+where++import Prelude++import Control.Monad+ ( forM_+ )+import Data.MonoidMap+ ( MonoidMap+ )+import Data.MonoidMap.JSON+ (+ )+import Data.Proxy+ ( Proxy (Proxy)+ )+import Data.Text+ ( Text+ )+import Test.Aeson.Internal.GoldenSpecs+ ( goldenSpecs+ )+import Test.Common+ ( Test+ , TestKey+ , TestValueType (TestValueType)+ , makeSpec+ , testValueTypesAll+ )+import Test.Hspec+ ( Spec+ , describe+ )+import Test.QuickCheck.Classes+ ( jsonLaws+ )+import Test.QuickCheck.Classes.Hspec+ ( testLaws+ )++import qualified Test.Aeson.Internal.Utils as Golden++spec :: Spec+spec = do+ describe "JSON"+ $ forM_ testKeyValueTypes+ $ \(TestKeyType k, TestValueType v) -> specForTypes k v+ where+ testKeyValueTypes =+ [(kt, vt) | kt <- testKeyTypes, vt <- testValueTypesAll]++specForTypes :: forall k v. (Test k v) => Proxy k -> Proxy v -> Spec+specForTypes = makeSpec $ do+ testLaws @(MonoidMap k v) jsonLaws+ goldenSpecs goldenSettings (Proxy @(MonoidMap k v))++goldenSettings :: Golden.Settings+goldenSettings =+ Golden.defaultSettings+ { Golden.goldenDirectoryOption =+ Golden.CustomDirectoryName "golden"+ , Golden.comparisonFile =+ Golden.OverwriteGoldenFile+ , Golden.randomMismatchOption =+ Golden.RandomMismatchError+ , Golden.useModuleNameAsSubDirectory =+ False+ , Golden.sampleSize =+ 10+ }++data TestKeyType = forall k. (TestKey k) => TestKeyType (Proxy k)++testKeyTypes :: [TestKeyType]+testKeyTypes =+ mconcat [testKeyTypes_textual, testKeyTypes_nonTextual]+ where+ -- A selection of key types for which keys are encoded as JSON strings.+ -- For these types, 'MonoidMap' objects are encoded as JSON objects.+ testKeyTypes_textual =+ [ TestKeyType (Proxy @Int)+ , TestKeyType (Proxy @Text)+ ]+ -- A selection of key types for which keys are NOT encoded as JSON strings.+ -- For these types, 'MonoidMap' objects are encoded as JSON arrays.+ testKeyTypes_nonTextual =+ [ TestKeyType (Proxy @[Int])+ , TestKeyType (Proxy @(Int, Int))+ ]
+ components/monoidmap-aeson-test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ components/monoidmap-aeson-test/SpecHook.hs view
@@ -0,0 +1,6 @@+module SpecHook where++import Test.Hspec++hook :: Spec -> Spec+hook = parallel
+ components/monoidmap-aeson-test/Test/Common.hs view
@@ -0,0 +1,197 @@+{-# LANGUAGE ExistentialQuantification #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{- HLINT ignore "Redundant bracket" -}+{- HLINT ignore "Use camelCase" -}+{- HLINT ignore "Use null" -}++-- |+-- Copyright: © 2022–2025 Jonathan Knowles+-- License: Apache-2.0+--+module Test.Common+ ( Key+ , Test+ , TestKey+ , TestValueType (..)+ , testValueTypesAll+ , TestValue+ , makeSpec+ , property+ ) where++import Prelude++import Data.Aeson+ ( FromJSON+ , FromJSONKey+ , ToJSON+ , ToJSONKey+ )+import Data.Kind+ ( Constraint, Type )+import Data.Monoid+ ( Dual, Product, Sum )+import Data.Monoid.Null+ ( MonoidNull )+import Data.MonoidMap+ ( MonoidMap )+import Data.MonoidMap.JSON+ ()+import Data.Proxy+ ( Proxy (Proxy) )+import Data.Set+ ( Set )+import Data.Text+ ( Text )+import Data.Typeable+ ( Typeable, typeRep )+import GHC.Exts+ ( IsList (..) )+import Numeric.Natural+ ( Natural )+import Test.Hspec+ ( Spec, describe )+import Test.Key+ ( Key2, Key4 )+import Test.QuickCheck+ ( Arbitrary (..)+ , CoArbitrary (..)+ , Function (..)+ , Property+ , Testable+ , arbitrarySizedIntegral+ , checkCoverage+ , coarbitraryIntegral+ , coarbitraryShow+ , frequency+ , functionIntegral+ , functionMap+ , functionShow+ , listOf+ , scale+ , shrinkIntegral+ , shrinkMapBy+ )++import qualified Data.MonoidMap as MonoidMap+import qualified Data.Text as Text+import qualified Test.QuickCheck as QC++--------------------------------------------------------------------------------+-- Arbitrary instances+--------------------------------------------------------------------------------++instance (Arbitrary k, Ord k, Arbitrary v, MonoidNull v) =>+ Arbitrary (MonoidMap k v)+ where+ arbitrary =+ fromList <$> scale (`mod` 16) (listOf ((,) <$> arbitrary <*> arbitrary))+ shrink =+ shrinkMapBy MonoidMap.fromMap MonoidMap.toMap shrink++instance (CoArbitrary k, CoArbitrary v) =>+ CoArbitrary (MonoidMap k v)+ where+ coarbitrary = coarbitrary . MonoidMap.toMap++instance (Function k, Function v, Ord k, MonoidNull v) =>+ Function (MonoidMap k v)+ where+ function = functionMap MonoidMap.toMap MonoidMap.fromMap++instance Arbitrary Natural where+ arbitrary = arbitrarySizedIntegral+ shrink = shrinkIntegral++instance CoArbitrary Natural where+ coarbitrary = coarbitraryIntegral++instance Function Natural where+ function = functionIntegral++instance Arbitrary Text where+ arbitrary = Text.pack <$> listOf genChar+ where+ genChar = frequency+ [ (64, pure 'a')+ , (16, pure 'b')+ , ( 4, pure 'c')+ , ( 1, pure 'd')+ ]++instance CoArbitrary Text where+ coarbitrary = coarbitraryShow++instance Function Text where+ function = functionShow++--------------------------------------------------------------------------------+-- Test keys+--------------------------------------------------------------------------------++type SmallKey = Key2+type Key = Key4++--------------------------------------------------------------------------------+-- Test constraints+--------------------------------------------------------------------------------++type Test k v = (TestKey k, TestValue v)++type TestKey k =+ ( Arbitrary k+ , CoArbitrary k+ , Function k+ , Ord k+ , Show k+ , Typeable k+ , ToJSONKey k+ , FromJSONKey k+ )++type TestValue v =+ ( Arbitrary v+ , CoArbitrary v+ , Eq v+ , Function v+ , MonoidNull v+ , Show v+ , Typeable v+ , ToJSON v+ , FromJSON v+ )++--------------------------------------------------------------------------------+-- Test value types+--------------------------------------------------------------------------------++data TestValueType (c :: Type -> Constraint) =+ forall v. (TestValue v, c v) => TestValueType (Proxy v)++testValueTypesAll :: [TestValueType MonoidNull]+testValueTypesAll =+ [ TestValueType (Proxy @(Dual Text))+ , TestValueType (Proxy @(Dual [Int]))+ , TestValueType (Proxy @(Dual [Natural]))+ , TestValueType (Proxy @(Product Int))+ , TestValueType (Proxy @(Product Natural))+ , TestValueType (Proxy @(Set Int))+ , TestValueType (Proxy @(Set Natural))+ , TestValueType (Proxy @(Sum Int))+ , TestValueType (Proxy @(Sum Natural))+ , TestValueType (Proxy @(Text))+ , TestValueType (Proxy @[Int])+ , TestValueType (Proxy @[Natural])+ , TestValueType (Proxy @(MonoidMap SmallKey (Sum Int)))+ , TestValueType (Proxy @(MonoidMap SmallKey (Sum Natural)))+ ]++--------------------------------------------------------------------------------+-- Utilities+--------------------------------------------------------------------------------++makeSpec :: forall k v. Test k v => Spec -> Proxy k -> Proxy v -> Spec+makeSpec spec _k _v = describe (show $ typeRep (Proxy @(MonoidMap k v))) spec++property :: Testable t => t -> Property+property = checkCoverage . QC.property
+ components/monoidmap-aeson-test/Test/Key.hs view
@@ -0,0 +1,91 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}++-- |+-- Copyright: © 2022–2025 Jonathan Knowles+-- License: Apache-2.0+--+-- Quasi-unique keys.+--+module Test.Key+ ( Key1+ , Key2+ , Key4+ , Key8+ )+where++import Prelude++import Data.Aeson.Types+ ( FromJSON (parseJSON)+ , FromJSONKey (fromJSONKey)+ , FromJSONKeyFunction (FromJSONKeyTextParser)+ , Parser+ , ToJSON (toEncoding, toJSON)+ , ToJSONKey (toJSONKey)+ , toJSONKeyText+ , withText+ )+import Data.Text+ ( Text+ )+import GHC.Generics+ ( Generic+ )+import GHC.TypeLits+ ( Nat+ )+import Test.QuickCheck+ ( Arbitrary+ , CoArbitrary+ , Function+ )+import Test.QuickCheck.Quid+ ( Latin (Latin)+ , Quid+ , Size (Size)+ )+import Text.Read+ ( readMaybe+ )++import qualified Data.Text as Text++newtype Key (size :: Nat) = Key Quid+ deriving stock (Eq, Generic, Ord)+ deriving (Read, Show) via Latin Quid+ deriving (Arbitrary) via Size size Quid+ deriving (CoArbitrary) via Quid+ deriving anyclass (Function)++type Key1 = Key 1+type Key2 = Key 2+type Key4 = Key 4+type Key8 = Key 8++instance ToJSON (Key size) where+ toEncoding = toEncoding . toText+ toJSON = toJSON . toText++instance ToJSONKey (Key size) where+ toJSONKey = toJSONKeyText toText++instance FromJSON (Key size) where+ parseJSON = withText "Key" parseFromText++instance FromJSONKey (Key size) where+ fromJSONKey = FromJSONKeyTextParser parseFromText++toText :: Key size -> Text+toText = Text.dropAround (== '\"') . Text.pack . show++maybeFromText :: Text -> Maybe (Key size)+maybeFromText = readMaybe . show . Text.unpack++parseFromText :: Text -> Parser (Key size)+parseFromText =+ maybe (fail failureMessage) pure . maybeFromText+ where+ failureMessage = "Failed to parse key from JSON"
+ components/monoidmap-aeson-test/Test/QuickCheck/Classes/Hspec.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE PolyKinds #-}++-- |+-- Copyright: © 2022–2025 Jonathan Knowles+-- License: Apache-2.0+--+-- Provides testing functions to check that type class instances obey laws.+--+module Test.QuickCheck.Classes.Hspec+ ( testLaws+ , testLawsMany+ ) where++import Prelude++import Control.Monad+ ( forM_ )+import Data.Proxy+ ( Proxy (..) )+import Data.Typeable+ ( Typeable, typeRep )+import Test.Hspec+ ( Spec, describe, it, parallel )+import Test.QuickCheck.Classes+ ( Laws (..) )++-- | Constructs a test to check that the given type class instance obeys the+-- given set of laws.+--+-- Example usage:+--+-- >>> testLaws @Natural ordLaws+-- >>> testLaws @(Map Int) functorLaws+--+testLaws+ :: forall a. Typeable a+ => (Proxy a -> Laws)+ -> Spec+testLaws getLaws =+ parallel $ describe description $+ forM_ (lawsProperties laws) $ uncurry it+ where+ description = mconcat+ [ "Testing "+ , lawsTypeclass laws+ , " laws for type "+ , show (typeRep $ Proxy @a)+ ]+ laws = getLaws $ Proxy @a++-- | Calls `testLaws` with multiple sets of laws.+--+-- Example usage:+--+-- >>> testLawsMany @Natural [eqLaws, ordLaws]+-- >>> testLawsMany @(Map Int) [foldableLaws, functorLaws]+--+testLawsMany+ :: forall a. Typeable a+ => [Proxy a -> Laws]+ -> Spec+testLawsMany getLawsMany =+ testLaws @a `mapM_` getLawsMany
+ components/monoidmap-aeson/Data/MonoidMap/JSON.hs view
@@ -0,0 +1,131 @@+{-# OPTIONS_GHC -Wno-orphans #-}++-- |+-- Copyright: © 2022–2025 Jonathan Knowles+-- License: Apache-2.0+--+module Data.MonoidMap.JSON+ (+ -- * Introduction+ -- $_introduction++ -- * Examples+ -- $_examples++ -- * Laws+ -- $_laws+ )+ where++import Prelude++import Data.Aeson+ ( FromJSON (parseJSON)+ , FromJSONKey+ , ToJSON (toEncoding, toJSON)+ , ToJSONKey+ , encode+ )+import Data.Map.Strict+ ( Map+ )+import Data.Monoid+ ( Sum+ )+import Data.Monoid.Null+ ( MonoidNull+ )+import Data.MonoidMap+ ( MonoidMap+ , fromList+ , fromMap+ , toMap+ )++-- $_introduction+-- #_introduction#+--+-- This module provides instances of 'ToJSON' and 'FromJSON' for 'MonoidMap'.+--+-- These instances provide objects of type 'MonoidMap' __@k@__ __@v@__ with a+-- JSON encoding that is /identical/ to objects of type 'Map' __@k@__ __@v@__,+-- which are serialised as either JSON /objects/ or /arrays/ depending on the+-- key type __@k@__.++-- $_examples+-- #_examples#+--+-- === Encoding as JSON objects+--+-- @+-- >>> 'encode' '$' 'MonoidMap'.'fromList' [("abc", 'Sum' 1), ("def", 'Sum' 2)]+--+-- "{\\"abc\\":1,\\"def\\":2}"+-- @+--+-- === Encoding as JSON arrays+--+-- @+-- >>> 'encode' '$' 'MonoidMap'.'fromList' [((1,2), 'Sum' 3), ((2,3), 'Sum' 5)]+--+-- "[[[1,2],3],[[2,3],5]]"+-- @++-- $_laws+-- #_laws#+--+-- === Encoding to JSON+--+-- The 'ToJSON' instance satisfies the following laws:+--+-- @+-- 'toEncoding' '==' 'toEncoding' '.' 'MonoidMap'.'toMap'+-- 'toJSON' '==' 'toJSON' '.' 'MonoidMap'.'toMap'+-- @+--+-- === Decoding from JSON+--+-- The 'FromJSON' instance satisfies the following law:+--+-- @+-- 'parseJSON' '==' 'fmap' ('fmap' 'MonoidMap'.'fromMap') 'parseJSON'+-- @+--+-- Mappings from keys to values that decode to 'mempty' are __not__ included in+-- decoded 'MonoidMap' objects.++_importsRequiredForDocumentation :: ()+_importsRequiredForDocumentation = ()+ where+ _encode = encode ()++ _fromList :: (Ord k, MonoidNull v) => [(k, v)] -> MonoidMap k v+ _fromList = fromList++ _fromMap :: (Ord k, MonoidNull v) => Map k v -> MonoidMap k v+ _fromMap = fromMap++ _toMap :: (Ord k, MonoidNull v) => MonoidMap k v -> Map k v+ _toMap = toMap++ _Sum :: Sum ()+ _Sum = undefined++instance+ ( ToJSONKey k+ , ToJSON v+ )+ => ToJSON (MonoidMap k v)+ where+ toEncoding = toEncoding . toMap+ toJSON = toJSON . toMap++instance+ ( FromJSONKey k+ , Ord k+ , FromJSON v+ , MonoidNull v+ )+ => FromJSON (MonoidMap k v)+ where+ parseJSON = fmap (fmap fromMap) parseJSON
+ monoidmap-aeson.cabal view
@@ -0,0 +1,113 @@+cabal-version: 3.0+name: monoidmap-aeson+version: 0.0.0.0+bug-reports: https://github.com/jonathanknowles/monoidmap-aeson/issues+license: Apache-2.0+license-file: LICENSE+author: Jonathan Knowles+maintainer: mail@jonathanknowles.net+copyright: 2022–2025 Jonathan Knowles+category: Data Structures+synopsis: JSON support for monoidmap.+description: JSON support for the monoidmap package, compatible with aeson.++extra-doc-files:+ CHANGELOG.md+ README.md++common dependency-aeson+ build-depends:aeson >= 2.2.3.0 && < 2.3+common dependency-base+ build-depends:base >= 4.14.3.0 && < 4.22+common dependency-containers+ build-depends:containers >= 0.6.5.1 && < 0.8+common dependency-hspec+ build-depends:hspec >= 2.10.9 && < 2.12+common dependency-hspec-golden-aeson+ build-depends:hspec-golden-aeson >= 0.9.0.0 && < 0.10+common dependency-monoid-subclasses+ build-depends:monoid-subclasses >= 1.2.3 && < 1.3+common dependency-monoidmap+ build-depends:monoidmap >= 0.0.3.0 && < 0.1+common dependency-QuickCheck+ build-depends:QuickCheck >= 2.14.2 && < 2.16+common dependency-quickcheck-classes+ build-depends:quickcheck-classes >= 0.6.5.0 && < 0.7+common dependency-quickcheck-quid+ build-depends:quickcheck-quid >= 0.0.1.7 && < 0.1+common dependency-text+ build-depends:text >= 1.2.4.1 && < 2.2++common extensions+ default-extensions:+ BangPatterns+ ConstraintKinds+ DerivingStrategies+ DerivingVia+ FlexibleContexts+ FlexibleInstances+ GeneralizedNewtypeDeriving+ LambdaCase+ MultiParamTypeClasses+ NoImplicitPrelude+ NumericUnderscores+ ScopedTypeVariables+ TupleSections+ TypeApplications+ TypeFamilies+ TypeOperators+ ViewPatterns++source-repository head+ type: git+ location: https://github.com/jonathanknowles/monoidmap-aeson++library+ import:+ , dependency-aeson+ , dependency-base+ , dependency-containers+ , dependency-monoid-subclasses+ , dependency-monoidmap+ , extensions+ hs-source-dirs:+ components/monoidmap-aeson+ exposed-modules:+ Data.MonoidMap.JSON+ default-language:+ Haskell2010++test-suite monoidmap-aeson-test+ import:+ , dependency-aeson+ , dependency-base+ , dependency-containers+ , dependency-hspec+ , dependency-hspec-golden-aeson+ , dependency-monoid-subclasses+ , dependency-monoidmap+ , dependency-QuickCheck+ , dependency-quickcheck-classes+ , dependency-quickcheck-quid+ , dependency-text+ , extensions+ build-depends:+ , monoidmap-aeson+ ghc-options:+ -threaded -with-rtsopts=-N+ main-is:+ Spec.hs+ hs-source-dirs:+ components/monoidmap-aeson-test+ other-modules:+ SpecHook+ Data.MonoidMap.JSONSpec+ Test.Common+ Test.QuickCheck.Classes.Hspec+ Test.Key+ type:+ exitcode-stdio-1.0+ default-language:+ Haskell2010+ build-tool-depends:+ hspec-discover:hspec-discover ==2.*