bower-json 0.3.0.0 → 0.4.0.0
raw patch · 3 files changed
+126/−24 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Web.BowerJson: instance ToJSON Author
+ Web.BowerJson: instance ToJSON BowerJson
+ Web.BowerJson: instance ToJSON ModuleType
+ Web.BowerJson: instance ToJSON PackageName
+ Web.BowerJson: instance ToJSON Repository
+ Web.BowerJson: instance ToJSON Version
+ Web.BowerJson: instance ToJSON VersionRange
Files
- bower-json.cabal +8/−4
- src/Web/BowerJson.hs +68/−1
- test/Main.hs +50/−19
bower-json.cabal view
@@ -1,5 +1,5 @@ name: bower-json-version: 0.3.0.0+version: 0.4.0.0 synopsis: bower.json from Haskell license: MIT license-file: LICENSE@@ -11,9 +11,11 @@ cabal-version: >=1.10 description:- This package provides a data type and FromJSON instance for bower.json- package description files.+ Bower is a package manager for the web (see <http://bower.io>). + This package provides a data type and FromJSON instance for Bower's package+ manifest file, bower.json.+ source-repository head type: git location: https://github.com/hdgarrood/bower-json@@ -38,7 +40,9 @@ , bower-json -any , aeson -any , bytestring -any+ , text -any+ , unordered-containers -any , tasty -any , tasty-hunit -any- ghc-options: -Wall+ ghc-options: -Wall -fno-warn-missing-signatures default-language: Haskell2010
src/Web/BowerJson.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TupleSections #-}+{-# LANGUAGE RecordWildCards #-} -- | A data type representing the Bower.json package description file, together -- with a parser and related functions.@@ -35,6 +35,12 @@ -- | A data type representing the data stored in a bower.json package manifest -- file.+--+-- Note that the 'ToJSON' / 'FromJSON' instances don't exactly match; for+-- example, it is not always the case that decoding from JSON and then encoding+-- to JSON will give you the exact same JSON that you started with. However, if+-- you start with a BowerJson value, encode to JSON, and then decode, you+-- should always get the same value back. data BowerJson = BowerJson { bowerName :: PackageName , bowerDescription :: Maybe String@@ -92,6 +98,42 @@ let xs = HashMap.toList o mapM (\(k, v) -> (,) <$> parseKey k <*> parseJSON v) xs +instance ToJSON BowerJson where+ toJSON BowerJson{..} =+ object $ concat+ [ [ "name" .= bowerName ]+ , maybePair "description" bowerDescription+ , maybeArrayPair "main" bowerMain+ , maybeArrayPair "moduleType" bowerModuleType+ , maybeArrayPair "licence" bowerLicence+ , maybeArrayPair "ignore" bowerIgnore+ , maybeArrayPair "keywords" bowerKeywords+ , maybeArrayPair "authors" bowerAuthors+ , maybePair "homepage" bowerHomepage+ , maybePair "repository" bowerRepository+ , assoc "dependencies" bowerDependencies+ , assoc "devDependencies" bowerDevDependencies+ , assoc "resolutions" bowerResolutions+ , if bowerPrivate then [ "private" .= True ] else []+ ]++ where+ asText = T.pack . runPackageName++ assoc :: ToJSON a => Text -> [(PackageName, a)] -> [Aeson.Pair]+ assoc = maybeArrayAssocPair asText++maybePair :: ToJSON a => Text -> Maybe a -> [Aeson.Pair]+maybePair key = maybe [] (\val -> [key .= val])++maybeArrayPair :: ToJSON a => Text -> [a] -> [Aeson.Pair]+maybeArrayPair _ [] = []+maybeArrayPair key xs = [key .= xs]++maybeArrayAssocPair :: ToJSON b => (a -> Text) -> Text -> [(a,b)] -> [Aeson.Pair]+maybeArrayAssocPair _ _ [] = []+maybeArrayAssocPair f key xs = [key .= object (map (\(k, v) -> f k .= v) xs)]+ -- | Read and attempt to decode a bower.json file. decodeFile :: FilePath -> IO (Either String BowerJson) decodeFile = fmap eitherDecode . B.readFile@@ -111,6 +153,9 @@ Just pkgName -> return pkgName Nothing -> fail ("unable to validate package name: " ++ show text) +instance ToJSON PackageName where+ toJSON = toJSON . runPackageName+ -- | A smart constructor for a PackageName. It ensures that the package name -- satisfies the restrictions described at -- <https://github.com/bower/bower.json-spec#name>.@@ -161,6 +206,9 @@ Just t' -> return t' Nothing -> fail ("invalid module type: " ++ show t) +instance ToJSON ModuleType where+ toJSON = toJSON . map toLower . show+ data Repository = Repository { repositoryUrl :: String , repositoryType :: String@@ -173,6 +221,12 @@ Repository <$> o .: "url" <*> o .: "type" +instance ToJSON Repository where+ toJSON Repository{..} =+ object [ "url" .= repositoryUrl+ , "type" .= repositoryType+ ]+ data Author = Author { authorName :: String , authorEmail :: Maybe String@@ -193,6 +247,13 @@ parseJSON v = Aeson.typeMismatch "Author" v +instance ToJSON Author where+ toJSON Author{..} =+ object $+ [ "name" .= authorName ] +++ maybePair "email" authorEmail +++ maybePair "homepage" authorHomepage+ -- | Given a prefix and a suffix, go through the supplied list, attempting -- to extract one string from the list which has the given prefix and suffix, -- All other strings in the list are returned as the second component of the@@ -223,6 +284,9 @@ parseJSON = withText "Version" (pure . Version . T.unpack) +instance ToJSON Version where+ toJSON = toJSON . runVersion+ newtype VersionRange = VersionRange { runVersionRange :: String } deriving (Show, Eq, Ord)@@ -230,3 +294,6 @@ instance FromJSON VersionRange where parseJSON = withText "VersionRange" (pure . VersionRange . T.unpack)++instance ToJSON VersionRange where+ toJSON = toJSON . runVersionRange
test/Main.hs view
@@ -26,47 +26,47 @@ tests = testGroup "tests" [ testGroup "FromJSON Author instance" authorTests , testGroup "optional keys" optionalKeyTests+ , testGroup "round trips" roundTripTests ] authorTests :: [TestTree] authorTests = [ testCase "As string without homepage/email" $ do- authorWithoutOptionalAttrs @=?+ Just authorWithoutOptionalAttrs @=? decodeValue "\"Harry Garrood\"" -- should not be sensitive to extra whitespace- authorWithoutOptionalAttrs @=?+ Just authorWithoutOptionalAttrs @=? decodeValue "\" Harry Garrood \"" , testCase "As string with homepage/email" $ do- authorWithEmail @=?+ Just authorWithEmail @=? decodeValue "\"Harry Garrood <harry@garrood.me>\"" - authorWithHomepage @=?+ Just authorWithHomepage @=? decodeValue "\"Harry Garrood (http://harry.garrood.me)\"" - authorWithBoth @=?+ Just authorWithBoth @=? decodeValue "\"Harry Garrood <harry@garrood.me> (http://harry.garrood.me)\"" , testCase "As object" $ do- authorWithoutOptionalAttrs @=?+ Just authorWithoutOptionalAttrs @=? decode "{\"name\": \"Harry Garrood\"}" - authorWithEmail @=?+ Just authorWithEmail @=? decode "{\"name\": \"Harry Garrood\", \"email\": \"harry@garrood.me\"}" - authorWithHomepage @=?+ Just authorWithHomepage @=? decode "{\"name\": \"Harry Garrood\", \"homepage\": \"http://harry.garrood.me\"}" - authorWithBoth @=?+ Just authorWithBoth @=? decode "{\"name\": \"Harry Garrood\", \"email\": \"harry@garrood.me\", \"homepage\": \"http://harry.garrood.me\"}" ] - where- authorWithoutOptionalAttrs = Just (Author "Harry Garrood" Nothing Nothing)- authorWithEmail = Just (Author "Harry Garrood" (Just "harry@garrood.me") Nothing)- authorWithHomepage = Just (Author "Harry Garrood" Nothing (Just "http://harry.garrood.me"))- authorWithBoth = Just (Author "Harry Garrood" (Just "harry@garrood.me") (Just "http://harry.garrood.me"))+authorWithoutOptionalAttrs = Author "Harry Garrood" Nothing Nothing+authorWithEmail = Author "Harry Garrood" (Just "harry@garrood.me") Nothing+authorWithHomepage = Author "Harry Garrood" Nothing (Just "http://harry.garrood.me")+authorWithBoth = Author "Harry Garrood" (Just "harry@garrood.me") (Just "http://harry.garrood.me") optionalKeyTests :: [TestTree] optionalKeyTests =@@ -88,8 +88,39 @@ decode "{\"name\": \"test-package\", \"moduleType\": [\"amd\"]}" ] where- pkgName = fromJust (mkPackageName "test-package")- depPkgName = fromJust (mkPackageName "dependency-package")- basic = BowerJson pkgName Nothing [] [] [] [] [] [] Nothing Nothing [] [] [] False- basicWithDeps = basic { bowerDependencies = [(depPkgName, VersionRange ">= 1.0")] }- basicWithModuleType = basic { bowerModuleType = [AMD] }++pkgName = fromJust (mkPackageName "test-package")+depPkgName = fromJust (mkPackageName "dependency-package")+basic = BowerJson pkgName Nothing [] [] [] [] [] [] Nothing Nothing [] [] [] False+basicWithDeps = basic { bowerDependencies = [(depPkgName, VersionRange ">= 1.0")] }+basicWithModuleType = basic { bowerModuleType = [AMD] }++complex =+ basicWithDeps+ { bowerDescription = Just "hello, world"+ , bowerMain = ["foo.js"]+ , bowerModuleType = [Globals, Node]+ , bowerLicence = ["MIT"]+ , bowerIgnore = []+ , bowerKeywords = ["purescript"]+ , bowerAuthors = [authorWithoutOptionalAttrs, authorWithEmail, authorWithBoth]+ , bowerHomepage = Nothing+ , bowerRepository = Just (Repository "git://github.com/hdgarrood/test-package" "git")+ , bowerDevDependencies = []+ , bowerResolutions = []+ }++complexPrivate = complex { bowerPrivate = True }++allBowerJsons =+ [ ("basic", basic)+ , ("basicWithDeps", basicWithDeps)+ , ("basicWithModuleType", basicWithModuleType)+ , ("complex", complex)+ , ("complexPrivate", complexPrivate)+ ]++roundTripTests :: [TestTree]+roundTripTests =+ map (\(name, b) -> testCase name (Just b @=? decode (encode b)))+ allBowerJsons