salve 0.0.3 → 0.0.4
raw patch · 4 files changed
+406/−359 lines, 4 filesdep +semverdep +semver-rangePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: semver, semver-range
API changes (from Hackage documentation)
- Salve: constraintAnd :: Constraint -> Constraint -> Constraint
- Salve: constraintCaret :: Version -> Constraint
- Salve: constraintEQ :: Version -> Constraint
- Salve: constraintGE :: Version -> Constraint
- Salve: constraintGT :: Version -> Constraint
- Salve: constraintHyphen :: Version -> Version -> Constraint
- Salve: constraintLE :: Version -> Constraint
- Salve: constraintLT :: Version -> Constraint
- Salve: constraintOr :: Constraint -> Constraint -> Constraint
- Salve: constraintTilde :: Version -> Constraint
- Salve.Internal: Parser :: (String -> [(a, String)]) -> Parser a
- Salve.Internal: [runParser] :: Parser a -> String -> [(a, String)]
- Salve.Internal: caretP :: Parser Constraint
- Salve.Internal: charP :: Char -> Parser Char
- Salve.Internal: choiceP :: Parser a -> Parser a -> Parser a
- Salve.Internal: comparing :: Ord b => (a -> b) -> a -> a -> Ordering
- Salve.Internal: eqP :: Parser Operator
- Salve.Internal: failP :: Parser a
- Salve.Internal: geP :: Parser Operator
- Salve.Internal: getP :: Parser Char
- Salve.Internal: gtP :: Parser Operator
- Salve.Internal: instance GHC.Base.Applicative Salve.Internal.Parser
- Salve.Internal: instance GHC.Base.Functor Salve.Internal.Parser
- Salve.Internal: instance GHC.Base.Monad Salve.Internal.Parser
- Salve.Internal: isAsciiAlpha :: Char -> Bool
- Salve.Internal: isAsciiAlphaLower :: Char -> Bool
- Salve.Internal: isAsciiAlphaUpper :: Char -> Bool
- Salve.Internal: isAsciiDigit :: Char -> Bool
- Salve.Internal: join :: Char -> [String] -> String
- Salve.Internal: leP :: Parser Operator
- Salve.Internal: ltP :: Parser Operator
- Salve.Internal: manyP :: Parser a -> Parser [a]
- Salve.Internal: newtype Parser a
- Salve.Internal: oneOfP :: [Parser a] -> Parser a
- Salve.Internal: optionP :: a -> Parser a -> Parser a
- Salve.Internal: safeHead :: [a] -> Maybe a
- Salve.Internal: satisfyP :: (Char -> Bool) -> Parser Char
- Salve.Internal: sepBy1P :: Parser b -> Parser a -> Parser [a]
- Salve.Internal: sepByP :: Parser b -> Parser a -> Parser [a]
- Salve.Internal: someP :: Parser a -> Parser [a]
- Salve.Internal: spaceP :: Parser Char
- Salve.Internal: stringP :: String -> Parser String
- Salve.Internal: tildeP :: Parser Constraint
+ Salve.Internal: ConstraintWildcard :: Wildcard -> Constraint
+ Salve.Internal: WildcardMajor :: Wildcard
+ Salve.Internal: WildcardMinor :: Word -> Wildcard
+ Salve.Internal: WildcardPatch :: Word -> Word -> Wildcard
+ Salve.Internal: data Wildcard
+ Salve.Internal: instance GHC.Classes.Eq Salve.Internal.Wildcard
+ Salve.Internal: instance GHC.Show.Show Salve.Internal.Wildcard
+ Salve.Internal: isWildcard :: Char -> Bool
+ Salve.Internal: spaces1P :: ReadP ()
+ Salve.Internal: spacesP :: ReadP ()
+ Salve.Internal: wildcardConstraintP :: ReadP Constraint
+ Salve.Internal: wildcardMajorP :: ReadP Wildcard
+ Salve.Internal: wildcardMinorP :: ReadP Wildcard
+ Salve.Internal: wildcardP :: ReadP Wildcard
+ Salve.Internal: wildcardPatchP :: ReadP Wildcard
- Salve.Internal: buildP :: Parser Build
+ Salve.Internal: buildP :: ReadP Build
- Salve.Internal: buildsP :: Parser [Build]
+ Salve.Internal: buildsP :: ReadP [Build]
- Salve.Internal: constraintP :: Parser Constraint
+ Salve.Internal: constraintP :: ReadP Constraint
- Salve.Internal: constraintsP :: Parser Constraint
+ Salve.Internal: constraintsP :: ReadP Constraint
- Salve.Internal: hyphenP :: Parser String
+ Salve.Internal: hyphenP :: ReadP ()
- Salve.Internal: hyphenatedP :: Parser Constraint
+ Salve.Internal: hyphenatedP :: ReadP Constraint
- Salve.Internal: nonZeroP :: Parser Word
+ Salve.Internal: nonZeroP :: ReadP Word
- Salve.Internal: numberP :: Parser Word
+ Salve.Internal: numberP :: ReadP Word
- Salve.Internal: operatorP :: Parser Operator
+ Salve.Internal: operatorP :: ReadP Operator
- Salve.Internal: orP :: Parser String
+ Salve.Internal: orP :: ReadP ()
- Salve.Internal: parse :: Parser a -> String -> Maybe a
+ Salve.Internal: parse :: ReadP a -> String -> Maybe a
- Salve.Internal: preReleaseNumberP :: Parser PreRelease
+ Salve.Internal: preReleaseNumberP :: ReadP PreRelease
- Salve.Internal: preReleaseP :: Parser PreRelease
+ Salve.Internal: preReleaseP :: ReadP PreRelease
- Salve.Internal: preReleaseStringP :: Parser PreRelease
+ Salve.Internal: preReleaseStringP :: ReadP PreRelease
- Salve.Internal: preReleasesP :: Parser [PreRelease]
+ Salve.Internal: preReleasesP :: ReadP [PreRelease]
- Salve.Internal: primitiveP :: Parser Constraint
+ Salve.Internal: primitiveP :: ReadP Constraint
- Salve.Internal: simpleP :: Parser Constraint
+ Salve.Internal: simpleP :: ReadP Constraint
- Salve.Internal: versionP :: Parser Version
+ Salve.Internal: versionP :: ReadP Version
- Salve.Internal: zeroP :: Parser Word
+ Salve.Internal: zeroP :: ReadP Word
Files
- benchmarks/benchmark.hs +71/−42
- library/Salve.hs +96/−29
- library/Salve/Internal.hs +236/−287
- salve.cabal +3/−1
benchmarks/benchmark.hs view
@@ -2,67 +2,96 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PackageImports #-} {-# LANGUAGE StandaloneDeriving #-} import qualified Control.DeepSeq as DeepSeq import qualified Criterion.Main as Criterion import qualified Data.Maybe as Maybe+import qualified "semver" Data.SemVer as SemVer+import qualified "semver-range" Data.SemVer as SemVerRange import qualified Data.Version as Version import qualified GHC.Generics as Ghc import qualified Salve.Internal as Salve import qualified Text.ParserCombinators.ReadP as ReadP -deriving instance Ghc.Generic Salve.Build-deriving instance Ghc.Generic Salve.Constraint-deriving instance Ghc.Generic Salve.Operator-deriving instance Ghc.Generic Salve.PreRelease-deriving instance Ghc.Generic Salve.Version- deriving instance DeepSeq.NFData Salve.Build deriving instance DeepSeq.NFData Salve.Constraint deriving instance DeepSeq.NFData Salve.Operator deriving instance DeepSeq.NFData Salve.PreRelease deriving instance DeepSeq.NFData Salve.Version+deriving instance DeepSeq.NFData Salve.Wildcard+deriving instance DeepSeq.NFData SemVerRange.PrereleaseTag+deriving instance DeepSeq.NFData SemVerRange.PrereleaseTags+deriving instance DeepSeq.NFData SemVerRange.SemVer+deriving instance DeepSeq.NFData SemVerRange.SemVerRange+deriving instance Ghc.Generic Salve.Build+deriving instance Ghc.Generic Salve.Constraint+deriving instance Ghc.Generic Salve.Operator+deriving instance Ghc.Generic Salve.PreRelease+deriving instance Ghc.Generic Salve.Version+deriving instance Ghc.Generic Salve.Wildcard+deriving instance Ghc.Generic SemVerRange.SemVerRange main :: IO () main = Criterion.defaultMain- [ Criterion.bgroup "Data.Version.parseVersion" (map- (\ x -> Criterion.bench x (Criterion.nf (runReadP Version.parseVersion) x))- [ "0.0.0"- , "123.456.789-pre-release-build-metadata"- ])- , Criterion.bgroup "parseVersion" (map- (\ x -> Criterion.bench x (Criterion.nf Salve.parseVersion x))- [ "0.0.0"- , "123.456.789-pre.release+build.metadata"- ])- , Criterion.bgroup "parseConstraint" (map- (\ x -> Criterion.bench x (Criterion.nf Salve.parseConstraint x))- [ ">=0.0.0"- , ">1.2.3 || =1.2.3 >=1.2.3 <1.2.3 || 1.2.3 <=1.2.3 ~1.2.3 ^1.2.3 1.2.3 - 1.2.3"- ])- , Criterion.bgroup "Data.Version.showVersion" (map- (\ x ->- let y = Maybe.fromJust (runReadP Version.parseVersion x)- in Criterion.bench x (Criterion.nf Version.showVersion y))- [ "0.0.0"- , "123.456.789-pre-release-build-metadata"- ])- , Criterion.bgroup "renderVersion" (map- (\ x ->- let y = Salve.unsafeParseVersion x- in Criterion.bench x (Criterion.nf Salve.renderVersion y))- [ "0.0.0"- , "123.456.789-pre.release+build.metadata"- ])- , Criterion.bgroup "renderConstraint" (map- (\ x ->- let y = Salve.unsafeParseConstraint x- in Criterion.bench x (Criterion.nf Salve.renderConstraint y))- [ ">=0.0.0"- , ">1.2.3 || =1.2.3 >=1.2.3 <1.2.3 || 1.2.3 <=1.2.3 ~1.2.3 ^1.2.3"- ])+ [ Criterion.bgroup "version"+ [ Criterion.bgroup "parse"+ [ Criterion.bgroup "simple"+ [ Criterion.bench "base" $ Criterion.nf (runReadP Version.parseVersion) "0.0.0"+ , Criterion.bench "salve" $ Criterion.nf Salve.parseVersion "0.0.0"+ , Criterion.bench "semver" $ Criterion.nf (fromRight . SemVer.fromText) "0.0.0"+ , Criterion.bench "semver-range" $ Criterion.nf (fromRight . SemVerRange.parseSemVer) "0.0.0"+ ]+ , Criterion.bgroup "complex"+ [ Criterion.bench "base" $ Criterion.nf (runReadP Version.parseVersion) "1.22.333-pre-build"+ , Criterion.bench "salve" $ Criterion.nf Salve.parseVersion "1.22.333-pre+build"+ , Criterion.bench "semver" $ Criterion.nf (fromRight . SemVer.fromText) "1.22.333-pre+build"+ , Criterion.bench "semver-range" $ Criterion.nf (fromRight . SemVerRange.parseSemVer) "1.22.333-pre+build"+ ]+ ]+ , Criterion.bgroup "render"+ [ Criterion.bgroup "simple"+ [ let Just v = runReadP Version.parseVersion "0.0.0" in Criterion.bench "base" $ Criterion.nf Version.showVersion v+ , let v = Salve.unsafeParseVersion "0.0.0" in Criterion.bench "salve" $ Criterion.nf Salve.renderVersion v+ , let Right v = SemVer.fromText "0.0.0" in Criterion.bench "semver" $ Criterion.nf SemVer.toText v+ , let Right v = SemVerRange.parseSemVer "0.0.0" in Criterion.bench "semver-range" $ Criterion.nf SemVerRange.renderSV v+ ]+ , Criterion.bgroup "complex"+ [ let Just v = runReadP Version.parseVersion "1.22.333-pre-build" in Criterion.bench "base" $ Criterion.nf Version.showVersion v+ , let v = Salve.unsafeParseVersion "1.22.333-pre+build" in Criterion.bench "salve" $ Criterion.nf Salve.renderVersion v+ , let Right v = SemVer.fromText "1.22.333-pre+build" in Criterion.bench "semver" $ Criterion.nf SemVer.toText v+ , let Right v = SemVerRange.parseSemVer "1.22.333-pre+build" in Criterion.bench "semver-range" $ Criterion.nf SemVerRange.renderSV v+ ]+ ]+ ]+ , Criterion.bgroup "constraint"+ [ Criterion.bgroup "parse"+ [ Criterion.bgroup "simple"+ [ Criterion.bench "salve" $ Criterion.nf Salve.parseConstraint "0.0.0"+ , Criterion.bench "semver-range" $ Criterion.nf (fromRight . SemVerRange.parseSemVerRange) "0.0.0"+ ]+ , Criterion.bgroup "complex"+ [ Criterion.bench "salve" $ Criterion.nf Salve.parseConstraint "<1.2.0 <=1.2.1 || =1.2.2 >=1.2.3 || >1.2.4 1.2.5 || 1.2.6 - 1.2.7 ~1.2.8 || ^1.2.9"+ , Criterion.bench "semver-range" $ Criterion.nf (fromRight . SemVerRange.parseSemVerRange) "<1.2.0 <=1.2.1 || =1.2.2 >=1.2.3 || >1.2.4 1.2.5 || 1.2.6 - 1.2.7 ~1.2.8 || ^1.2.9"+ ]+ ]+ , Criterion.bgroup "render"+ [ Criterion.bgroup "simple"+ [ let c = Salve.unsafeParseConstraint "0.0.0" in Criterion.bench "salve" $ Criterion.nf Salve.renderConstraint c+ ]+ , Criterion.bgroup "complex"+ [ let c = Salve.unsafeParseConstraint "<1.2.0 <=1.2.1 || =1.2.2 >=1.2.3 || >1.2.4 1.2.5 || 1.2.6 - 1.2.7 ~1.2.8 || ^1.2.9" in Criterion.bench "salve" $ Criterion.nf Salve.renderConstraint c+ ]+ ]+ ] ]++fromRight :: Either a b -> Maybe b+fromRight e = case e of+ Left _ -> Nothing+ Right r -> Just r runReadP :: ReadP.ReadP a -> String -> Maybe a runReadP parser string = Maybe.listToMaybe (do
library/Salve.hs view
@@ -38,16 +38,6 @@ -- * Constructors makeVersion, initialVersion,-constraintLT,-constraintLE,-constraintEQ,-constraintGE,-constraintGT,-constraintAnd,-constraintOr,-constraintHyphen,-constraintTilde,-constraintCaret, -- * Parsing parseVersion,@@ -152,28 +142,77 @@ -- >>> parseConstraint "1.2" -- Nothing ----- Wildcards (also known as "x-ranges") are not allowed.+-- Wildcards (also known as "x-ranges") are allowed. The exact character used+-- for the wildcard is not round-tripped. ----- >>> parseConstraint "1.2.x"+-- >>> renderConstraint <$> parseConstraint "1.2.x"+-- Just "1.2.x"+-- >>> renderConstraint <$> parseConstraint "1.2.X"+-- Just "1.2.x"+-- >>> renderConstraint <$> parseConstraint "1.2.*"+-- Just "1.2.x"+--+-- Wildcards can be combined with other constraints.+--+-- >>> renderConstraint <$> parseConstraint "1.2.x 2.3.4"+-- Just "1.2.x 2.3.4"+-- >>> renderConstraint <$> parseConstraint "1.2.x || 2.3.4"+-- Just "1.2.x || 2.3.4"+--+-- Wildcards are allowed at any position.+--+-- >>> renderConstraint <$> parseConstraint "1.2.x"+-- Just "1.2.x"+-- >>> renderConstraint <$> parseConstraint "1.x.x"+-- Just "1.x.x"+-- >>> renderConstraint <$> parseConstraint "x.x.x"+-- Just "x.x.x"+--+-- Non-wildcards cannot come after wildcards.+--+-- >>> parseConstraint "1.x.3" -- Nothing--- >>> parseConstraint "1.2.X"+-- >>> parseConstraint "x.2.3" -- Nothing--- >>> parseConstraint "1.2.*"+-- >>> parseConstraint "x.x.3" -- Nothing+-- >>> parseConstraint "x.2.x"+-- Nothing ----- Extra spaces are not allowed.+-- Wildcards cannot be used with other operators. ----- >>> parseConstraint " 1.2.3 "+-- >>> parseConstraint "<1.2.x" -- Nothing--- >>> parseConstraint "> 1.2.3"+-- >>> parseConstraint "<=1.2.x" -- Nothing--- >>> parseConstraint "1.2.3 - 2.3.4"+-- >>> parseConstraint "=1.2.x" -- Nothing--- >>> parseConstraint "1.2.3 2.3.4"+-- >>> parseConstraint ">=1.2.x" -- Nothing--- >>> parseConstraint "1.2.3 || 2.3.4"+-- >>> parseConstraint ">1.2.x" -- Nothing+-- >>> parseConstraint "~1.2.x"+-- Nothing+-- >>> parseConstraint "^1.2.x"+-- Nothing+-- >>> parseConstraint "1.2.x - 2.3.4"+-- Nothing+-- >>> parseConstraint "1.2.3 - 2.3.x"+-- Nothing --+-- Spaces are allowed in most places. Extra spaces are not round-tripped.+--+-- >>> renderConstraint <$> parseConstraint " 1.2.3 "+-- Just "1.2.3"+-- >>> renderConstraint <$> parseConstraint "> 1.2.3"+-- Just ">1.2.3"+-- >>> renderConstraint <$> parseConstraint "1.2.3 - 2.3.4"+-- Just "1.2.3 - 2.3.4"+-- >>> renderConstraint <$> parseConstraint "1.2.3 2.3.4"+-- Just "1.2.3 2.3.4"+-- >>> renderConstraint <$> parseConstraint "1.2.3 || 2.3.4"+-- Just "1.2.3 || 2.3.4"+-- -- Parentheses are not allowed. Note that combining two constraints with a -- space (and) has higher precedence than combining them with pipes (or). In -- other words, @"a b || c"@ parses as @"(a b) || c"@, not @"a (b || c)"@.@@ -213,7 +252,7 @@ -- >>> renderConstraint <$> parseConstraint "=1.2.3" -- Just "1.2.3" ----- Pre-releases and builds are allowed on any constraints.+-- Pre-releases and builds are allowed on any constraints except wildcards. -- -- >>> renderConstraint <$> parseConstraint "1.2.3-p+b" -- Just "1.2.3-p+b"@@ -226,16 +265,19 @@ -- >>> renderConstraint <$> parseConstraint "^1.2.3-p+b" -- Just "^1.2.3-p+b" --+-- >>> parseConstraint "1.2.x-p+b"+-- Nothing+-- -- These examples show every type of constraint in a single expression. ----- >>> renderConstraint <$> parseConstraint "<1.2.0 <=1.2.1 =1.2.2 >=1.2.3 >1.2.4 1.2.5 1.2.6 - 1.2.7 ~1.2.8 ^1.2.9"--- Just "<1.2.0 <=1.2.1 1.2.2 >=1.2.3 >1.2.4 1.2.5 1.2.6 - 1.2.7 ~1.2.8 ^1.2.9"--- >>> renderConstraint <$> parseConstraint "<1.2.0 <=1.2.1 || =1.2.2 >=1.2.3 || >1.2.4 1.2.5 || 1.2.6 - 1.2.7 ~1.2.8 || ^1.2.9"--- Just "<1.2.0 <=1.2.1 || 1.2.2 >=1.2.3 || >1.2.4 1.2.5 || 1.2.6 - 1.2.7 ~1.2.8 || ^1.2.9"--- >>> renderConstraint <$> parseConstraint "<1.2.0 || <=1.2.1 =1.2.2 || >=1.2.3 >1.2.4 || 1.2.5 1.2.6 - 1.2.7 || ~1.2.8 ^1.2.9"--- Just "<1.2.0 || <=1.2.1 1.2.2 || >=1.2.3 >1.2.4 || 1.2.5 1.2.6 - 1.2.7 || ~1.2.8 ^1.2.9"--- >>> renderConstraint <$> parseConstraint "<1.2.0 || <=1.2.1 || =1.2.2 || >=1.2.3 || >1.2.4 || 1.2.5 || 1.2.6 - 1.2.7 || ~1.2.8 || ^1.2.9"--- Just "<1.2.0 || <=1.2.1 || 1.2.2 || >=1.2.3 || >1.2.4 || 1.2.5 || 1.2.6 - 1.2.7 || ~1.2.8 || ^1.2.9"+-- >>> renderConstraint <$> parseConstraint "<1.2.0 <=1.2.1 =1.2.2 >=1.2.3 >1.2.4 1.2.5 1.2.6 - 1.2.7 ~1.2.8 ^1.2.9 1.2.x"+-- Just "<1.2.0 <=1.2.1 1.2.2 >=1.2.3 >1.2.4 1.2.5 1.2.6 - 1.2.7 ~1.2.8 ^1.2.9 1.2.x"+-- >>> renderConstraint <$> parseConstraint "<1.2.0 <=1.2.1 || =1.2.2 >=1.2.3 || >1.2.4 1.2.5 || 1.2.6 - 1.2.7 ~1.2.8 || ^1.2.9 1.2.x"+-- Just "<1.2.0 <=1.2.1 || 1.2.2 >=1.2.3 || >1.2.4 1.2.5 || 1.2.6 - 1.2.7 ~1.2.8 || ^1.2.9 1.2.x"+-- >>> renderConstraint <$> parseConstraint "<1.2.0 || <=1.2.1 =1.2.2 || >=1.2.3 >1.2.4 || 1.2.5 1.2.6 - 1.2.7 || ~1.2.8 ^1.2.9 || 1.2.x"+-- Just "<1.2.0 || <=1.2.1 1.2.2 || >=1.2.3 >1.2.4 || 1.2.5 1.2.6 - 1.2.7 || ~1.2.8 ^1.2.9 || 1.2.x"+-- >>> renderConstraint <$> parseConstraint "<1.2.0 || <=1.2.1 || =1.2.2 || >=1.2.3 || >1.2.4 || 1.2.5 || 1.2.6 - 1.2.7 || ~1.2.8 || ^1.2.9 || 1.2.x"+-- Just "<1.2.0 || <=1.2.1 || 1.2.2 || >=1.2.3 || >1.2.4 || 1.2.5 || 1.2.6 - 1.2.7 || ~1.2.8 || ^1.2.9 || 1.2.x" -- ** Satisfying constraints -- | Although in general you should use 'satisfies', 'parseVersion', and@@ -385,6 +427,31 @@ -- True -- >>> "0.0.4" ? "^0.0.3" -- False+--+-- - Wildcard:+--+-- >>> "1.1.0" ? "1.2.x"+-- False+-- >>> "1.2.3" ? "1.2.x"+-- True+-- >>> "1.3.0" ? "1.2.x"+-- False+--+-- >>> "0.1.0" ? "1.x.x"+-- False+-- >>> "1.0.0" ? "1.x.x"+-- True+-- >>> "1.2.3" ? "1.x.x"+-- True+-- >>> "2.0.0" ? "1.x.x"+-- False+--+-- >>> "0.0.0" ? "x.x.x"+-- True+-- >>> "1.2.3" ? "x.x.x"+-- True+-- >>> "2.0.0" ? "x.x.x"+-- True ) where import Salve.Internal
library/Salve/Internal.hs view
@@ -3,6 +3,14 @@ -- that thing exported from "Salve". module Salve.Internal where +import qualified Control.Monad as Monad+import qualified Data.Char as Char+import qualified Data.List as List+import qualified Data.Maybe as Maybe+import qualified Data.Ord as Ord+import qualified Text.ParserCombinators.ReadP as ReadP+import qualified Text.Read as Read+ -- $setup -- >>> import Lens.Micro -- >>> import Lens.Micro.Extras@@ -62,9 +70,9 @@ -- Just False instance Ord Version where compare x y = mconcat- [ comparing versionMajor x y- , comparing versionMinor x y- , comparing versionPatch x y+ [ Ord.comparing versionMajor x y+ , Ord.comparing versionMinor x y+ , Ord.comparing versionPatch x y , case both versionPreReleases (x, y) of ([], []) -> EQ ([], _) -> GT@@ -128,6 +136,7 @@ data Constraint = ConstraintOperator Operator Version | ConstraintHyphen Version Version+ | ConstraintWildcard Wildcard | ConstraintAnd Constraint Constraint | ConstraintOr Constraint Constraint deriving (Eq, Show)@@ -155,99 +164,6 @@ initialVersion :: Version initialVersion = makeVersion 0 0 0 [] [] --- | Makes a new constraint that must be less than the version number.------ >>> constraintLT <$> parseVersion "1.2.3"--- Just (ConstraintOperator OperatorLT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))--- >>> parseConstraint "<1.2.3"--- Just (ConstraintOperator OperatorLT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))-constraintLT :: Version -> Constraint-constraintLT v = ConstraintOperator OperatorLT v---- | Makes a new constraint that must be less than or euqal to the version--- number.------ >>> constraintLE <$> parseVersion "1.2.3"--- Just (ConstraintOperator OperatorLE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))--- >>> parseConstraint "<=1.2.3"--- Just (ConstraintOperator OperatorLE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))-constraintLE :: Version -> Constraint-constraintLE v = ConstraintOperator OperatorLE v---- | Makes a new constraint that must be equal to the version number.------ >>> constraintEQ <$> parseVersion "1.2.3"--- Just (ConstraintOperator OperatorEQ (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))--- >>> parseConstraint "=1.2.3"--- Just (ConstraintOperator OperatorEQ (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))-constraintEQ :: Version -> Constraint-constraintEQ v = ConstraintOperator OperatorEQ v---- | Makes a new constraint that must be greater than or equal to the version--- number.------ >>> constraintGE <$> parseVersion "1.2.3"--- Just (ConstraintOperator OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))--- >>> parseConstraint ">=1.2.3"--- Just (ConstraintOperator OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))-constraintGE :: Version -> Constraint-constraintGE v = ConstraintOperator OperatorGE v---- | Makes a new constraint that must be greater than the version number.------ >>> constraintGT <$> parseVersion "1.2.3"--- Just (ConstraintOperator OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))--- >>> parseConstraint ">1.2.3"--- Just (ConstraintOperator OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))-constraintGT :: Version -> Constraint-constraintGT v = ConstraintOperator OperatorGT v---- | Makes a new constraint that must satisfy both constraints.------ >>> constraintAnd <$> (constraintGE <$> parseVersion "1.2.3") <*> (constraintLT <$> parseVersion "2.0.0")--- Just (ConstraintAnd (ConstraintOperator OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintOperator OperatorLT (Version {versionMajor = 2, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})))--- >>> parseConstraint ">=1.2.3 <2.0.0"--- Just (ConstraintAnd (ConstraintOperator OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintOperator OperatorLT (Version {versionMajor = 2, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})))-constraintAnd :: Constraint -> Constraint -> Constraint-constraintAnd l r = ConstraintAnd l r---- | Makes a new constraint that must satisfy either constraint.------ >>> constraintOr <$> (constraintEQ <$> parseVersion "1.2.3") <*> (constraintGT <$> parseVersion "1.2.3")--- Just (ConstraintOr (ConstraintOperator OperatorEQ (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintOperator OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})))--- >>> parseConstraint "=1.2.3 || >1.2.3"--- Just (ConstraintOr (ConstraintOperator OperatorEQ (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintOperator OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})))-constraintOr :: Constraint -> Constraint -> Constraint-constraintOr l r = ConstraintOr l r---- | Makes a new constraint that must be between the versions, inclusive.------ >>> constraintHyphen <$> parseVersion "1.2.3" <*> parseVersion "2.3.4"--- Just (ConstraintHyphen (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}) (Version {versionMajor = 2, versionMinor = 3, versionPatch = 4, versionPreReleases = [], versionBuilds = []}))--- >>> parseConstraint "1.2.3 - 2.3.4"--- Just (ConstraintHyphen (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}) (Version {versionMajor = 2, versionMinor = 3, versionPatch = 4, versionPreReleases = [], versionBuilds = []}))-constraintHyphen :: Version -> Version -> Constraint-constraintHyphen v w = ConstraintHyphen v w---- | Makes a new constraint that allows changes to the patch version number.------ >>> constraintTilde <$> parseVersion "1.2.3"--- Just (ConstraintOperator OperatorTilde (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))--- >>> parseConstraint "~1.2.3"--- Just (ConstraintOperator OperatorTilde (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))-constraintTilde :: Version -> Constraint-constraintTilde v = ConstraintOperator OperatorTilde v---- | Makes a new constraint that allows changes that do not modify the--- left-most non-zero version number.------ >>> constraintCaret <$> parseVersion "1.2.3"--- Just (ConstraintOperator OperatorCaret (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))--- >>> parseConstraint "^1.2.3"--- Just (ConstraintOperator OperatorCaret (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))-constraintCaret :: Version -> Constraint-constraintCaret v = ConstraintOperator OperatorCaret v- -- | 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). --@@ -444,9 +360,13 @@ OperatorGT -> '>' : s OperatorTilde -> '~' : s OperatorCaret -> '^' : s- ConstraintHyphen l r -> join ' ' [renderVersion l, "-", renderVersion r]- ConstraintAnd l r -> join ' ' (map renderConstraint [l, r])- ConstraintOr l r -> join ' ' [renderConstraint l, "||", renderConstraint r]+ ConstraintHyphen l r -> unwords [renderVersion l, "-", renderVersion r]+ ConstraintWildcard w -> case w of+ WildcardMajor -> "x.x.x"+ WildcardMinor m -> show m ++ ".x.x"+ WildcardPatch m n -> List.intercalate "." [show m, show n, "x"]+ ConstraintAnd l r -> unwords (map renderConstraint [l, r])+ ConstraintOr l r -> unwords [renderConstraint l, "||", renderConstraint r] -- | Returns 'True' if the major version number is zero, 'False' otherwise. --@@ -549,6 +469,10 @@ else makeVersion (versionMajor w + 1) 0 0 [] [] in (v >= w) && (v < u) ConstraintHyphen l r -> (l <= v) && (v <= r)+ ConstraintWildcard w -> case w of+ WildcardMajor -> True+ WildcardMinor m -> (makeVersion m 0 0 [] [] <= v) && (v < makeVersion (m + 1) 0 0 [] [])+ WildcardPatch m n -> (makeVersion m n 0 [] [] <= v) && (v < makeVersion m (n + 1) 0 [] []) ConstraintAnd l r -> satisfies v l && satisfies v r ConstraintOr l r -> satisfies v l || satisfies v r @@ -621,266 +545,291 @@ | OperatorCaret deriving (Eq, Show) +data Wildcard+ = WildcardMajor+ | WildcardMinor Word+ | WildcardPatch Word Word+ deriving (Eq, Show)++-- ** Constructors++-- | Makes a new constraint that must be less than the version number.+--+-- >>> constraintLT <$> parseVersion "1.2.3"+-- Just (ConstraintOperator OperatorLT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+-- >>> parseConstraint "<1.2.3"+-- Just (ConstraintOperator OperatorLT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+constraintLT :: Version -> Constraint+constraintLT v = ConstraintOperator OperatorLT v++-- | Makes a new constraint that must be less than or euqal to the version+-- number.+--+-- >>> constraintLE <$> parseVersion "1.2.3"+-- Just (ConstraintOperator OperatorLE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+-- >>> parseConstraint "<=1.2.3"+-- Just (ConstraintOperator OperatorLE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+constraintLE :: Version -> Constraint+constraintLE v = ConstraintOperator OperatorLE v++-- | Makes a new constraint that must be equal to the version number.+--+-- >>> constraintEQ <$> parseVersion "1.2.3"+-- Just (ConstraintOperator OperatorEQ (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+-- >>> parseConstraint "=1.2.3"+-- Just (ConstraintOperator OperatorEQ (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+constraintEQ :: Version -> Constraint+constraintEQ v = ConstraintOperator OperatorEQ v++-- | Makes a new constraint that must be greater than or equal to the version+-- number.+--+-- >>> constraintGE <$> parseVersion "1.2.3"+-- Just (ConstraintOperator OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+-- >>> parseConstraint ">=1.2.3"+-- Just (ConstraintOperator OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+constraintGE :: Version -> Constraint+constraintGE v = ConstraintOperator OperatorGE v++-- | Makes a new constraint that must be greater than the version number.+--+-- >>> constraintGT <$> parseVersion "1.2.3"+-- Just (ConstraintOperator OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+-- >>> parseConstraint ">1.2.3"+-- Just (ConstraintOperator OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+constraintGT :: Version -> Constraint+constraintGT v = ConstraintOperator OperatorGT v++-- | Makes a new constraint that must satisfy both constraints.+--+-- >>> constraintAnd <$> (constraintGE <$> parseVersion "1.2.3") <*> (constraintLT <$> parseVersion "2.0.0")+-- Just (ConstraintAnd (ConstraintOperator OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintOperator OperatorLT (Version {versionMajor = 2, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})))+-- >>> parseConstraint ">=1.2.3 <2.0.0"+-- Just (ConstraintAnd (ConstraintOperator OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintOperator OperatorLT (Version {versionMajor = 2, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})))+constraintAnd :: Constraint -> Constraint -> Constraint+constraintAnd l r = ConstraintAnd l r++-- | Makes a new constraint that must satisfy either constraint.+--+-- >>> constraintOr <$> (constraintEQ <$> parseVersion "1.2.3") <*> (constraintGT <$> parseVersion "1.2.3")+-- Just (ConstraintOr (ConstraintOperator OperatorEQ (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintOperator OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})))+-- >>> parseConstraint "=1.2.3 || >1.2.3"+-- Just (ConstraintOr (ConstraintOperator OperatorEQ (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintOperator OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})))+constraintOr :: Constraint -> Constraint -> Constraint+constraintOr l r = ConstraintOr l r++-- | Makes a new constraint that must be between the versions, inclusive.+--+-- >>> constraintHyphen <$> parseVersion "1.2.3" <*> parseVersion "2.3.4"+-- Just (ConstraintHyphen (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}) (Version {versionMajor = 2, versionMinor = 3, versionPatch = 4, versionPreReleases = [], versionBuilds = []}))+-- >>> parseConstraint "1.2.3 - 2.3.4"+-- Just (ConstraintHyphen (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}) (Version {versionMajor = 2, versionMinor = 3, versionPatch = 4, versionPreReleases = [], versionBuilds = []}))+constraintHyphen :: Version -> Version -> Constraint+constraintHyphen v w = ConstraintHyphen v w++-- | Makes a new constraint that allows changes to the patch version number.+--+-- >>> constraintTilde <$> parseVersion "1.2.3"+-- Just (ConstraintOperator OperatorTilde (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+-- >>> parseConstraint "~1.2.3"+-- Just (ConstraintOperator OperatorTilde (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+constraintTilde :: Version -> Constraint+constraintTilde v = ConstraintOperator OperatorTilde v++-- | Makes a new constraint that allows changes that do not modify the+-- left-most non-zero version number.+--+-- >>> constraintCaret <$> parseVersion "1.2.3"+-- Just (ConstraintOperator OperatorCaret (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+-- >>> parseConstraint "^1.2.3"+-- Just (ConstraintOperator OperatorCaret (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))+constraintCaret :: Version -> Constraint+constraintCaret v = ConstraintOperator OperatorCaret v+ -- ** Parsing -versionP :: Parser Version+versionP :: ReadP.ReadP Version versionP = do major <- numberP- _ <- charP '.'+ Monad.void (ReadP.char '.') minor <- numberP- _ <- charP '.'+ Monad.void (ReadP.char '.') patch <- numberP preReleases <- preReleasesP builds <- buildsP pure (makeVersion major minor patch preReleases builds) -preReleasesP :: Parser [PreRelease]-preReleasesP = optionP [] (do- _ <- charP '-'- sepBy1P (charP '.') preReleaseP)+preReleasesP :: ReadP.ReadP [PreRelease]+preReleasesP = ReadP.option [] (do+ Monad.void (ReadP.char '-')+ ReadP.sepBy1 preReleaseP (ReadP.char '.')) -preReleaseP :: Parser PreRelease-preReleaseP = choiceP preReleaseStringP preReleaseNumberP+preReleaseP :: ReadP.ReadP PreRelease+preReleaseP = preReleaseNumberP ReadP.<++ preReleaseStringP -preReleaseNumberP :: Parser PreRelease+preReleaseNumberP :: ReadP.ReadP PreRelease preReleaseNumberP = do n <- numberP pure (PreReleaseNumeric n) -preReleaseStringP :: Parser PreRelease+preReleaseStringP :: ReadP.ReadP PreRelease preReleaseStringP = do- s <- someP (satisfyP isIdentifier)- if all isAsciiDigit s- then failP+ s <- ReadP.munch1 isIdentifier+ if all Char.isDigit s+ then ReadP.pfail else pure (PreReleaseTextual s) -buildsP :: Parser [Build]-buildsP = optionP [] (do- _ <- charP '+'- sepBy1P (charP '.') buildP)+buildsP :: ReadP.ReadP [Build]+buildsP = ReadP.option [] (do+ Monad.void (ReadP.char '+')+ ReadP.sepBy1 buildP (ReadP.char '.')) -buildP :: Parser Build+buildP :: ReadP.ReadP Build buildP = do- b <- someP (satisfyP isIdentifier)+ b <- ReadP.munch1 isIdentifier pure (Build b) -numberP :: Parser Word-numberP = choiceP zeroP nonZeroP+numberP :: ReadP.ReadP Word+numberP = nonZeroP ReadP.<++ zeroP -zeroP :: Parser Word+zeroP :: ReadP.ReadP Word zeroP = do- _ <- charP '0'+ Monad.void (ReadP.char '0') pure 0 -nonZeroP :: Parser Word+nonZeroP :: ReadP.ReadP Word nonZeroP = do- x <- satisfyP isAsciiDigitNonZero- ys <- manyP (satisfyP isAsciiDigit)- pure (read (x : ys))+ x <- ReadP.satisfy isAsciiDigitNonZero+ ys <- ReadP.munch Char.isDigit+ case Read.readMaybe (x : ys) of+ Nothing -> ReadP.pfail+ Just n -> pure n -constraintsP :: Parser Constraint+constraintsP :: ReadP.ReadP Constraint constraintsP = do- cs <- sepBy1P orP constraintP+ spacesP+ cs <- ReadP.sepBy1 constraintP orP+ spacesP pure (foldr1 constraintOr cs) -constraintP :: Parser Constraint+constraintP :: ReadP.ReadP Constraint constraintP = do- cs <- sepBy1P spaceP simpleP+ cs <- ReadP.sepBy1 simpleP spaces1P pure (foldr1 constraintAnd cs) -hyphenatedP :: Parser Constraint+hyphenatedP :: ReadP.ReadP Constraint hyphenatedP = do v <- versionP- _ <- hyphenP+ hyphenP w <- versionP pure (constraintHyphen v w) -simpleP :: Parser Constraint-simpleP = oneOfP [hyphenatedP, caretP, tildeP, primitiveP]+simpleP :: ReadP.ReadP Constraint+simpleP = ReadP.choice [hyphenatedP, wildcardConstraintP, primitiveP] -caretP :: Parser Constraint-caretP = do- _ <- charP '^'- v <- versionP- pure (constraintCaret v)+wildcardConstraintP :: ReadP.ReadP Constraint+wildcardConstraintP = do+ w <- wildcardP+ pure (ConstraintWildcard w) -tildeP :: Parser Constraint-tildeP = do- _ <- charP '~'- v <- versionP- pure (constraintTilde v)+wildcardP :: ReadP.ReadP Wildcard+wildcardP = ReadP.choice [wildcardPatchP, wildcardMinorP, wildcardMajorP] -primitiveP :: Parser Constraint+wildcardPatchP :: ReadP.ReadP Wildcard+wildcardPatchP = do+ m <- numberP+ Monad.void (ReadP.char '.')+ n <- numberP+ Monad.void (ReadP.char '.')+ Monad.void (ReadP.satisfy isWildcard)+ pure (WildcardPatch m n)++wildcardMinorP :: ReadP.ReadP Wildcard+wildcardMinorP = do+ m <- numberP+ Monad.void (ReadP.char '.')+ Monad.void (ReadP.satisfy isWildcard)+ Monad.void (ReadP.char '.')+ Monad.void (ReadP.satisfy isWildcard)+ pure (WildcardMinor m)++wildcardMajorP :: ReadP.ReadP Wildcard+wildcardMajorP = do+ Monad.void (ReadP.satisfy isWildcard)+ Monad.void (ReadP.char '.')+ Monad.void (ReadP.satisfy isWildcard)+ Monad.void (ReadP.char '.')+ Monad.void (ReadP.satisfy isWildcard)+ pure WildcardMajor++primitiveP :: ReadP.ReadP Constraint primitiveP = do o <- operatorP+ spacesP v <- versionP pure (ConstraintOperator o v) -operatorP :: Parser Operator-operatorP = oneOfP [leP, geP, ltP, gtP, eqP, pure OperatorEQ]--leP :: Parser Operator-leP = do- _ <- stringP "<="- pure OperatorLE--geP :: Parser Operator-geP = do- _ <- stringP ">="- pure OperatorGE--ltP :: Parser Operator-ltP = do- _ <- charP '<'- pure OperatorLT--gtP :: Parser Operator-gtP = do- _ <- charP '>'- pure OperatorGT+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+ ] -eqP :: Parser Operator-eqP = do- _ <- charP '='- pure OperatorEQ+hyphenP :: ReadP.ReadP ()+hyphenP = do+ spaces1P+ Monad.void (ReadP.char '-')+ spaces1P -hyphenP :: Parser String-hyphenP = stringP " - "+orP :: ReadP.ReadP ()+orP = do+ spaces1P+ Monad.void (ReadP.string "||")+ spaces1P -orP :: Parser String-orP = stringP " || "+spaces1P :: ReadP.ReadP ()+spaces1P = Monad.void (ReadP.munch1 (== ' ')) -spaceP :: Parser Char-spaceP = charP ' '+spacesP :: ReadP.ReadP ()+spacesP = Monad.void (ReadP.munch (== ' ')) -- *** Helpers -parse :: Parser a -> String -> Maybe a-parse p s = safeHead (do- (x, "") <- runParser p s- pure x)--newtype Parser a = Parser { runParser :: String -> [(a, String)] }--instance Functor Parser where- fmap f p = Parser (\s -> do- (x, t) <- runParser p s- pure (f x, t))--instance Applicative Parser where- pure x = Parser (\ s -> pure (x, s))-- p <*> q = Parser (\ s -> do- (f, t) <- runParser p s- (x, u) <- runParser q t- pure (f x, u))--instance Monad Parser where- fail x = Parser (\ _ -> fail x)-- p >>= f = Parser (\ s -> do- (x, t) <- runParser p s- runParser (f x) t)--charP :: Char -> Parser Char-charP c = satisfyP (\ d -> d == c)--choiceP :: Parser a -> Parser a -> Parser a-choiceP p q = Parser (\ s -> case runParser p s of- [] -> runParser q s- xs -> xs)--failP :: Parser a-failP = fail undefined--getP :: Parser Char-getP = Parser (\ s -> case s of- "" -> []- c : t -> pure (c, t))--manyP :: Parser a -> Parser [a]-manyP p = choiceP (someP p) (pure [])--oneOfP :: [Parser a] -> Parser a-oneOfP ps = foldr choiceP failP ps--optionP :: a -> Parser a -> Parser a-optionP x p = choiceP p (pure x)--satisfyP :: (Char -> Bool) -> Parser Char-satisfyP f = do- c <- getP- if f c then pure c else failP--sepByP :: Parser b -> Parser a -> Parser [a]-sepByP q p = choiceP (sepBy1P q p) (pure [])--sepBy1P :: Parser b -> Parser a -> Parser [a]-sepBy1P q p = do- x <- p- xs <- optionP [] (do- _ <- q- sepBy1P q p)- pure (x : xs)--someP :: Parser a -> Parser [a]-someP p = do- x <- p- xs <- manyP p- pure (x : xs)--stringP :: String -> Parser String-stringP s = case s of- "" -> pure s- c : t -> do- _ <- charP c- _ <- stringP t- pure s+parse :: ReadP.ReadP a -> String -> Maybe a+parse p s =+ let p' = ReadP.readP_to_S p+ in Maybe.listToMaybe (do+ (x, "") <- p' s+ pure x) -- ** Rendering renderPreReleases :: [PreRelease] -> String renderPreReleases ps = if null ps then ""- else '-' : join '.' (map renderPreRelease ps)+ else '-' : List.intercalate "." (map renderPreRelease ps) renderBuilds :: [Build] -> String renderBuilds bs = if null bs then ""- else '+' : join '.' (map renderBuild bs)+ else '+' : List.intercalate "." (map renderBuild bs) -- ** Helpers both :: (a -> b) -> (a, a) -> (b, b) both f (x, y) = (f x, f y) -comparing :: Ord b => (a -> b) -> a -> a -> Ordering-comparing f x y = compare (f x) (f y)--isAsciiAlpha :: Char -> Bool-isAsciiAlpha c = (isAsciiAlphaUpper c) || (isAsciiAlphaLower c)--isAsciiAlphaLower :: Char -> Bool-isAsciiAlphaLower c = ('a' <= c) && (c <= 'z')--isAsciiAlphaUpper :: Char -> Bool-isAsciiAlphaUpper c = ('A' <= c) && (c <= 'Z')--isAsciiDigit :: Char -> Bool-isAsciiDigit c = ('0' <= c) && (c <= '9')- isAsciiDigitNonZero :: Char -> Bool-isAsciiDigitNonZero c = isAsciiDigit c && (c /= '0')+isAsciiDigitNonZero c = Char.isDigit c && (c /= '0') isIdentifier :: Char -> Bool-isIdentifier c = (c == '-') || isAsciiDigit c || isAsciiAlpha c--join :: Char -> [String] -> String-join c ss = case ss of- [] -> ""- s : ts -> mconcat (s : map (\ t -> c : t) ts)+isIdentifier c = (Char.isAscii c && Char.isAlphaNum c) || (c == '-') -safeHead :: [a] -> Maybe a-safeHead xs = case xs of- [] -> Nothing- x : _ -> Just x+isWildcard :: Char -> Bool+isWildcard c = (c == 'x') || (c == '*') || (c == 'X')
salve.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack name: salve-version: 0.0.3+version: 0.0.4 synopsis: Semantic version numbers and constraints. description: Salve provides semantic version numbers and constraints. category: Distribution@@ -57,4 +57,6 @@ , criterion >=1.1.0 && <1.3 , deepseq >=1.4.1 && <1.5 , salve+ , semver >=0.3.3 && <0.4+ , semver-range >=0.2.2 && <0.3 default-language: Haskell2010