packages feed

salve 0.0.6 → 0.0.7

raw patch · 4 files changed

+124/−71 lines, 4 filesdep ~basedep ~doctestdep ~microlensPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base, doctest, microlens

API changes (from Hackage documentation)

+ Salve.Internal: stringToIntegral :: Integral a => String -> a
+ Salve.Internal: toWord64 :: Integer -> Maybe Word64
- Salve: majorLens :: Functor f => (Word -> f Word) -> Version -> f Version
+ Salve: majorLens :: Functor f => (Word64 -> f Word64) -> Version -> f Version
- Salve: makeVersion :: Word -> Word -> Word -> [PreRelease] -> [Build] -> Version
+ Salve: makeVersion :: Word64 -> Word64 -> Word64 -> [PreRelease] -> [Build] -> Version
- Salve: minorLens :: Functor f => (Word -> f Word) -> Version -> f Version
+ Salve: minorLens :: Functor f => (Word64 -> f Word64) -> Version -> f Version
- Salve: patchLens :: Functor f => (Word -> f Word) -> Version -> f Version
+ Salve: patchLens :: Functor f => (Word64 -> f Word64) -> Version -> f Version
- Salve.Internal: PreReleaseNumeric :: Word -> PreRelease
+ Salve.Internal: PreReleaseNumeric :: Word64 -> PreRelease
- Salve.Internal: Version :: Word -> Word -> Word -> [PreRelease] -> [Build] -> Version
+ Salve.Internal: Version :: Word64 -> Word64 -> Word64 -> [PreRelease] -> [Build] -> Version
- Salve.Internal: WildcardMinor :: Word -> Wildcard
+ Salve.Internal: WildcardMinor :: Word64 -> Wildcard
- Salve.Internal: WildcardPatch :: Word -> Word -> Wildcard
+ Salve.Internal: WildcardPatch :: Word64 -> Word64 -> Wildcard
- Salve.Internal: [versionMajor] :: Version -> Word
+ Salve.Internal: [versionMajor] :: Version -> Word64
- Salve.Internal: [versionMinor] :: Version -> Word
+ Salve.Internal: [versionMinor] :: Version -> Word64
- Salve.Internal: [versionPatch] :: Version -> Word
+ Salve.Internal: [versionPatch] :: Version -> Word64
- Salve.Internal: majorLens :: Functor f => (Word -> f Word) -> Version -> f Version
+ Salve.Internal: majorLens :: Functor f => (Word64 -> f Word64) -> Version -> f Version
- Salve.Internal: makeVersion :: Word -> Word -> Word -> [PreRelease] -> [Build] -> Version
+ Salve.Internal: makeVersion :: Word64 -> Word64 -> Word64 -> [PreRelease] -> [Build] -> Version
- Salve.Internal: minorLens :: Functor f => (Word -> f Word) -> Version -> f Version
+ Salve.Internal: minorLens :: Functor f => (Word64 -> f Word64) -> Version -> f Version
- Salve.Internal: mkV :: Word -> Word -> Word -> Version
+ Salve.Internal: mkV :: Word64 -> Word64 -> Word64 -> Version
- Salve.Internal: nonZeroP :: ReadP Word
+ Salve.Internal: nonZeroP :: ReadP Word64
- Salve.Internal: numberP :: ReadP Word
+ Salve.Internal: numberP :: ReadP Word64
- Salve.Internal: patchLens :: Functor f => (Word -> f Word) -> Version -> f Version
+ Salve.Internal: patchLens :: Functor f => (Word64 -> f Word64) -> Version -> f Version
- Salve.Internal: zeroP :: ReadP Word
+ Salve.Internal: zeroP :: ReadP Word64

Files

