packages feed

salve 1.0.9 → 1.0.10

raw patch · 11 files changed

+1772/−1726 lines, 11 filesdep +HUnitdep +salvedep −doctestdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: HUnit, salve

Dependencies removed: doctest

Dependency ranges changed: base

API changes (from Hackage documentation)

Files

− CHANGELOG.markdown
@@ -1,7 +0,0 @@-# Change log--Salve uses [Semantic Versioning][].-The change log is available through the [releases on GitHub][].--[Semantic Versioning]: http://semver.org/spec/v2.0.0.html-[releases on GitHub]: https://github.com/tfausak/salve/releases
README.markdown view
@@ -1,11 +1,9 @@ # Salve--[![Build badge][]][build status]+[![Travis CI](https://travis-ci.org/tfausak/salve.svg?branch=master)](https://travis-ci.org/tfausak/salve)+[![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>.--[Build badge]: https://travis-ci.org/tfausak/salve.svg?branch=master-[build status]: https://travis-ci.org/tfausak/salve
− library/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
− library/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)
− package.yaml
@@ -1,41 +0,0 @@-name: salve-version: 1.0.9--category: Distribution-description:-  Salve provides semantic version (SemVer) numbers and constraints (ranges).-extra-source-files:-  - CHANGELOG.markdown-  - package.yaml-  - README.markdown-  - stack.yaml-github: tfausak/salve-license-file: LICENSE.markdown-license: MIT-maintainer: Taylor Fausak-synopsis: Semantic version numbers and constraints.--dependencies:-  base: '>= 4.9.0 && < 4.15'-ghc-options:-  - -Weverything-  - -Wno-implicit-prelude-  - -Wno-safe-  - -Wno-unsafe--when:-  - condition: impl(ghc >= 8.8.1)-    ghc-options: -Wno-missing-deriving-strategies--library:-  source-dirs: library--tests:-  doctest:-    dependencies:-      doctest: '>= 0.11.0 && < 0.17'-    ghc-options:-      - -rtsopts-      - -threaded-    main: Main.hs-    source-dirs: tests
salve.cabal view
@@ -1,58 +1,60 @@-cabal-version: 1.12+cabal-version: 2.2 --- This file has been generated from package.yaml by hpack version 0.33.0.------ see: https://github.com/sol/hpack------ hash: 819ccef7644498bebc5302d80b59de266c93ebf52b3037e2d7f3f3433db20512+name: salve+version: 1.0.10 -name:           salve-version:        1.0.9-synopsis:       Semantic version numbers and constraints.-description:    Salve provides semantic version (SemVer) numbers and constraints (ranges).-category:       Distribution-homepage:       https://github.com/tfausak/salve#readme-bug-reports:    https://github.com/tfausak/salve/issues-maintainer:     Taylor Fausak-license:        MIT-license-file:   LICENSE.markdown-build-type:     Simple-extra-source-files:-    CHANGELOG.markdown-    package.yaml-    README.markdown-    stack.yaml+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+license: MIT+maintainer: Taylor Fausak+ source-repository head-  type: git   location: https://github.com/tfausak/salve+  type: git +common basics+  default-language: Haskell2010+  ghc-options:+    -Weverything+    -Wno-all-missed-specialisations+    -Wno-implicit-prelude+    -Wno-missing-exported-signatures+    -Wno-missing-import-lists+    -Wno-safe+    -Wno-unsafe++  if impl(ghc >= 8.8)+    ghc-options:+      -Wno-missing-deriving-strategies++  if impl(ghc >= 8.10)+    ghc-options:+      -Wno-missing-safe-haskell-mode+      -Wno-prepositive-qualified-module+ library-  exposed-modules:-      Salve-      Salve.Internal-  other-modules:-      Paths_salve-  hs-source-dirs:-      library-  ghc-options: -Weverything -Wno-implicit-prelude -Wno-safe -Wno-unsafe+  import: basics+   build-depends:-      base >=4.9.0 && <4.15-  if impl(ghc >= 8.8.1)-    ghc-options: -Wno-missing-deriving-strategies-  default-language: Haskell2010+    base >= 4.9.0 && < 4.15+  exposed-modules:+    Salve+    Salve.Internal+  hs-source-dirs: src/lib -test-suite doctest-  type: exitcode-stdio-1.0-  main-is: Main.hs-  other-modules:-      Paths_salve-  hs-source-dirs:-      tests-  ghc-options: -Weverything -Wno-implicit-prelude -Wno-safe -Wno-unsafe -rtsopts -threaded+test-suite test+  import: basics+   build-depends:-      base >=4.9.0 && <4.15-    , doctest >=0.11.0 && <0.17-  if impl(ghc >= 8.8.1)-    ghc-options: -Wno-missing-deriving-strategies-  default-language: Haskell2010+    base -any+    , HUnit >= 1.6.0 && < 1.7+    , salve -any+  hs-source-dirs: src/test+  main-is: Main.hs+  type: exitcode-stdio-1.0
+ src/lib/Salve.hs view
@@ -0,0 +1,611 @@+-- | 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 view
@@ -0,0 +1,1006 @@+{-# 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 view
@@ -0,0 +1,102 @@+-- 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)
− stack.yaml
@@ -1,1 +0,0 @@-resolver: lts-15.4
− tests/Main.hs
@@ -1,7 +0,0 @@-import qualified Test.DocTest as Doctest--main :: IO ()-main = Doctest.doctest-  [ "library/Salve/Internal.hs"-  , "library/Salve.hs"-  ]