packages feed

salve 1.0.11 → 2.0.0.10

raw patch · 12 files changed

Files

+ CHANGELOG.md view
@@ -0,0 +1,4 @@+# Change log++Salve follows the [Package Versioning Policy](https://pvp.haskell.org).+You can find release notes [on GitHub](https://github.com/tfausak/salve/releases).
− LICENSE.markdown
@@ -1,21 +0,0 @@-MIT License--Copyright (c) 2021 Taylor Fausak--Permission is hereby granted, free of charge, to any person obtaining a copy-of this software and associated documentation files (the "Software"), to deal-in the Software without restriction, including without limitation the rights-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell-copies of the Software, and to permit persons to whom the Software is-furnished to do so, subject to the following conditions:--The above copyright notice and this permission notice shall be included in all-copies or substantial portions of the Software.--THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-SOFTWARE.
+ LICENSE.txt view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2026 Taylor Fausak++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
− README.markdown
@@ -1,10 +0,0 @@-# Salve--[![CI](https://github.com/tfausak/salve/workflows/CI/badge.svg)](https://github.com/tfausak/salve/actions/new)-[![Hackage](https://img.shields.io/hackage/v/salve)](https://hackage.haskell.org/package/salve)-[![Stackage](https://www.stackage.org/package/salve/badge/nightly?label=stackage)](https://www.stackage.org/package/salve)--Salve provides semantic version numbers and constraints for Haskell.--Salve has extensive documentation available on Hackage:-<https://hackage.haskell.org/package/salve>.
+ README.md view
@@ -0,0 +1,9 @@+# Salve++[![CI](https://github.com/tfausak/salve/actions/workflows/ci.yml/badge.svg)](https://github.com/tfausak/salve/actions/workflows/ci.yml)+[![Hackage](https://badgen.net/hackage/v/salve)](https://hackage.haskell.org/package/salve)++Salve provides semantic version numbers and constraints for Haskell.++Salve has extensive documentation available on Hackage:+<https://hackage.haskell.org/package/salve>.
salve.cabal view
@@ -1,16 +1,17 @@-cabal-version: >= 1.10-+cabal-version: 2.2 name: salve-version: 1.0.11-+version: 2.0.0.10 synopsis: Semantic version numbers and constraints. description:   Salve provides semantic version (SemVer) numbers and constraints (ranges).  build-type: Simple category: Distribution-extra-source-files: README.markdown-license-file: LICENSE.markdown+extra-doc-files:+  CHANGELOG.md+  README.md++license-file: LICENSE.txt license: MIT maintainer: Taylor Fausak @@ -18,32 +19,49 @@   location: https://github.com/tfausak/salve   type: git -library-  build-depends:-    base >= 4.13.0 && < 4.16+flag pedantic+  default: False+  manual: True++common library+  build-depends: base ^>=4.20.0.0 || ^>=4.21.0.0 || ^>=4.22.0.0   default-language: Haskell2010-  exposed-modules:-    Salve-    Salve.Internal   ghc-options:     -Weverything+    -Wno-all-missed-specialisations     -Wno-implicit-prelude     -Wno-missing-deriving-strategies     -Wno-missing-exported-signatures+    -Wno-missing-kind-signatures+    -Wno-missing-safe-haskell-mode+    -Wno-prepositive-qualified-module     -Wno-safe-  hs-source-dirs: src/lib -  if impl(ghc >= 8.10)-    ghc-options:-      -Wno-missing-safe-haskell-mode-      -Wno-prepositive-qualified-module+  if flag(pedantic)+    ghc-options: -Werror -test-suite test+common executable+  import: library+  build-depends: salve+  ghc-options:+    -rtsopts+    -threaded+    -Wno-unused-packages++library+  import: library+  -- cabal-gild: discover source/library+  exposed-modules:+    Salve+    Salve.Internal++  hs-source-dirs: source/library++test-suite salve-test-suite+  import: executable   build-depends:-    base -any-    , HUnit >= 1.6.1 && < 1.7-    , salve -any-  default-language: Haskell2010-  hs-source-dirs: src/test+    HUnit ^>=1.6.2.0++  hs-source-dirs: source/test-suite   main-is: Main.hs   type: exitcode-stdio-1.0
+ source/library/Salve.hs view
@@ -0,0 +1,621 @@+-- | 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://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.+    --+    -- >>> import Salve+    --+    -- This module provides lenses for modifying versions. If you want to modify+    -- 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.+    --+    -- >>> renderVersion <$> parseVersion "1.2.3"+    -- Just "1.2.3"+    --+    -- The 'Constraint' data type allows you to specify version constraints. Use+    -- 'parseConstraint' to make constraints and 'renderConstraint' to convert them+    -- into strings.+    --+    -- >>> renderConstraint <$> parseConstraint ">1.2.0"+    -- Just ">1.2.0"+    --+    -- Use 'satisfiesConstraint' to see if a version satisfiesConstraint a+    -- constraint.+    --+    -- >>> satisfiesConstraint <$> parseConstraint ">1.2.0" <*> parseVersion "1.2.3"+    -- Just True++    -- * Cheat sheet++    -- | If you're coming from Cabal, you might not be familiar with npm's version+    -- range syntax. This table shows you how npm version ranges map to Cabal's+    -- version constraints.+    --+    -- > Salve           | Cabal              | Notes+    -- > -----           | -----              | -----+    -- > <1.2.3          | <1.2.3             | -+    -- > <=1.2.3         | <=1.2.3            | -+    -- > =1.2.3          | ==1.2.3            | equals sign is optional+    -- > >=1.2.3         | >=1.2.3            | -+    -- > >1.2.3          | >1.2.3             | -+    -- > 1.2.3 || >1.2.3 | ==1.2.3 || >1.2.3  | lower precedence than and+    -- > >=1.2.3 <2.0.0  | >=1.2.3 && <2.0.0  | higher precedence than or+    -- > 1.2.3 - 2.3.4   | >=1.2.3 && <=2.3.4 | inclusive ranges+    -- > 1.2.x           | ==1.2.*            | can use X or * instead of x+    -- > 1.x.x           | ==1.*              | -+    -- > x.x.x           | ==*                | same as -any+    -- > ~1.2.3          | ^>=1.2.3           | same as >=1.2.3 && <1.3.0+    -- > ^1.2.3          | >=1.2.3 && <2      | -+    -- > ^0.2.3          | >=0.2.3 && <0.3    | -+    -- > ^0.0.3          | >=0.0.3 && <0.0.4  | -++    -- * Rationale++    -- ** The PVP++    -- | 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.+    -- 2.  A spec for constraining the versions of your dependencies, which+    --     incldues how version ranges look.+    -- 3.  A prescription for how to constrain the versions of your dependencies,+    --     which includes how the ranges of your dependencies should be.+    --+    -- By comparison, Semantic Versioning only deals with the first thing. npm's+    -- version ranges only deal with the second thing. This module deals with the+    -- first and second things but leaves the third up to you.+    --+    -- 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+    -- [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.+    --+    -- Moving on to the second point, why should we use npm's version ranges+    -- instead of the PVP's? This is a less clear cut. The two syntaxes are broadly+    -- compatible. Really the only gains here are compatibility with a widely-used+    -- syntax and convenient shorthand for common constraints (like hyphens+    -- @1.2.3 - 2.3.4@, tildes @~1.2.3@, and carets @^1.2.3@).++    -- ** Other modules++    -- | There are already a few modules that provide version numbers. Why do we+    -- need another one? Let's take a look at the options.+    --+    -- -   [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+    --         parsed.+    --     -   Allows any number of components, from zero to inifinity.+    --     -   Deprecated tags on versions.+    --     -   Does not support build metadata on versions.+    --     -   Does not support constraints.+    --+    -- -   [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+    --         version type.+    --     -   Depends on the @array@, @binary@, @bytestring@, @containers@,+    --         @deepseq@, @directory@, @filepath@, @pretty@, @process@, @time@, and+    --         @unix@ packages.+    --+    -- -   [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.+    --+    -- -   [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+    --         @unordered-containers@ packages.+    --     -   Module name collides with the @semver@ package.+    --     -   Supports constraints, but does not provide a way to render them.+    --+    -- -   [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@+    --         packages.+    --     -   Intentially allows weird versions.+    --     -   Does not support constraints.+    --+    -- By comparison, this module:+    --+    -- -   Does not expose constructors. Any version you create can be rendered and+    --     parsed without issue.+    -- -   Requires exactly three components. You won't have to wonder if version+    --     @1.2.0@ is greater than @1.2@.+    -- -   Allows pre-release identifiers on versions. Go ahead and release version+    --     @1.0.0-alpha@ for early adopters.+    -- -   Allows build metadata on versions. Show when a release was made with+    --     versions like @1.0.0+2001-02-03@.+    -- -   Supports version constraints. Just like versions, rendering and parsing+    --     constraints is no problem.+    -- -   Only depends on the @base@ package. You can use all the functionality+    --     without installing any other packages.+    -- -   Has a unique module name. You won't have to use the @PackageImports@+    --     extension simply to deal with version numbers.++    -- * Types+    Salve.Version,+    Salve.PreRelease,+    Salve.Build,+    Salve.Constraint,++    -- * Constructors+    Salve.makeVersion,+    Salve.initialVersion,++    -- * Parsing+    Salve.parseVersion,+    Salve.parsePreRelease,+    Salve.parseBuild,+    Salve.parseConstraint,++    -- ** Unsafe++    -- | These functions can be used to unsafely parse strings. Instead of+    -- returning 'Nothing', they raise an exception. Only use these if you are sure+    -- the string can be successfully parsed!+    Salve.unsafeParseVersion,+    Salve.unsafeParsePreRelease,+    Salve.unsafeParseBuild,+    Salve.unsafeParseConstraint,++    -- * Rendering+    Salve.renderVersion,+    Salve.renderPreRelease,+    Salve.renderBuild,+    Salve.renderConstraint,++    -- * Predicates+    Salve.isUnstable,+    Salve.isStable,++    -- * Conversions+    Salve.fromBaseVersion,+    Salve.toBaseVersion,++    -- * Helpers+    Salve.bumpMajor,+    Salve.bumpMinor,+    Salve.bumpPatch,+    Salve.satisfiesConstraint,++    -- * Lenses++    -- | These lenses can be used to access and modify specific parts of a+    -- 'Version'.+    --+    -- 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' 'Version' a@, which you may already be familiar with.+    Salve.majorLens,+    Salve.minorLens,+    Salve.patchLens,+    Salve.preReleasesLens,+    Salve.buildsLens,++    -- * Examples++    -- | These examples are provided to showcase functionality and explain weird+    -- behavior. If something isn't clear, please open a pull request adding an+    -- example!++    -- ** Versions++    -- | Leading zeros are not allowed.+    --+    -- >>> parseVersion "01.0.0"+    -- Nothing+    -- >>> parseVersion "0.01.0"+    -- Nothing+    -- >>> parseVersion "0.0.01"+    -- Nothing+    --+    -- Negative numbers are not allowed.+    --+    -- >>> parseVersion "-1.0.0"+    -- Nothing+    -- >>> parseVersion "0.-1.0"+    -- Nothing+    -- >>> parseVersion "0.0.-1"+    -- Nothing+    --+    -- Non-digits are not allowed.+    --+    -- >>> parseVersion "a.0.0"+    -- Nothing+    -- >>> parseVersion "0.a.0"+    -- Nothing+    -- >>> parseVersion "0.0.a"+    -- Nothing+    --+    -- Partial version numbers are not allowed.+    --+    -- >>> parseVersion "0.0"+    -- Nothing+    --+    -- Extra version numbers are not allowed.+    --+    -- >>> parseVersion "0.0.0.0"+    -- Nothing+    --+    -- Spaces are allowed+    --+    -- >>> parseVersion " 0.0.0"+    -- Just (Version {versionMajor = 0, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})+    -- >>> parseVersion "0.0.0 "+    -- Just (Version {versionMajor = 0, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})+    --+    -- Interior spaces are not allowed.+    --+    -- >>> parseVersion "0 .0.0"+    -- 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.+    --+    -- >>> parseConstraint "1.2"+    -- Nothing+    --+    -- Wildcards (also known as "x-ranges") are allowed. The exact character used+    -- for the wildcard is not round-tripped.+    --+    -- >>> 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"+    --+    -- An optional equals sign can be included with wildcard constraints.+    --+    -- >>> renderConstraint <$> parseConstraint "=1.2.x"+    -- 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 "x.2.3"+    -- Nothing+    -- >>> parseConstraint "x.x.3"+    -- Nothing+    -- >>> parseConstraint "x.2.x"+    -- Nothing+    --+    -- Wildcards cannot be used with other operators.+    --+    -- >>> parseConstraint "<1.2.x"+    -- Nothing+    -- >>> parseConstraint "<=1.2.x"+    -- Nothing+    -- >>> parseConstraint ">=1.2.x"+    -- Nothing+    -- >>> 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)"@.+    --+    -- >>> parseConstraint "(1.2.3)"+    -- Nothing+    -- >>> parseConstraint "(1.2.3 || >1.2.3) <1.3.0"+    -- Nothing+    -- >>> parseConstraint "(>1.2.3 <1.3.0) || 1.2.3"+    -- Nothing+    --+    -- Most constraints can be round-tripped through parsing and rendering.+    --+    -- >>> renderConstraint <$> parseConstraint "<1.2.3"+    -- Just "<1.2.3"+    -- >>> renderConstraint <$> parseConstraint "<=1.2.3"+    -- Just "<=1.2.3"+    -- >>> renderConstraint <$> parseConstraint "1.2.3"+    -- Just "1.2.3"+    -- >>> 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"+    -- Just "~1.2.3"+    -- >>> renderConstraint <$> parseConstraint "^1.2.3"+    -- Just "^1.2.3"+    -- >>> renderConstraint <$> parseConstraint ">1.2.3 <2.0.0"+    -- Just ">1.2.3 <2.0.0"+    -- >>> renderConstraint <$> parseConstraint "1.2.3 || >1.2.3"+    -- Just "1.2.3 || >1.2.3"+    --+    -- Explicit equal signs do not get round-tripped.+    --+    -- >>> renderConstraint <$> parseConstraint "=1.2.3"+    -- Just "1.2.3"+    --+    -- Pre-releases and builds are allowed on any constraints except wildcards.+    --+    -- >>> renderConstraint <$> parseConstraint "1.2.3-p+b"+    -- Just "1.2.3-p+b"+    -- >>> renderConstraint <$> parseConstraint ">1.2.3-p+b"+    -- Just ">1.2.3-p+b"+    -- >>> renderConstraint <$> parseConstraint "1.2.3-p+b - 2.3.4-p+b"+    -- Just "1.2.3-p+b - 2.3.4-p+b"+    -- >>> renderConstraint <$> parseConstraint "~1.2.3-p+b"+    -- Just "~1.2.3-p+b"+    -- >>> 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 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 'satisfiesConstraint', 'parseVersion',+    -- and 'parseConstraint', doing that here makes it hard to tell what the+    -- examples are doing. An operator makes things clearer.+    --+    -- >>> satisfiesConstraint <$> parseConstraint "=1.2.3" <*> parseVersion "1.2.3"+    -- Just True+    -- >>> let version ? constraint = satisfiesConstraint (unsafeParseConstraint constraint) (unsafeParseVersion version)+    -- >>> "1.2.3" ? "=1.2.3"+    -- True+    --+    -- -   Less than:+    --+    --     >>> "1.2.2" ? "<1.2.3"+    --     True+    --     >>> "1.2.3" ? "<1.2.3"+    --     False+    --     >>> "1.2.4" ? "<1.2.3"+    --     False+    --     >>> "1.2.3-pre" ? "<1.2.3"+    --     True+    --+    -- -   Less than or equal to:+    --+    --     >>> "1.2.2" ? "<=1.2.3"+    --     True+    --     >>> "1.2.3" ? "<=1.2.3"+    --     True+    --     >>> "1.2.4" ? "<=1.2.3"+    --     False+    --+    -- -   Equal to:+    --+    --     >>> "1.2.2" ? "=1.2.3"+    --     False+    --     >>> "1.2.3" ? "=1.2.3"+    --     True+    --     >>> "1.2.4" ? "=1.2.3"+    --     False+    --     >>> "1.2.3-pre" ? "=1.2.3"+    --     False+    --     >>> "1.2.3+build" ? "=1.2.3"+    --     True+    --+    -- -   Greater than or equal to:+    --+    --     >>> "1.2.2" ? ">=1.2.3"+    --     False+    --     >>> "1.2.3" ? ">=1.2.3"+    --     True+    --     >>> "1.2.4" ? ">=1.2.3"+    --     True+    --+    -- -   Greater than:+    --+    --     >>> "1.2.2" ? ">1.2.3"+    --     False+    --     >>> "1.2.3" ? ">1.2.3"+    --     False+    --     >>> "1.2.4" ? ">1.2.3"+    --     True+    --     >>> "1.2.4-pre" ? ">1.2.3"+    --     True+    --+    --     >>> "1.2.4" ? ">1.2.3-pre"+    --     True+    --+    -- -   And:+    --+    --     >>> "1.2.3" ? ">1.2.3 <1.2.5"+    --     False+    --     >>> "1.2.4" ? ">1.2.3 <1.2.5"+    --     True+    --     >>> "1.2.5" ? ">1.2.3 <1.2.5"+    --     False+    --+    -- -   Or:+    --+    --     >>> "1.2.2" ? "1.2.3 || 1.2.4"+    --     False+    --     >>> "1.2.3" ? "1.2.3 || 1.2.4"+    --     True+    --     >>> "1.2.4" ? "1.2.3 || 1.2.4"+    --     True+    --     >>> "1.2.5" ? "1.2.3 || 1.2.4"+    --     False+    --+    -- -   And & or:+    --+    --     >>> "1.2.2" ? "1.2.2 || >1.2.3 <1.3.0"+    --     True+    --     >>> "1.2.3" ? "1.2.2 || >1.2.3 <1.3.0"+    --     False+    --     >>> "1.2.4" ? "1.2.2 || >1.2.3 <1.3.0"+    --     True+    --     >>> "1.3.0" ? "1.2.2 || >1.2.3 <1.3.0"+    --     False+    --+    -- -   Hyphen:+    --+    --     >>> "1.2.2" ? "1.2.3 - 1.2.4"+    --     False+    --     >>> "1.2.3" ? "1.2.3 - 1.2.4"+    --     True+    --     >>> "1.2.4" ? "1.2.3 - 1.2.4"+    --     True+    --     >>> "1.2.5" ? "1.2.3 - 1.2.4"+    --     False+    --+    -- -   Tilde:+    --+    --     >>> "1.2.2" ? "~1.2.3"+    --     False+    --     >>> "1.2.3" ? "~1.2.3"+    --     True+    --     >>> "1.2.4" ? "~1.2.3"+    --     True+    --     >>> "1.3.0" ? "~1.2.3"+    --     False+    --+    -- -   Caret:+    --+    --     >>> "1.2.2" ? "^1.2.3"+    --     False+    --     >>> "1.2.3" ? "^1.2.3"+    --     True+    --     >>> "1.2.4" ? "^1.2.3"+    --     True+    --     >>> "1.3.0" ? "^1.2.3"+    --     True+    --     >>> "2.0.0" ? "^1.2.3"+    --     False+    --+    --     >>> "0.2.2" ? "^0.2.3"+    --     False+    --     >>> "0.2.3" ? "^0.2.3"+    --     True+    --     >>> "0.2.4" ? "^0.2.3"+    --     True+    --     >>> "0.3.0" ? "^0.2.3"+    --     False+    --+    --     >>> "0.0.2" ? "^0.0.3"+    --     False+    --     >>> "0.0.3" ? "^0.0.3"+    --     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 qualified Salve.Internal as Salve++-- $setup+-- >>> import Control.Applicative+-- >>> import Salve
+ source/library/Salve/Internal.hs view
@@ -0,0 +1,1012 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}++-- | WARNING: This module should be considered private! If you find yourself+-- wanting to import something from this module, please open an issue to get+-- that thing exported from "Salve".+module Salve.Internal+  ( Version (..),+    PreRelease (..),+    Build (..),+    Constraint (..),+    makeVersion,+    initialVersion,+    parseVersion,+    parsePreRelease,+    parseBuild,+    parseConstraint,+    unsafeParseVersion,+    unsafeParsePreRelease,+    unsafeParseBuild,+    unsafeParseConstraint,+    renderVersion,+    renderPreRelease,+    renderBuild,+    renderConstraint,+    isUnstable,+    isStable,+    fromBaseVersion,+    toBaseVersion,+    bumpMajor,+    bumpMinor,+    bumpPatch,+    satisfiesConstraint,+    majorLens,+    minorLens,+    patchLens,+    preReleasesLens,+    buildsLens,+    Operator (..),+    Wildcard (..),+    constraintLT,+    constraintLE,+    constraintEQ,+    constraintGE,+    constraintGT,+    constraintAnd,+    constraintOr,+    constraintHyphen,+    constraintTilde,+    constraintCaret,+  )+where++import qualified Control.Monad as Monad+import qualified Data.Char as Char+import qualified Data.Data as Data+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.Version as Version+import qualified Data.Word as Word+import qualified GHC.Generics as Generics+import qualified Text.ParserCombinators.ReadP as ReadP++-- $setup+--+-- >>> import Control.Applicative (Const(..))+-- >>> let view lens record = getConst (lens Const record)+--+-- >>> import Data.Functor.Identity (Identity(..))+-- >>> let set lens field record = runIdentity (lens (const (Identity field)) record)+--+-- >>> import Control.Applicative ((<$>), (<*>))++-- * Public++-- | A semantic version number. Versions have five parts:+--+-- 1. 'majorLens': The major version number.+-- 2. 'minorLens': The minor version number.+-- 3. 'patchLens': The patch version number.+-- 4. 'preReleasesLens': A list of pre-release identifiers.+-- 5. 'buildsLens': A list of build metadata.+--+-- Use 'parseVersion' to create versions.+data Version = Version+  { versionMajor :: Word.Word64,+    versionMinor :: Word.Word64,+    versionPatch :: Word.Word64,+    versionPreReleases :: [PreRelease],+    versionBuilds :: [Build]+  }+  deriving (Data.Data, Eq, Generics.Generic, Read, Show)++-- | 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"+-- Just LT+-- >>> compare <$> parseVersion "1.2.3" <*> parseVersion "1.3.0"+-- Just LT+-- >>> compare <$> parseVersion "1.2.3" <*> parseVersion "1.2.4"+-- Just LT+--+-- Numbers are compared numerically, not alphabetically.+--+-- >>> compare <$> parseVersion "0.0.9" <*> parseVersion "0.0.10"+-- Just LT+--+-- If all the numbers are the same, the pre-releases are compared.+--+-- >>> compare <$> parseVersion "1.2.3-a" <*> parseVersion "1.2.3-b"+-- Just LT+--+-- A version with a pre-release is always less than a version without one as+-- long as the other parts are the same.+--+-- >>> compare <$> parseVersion "1.2.3-pre" <*> parseVersion "1.2.3"+-- Just LT+-- >>> compare <$> parseVersion "1.2.4-pre" <*> parseVersion "1.2.3"+-- Just GT+--+-- Builds are not considered when comparing versions.+--+-- >>> compare <$> parseVersion "1.2.3+a" <*> parseVersion "1.2.3+b"+-- Just EQ+-- >>> (==) <$> parseVersion "1.2.3+a" <*> parseVersion "1.2.3+b"+-- Just False+instance Ord Version where+  compare x y =+    Monoid.mconcat+      [ Ord.comparing versionMajor x y,+        Ord.comparing versionMinor x y,+        Ord.comparing versionPatch x y,+        case both versionPreReleases (x, y) of+          ([], []) -> EQ+          ([], _) -> GT+          (_, []) -> LT+          (p, q) -> compare p q+      ]++-- | Pre-release information attached to a version. These can either be numeric+-- or textual. They must not be empty.+--+-- - Numeric: Can be any non-negative integer. Cannot have leading zeros.+--+-- - Textual: Can be any string of ASCII digits, letters, or hyphens. Cannot be+--   all digits, as that would be numeric.+--+-- In general, pre-releases must match the regular expression+-- @\/^[-0-9A-Za-z]+$\/@.+--+-- Use 'parsePreRelease' to create pre-releases.+data PreRelease+  = PreReleaseNumeric Word.Word64+  | PreReleaseTextual String+  deriving (Data.Data, Eq, Generics.Generic, Read, Show)++-- | Numeric pre-releases are always less than textual pre-releases.+--+-- >>> compare <$> parsePreRelease "1" <*> parsePreRelease "a"+-- Just LT+--+-- Numeric pre-releases are compared numerically.+--+-- >>> compare <$> parsePreRelease "9" <*> parsePreRelease "10"+-- Just LT+--+-- Textual pre-releases are compared alphabetically.+--+-- >>> compare <$> parsePreRelease "p10" <*> parsePreRelease "p9"+-- Just LT+instance Ord PreRelease where+  compare x y = case (x, y) of+    (PreReleaseNumeric n, PreReleaseNumeric m) -> compare n m+    (PreReleaseNumeric _, PreReleaseTextual _) -> LT+    (PreReleaseTextual _, PreReleaseNumeric _) -> GT+    (PreReleaseTextual s, PreReleaseTextual t) -> compare s t++-- | Build metadata attached to a version. These are similar to+-- 'PreRelease's with some key differences:+--+-- 1. There is no such thing as numeric builds. Even though builds can look+--    like numbers, all builds are textual.+-- 2. As a result, builds that look numeric are allowed to have leading zeros.+-- 3. Builds cannot be compared. That is, they do not have an 'Ord' instance.+--+-- Use 'parseBuild' to create builds.+newtype Build = Build String+  deriving (Data.Data, Eq, Generics.Generic, Read, Show)++-- | Constrains allowable version numbers.+--+-- Use 'parseConstraint' to create constraints and 'satisfiesConstraint' to see+-- if a version number satisfies a constraint.+data Constraint+  = ConstraintOperator Operator Version+  | ConstraintHyphen Version Version+  | ConstraintWildcard Wildcard+  | ConstraintAnd Constraint Constraint+  | ConstraintOr Constraint Constraint+  deriving (Data.Data, Eq, Generics.Generic, Ord, Read, Show)++-- | Makes a new version number.+--+-- >>> 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.Word64 ->+  Word.Word64 ->+  Word.Word64 ->+  [PreRelease] ->+  [Build] ->+  Version+makeVersion major minor patch preReleases builds =+  Version+    { versionMajor = major,+      versionMinor = minor,+      versionPatch = patch,+      versionPreReleases = preReleases,+      versionBuilds = builds+    }++-- | The initial version number for development.+--+-- >>> initialVersion+-- Version {versionMajor = 0, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []}+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).+--+-- >>> 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"]})+--+-- Returns 'Nothing' if the parse fails.+--+-- >>> parseVersion "wrong"+-- Nothing+--+-- Whitespace is allowed.+--+-- >>> parseVersion " 1.2.3 "+-- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})+parseVersion :: String -> Maybe Version+parseVersion =+  parse+    ( do+        ReadP.skipSpaces+        version <- versionP+        ReadP.skipSpaces+        pure version+    )++-- | Attempts to parse a pre-release.+--+-- >>> parsePreRelease "pre"+-- Just (PreReleaseTextual "pre")+-- >>> parsePreRelease "1"+-- Just (PreReleaseNumeric 1)+--+-- Returns 'Nothing' if the parse fails.+--+-- >>> parsePreRelease "wrong!"+-- Nothing+--+-- Numeric pre-releases cannot contain leading zeros.+--+-- >>> parsePreRelease "01"+-- Nothing+parsePreRelease :: String -> Maybe PreRelease+parsePreRelease = parse preReleaseP++-- | Attempts to parse a build.+--+-- >>> parseBuild "build"+-- Just (Build "build")+-- >>> parseBuild "1"+-- Just (Build "1")+--+-- Returns 'Nothing' if the parse fails.+--+-- >>> parseBuild "wrong!"+-- Nothing+--+-- Unlike pre-releases, numeric builds can have leading zeros.+--+-- >>> parseBuild "01"+-- Just (Build "01")+parseBuild :: String -> Maybe Build+parseBuild = parse buildP++-- | 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 = []}))+--+-- Returns 'Nothing' if the parse fails.+--+-- >>> 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 = parse constraintsP++-- | Parses a version.+--+-- >>> unsafeParseVersion "1.2.3-p.4+b.5"+-- Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [PreReleaseTextual "p",PreReleaseNumeric 4], versionBuilds = [Build "b",Build "5"]}+--+-- Raises an exception if the parse fails.+--+-- >>> unsafeParseVersion "wrong"+-- *** Exception: unsafeParseVersion: invalid version: "wrong"+-- ...+--+-- See 'parseVersion' for a safe version of this function.+unsafeParseVersion :: String -> Version+unsafeParseVersion s = case parseVersion s of+  Nothing -> error ("unsafeParseVersion: invalid version: " <> show s)+  Just v -> v++-- | Parses a pre-release.+--+-- >>> unsafeParsePreRelease "pre"+-- PreReleaseTextual "pre"+--+-- Raises an exception if the parse fails.+--+-- >>> unsafeParsePreRelease "wrong!"+-- *** Exception: unsafeParsePreRelease: invalid pre-release: "wrong!"+-- ...+--+-- See 'parsePreRelease' for a safe version of this function.+unsafeParsePreRelease :: String -> PreRelease+unsafeParsePreRelease s = case parsePreRelease s of+  Nothing -> error ("unsafeParsePreRelease: invalid pre-release: " <> show s)+  Just p -> p++-- | Parses a build.+--+-- >>> unsafeParseBuild "build"+-- Build "build"+--+-- Raises an exception if the parse fails.+--+-- >>> unsafeParseBuild "wrong!"+-- Build "*** Exception: unsafeParseBuild: invalid build: "wrong!"+-- ...+--+-- See 'parseBuild' for a safe version of this function.+unsafeParseBuild :: String -> Build+unsafeParseBuild s = case parseBuild s of+  Nothing -> error ("unsafeParseBuild: invalid build: " <> show s)+  Just b -> b++-- | Parses a constraint.+--+-- >>> unsafeParseConstraint ">1.2.3"+-- ConstraintOperator OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})+--+-- Raises an exception if the parse fails.+--+-- >>> unsafeParseConstraint "wrong"+-- *** Exception: unsafeParseConstraint: invalid constraint: "wrong"+-- ...+--+-- See 'parseConstraint' for a safe version of this function.+unsafeParseConstraint :: String -> Constraint+unsafeParseConstraint s = case parseConstraint s of+  Nothing -> error ("unsafeParseConstraint: invalid constraint: " <> show s)+  Just c -> c++-- | Renders a version.+--+-- >>> renderVersion <$> parseVersion "1.2.3-p.4+b.5"+-- Just "1.2.3-p.4+b.5"+renderVersion :: Version -> String+renderVersion v =+  concat+    [ show (versionMajor v),+      ".",+      show (versionMinor v),+      ".",+      show (versionPatch v),+      renderPreReleases (versionPreReleases v),+      renderBuilds (versionBuilds v)+    ]++-- | Renders a pre-release.+--+-- >>> renderPreRelease <$> parsePreRelease "pre"+-- Just "pre"+-- >>> renderPreRelease <$> parsePreRelease "1"+-- Just "1"+renderPreRelease :: PreRelease -> String+renderPreRelease p = case p of+  PreReleaseNumeric n -> show n+  PreReleaseTextual s -> s++-- | Renders a build.+--+-- >>> renderBuild <$> parseBuild "build"+-- Just "build"+-- >>> renderBuild <$> parseBuild "1"+-- Just "1"+renderBuild :: Build -> String+renderBuild (Build b) = b++-- | Renders a constraint.+--+-- >>> renderConstraint <$> parseConstraint ">1.2.3"+-- Just ">1.2.3"+--+-- Parsing and rendering a constraint doesn't always return what you started+-- with.+--+-- >>> renderConstraint <$> parseConstraint "=1.2.3"+-- Just "1.2.3"+renderConstraint :: Constraint -> String+renderConstraint c = case c of+  ConstraintOperator o v ->+    let s = renderVersion v+     in case o of+          OperatorLT -> '<' : s+          OperatorLE -> '<' : '=' : s+          OperatorEQ -> s+          OperatorGE -> '>' : '=' : s+          OperatorGT -> '>' : s+          OperatorTilde -> '~' : s+          OperatorCaret -> '^' : s+  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 (fmap renderConstraint [l, r])+  ConstraintOr l r -> unwords [renderConstraint l, "||", renderConstraint r]++-- | Returns 'True' if the major version number is zero, 'False' otherwise.+--+-- >>> isUnstable <$> parseVersion "0.1.2"+-- Just True+-- >>> isUnstable <$> parseVersion "1.0.0"+-- Just False+isUnstable :: Version -> Bool+isUnstable v = versionMajor v == 0++-- | Returns 'True' if the major version number is not zero, 'False' otherwise.+--+-- >>> isStable <$> parseVersion "1.0.0"+-- Just True+-- >>> isStable <$> parseVersion "0.1.2"+-- Just False+isStable :: Version -> Bool+isStable v = not (isUnstable v)++-- | Converts from a 'Version.Version' from the @base@ package.+--+-- >>> renderVersion . fromBaseVersion $ Version.makeVersion [1, 2, 3]+-- "1.2.3"+--+-- Missing version components are set to zero.+--+-- >>> renderVersion . fromBaseVersion $ Version.makeVersion []+-- "0.0.0"+-- >>> renderVersion . fromBaseVersion $ Version.makeVersion [1]+-- "1.0.0"+-- >>> renderVersion . fromBaseVersion $ Version.makeVersion [1, 2]+-- "1.2.0"+--+-- Extra version components are ignored.+--+-- >>> renderVersion . fromBaseVersion $ Version.makeVersion [1, 2, 3, 4]+-- "1.2.3"+--+-- Tags are ignored.+--+-- >>> renderVersion . fromBaseVersion $ Version.Version [] ["ignored"]+-- "0.0.0"+fromBaseVersion :: Version.Version -> Version+fromBaseVersion v = case Version.versionBranch v of+  (m : n : p : _) -> mkV (fromIntegral m) (fromIntegral n) (fromIntegral p)+  (m : n : _) -> mkV (fromIntegral m) (fromIntegral n) 0+  (m : _) -> mkV (fromIntegral m) 0 0+  _ -> mkV 0 0 0++-- | Converts to a 'Version.Version' from the @base@ package.+--+-- >>> toBaseVersion <$> parseVersion "1.2.3"+-- Just (Version {versionBranch = [1,2,3], versionTags = []})+--+-- Pre-releases and builds are converted to tags.+--+-- >>> toBaseVersion <$> parseVersion "1.2.3-pre+build"+-- Just (Version {versionBranch = [1,2,3], versionTags = ["pre","build"]})+toBaseVersion :: Version -> Version.Version+toBaseVersion v =+  Version.Version+    (fmap fromIntegral [versionMajor v, versionMinor v, versionPatch v])+    ( mconcat+        [ fmap renderPreRelease (versionPreReleases v),+          fmap renderBuild (versionBuilds v)+        ]+    )++-- | Increments the major version number.+--+-- >>> bumpMajor <$> parseVersion "0.0.0"+-- Just (Version {versionMajor = 1, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})+--+-- The minor and patch numbers are reset to zero.+--+-- >>> bumpMajor <$> parseVersion "1.2.3"+-- Just (Version {versionMajor = 2, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})+--+-- The pre-releases and builds are removed.+--+-- >>> bumpMajor <$> parseVersion "0.0.0-pre+build"+-- Just (Version {versionMajor = 1, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})+--+-- Consider using 'majorLens' if you want to arbitrarily change the major+-- number, or if you don't want the other parts of the version to change.+bumpMajor :: Version -> Version+bumpMajor v = makeVersion (versionMajor v + 1) 0 0 [] []++-- | Increments the minor version number.+--+-- >>> bumpMinor <$> parseVersion "0.0.0"+-- Just (Version {versionMajor = 0, versionMinor = 1, versionPatch = 0, versionPreReleases = [], versionBuilds = []})+--+-- The patch number is reset to zero.+--+-- >>> bumpMinor <$> parseVersion "1.2.3"+-- Just (Version {versionMajor = 1, versionMinor = 3, versionPatch = 0, versionPreReleases = [], versionBuilds = []})+--+-- The pre-releases and builds are removed.+--+-- >>> bumpMinor <$> parseVersion "0.0.0-pre+build"+-- Just (Version {versionMajor = 0, versionMinor = 1, versionPatch = 0, versionPreReleases = [], versionBuilds = []})+--+-- Consider using 'minorLens' if you want to arbitrarily change the minor+-- number, or if you don't want the other parts of the version to change.+bumpMinor :: Version -> Version+bumpMinor v = makeVersion (versionMajor v) (versionMinor v + 1) 0 [] []++-- | Increments the patch number.+--+-- >>> bumpPatch <$> parseVersion "0.0.0"+-- Just (Version {versionMajor = 0, versionMinor = 0, versionPatch = 1, versionPreReleases = [], versionBuilds = []})+--+-- The major and minor numbers are not changed.+--+-- >>> bumpPatch <$> parseVersion "1.2.3"+-- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 4, versionPreReleases = [], versionBuilds = []})+--+-- The pre-releases and builds are removed.+--+-- >>> bumpPatch <$> parseVersion "0.0.0-pre+build"+-- Just (Version {versionMajor = 0, versionMinor = 0, versionPatch = 1, versionPreReleases = [], versionBuilds = []})+--+-- Consider using 'patchLens' if you want to arbitrarily change the patch+-- number, or if you don't want the other parts of the version to change.+bumpPatch :: Version -> Version+bumpPatch v =+  makeVersion (versionMajor v) (versionMinor v) (versionPatch v + 1) [] []++-- | Returns 'True' if the version satisfies the constraint, 'False' otherwise.+--+-- >>> satisfiesConstraint <$> parseConstraint ">1.2.0" <*> parseVersion "1.2.3"+-- Just True+satisfiesConstraint :: Constraint -> Version -> Bool+satisfiesConstraint c = satisfiesSC (toSC c)++-- | Focuses on the major version number.+--+-- >>> view majorLens <$> parseVersion "1.2.3-pre.4+build.5"+-- Just 1+-- >>> set majorLens 4 <$> parseVersion "1.2.3"+-- Just (Version {versionMajor = 4, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})+majorLens ::+  (Functor f) => (Word.Word64 -> f Word.Word64) -> Version -> f Version+majorLens f v = fmap (\m -> v {versionMajor = m}) (f (versionMajor v))++-- | Focuses on the minor version number.+--+-- >>> view minorLens <$> parseVersion "1.2.3-pre.4+build.5"+-- Just 2+-- >>> set minorLens 4 <$> parseVersion "1.2.3"+-- Just (Version {versionMajor = 1, versionMinor = 4, versionPatch = 3, versionPreReleases = [], versionBuilds = []})+minorLens ::+  (Functor f) => (Word.Word64 -> f Word.Word64) -> Version -> f Version+minorLens f v = fmap (\n -> v {versionMinor = n}) (f (versionMinor v))++-- | Focuses on the patch version number.+--+-- >>> view patchLens <$> parseVersion "1.2.3-pre.4+build.5"+-- Just 3+-- >>> set patchLens 4 <$> parseVersion "1.2.3"+-- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 4, versionPreReleases = [], versionBuilds = []})+patchLens ::+  (Functor f) => (Word.Word64 -> f Word.Word64) -> Version -> f Version+patchLens f v = fmap (\p -> v {versionPatch = p}) (f (versionPatch v))++-- | Focuses on the pre-release identifiers.+--+-- >>> view preReleasesLens <$> parseVersion "1.2.3-pre.4+build.5"+-- Just [PreReleaseTextual "pre",PreReleaseNumeric 4]+-- >>> set preReleasesLens [] <$> parseVersion "1.2.3-pre"+-- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})+preReleasesLens ::+  (Functor f) => ([PreRelease] -> f [PreRelease]) -> Version -> f Version+preReleasesLens f v =+  fmap (\ps -> v {versionPreReleases = ps}) (f (versionPreReleases v))++-- | Focuses on the build metadata.+--+-- >>> view buildsLens <$> parseVersion "1.2.3-pre.4+build.5"+-- Just [Build "build",Build "5"]+-- >>> set buildsLens [] <$> parseVersion "1.2.3+build"+-- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})+buildsLens :: (Functor f) => ([Build] -> f [Build]) -> Version -> f Version+buildsLens f v = fmap (\bs -> v {versionBuilds = bs}) (f (versionBuilds v))++-- * Private++-- ** Types++data Operator+  = OperatorLT+  | OperatorLE+  | OperatorEQ+  | OperatorGE+  | OperatorGT+  | OperatorTilde+  | OperatorCaret+  deriving (Data.Data, Eq, Generics.Generic, Ord, Read, Show)++data Wildcard+  = WildcardMajor+  | WildcardMinor Word.Word64+  | WildcardPatch Word.Word64 Word.Word64+  deriving (Data.Data, Eq, Generics.Generic, Ord, Read, 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 = ConstraintOperator OperatorLT++-- | 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 = ConstraintOperator OperatorLE++-- | 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 = ConstraintOperator OperatorEQ++-- | 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 = ConstraintOperator OperatorGE++-- | 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 = ConstraintOperator OperatorGT++-- | 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 = ConstraintAnd++-- | 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 = ConstraintOr++-- | 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 = ConstraintHyphen++-- | 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 = ConstraintOperator OperatorTilde++-- | 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 = ConstraintOperator OperatorCaret++-- ** Parsing++versionP :: ReadP.ReadP Version+versionP = do+  major <- numberP+  Monad.void (ReadP.char '.')+  minor <- numberP+  Monad.void (ReadP.char '.')+  patch <- numberP+  preReleases <- preReleasesP+  makeVersion major minor patch preReleases <$> buildsP++preReleasesP :: ReadP.ReadP [PreRelease]+preReleasesP =+  ReadP.option+    []+    ( do+        Monad.void (ReadP.char '-')+        ReadP.sepBy1 preReleaseP (ReadP.char '.')+    )++preReleaseP :: ReadP.ReadP PreRelease+preReleaseP = preReleaseNumberP ReadP.<++ preReleaseStringP++preReleaseNumberP :: ReadP.ReadP PreRelease+preReleaseNumberP = PreReleaseNumeric <$> numberP++preReleaseStringP :: ReadP.ReadP PreRelease+preReleaseStringP = do+  s <- ReadP.munch1 isIdentifier+  if all Char.isDigit s then ReadP.pfail else pure (PreReleaseTextual s)++buildsP :: ReadP.ReadP [Build]+buildsP =+  ReadP.option+    []+    ( do+        Monad.void (ReadP.char '+')+        ReadP.sepBy1 buildP (ReadP.char '.')+    )++buildP :: ReadP.ReadP Build+buildP = do+  b <- ReadP.munch1 isIdentifier+  pure (Build b)++numberP :: ReadP.ReadP Word.Word64+numberP = zeroP ReadP.<++ nonZeroP++zeroP :: ReadP.ReadP Word.Word64+zeroP = do+  Monad.void (ReadP.char '0')+  pure 0++nonZeroP :: ReadP.ReadP Word.Word64+nonZeroP = do+  x <- ReadP.satisfy isAsciiDigitNonZero+  ys <- ReadP.munch Char.isDigit+  maybe ReadP.pfail pure . toWord64 . stringToIntegral $ x : ys++constraintsP :: ReadP.ReadP Constraint+constraintsP = do+  spacesP+  cs <- ReadP.sepBy1 constraintP orP+  spacesP+  pure (foldr1 constraintOr cs)++constraintP :: ReadP.ReadP Constraint+constraintP = do+  cs <- ReadP.sepBy1 simpleP spaces1P+  pure (foldr1 constraintAnd cs)++hyphenatedP :: ReadP.ReadP Constraint+hyphenatedP = do+  v <- versionP+  hyphenP+  constraintHyphen v <$> versionP++simpleP :: ReadP.ReadP Constraint+simpleP = ReadP.choice [hyphenatedP, wildcardConstraintP, primitiveP]++wildcardConstraintP :: ReadP.ReadP Constraint+wildcardConstraintP = do+  ReadP.optional (ReadP.char '=')+  ConstraintWildcard <$> wildcardP++wildcardP :: ReadP.ReadP Wildcard+wildcardP = ReadP.choice [wildcardPatchP, wildcardMinorP, wildcardMajorP]++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+  ConstraintOperator o <$> versionP++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+    ]++hyphenP :: ReadP.ReadP ()+hyphenP = do+  spaces1P+  Monad.void (ReadP.char '-')+  spaces1P++orP :: ReadP.ReadP ()+orP = do+  spaces1P+  Monad.void (ReadP.string "||")+  spaces1P++spaces1P :: ReadP.ReadP ()+spaces1P = Monad.void (ReadP.munch1 (== ' '))++spacesP :: ReadP.ReadP ()+spacesP = Monad.void (ReadP.munch (== ' '))++-- ** Rendering++renderPreReleases :: [PreRelease] -> String+renderPreReleases ps =+  if null ps then "" else '-' : List.intercalate "." (fmap renderPreRelease ps)++renderBuilds :: [Build] -> String+renderBuilds bs =+  if null bs then "" else '+' : List.intercalate "." (fmap renderBuild bs)++-- ** Helpers++both :: (a -> b) -> (a, a) -> (b, b)+both f (x, y) = (f x, f y)++isAsciiDigitNonZero :: Char -> Bool+isAsciiDigitNonZero c = Char.isDigit c && (c /= '0')++isIdentifier :: Char -> Bool+isIdentifier c = (Char.isAscii c && Char.isAlphaNum c) || (c == '-')++isWildcard :: Char -> Bool+isWildcard c = (c == 'x') || (c == '*') || (c == 'X')++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+        )++stringToIntegral :: (Integral a) => String -> a+stringToIntegral =+  foldl (\n d -> (n * 10) + (fromIntegral (fromEnum d) - 48)) 0++toWord64 :: Integer -> Maybe Word.Word64+toWord64 n+  | n < 0 = Nothing+  | n > fromIntegral (maxBound :: Word.Word64) = Nothing+  | otherwise = 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+-- 'Constraint's.+data SimpleConstraint+  = SCLT Version+  | SCEQ Version+  | SCGT Version+  | SCAnd SimpleConstraint SimpleConstraint+  | SCOr SimpleConstraint SimpleConstraint+  deriving (Data.Data, Eq, Generics.Generic, Ord, Read, Show)++mkV :: Word.Word64 -> Word.Word64 -> Word.Word64 -> Version+mkV m n p = makeVersion m n p [] []++{- hlint ignore satisfiesSC "Redundant compare" -}+satisfiesSC :: SimpleConstraint -> Version -> Bool+satisfiesSC c v = case c of+  SCLT u -> v < u+  -- This uses `compare` rather than `==` to ignore build metadata.+  SCEQ u -> compare v u == EQ+  SCGT u -> v > u+  SCAnd l r -> satisfiesSC l v && satisfiesSC r v+  SCOr l r -> satisfiesSC l v || satisfiesSC r v++scLE :: Version -> SimpleConstraint+scLE v = SCOr (SCLT v) (SCEQ v)++scGE :: Version -> SimpleConstraint+scGE v = SCOr (SCGT v) (SCEQ v)++toSC :: Constraint -> SimpleConstraint+toSC c = case c of+  ConstraintOperator o v -> case o of+    OperatorLT -> SCLT v+    OperatorLE -> scLE v+    OperatorEQ -> SCEQ v+    OperatorGE -> scGE v+    OperatorGT -> SCGT v+    OperatorTilde ->+      SCAnd (scGE v) (SCLT (mkV (versionMajor v) (versionMinor v + 1) 0))+    OperatorCaret ->+      SCAnd+        (scGE v)+        ( SCLT+            ( case (versionMajor v, versionMinor v, versionPatch v) of+                (0, 0, p) -> mkV 0 0 (p + 1)+                (0, n, _) -> mkV 0 (n + 1) 0+                (m, _, _) -> mkV (m + 1) 0 0+            )+        )+  ConstraintHyphen l h -> SCAnd (scGE l) (scLE h)+  ConstraintWildcard w -> case w of+    WildcardMajor -> scGE initialVersion+    WildcardMinor m -> SCAnd (scGE (mkV m 0 0)) (SCLT (mkV (m + 1) 0 0))+    WildcardPatch m n -> SCAnd (scGE (mkV m n 0)) (SCLT (mkV m (n + 1) 0))+  ConstraintAnd l r -> SCAnd (toSC l) (toSC r)+  ConstraintOr l r -> SCOr (toSC l) (toSC r)
+ source/test-suite/Main.hs view
@@ -0,0 +1,360 @@+import qualified Control.Monad as Monad+import qualified Salve+import qualified System.Exit as Exit+import qualified Test.HUnit as Test++main :: IO ()+main = do+  counts <-+    Test.runTestTT $+      Test.TestList+        [ (compare <$> Salve.parseVersion "1.2.3" <*> Salve.parseVersion "2.0.0")+            Test.~?= Just LT,+          (compare <$> Salve.parseVersion "1.2.3" <*> Salve.parseVersion "1.3.0")+            Test.~?= Just LT,+          (compare <$> Salve.parseVersion "1.2.3" <*> Salve.parseVersion "1.2.4")+            Test.~?= Just LT,+          (compare <$> Salve.parseVersion "0.0.9" <*> Salve.parseVersion "0.0.10")+            Test.~?= Just LT,+          ( compare+              <$> Salve.parseVersion "1.2.3-a"+              <*> Salve.parseVersion+                "1.2.3-b"+          )+            Test.~?= Just LT,+          ( compare+              <$> Salve.parseVersion "1.2.3-pre"+              <*> Salve.parseVersion+                "1.2.3"+          )+            Test.~?= Just LT,+          ( compare+              <$> Salve.parseVersion "1.2.4-pre"+              <*> Salve.parseVersion+                "1.2.3"+          )+            Test.~?= Just GT,+          ( compare+              <$> Salve.parseVersion "1.2.3+a"+              <*> Salve.parseVersion+                "1.2.3+b"+          )+            Test.~?= Just EQ,+          ((==) <$> Salve.parseVersion "1.2.3+a" <*> Salve.parseVersion "1.2.3+b")+            Test.~?= Just False,+          (compare <$> Salve.parsePreRelease "1" <*> Salve.parsePreRelease "a")+            Test.~?= Just LT,+          (compare <$> Salve.parsePreRelease "9" <*> Salve.parsePreRelease "10")+            Test.~?= Just LT,+          (compare <$> Salve.parsePreRelease "p10" <*> Salve.parsePreRelease "p9")+            Test.~?= Just LT,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "<1.2.3"+              <*> Salve.parseVersion "1.2.2"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "<1.2.3"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "<1.2.3"+              <*> Salve.parseVersion "1.2.4"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "<1.2.3"+              <*> Salve.parseVersion "1.2.3-pre"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "<=1.2.3"+              <*> Salve.parseVersion "1.2.2"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "<=1.2.3"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "<=1.2.3"+              <*> Salve.parseVersion "1.2.4"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "=1.2.3"+              <*> Salve.parseVersion "1.2.2"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "=1.2.3"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "=1.2.3"+              <*> Salve.parseVersion "1.2.4"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "=1.2.3"+              <*> Salve.parseVersion "1.2.3-pre"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "=1.2.3"+              <*> Salve.parseVersion "1.2.3+build"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint ">=1.2.3"+              <*> Salve.parseVersion "1.2.2"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint ">=1.2.3"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint ">=1.2.3"+              <*> Salve.parseVersion "1.2.4"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint ">1.2.3"+              <*> Salve.parseVersion "1.2.2"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint ">1.2.3"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint ">1.2.3"+              <*> Salve.parseVersion "1.2.4"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint ">1.2.3"+              <*> Salve.parseVersion "1.2.4-pre"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint ">1.2.3-pre"+              <*> Salve.parseVersion "1.2.4"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint ">1.2.3 <1.2.5"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint ">1.2.3 <1.2.5"+              <*> Salve.parseVersion "1.2.4"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint ">1.2.3 <1.2.5"+              <*> Salve.parseVersion "1.2.5"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.3 || 1.2.4"+              <*> Salve.parseVersion "1.2.2"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.3 || 1.2.4"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.3 || 1.2.4"+              <*> Salve.parseVersion "1.2.4"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.3 || 1.2.4"+              <*> Salve.parseVersion "1.2.5"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.2 || >1.2.3 <1.3.0"+              <*> Salve.parseVersion "1.2.2"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.2 || >1.2.3 <1.3.0"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.2 || >1.2.3 <1.3.0"+              <*> Salve.parseVersion "1.2.4"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.2 || >1.2.3 <1.3.0"+              <*> Salve.parseVersion "1.3.0"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.3 - 1.2.4"+              <*> Salve.parseVersion "1.2.2"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.3 - 1.2.4"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.3 - 1.2.4"+              <*> Salve.parseVersion "1.2.4"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.3 - 1.2.4"+              <*> Salve.parseVersion "1.2.5"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "~1.2.3"+              <*> Salve.parseVersion "1.2.2"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "~1.2.3"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "~1.2.3"+              <*> Salve.parseVersion "1.2.4"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "~1.2.3"+              <*> Salve.parseVersion "1.3.0"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "^1.2.3"+              <*> Salve.parseVersion "1.2.2"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "^1.2.3"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "^1.2.3"+              <*> Salve.parseVersion "1.2.4"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "^1.2.3"+              <*> Salve.parseVersion "1.3.0"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "^1.2.3"+              <*> Salve.parseVersion "2.0.0"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "^0.2.3"+              <*> Salve.parseVersion "0.2.2"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "^0.2.3"+              <*> Salve.parseVersion "0.2.3"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "^0.2.3"+              <*> Salve.parseVersion "0.2.4"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "^0.2.3"+              <*> Salve.parseVersion "0.3.0"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "^0.0.3"+              <*> Salve.parseVersion "0.0.2"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "^0.0.3"+              <*> Salve.parseVersion "0.0.3"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "^0.0.3"+              <*> Salve.parseVersion "0.0.4"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.x"+              <*> Salve.parseVersion "1.1.0"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.x"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.2.x"+              <*> Salve.parseVersion "1.3.0"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.x.x"+              <*> Salve.parseVersion "0.1.0"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.x.x"+              <*> Salve.parseVersion "1.0.0"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.x.x"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "1.x.x"+              <*> Salve.parseVersion "2.0.0"+          )+            Test.~?= Just False,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "x.x.x"+              <*> Salve.parseVersion "0.0.0"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "x.x.x"+              <*> Salve.parseVersion "1.2.3"+          )+            Test.~?= Just True,+          ( Salve.satisfiesConstraint+              <$> Salve.parseConstraint "x.x.x"+              <*> Salve.parseVersion "2.0.0"+          )+            Test.~?= Just True+        ]++  let hasErrors = Test.errors counts /= 0+      hasFailures = Test.failures counts /= 0+  Monad.when (hasErrors || hasFailures) Exit.exitFailure
− src/lib/Salve.hs
@@ -1,611 +0,0 @@--- | 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://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.------ >>> import Salve------ This module provides lenses for modifying versions. If you want to modify--- 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.------ >>> renderVersion <$> parseVersion "1.2.3"--- Just "1.2.3"------ The 'Constraint' data type allows you to specify version constraints. Use--- 'parseConstraint' to make constraints and 'renderConstraint' to convert them--- into strings.------ >>> renderConstraint <$> parseConstraint ">1.2.0"--- Just ">1.2.0"------ Use 'satisfiesConstraint' to see if a version satisfiesConstraint a--- constraint.------ >>> satisfiesConstraint <$> parseConstraint ">1.2.0" <*> parseVersion "1.2.3"--- Just True---- * Cheat sheet--- | If you're coming from Cabal, you might not be familiar with npm's version--- range syntax. This table shows you how npm version ranges map to Cabal's--- version constraints.------ > Salve           | Cabal              | Notes--- > -----           | -----              | -------- > <1.2.3          | <1.2.3             | ---- > <=1.2.3         | <=1.2.3            | ---- > =1.2.3          | ==1.2.3            | equals sign is optional--- > >=1.2.3         | >=1.2.3            | ---- > >1.2.3          | >1.2.3             | ---- > 1.2.3 || >1.2.3 | ==1.2.3 || >1.2.3  | lower precedence than and--- > >=1.2.3 <2.0.0  | >=1.2.3 && <2.0.0  | higher precedence than or--- > 1.2.3 - 2.3.4   | >=1.2.3 && <=2.3.4 | inclusive ranges--- > 1.2.x           | ==1.2.*            | can use X or * instead of x--- > 1.x.x           | ==1.*              | ---- > x.x.x           | ==*                | same as -any--- > ~1.2.3          | ^>=1.2.3           | same as >=1.2.3 && <1.3.0--- > ^1.2.3          | >=1.2.3 && <2      | ---- > ^0.2.3          | >=0.2.3 && <0.3    | ---- > ^0.0.3          | >=0.0.3 && <0.0.4  | ----- * Rationale---- ** The PVP--- | 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.--- 2.  A spec for constraining the versions of your dependencies, which---     incldues how version ranges look.--- 3.  A prescription for how to constrain the versions of your dependencies,---     which includes how the ranges of your dependencies should be.------ By comparison, Semantic Versioning only deals with the first thing. npm's--- version ranges only deal with the second thing. This module deals with the--- first and second things but leaves the third up to you.------ 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--- [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.------ Moving on to the second point, why should we use npm's version ranges--- instead of the PVP's? This is a less clear cut. The two syntaxes are broadly--- compatible. Really the only gains here are compatibility with a widely-used--- syntax and convenient shorthand for common constraints (like hyphens--- @1.2.3 - 2.3.4@, tildes @~1.2.3@, and carets @^1.2.3@).---- ** Other modules--- | There are already a few modules that provide version numbers. Why do we--- need another one? Let's take a look at the options.------ -   [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---         parsed.---     -   Allows any number of components, from zero to inifinity.---     -   Deprecated tags on versions.---     -   Does not support build metadata on versions.---     -   Does not support constraints.------ -   [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---         version type.---     -   Depends on the @array@, @binary@, @bytestring@, @containers@,---         @deepseq@, @directory@, @filepath@, @pretty@, @process@, @time@, and---         @unix@ packages.------ -   [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.------ -   [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---         @unordered-containers@ packages.---     -   Module name collides with the @semver@ package.---     -   Supports constraints, but does not provide a way to render them.------ -   [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@---         packages.---     -   Intentially allows weird versions.---     -   Does not support constraints.------ By comparison, this module:------ -   Does not expose constructors. Any version you create can be rendered and---     parsed without issue.--- -   Requires exactly three components. You won't have to wonder if version---     @1.2.0@ is greater than @1.2@.--- -   Allows pre-release identifiers on versions. Go ahead and release version---     @1.0.0-alpha@ for early adopters.--- -   Allows build metadata on versions. Show when a release was made with---     versions like @1.0.0+2001-02-03@.--- -   Supports version constraints. Just like versions, rendering and parsing---     constraints is no problem.--- -   Only depends on the @base@ package. You can use all the functionality---     without installing any other packages.--- -   Has a unique module name. You won't have to use the @PackageImports@---     extension simply to deal with version numbers.---- * Types-Salve.Version,-Salve.PreRelease,-Salve.Build,-Salve.Constraint,---- * Constructors-Salve.makeVersion,-Salve.initialVersion,---- * Parsing-Salve.parseVersion,-Salve.parsePreRelease,-Salve.parseBuild,-Salve.parseConstraint,---- ** Unsafe--- | These functions can be used to unsafely parse strings. Instead of--- returning 'Nothing', they raise an exception. Only use these if you are sure--- the string can be successfully parsed!-Salve.unsafeParseVersion,-Salve.unsafeParsePreRelease,-Salve.unsafeParseBuild,-Salve.unsafeParseConstraint,---- * Rendering-Salve.renderVersion,-Salve.renderPreRelease,-Salve.renderBuild,-Salve.renderConstraint,---- * Predicates-Salve.isUnstable,-Salve.isStable,---- * Conversions-Salve.fromBaseVersion,-Salve.toBaseVersion,---- * Helpers-Salve.bumpMajor,-Salve.bumpMinor,-Salve.bumpPatch,-Salve.satisfiesConstraint,---- * Lenses--- | These lenses can be used to access and modify specific parts of a--- 'Version'.------ 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' 'Version' a@, which you may already be familiar with.-Salve.majorLens,-Salve.minorLens,-Salve.patchLens,-Salve.preReleasesLens,-Salve.buildsLens,---- * Examples--- | These examples are provided to showcase functionality and explain weird--- behavior. If something isn't clear, please open a pull request adding an--- example!---- ** Versions--- | Leading zeros are not allowed.------ >>> parseVersion "01.0.0"--- Nothing--- >>> parseVersion "0.01.0"--- Nothing--- >>> parseVersion "0.0.01"--- Nothing------ Negative numbers are not allowed.------ >>> parseVersion "-1.0.0"--- Nothing--- >>> parseVersion "0.-1.0"--- Nothing--- >>> parseVersion "0.0.-1"--- Nothing------ Non-digits are not allowed.------ >>> parseVersion "a.0.0"--- Nothing--- >>> parseVersion "0.a.0"--- Nothing--- >>> parseVersion "0.0.a"--- Nothing------ Partial version numbers are not allowed.------ >>> parseVersion "0.0"--- Nothing------ Extra version numbers are not allowed.------ >>> parseVersion "0.0.0.0"--- Nothing------ Spaces are allowed------ >>> parseVersion " 0.0.0"--- Just (Version {versionMajor = 0, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})--- >>> parseVersion "0.0.0 "--- Just (Version {versionMajor = 0, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})------ Interior spaces are not allowed.------ >>> parseVersion "0 .0.0"--- 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.------ >>> parseConstraint "1.2"--- Nothing------ Wildcards (also known as "x-ranges") are allowed. The exact character used--- for the wildcard is not round-tripped.------ >>> 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"------ An optional equals sign can be included with wildcard constraints.------ >>> renderConstraint <$> parseConstraint "=1.2.x"--- 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 "x.2.3"--- Nothing--- >>> parseConstraint "x.x.3"--- Nothing--- >>> parseConstraint "x.2.x"--- Nothing------ Wildcards cannot be used with other operators.------ >>> parseConstraint "<1.2.x"--- Nothing--- >>> parseConstraint "<=1.2.x"--- Nothing--- >>> parseConstraint ">=1.2.x"--- Nothing--- >>> 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)"@.------ >>> parseConstraint "(1.2.3)"--- Nothing--- >>> parseConstraint "(1.2.3 || >1.2.3) <1.3.0"--- Nothing--- >>> parseConstraint "(>1.2.3 <1.3.0) || 1.2.3"--- Nothing------ Most constraints can be round-tripped through parsing and rendering.------ >>> renderConstraint <$> parseConstraint "<1.2.3"--- Just "<1.2.3"--- >>> renderConstraint <$> parseConstraint "<=1.2.3"--- Just "<=1.2.3"--- >>> renderConstraint <$> parseConstraint "1.2.3"--- Just "1.2.3"--- >>> 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"--- Just "~1.2.3"--- >>> renderConstraint <$> parseConstraint "^1.2.3"--- Just "^1.2.3"--- >>> renderConstraint <$> parseConstraint ">1.2.3 <2.0.0"--- Just ">1.2.3 <2.0.0"--- >>> renderConstraint <$> parseConstraint "1.2.3 || >1.2.3"--- Just "1.2.3 || >1.2.3"------ Explicit equal signs do not get round-tripped.------ >>> renderConstraint <$> parseConstraint "=1.2.3"--- Just "1.2.3"------ Pre-releases and builds are allowed on any constraints except wildcards.------ >>> renderConstraint <$> parseConstraint "1.2.3-p+b"--- Just "1.2.3-p+b"--- >>> renderConstraint <$> parseConstraint ">1.2.3-p+b"--- Just ">1.2.3-p+b"--- >>> renderConstraint <$> parseConstraint "1.2.3-p+b - 2.3.4-p+b"--- Just "1.2.3-p+b - 2.3.4-p+b"--- >>> renderConstraint <$> parseConstraint "~1.2.3-p+b"--- Just "~1.2.3-p+b"--- >>> 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 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 'satisfiesConstraint', 'parseVersion',--- and 'parseConstraint', doing that here makes it hard to tell what the--- examples are doing. An operator makes things clearer.------ >>> satisfiesConstraint <$> parseConstraint "=1.2.3" <*> parseVersion "1.2.3"--- Just True--- >>> let version ? constraint = satisfiesConstraint (unsafeParseConstraint constraint) (unsafeParseVersion version)--- >>> "1.2.3" ? "=1.2.3"--- True------ -   Less than:------     >>> "1.2.2" ? "<1.2.3"---     True---     >>> "1.2.3" ? "<1.2.3"---     False---     >>> "1.2.4" ? "<1.2.3"---     False---     >>> "1.2.3-pre" ? "<1.2.3"---     True------ -   Less than or equal to:------     >>> "1.2.2" ? "<=1.2.3"---     True---     >>> "1.2.3" ? "<=1.2.3"---     True---     >>> "1.2.4" ? "<=1.2.3"---     False------ -   Equal to:------     >>> "1.2.2" ? "=1.2.3"---     False---     >>> "1.2.3" ? "=1.2.3"---     True---     >>> "1.2.4" ? "=1.2.3"---     False---     >>> "1.2.3-pre" ? "=1.2.3"---     False---     >>> "1.2.3+build" ? "=1.2.3"---     True------ -   Greater than or equal to:------     >>> "1.2.2" ? ">=1.2.3"---     False---     >>> "1.2.3" ? ">=1.2.3"---     True---     >>> "1.2.4" ? ">=1.2.3"---     True------ -   Greater than:------     >>> "1.2.2" ? ">1.2.3"---     False---     >>> "1.2.3" ? ">1.2.3"---     False---     >>> "1.2.4" ? ">1.2.3"---     True---     >>> "1.2.4-pre" ? ">1.2.3"---     True------     >>> "1.2.4" ? ">1.2.3-pre"---     True------ -   And:------     >>> "1.2.3" ? ">1.2.3 <1.2.5"---     False---     >>> "1.2.4" ? ">1.2.3 <1.2.5"---     True---     >>> "1.2.5" ? ">1.2.3 <1.2.5"---     False------ -   Or:------     >>> "1.2.2" ? "1.2.3 || 1.2.4"---     False---     >>> "1.2.3" ? "1.2.3 || 1.2.4"---     True---     >>> "1.2.4" ? "1.2.3 || 1.2.4"---     True---     >>> "1.2.5" ? "1.2.3 || 1.2.4"---     False------ -   And & or:------     >>> "1.2.2" ? "1.2.2 || >1.2.3 <1.3.0"---     True---     >>> "1.2.3" ? "1.2.2 || >1.2.3 <1.3.0"---     False---     >>> "1.2.4" ? "1.2.2 || >1.2.3 <1.3.0"---     True---     >>> "1.3.0" ? "1.2.2 || >1.2.3 <1.3.0"---     False------ -   Hyphen:------     >>> "1.2.2" ? "1.2.3 - 1.2.4"---     False---     >>> "1.2.3" ? "1.2.3 - 1.2.4"---     True---     >>> "1.2.4" ? "1.2.3 - 1.2.4"---     True---     >>> "1.2.5" ? "1.2.3 - 1.2.4"---     False------ -   Tilde:------     >>> "1.2.2" ? "~1.2.3"---     False---     >>> "1.2.3" ? "~1.2.3"---     True---     >>> "1.2.4" ? "~1.2.3"---     True---     >>> "1.3.0" ? "~1.2.3"---     False------ -   Caret:------     >>> "1.2.2" ? "^1.2.3"---     False---     >>> "1.2.3" ? "^1.2.3"---     True---     >>> "1.2.4" ? "^1.2.3"---     True---     >>> "1.3.0" ? "^1.2.3"---     True---     >>> "2.0.0" ? "^1.2.3"---     False------     >>> "0.2.2" ? "^0.2.3"---     False---     >>> "0.2.3" ? "^0.2.3"---     True---     >>> "0.2.4" ? "^0.2.3"---     True---     >>> "0.3.0" ? "^0.2.3"---     False------     >>> "0.0.2" ? "^0.0.3"---     False---     >>> "0.0.3" ? "^0.0.3"---     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 qualified Salve.Internal as Salve---- $setup--- >>> import Control.Applicative--- >>> import Salve
− src/lib/Salve/Internal.hs
@@ -1,1006 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric #-}---- | WARNING: This module should be considered private! If you find yourself--- wanting to import something from this module, please open an issue to get--- that thing exported from "Salve".-module Salve.Internal-  ( Version(..)-  , PreRelease(..)-  , Build(..)-  , Constraint(..)-  , makeVersion-  , initialVersion-  , parseVersion-  , parsePreRelease-  , parseBuild-  , parseConstraint-  , unsafeParseVersion-  , unsafeParsePreRelease-  , unsafeParseBuild-  , unsafeParseConstraint-  , renderVersion-  , renderPreRelease-  , renderBuild-  , renderConstraint-  , isUnstable-  , isStable-  , fromBaseVersion-  , toBaseVersion-  , bumpMajor-  , bumpMinor-  , bumpPatch-  , satisfiesConstraint-  , majorLens-  , minorLens-  , patchLens-  , preReleasesLens-  , buildsLens-  , Operator(..)-  , Wildcard(..)-  , constraintLT-  , constraintLE-  , constraintEQ-  , constraintGE-  , constraintGT-  , constraintAnd-  , constraintOr-  , constraintHyphen-  , constraintTilde-  , constraintCaret-  ) where--import qualified Control.Monad as Monad-import qualified Data.Char as Char-import qualified Data.Data as Data-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.Version as Version-import qualified Data.Word as Word-import qualified GHC.Generics as Generics-import qualified Text.ParserCombinators.ReadP as ReadP---- $setup------ >>> import Control.Applicative (Const(..))--- >>> let view lens record = getConst (lens Const record)------ >>> import Data.Functor.Identity (Identity(..))--- >>> let set lens field record = runIdentity (lens (const (Identity field)) record)------ >>> import Control.Applicative ((<$>), (<*>))---- * Public---- | A semantic version number. Versions have five parts:------ 1. 'majorLens': The major version number.--- 2. 'minorLens': The minor version number.--- 3. 'patchLens': The patch version number.--- 4. 'preReleasesLens': A list of pre-release identifiers.--- 5. 'buildsLens': A list of build metadata.------ Use 'parseVersion' to create versions.-data Version = Version-  { versionMajor :: Word.Word64-  , versionMinor :: Word.Word64-  , versionPatch :: Word.Word64-  , versionPreReleases :: [PreRelease]-  , versionBuilds :: [Build]-  } deriving (Data.Data, Eq, Generics.Generic, Read, Show)---- | 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"--- Just LT--- >>> compare <$> parseVersion "1.2.3" <*> parseVersion "1.3.0"--- Just LT--- >>> compare <$> parseVersion "1.2.3" <*> parseVersion "1.2.4"--- Just LT------ Numbers are compared numerically, not alphabetically.------ >>> compare <$> parseVersion "0.0.9" <*> parseVersion "0.0.10"--- Just LT------ If all the numbers are the same, the pre-releases are compared.------ >>> compare <$> parseVersion "1.2.3-a" <*> parseVersion "1.2.3-b"--- Just LT------ A version with a pre-release is always less than a version without one as--- long as the other parts are the same.------ >>> compare <$> parseVersion "1.2.3-pre" <*> parseVersion "1.2.3"--- Just LT--- >>> compare <$> parseVersion "1.2.4-pre" <*> parseVersion "1.2.3"--- Just GT------ Builds are not considered when comparing versions.------ >>> compare <$> parseVersion "1.2.3+a" <*> parseVersion "1.2.3+b"--- Just EQ--- >>> (==) <$> parseVersion "1.2.3+a" <*> parseVersion "1.2.3+b"--- Just False-instance Ord Version where-  compare x y = Monoid.mconcat-    [ Ord.comparing versionMajor x y-    , Ord.comparing versionMinor x y-    , Ord.comparing versionPatch x y-    , case both versionPreReleases (x, y) of-      ([], []) -> EQ-      ([], _) -> GT-      (_, []) -> LT-      (p, q) -> compare p q-    ]---- | Pre-release information attached to a version. These can either be numeric--- or textual. They must not be empty.------ - Numeric: Can be any non-negative integer. Cannot have leading zeros.------ - Textual: Can be any string of ASCII digits, letters, or hyphens. Cannot be---   all digits, as that would be numeric.------ In general, pre-releases must match the regular expression--- @\/^[-0-9A-Za-z]+$\/@.------ Use 'parsePreRelease' to create pre-releases.-data PreRelease-  = PreReleaseNumeric Word.Word64-  | PreReleaseTextual String-  deriving (Data.Data, Eq, Generics.Generic, Read, Show)---- | Numeric pre-releases are always less than textual pre-releases.------ >>> compare <$> parsePreRelease "1" <*> parsePreRelease "a"--- Just LT------ Numeric pre-releases are compared numerically.------ >>> compare <$> parsePreRelease "9" <*> parsePreRelease "10"--- Just LT------ Textual pre-releases are compared alphabetically.------ >>> compare <$> parsePreRelease "p10" <*> parsePreRelease "p9"--- Just LT-instance Ord PreRelease where-  compare x y = case (x, y) of-    (PreReleaseNumeric n, PreReleaseNumeric m) -> compare n m-    (PreReleaseNumeric _, PreReleaseTextual _) -> LT-    (PreReleaseTextual _, PreReleaseNumeric _) -> GT-    (PreReleaseTextual s, PreReleaseTextual t) -> compare s t---- | Build metadata attached to a version. These are similar to--- 'PreRelease's with some key differences:------ 1. There is no such thing as numeric builds. Even though builds can look---    like numbers, all builds are textual.--- 2. As a result, builds that look numeric are allowed to have leading zeros.--- 3. Builds cannot be compared. That is, they do not have an 'Ord' instance.------ Use 'parseBuild' to create builds.-newtype Build = Build String-  deriving (Data.Data, Eq, Generics.Generic, Read, Show)---- | Constrains allowable version numbers.------ Use 'parseConstraint' to create constraints and 'satisfiesConstraint' to see--- if a version number satisfies a constraint.-data Constraint-  = ConstraintOperator Operator Version-  | ConstraintHyphen Version Version-  | ConstraintWildcard Wildcard-  | ConstraintAnd Constraint Constraint-  | ConstraintOr Constraint Constraint-  deriving (Data.Data, Eq, Generics.Generic, Ord, Read, Show)---- | Makes a new version number.------ >>> 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.Word64 -> Word.Word64 -> Word.Word64 -> [PreRelease] -> [Build] -> Version-makeVersion major minor patch preReleases builds = Version-  { versionMajor = major-  , versionMinor = minor-  , versionPatch = patch-  , versionPreReleases = preReleases-  , versionBuilds = builds-  }---- | The initial version number for development.------ >>> initialVersion--- Version {versionMajor = 0, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []}-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).------ >>> 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"]})------ Returns 'Nothing' if the parse fails.------ >>> parseVersion "wrong"--- Nothing------ Whitespace is allowed.------ >>> parseVersion " 1.2.3 "--- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})-parseVersion :: String -> Maybe Version-parseVersion s = parse-  (do-    ReadP.skipSpaces-    version <- versionP-    ReadP.skipSpaces-    return version)-  s---- | Attempts to parse a pre-release.------ >>> parsePreRelease "pre"--- Just (PreReleaseTextual "pre")--- >>> parsePreRelease "1"--- Just (PreReleaseNumeric 1)------ Returns 'Nothing' if the parse fails.------ >>> parsePreRelease "wrong!"--- Nothing------ Numeric pre-releases cannot contain leading zeros.------ >>> parsePreRelease "01"--- Nothing-parsePreRelease :: String -> Maybe PreRelease-parsePreRelease s = parse preReleaseP s---- | Attempts to parse a build.------ >>> parseBuild "build"--- Just (Build "build")--- >>> parseBuild "1"--- Just (Build "1")------ Returns 'Nothing' if the parse fails.------ >>> parseBuild "wrong!"--- Nothing------ Unlike pre-releases, numeric builds can have leading zeros.------ >>> parseBuild "01"--- Just (Build "01")-parseBuild :: String -> Maybe Build-parseBuild s = parse buildP s---- | 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 = []}))------ Returns 'Nothing' if the parse fails.------ >>> 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---- | Parses a version.------ >>> unsafeParseVersion "1.2.3-p.4+b.5"--- Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [PreReleaseTextual "p",PreReleaseNumeric 4], versionBuilds = [Build "b",Build "5"]}------ Raises an exception if the parse fails.------ >>> unsafeParseVersion "wrong"--- *** Exception: unsafeParseVersion: invalid version: "wrong"--- ...------ See 'parseVersion' for a safe version of this function.-unsafeParseVersion :: String -> Version-unsafeParseVersion s = case parseVersion s of-  Nothing -> error ("unsafeParseVersion: invalid version: " ++ show s)-  Just v -> v---- | Parses a pre-release.------ >>> unsafeParsePreRelease "pre"--- PreReleaseTextual "pre"------ Raises an exception if the parse fails.------ >>> unsafeParsePreRelease "wrong!"--- *** Exception: unsafeParsePreRelease: invalid pre-release: "wrong!"--- ...------ See 'parsePreRelease' for a safe version of this function.-unsafeParsePreRelease :: String -> PreRelease-unsafeParsePreRelease s = case parsePreRelease s of-  Nothing -> error ("unsafeParsePreRelease: invalid pre-release: " ++ show s)-  Just p -> p---- | Parses a build.------ >>> unsafeParseBuild "build"--- Build "build"------ Raises an exception if the parse fails.------ >>> unsafeParseBuild "wrong!"--- Build "*** Exception: unsafeParseBuild: invalid build: "wrong!"--- ...------ See 'parseBuild' for a safe version of this function.-unsafeParseBuild :: String -> Build-unsafeParseBuild s = case parseBuild s of-  Nothing -> error ("unsafeParseBuild: invalid build: " ++ show s)-  Just b -> b---- | Parses a constraint.------ >>> unsafeParseConstraint ">1.2.3"--- ConstraintOperator OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})------ Raises an exception if the parse fails.------ >>> unsafeParseConstraint "wrong"--- *** Exception: unsafeParseConstraint: invalid constraint: "wrong"--- ...------ See 'parseConstraint' for a safe version of this function.-unsafeParseConstraint :: String -> Constraint-unsafeParseConstraint s = case parseConstraint s of-  Nothing -> error ("unsafeParseConstraint: invalid constraint: " ++ show s)-  Just c -> c---- | Renders a version.------ >>> renderVersion <$> parseVersion "1.2.3-p.4+b.5"--- Just "1.2.3-p.4+b.5"-renderVersion :: Version -> String-renderVersion v = concat-  [ show (versionMajor v)-  , "."-  , show (versionMinor v)-  , "."-  , show (versionPatch v)-  , renderPreReleases (versionPreReleases v)-  , renderBuilds (versionBuilds v)-  ]---- | Renders a pre-release.------ >>> renderPreRelease <$> parsePreRelease "pre"--- Just "pre"--- >>> renderPreRelease <$> parsePreRelease "1"--- Just "1"-renderPreRelease :: PreRelease -> String-renderPreRelease p = case p of-  PreReleaseNumeric n -> show n-  PreReleaseTextual s -> s---- | Renders a build.------ >>> renderBuild <$> parseBuild "build"--- Just "build"--- >>> renderBuild <$> parseBuild "1"--- Just "1"-renderBuild :: Build -> String-renderBuild (Build b) = b---- | Renders a constraint.------ >>> renderConstraint <$> parseConstraint ">1.2.3"--- Just ">1.2.3"------ Parsing and rendering a constraint doesn't always return what you started--- with.------ >>> renderConstraint <$> parseConstraint "=1.2.3"--- Just "1.2.3"-renderConstraint :: Constraint -> String-renderConstraint c = case c of-  ConstraintOperator o v ->-    let s = renderVersion v-    in case o of-      OperatorLT -> '<' : s-      OperatorLE -> '<' : '=' : s-      OperatorEQ -> s-      OperatorGE -> '>' : '=' : s-      OperatorGT -> '>' : s-      OperatorTilde -> '~' : s-      OperatorCaret -> '^' : s-  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.------ >>> isUnstable <$> parseVersion "0.1.2"--- Just True--- >>> isUnstable <$> parseVersion "1.0.0"--- Just False-isUnstable :: Version -> Bool-isUnstable v = versionMajor v == 0---- | Returns 'True' if the major version number is not zero, 'False' otherwise.------ >>> isStable <$> parseVersion "1.0.0"--- Just True--- >>> isStable <$> parseVersion "0.1.2"--- Just False-isStable :: Version -> Bool-isStable v = not (isUnstable v)---- | Converts from a 'Version.Version' from the @base@ package.------ >>> renderVersion . fromBaseVersion $ Version.makeVersion [1, 2, 3]--- "1.2.3"------ Missing version components are set to zero.------ >>> renderVersion . fromBaseVersion $ Version.makeVersion []--- "0.0.0"--- >>> renderVersion . fromBaseVersion $ Version.makeVersion [1]--- "1.0.0"--- >>> renderVersion . fromBaseVersion $ Version.makeVersion [1, 2]--- "1.2.0"------ Extra version components are ignored.------ >>> renderVersion . fromBaseVersion $ Version.makeVersion [1, 2, 3, 4]--- "1.2.3"------ Tags are ignored.------ >>> renderVersion . fromBaseVersion $ Version.Version [] ["ignored"]--- "0.0.0"-fromBaseVersion :: Version.Version -> Version-fromBaseVersion v = case Version.versionBranch v of-  (m : n : p : _) -> mkV (fromIntegral m) (fromIntegral n) (fromIntegral p)-  (m : n : _) -> mkV (fromIntegral m) (fromIntegral n) 0-  (m : _) -> mkV (fromIntegral m) 0 0-  _ -> mkV 0 0 0---- | Converts to a 'Version.Version' from the @base@ package.------ >>> toBaseVersion <$> parseVersion "1.2.3"--- Just (Version {versionBranch = [1,2,3], versionTags = []})------ Pre-releases and builds are converted to tags.------ >>> toBaseVersion <$> parseVersion "1.2.3-pre+build"--- Just (Version {versionBranch = [1,2,3], versionTags = ["pre","build"]})-toBaseVersion :: Version -> Version.Version-toBaseVersion v = Version.Version-  (map fromIntegral-    [ versionMajor v-    , versionMinor v-    , versionPatch v-    ])-  (concat-    [ map renderPreRelease (versionPreReleases v)-    , map renderBuild (versionBuilds v)-    ])---- | Increments the major version number.------ >>> bumpMajor <$> parseVersion "0.0.0"--- Just (Version {versionMajor = 1, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})------ The minor and patch numbers are reset to zero.------ >>> bumpMajor <$> parseVersion "1.2.3"--- Just (Version {versionMajor = 2, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})------ The pre-releases and builds are removed.------ >>> bumpMajor <$> parseVersion "0.0.0-pre+build"--- Just (Version {versionMajor = 1, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})------ Consider using 'majorLens' if you want to arbitrarily change the major--- number, or if you don't want the other parts of the version to change.-bumpMajor :: Version -> Version-bumpMajor v = makeVersion (versionMajor v + 1) 0 0 [] []---- | Increments the minor version number.------ >>> bumpMinor <$> parseVersion "0.0.0"--- Just (Version {versionMajor = 0, versionMinor = 1, versionPatch = 0, versionPreReleases = [], versionBuilds = []})------ The patch number is reset to zero.------ >>> bumpMinor <$> parseVersion "1.2.3"--- Just (Version {versionMajor = 1, versionMinor = 3, versionPatch = 0, versionPreReleases = [], versionBuilds = []})------ The pre-releases and builds are removed.------ >>> bumpMinor <$> parseVersion "0.0.0-pre+build"--- Just (Version {versionMajor = 0, versionMinor = 1, versionPatch = 0, versionPreReleases = [], versionBuilds = []})------ Consider using 'minorLens' if you want to arbitrarily change the minor--- number, or if you don't want the other parts of the version to change.-bumpMinor :: Version -> Version-bumpMinor v = makeVersion (versionMajor v) (versionMinor v + 1) 0 [] []---- | Increments the patch number.------ >>> bumpPatch <$> parseVersion "0.0.0"--- Just (Version {versionMajor = 0, versionMinor = 0, versionPatch = 1, versionPreReleases = [], versionBuilds = []})------ The major and minor numbers are not changed.------ >>> bumpPatch <$> parseVersion "1.2.3"--- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 4, versionPreReleases = [], versionBuilds = []})------ The pre-releases and builds are removed.------ >>> bumpPatch <$> parseVersion "0.0.0-pre+build"--- Just (Version {versionMajor = 0, versionMinor = 0, versionPatch = 1, versionPreReleases = [], versionBuilds = []})------ Consider using 'patchLens' if you want to arbitrarily change the patch--- number, or if you don't want the other parts of the version to change.-bumpPatch :: Version -> Version-bumpPatch v = makeVersion-  (versionMajor v) (versionMinor v) (versionPatch v + 1) [] []---- | Returns 'True' if the version satisfies the constraint, 'False' otherwise.------ >>> satisfiesConstraint <$> parseConstraint ">1.2.0" <*> parseVersion "1.2.3"--- Just True-satisfiesConstraint :: Constraint -> Version -> Bool-satisfiesConstraint c v = satisfiesSC (toSC c) v---- | Focuses on the major version number.------ >>> view majorLens <$> parseVersion "1.2.3-pre.4+build.5"--- Just 1--- >>> set majorLens 4 <$> parseVersion "1.2.3"--- Just (Version {versionMajor = 4, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})-majorLens :: Functor f => (Word.Word64 -> f Word.Word64) -> Version -> f Version-majorLens f v = fmap-  (\ m -> v { versionMajor = m })-  (f (versionMajor v))---- | Focuses on the minor version number.------ >>> view minorLens <$> parseVersion "1.2.3-pre.4+build.5"--- Just 2--- >>> set minorLens 4 <$> parseVersion "1.2.3"--- Just (Version {versionMajor = 1, versionMinor = 4, versionPatch = 3, versionPreReleases = [], versionBuilds = []})-minorLens :: Functor f => (Word.Word64 -> f Word.Word64) -> Version -> f Version-minorLens f v = fmap-  (\ n -> v { versionMinor = n })-  (f (versionMinor v))---- | Focuses on the patch version number.------ >>> view patchLens <$> parseVersion "1.2.3-pre.4+build.5"--- Just 3--- >>> set patchLens 4 <$> parseVersion "1.2.3"--- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 4, versionPreReleases = [], versionBuilds = []})-patchLens :: Functor f => (Word.Word64 -> f Word.Word64) -> Version -> f Version-patchLens f v = fmap-  (\ p -> v { versionPatch = p })-  (f (versionPatch v))---- | Focuses on the pre-release identifiers.------ >>> view preReleasesLens <$> parseVersion "1.2.3-pre.4+build.5"--- Just [PreReleaseTextual "pre",PreReleaseNumeric 4]--- >>> set preReleasesLens [] <$> parseVersion "1.2.3-pre"--- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})-preReleasesLens :: Functor f => ([PreRelease] -> f [PreRelease]) -> Version -> f Version-preReleasesLens f v = fmap-  (\ ps -> v { versionPreReleases = ps })-  (f (versionPreReleases v))---- | Focuses on the build metadata.------ >>> view buildsLens <$> parseVersion "1.2.3-pre.4+build.5"--- Just [Build "build",Build "5"]--- >>> set buildsLens [] <$> parseVersion "1.2.3+build"--- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})-buildsLens :: Functor f => ([Build] -> f [Build]) -> Version -> f Version-buildsLens f v = fmap-  (\ bs -> v { versionBuilds = bs })-  (f (versionBuilds v))---- * Private---- ** Types--data Operator-  = OperatorLT-  | OperatorLE-  | OperatorEQ-  | OperatorGE-  | OperatorGT-  | OperatorTilde-  | OperatorCaret-  deriving (Data.Data, Eq, Generics.Generic, Ord, Read, Show)--data Wildcard-  = WildcardMajor-  | WildcardMinor Word.Word64-  | WildcardPatch Word.Word64 Word.Word64-  deriving (Data.Data, Eq, Generics.Generic, Ord, Read, 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 :: ReadP.ReadP Version-versionP = do-  major <- numberP-  Monad.void (ReadP.char '.')-  minor <- numberP-  Monad.void (ReadP.char '.')-  patch <- numberP-  preReleases <- preReleasesP-  builds <- buildsP-  return (makeVersion major minor patch preReleases builds)--preReleasesP :: ReadP.ReadP [PreRelease]-preReleasesP = ReadP.option [] (do-  Monad.void (ReadP.char '-')-  ReadP.sepBy1 preReleaseP (ReadP.char '.'))--preReleaseP :: ReadP.ReadP PreRelease-preReleaseP = preReleaseNumberP ReadP.<++ preReleaseStringP--preReleaseNumberP :: ReadP.ReadP PreRelease-preReleaseNumberP = do-  n <- numberP-  return (PreReleaseNumeric n)--preReleaseStringP :: ReadP.ReadP PreRelease-preReleaseStringP = do-  s <- ReadP.munch1 isIdentifier-  if all Char.isDigit s-    then ReadP.pfail-    else return (PreReleaseTextual s)--buildsP :: ReadP.ReadP [Build]-buildsP = ReadP.option [] (do-  Monad.void (ReadP.char '+')-  ReadP.sepBy1 buildP (ReadP.char '.'))--buildP :: ReadP.ReadP Build-buildP = do-  b <- ReadP.munch1 isIdentifier-  return (Build b)--numberP :: ReadP.ReadP Word.Word64-numberP = zeroP ReadP.<++ nonZeroP--zeroP :: ReadP.ReadP Word.Word64-zeroP = do-  Monad.void (ReadP.char '0')-  return 0--nonZeroP :: ReadP.ReadP Word.Word64-nonZeroP = do-  x <- ReadP.satisfy isAsciiDigitNonZero-  ys <- ReadP.munch Char.isDigit-  case toWord64 (stringToIntegral (x : ys)) of-    Nothing -> ReadP.pfail-    Just n -> return n--constraintsP :: ReadP.ReadP Constraint-constraintsP = do-  spacesP-  cs <- ReadP.sepBy1 constraintP orP-  spacesP-  return (foldr1 constraintOr cs)--constraintP :: ReadP.ReadP Constraint-constraintP = do-  cs <- ReadP.sepBy1 simpleP spaces1P-  return (foldr1 constraintAnd cs)--hyphenatedP :: ReadP.ReadP Constraint-hyphenatedP = do-  v <- versionP-  hyphenP-  w <- versionP-  return (constraintHyphen v w)--simpleP :: ReadP.ReadP Constraint-simpleP = ReadP.choice [hyphenatedP, wildcardConstraintP, primitiveP]--wildcardConstraintP :: ReadP.ReadP Constraint-wildcardConstraintP = do-  ReadP.optional (ReadP.char '=')-  w <- wildcardP-  return (ConstraintWildcard w)--wildcardP :: ReadP.ReadP Wildcard-wildcardP = ReadP.choice [wildcardPatchP, wildcardMinorP, wildcardMajorP]--wildcardPatchP :: ReadP.ReadP Wildcard-wildcardPatchP = do-  m <- numberP-  Monad.void (ReadP.char '.')-  n <- numberP-  Monad.void (ReadP.char '.')-  Monad.void (ReadP.satisfy isWildcard)-  return (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)-  return (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)-  return WildcardMajor--primitiveP :: ReadP.ReadP Constraint-primitiveP = do-  o <- operatorP-  spacesP-  v <- versionP-  return (ConstraintOperator o v)--operatorP :: ReadP.ReadP Operator-operatorP = ReadP.choice-  [ 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 ()-hyphenP = do-  spaces1P-  Monad.void (ReadP.char '-')-  spaces1P--orP :: ReadP.ReadP ()-orP = do-  spaces1P-  Monad.void (ReadP.string "||")-  spaces1P--spaces1P :: ReadP.ReadP ()-spaces1P = Monad.void (ReadP.munch1 (== ' '))--spacesP :: ReadP.ReadP ()-spacesP = Monad.void (ReadP.munch (== ' '))---- ** Rendering--renderPreReleases :: [PreRelease] -> String-renderPreReleases ps = if null ps-  then ""-  else '-' : List.intercalate "." (map renderPreRelease ps)--renderBuilds :: [Build] -> String-renderBuilds bs = if null bs-  then ""-  else '+' : List.intercalate "." (map renderBuild bs)---- ** Helpers--both :: (a -> b) -> (a, a) -> (b, b)-both f (x, y) = (f x, f y)--isAsciiDigitNonZero :: Char -> Bool-isAsciiDigitNonZero c = Char.isDigit c && (c /= '0')--isIdentifier :: Char -> Bool-isIdentifier c = (Char.isAscii c && Char.isAlphaNum c) || (c == '-')--isWildcard :: Char -> Bool-isWildcard c = (c == 'x') || (c == '*') || (c == 'X')--parse :: ReadP.ReadP a -> String -> Maybe a-parse p s =-  let p' = ReadP.readP_to_S p-  in Maybe.listToMaybe (do-    (x, "") <- p' s-    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--- 'Constraint's.--data SimpleConstraint-  = SCLT Version-  | SCEQ Version-  | SCGT Version-  | SCAnd SimpleConstraint SimpleConstraint-  | SCOr SimpleConstraint SimpleConstraint-  deriving (Data.Data, Eq, Generics.Generic, Ord, Read, Show)--mkV :: Word.Word64 -> Word.Word64 -> Word.Word64 -> Version-mkV m n p = makeVersion m n p [] []--satisfiesSC :: SimpleConstraint -> Version -> Bool-satisfiesSC c v = case c of-  SCLT u -> v < u-  -- This uses `compare` rather than `==` to ignore build metadata.-  SCEQ u -> compare v u == EQ-  SCGT u -> v > u-  SCAnd l r -> satisfiesSC l v && satisfiesSC r v-  SCOr l r -> satisfiesSC l v || satisfiesSC r v--scLE :: Version -> SimpleConstraint-scLE v = SCOr (SCLT v) (SCEQ v)--scGE :: Version -> SimpleConstraint-scGE v = SCOr (SCGT v) (SCEQ v)--toSC :: Constraint -> SimpleConstraint-toSC c = case c of-  ConstraintOperator o v -> case o of-    OperatorLT -> SCLT v-    OperatorLE -> scLE v-    OperatorEQ -> SCEQ v-    OperatorGE -> scGE v-    OperatorGT -> SCGT v-    OperatorTilde -> SCAnd-      (scGE v)-      (SCLT (mkV (versionMajor v) (versionMinor v + 1) 0))-    OperatorCaret -> SCAnd-      (scGE v)-      (SCLT (case (versionMajor v, versionMinor v, versionPatch v) of-        (0, 0, p) -> mkV 0 0 (p + 1)-        (0, n, _) -> mkV 0 (n + 1) 0-        (m, _, _) -> mkV (m + 1) 0 0))-  ConstraintHyphen l h -> SCAnd (scGE l) (scLE h)-  ConstraintWildcard w -> case w of-    WildcardMajor -> scGE initialVersion-    WildcardMinor m -> SCAnd (scGE (mkV m 0 0)) (SCLT (mkV (m + 1) 0 0))-    WildcardPatch m n -> SCAnd (scGE (mkV m n 0)) (SCLT (mkV m (n + 1) 0))-  ConstraintAnd l r -> SCAnd (toSC l) (toSC r)-  ConstraintOr l r -> SCOr (toSC l) (toSC r)
− src/test/Main.hs
@@ -1,102 +0,0 @@--- import qualified Control.Applicative as Applicative-import qualified Control.Monad as Monad--- import qualified Data.Functor.Identity as Identity-import qualified Salve-import qualified System.Exit as Exit-import qualified Test.HUnit as Test--main :: IO ()-main = do-  counts <- Test.runTestTT $ Test.TestList-    [ (compare <$> Salve.parseVersion "1.2.3" <*> Salve.parseVersion "2.0.0") Test.~?= Just LT-    , (compare <$> Salve.parseVersion "1.2.3" <*> Salve.parseVersion "1.3.0") Test.~?= Just LT-    , (compare <$> Salve.parseVersion "1.2.3" <*> Salve.parseVersion "1.2.4") Test.~?= Just LT-    , (compare <$> Salve.parseVersion "0.0.9" <*> Salve.parseVersion "0.0.10") Test.~?= Just LT-    , (compare <$> Salve.parseVersion "1.2.3-a" <*> Salve.parseVersion "1.2.3-b") Test.~?= Just LT-    , (compare <$> Salve.parseVersion "1.2.3-pre" <*> Salve.parseVersion "1.2.3") Test.~?= Just LT-    , (compare <$> Salve.parseVersion "1.2.4-pre" <*> Salve.parseVersion "1.2.3") Test.~?= Just GT-    , (compare <$> Salve.parseVersion "1.2.3+a" <*> Salve.parseVersion "1.2.3+b") Test.~?= Just EQ-    , ((==) <$> Salve.parseVersion "1.2.3+a" <*> Salve.parseVersion "1.2.3+b") Test.~?= Just False-    , (compare <$> Salve.parsePreRelease "1" <*> Salve.parsePreRelease "a") Test.~?= Just LT-    , (compare <$> Salve.parsePreRelease "9" <*> Salve.parsePreRelease "10") Test.~?= Just LT-    , (compare <$> Salve.parsePreRelease "p10" <*> Salve.parsePreRelease "p9") Test.~?= Just LT-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "<1.2.3" <*> Salve.parseVersion "1.2.2") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "<1.2.3" <*> Salve.parseVersion "1.2.3") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "<1.2.3" <*> Salve.parseVersion "1.2.4") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "<1.2.3" <*> Salve.parseVersion "1.2.3-pre") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "<=1.2.3" <*> Salve.parseVersion "1.2.2") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "<=1.2.3" <*> Salve.parseVersion "1.2.3") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "<=1.2.3" <*> Salve.parseVersion "1.2.4") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "=1.2.3" <*> Salve.parseVersion "1.2.2") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "=1.2.3" <*> Salve.parseVersion "1.2.3") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "=1.2.3" <*> Salve.parseVersion "1.2.4") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "=1.2.3" <*> Salve.parseVersion "1.2.3-pre") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "=1.2.3" <*> Salve.parseVersion "1.2.3+build") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint ">=1.2.3" <*> Salve.parseVersion "1.2.2") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint ">=1.2.3" <*> Salve.parseVersion "1.2.3") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint ">=1.2.3" <*> Salve.parseVersion "1.2.4") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint ">1.2.3" <*> Salve.parseVersion "1.2.2") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint ">1.2.3" <*> Salve.parseVersion "1.2.3") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint ">1.2.3" <*> Salve.parseVersion "1.2.4") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint ">1.2.3" <*> Salve.parseVersion "1.2.4-pre") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint ">1.2.3-pre" <*> Salve.parseVersion "1.2.4") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint ">1.2.3 <1.2.5" <*> Salve.parseVersion "1.2.3") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint ">1.2.3 <1.2.5" <*> Salve.parseVersion "1.2.4") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint ">1.2.3 <1.2.5" <*> Salve.parseVersion "1.2.5") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.3 || 1.2.4" <*> Salve.parseVersion "1.2.2") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.3 || 1.2.4" <*> Salve.parseVersion "1.2.3") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.3 || 1.2.4" <*> Salve.parseVersion "1.2.4") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.3 || 1.2.4" <*> Salve.parseVersion "1.2.5") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.2 || >1.2.3 <1.3.0" <*> Salve.parseVersion "1.2.2") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.2 || >1.2.3 <1.3.0" <*> Salve.parseVersion "1.2.3") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.2 || >1.2.3 <1.3.0" <*> Salve.parseVersion "1.2.4") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.2 || >1.2.3 <1.3.0" <*> Salve.parseVersion "1.3.0") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.3 - 1.2.4" <*> Salve.parseVersion "1.2.2") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.3 - 1.2.4" <*> Salve.parseVersion "1.2.3") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.3 - 1.2.4" <*> Salve.parseVersion "1.2.4") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.3 - 1.2.4" <*> Salve.parseVersion "1.2.5") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "~1.2.3" <*> Salve.parseVersion "1.2.2") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "~1.2.3" <*> Salve.parseVersion "1.2.3") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "~1.2.3" <*> Salve.parseVersion "1.2.4") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "~1.2.3" <*> Salve.parseVersion "1.3.0") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "^1.2.3" <*> Salve.parseVersion "1.2.2") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "^1.2.3" <*> Salve.parseVersion "1.2.3") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "^1.2.3" <*> Salve.parseVersion "1.2.4") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "^1.2.3" <*> Salve.parseVersion "1.3.0") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "^1.2.3" <*> Salve.parseVersion "2.0.0") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "^0.2.3" <*> Salve.parseVersion "0.2.2") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "^0.2.3" <*> Salve.parseVersion "0.2.3") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "^0.2.3" <*> Salve.parseVersion "0.2.4") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "^0.2.3" <*> Salve.parseVersion "0.3.0") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "^0.0.3" <*> Salve.parseVersion "0.0.2") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "^0.0.3" <*> Salve.parseVersion "0.0.3") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "^0.0.3" <*> Salve.parseVersion "0.0.4") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.x" <*> Salve.parseVersion "1.1.0") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.x" <*> Salve.parseVersion "1.2.3") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.2.x" <*> Salve.parseVersion "1.3.0") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.x.x" <*> Salve.parseVersion "0.1.0") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.x.x" <*> Salve.parseVersion "1.0.0") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.x.x" <*> Salve.parseVersion "1.2.3") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "1.x.x" <*> Salve.parseVersion "2.0.0") Test.~?= Just False-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "x.x.x" <*> Salve.parseVersion "0.0.0") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "x.x.x" <*> Salve.parseVersion "1.2.3") Test.~?= Just True-    , (Salve.satisfiesConstraint <$> Salve.parseConstraint "x.x.x" <*> Salve.parseVersion "2.0.0") Test.~?= Just True-    ]--  let-    hasErrors = Test.errors counts /= 0-    hasFailures = Test.failures counts /= 0-  Monad.when (hasErrors || hasFailures) Exit.exitFailure---- view---   :: ((record -> Applicative.Const record field) -> record -> Applicative.Const field field)---   -> record---   -> field--- view lens = Applicative.getConst . lens Applicative.Const---- set---   :: ((record -> Identity.Identity field) -> record -> Identity.Identity record)---   -> field---   -> record---   -> record--- set lens field = Identity.runIdentity . lens (const $ Identity.Identity field)