library/Salve.hs view
@@ -1,7 +1,7 @@ -- | This module defines types and functions for working with versions as -- defined by [Semantic Versioning](http://semver.org/spec/v2.0.0.html). It -- also provides types and functions for working with version constraints as--- described by [npm](https://docs.npmjs.com/misc/semver#ranges).+-- described by [npm](https://github.com/npm/npm/blob/d081cc6/doc/misc/semver.md#ranges). module Salve ( -- | This module doesn't export anything that conflicts with the "Prelude", so -- you can import it unqualified.@@ -9,7 +9,8 @@ -- >>> import Salve -- -- This module provides lenses for modifying versions. If you want to modify--- versions, consider importing a lens library like "Lens.Micro".+-- versions, consider importing a lens library like+-- [microlens](https://www.stackage.org/lts-9.3/package/microlens-0.4.8.1). -- -- The 'Version' data type is the core of this module. Use 'parseVersion' to -- make versions and 'renderVersion' to convert them into strings.@@ -56,8 +57,9 @@ -- * Rationale  -- ** The PVP--- | Haskell's <https://pvp.haskell.org/ Package Versioning Policy> (PVP)--- defines three things:+-- | Haskell's+-- [Package Versioning Policy](https://github.com/haskell/pvp/blob/176bb14/pvp-specification.md)+-- (PVP) defines three things: -- -- 1.  A spec for versioning your package, which includes how version numbers --     look and how to encode breaking changes.@@ -72,7 +74,7 @@ -- -- Looking at the first point, why might you want to use SemVer instead of the -- PVP? The PVP has many problems, as described by the--- <http://taylor.fausak.me/2016/12/28/problematic-versioning-policy/ Problematic versioning policy>+-- [Problematic versioning policy](http://taylor.fausak.me/2016/12/28/problematic-versioning-policy/) -- blog post. In short, the PVP is too flexible and it's unique to Haskell, -- which causes unnecessary friction with developers from other languages. --@@ -86,7 +88,7 @@ -- | There are already a few modules that provide version numbers. Why do we -- need another one? Let's take a look at the options. ----- -   <https://www.stackage.org/haddock/lts-9.3/base-4.9.1.0/Data-Version.html Data.Version>+-- -   [Data.Version](https://www.stackage.org/haddock/lts-9.3/base-4.9.1.0/Data-Version.html) --     from the @base@ package: -- --     -   Exposes constructors, which allows creating versions that cannot be@@ -96,7 +98,7 @@ --     -   Does not support build metadata on versions. --     -   Does not support constraints. ----- -   <https://www.stackage.org/haddock/lts-9.3/Cabal-1.24.2.0/Distribution-Version.html Distribution.Version>+-- -   [Distribution.Version](https://www.stackage.org/haddock/lts-9.3/Cabal-1.24.2.0/Distribution-Version.html) --     from the @Cabal@ package: -- --     -   Has the same problems as Data.Version because it re-uses that@@ -105,13 +107,13 @@ --         @deepseq@, @directory@, @filepath@, @pretty@, @process@, @time@, and --         @unix@ packages. ----- -   <https://www.stackage.org/haddock/lts-9.3/semver-0.3.3.1/Data-SemVer.html Data.SemVer>+-- -   [Data.SemVer](https://www.stackage.org/haddock/lts-9.3/semver-0.3.3.1/Data-SemVer.html) --     from the @semver@ package: -- --     -   Depends on the @attoparsec@, @deepseq@, and @text@ packages. --     -   Does not support version constraints. ----- -   <https://hackage.haskell.org/package/semver-range-0.2.2/docs/Data-SemVer.html Data.SemVer>+-- -   [Data.SemVer](https://hackage.haskell.org/package/semver-range-0.2.2/docs/Data-SemVer.html) --     from the @semver-range@ package: -- --     -   Depends on the @classy-prelude@, @parsec@, @text@, and@@ -119,7 +121,7 @@ --     -   Module name collides with the @semver@ package. --     -   Supports constraints, but does not provide a way to render them. ----- -   <https://www.stackage.org/haddock/lts-9.3/versions-3.1.1/Data-Versions.html Data.Versions>+-- -   [Data.Versions](https://www.stackage.org/haddock/lts-9.3/versions-3.1.1/Data-Versions.html) --     from the @versions@ package: -- --     -   Depends on the @deepseq@, @hashable@, @megaparsec@, and @text@@@ -192,8 +194,7 @@ -- Don't be scared by these type signatures. They are provided in full to avoid -- the @RankNTypes@ language extension. The type signature -- @'Functor' f => (a -> f a) -> 'Version' -> f 'Version'@ is the same as--- @'Lens.Micro.Lens'' 'Version' a@ (from "Lens.Micro"), which you may already--- be familiar with.+-- @Lens' 'Version' a@, which you may already be familiar with. majorLens, minorLens, patchLens,@@ -253,6 +254,27 @@ -- Nothing -- >>> parseVersion "0.0.0 " -- Nothing+--+-- Each version component cannot be larger than a 64-bit unsigned integer.+--+-- >>> parseVersion "18446744073709551615.0.0"+-- Just (Version {versionMajor = 18446744073709551615, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})+-- >>> parseVersion "18446744073709551616.0.0"+-- Nothing+--+-- Numeric pre-releases tags cannot be larger than a 64-bit unsigned integer.+--+-- >>> parseVersion "0.0.0-18446744073709551615"+-- Just (Version {versionMajor = 0, versionMinor = 0, versionPatch = 0, versionPreReleases = [PreReleaseNumeric 18446744073709551615], versionBuilds = []})+-- >>> parseVersion "0.0.0-18446744073709551616"+-- Nothing+--+-- Build metadata is not numeric so it does not have any limit.+--+-- >>> parseVersion "0.0.0+18446744073709551615"+-- Just (Version {versionMajor = 0, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = [Build "18446744073709551615"]})+-- >>> parseVersion "0.0.0+18446744073709551616"+-- Just (Version {versionMajor = 0, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = [Build "18446744073709551616"]})  -- ** Constraints -- | Partial version numbers are not allowed.@@ -576,3 +598,6 @@ ) where  import Salve.Internal++-- $setup+-- >>> import Control.Applicative
library/Salve/Internal.hs view
@@ -7,13 +7,15 @@ import qualified Data.Char as Char import qualified Data.List as List import qualified Data.Maybe as Maybe+import qualified Data.Monoid as Monoid import qualified Data.Ord as Ord+import qualified Data.Word as Word import qualified Text.ParserCombinators.ReadP as ReadP-import qualified Text.Read as Read  -- $setup+-- >>> import Control.Applicative -- >>> import Lens.Micro--- >>> import Lens.Micro.Extras+-- >>> let view l x = x ^. l  -- * Public @@ -27,14 +29,14 @@ -- -- Use 'parseVersion' to create versions. data Version = Version-  { versionMajor :: Word-  , versionMinor :: Word-  , versionPatch :: Word+  { versionMajor :: Word.Word64+  , versionMinor :: Word.Word64+  , versionPatch :: Word.Word64   , versionPreReleases :: [PreRelease]   , versionBuilds :: [Build]   } deriving (Eq, Show) --- | In general, 'Version's compare in the way that you would expect. First the+-- | In general, versions compare in the way that you would expect. First the -- major version numbers are compared, then the minors, then the patches. -- -- >>> compare <$> parseVersion "1.2.3" <*> parseVersion "2.0.0"@@ -69,7 +71,7 @@ -- >>> (==) <$> parseVersion "1.2.3+a" <*> parseVersion "1.2.3+b" -- Just False instance Ord Version where-  compare x y = mconcat+  compare x y = Monoid.mconcat     [ Ord.comparing versionMajor x y     , Ord.comparing versionMinor x y     , Ord.comparing versionPatch x y@@ -93,7 +95,7 @@ -- -- Use 'parsePreRelease' to create pre-releases. data PreRelease-  = PreReleaseNumeric Word+  = PreReleaseNumeric Word.Word64   | PreReleaseTextual String   deriving (Eq, Show) @@ -132,7 +134,7 @@ -- | Constrains allowable version numbers. -- -- Use 'parseConstraint' to create constraints and 'satisfiesConstraint' to see--- if a version number satisfiesConstraint a constraint.+-- if a version number satisfies a constraint. data Constraint   = ConstraintOperator Operator Version   | ConstraintHyphen Version Version@@ -143,12 +145,12 @@  -- | Makes a new version number. ----- >>> makeVersion 0 0 0 [] []--- Version {versionMajor = 0, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []}+-- >>> makeVersion 1 2 3 [unsafeParsePreRelease "pre"] [unsafeParseBuild "build"]+-- Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [PreReleaseTextual "pre"], versionBuilds = [Build "build"]} -- -- This can be a useful alternative to 'parseVersion' if you want a total way -- to create a version.-makeVersion :: Word -> Word -> Word -> [PreRelease] -> [Build] -> Version+makeVersion :: Word.Word64 -> Word.Word64 -> Word.Word64 -> [PreRelease] -> [Build] -> Version makeVersion major minor patch preReleases builds = Version   { versionMajor = major   , versionMinor = minor@@ -164,8 +166,8 @@ initialVersion :: Version initialVersion = makeVersion 0 0 0 [] [] --- | Attempts to parse a version. This parser follows [SemVer's--- BNF](https://github.com/mojombo/semver/blob/eb9aac5/semver.md#backusnaur-form-grammar-for-valid-semver-versions).+-- | Attempts to parse a version. This parser follows+-- [SemVer's BNF](https://github.com/mojombo/semver/blob/eb9aac5/semver.md#backusnaur-form-grammar-for-valid-semver-versions). -- -- >>> parseVersion "1.2.3-p.4+b.5" -- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [PreReleaseTextual "p",PreReleaseNumeric 4], versionBuilds = [Build "b",Build "5"]})@@ -220,10 +222,8 @@ parseBuild :: String -> Maybe Build parseBuild s = parse buildP s --- | Attempts to parse a constraint. This parser follows [npm's--- BNF](https://github.com/npm/npm/blob/d081cc6/doc/misc/semver.md#range-grammar),--- except that neither the so-called "x-ranges" nor partial version numbers are--- not supported. So you cannot use @1.2.x@ or @>1.2@ as version constraints.+-- | Attempts to parse a constraint. This parser mostly follows+-- [npm's BNF](https://github.com/npm/npm/blob/d081cc6/doc/misc/semver.md#range-grammar). -- -- >>> parseConstraint ">1.2.3" -- Just (ConstraintOperator OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))@@ -232,6 +232,19 @@ -- -- >>> parseConstraint "wrong" -- Nothing+--+-- The two departures from npm's BNF are that x-ranges cannot be used with+-- other operators and partial version numbers are not allowed.+--+-- >>> parseConstraint "1.2.x"+-- Just (ConstraintWildcard (WildcardPatch 1 2))+-- >>> parseConstraint ">=1.2.x"+-- Nothing+--+-- >>> parseConstraint "1.2"+-- Nothing+-- >>> parseConstraint ">=1.2"+-- Nothing parseConstraint :: String -> Maybe Constraint parseConstraint s = parse constraintsP s @@ -308,7 +321,7 @@ -- >>> renderVersion <$> parseVersion "1.2.3-p.4+b.5" -- Just "1.2.3-p.4+b.5" renderVersion :: Version -> String-renderVersion v = mconcat+renderVersion v = concat   [ show (versionMajor v)   , "."   , show (versionMinor v)@@ -460,7 +473,7 @@ -- Just 1 -- >>> set majorLens 4 <$> parseVersion "1.2.3" -- Just (Version {versionMajor = 4, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})-majorLens :: Functor f => (Word -> f Word) -> Version -> f Version+majorLens :: Functor f => (Word.Word64 -> f Word.Word64) -> Version -> f Version majorLens f v = fmap   (\ m -> v { versionMajor = m })   (f (versionMajor v))@@ -471,7 +484,7 @@ -- Just 2 -- >>> set minorLens 4 <$> parseVersion "1.2.3" -- Just (Version {versionMajor = 1, versionMinor = 4, versionPatch = 3, versionPreReleases = [], versionBuilds = []})-minorLens :: Functor f => (Word -> f Word) -> Version -> f Version+minorLens :: Functor f => (Word.Word64 -> f Word.Word64) -> Version -> f Version minorLens f v = fmap   (\ n -> v { versionMinor = n })   (f (versionMinor v))@@ -482,7 +495,7 @@ -- Just 3 -- >>> set patchLens 4 <$> parseVersion "1.2.3" -- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 4, versionPreReleases = [], versionBuilds = []})-patchLens :: Functor f => (Word -> f Word) -> Version -> f Version+patchLens :: Functor f => (Word.Word64 -> f Word.Word64) -> Version -> f Version patchLens f v = fmap   (\ p -> v { versionPatch = p })   (f (versionPatch v))@@ -525,8 +538,8 @@  data Wildcard   = WildcardMajor-  | WildcardMinor Word-  | WildcardPatch Word Word+  | WildcardMinor Word.Word64+  | WildcardPatch Word.Word64 Word.Word64   deriving (Eq, Show)  -- ** Constructors@@ -635,7 +648,7 @@   patch <- numberP   preReleases <- preReleasesP   builds <- buildsP-  pure (makeVersion major minor patch preReleases builds)+  return (makeVersion major minor patch preReleases builds)  preReleasesP :: ReadP.ReadP [PreRelease] preReleasesP = ReadP.option [] (do@@ -648,14 +661,14 @@ preReleaseNumberP :: ReadP.ReadP PreRelease preReleaseNumberP = do   n <- numberP-  pure (PreReleaseNumeric n)+  return (PreReleaseNumeric n)  preReleaseStringP :: ReadP.ReadP PreRelease preReleaseStringP = do   s <- ReadP.munch1 isIdentifier   if all Char.isDigit s     then ReadP.pfail-    else pure (PreReleaseTextual s)+    else return (PreReleaseTextual s)  buildsP :: ReadP.ReadP [Build] buildsP = ReadP.option [] (do@@ -665,21 +678,21 @@ buildP :: ReadP.ReadP Build buildP = do   b <- ReadP.munch1 isIdentifier-  pure (Build b)+  return (Build b) -numberP :: ReadP.ReadP Word-numberP = nonZeroP ReadP.<++ zeroP+numberP :: ReadP.ReadP Word.Word64+numberP = zeroP ReadP.<++ nonZeroP -zeroP :: ReadP.ReadP Word+zeroP :: ReadP.ReadP Word.Word64 zeroP = do   Monad.void (ReadP.char '0')-  pure 0+  return 0 -nonZeroP :: ReadP.ReadP Word+nonZeroP :: ReadP.ReadP Word.Word64 nonZeroP = do   x <- ReadP.satisfy isAsciiDigitNonZero   ys <- ReadP.munch Char.isDigit-  case Read.readMaybe (x : ys) of+  case toWord64 (stringToIntegral (x : ys)) of     Nothing -> ReadP.pfail     Just n -> pure n @@ -688,19 +701,19 @@   spacesP   cs <- ReadP.sepBy1 constraintP orP   spacesP-  pure (foldr1 constraintOr cs)+  return (foldr1 constraintOr cs)  constraintP :: ReadP.ReadP Constraint constraintP = do   cs <- ReadP.sepBy1 simpleP spaces1P-  pure (foldr1 constraintAnd cs)+  return (foldr1 constraintAnd cs)  hyphenatedP :: ReadP.ReadP Constraint hyphenatedP = do   v <- versionP   hyphenP   w <- versionP-  pure (constraintHyphen v w)+  return (constraintHyphen v w)  simpleP :: ReadP.ReadP Constraint simpleP = ReadP.choice [hyphenatedP, wildcardConstraintP, primitiveP]@@ -709,7 +722,7 @@ wildcardConstraintP = do   ReadP.optional (ReadP.char '=')   w <- wildcardP-  pure (ConstraintWildcard w)+  return (ConstraintWildcard w)  wildcardP :: ReadP.ReadP Wildcard wildcardP = ReadP.choice [wildcardPatchP, wildcardMinorP, wildcardMajorP]@@ -721,7 +734,7 @@   n <- numberP   Monad.void (ReadP.char '.')   Monad.void (ReadP.satisfy isWildcard)-  pure (WildcardPatch m n)+  return (WildcardPatch m n)  wildcardMinorP :: ReadP.ReadP Wildcard wildcardMinorP = do@@ -730,7 +743,7 @@   Monad.void (ReadP.satisfy isWildcard)   Monad.void (ReadP.char '.')   Monad.void (ReadP.satisfy isWildcard)-  pure (WildcardMinor m)+  return (WildcardMinor m)  wildcardMajorP :: ReadP.ReadP Wildcard wildcardMajorP = do@@ -739,25 +752,25 @@   Monad.void (ReadP.satisfy isWildcard)   Monad.void (ReadP.char '.')   Monad.void (ReadP.satisfy isWildcard)-  pure WildcardMajor+  return WildcardMajor  primitiveP :: ReadP.ReadP Constraint primitiveP = do   o <- operatorP   spacesP   v <- versionP-  pure (ConstraintOperator o v)+  return (ConstraintOperator o v)  operatorP :: ReadP.ReadP Operator operatorP = ReadP.choice-  [ ReadP.string "<=" *> pure OperatorLE-  , ReadP.string ">=" *> pure OperatorGE-  , ReadP.char '<' *> pure OperatorLT-  , ReadP.char '>' *> pure OperatorGT-  , ReadP.char '=' *> pure OperatorEQ-  , ReadP.char '^' *> pure OperatorCaret-  , ReadP.char '~' *> pure OperatorTilde-  , pure OperatorEQ+  [ ReadP.string "<=" >> return OperatorLE+  , ReadP.string ">=" >> return OperatorGE+  , ReadP.char '<' >> return OperatorLT+  , ReadP.char '>' >> return OperatorGT+  , ReadP.char '=' >> return OperatorEQ+  , ReadP.char '^' >> return OperatorCaret+  , ReadP.char '~' >> return OperatorTilde+  , return OperatorEQ   ]  hyphenP :: ReadP.ReadP ()@@ -809,8 +822,20 @@   let p' = ReadP.readP_to_S p   in Maybe.listToMaybe (do     (x, "") <- p' s-    pure x)+    return x) +stringToIntegral :: Integral a => String -> a+stringToIntegral s = foldl+  (\ n d -> (n * 10) + (fromIntegral (fromEnum d) - 48)) 0 s++toWord64 :: Integer -> Maybe Word.Word64+toWord64 n =+  if n < 0+  then Nothing+  else if n > fromIntegral (maxBound :: Word.Word64)+  then Nothing+  else Just (fromIntegral n)+ -- * Simple constraints -- | Simple constraints are just as expressive as 'Constraint's, but they are -- easier to reason about. You can think of them as the desugared version of@@ -824,7 +849,7 @@   | SCOr SimpleConstraint SimpleConstraint   deriving (Eq, Show) -mkV :: Word -> Word -> Word -> Version+mkV :: Word.Word64 -> Word.Word64 -> Word.Word64 -> Version mkV m n p = makeVersion m n p [] []  satisfiesSC :: SimpleConstraint -> Version -> Bool
salve.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack  name:           salve-version:        0.0.6+version:        0.0.7 synopsis:       Semantic version numbers and constraints. description:    Salve provides semantic version (SemVer) numbers and constraints (ranges). category:       Distribution@@ -28,7 +28,7 @@       library   ghc-options: -Wall   build-depends:-      base >=4.8.2 && <4.11+      base >=4.7.0 && <4.11   exposed-modules:       Salve       Salve.Internal@@ -41,9 +41,9 @@       tests   ghc-options: -Wall   build-depends:-      base >=4.8.2 && <4.11-    , doctest >=0.10.1 && <0.14-    , microlens >=0.3.5 && <0.5+      base >=4.7.0 && <4.11+    , doctest >=0.9.11 && <0.14+    , microlens >=0.2.0 && <0.5   default-language: Haskell2010  benchmark benchmark@@ -53,7 +53,7 @@       benchmarks   ghc-options: -Wall   build-depends:-      base >=4.8.2 && <4.11+      base >=4.7.0 && <4.11     , criterion >=1.1.0 && <1.3     , deepseq >=1.4.1 && <1.5     , salve
tests/doctest.hs view
@@ -1,4 +1,7 @@ import Test.DocTest  main :: IO ()-main = doctest ["library"]+main = doctest+  [ "library/Salve/Internal.hs"+  , "library/Salve.hs"+  ]